05day02pwm

  1 /*
  2 pwm  硬件手册24章
  3 蜂鸣器   GPD0_0  配置成  tout0  pwm0的输出
  4 
  5 从硬件手册P446页 查出  总线的频率是100Mhz
  6 
  7 TCFG0  配置一级分频  0-7位  配置timer0~1的预分频
  8 8~15  配置timer2 3 4预分频
  9 TCFG1  设置5个timer的二级分频
 10 TCON  pwm定时器的控制寄存器
 11 [0]  定时器0的开关
 12 [1]   将TCNTB0和TCMPB0的值分别写入定时器0内部
 13 注意一点,写入的操是瞬间完成,写完之后要立即把该位清0
 14 否则,写入的操作将会连续不断的持续进行,那么定时器就无法计数
 15 [2]  输出电平的极性,参照1300 ,该值会影响到占空比的计算
 16 [3]  单次开启还是连续开启  (每个计数周期结束之后会自动将TCMB0写入计数器中,开始新的周期)
 17 
 18 TINT_CSTAT  使能和清除,对应的中断
 19 
 20 
 21 linux 内核  设备和设备分离
 22 
 23 */  
 24 #include <linux/module.h>
 25 #include <linux/init.h>
 26 #include <linux/kernel.h> //printk
 27 
 28 #include <linux/miscdevice.h> //misc_register....
 29 #include <linux/fs.h> //file_operations
 30 #include <mach/regs-gpio.h> //S5P_VA_GPIO2
 31 #include <linux/ioport.h> //request_mem_region
 32 
 33 #include <linux/io.h>
 34 
 35 #include "pwm_ctl.h"
 36 
 37 #define DEVNAME "ldm"
 38 
 39 
 40 #define TCFG0   (*(volatile u32 *)ioremap(0x139d0000, 4))
 41 #define TCFG1    (*(volatile u32 *)ioremap(0x139d0004, 4))
 42 #define TCON    (*(volatile u32 *)ioremap(0x139d0008, 4))
 43 #define TCNTB0  (*(volatile u32 *)ioremap(0x139d000c, 4))
 44 #define TCMPB0  (*(volatile u32 *)ioremap(0x139d0010, 4))
 45 #define TINT_CSTAT  (*(volatile u32 *)ioremap(0x139d0044, 4))
 46 
 47 #define GPD0CON    (*(volatile u32 *)ioremap(0x114000a0, 4))
 48 
 49 struct   ldm_info 
 50 {
 51     struct miscdevice dev;
 52     struct file_operations  ops;
 53 };
 54 
 55 struct ldm_info ldm;
 56 
 57 //跟时钟配置相关
 58 
 59 
 60 // int pwm_init()
 61 // {
 62 //     //GPD0CON 配置成复用模式
 63 
 64 //     //设置频率
 65 
 66 //     //设置TCNTB0  TCMPB0  两个寄存器
 67 //     //提供应用层相关的接口
 68 
 69 //     //把TCNTB0  和  TCMPB0  加载到 定时器中
 70 //     TCON  |=   1 << 1;
 71 //     TCON  &= ~(1 << 1);
 72 
 73 //     //打开定时器,开启连续触发的模式
 74 
 75 
 76 //     //加入到misc 子系统中 以提供给用户层访问
 77 
 78 
 79 static inline void timer0_cout_set(u32  cmp, u32  cnt)
 80 {
 81     TCNTB0 = cnt;
 82     TCMPB0 = cmp;
 83 
 84     TCON  |=   1 << 1;
 85     TCON  &= ~(1 << 1);
 86 }
 87 
 88 long ldm_ioctl(struct file *  file, unsigned int  cmd, unsigned long arg)
 89 {
 90 
 91     switch(cmd) {
 92         case SET_CMP:
 93             timer0_cout_set(arg, TIMER0_KHZ /2);
 94             break;
 95         default:
 96             break;
 97     }
 98     return 0;
 99 }
100 
101 static int ldm_init(void)
102 {
103     int ret = 0;
104     printk("%s:%s, %d
", __FILE__, __FUNCTION__, __LINE__);
105 
106     ////GPD0CON 配置成复用模式
107     GPD0CON = (GPD0CON & ~0xf) | 0x2;
108 
109     //设置频率
110     TCFG0 = (TCFG0 & ~0xff) | PWM_PRESCALER0;
111     TCFG1 = (TCFG1 & ~0xf) | DIV;
112 
113     //占空比为50%
114     timer0_cout_set(TIMER0_KHZ/4, TIMER0_KHZ /2);
115 
116     //把TCNTB0  和  TCMPB0  加载到 定时器中
117     TCON  |=   1 << 1;
118     TCON  &= ~(1 << 1);
119 
120     //打开定时器,选择连续触发模式
121     TCON &= ~(1 << 2);
122     TCON |=  1<< 3 | 1;
123 
124     //给应用层提供接口
125     ldm.dev.minor =  MISC_DYNAMIC_MINOR;
126     ldm.dev.name  = DEVNAME;
127     ldm.dev.fops = &ldm.ops;
128     ldm.ops.unlocked_ioctl = ldm_ioctl;
129 
130     ret = misc_register(&ldm.dev);
131     if(ret < 0) {
132         printk("misc_register  failed
");
133         goto err_misc_register;
134     }
135 
136     return 0;
137 err_misc_register:
138     return -1;
139 
140 }
141 
142 static void ldm_exit(void)
143 {
144     printk("%s:%s, %d
", __FILE__, __FUNCTION__, __LINE__);
145     misc_deregister(&ldm.dev);
146 }
147 
148 
149 
150 module_init(ldm_init);
151 module_exit(ldm_exit);
152 MODULE_LICENSE("GPL");

.h

 1 #pragma once
 2 
 3 #include <linux/ioctl.h>
 4 //参考下内核文档 linux/linux-3.5/Documentation/ioctl
 5 //ioctl-decoding.txt  和 ioctl-number.txt
 6 //例如 实现  控制LED灯
 7 /*
 8 _IO (魔数, 基数);
 9 • _IOR (魔数, 基数, 变量型)
10 • _IOW (魔数, 基数, 变量型)
11 • _IOWR (魔数, 基数,变量型 )
12 */
13 
14 enum 
15 {    
16     //4412  P446  100MHZ
17     PCLK_PERIL = 100000000,
18     PWM_PRESCALER0 = 99,
19     DIV =  4,
20 
21     TIMER0_HZ = PCLK_PERIL / (PWM_PRESCALER0 + 1) / 16,
22     TIMER0_KHZ  = TIMER0_HZ /1000,
23 };
24 
25 //
26 #define  SET_CMP   _IOW('l', 1, unsigned int)
27 //底层的驱动生成的一系列 命令  这个头文件同样也需要提供给应用层
28 
29 #define DUTY_0   TIMER0_KHZ/2
30 //#define DUTY_25 
31 #define DUTY_50    TIMER0_KHZ/4
32 //#define DUTY_75
33 #define DUTY_100   0

.app

//应用层
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

#include "pwm_ctl.h"


int main(int argc, char const *argv[])
{


    int fd = open("/dev/ldm", O_RDWR);
    if(fd < 0) {
           perror("open");
           goto err_open;
    }



    //ioctl(fd, LED_STATUS, led_status);
    //ioctl(fd, LED1_ON);
    ioctl(fd, SET_CMP, DUTY_100);

    close(fd);

    return 0;

err_open:
    return -1;
}
原文地址:https://www.cnblogs.com/baoshulin/p/6477014.html