5

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);
      }
 }
DragonflyN
  • 51
  • 1
  • 5

2 Answers2

11

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.

pgvoorhees
  • 2,496
  • 16
  • 14
0

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

jslav
  • 1