cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 PWM+DMA problem

alexzapf9
Associate II
Posted on September 19, 2013 at 08:30

Hello,

I've been trying to set up a 800kHz PWM signal with its duty cycles being transfered via DMA to the capture compare register. Well, it just doesn't work, not a single transfer is happening and I just can't figure out why. Heres the code:

#include <stm32f4xx.h>
#include ''main.h''
uint16_t timerValues[48];
int
main(
void
)
{
create_testpattern(); 
//fill timerValues[]
init_DMA();
init_TIM();
userbutton_init();
GPIO_SetBits(GPIOD, GPIO_Pin_13);
while
(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)); 
//wait for user button
GPIO_ResetBits(GPIOD, GPIO_Pin_13);
TIM_Cmd(TIM3, ENABLE);
DMA_Cmd(DMA1_Stream7, ENABLE);
while
(!DMA_GetCmdStatus(DMA1_Stream7)); 
//wait till stream is enabled
TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);
while
(1);
}
void
DMA1_Stream7_IRQHandler(
void
) {
DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF1);
GPIO_SetBits(GPIOD, GPIO_Pin_13);
DMA_Cmd(DMA1_Stream7, DISABLE);
}
void
init_DMA(
void
){
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_BufferSize = 48;
DMA_InitStruct.DMA_Channel = DMA_Channel_5;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&timerValues[0];
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&TIM3->CCR3 ;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Stream7, &DMA_InitStruct);
DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);
}
void
init_TIM(
void
){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
TIM_DeInit(TIM3);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_Prescaler = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = 103;
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 95;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStruct.TIM_OutputNState = TIM_OutputState_Disable;
TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC3Init(TIM3, &TIM_OCInitStruct);
/* --- Interrupt DMA --- */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_DMACmd(TIM3, TIM_DMA_Update, DISABLE);
}

I am watching the signal with my logic analyzer after pressing the user button, but CCR3 always contains the pre-configured value (CCR3 = 95), there are no changes happening. Any suggestions? -Alex
5 REPLIES 5
Posted on September 19, 2013 at 11:57

DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF1); // TCIF7 ??

TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE); // Isn't TIM3_UP Stream2 ? You'd want CC3 for TIM3_CC3 Stream7

STM32 Very fussy about coherent setting/configuration
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
alexzapf9
Associate II
Posted on September 19, 2013 at 14:26

damn, you are right! guess I got confused about what's source/destination, should work now, I'll give it a try asap.

Thanks!

alexzapf9
Associate II
Posted on September 19, 2013 at 18:54

Ok, tried it...didn't work, nothing! shock!

BUT

I've found out that the stdperiph selects the wrong channel. It always selects channel 7 instead of channel 5.

I tried to select every channel and it works properly from channel 0 - 3, channels above are incremented by 2, which makes channel 4 to channel 6 and the rest to channel 7. I didn't check what's going wrong there yet.

When I select channel 5 manually  it works just fine.

Posted on September 19, 2013 at 22:40

I've generally used the Update without preload. Modifying CCR3 (advancing beyond CNT) runs the risk of creating a race condition if the change is not shadowed.

I didn't rack up your code, so not sure what might be going on wrt default TIM/DMA settings.

This was some VL-Discovery code I built a long time ago. [DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/DMA%20and%20timers%20problem&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=449]https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Discovery%2FDMA%20and%20timers%20problem&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=449
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on September 19, 2013 at 23:15

// STM32 TIM4_CH3 PD.12 GREEN LED DMA PWM Phaser STM32F401C-DISCO - sourcer32@gmail.com
#include ''stm32f401_discovery.h''
#define PWM_ELEMENTS 100
u16 PWM_Buffer[PWM_ELEMENTS];
/**************************************************************************************/
void RCC_Configuration(void)
{
/* GPIOD clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* DMA1 clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/* TIM4 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*-------------------------- GPIO Configuration ----------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* Connect TIM4 pins to AF */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
}
/**************************************************************************************/
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStruct;
// TIM4_UP - DMA1, Channel 2, Stream 6
DMA_InitStruct.DMA_Channel = DMA_Channel_2;
DMA_InitStruct.DMA_BufferSize = PWM_ELEMENTS;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&PWM_Buffer[0];
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&TIM4->CCR1;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Stream6, &DMA_InitStruct);
// turning DMA on
DMA_Cmd(DMA1_Stream6, ENABLE);
}
/**************************************************************************************/
void TIM4_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 10000) - 1; // 10 KHz tick
TIM_TimeBaseStructure.TIM_Period = 100-1; // 100 0..99 ON DUTY (100 Hz) Phases over 1 Second
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 1;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
// channel 1 configuration (PD.12)
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 50;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
// ''connecting'' DMA and TIM4 (DMA1 Channel 2, Stream 6)
TIM_DMACmd(TIM4, TIM_DMA_Update, ENABLE);
// turning on TIM4 and PWM outputs
TIM_Cmd(TIM4, ENABLE);
}
/**************************************************************************************/
int main(void)
{
int i;
for(i=0 ; i < PWM_ELEMENTS ; i++) PWM_Buffer[i] = i / (PWM_ELEMENTS / 100);
RCC_Configuration();
GPIO_Configuration();
DMA_Configuration();
TIM4_Configuration();
while(1);
}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..