2022-02-19 02:41 AM
2022-02-19 02:44 AM
Have a look at the refernce manual for the chip you use. There are such mechanisms available, look if they fit for you.
2022-02-19 03:00 AM
Testing this on STM32F411CE.
I'm using Timer 2 to:
- Trigger ADC using TRGO, start conversion and DMA2 transfer, writing to "ADC_value" variable.
DMA config:
Works correctly.
- Use T2_UPDATE source to trigger DMA1 write from "ADC_value" to USART2->DR.
DMA config:
Partially works, this is where I'm struggling.
I'm trying to force the DMA + FIFO to split a single 16 or 32-bit read into multiple UART TX transfers.
So for a single DMA requests, the DMA loads the data into the fifo as 4-byte, and then the fifo starts unloading onto the UART as single byte transfers.
I expected the fifo to keep writing to the UART until empty, but I'm getting a single byte transfer on every DMA request.
My current code is:
volatile uint32_t my_value;
void main(void){
// HAL_Init, etc
// Prepare ADC (Set in TRGO mode, using DMA2 transfer and continuous dma requests)
HAL_ADC_Start_DMA(&hadc1, &my_value, 1);
// Prepare Timer2, clear counter and flags
__HAL_TIM_SET_COUNTER(&htim2,0);
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_UPDATE);
// Prepare DMA1
HAL_DMA_Start_IT(&hdma_tim2_ch3_up, (uint32_t)&my_value, (uint32_t)&USART2->DR, 1);
// Start Timer2 (Enable interrupt for toggling LED, for debugging purposes)
HAL_TIM_Base_Start_IT(&htim2);
// Enable Timer2 update DMA trigger for DMA1 transfer
__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_UPDATE);
while(1);
}
I also tried setting DMA1 in byte mode for both and setting a 2 or 4-byte transfer size, without sucess. Maybe USART->DR has to be accessed as 16 or 32-bit?
Another issue I'm thinking of is that dma will probably write the data very fast, without any control, as it's not being handled by UART_TX request.
2022-02-19 03:33 AM
> Maybe USART->DR has to be accessed as 16 or 32-bit?
No, USART does not support data packing as SPI in some newer STM32 does.
> I expected the fifo to keep writing to the UART until empty,
What makes you to expect this, except your wishes? I mean, where did you see this behaviour to be described?
> but I'm getting a single byte transfer on every DMA request.
This is what DMA does. Upon one DMA request, it performs one DMA transfer. DMA transfers are counted on the Peripheral side. Memory side fills/empties FIFO according to FIFO settings (if FIFO is enabled).
One way to do what you want would be to generate a relatively long TRGO from the timer you use to trigger ADC and feed that as TRGI to another timer, which Slave-mode controller would be set to Gated. Set that timer to run fast so that it generates exactly two/four Updates during the TRGO duration and use those to trigger the DMA (OTOH that timer must run slow enough for UART to succeed to transmit the data, of course).
I personally wouldn't use Cube/HAL for this, as with anything outside the simplistic tasks which could be clicked in CubeMX, it just gets into way.
JW
2022-02-19 03:52 AM
Thanks for the clarification :)
Yep, that's what I thought, but the DMA packing / fifo / endianess section is a little fuzzi, so I had to try!
Why did I thought that?
Well, you can trigger a memory-to-memory transfer of any size (well, up to 64K) and it will do the whole thing itself, so I thought it could be also possible to do the same with a peripheral somehow.
Using a secondary timer would work but, but sadly not optimal, I was trying to make a silent, unassisted bridge between adc and uart so I could debug everything without any CPU intervention, even at few Ksps, with zero interrupts wasting power.
2022-02-19 05:51 AM
> silent, unassisted bridge
That's exactly what you'd achieve using the second timer to trigger transfers.
JW
2022-02-19 07:08 AM
Yep, that's what I'm trying to do!
It's easy to run a second timer 4 times faster to send 4 bytes every one primary Timer clock cycle, however the clock division must be perfect or it will cause drift.
This is an issue in higher frequencies, for example if your primary timer period is 3125, you can't run it exactly at 1/4 the period.
HAL wasn't really an issue here, requires some reading at the libs but you'll eventually get there:
// Start ADC (Configured with Timer 2 TRGO)
HAL_ADC_Start_DMA(&hadc1, &adc_val, 1);
// Clear flags and counters
__HAL_TIM_SET_COUNTER(&htim2,0);
__HAL_TIM_SET_COUNTER(&htim3,0);
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_UPDATE);
__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);
// Start mem->USART TX DMA, send 2 bytes in circular buffer
HAL_DMA_Start(&hdma_tim3_ch4_up, (uint32_t)&adc_val, (uint32_t)&USART2->DR, 2);
// Enable Timer 3 DMA signal
__HAL_TIM_ENABLE_DMA(&htim3, TIM_DMA_UPDATE);
// Test value
adc_val = 0xAA55;
// Start Timer 2 (Triggers ADC conversion)
__HAL_TIM_ENABLE(&htim2);
// Cheap way to detect first conversion
while (adc_val==0xAA55);
// Start Timer1 (UART DMA starts receiving transfer requests)
__HAL_TIM_ENABLE(&htim3);
2022-02-19 09:39 AM