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);

}
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on September 14, 2017 at 14:30

   // DMA USART TX Enable

    USART1->CR3 |= USART_CR3_DMAT;

This is your peripheral trigger.

JW

View solution in original post

11 REPLIES 11
Posted on September 14, 2017 at 12:34

Pity this isn't posted in a compilable form.

Wouldn't memory to memory just blast the register rather than being properly constrained by TXE?

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on September 14, 2017 at 12:52

    // Memory to memory transfer

    DMA1_Channel2->CCR |= DMA_CCR_MEM2MEM;

?

JW

PS. Oh Clive beaten me again 🙂

Thomas Lotz
Associate II
Posted on September 14, 2017 at 12:55

Thanks for your reply

If I remove the memory to memory bit DMA1_Channel2->CCR |= DMA_CCR_MEM2MEM;

no message is sent

by usart.
Thomas Lotz
Associate II
Posted on September 14, 2017 at 13:55

The datasheet :

The DMA channels can also work without being triggered by a request from a peripheral.

This mode is called Memory to Memory mode.

In my application, the DMA works without peripheral trigger, so the MEM2MEM seems to be right.

Posted on September 14, 2017 at 14:47

I might have spotted it:

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

You meant 0b011 rather than 0x011.

JW

Posted on September 14, 2017 at 13:01

You want memory to peripheral.

JW

Thomas Lotz
Associate II
Posted on September 14, 2017 at 15:20

You meant 0b011 rather than 0x011.

Yes it is a mistake,

I corrected it.

The trigger is DMAT right, it works

It solve the problem.

Sorry for that mistake, and thank you for your help !

Posted on September 14, 2017 at 13:47

Yes memory to peripheral.

But when I enable DMA channel, nothing happens, and I don't know how to

start the transfer by another means

. In case of peripheral to memory (like usart Rx) it is the peripheral that enable the DMA transfer, in case of memory to memory

the transfer is initiated by the activation of the channel

, but in case of memory to peripheral I don't know.
Posted on September 14, 2017 at 14:30

No, in your application you are jamming data into the transmit register giving you a depth of two characters, ie one shifting, one holding.

Make sure you're using the right DMA/CHANNEL for the USART in question. Review the Reference Manual, don't have access to it on phone.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..