2017-09-14 02:35 AM
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);}Solved! Go to Solution.
2017-09-14 07:30 AM
// DMA USART TX Enable
USART1->CR3 |= USART_CR3_DMAT;This is your peripheral trigger.
JW
2017-09-14 03:34 AM
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?
2017-09-14 03:52 AM
// Memory to memory transfer
DMA1_Channel2->CCR |= DMA_CCR_MEM2MEM;?
JW
PS. Oh Clive beaten me again :)
2017-09-14 03:55 AM
Thanks for your reply
If I remove the memory to memory bit DMA1_Channel2->CCR |= DMA_CCR_MEM2MEM;
no message is sent
by usart.2017-09-14 04:55 AM
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.
2017-09-14 05:47 AM
I might have spotted it:
DMA1_CSELR->CSELR |= 0x011 << DMA_CSELR_C2S_Pos;
You meant 0b011 rather than 0x011.
JW
2017-09-14 06:01 AM
You want memory to peripheral.
JW
2017-09-14 06:20 AM
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 !
2017-09-14 06:47 AM
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 memorythe transfer is initiated by the activation of the channel
, but in case of memory to peripheral I don't know.2017-09-14 07:30 AM
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.