完善资料让更多小伙伴认识你,还能领取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通道,在需要数据传输时再打开。 |
|
|
|
只有小组成员才能发言,加入小组>>
2947 浏览 9 评论
2667 浏览 16 评论
3197 浏览 1 评论
8388 浏览 16 评论
3751 浏览 18 评论
6910浏览 6评论
求助,请问MS51FB9AE带隙电压能作为侦测的基准电压吗?
7430浏览 3评论
6937浏览 3评论
支持UART-to-BLE透传的新唐NuTool – BLE ATCMD开发工具推荐
5784浏览 3评论
9351浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-3-29 04:22 , Processed in 0.652283 second(s), Total 47, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 深圳华秋电子有限公司
电子发烧友 (电路图) 粤公网安备 44030402000349 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号