AnsweredAssumed Answered

STM32F4 DMA and Varying Duty Cycle

Question asked by nain.haseeb on Jun 28, 2016
Latest reply on Jul 1, 2016 by Clive One
Hi everyone,

I am wondering how to go about setting up a varying duty cycle on an F4 board using the DMA. This is for a personal project of mine, I have asked around and believe my code does not have any glaring logic issues but it still does not vary the duty cycle of the timer. For the purpose of this project I need to use TIM5 (projecting the output PWM to PA0).

I attempted using Channel 6 and Stream 0 but cannot as something is already using PA2 not allowing me to mess with TIM5_CH3.

//initialize structs
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
uint16_t prescalerValue;
//enable GPIOA clock
//enable TIM5 clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
//enable DMA1 clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/* GPIOA Configuration: TIM5 Channel 1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0,  GPIO_AF_TIM5);
// Stop timer
/* Compute the prescaler value */
prescalerValue = (uint16_t) (SystemCoreClock / 2 / 84000000) - 1;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 104; // 800kHz
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM5, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);
//TIM5->CCR2 = 106;
/* configure DMA */
/* DMA1 Channel Config */
/* DMA1 Stream6 setup*/
DMA_Cmd(DMA1_Stream6, DISABLE);            // disable DMA channel 6
DMA_InitStructure.DMA_Channel = DMA_Channel_6;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM5->CCR1);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ledStripDMABuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream6, &DMA_InitStructure);
DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);
DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);               // clear DMA1 Channel 6 transfer complete flag
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(NVIC_PRIO_WS2811_DMA);
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(NVIC_PRIO_WS2811_DMA);
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

My desire is to update the duty cycle every time the timer update occurs, the value of that duty cycle should be updated with the value of the ledStripDMABuffer. Is there something obvious I am missing?