树莓派3 调试pwm:
1.用指令控制硬件pwm
pwm输出频率为4.8Mhz/1024 = 4.6875kHz:
gpio mode 1 pwm #设置pwm引脚功能为pwm
gpio pwm-ms #设置pwm的模式为pwm-ms Mark-Space 模式
gpio pwmr 1024 #设置pwm的范围 1024
gpio pwmc 4 #设置pwm的频率 4 :4.8MHz
gpio pwm 1 512 #设置pwm的占空比 512/1024
其中pwmc的范围是
/*!< 2048 = 9.375kHz */
/*!< 1024 = 18.75kHz */
/*!< 512 = 37.5kHz */
/*!< 256 = 75kHz */
/*!< 128 = 150kHz */
/*!< 64 = 300kHz */
/*!< 32 = 600.0kHz */
/*!< 16 = 1.2MHz */
/*!< 8 = 2.4MHz */
/*!< 4 = 4.8MHz */
/*!< 2 = 9.6MHz, fastest you can get */
/*!< 1 = 4.6875kHz, same as divider 4096 */
2.程序控制硬件pwm
a) 采用bcm2835 C library
b) 下载 wgethttp://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz
c) 解压 tar -zxvf bcm2835-1.50.tar.gz
d) cd bcm2835-1.50/examples/pwm
e) gcc -o pwm -I ../../src ../../src/bcm2835.c pwm.c
f) sudo ./pwm
发现问题:
执行pwm命令后执行该程序有pwm波形输出,重启直接运行该程序没有pwm波形输出。
查看官网关于pwm的函数http://www.airspayce.com/mikem/bcm2835/group__pwm.html
例程中也都用到了这四个函数,接下来查看源码:
$ vi bcm2835-1.50/src/bcm2835.c
其中函数
void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled)
中有读取PWM寄存器中的值,将读取的值打印出来,然后将修改后的值再次打印出来。
printf("control = 0x%02x\n", control);
打印的值分别为
0x2121
0x21a1
查看BCM2835 ARM Peripherals文档,因为BCM2835与BCM2837通用。
PWM中CTL寄存器,其中a1表示10100001 代表启用M/S传送模式、数据传送到FIFO中、启用PWM。
用手册中USEFi bit is used to enable/disable FIFO transfer. When this bit is high data stored in the FIFO is used for transmission. When it is low, data written to PWM_DATi is transferred. This bit is 0 as default.
意思也就是置位启用FIFO传输,清零将数据写入PWM_DAT寄存器中,关键是默认为0。读取出来的是1,所以没有pwm波形输出。
修改代码该源码。将USEFi位清零。
$ vi bcm2835-1.50/src/bcm2835.c
修改bcm2835_pwm_set_mode函数如下:
void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) { if ( bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) return; /* bcm2835_init() failed or not root */ uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); if (channel == 0) { if (markspace) control |= BCM2835_PWM0_MS_MODE; else control &= ~BCM2835_PWM0_MS_MODE; if (enabled) control |= BCM2835_PWM0_ENABLE; else control &= ~BCM2835_PWM0_ENABLE; if(markspace && enabled) control &= ~BCM2835_PWM0_USEFIFO; } else if (channel == 1) { if (markspace) control |= BCM2835_PWM1_MS_MODE; else control &= ~BCM2835_PWM1_MS_MODE; if (enabled) control |= BCM2835_PWM1_ENABLE; else control &= ~BCM2835_PWM1_ENABLE; if(markspace && enabled) control &= ~BCM2835_PWM1_USEFIFO; } /* If you use the barrier here, wierd things happen, and the commands dont work */ bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); /* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */ }
编译,重启再次执行该函数,有波形输出。