2024-09-10 02:16 PM - last edited on 2024-09-11 02:20 AM by SofLit
Hi Folks,
I'm working on pattern generation on GPIO pins and I've done it successfully using bare-metal programming approach. I used TIM1 to trigger DMA2 to take data from a buffer and send it GPIOA->BSRR.
But when I try to change the timer from TIM1 to TIM2 and change the respective DMA stream, the same code does not work.
code:
uint32_t signal1[6]; //pattern no included
// Enable clocks for GPIOA, TIM2, and DMA1
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
// Configure GPIOA Pins 0-5 as output
GPIOA->MODER &= ~0x00000FFF; // Clear mode for PA0-PA5
GPIOA->MODER |= 0x00000555; // Set PA0-PA5 as General Purpose Output
// Configure TIM2 for DMA requests on update event
TIM2->PSC = 0; // Set prescaler to 0
TIM2->ARR = 999; // Set auto-reload value (adjust for timing)
TIM2->DIER |= TIM_DIER_UDE; // Enable update DMA request
TIM2->CR1 |= TIM_CR1_CEN; // Enable TIM2
// Configure DMA1 Stream 5 for TIM2 Update
DMA1_Stream5->CR &= ~DMA_SxCR_EN; // Disable stream to configure
DMA1_Stream5->PAR = (uint32_t)&GPIOA->ODR; // Peripheral address (GPIOA ODR)
DMA1_Stream5->M0AR = (uint32_t)signal1; // Memory address (signal1 array)
DMA1_Stream5->NDTR = 6; // Number of data items
// Configure DMA control register
DMA1_Stream5->CR = (3 << DMA_SxCR_CHSEL_Pos) | // Channel 3 for TIM2_UP
(0 << DMA_SxCR_DIR_Pos) | // Memory-to-Peripheral
(2 << DMA_SxCR_MSIZE_Pos) | // Memory size: 32-bit
(2 << DMA_SxCR_PSIZE_Pos) | // Peripheral size: 32-bit
DMA_SxCR_MINC | // Memory increment mode
DMA_SxCR_CIRC; // Circular mode
// Enable DMA1 Stream 5
DMA1_Stream5->CR |= DMA_SxCR_EN;
// TIM2 will now trigger DMA transfers to output the pattern on GPIOA pins 0-5
This code does not work but if you change it to TIM1 and respective DMA stream it works. I checked and i get transfer error interrupt flag. Any help or direction is appreciated.
Solved! Go to Solution.
2024-09-11 02:02 PM
>>So is there a way to know what can the DMA1 access and what it cannot?
There's a bus matrix diagram
DMA1 associates with peripherals on the APB1, ie access to registers, source of triggers
DMA2 associates with peripherals on the APB2, ie access to registers, source of triggers
DMA2 can also do memory-to-memory, basically a two step process, a read, then a write, rather than simple flow-thru mechanics.
This functionality has been repeatedly stated for F2 / F4 designs for well over a decade.
My correction to the earlier statement
"DMA1 does not have direct access to the AHB1 bus, which is why the transfer is failing"
>>Is this intentional or a flaw?
It's a function of the design, to simplify the implementation.
APB1/DMA1 has internal connectivity, think points on a rail system, and can connect peripherals to/from memory. It doesn't inter-stage, so it can't go memory-to-memory, bus-to-bus,or APB1-to-APB2
2024-09-11 08:44 AM - edited 2024-09-11 08:45 AM
Hello @zd9797,
As you can see from the system architecture:
DMA1 does not have direct access to the APB1 bus, which is why the transfer is failing
Using TIM1, DMA2 has access to both AHB1 and APB2 buses that's why it works.
You either use a timer that's on APB2 bus, or use a different DMA stream that has access to to APB1 bus
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2024-09-11 12:56 PM
Oh is that why it was failing! I brought up this issue with my senior and I was afraid of this answer.
DMA1 does not have direct access to the APB1 bus, which is why the transfer is failing - Is this intentional or a flaw?
So is there a way to know what can the DMA1 access and what it cannot?
2024-09-11 02:02 PM
>>So is there a way to know what can the DMA1 access and what it cannot?
There's a bus matrix diagram
DMA1 associates with peripherals on the APB1, ie access to registers, source of triggers
DMA2 associates with peripherals on the APB2, ie access to registers, source of triggers
DMA2 can also do memory-to-memory, basically a two step process, a read, then a write, rather than simple flow-thru mechanics.
This functionality has been repeatedly stated for F2 / F4 designs for well over a decade.
My correction to the earlier statement
"DMA1 does not have direct access to the AHB1 bus, which is why the transfer is failing"
>>Is this intentional or a flaw?
It's a function of the design, to simplify the implementation.
APB1/DMA1 has internal connectivity, think points on a rail system, and can connect peripherals to/from memory. It doesn't inter-stage, so it can't go memory-to-memory, bus-to-bus,or APB1-to-APB2
2024-09-12 08:30 AM
That makes sense. Thank you so much!