STM32H7 Synchronous USART receiving problem with DMA
Hello, in my project I need to read an encoder that clocks out data with clock burst. For this I decided to use UART with clock generation and DMA. (I also mixed up RX from one UART to another , but this is not a problem if request happens at the same time which it does)
I have multiple DMA channels running, so I would like to think I set up everything correctly. In order to receive, I have to make fake TX bursts, since clocks are not generated only in RX mode.
For this I have 4 streams ( 3 4 5 6 ). And TX works great, I get clock burst at CK pin of USART peripheral (both of them at the same time) BUt I get TE DMA errors at receiving and, and I Get no data, and Can’t understand the reason why. I am also using correct memory for that DMA with memory protection unit. I have no problem in other DMA channels using same memory location. (0x2400000 location of AXI RAM)
And this is what I get :
Clock is nice, and I get data from the encoder, no problem. Gaps in clock are allowed as long as they are below 15us
And here is my code (DMA2 clock is enabled elsewhere, also USART2/6 is running at 137.5MHz) and both USART2 TX and USART6 TX are forking, TC are triggering, and TE is 0 for this stream (to generate clock burst)
uint8_t ENCODER_Init(void)
{
uint8_t error = 0;
LL_USART_ClockInitTypeDef USART_ClockInitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_RCC_SetUSARTClockSource(LL_RCC_USART16_CLKSOURCE_PCLK2);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART6);
LL_RCC_SetUSARTClockSource(LL_RCC_USART234578_CLKSOURCE_PCLK1);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOG, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOD, &GPIO_InitStruct);
LL_USART_SetTransferDirection(USART6, LL_USART_DIRECTION_TX_RX);
LL_USART_ConfigCharacter(USART6, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_0_5);
LL_USART_SetBaudRate(USART6, 137500000, LL_USART_PRESCALER_DIV1, LL_USART_OVERSAMPLING_16, 5000000-1);
LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX);
LL_USART_ConfigCharacter(USART2, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_0_5);
LL_USART_SetBaudRate(USART2, 137500000, LL_USART_PRESCALER_DIV1, LL_USART_OVERSAMPLING_16, 5000000-1);
USART_ClockInitStruct.ClockOutput = LL_USART_CLOCK_ENABLE;
USART_ClockInitStruct.ClockPolarity = LL_USART_POLARITY_LOW;
USART_ClockInitStruct.ClockPhase = LL_USART_PHASE_1EDGE;
USART_ClockInitStruct.LastBitClockPulse = LL_USART_LASTCLKPULSE_OUTPUT;
LL_USART_DisableFIFO(USART2);
LL_USART_DisableFIFO(USART6);
LL_USART_ClockInit(USART6, &USART_ClockInitStruct);
LL_USART_ConfigSyncMode(USART6);
LL_USART_ClockInit(USART2, &USART_ClockInitStruct);
LL_USART_ConfigSyncMode(USART2);
LL_USART_EnableDMAReq_RX(USART6);
LL_USART_EnableDMAReq_TX(USART6);
LL_USART_EnableDMAReq_RX(USART2);
LL_USART_EnableDMAReq_TX(USART2);
LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_3);
LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_3);
LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_4);
LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_4);
LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_5);
LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_5);
LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_6);
LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_6);
NVIC_SetPriority(DMA2_Stream3_IRQn, 12);
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
NVIC_SetPriority(DMA2_Stream4_IRQn, 13);
NVIC_EnableIRQ(DMA2_Stream4_IRQn);
NVIC_SetPriority(DMA2_Stream5_IRQn, 14);
NVIC_EnableIRQ(DMA2_Stream5_IRQn);
NVIC_SetPriority(DMA2_Stream6_IRQn, 15);
NVIC_EnableIRQ(DMA2_Stream6_IRQn);
LL_USART_Enable(USART6);
LL_USART_Enable(USART2);
uint32_t timeout = 0xFFFFFF;
while((!(LL_USART_IsActiveFlag_TEACK(USART6))) || (!(LL_USART_IsActiveFlag_REACK(USART6))))
{
timeout--;
if(timeout==0)
{
error= 1;
break;
}
}
timeout = 0xFFFFFF;
while((!(LL_USART_IsActiveFlag_TEACK(USART2))) || (!(LL_USART_IsActiveFlag_REACK(USART2))))
{
timeout--;
if(timeout==0)
{
error+= 2;
break;
}
}
return error;
}
And DMA config with winwith interrupts for TC/TE
void ENCODER_DMA_READ(void)
{
LL_DMA_ConfigTransfer(DMA2,LL_DMA_STREAM_3,LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_MEDIUM | LL_DMA_MODE_NORMAL |LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigTransfer(DMA2,LL_DMA_STREAM_4,LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_LOW | LL_DMA_MODE_NORMAL |LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_3,0x24000010, (uint32_t) &(USART2->RDR),LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_4,0x24000020, (uint32_t) &(USART2->TDR),LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_ConfigTransfer(DMA2,LL_DMA_STREAM_5,LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_MEDIUM | LL_DMA_MODE_NORMAL |LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigTransfer(DMA2,LL_DMA_STREAM_6,LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_LOW | LL_DMA_MODE_NORMAL |LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_5,0x24000030, (uint32_t) &(USART6->RDR),LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_6,0x24000040, (uint32_t) &(USART6->TDR),LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_3, 5);
LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_4, 5);
LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_5, 5);
LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_6, 5);
LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_3, LL_DMAMUX1_REQ_USART2_RX);
LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_4, LL_DMAMUX1_REQ_USART2_TX);
LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_5, LL_DMAMUX1_REQ_USART6_RX);
LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_6, LL_DMAMUX1_REQ_USART6_TX);
LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_3); //Don't know if it's needed, does not work with or without
LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_4);
LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_5);
LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_6);
LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_3);
LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_5);
LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_4);
LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_6);
}
uint32_t DMA2_TC3 = 0;
uint32_t DMA2_TE3 = 0;
uint32_t DMA2_TC4 = 0;
uint32_t DMA2_TE4 = 0;
uint32_t DMA2_TC5 = 0;
uint32_t DMA2_TE5 = 0;
uint32_t DMA2_TC6 = 0;
uint32_t DMA2_TE6 = 0;
void DMA2_Stream3_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC3(DMA2) == 1)
{
LL_DMA_ClearFlag_TC3(DMA2);
DMA2_TC3++;
}
else if(LL_DMA_IsActiveFlag_TE3(DMA2) == 1)
{
LL_DMA_ClearFlag_TE3(DMA2);
DMA2_TE3++;
}
}
void DMA2_Stream4_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC4(DMA2) == 1)
{
LL_DMA_ClearFlag_TC4(DMA2);
DMA2_TC4++;
}
else if(LL_DMA_IsActiveFlag_TE4(DMA2) == 1)
{
LL_DMA_ClearFlag_TE4(DMA2);
DMA2_TE4++;
}
}
void DMA2_Stream5_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC5(DMA2) == 1)
{
LL_DMA_ClearFlag_TC5(DMA2);
DMA2_TC5++;
}
else if(LL_DMA_IsActiveFlag_TE5(DMA2) == 1)
{
LL_DMA_ClearFlag_TE5(DMA2);
DMA2_TE5++;
}
}
void DMA2_Stream6_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC6(DMA2) == 1)
{
LL_DMA_ClearFlag_TC6(DMA2);
DMA2_TC6++;
}
else if(LL_DMA_IsActiveFlag_TE6(DMA2) == 1)
{
LL_DMA_ClearFlag_TE6(DMA2);
DMA2_TE6++;
}
}
So I get only TE3 and TC4 (same number), same goes to TE5 and TC6, same number.... TE6 and TE4 is zero.
Does any one can spot the problem, why I am getting TE on my RX streams ? (and no data...) This forum is a huge help of tracking simple problems that is costing so much time....
Thank you !