cancel
Showing results for 
Search instead for 
Did you mean: 

Usart TX with DMA : it doesn't send all buffer data

Thomas Lotz
Associate II
Posted on September 14, 2017 at 11:35

Hello,

I try to use Usart Tx with DMA on a STM32L052K6, in order to send a string

without needing to send each character independently.

I don't use ISR. The Usart TX works well without DMA using HAL functions.

The problem : when I call my function UsartTxData, there is only 2 bytes that are transferred, whereas my string is 13 characters. I've checked with debugger that CNDTR is correctly loaded to the value 13.

As soon as TCIF = 1, there is only 2 bytes transferred instead of 13, I've check Tx signal with oscilloscope.

I can not find out the problem, can you please help me ?

Thanks !

Thomas

Main  :

char msg[20] = 'page keybd   ';

#define BUFFER_SIZE        50

char TxBuffer[BUFFER_SIZE];

while(1)

{

    UsartTxData(msg);

    for(i=0;i<1000000;i++) RestartWdt();  // Delay

}

void UsartInit(void)

{

    GPIO_InitTypeDef GPIO_InitStruct;

    // Peripheral clock enable

    __USART1_CLK_ENABLE();

    // USART1 GPIO Configuration

    // PB6     ------> USART1_TX

    // PB7     ------> USART1_RX

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_PULLUP;

    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF0_USART1;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // DMA controller clock enable

    RCC->AHBENR |= RCC_AHBENR_DMA1EN;

    // Remap DMA channel2 on USART TX

    DMA1_CSELR->CSELR |= 0x011 << DMA_CSELR_C2S_Pos;

    // Configure the peripheral data register address

    DMA1_Channel2->CPAR = (uint32_t) (&(USART1->TDR));

    // Configure the memory address

    DMA1_Channel2->CMAR = (uint32_t)(TxBuffer);

    // Memory to memory transfer

    DMA1_Channel2->CCR |= DMA_CCR_MEM2MEM;

    // Memory increment mode enabled

    DMA1_Channel2->CCR |= DMA_CCR_MINC;

    // Data transfer direction, Read from memory

    DMA1_Channel2->CCR |= DMA_CCR_DIR;

    huart1.Instance = USART1;

    huart1.Init.BaudRate = 9600;

    huart1.Init.WordLength = UART_WORDLENGTH_8B;

    huart1.Init.StopBits = UART_STOPBITS_1;

    huart1.Init.Parity = UART_PARITY_NONE;

    huart1.Init.Mode = UART_MODE_TX_RX;

    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

    huart1.Init.OverSampling = UART_OVERSAMPLING_16;

    huart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;

    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

    HAL_UART_Init(&huart1);

    // DMA USART TX Enable

    USART1->CR3 |= USART_CR3_DMAT;

}

void UsartTxData(char *data)

{

    // Check if Tx DMA is busy

    if(UsartTxBusy() == 1) return;

    // Clear status / interrupt flags

    DMA1->IFCR |= DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;

    // Set transfer data size

    DMA1_Channel2->CNDTR = strlen(data);

    // Copy data to buffer

    strcpy(TxBuffer, data);

    // Set busy flag (used in UsartTxBusy())

    TxBusyFlag = 1;

    // Channel Enable - start transfer

    DMA1_Channel2->CCR |= DMA_CCR_EN;

}

uint8_t UsartTxBusy(void)

{

    if((DMA1->ISR & DMA_ISR_TCIF2) != 0)

    {

        TxBusyFlag = 0;

        DMA1_Channel2->CCR &= ~DMA_CCR_EN;

        // Clear status / interrupt flags

        DMA1->IFCR |= DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;

    }

    return(TxBusyFlag);

}
11 REPLIES 11
Posted on September 14, 2017 at 14:30

   // DMA USART TX Enable

    USART1->CR3 |= USART_CR3_DMAT;

This is your peripheral trigger.

JW

Posted on September 14, 2017 at 14:43

Without setting M2M, read out and post content of relevant DMA registers (including status).

JW