串口使用DMA发送,使用DMA_Mode_Normal模式,怎么来手动触发发送?

串口使用DMA发送,使用DMA_Mode_Normal模式,怎么来手动触发发送?

DMA设置如下:

void bsp_InitHardUart(void)

{

    GPIO_InitTypeDef GPIO_InitStructure = {0};

    USART_InitTypeDef USART_InitStructure = {0};

    DMA_InitTypeDef DMA_InitStructure = {0};

    NVIC_InitTypeDef NVIC_InitStructure = {0};


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, ENABLE);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


    // USART1 TX->B.6   RX->B.7

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;

    GPIO_Init(GPIOB, &GPIO_InitStructure);


    // USART1重映射至PB6、PB7

    GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);


    // 配置串口1

    USART_DeInit(USART1);

    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_Tx | USART_Mode_Rx;

    USART_Init(USART1, &USART_InitStructure);


    // 配置DMA

    DMA_DeInit(DMA1_Channel4);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DATAR;

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ucaTxBuffer;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitStructure.DMA_BufferSize = FRAME_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_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel4, &DMA_InitStructure);


    DMA_DeInit(DMA1_Channel5);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DATAR;

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ucaRxBuffer;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

    DMA_InitStructure.DMA_BufferSize = FRAME_SIZE;

    DMA_Init(DMA1_Channel5, &DMA_InitStructure);


    // 启用 USART DMA 接口

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);


    // 使能 DMA 通道传输

    DMA_Cmd(DMA1_Channel4, ENABLE); // USART1_TX

    DMA_Cmd(DMA1_Channel5, ENABLE); // USART1_RX


    // 设置中断优先级

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         // IRQ通道

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级别

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        // 从优先级别

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 使能

    NVIC_Init(&NVIC_InitStructure);


    // 使能串口接收中断

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 使能串口

    USART_Cmd(USART1, ENABLE);

}


你好,在DMA正常模式下,当DMA传输完一次需要启动第二次传输时,需要关闭DMA对应的通道,对CNTR寄存器进行赋值,同时如若需要修改传输的Buff ,也需要将待传输的数据地址重新赋值给MADDR寄存器,后再使能DMA通道开启第二次传输。如图是个参考:

image.png


我现在只重新给CNTR寄存器数据长度就可以重新发了,我的缓冲区位置不变,只改了内容,重新CNTR赋值就可以触发发送了,这样没有啥问题吧?


这个不用,数据地址不变的话不用重新赋值。CNTR需要重新复制的原因见下面手册:

image.png


就是这个寄存器递减没了,所以在上面初始化完后的基础上,我每次改好缓冲区的内容后,调用了

DMA_SetCurrDataCounter(DMA1_Channel4, usLength);

这个函数,数据就发送出去了,不过为了确保数据能正常发送,确实需要再次打开DMA对应的通道。


DMA_Cmd(USARTx_DMA_CHN_Tx[idx], DISABLE);                       //关DMA_ChannelTx修改参数
DMA_ClearFlag(USARTx_DMA_FLAG_Tx[idx]);                         // 清除DMA1_IT_TC传输完成标志
DMA_SetCurrDataCounter(USARTx_DMA_CHN_Tx[idx], TxLen);          // 设置数据发送长度
USART_Cmd(USARTx[idx], ENABLE);                                 // 开启串口X
USART_DMACmd(USARTx[idx], USART_DMAReq_Tx, ENABLE);             // 开启串口DMATx
DMA_Cmd(USARTx_DMA_CHN_Tx[idx], ENABLE);                        // 开启DMA_ChannelTx

0处理完成要发送的数据,1关闭DMA,2清标志,3设长度,4开串口,5开DMA Tx,6开DMA....我一直都是这样用的,不知道有没有错。

因为曾经发现不关闭会被干扰得很烦人,所以现在都习惯不用时都关掉串口、关掉DMA。


只有登录才能回复,可以选择微信账号登录