【STM32】DMA还能这么用?(定时器触发USART的DMA传输)
前段时间,在看STM32F030例程的时候,看到了DMA的一种新奇的用法,是我没有用过的,在理解以后,在串口上面实践了一下,感觉对DMA的认识更深了一点,拿来给大家分享一下。
想高效的定时发送串口数据,不过多占用CPU资源的方法:利用定时器可以通过更新事件产生DMA请求,在DMA配置外设地址为串口地址,这样就可以通过定时器的计数器更新事件周期性传输串口数据:
关于定时器配置如下:
void TIM6_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/*设置更新时间为1s*/
TIM_TimeBaseStructure.TIM_Prescaler = ((8000000 / 1000) - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 1000;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
TIM_Cmd(TIM6, ENABLE);
/*使能TIM6的更新DMA请求*/
TIM_DMACmd(TIM6,TIM_DMA_Update,ENABLE);
}
关于DMA配置:
void DMA_Config(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel3);
/*外设地址设置为串口的发送数据寄存器*/
DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)(&USART1->TDR));
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)txbuf;
/*从内存读取数据*/
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
/*传输10个数据*/
DMA_InitStructure.DMA_BufferSize = 10;
/*外设地址不自增*/
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/*内存地址自增*/
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/*数据以字传输*/
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
/*循环模式*/
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel3,ENABLE);
}
串口正常使能:
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_PinAFConfig(GPIOA,GPIO._PinSource10,GPIO_AF_1);
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置波特率
USART_InitStructure.USART_BaudRate = 115200;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 配置校验位
USART_InitStructure.USART_Parity = USART_Parity_No ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(USART1, &USART_InitStructure);
// 使能串口
USART_Cmd(USART1, ENABLE);
}
总的时序图如下:
原来我对DMA的刻板认识是,如果想用DMA搬移数据到外设,需要外设自身使能DMA请求,但是在理解这种用法后,对DMA有了更深一步的认识,对于DMA本身来说,只要有DMA请求,它就会按照预定的源地址和目的地址进行传输,而DMA请求的来源不一定要和DMA数据搬运地相关。
作者:一个人的嵌入式~