cancel
Showing results for 
Search instead for 
Did you mean: 

Timer with DMA

John Hite
Associate III
Posted on March 24, 2017 at 19:00

STM32F437

I am using TIM4 channel 1 and would like to have the timer output handled by DMA instead of my timer ISR but my DMA attempt is not working. So I am fishing for timer/dma example code hopefully that uses DMA interrupts as well.

Thanks,

JH

3 REPLIES 3
S.Ma
Principal
Posted on March 25, 2017 at 17:11

Have you browsed through cube nucleo/discovery/HAL/LL examples related to Timer+DMA?

Posted on March 25, 2017 at 18:03

Thanks for posting. I have not looked there. If there are non-HAL examples I would be interested. Could you provide a URL?

Thanks,

jh

Posted on March 25, 2017 at 18:50

I guess it's related to download STM32 Cube package.

Otherwise, did a fun project where the datasheet of the STM32F437 was C coded... consider this as pseudo code to get clues on the DMA vs Timer. In this code, it's mostly for Output compare extract. 

//====================== Capture Compare Initialization functions ================================ 8><8 =======

u32 EnableTimerCC_Interrupt(u32 u, u32 n, FunctionalState Enable) { // n = [1..4]

Timer_t* Timer = (Timer_t*) u;

if(n==0) while(1); // not allowed

if(n>=TIMER_MAX_CC) while(1); // not available CCn

if(Timer->CCR[n]==0) while(1); // not available

// Clear any pending flags first

Timer->TIM->SR &= TimerCCFlags[n];

if(Enable) Timer->TIM->DIER |= TimerCCFlags[n];

else Timer->TIM->DIER &= ~TimerCCFlags[n];

return 0;

}

u32 SetTimerInputCC(u32 u, u32 n, IO_Pin_t* Pin, FunctionalState Enable) {

Timer_t* Timer = (Timer_t*) u;

if(n==0) while(1); // not allowed

if(n>=TIMER_MAX_CC) while(1); // not available CCn

if(Timer->CCR[n]==0) while(1); // not available

// Enable is not used yet....

TIM_ICInitTypeDef IC;

TIM_ICStructInit(&IC);

// For now... should be passed as parameter later on. Rising edge, no prescaler, no filtering

IC.TIM_Channel = TimerCC_Channels[n];

IC.TIM_ICPolarity = TIM_ICPolarity_Rising;

IC.TIM_ICSelection = TIM_ICSelection_DirectTI;

IC.TIM_ICPrescaler = TIM_ICPSC_DIV1;

IC.TIM_ICFilter = 0;

TIM_ICInit(Timer->TIM, &IC);

if(Pin) {

Timer->PinCC[n] = Pin;

IO_PinClockEnable(Pin);

IO_PinSetHigh(Pin);

IO_PinSetInput(Pin);

IO_PinEnablePullUpDown(Pin, ENABLE, DISABLE);

IO_PinEnableHighDrive(Pin, ENABLE);

IO_PinConfiguredAs(Pin, GetPinAF(Pin->Name,(u32)Timer->TIM));

};

// EnableTimerCC_Interrupt(u, n, Enable);

return 0;

}

u32 HookTimerCC(u32 u, u32 n, u32 fn, u32 ct) {

Timer_t* Timer = (Timer_t*) u;

if(n==0) while(1); // not allowed

if(n>=TIMER_MAX_CC) while(1); // not available CCn

if(Timer->CCR[n]==0) while(1); // not available

Timer->ctCC[n] = ct;

Timer->fnCC[n] = fn;

return 0;

}

void TIM_DMA_Activate(Timer_t* Timer) {

u32 n;

for(n=1;n<4;n++) {

if(Timer->EdgesSize[n]<=1) continue;

// This CC is hooked up to a DMA, let's enable them

DMA_StreamChannelInfo_t* DSCI = Get_TimerDMA_InfoByPPP_n((u32)Timer->TIM, n, DMA_DIR_PeripheralToMemory | DMA_DIR_MemoryToPeripheral);

DMA_Cmd(DSCI->Stream/*DMA1_Stream4*/, ENABLE); // DMA enable

BookDMA_Stream(DSCI->Stream);

TIM_DMACmd(Timer->TIM, TIM_DMA_n[n], ENABLE); // TIM2 Update DMA Request enable

};

}

// In this scheme, the timer is reset, wait for Ch2 rising edge, then starts one pulse mode

// For example, the output compares can generate pulses or edge which can trigger time shifted ADC, DAC, Analog Switch behaviours

