2023-07-28 08:47 AM
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 !
Solved! Go to Solution.
2023-07-29 07:48 AM - edited 2023-07-29 07:50 AM
> 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_5,0x24000030, (uint32_t) &(USART6->RDR),LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
Your calls to LL_DMA_ConfigAddresses have the memory addresses backwards. The function expects source first, then destination.
__STATIC_INLINE void LL_DMA_ConfigAddresses(DMA_TypeDef *DMAx, uint32_t Stream, uint32_t SrcAddress, uint32_t DstAddress, uint32_t Direction)
Not sure if this is the ONLY problem, but it's A problem. Should be:
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_3, (uint32_t) &(USART2->RDR), 0x24000010, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_5, (uint32_t) &(USART6->RDR), 0x24000030, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
Strong recommendation: ditch LL and program registers directly, if that's the control you want. HAL is good (for what it's supposed to be), direct register access is good, LL is garbagio, largely due to stuff like this.
Examining registers directly and ensuring they are as expected is also a good debug option. Would have caught this.
2023-07-28 09:24 AM
Can't multiple bits be asserted concurrently? Lose the if/else construct.
Errors perhaps the memory used, alignment, or size.
Could you use SPI, or drive via a pattern buffer ie TIM+DMA+GPIO BSRR
2023-07-28 09:59 AM
Hi,
Alignment problem should not exist, I am manually defining a memory location that I know DMA can access.
0x24000010 and 0x24000030
And this ideology works with >5 more streams on DMA1 and BDMA..., but mainly for SPI... In this example, I am running only streams from USART.
While in the main program, 5 streams can be executed in parallel with no errors with DMA1.
I am also first enabling RX streams, and TX after, and looking by scope, clock bursts for USART2 and USART6 are in exactly the same position.
( I was very "smart" connecting the RX part from USART6 to TX part from USART2 on the PCB. but this should not matter, since it should work as SPI as far as I understand, latching data at rising/falling edges based on USART configuration ? )
I can use GPIO toggle, but the main problem is that if I get interrupted from my TDC, and it will take more time to process, the encoder will time out and data will be garbage.... (15us timeout time)
2023-07-29 06:18 AM - edited 2023-07-29 07:10 AM
Another attempt. Generated all the code from 0 for STM32H7A3. connected RX to TX, and also checking data on scope.
Same results, I never get TC interrupt on the RX side, only errors.
Also, waveform TX is correctly represented on the GPIO pin based on memory content, while memory in the RX part of DMA stream did not change a bit...
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,0x24000000, (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_SetDataLength(DMA2, LL_DMA_STREAM_3, 5);
LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_4, 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_EnableStream(DMA2, LL_DMA_STREAM_4);
LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_3);
}
uint8_t enc_dataA[5];
uint8_t enc_datab[5]={0xAA,0xBB,0xFF,0x00,0xCC};
uint32_t DMA2_TC3 = 0;
uint32_t DMA2_TE3 = 0;
uint32_t DMA2_TC4 = 0;
uint32_t DMA2_TE4 = 0;
void DMA2_Stream3_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC3(DMA2) == 1)
{
LL_DMA_ClearFlag_TC3(DMA2);
DMA2_TC3++;
}
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++;
}
if(LL_DMA_IsActiveFlag_TE4(DMA2) == 1)
{
LL_DMA_ClearFlag_TE4(DMA2);
DMA2_TE4++;
}
}
And here is my USART2 config...
static void MX_USART2_Init(void)
{
LL_USART_InitTypeDef USART_InitStruct = {0};
LL_USART_ClockInitTypeDef USART_ClockInitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_RCC_SetUSARTClockSource(LL_RCC_USART234578_CLKSOURCE_PCLK1);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
/*
PA2 ------> USART2_TX
PA3 ------> USART2_RX
PA4 ------> USART2_CK
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_2|LL_GPIO_PIN_3|LL_GPIO_PIN_4;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
USART_InitStruct.BaudRate = 1000000;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_0_5;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_8;
LL_USART_Init(USART2, &USART_InitStruct);
LL_USART_SetTXFIFOThreshold(USART2, LL_USART_FIFOTHRESHOLD_1_8);
LL_USART_SetRXFIFOThreshold(USART2, LL_USART_FIFOTHRESHOLD_1_8);
USART_ClockInitStruct.ClockOutput = LL_USART_CLOCK_ENABLE;
USART_ClockInitStruct.ClockPolarity = LL_USART_POLARITY_HIGH;
USART_ClockInitStruct.ClockPhase = LL_USART_PHASE_1EDGE;
USART_ClockInitStruct.LastBitClockPulse = LL_USART_LASTCLKPULSE_OUTPUT;
LL_USART_ClockInit(USART2, &USART_ClockInitStruct);
LL_USART_SetTransferBitOrder(USART2,LL_USART_BITORDER_MSBFIRST);
LL_USART_ConfigSyncMode(USART2);
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);
NVIC_SetPriority(DMA2_Stream3_IRQn, 12);
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
NVIC_SetPriority(DMA2_Stream4_IRQn, 13);
NVIC_EnableIRQ(DMA2_Stream4_IRQn);
LL_USART_Enable(USART2);
while((!(LL_USART_IsActiveFlag_TEACK(USART2))) || (!(LL_USART_IsActiveFlag_REACK(USART2))))
{
}
}
If someone has a devkit and time, all my project is loaded to this thread below to download.
Update:
errata does not say anything about this. Also switched RX to DMA1, same effect, only errors...
2023-07-29 07:48 AM - edited 2023-07-29 07:50 AM
> 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_5,0x24000030, (uint32_t) &(USART6->RDR),LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
Your calls to LL_DMA_ConfigAddresses have the memory addresses backwards. The function expects source first, then destination.
__STATIC_INLINE void LL_DMA_ConfigAddresses(DMA_TypeDef *DMAx, uint32_t Stream, uint32_t SrcAddress, uint32_t DstAddress, uint32_t Direction)
Not sure if this is the ONLY problem, but it's A problem. Should be:
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_3, (uint32_t) &(USART2->RDR), 0x24000010, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_5, (uint32_t) &(USART6->RDR), 0x24000030, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
Strong recommendation: ditch LL and program registers directly, if that's the control you want. HAL is good (for what it's supposed to be), direct register access is good, LL is garbagio, largely due to stuff like this.
Examining registers directly and ensuring they are as expected is also a good debug option. Would have caught this.
2023-07-29 08:40 AM - edited 2023-07-29 08:50 AM
Ohh, this is sooo stupid. I was looking at this line so many times, and forgot to do that.... You have very good eyes or just are expert in programming :thinking_face:
I like LL because it gives just a small hint of what you are doing, and HAL is just way too bloated. I am trying to learn to write as little code with as little footprint in flash/execution as possible, while still more or less readable..
Everything sprung into life, and everything is working. Thank you so much sir ! I have 4 streams to read encoder, no errors, only TC IRQ's are triggered 8)