cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F756 use TIMER event DMA from GPIO to Memory

bm2
Associate III

Hello,

now I will record 32 GPIO's via DMA for the analyse. The DMA itself shall triggered with a timer.

So first I have found different information to solve this. So I have tested some solution, but on the STM32F756 will it not run.

My solution is: GPIOD and GPIOE tranfer with two DMA streams to an public array. After the DMA transmition complete I will start the ISR to switch the buffer.

At the moment, the DMA transfer is not started. The timer runs, but the NTDR register is not changed.

Here my configuration for the DMA and timer:

 

/* DMA1 inititialisation */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
  NVIC_SetPriority(DMA1_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(DMA1_Stream1_IRQn);
  NVIC_SetPriority(DMA1_Stream2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(DMA1_Stream2_IRQn);
/* TIM2 initialisation */
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
  LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_1, LL_DMA_CHANNEL_3);
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
  LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_LOW);
  LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_NORMAL);
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_WORD);
  LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_WORD);
  LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_1);
  LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_1, (uint32_t)&GPIOD->IDR);
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_1);
  LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_1, LL_DMA_CHANNEL_3);

  TIM_InitStruct.Prescaler = 11;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 588;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM2, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM2);
  LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM2);
  LL_TIM_CC_SetDMAReqTrigger(TIM2, LL_TIM_CCDMAREQUEST_UPDATE);
  LL_TIM_EnableCounter(TIM2);
/* TIM3 initialisation */
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
  LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_2, LL_DMA_CHANNEL_5);
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
  LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_2, LL_DMA_PRIORITY_LOW);
  LL_DMA_SetMode(DMA1, LL_DMA_STREAM_2, LL_DMA_MODE_CIRCULAR);
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_2, LL_DMA_PERIPH_NOINCREMENT);
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_2, LL_DMA_MEMORY_INCREMENT);
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_2, LL_DMA_PDATAALIGN_HALFWORD);
  LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_2, LL_DMA_MDATAALIGN_HALFWORD);
  LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_2);
  TIM_InitStruct.Prescaler = 11;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 588;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM3, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM3);
  LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM3);
  LL_TIM_CC_SetDMAReqTrigger(TIM3, LL_TIM_CCDMAREQUEST_UPDATE);
  LL_TIM_EnableCounter(TIM3);
/* start transfer */
   LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, 10);
   LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_1,(uint32_t)bufferA);
   LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_2, 10);
   LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_2,(uint32_t)bufferB);
   LL_DMA_ClearFlag_TC1(DMA1);
   LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1);
   LL_DMA_ClearFlag_TC2(DMA1);
   LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_2);

 

So I've read in the web different information and it is unclair why or what is correct:

- using transfer direction priphery to memory and/or memory to memory

- using of DMA2 instead of DMA1

Have everyone an idee why it is not work?

Thanks for our help,

Bernd

8 REPLIES 8

Instead of the Cube/LL gobbledygook, read out and post the TIM and DMA registers' content (and you are better off writing that, too).

> memory to memory

No. Read DMA chapter, what "memory to memory" means.

> using of DMA2 instead of DMA1

Yes.

JW

gbm
Lead III

In F4/F7 there is no connection between DMA1 and GPIO - see the first big picture in the RefMan. Use DMA2.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
bm2
Associate III

Thanks for our answers. I will test it today and give here a feedback.

@gbm

Which first big picture did you mean?

Figure 1. System architecture for STM32F75xxx and STM32F74xxx devices

Here I see that the DMA1 have connection to APB1 and DMA2 to APB2. Booth, APB1 and APB2 connected to AHB1, which is also connected to GPIOx (see Table 1. STM32F75xxx and STM32F74xxx register boundary addresses).

How can I find the information that the GPIOx is only connected to DMA2? It is not so easy to find it.

Get a closer look at DMA_P1 and DMA_P2 buses and discover the difference between them. DMA_P1 connects to APB1 only - that's the problem.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

> How can I find the information that the GPIOx is only connected to DMA2? It is not so easy to find it.

I have a picture in that article I gave link above to, which may shed some light to it.

That picture is for the 'F4, but things work analogously in 'F7.

JW

So, I have test it. I have change DMA1 to DMA2. Now it works only for one DMA transfer. When I enable by booth timer the DMA Request update, the software crash and the debugger stop at the adress 0xbeca4cf0. The callstack give me the follwoing information:

bm2_0-1734512382976.png

It is not so help full. The initialilsation is generated with STM32CubeMX.

Here my initialisation code:

