5
\$\begingroup\$

I am trying to trigger the DMA peripheral by the Timer using STM32F4-Discovery board, but it doesn't seem to work.

I want to get the value of a port (Port C) every 5 ms and save the value in memory at certain address. When the timer (TIM5) overflows at 5 ms, I want the DMA (DMA1 Stream6 Channel6) to be triggered.

What I have done: configured the Timer, the DMA, the Timer interrupt and also the DMA interrupt.

Should I respect a certain order of the instructions? How to make the connection between the DMA and Timer, other than using the specific DMA channel?

How do I get the DMA working on the STM32F?

Edit 1: I attached the code

void Timer5_Setup(void)
{
TIM_TimeBaseInitTypeDef Timer5_InitStructure;       
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);        
Timer5_InitStructure.TIM_Prescaler = 1;         
Timer5_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;  
Timer5_InitStructure.TIM_Period = 0x48;     
Timer5_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;  
TIM_TimeBaseInit(TIM5, &Timer5_InitStructure);  
TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);  
TIM_DMAConfig(TIM5, 0, TIM_DMABurstLength_1Transfer);
TIM_DMACmd(TIM5, TIM_DMA_Update | TIM_DMA_Trigger | TIM_DMA_COM, ENABLE);
TIM_SelectOutputTrigger(TIM5, TIM_TRGOSource_Update);
TIM_Cmd(TIM5, ENABLE);      
}


void DMA1_Config (void)
{
DMA_InitTypeDef  DMA_InitStructure;

DMA_DeInit(DMA1_Stream6);
DMA_StructInit(&DMA_InitStructure);

DMA_InitStructure.DMA_Channel = DMA_Channel_6;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(GPIOC->ODR);    
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) sdram_adr;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 2;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                        
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                 
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                               
DMA_InitStructure.DMA_Priority = DMA_Priority_High;             
/*  
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
*/
DMA_Init(DMA1_Stream6, &DMA_InitStructure);


DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TEIF6);
DMA_Cmd(DMA1_Stream6, ENABLE);

DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE);

TIM_DMAConfig(TIM5, TIM_DMABase_CR1 ,TIM_DMABurstLength_1Transfer);

TIM_Cmd(TIM5, ENABLE);
}

void TIM5_IRQHandler(void)
{
 if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) 
 {
    TIM_ClearITPendingBit(TIM5, TIM_IT_Update);     

    /*code related to app */        
 }
} 


void DMA1_Stream6_IRQHandler (void)
{
      if(DMA_GetITStatus(DMA1_Stream6, DMA_FLAG_TCIF6))
      {
      DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);
      }
 }
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Please post code. \$\endgroup\$
    – pgvoorhees
    Apr 10 '17 at 15:38
  • \$\begingroup\$ sure, I have attached it in the first post \$\endgroup\$
    – DragonflyN
    Apr 12 '17 at 9:06
11
\$\begingroup\$

The big reason the DMA isn't transferring is that it isn't actually connected to the peripheral.

In most Cortex implementations I've seen, there are multiple memory buses. The ST implementation isn't any different. You can see how GPIO C is attached to the chip's memory system in the table below (found in the Memory map section of the reference manual).

GPIO C memory map placement

The reason that is important is because DMA controllers are usually imeplemented with specific use cases in mind. In this case, DMA1 is implemented with memory-to-memory transfers in mind. You can tell because of the bus-matrix tap points (See graphic below, from System Architecture section of Reference manual).

DMA memory taps

The missing taps at AHB1 and AHB2 mean that, no matter how you program DMA1, it can't actually access GPIO data, the physical connections aren't present. DMA1 can, however, use signals from the peripherals to trigger transfers. Which just makes the issue confusing.

Switch to DMA2.

It looks like you had the right idea with mapping a request to a stream, so you will see that, when you switch to DMA2, you'll need to pick a new timer and trigger event.

Hope this helps.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ THIS! You just saved me hours of debugging as well. Thank you! \$\endgroup\$
    – Martin
    May 5 '19 at 18:55
0
\$\begingroup\$

It appears that there is no way to use both DMA controllers if I need in one app do

  1. trigger the DMA peripheral by the Timer
  2. copy mem to mem with DMA

because DMA1 is not physically connected to peripheral bus mem-to-mem mode is not implemented in STM32F4x5/STM32F4x7 RM0090 paragraph 8.3.6 Source, destination and transfer modes 2 Only the DMA2 controller is able to perform memory-to-memory transfers

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.