AT9G45的pwm驱动有问题,快来解救小弟.

来源:互联网 发布:广告牌设计软件下载 编辑:程序博客网 时间:2024/05/22 03:27

 AT9G45的pwm,头文件

#ifndef AT91_PWM_H#define AT91_PWM_H#define PWMC_BASE 0xfffb8000/****************  pwm模式寄存器偏移0x00  *****************/#define PWM_MR_OFF              0x00000000    ///< PWM Mode Register offset.#define PWM_MR     (*((volatile unsigned long *)(PWMC_BASE + PWM_MR_OFF))) ///< PWM Mode Register.#define PWM_MR_DIVA_MASK        0x000000FF    ///< PWM Mode Divide factor A Mask.#define PWM_MR_DIVA_SHIFT       0             ///< PWM Mode Divide factor A LSB.#define PWM_MR_DIVB_MASK        0x00FF0000    ///< PWM Mode Divide factor B Mask.#define PWM_MR_DIVB_SHIFT       16            ///< PWM Mode Divide factor B LSB.#define PWM_MR_PREA_MASK        0x00000F00    ///< PWM Mode prescaler A Mask.#define PWM_MR_PREA_SHIFT       8             ///< PWM Mode prescaler A LSB.#define PWM_MR_PREB_MASK        0x0F000000    ///< PWM Mode prescaler B Mask.#define PWM_MR_PREB_SHIFT       24            ///< PWM Mode prescaler B LSB.#define PWM_MR_PRE_MCK          0             ///< PWM Mode prescaler set to MCK.#define PWM_MR_PRE_MCK_DIV2     1             ///< PWM Mode prescaler set to MCK/2.#define PWM_MR_PRE_MCK_DIV4     2             ///< PWM Mode prescaler set to MCK/4.#define PWM_MR_PRE_MCK_DIV8     3             ///< PWM Mode prescaler set to MCK/8.#define PWM_MR_PRE_MCK_DIV16    4             ///< PWM Mode prescaler set to MCK/16.#define PWM_MR_PRE_MCK_DIV32    5             ///< PWM Mode prescaler set to MCK/32.#define PWM_MR_PRE_MCK_DIV64    6             ///< PWM Mode prescaler set to MCK/64.#define PWM_MR_PRE_MCK_DIV128   7             ///< PWM Mode prescaler set to MCK/128.#define PWM_MR_PRE_MCK_DIV256   8             ///< PWM Mode prescaler set to MCK/256.#define PWM_MR_PRE_MCK_DIV512   9             ///< PWM Mode prescaler set to MCK/512.#define PWM_MR_PRE_MCK_DIV1024  10            ///< PWM Mode prescaler set to MCK/1024.#define PWM_CHID_MASK           0x0000000F#define PWM_CHID0               0#define PWM_CHID1               1#define PWM_CHID2               2#define PWM_CHID3               3/***********************  pwm使能寄存器偏移0x04  *****************/#define PWM_ENA_OFF             0x00000004    ///< PWM Enable Register offset.#define PWM_ENA     (*((volatile unsigned long *)(PWMC_BASE + PWM_ENA_OFF))) ///< PWM Enable Register./***********************  pwm去使能寄存器0x08  *****************/#define PWM_DIS_OFF             0x00000008    ///< PWM Disable Register offset.#define PWM_DIS     (*((volatile unsigned long *)(PWMC_BASE + PWM_DIS_OFF))) ///< PWM Disable Register./*********************  pwm状态寄存器0x0C  *****************/#define PWM_SR_OFF              0x0000000C    ///< PWM Status Register offset.#define PWM_SR      (*((volatile unsigned long *)(PWMC_BASE + PWM_SR_OFF)))  ///< PWM Status Register./**********************  pwm中断使能寄存器0x10 *****************/#define PWM_IER_OFF             0x00000010    ///< PWM Interrupt Enable Register offset.#define PWM_IER     (*((volatile unsigned long *)(PWMC_BASE + PWM_IER_OFF))) ///< PWM Interrupt Enable Register./**********************  pwm中断去使能寄存器0x14  *****************/#define PWM_IDR_OFF             0x00000014    ///< PWM Interrupt Disable Register offset.#define PWM_IDR     (*((volatile unsigned long *)(PWMC_BASE + PWM_IDR_OFF))) ///< PWM Interrupt Disable Register./**********************  pwm中断掩码寄存器0x18  *****************/#define PWM_IMR_OFF             0x00000018    ///< PWM Interrupt Mask Register offset.#define PWM_IMR     (*((volatile unsigned long *)(PWMC_BASE + PWM_IMR_OFF))) ///< PWM Interrupt Mask Register./**********************  pwm中断状态寄存器0x1c  *****************/#define PWM_ISR_OFF             0x0000001C    ///< PWM Interrupt Status Register offset.#define PWM_ISR     (*((volatile unsigned long *)(PWMC_BASE + PWM_ISR_OFF))) ///< PWM Interrupt Status Register./**********************  pwm通道模式寄存器 0x200+ch_num*0x20+0x00  *****************/#define PWM_CH0_OFF             0x00000200    ///< PWM Channel 0 registers offset.#define PWM_CH1_OFF             0x00000220    ///< PWM Channel 1 registers offset.#define PWM_CH2_OFF             0x00000240    ///< PWM Channel 2 registers offset.#define PWM_CH3_OFF             0x00000260    ///< PWM Channel 3 registers offset.#define PWM_CMR_OFF             0x00000000    ///< PWM Channel Mode Register offset.#define PWM_CMR0    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Mode Register.#define PWM_CMR1    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Mode Register.#define PWM_CMR2    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Mode Register.#define PWM_CMR3    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Mode Register.#define PWM_CPRE_MCK_MASK       0x0000000F    ///< PWM Mode prescaler mask.#define PWM_CPRE_MCK            0             ///< PWM Mode prescaler set to MCK.#define PWM_CPRE_MCK_DIV2       1             ///< PWM Mode prescaler set to MCK/2.#define PWM_CPRE_MCK_DIV4       2             ///< PWM Mode prescaler set to MCK/4.#define PWM_CPRE_MCK_DIV8       3             ///< PWM Mode prescaler set to MCK/8.#define PWM_CPRE_MCK_DIV16      4             ///< PWM Mode prescaler set to MCK/16.#define PWM_CPRE_MCK_DIV32      5             ///< PWM Mode prescaler set to MCK/32.#define PWM_CPRE_MCK_DIV64      6             ///< PWM Mode prescaler set to MCK/64.#define PWM_CPRE_MCK_DIV128     7             ///< PWM Mode prescaler set to MCK/128.#define PWM_CPRE_MCK_DIV256     8             ///< PWM Mode prescaler set to MCK/256.#define PWM_CPRE_MCK_DIV512     9             ///< PWM Mode prescaler set to MCK/512.#define PWM_CPRE_MCK_DIV1024    10            ///< PWM Mode prescaler set to MCK/1024.#define PWM_CPRE_CLKA           11            ///< PWM Mode prescaler set to CLKA.#define PWM_CPRE_CLKB           12            ///< PWM Mode prescaler set to CLKB.#define AT91C_PWMC_CPRE_MCKB                 0xC /**< (PWMC_CH)  */ #define PWM_CALG                8             ///< PWM Mode channel alignment.#define PWM_CPOL                9             ///< PWM Mode channel polarity.#define PWM_CPD                 10            ///< PWM Mode channel update period.#define PWM_CDTY_OFF            0x00000004    ///< PWM Channel Duty Cycle Register offset.#define PWM_CDTY0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Duty Cycle Register.#define PWM_CDTY1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Duty Cycle Register.#define PWM_CDTY2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Duty Cycle Register.#define PWM_CDTY3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Duty Cycle Register.#define PWM_CPRD_OFF            0x00000008    ///< PWM Channel Period Register offset.#define PWM_CPRD0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Period Register.#define PWM_CPRD1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Period Register.#define PWM_CPRD2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Period Register.#define PWM_CPRD3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Period Register.#define PWM_CCNT_OFF            0x0000000C    ///< PWM Channel Counter Register offset.#define PWM_CCNT0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Counter Register.00204#define PWM_CCNT1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Counter Register.#define PWM_CCNT2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Counter Register.#define PWM_CCNT3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Counter Register.#define PWM_CUPD_OFF            0x00000010    ///< PWM Channel Update Register offset.#define PWM_CUPD0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Update Register.#define PWM_CUPD1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Update Register.#define PWM_CUPD2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Update Register.#define PWM_CUPD3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Update Register.extern void PWMC_ConfigureChannel(     unsigned char channel,     unsigned int prescaler,     unsigned int alignment,     unsigned int polarity);  extern void PWMC_ConfigureClocks     (unsigned int clka,      unsigned int clkb,      unsigned int mck);  void PWMC_SetPeriod(unsigned char channel, unsigned short period); void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty); void PWMC_EnableChannel(unsigned char channel); void PWMC_DisableChannel(unsigned char channel); void PWMC_EnableChannelIt(unsigned char channel); void PWMC_DisableChannelIt(unsigned char channel); unsigned short FindClockConfiguration(unsigned int frequency, unsigned int mck);#define trace_DEBUG                     0 #define trace_INFO                      1 #define trace_WARNING                   2 #define trace_ERROR                     3 #define trace_FATAL                     4 #define trace_LEVEL                     0 #define trace_CONFIGURE(mode, baudrate, mck) { \        const Pin pinsDbgu[] = {PINS_DBGU}; \        PIO_Configure(pinsDbgu, PIO_LISTSIZE(pinsDbgu)); \        DBGU_Configure(mode, baudrate, mck); \    } #define trace_LOG(level, ...) { \        if (level >= trace_LEVEL) { \            printk(__VA_ARGS__); \        } \    } #define ASSERT(condition, ...)  { \        if (!(condition)) { \            printk(__VA_ARGS__); \            while (1); \        } \    } #define SANITY_ERROR            "Sanity check failed at %s:%d\n\r" #define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__) #endif /* AT91_PWM_H */

