cancel
Showing results for 
Search instead for 
Did you mean: 

stm32 DMA transfer to Timer

phill4563
Associate II
Posted on February 16, 2015 at 14:21

Hello,

I'm working with the STM32F373 µC trying to get the DMA work with a timer. I want the DMA controller to write 3 different values in the ccr1 register of timer Unfortunately there is no example how to implement this on the STM32f373 in the STDPeriPH. So i take the example out of the STM32F4xx STDPeriph and try to adapt the source code for the stm32f Sadly to program doesn't work. The output on the PA2 pin is only a PWM signal with a fixed duty cycle. There is no update on the duty cycle which i expect. Here is the code i try to adept so far:

#include ''stm32f37x.h''
#include ''stm32f37x_conf.h''
#include ''stdbool.h''
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t aSRC_Buffer[3] = {0, 0, 0};
uint16_t uhTimerPeriod = 0;
/* Private function prototypes -----------------------------------------------*/
static void TIM_Config(void);
int main(void)
{
/* TIM Configuration */
TIM_Config();
/* Compute the value to be set in ARR regiter to generate signal frequency at 57 Khz */
uhTimerPeriod = (SystemCoreClock / 17570 ) - 1;
/* Compute CCR1 value to generate a duty cycle at 50% */
aSRC_Buffer[0] = (uint16_t) (((uint32_t) 5 * (uhTimerPeriod - 1)) / 10);
/* Compute CCR1 value to generate a duty cycle at 5% */
aSRC_Buffer[1] = (uint16_t) (((uint32_t) 375 * (uhTimerPeriod - 1)) / 1000);
/* Compute CCR1 value to generate a duty cycle at 25% */
aSRC_Buffer[2] = (uint16_t) (((uint32_t) 25 * (uhTimerPeriod - 1)) / 100);
/* TIM1 Peripheral Configuration -------------------------------------------*/
/* TIM1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = uhTimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM15, &TIM_TimeBaseStructure);
/* Channel 3 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_Pulse = 50;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
// TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
// TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM15, &TIM_OCInitStructure);
/* Enable preload feature */
TIM_OC1PreloadConfig(TIM15, TIM_OCPreload_Enable);
/* TIM1 counter enable */
TIM_Cmd(TIM15, ENABLE);
/* DMA enable*/
DMA_Cmd(DMA1_Channel5, ENABLE);
/* TIM1 Update DMA Request enable */
TIM_DMACmd(TIM15, TIM_DMA_CC1, ENABLE);
// TIM_DMACmd(TIM15, TIM_DMA_Update, ENABLE);
/* Main Output Enable */
TIM_CtrlPWMOutputs(TIM15, ENABLE);
while (1)
{
}
}
/**
* @brief Configure the TIM1 Pins.
* @param None
* @retval None
*/
static void TIM_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* GPIOA and GPIOB clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* GPIOA Configuration: Channel 3 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOA, &GPIO_InitStructure); 
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_9);
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM15->CCR1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&aSRC_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 3;
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_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
}

and this is what the osczi says: As i described i take the code out of the STM32F4 STDPeriph. There i used the example: \STM32F4xx_DSP_StdPeriph_Lib_V1.3.0\Project\STM32F4xx_StdPeriph_Examples\TIM\TIM_DMA After starting the programm there is the first value of

aSRC_Buffer

in the ccr1 register but the dma doesnt update. I hope you can help me with that issue greetz
4 REPLIES 4
Posted on February 16, 2015 at 18:01

This works for me on an F303

// STM32F3-Discovery TIM15 DMA Demo - sourcer32@gmail.com
#include ''stm32f3_discovery.h''
#include ''stm32f30x.h''
//******************************************************************************
void RCC_Configuration(void)
{
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* Enable TIM15 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
/* GPIOA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
}
//******************************************************************************
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_9); // PA2 TIM15_CH1
}
//******************************************************************************
volatile uint16_t PatternBuffer[3];
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
int Period;
Period = (SystemCoreClock / 17570); // 57 KHz timebase, assumes APB2 H/1 TIMCLK15 H/1
PatternBuffer[0] = (Period * 50) / 100; // 50%
PatternBuffer[1] = (Period * 375) / 1000; // 5%
PatternBuffer[2] = (Period * 25) / 100; // 25%
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0; // DIV1
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM15, &TIM_TimeBaseStructure);
/* Output Compare PMW1 Mode configuration */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OCInitStructure.TIM_Pulse = Period / 2; // 50%
TIM_OC1Init(TIM15, &TIM_OCInitStructure);
/* Enable the DMA trigger */
TIM_DMACmd(TIM15, TIM_DMA_Update, ENABLE);
/* Enable pins, TIM15 more sensitive/special */
TIM_CtrlPWMOutputs(TIM15, ENABLE);
/* TIM15 enable counter */
TIM_Cmd(TIM15, ENABLE);
}
//******************************************************************************
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
// DMA1 Channel5 TIM15_UP
/* DMA configuration */
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM15->CCR1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&PatternBuffer[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 3;
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_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
/* Enable the DMA channel */
DMA_Cmd(DMA1_Channel5, ENABLE);
}
//******************************************************************************
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA1 Channel5 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//******************************************************************************
void DMA1_Channel5_IRQHandler(void) // X Hz (~5.86 KHz)
{
/* Test on DMA1 Channel5 Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_IT_TC5))
{
/* Clear DMA1 Channel5 Transfer Complete interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_TC5);
STM_EVAL_LEDToggle(LED3); // X/2 Hz (~2.93 KHz)
}
}
//******************************************************************************
int main(void)
{
/* Initialize LED available on STM32F3-Discovery board */
STM_EVAL_LEDInit(LED3);
/* Turn on LD3 */
STM_EVAL_LEDOn(LED3);
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
DMA_Configuration();
TIM_Configuration();
while(1); /* Infinite loop */
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
phill4563
Associate II
Posted on February 20, 2015 at 01:54

Hi clive,

thanks for the source example and sorry for answering late.

Your example works fine. I try to get it work for tim2 now.

i keep you updated.

thanks and greetz

phil

Posted on February 20, 2015 at 04:03

TIM2 is 32-bit so you'd need ''Word'' operations, rather than 16-bit ''Half-Word'' ones.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
phill4563
Associate II
Posted on February 20, 2015 at 14:09

thank you,

I just find it out before I see your post :$. Anyway, your tip is absolute correct. Here the correct DMA Init:

/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
DMA_DeInit(DMA1_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM2->ARR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&aSRC_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 7;
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_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
}

so thanks again clive, greetz phil