How to use PWM with DMA (STL Libraries)
Goodmorning to everyone,
I read a lot about this argument, and I know that with HAL libraries this topic is really easy to do. Unfortunately due to project request i need to use STL libraries. I create a pwm signal with TIM1. This signal is about 1MHz and i need to change every period the DC of the signal due to transmision protocol needs.
I drop here my program in order to let you understand better what I am doing.
I never used DMA using this libraries and I have totally no ideas where to start, could someone help me?
thank you!
If you need more details this program doesn't works only because every 13 period sent, it stops for about 2 period. This probably because some main interrupts have the priority on the exti one. I thought that this problem could be solved using DMA.
static __IO uint32_t TimingDelay;
volatile int LedOff = 0;
volatile int DataSend = 0; //variable used to avoid strange Tim3 ISR executions
volatile uint8_t LED_Data[MAX_LED][4];
volatile uint8_t LED_Mod[MAX_LED][4]; //used to programme leds brightness
volatile uint16_t pwmData[MAX_BITLED+STOP_BITS];
volatile uint32_t DataIndx = 0;
volatile uint32_t TimIndx = 0;
/* Private function prototypes -----------------------------------------------*/
static void Delay(uint32_t nCount);
#define WAIT_1s 1000 //ticks to get about a second of pause
#define WAIT_50ms 50 //ticks to get about 50ms of pause
#define NEW_FREQUENCY 4200U
/* Led Control constants -----------------------------------------------------*/
#define MAX_LED 8
#define PI 3.14159265
#define USE_BRIGHTNESS 0
#define STOP_BITS 50
#define HIGH_VALUE 8
#define LOW_VALUE 4
#define MAX_BITLED 24*MAX_LED
/* PWM_TIM and PWM values ----------------------------------------------------*/
#define PWM_PSC 1
#define PWM_GPIO GPIOA
#define PWM_PIN_SOURCE GPIO_PinSource8
#define PWM_PIN GPIO_Pin_8
#define PWM_AF_TIMER GPIO_AF_TIM1
#define PWM_TIMER TIM1
#define PULSE_VALUE 12
void TIM_PWMConfig(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
/* Connect the involved PWM pins to AF -------------------------------------*/
GPIO_PinAFConfig(PWM_GPIO, PWM_PIN_SOURCE, PWM_AF_TIMER);
/* Configure these PWM pins in alternate function mode ---------------------*/
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_Pin = PWM_PIN;
GPIO_Init(PWM_GPIO, &GPIO_InitStruct);
/* Configure timer ---------------------------------------------------------*/
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
TIM_TimeBaseInitStruct.TIM_Prescaler = PWM_PSC;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_Period = PULSE_VALUE;
TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseInitStruct);
TIM_ARRPreloadConfig(TIM1, ENABLE);
/* Configure the channels for PWM MODE -------------------------------------*/
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Set;
TIM_OC1Init(PWM_TIMER, &TIM_OCInitStruct);
/* Turning on the TIM counter ----------------------------------------------*/
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(PWM_TIMER, ENABLE);
/* Enable ARR Prereload ----------------------------------------------------*/
TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);
}
void SetPWM(double Duty)
{
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Set;
TIM_OCInitStruct.TIM_Pulse = Duty;
TIM_OC1Init(PWM_TIMER, &TIM_OCInitStruct);
TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);
}
void PWM_ControlConfig(void)
{
/* EXTI Configuration ------------------------------------------------------*/
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource9);
EXTI_InitTypeDef EXTI_PWM_Struct;
EXTI_StructInit(&EXTI_PWM_Struct);
EXTI_PWM_Struct.EXTI_Line = EXTI_Line9;
EXTI_PWM_Struct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_PWM_Struct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_PWM_Struct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_PWM_Struct);
/* NVIC Configuration ------------------------------------------------------*/
NVIC_InitTypeDef NVIC_PWM_Struct;
NVIC_PWM_Struct.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_PWM_Struct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_PWM_Struct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_PWM_Struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_PWM_Struct);
}
void EXTI9_5_IRQHandler()
{
if (EXTI_GetITStatus(EXTI_Line9) != RESET)
{
if (TimIndx < DataIndx && DataSend) //If data signal has not finished yet
{
if(TimIndx == 0)
{
TimIndx++; //The first data as already been sent when the trasmission started
}
else if (TimIndx < MAX_BITLED)//after the first data sent, the cycle start the normal behavior
{
SetPWM(pwmData[TimIndx]);
TimIndx++;
}
else //all the data as been sent, now silence as to be delivered in order to let leds know that the signal has ended
{
SetPWM(0);
for(int i = 0; i<350; i++); //set silence for about 50us
//Setting all the values in order to be ready to start another data transmission
DataIndx = 0;
TimIndx = 0;
DataSend = 0;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line9);
}
void Set_LED (int LEDnum, int Red, int Green, int Blue)
{
LED_Data[LEDnum][0] = LEDnum;
LED_Data[LEDnum][1] = Green;
LED_Data[LEDnum][2] = Red;
LED_Data[LEDnum][3] = Blue;
}
void DataLed_Send (void)
{
volatile uint32_t color;
for (int i= 0; i<MAX_LED; i++)
{
color = ((LED_Data[i][1]<<16) | (LED_Data[i][2]<<8) | (LED_Data[i][3]));
for (int i=23; i>=0; i--)
{
if (color&(1<<i)) pwmData[DataIndx] = HIGH_VALUE; // 2/3 of PWM Period
else pwmData[DataIndx] = LOW_VALUE; // 1/3 of PWM Period
DataIndx++;
}
}
for (int i=0; i<STOP_BITS; i++)
{
pwmData[DataIndx] = 0;
DataIndx++;
}
DataSend = 1;
TimIndx = 0;
SetPWM(pwmData[0]);
while(DataIndx);
}
int main(void)
{
/* Setting up the SysTick routine ------------------------------------------*/
SysTick_Config(SystemCoreClock / NEW_FREQUENCY);
/* Peripheral clock enables ------------------------------------------------*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* Setting up peripherals --------------------------------------------------*/
TIM_PWMConfig();
PWM_ControlConfig();
/* Leds initialization -----------------------------------------------------*/
while(1)
{
for(int k = 0; k < MAX_LED; k++) {Set_LED(k, 0, 255, 0);}
DataLed_Send();
Delay(WAIT_1s);
}
}