at9g45库文件:

#include "at91_pwm.h"  unsigned short FindClockConfiguration(       unsigned int frequency,       unsigned int mck)   {       unsigned int divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};       unsigned char divisor = 0;       unsigned int prescaler;          SANITY_CHECK(frequency < mck);       // Find prescaler and divisor values       prescaler = (mck / divisors[divisor]) / frequency;       while ((prescaler > 255) && (divisor < 11)) {              divisor++;           prescaler = (mck / divisors[divisor]) / frequency;       }          // Return result       if (divisor < 11) {              trace_LOG(trace_DEBUG, "-D- Found divisor=%d and prescaler=%d for freq=%dHz\n\r",                     divisors[divisor], prescaler, frequency);           return prescaler | (divisor << 8);       }       else {              return 0;       }   }   //------------------------------------------------------------------------------   //         Global functions   //------------------------------------------------------------------------------      //------------------------------------------------------------------------------   /// Configures PWM a channel with the given parameters.   /// The PWM controller must have been clocked in the PMC prior to calling this   /// function.   /// \param channel  Channel number.   /// \param prescaler  Channel prescaler.   /// \param alignment  Channel alignment.   /// \param polarity  Channel polarity.   //------------------------------------------------------------------------------   void PWMC_ConfigureChannel(       unsigned char channel,       unsigned int prescaler,       unsigned int alignment,       unsigned int polarity)   {       SANITY_CHECK(prescaler < PWM_CPRE_CLKB);       SANITY_CHECK((alignment & ~(1 << PWM_CALG)) == 0);       SANITY_CHECK((polarity & ~(1<<PWM_CPOL)) == 0);          // Disable channel       PWM_DIS |= (1 << channel);       // Configure channel       PWM_CMR0 = prescaler | alignment | polarity;   }      //------------------------------------------------------------------------------   /// Configures PWM clocks A & B to run at the given frequencies. This function   /// finds the best MCK divisor and prescaler values automatically.   /// \param clka  Desired clock A frequency (0 if not used).   /// \param clkb  Desired clock B frequency (0 if not used).   /// \param mck  Master clock frequency.   //------------------------------------------------------------------------------   void PWMC_ConfigureClocks(unsigned int clka, unsigned int clkb, unsigned int mck)   {       unsigned int mode = 0;       unsigned int result;          // Clock A       if (clka != 0) {              result = FindClockConfiguration(clka, mck);           ASSERT(result != 0, "-F- Could not generated the desired PWM frequency (%dHz)\n\r", clka);           mode |= result;       }          // Clock B       if (clkb != 0) {              result = FindClockConfiguration(clkb, mck);           ASSERT(result != 0, "-F- Could not generated the desired PWM frequency (%dHz)\n\r", clkb);           mode |= (result << 16);       }          // Configure clocks       trace_LOG(trace_DEBUG, "-D- Setting PWMC_MR = 0x%08X\n\r", mode);       PWM_MR = mode;   }      //------------------------------------------------------------------------------   /// Sets the period value used by a PWM channel. This function writes directly   /// to the CPRD register if the channel is disabled; otherwise, it uses the   /// update register CUPD.   /// \param channel  Channel number.   /// \param period  Period value.   //------------------------------------------------------------------------------   void PWMC_SetPeriod(unsigned char channel, unsigned short period)   {       // If channel is disabled, write to CPRD       if ((PWM_SR & (1 << channel)) == 0) {              PWM_CPRD0 = period;       }       // Otherwise use update register       else {              PWM_CMR0 |= (1 << PWM_CPD);           PWM_CUPD0 = period;       }   }      //------------------------------------------------------------------------------   /// Sets the duty cycle used by a PWM channel. This function writes directly to   /// the CDTY register if the channel is disabled; otherwise it uses the   /// update register CUPD.   /// Note that the duty cycle must always be inferior or equal to the channel   /// period.   /// \param channel  Channel number.   /// \param duty  Duty cycle value.   //------------------------------------------------------------------------------   void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty)   {       SANITY_CHECK(duty <= PWM_CPRD0);           ASSERT(duty > 0, "-F- Duty cycle value 0 is not permitted on SAM7S chips.\n\r");       ASSERT((duty > 1) || (PWM_CMR0 & (1 << PWM_CALG)),              "-F- Duty cycle value 1 is not permitted in left-aligned mode on SAM7S chips.\n\r");          // If channel is disabled, write to CDTY       if ((PWM_SR & (1 << channel)) == 0) {              PWM_CDTY0 = duty;       }       // Otherwise use update register       else {              PWM_CMR0 &= ~(1 << PWM_CPD);           PWM_CUPD0 = duty;       }   }      //------------------------------------------------------------------------------   /// Enables the given PWM channel. This does NOT enable the corresponding pin;   /// this must be done in the user code.   /// \param channel  Channel number.   //------------------------------------------------------------------------------   void PWMC_EnableChannel(unsigned char channel)   {       PWM_ENA |= 1 << channel;   }      //------------------------------------------------------------------------------   /// Disables the given PWM channel.   /// \param channel  Channel number.   //------------------------------------------------------------------------------   void PWMC_DisableChannel(unsigned char channel)   {       PWM_DIS |= 1 << channel;   }      //------------------------------------------------------------------------------   /// Enables the period interrupt for the given PWM channel.   /// \param channel  Channel number.   //------------------------------------------------------------------------------   void PWMC_EnableChannelIt(unsigned char channel)   {       PWM_IER |= 1 << channel;   }      //------------------------------------------------------------------------------   /// Disables the period interrupt for the given PWM channel.   /// \param channel  Channel number.   //------------------------------------------------------------------------------   void PWMC_DisableChannelIt(unsigned char channel)   {       PWM_IDR |= 1 << channel;   }   

