完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛|
|
|
相关推荐
1个回答
|
|
|
在使用串口DMA试验过程中,遇到了一些问题,通过试验找到了问题所在,也对DMA的应用有了新的认识,仅以此分享给大家,不足之处请多多指教。
DMA初始化 // 串口对应的DMA请求通道 #define USART_TX_DMA_CHANNEL DMA1_Channel4 #define USART_TX_DMA_IRQ DMA1_Channel4_IRQn #define USART_TX_DMA_IRQHandler DMA1_Channel4_IRQHandler // 外设寄存器地址 #define USART_DR_ADDRESS (USART1_BASE+0x04) // 一次发送的数据量 #define SENDBUFF_SIZE 250 /** * @brief USARTx TX DMA 配置,内存到外设(USART1->DR) * @param 无 * @retval 无 */ void USARTx_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(USART_TX_DMA_CHANNEL); // 开启DMA时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 设置DMA源地址:串口数据寄存器地址*/ DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS; // 内存地址(要传输的变量的指针) DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; // 方向:从内存到外设 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 传输大小 DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; // 外设地址不增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 内存地址自增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 外设数据单位 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 内存数据单位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // DMA模式,一次或者循环模式 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //单次模式,需要手动加载数据传输数量 // DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //自动重载数据传输数量 // 优先级:中 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 禁止内存到内存的传输 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 配置DMA通道 DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure); NVIC_DMA_Configuration(); // 使能DMA DMA_Cmd(USART_TX_DMA_CHANNEL,DISABLE); //使能DMA传送完成中断 DMA_ITConfig(USART_TX_DMA_CHANNEL,DMA_IT_TC,ENABLE); } 在本次试验中,主要遇到的问题是:DMA模式配置为单次模式(DMA_Mode_Normal),这样在完成一次数据发送后通道传输数量寄存器CNDTR数值为0,根据手册介绍:当CNDTR为0 时,即使通道开启,都不会发生任何数据传输。所以在下一次数据传输时,需要重新配置CNDTR寄存器。 我这里是自己写了一个函数配置CNDTR寄存器。需要注意的是:CNDTR寄存器只有在通道不工作(DMA_CCRx的EN=0)时才可以写入数据。 void USART_DMA_Enable(void) { USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE); DMA_Cmd(USART_TX_DMA_CHANNEL, DISABLE ); //关闭 USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(USART_TX_DMA_CHANNEL,SENDBUFF_SIZE);//设置 DMA 缓存的大小 DMA_Cmd(USART_TX_DMA_CHANNEL, ENABLE); //使能 USART1 TX DMA1 所指示的通道 } DMA的循环模式 针对上面的问题,还可以使用DMA的循环模式进行解决。 在DMA循环模式下,CNDTR寄存器内容变为0时,将自动重载为之前配置的值。不需要手动重载。 当然这种模式下需要注意的是,当通道开启时,会一直进行数据传输。所以需要在一次数据传输完成后,关闭DMA通道。 我这里是使用的DMA中断,在中断中关闭DMA通道。 void USART_TX_DMA_IRQHandler(void) { // if(DMA_GetITStatus(DMA1_IT_TC4) != RESET) // { // DMA_ClearITPendingBit(DMA1_IT_TC4); DMA_Cmd (USART_TX_DMA_CHANNEL,DISABLE); DMA_ClearFlag(DMA1_FLAG_TC4|DMA1_FLAG_GL4|DMA1_FLAG_HT4);//清除通道 4 传输完成标志 // 使能串口发送中断 USART_ITConfig(DEBUG_USARTx, USART_IT_TC, ENABLE); // } } 循环模式 下,发送数据只要使能DMA通道即可,不需要重新设置CNDTR寄存器 void USART_DMA_Enable(void) { USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE); // DMA_Cmd(USART_TX_DMA_CHANNEL, DISABLE ); //关闭 USART1 TX DMA1 所指示的通道 // DMA_SetCurrDataCounter(USART_TX_DMA_CHANNEL,SENDBUFF_SIZE);//设置 DMA 缓存的大小 DMA_Cmd(USART_TX_DMA_CHANNEL, ENABLE); //使能 USART1 TX DMA1 所指示的通道 } 综上所述,建议无论DMA模式是单次还是循环,在DMA初始化时先关闭DMA通道,在需要数据传输时再打开。 |
|
|
|
|
只有小组成员才能发言,加入小组>>
1599 浏览 0 评论
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
4738 浏览 0 评论
4229 浏览 9 评论
3822 浏览 16 评论
4398 浏览 1 评论
4210浏览 3评论
2379浏览 0评论
3393浏览 0评论
1158浏览 0评论
2843浏览 0评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-2 03:17 , Processed in 0.709217 second(s), Total 74, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
2758