// Using external triggers is easier to probe, hence easier debug, faster move forward job

void EnableOneShotTimerCC_Triggered(Timer_t* Timer, u32 n) {

TIM_DMA_Activate(Timer); // Will sweep through all DMA possible interaction

TIM_SelectOnePulseMode(Timer->TIM, TIM_OPMode_Single); // One Pulse Mode selection

if(n==1)

TIM_SelectInputTrigger(Timer->TIM, TIM_TS_TI1FP1); // Input Timer Trigged on CH1

else

if(n==2) TIM_SelectInputTrigger(Timer->TIM, TIM_TS_TI2FP2); // Input Timer Trigged on CH2

else

while(1);

// Slave Mode selection: Trigger Mode (the trigger will set the Timer enable bit)

TIM_SelectSlaveMode(Timer->TIM, TIM_SlaveMode_Trigger);

}

static void TimerOutputCC_SetDMA(Timer_t* Timer, u32 n) {

DMA_InitTypeDef DMAI;

u32 DataSize;

if(Timer->Max > 0x0000FFFF)

DataSize = DMA_PeripheralDataSize_Word;

else

DataSize = DMA_PeripheralDataSize_HalfWord;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE);

DMA_StreamChannelInfo_t* DSCI = Get_TimerDMA_InfoByPPP_n((u32)Timer->TIM, n, DMA_DIR_PeripheralToMemory | DMA_DIR_MemoryToPeripheral);

DMA_DeInit(DSCI->Stream);//(DMA1_Stream4);

DMAI.DMA_Channel = DSCI->Channel;//DMA_Channel_5;

DMAI.DMA_PeripheralBaseAddr = (u32)Timer->CCR[n];

DMAI.DMA_Memory0BaseAddr = (u32)Timer->EdgesTableAdr[n];

DMAI.DMA_DIR = DMA_DIR_MemoryToPeripheral;

DMAI.DMA_BufferSize = Timer->EdgesSize[n];

DMAI.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMAI.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMAI.DMA_PeripheralDataSize = DataSize;

DMAI.DMA_MemoryDataSize = DataSize;

DMAI.DMA_Mode = DMA_Mode_Circular;

DMAI.DMA_Priority = DMA_Priority_High;

DMAI.DMA_FIFOMode = DMA_FIFOMode_Disable;

DMAI.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

DMAI.DMA_MemoryBurst = DMA_MemoryBurst_Single;

DMAI.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_Init(DSCI->Stream/*DMA1_Stream4*/, &DMAI);

}

void SetTimerOutputCC_SingleEdge(Timer_t* Timer, u32 n, u32 Value_lsb) {

Timer->EdgesSize[n] = 0; // Non zero triggers the DMA mode for multiple pulses

Timer->EdgesTableAdr[n] = 0;

TIM_OCInitTypeDef OC;

TIM_OCStructInit(&OC);

OC.TIM_OCMode = TIM_OCMode_PWM2;

OC.TIM_OutputState = TIM_OutputState_Enable;

OC.TIM_Pulse = Value_lsb;

OC.TIM_OCPolarity = TIM_OCPolarity_Low;

TIM_OCnInit(Timer->TIM, n, &OC);

}

void SetTimerOutputCC_MultiEdges(Timer_t* Timer, u32 n, u32 Adr, u32 Size) {

Timer->EdgesSize[n] = Size; // Non zero triggers the DMA mode for multiple pulses

Timer->EdgesTableAdr[n] = Adr;

TIM_OCInitTypeDef OC;

TIM_OCStructInit(&OC);

OC.TIM_OCMode = TIM_OCMode_Toggle;

OC.TIM_OutputState = TIM_OutputState_Enable;

OC.TIM_Pulse = 1;

OC.TIM_OCPolarity = TIM_OCPolarity_Low;

TIM_OCnInit(Timer->TIM, n, &OC);

//CC1 only for now

TimerOutputCC_SetDMA(Timer, n);

TIM_OCnPreloadConfig(Timer->TIM, n, TIM_OCPreload_Disable); // Enable preload feature * // no shadow registers please

}

void EnableFreeRunTimer(Timer_t* Timer) {

//u32 n;

// Simnple timer mode

if(Timer->EdgesSize[1]<2) { // DMA needed here

TIM_Cmd(Timer->TIM, ENABLE);

return;

}

//=======================================================

// DMA transfer is required here (CC1 hard code for now

TIM_DMA_Activate(Timer);

TIM_Cmd(Timer->TIM, ENABLE); // let's run the Timer at last

}