2024-10-24 04:32 AM - edited 2024-10-24 04:35 AM
Hello,
I am looking for a way to set up DMA to transfer from peripheral to circular buffer triggered from Timer
I hoped I could set it up just like it is described here, just change the source:
It samples data as expected but only once, it does not repeat when all 256 samples are taken.
Do I understand that picture wrong or is it bad? Do I need to do some more settings?
So my code looks like this:
#define GPIO_DMA_SAMPLE_BUFFER (256)
uint16_t gGPIO_DMASampleBuffer[GPIO_DMA_SAMPLE_BUFFER] = {0};
void DMA_Init()
{
//Enable DMA clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPDMA1EN | RCC_AHB1ENR_GPDMA2EN;
//Destination address increase, Source = Destination 16 bit wide
GPDMA1_Channel0->CTR1 = DMA_CTR1_DINC | DMA_CTR1_DDW_LOG2_0 | DMA_CTR1_SDW_LOG2_0;
//Request by tim2_upd_dma
GPDMA1_Channel0->CTR2 = 76;
//Transfer buffer size
GPDMA1_Channel0->CBR1 = GPIO_DMA_SAMPLE_BUFFER;
//Source GPIOC
GPDMA1_Channel0->CSAR = (uint32_t)&(GPIOC->IDR);
//Destination Sample buffer
GPDMA1_Channel0->CDAR = (uint32_t)gGPIO_DMASampleBuffer;
//Circular buffer mode
GPDMA1_Channel0->CLLR |= DMA_CLLR_UDA;
//Activate DMA1 Channel 1
GPDMA1_Channel0->CCR = DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;
NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
}
void GPDMA1_Channel0_IRQHandler(void)
{
unsigned int statusOfInputDatalines;
extern uint16_t gGPIO_DMASampleBuffer[];
if (GPDMA1_Channel0->CSR & DMA_CSR_TCF)
{
GPDMA1_Channel0->CFCR = DMA_CFCR_TCF; //clear flag
for (int i = 128; i < 256; i++)
{
statusOfInputDatalines = (((gGPIO_DMASampleBuffer[i]) >> 6) & 0xFF); // reading status of the port C (6-13) pins
statusOfInputDatalines = (statusOfInputDatalines << 2) | ((statusOfInputDatalines >> 5) & 0x02) | ((statusOfInputDatalines >> 7) & 0x01); // reorder input pins
_SaveDataToBuffer(statusOfInputDatalines);
}
}
else if (GPDMA1_Channel0->CSR & DMA_CSR_HTF)
{
GPDMA1_Channel0->CFCR = DMA_CSR_HTF; //clear flag
for (int i = 0; i < 128; i++)
{
statusOfInputDatalines = (((gGPIO_DMASampleBuffer[i]) >> 6) & 0xFF); // reading status of the port C (6-13) pins
statusOfInputDatalines = (statusOfInputDatalines << 2) | ((statusOfInputDatalines >> 5) & 0x02) | ((statusOfInputDatalines >> 7) & 0x01); // reorder input pins
_SaveDataToBuffer(statusOfInputDatalines);
}
}
}
Solved! Go to Solution.
2024-10-24 07:36 AM
It needed some more parameters.
In the Reference manual, it was described, but that DMA presentation paper was very misleading. And even that description in the reference manual is somewhat cumbersome.
This works as expected.
#define GPIO_DMA_SAMPLE_BUFFER (256)
volatile uint16_t gGPIO_DMASampleBuffer[GPIO_DMA_SAMPLE_BUFFER] = {0};
__attribute__((aligned(32))) static uint32_t DesttinationAddress = (uint32_t)gGPIO_DMASampleBuffer;
void DMA_Init()
{
//Enable DMA clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPDMA1EN | RCC_AHB1ENR_GPDMA2EN;
//Destination address increase, Source = Destination 16 bit wide
GPDMA1_Channel0->CTR1 = DMA_CTR1_DINC | DMA_CTR1_DDW_LOG2_0 | DMA_CTR1_SDW_LOG2_0;
//Request by tim2_upd_dma
GPDMA1_Channel0->CTR2 = 76;
//Transfer buffer size
GPDMA1_Channel0->CBR1 = GPIO_DMA_SAMPLE_BUFFER * 2;
//Source GPIOC
GPDMA1_Channel0->CSAR = (uint32_t)&(GPIOC->IDR);
//Destination Sample buffer
GPDMA1_Channel0->CDAR = (uint32_t)gGPIO_DMASampleBuffer;
//Circular buffer mode
GPDMA1_Channel0->CLLR = DMA_CLLR_UDA;
//Setup Linked List
GPDMA1_Channel0->CLBAR &= 0x0000FFFF;
GPDMA1_Channel0->CLBAR |= (uint32_t)&DesttinationAddress & 0xFFFF0000;
GPDMA1_Channel0->CLLR |= (uint32_t)&DesttinationAddress & 0x0000FFFC;
//Activate DMA1 Channel 1
GPDMA1_Channel0->CCR = DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;
NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
}
2024-10-24 04:39 AM - edited 2024-10-24 04:40 AM
First, do it in HAL (or find a HAL example which does it).
Then pick the bits you need from that ...
2024-10-24 07:12 AM
Also study the DMA chapter of the Reference Manual for your stm32.
I know this is a long and complicated document and it takes effort to understand, but that just reflects the fact that stm32 are extremely powerful devices.
2024-10-24 07:36 AM
It needed some more parameters.
In the Reference manual, it was described, but that DMA presentation paper was very misleading. And even that description in the reference manual is somewhat cumbersome.
This works as expected.
#define GPIO_DMA_SAMPLE_BUFFER (256)
volatile uint16_t gGPIO_DMASampleBuffer[GPIO_DMA_SAMPLE_BUFFER] = {0};
__attribute__((aligned(32))) static uint32_t DesttinationAddress = (uint32_t)gGPIO_DMASampleBuffer;
void DMA_Init()
{
//Enable DMA clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPDMA1EN | RCC_AHB1ENR_GPDMA2EN;
//Destination address increase, Source = Destination 16 bit wide
GPDMA1_Channel0->CTR1 = DMA_CTR1_DINC | DMA_CTR1_DDW_LOG2_0 | DMA_CTR1_SDW_LOG2_0;
//Request by tim2_upd_dma
GPDMA1_Channel0->CTR2 = 76;
//Transfer buffer size
GPDMA1_Channel0->CBR1 = GPIO_DMA_SAMPLE_BUFFER * 2;
//Source GPIOC
GPDMA1_Channel0->CSAR = (uint32_t)&(GPIOC->IDR);
//Destination Sample buffer
GPDMA1_Channel0->CDAR = (uint32_t)gGPIO_DMASampleBuffer;
//Circular buffer mode
GPDMA1_Channel0->CLLR = DMA_CLLR_UDA;
//Setup Linked List
GPDMA1_Channel0->CLBAR &= 0x0000FFFF;
GPDMA1_Channel0->CLBAR |= (uint32_t)&DesttinationAddress & 0xFFFF0000;
GPDMA1_Channel0->CLLR |= (uint32_t)&DesttinationAddress & 0x0000FFFC;
//Activate DMA1 Channel 1
GPDMA1_Channel0->CCR = DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;
NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
}
2024-10-24 07:54 AM
@Miyuki wrote:that DMA presentation paper was very misleading.
What "presentation paper" was it?
Please give a link.