at9g45,驱动文件:

#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>           /* everything... */#include <linux/cdev.h>                /* cdev...*/#include <linux/gpio.h>#include <linux/proc_fs.h>#include <asm/uaccess.h>#include "at91_pwm.h"#include "at91_pwm.c"#define DEVICE_NAME "mypwm"static int led_major = 0;static int led_minor = 0;struct cdev *led_device;static void PWM_Set_Freq(int arg){at91_set_gpio_output(AT91_PIN_PD15, 0);//设置PD15为输出模式at91_set_gpio_value(AT91_PIN_PD15, 0);//设置PD15输出为0,表示点亮at91_set_B_periph(AT91_PIN_PD24, 1);/* enable PWM0 */PWMC_ConfigureChannel(0, 1, 2, 3);PWMC_ConfigureClocks(1000, 500, 10);PWMC_SetPeriod(0, 1);PWMC_SetDutyCycle(0, 50);}static void PWM_Stop(void){at91_set_gpio_output(AT91_PIN_PD24, 0);at91_set_gpio_value(AT91_PIN_PD24, 1);return ;}   static int myled_open(struct inode *inode, struct file *filp){PWMC_EnableChannel(0);//这一步在测试驱动的时候总是报内存操作错误at91_set_B_periph(AT91_PIN_PD24, 1);/* enable PWM0 */return 0;}static int myled_release(struct inode *inode, struct file *filp){PWMC_DisableChannel(0); //这一步在测试驱动的时候总是报内存操作错误return 0;}static int myled_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){if (arg > 4){return -1;}switch (cmd){case 0:if (arg == 0)return -1;PWM_Set_Freq(arg);break;//通过cmd命令控制PD15case 1:PWM_Stop();break;}return 0;}struct file_operations led_fops = {.owner =    THIS_MODULE,.open =     myled_open,.release =  myled_release,.ioctl = myled_ioctl,};static void __exit my_led_exit(void){    dev_t devno = MKDEV(led_major, led_minor);//通过主次设备号获得设备号if (led_device){cdev_del(led_device);//删除设备号kfree(led_device);//释放设备号空间led_device = NULL;//设置为空, 防止再次被调用}unregister_chrdev_region(devno, 1);//卸载主设备号    return;}static int __init my_led_init(void){int result = 0;//用来返回结果值dev_t dev = 0;//设备号/***********************分配主次设备号******************/result = alloc_chrdev_region(&dev, led_minor, 1, DEVICE_NAME);//自动分配主设备号led_major = MAJOR(dev);//得到主设备号if (result < 0){printk(KERN_WARNING "wfet_kb: can't get major %d\n", led_major);return result;}/*********************注册字符设备*************************/led_device = kmalloc(sizeof(struct cdev), GFP_KERNEL);//字符设备的全局结构占用的内存要用kmalloc或kzalloc申请if(!led_device){result = -ENOMEM;unregister_chrdev_region(dev, 1);return result;}memset(led_device, 0, sizeof(struct cdev));cdev_init(led_device, &led_fops);//字符设备初始化led_device->owner = THIS_MODULE;result = cdev_add(led_device, dev, 1);//字符设备添加if(result){printk(KERN_NOTICE "Error %d adding LED device, major_%d", result, MAJOR(dev));kfree(led_device);//释放空间unregister_chrdev_region(dev, 1);//注销设备号return result;}    return 0;}module_init(my_led_init)module_exit(my_led_exit)MODULE_LICENSE("GPL");

at9g45测试文件:

#include <stdio.h>#include "at91_ioctl.h"int main(int argc, char** argv){    int fp;    fp = open("/dev/mypwm", 0);    if(fp < 0)    {        printf("Open error!\n");        return -1;    }    ioctl(fp, atoi(argv[1]));    close(fp);    return 0;}


原创粉丝点击