在之前做飞思卡尔智能车比赛时接触过K60的DMA ,用DMA 可以采集图像,也可以用DMA 来测速。
概念相信大家都清楚:所谓 DMA就是直接内存取( Direct Memory Access ),是计算机科学中的一种内存访问技术。
书上说,DMA 模块可以不占用CPU 自行传输数据,能够减轻CPU 的负担,然而具体原理是怎样的呢?为什么DMA 能够不需要CPU 的介入呢?我查阅了相关资料,大概地了解了些。
在STM32中,DMA 单元和Cortex CPU之间对总线使用一种交叉存取的机制。DMA 传输遵循相应的传输流程。其中,在数据从内存传输到内存的情况下,每传输一个字要消耗5个时钟周期:1个读周期,1个写周期,插入3个空闲周期供CPU 使用。所以,每个DMA 通道都只是在总线存取周期才会占用总线,即使传输大量数据,DMA 单元最大也只会消耗40%的数据总线带宽。
所以说,STM32中的DMA 与CPU 对总线的使用方式是交叉式的。
在K60中,DMA 是通过DMA 控制器接管接管数据和地址总线。如果CPU 正在执行指令,DMA 控制利用空闲的地址和数据总线完成数据传送,某种程度上说,CPU 运算和数据传送是在并行进行的。K60的DMA 数据的传送分为主循环(major loop )和副循环(minor loop)。major loop循环一次,可能需要minor loop循环多次。每个minor loop 循环都需要DMA 源发来请求或者通过软件请求。每个minor loop 传送完毕,对应的DMA 通道就进入空闲模式,等待下一次DMA 请求。当所有DMA 传送完毕,即置DONE 标志,并且可以通过设置选择传送完毕是否触发中断。此外,可以通过相关寄存器设置,使用Kinetis 的DMA 模块的主/副循环链接功能、散/聚模式、副循环映射。
对DMA 模块的相应的寄存器进行初始化后,便可开启DMA 功能。例如(K60例程): 以智能车摄像头组图采集应用为例。使GPIO 口 D0~D7采集数字摄像头OV7620的 8位灰度输出,使用引脚位灰度输出,使用引脚 A19输入像素同步脉冲pclk4分频后的信号,上升沿触发分频后的信号,上升沿触发DMA 请求。每行采集点数为 V,通过 DMA传送到到 video 数组。一行采集完成后关闭 DMA 硬件请求,进入 DMA中断,使用 DMA 通道 0:
[plain]view plaincopyprint?
1. void DMA0_Init(void)
2. {
3. SIM_SCGC6|=SIM_SCGC6_DMAMUX_MASK;//打开DMA 多路复用时钟
4. SIM_SCGC7|=SIM_SCGC7_DMA_MASK;//打开DMA 模块时钟
5. DMAMUX_CHCFG0=DMAMUX_CHCFG_SOURCE(49);//DMA通道0对应49号DMA 请求,即PORTA
6. DMA_TCD0_CITER_ELINKNO=DMA_CITER_ELINKNO_CITER(V);//当前主循环次数,采集点数
7. DMA_TCD0_BITER_ELINKNO=DMA_BITER_ELINKNO_BITER(V);//起始主循环次数,采集点数
8. DMA_TCD0_SADDR=(uint32)&GPIOD_PDIR;//设置源地址GPIO 口,PORTD
9. DMA_TCD0_SOFF=0;//每次传送源地址不变 DMA_TCD0_NBYTES_MLNO=DMA_NBYTES_MLNO_NBYTES(1);//每次读取一字节
11. DMA_TCD0_SLAST=0;//主循环结束后源地址不变
12. DMA_TCD0_DLASTSGA=0;//主循环结束后目的地址不调整,自动指向下一行数组第一个元素
13. DMA_TCD0_DADDR=(uint32)video;//设置目的地址,video 数组第一个元素
14. DMA_TCD0_DOFF=1;//每次写目的地址加1
15. DMA_TCD0_ATTR=DMA_ATTR_SSIZE(0)+DMA_ATTR_DSIZE(0);//源数据8bit, 目的数据
8bit
16. DMA_TCD0_CSR=DMA_CSR_DREQ_MASK;//通道0主循环结束后停止硬件请求
17. DMA_TCD0_CSR|=DMA_CSR_INTMAJOR_MASK;//使能DMA0中断
18. DMAMUX_CHCFG0|=DMAMUX_CHCFG_ENBL_MASK;//DMA通道0使能
19. }
DMA 的中断服务函数中可登记采集的行数:
[plain]view plaincopyprint?
1. void DMA_CH0_ISR(void)
2. {
3. DMA_INT|=DMA_INT_INT0_MASK;//清除通道0中断 10.
4. row_F[imagerow]=1;//采集完成标志
5. imagerow++;
6. }
顺便提一句,用DMA 测速,就是把编码器或者光电马盘的脉冲当做DMA 请求信号,在周期中断中读相应寄存器的值,再考虑上是否溢出,经过简单计算((DMA_MAX_NUM - DMA_BASE_PTR->TCD[DMA_CH0].CITER_ELINKNO)+
DMA_MAX_NUM*ch0_over_cnt),便可得出一定时间内的脉冲数,便可用于测速。
在之前做飞思卡尔智能车比赛时接触过K60的DMA ,用DMA 可以采集图像,也可以用DMA 来测速。
概念相信大家都清楚:所谓 DMA就是直接内存取( Direct Memory Access ),是计算机科学中的一种内存访问技术。
书上说,DMA 模块可以不占用CPU 自行传输数据,能够减轻CPU 的负担,然而具体原理是怎样的呢?为什么DMA 能够不需要CPU 的介入呢?我查阅了相关资料,大概地了解了些。
在STM32中,DMA 单元和Cortex CPU之间对总线使用一种交叉存取的机制。DMA 传输遵循相应的传输流程。其中,在数据从内存传输到内存的情况下,每传输一个字要消耗5个时钟周期:1个读周期,1个写周期,插入3个空闲周期供CPU 使用。所以,每个DMA 通道都只是在总线存取周期才会占用总线,即使传输大量数据,DMA 单元最大也只会消耗40%的数据总线带宽。
所以说,STM32中的DMA 与CPU 对总线的使用方式是交叉式的。
在K60中,DMA 是通过DMA 控制器接管接管数据和地址总线。如果CPU 正在执行指令,DMA 控制利用空闲的地址和数据总线完成数据传送,某种程度上说,CPU 运算和数据传送是在并行进行的。K60的DMA 数据的传送分为主循环(major loop )和副循环(minor loop)。major loop循环一次,可能需要minor loop循环多次。每个minor loop 循环都需要DMA 源发来请求或者通过软件请求。每个minor loop 传送完毕,对应的DMA 通道就进入空闲模式,等待下一次DMA 请求。当所有DMA 传送完毕,即置DONE 标志,并且可以通过设置选择传送完毕是否触发中断。此外,可以通过相关寄存器设置,使用Kinetis 的DMA 模块的主/副循环链接功能、散/聚模式、副循环映射。
对DMA 模块的相应的寄存器进行初始化后,便可开启DMA 功能。例如(K60例程): 以智能车摄像头组图采集应用为例。使GPIO 口 D0~D7采集数字摄像头OV7620的 8位灰度输出,使用引脚位灰度输出,使用引脚 A19输入像素同步脉冲pclk4分频后的信号,上升沿触发分频后的信号,上升沿触发DMA 请求。每行采集点数为 V,通过 DMA传送到到 video 数组。一行采集完成后关闭 DMA 硬件请求,进入 DMA中断,使用 DMA 通道 0:
[plain]view plaincopyprint?
1. void DMA0_Init(void)
2. {
3. SIM_SCGC6|=SIM_SCGC6_DMAMUX_MASK;//打开DMA 多路复用时钟
4. SIM_SCGC7|=SIM_SCGC7_DMA_MASK;//打开DMA 模块时钟
5. DMAMUX_CHCFG0=DMAMUX_CHCFG_SOURCE(49);//DMA通道0对应49号DMA 请求,即PORTA
6. DMA_TCD0_CITER_ELINKNO=DMA_CITER_ELINKNO_CITER(V);//当前主循环次数,采集点数
7. DMA_TCD0_BITER_ELINKNO=DMA_BITER_ELINKNO_BITER(V);//起始主循环次数,采集点数
8. DMA_TCD0_SADDR=(uint32)&GPIOD_PDIR;//设置源地址GPIO 口,PORTD
9. DMA_TCD0_SOFF=0;//每次传送源地址不变 DMA_TCD0_NBYTES_MLNO=DMA_NBYTES_MLNO_NBYTES(1);//每次读取一字节
11. DMA_TCD0_SLAST=0;//主循环结束后源地址不变
12. DMA_TCD0_DLASTSGA=0;//主循环结束后目的地址不调整,自动指向下一行数组第一个元素
13. DMA_TCD0_DADDR=(uint32)video;//设置目的地址,video 数组第一个元素
14. DMA_TCD0_DOFF=1;//每次写目的地址加1
15. DMA_TCD0_ATTR=DMA_ATTR_SSIZE(0)+DMA_ATTR_DSIZE(0);//源数据8bit, 目的数据
8bit
16. DMA_TCD0_CSR=DMA_CSR_DREQ_MASK;//通道0主循环结束后停止硬件请求
17. DMA_TCD0_CSR|=DMA_CSR_INTMAJOR_MASK;//使能DMA0中断
18. DMAMUX_CHCFG0|=DMAMUX_CHCFG_ENBL_MASK;//DMA通道0使能
19. }
DMA 的中断服务函数中可登记采集的行数:
[plain]view plaincopyprint?
1. void DMA_CH0_ISR(void)
2. {
3. DMA_INT|=DMA_INT_INT0_MASK;//清除通道0中断 10.
4. row_F[imagerow]=1;//采集完成标志
5. imagerow++;
6. }
顺便提一句,用DMA 测速,就是把编码器或者光电马盘的脉冲当做DMA 请求信号,在周期中断中读相应寄存器的值,再考虑上是否溢出,经过简单计算((DMA_MAX_NUM - DMA_BASE_PTR->TCD[DMA_CH0].CITER_ELINKNO)+
DMA_MAX_NUM*ch0_over_cnt),便可得出一定时间内的脉冲数,便可用于测速。