static void MX_TIM1_Init(void)
{
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
  LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_5, LL_DMA_CHANNEL_6);
  LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_5, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
  LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_5, LL_DMA_PRIORITY_LOW);
  LL_DMA_SetMode(DMA2, LL_DMA_STREAM_5, LL_DMA_MODE_CIRCULAR);
  LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_5, LL_DMA_PERIPH_NOINCREMENT);
  LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_5, LL_DMA_MEMORY_INCREMENT);
  LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_5, LL_DMA_PDATAALIGN_HALFWORD);
  LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_5, LL_DMA_MDATAALIGN_HALFWORD);
  LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_5);
  TIM_InitStruct.Prescaler = 11;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_DOWN;
  TIM_InitStruct.Autoreload = 588;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  TIM_InitStruct.RepetitionCounter = 0;
  LL_TIM_Init(TIM1, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM1);
  LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM1, LL_TIM_TRGO_UPDATE);
  LL_TIM_SetTriggerOutput2(TIM1, LL_TIM_TRGO2_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM1);
}

static void MX_TIM8_Init(void)
{
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM8);
  LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_1, LL_DMA_CHANNEL_7);
  LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
  LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_1, LL_DMA_PRIORITY_LOW);
  LL_DMA_SetMode(DMA2, LL_DMA_STREAM_1, LL_DMA_MODE_CIRCULAR);
  LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
  LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
  LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_HALFWORD);
  LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_HALFWORD);
  LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_1);
  TIM_InitStruct.Prescaler = 11;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_DOWN;
  TIM_InitStruct.Autoreload = 588;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  TIM_InitStruct.RepetitionCounter = 0;
  LL_TIM_Init(TIM8, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM8);
  LL_TIM_SetClockSource(TIM8, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM8, LL_TIM_TRGO_UPDATE);
  LL_TIM_SetTriggerOutput2(TIM8, LL_TIM_TRGO2_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM8);
}

static void MX_DMA_Init(void)
{
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
  NVIC_SetPriority(DMA2_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(DMA2_Stream1_IRQn);
  NVIC_SetPriority(DMA2_Stream5_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(DMA2_Stream5_IRQn);
}

/* start of the DMA transfer */
   LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_5);
   LL_TIM_CC_SetDMAReqTrigger(TIM1, LL_TIM_CCDMAREQUEST_UPDATE);
   LL_TIM_EnableDMAReq_UPDATE(TIM1);
   LL_TIM_EnableCounter(TIM1);
   LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_5, 10);
   LL_DMA_SetMemoryAddress(DMA2, LL_DMA_STREAM_5, (uint32_t)bufferA);
   LL_DMA_SetPeriphAddress(DMA2, LL_DMA_STREAM_5, (uint32_t)&GPIOD->IDR);
   LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_5);
   LL_DMA_ClearFlag_TC1(DMA2);
   LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_5);

   LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_1);
   LL_TIM_CC_SetDMAReqTrigger(TIM8, LL_TIM_CCDMAREQUEST_UPDATE);
   LL_TIM_EnableDMAReq_UPDATE(TIM8);
   LL_TIM_EnableCounter(TIM8);
   LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, 10);
   LL_DMA_SetMemoryAddress(DMA2, LL_DMA_STREAM_1, (uint32_t)bufferB);
   LL_DMA_SetPeriphAddress(DMA2, LL_DMA_STREAM_1, (uint32_t)&GPIOE->IDR);
   LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);
   LL_DMA_ClearFlag_TC2(DMA2);
   LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_1);

 

After the crash the following DMA and timer configuration are shown:

DMA2:

bm2_1-1734531883057.png

bm2_2-1734531916750.png

bm2_3-1734531961343.png

TIM1

bm2_4-1734532022646.png

 

bm2_5-1734532056492.png

 

TIM8

bm2_6-1734532089644.png

bm2_7-1734532123224.png

 

Whre come this crash? If it a problem with the timing otself? Booth timer have the same timing.

Thanks for our help,

Bernd

 

Thank @waclawek.jan , now I understand it.

Registers look OK.

The crash is outside of what you've shown us.

TIM1 just rolled over (or under - choosing downcounter is weird, and also are you sure you want to set up TRGO/TRGO2? they are harmeless now but not needed for this exercise either) as witnessed by it CNT, and DMA2Stream just triggered a Transfer Complete as witnessed by NDTR and the flags in HISR.  As the flags (namely TC) is not cleared and you have interrupt on TC enabled, the crash is most probably consequence of the interrupt, most probably incorrectly handled.

Check - best in mixed C/disasm view - that the proper vector to the ISR is inserted to proper position inside the interrupt vector table. If not, check if the ISR name matches exactly (noting that C is case sensitive) that in the vector table (usually in the startup code; the interrupt chapter in RM contains the reference list of interrupt vectors). If you use C++, mind name mangling.

JW

 

PS. What's this IDE?