cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F100RB DMA+Timer PPM Stream[SOLVED]

terrapinlogo
Associate
Posted on June 21, 2015 at 12:42

I am currently trying to generate a ppm stream for a RC transmitter using the DMA and timer on a STM32F100RB but am having a few difficulties getting it working. The code I have is based on a similar problem solved

/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=https%3a//my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/DMA%20and%20timers%20problem&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=637

#include <
stm32f10x.h
>
#include <
stm32f10x_adc.h
>
#include <
stm32f10x_dma.h
>
#include <
stm32f10x_exti.h
>
#include <
stm32f10x_gpio.h
>
#include <
stm32f10x_rcc.h
>
#include <
stm32f10x_spi.h
>
#include <
stm32f10x_tim.h
>
#include <
misc.h
>
#define TIM2_CCR1 0x4000004C // Not CCR but DMAR pointing to CCR
#define ADC1_DR 0x4001244C
#define PPM_ELEMENTS 18
#define ADC_ELEMENTS 9
u16 PPM_Buffer[PPM_ELEMENTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21998};
u16 ADC_Buffer[ADC_ELEMENTS];
void SysClkInit(void);
void ADCInit(void);
void DMAInit(void);
void TIM2Init(void);
int main(void)
{
SysClkInit();
ADCInit();
TIM2Init();
DMAInit();

// if (pressed trim at power on) calibrate mode
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(1)
{
}
}
void SysClkInit()
{
RCC_DeInit(); // Reset RCC to default
RCC_HSEConfig(RCC_HSE_ON); // Enable HSE
ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp(); // Wait for HSE to stabilise
if (HSEStartUpStatus == SUCCESS) // If we are stable
{
RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK/1
RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK/1
RCC_PCLK1Config(RCC_HCLK_Div1); // PCLK1 = HCLK/1
// PLLCLK = (8MHzHSE/2) * 6 = 24 MHz
RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div2);
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_6);
RCC_PLLCmd(ENABLE); // Enable the PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // Wait for it to be ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // Use PLL as SYSCLK
while (RCC_GetSYSCLKSource() != 0x08); // Wait for switch over to happen
}
}
void ADCInit(void)
{
//Enable ADC1, GPIOA, and GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 |
RCC_APB2Periph_GPIOA |
RCC_APB2Periph_GPIOB |
RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure; //Variable used to setup the GPIO pins
//Configure ADC pins (PA0 -> Channel 1 to PA7 -> Channel 8) as analog inputs
GPIO_StructInit(&GPIO_InitStructure); // Reset init structure, if not it can cause issues...
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |
GPIO_Pin_1 |
GPIO_Pin_2 |
GPIO_Pin_3 |
GPIO_Pin_4 |
GPIO_Pin_5 |
GPIO_Pin_6 |
GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure); // init batt pin
ADC_InitTypeDef ADC_InitStructure;
//ADC1 configuration
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//We will convert multiple channels
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
//select single conversion mode
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//select no external triggering
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
//right 12-bit data alignment in ADC data register
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//9 channels conversion
ADC_InitStructure.ADC_NbrOfChannel = 9;
//load structure values to control and status registers
ADC_Init(ADC1, &ADC_InitStructure);
//configure each channel
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 7, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 9, ADC_SampleTime_41Cycles5);
//Enable ADC1
ADC_Cmd(ADC1, ENABLE);
//enable DMA for ADC
ADC_DMACmd(ADC1, ENABLE);
//Enable ADC1 reset calibration register
ADC_ResetCalibration(ADC1);
//Check the end of ADC1 reset calibration register
while(ADC_GetResetCalibrationStatus(ADC1));
//Start ADC1 calibration
ADC_StartCalibration(ADC1);
//Check the end of ADC1 calibration
while(ADC_GetCalibrationStatus(ADC1));
}
void DMAInit(void)
{
//enable DMA1 clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//create DMA structure
DMA_InitTypeDef DMA_InitStructure;
//reset DMA1 channe1 to default values;
DMA_DeInit(DMA1_Channel1);
//channel will be used for memory to memory transfer
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//setting normal mode (non circular)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//medium priority
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//source and destination data size word=32bit
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//automatic memory destination increment enable.
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//source address increment disable
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//Location assigned to peripheral register will be source
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//chunk of data to be transfered
DMA_InitStructure.DMA_BufferSize = ADC_ELEMENTS; // 8 channels + Batt sense
//source and destination start addresses
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_Buffer;
//send values to DMA registers
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// Enable DMA1 Channel Transfer Complete interrupt
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable the DMA1 - Channel1
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = PPM_ELEMENTS; // 8 channels + 9 space + end
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM2_CCR1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)PPM_Buffer;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
// turning DMA on
DMA_Cmd(DMA1_Channel5, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
//Enable DMA1 channel1 IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*
//Enable DMA1 channel5 IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);*/
}
void TIM2Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure ;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseStructure.TIM_Period = 22000 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 24 - 1; // 24 MHz / 24 (1 MHz tick)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_DMAConfig(TIM2, TIM_DMABase_CCR1, TIM_DMABurstLength_1Transfer);
// ''connecting'' DMA and TIM2
TIM_DMACmd(TIM2, TIM_DMA_CC1, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// turning on TIM3 and PWM outputs
TIM_Cmd(TIM2, ENABLE);
}
void DMA1_Channel1_IRQHandler(void) // Convert ADC to mS
{
int i;
for (i = 0; i < PPM_ELEMENTS - 1; ++i)
{
if (i == 0)
{
PPM_Buffer[i] = 400;
}
else if (i % 2 == 1)
{
PPM_Buffer[i] = PPM_Buffer[i - 1] + ADC_Buffer[(i - 1) / 2]/4 + 1000;
}
else
{
PPM_Buffer[i] = PPM_Buffer[i - 1] + 400;
}
}
DMA_ClearFlag(DMA1_FLAG_TC1 | DMA1_FLAG_GL1 | DMA1_FLAG_HT1);
}

The output should look like the attached picture. Any ideas on where I am going wrong?
3 REPLIES 3
Posted on June 21, 2015 at 14:10

How many times do you think the ADC values will change in the 22 ms window? Do you think it's wise to change the PWM values before it's completed a full cycle?

Try outputting a fixed pattern, does that work?

You enable a TIM IRQ, not seeing any NVIC or IRQ code for that.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
terrapinlogo
Associate
Posted on June 24, 2015 at 09:18

My problem was that i had forgotten to remap the JTAG and TIM2 pins. Adding the following two lines fixed my problem.

GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);

Here is the full code for 8 channel ADC to PPM via DMA for those that may be interested.

#include <
stm32f10x.h
>
#include <
stm32f10x_adc.h
>
#include <
stm32f10x_dma.h
>
#include <
stm32f10x_exti.h
>
#include <
stm32f10x_gpio.h
>
#include <
stm32f10x_rcc.h
>
#include <
stm32f10x_spi.h
>
#include <
stm32f10x_tim.h
>
#include <
misc.h
>
#define TIM2_CCR1 0x4000004C // Not CCR but DMAR pointing to CCR
#define ADC1_DR 0x4001244C
#define PPM_ELEMENTS 18
#define ADC_ELEMENTS 9
u16 PPM_Buffer[PPM_ELEMENTS] = {400, 1400, 1800, 3000, 3400, 4700, 5100, 6500, 6900, 8400, 8800, 10800, 11200, 13200, 13600, 16000, 16400, 21999};
u16 ADC_Buffer[ADC_ELEMENTS];
void SysClkInit(void);
void ADCInit(void);
void DMAInit(void);
void TIM2Init(void);
int main(void)
{
SysClkInit();
ADCInit();
TIM2Init();
DMAInit();
// if (pressed trim at power on) calibrate mode
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(1)
{
}
}
void SysClkInit()
{
RCC_DeInit(); // Reset RCC to default
RCC_HSEConfig(RCC_HSE_ON); // Enable HSE
ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp(); // Wait for HSE to stabilise
if (HSEStartUpStatus == SUCCESS) // If we are stable
{
RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK/1
RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK/1
RCC_PCLK1Config(RCC_HCLK_Div1); // PCLK1 = HCLK/1
// PLLCLK = (8MHzHSE/2) * 6 = 24 MHz
RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div2);
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_6);
RCC_PLLCmd(ENABLE); // Enable the PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // Wait for it to be ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // Use PLL as SYSCLK
while (RCC_GetSYSCLKSource() != 0x08); // Wait for switch over to happen
}
}
void ADCInit(void)
{
//Enable ADC1, GPIOA, and GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 |
RCC_APB2Periph_GPIOA |
RCC_APB2Periph_GPIOB |
RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure; //Variable used to setup the GPIO pins
//Configure ADC pins (PA0 -> Channel 1 to PA7 -> Channel 8) as analog inputs
GPIO_StructInit(&GPIO_InitStructure); // Reset init structure, if not it can cause issues...
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |
GPIO_Pin_1 |
GPIO_Pin_2 |
GPIO_Pin_3 |
GPIO_Pin_4 |
GPIO_Pin_5 |
GPIO_Pin_6 |
GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure); // init batt pin
ADC_InitTypeDef ADC_InitStructure;
//ADC1 configuration
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//We will convert multiple channels
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
//select single conversion mode
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//select no external triggering
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
//right 12-bit data alignment in ADC data register
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//9 channels conversion
ADC_InitStructure.ADC_NbrOfChannel = 9;
//load structure values to control and status registers
ADC_Init(ADC1, &ADC_InitStructure);
//configure each channel
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 7, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 9, ADC_SampleTime_41Cycles5);
//Enable ADC1
ADC_Cmd(ADC1, ENABLE);
//enable DMA for ADC
ADC_DMACmd(ADC1, ENABLE);
//Enable ADC1 reset calibration register
ADC_ResetCalibration(ADC1);
//Check the end of ADC1 reset calibration register
while(ADC_GetResetCalibrationStatus(ADC1));
//Start ADC1 calibration
ADC_StartCalibration(ADC1);
//Check the end of ADC1 calibration
while(ADC_GetCalibrationStatus(ADC1));
}
void DMAInit(void)
{
//enable DMA1 clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//create DMA structure
DMA_InitTypeDef DMA_InitStructure;
//reset DMA1 channe1 to default values;
DMA_DeInit(DMA1_Channel1);
//channel will be used for memory to memory transfer
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//setting normal mode (non circular)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//medium priority
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//source and destination data size word=32bit
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//automatic memory destination increment enable.
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//source address increment disable
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//Location assigned to peripheral register will be source
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//chunk of data to be transfered
DMA_InitStructure.DMA_BufferSize = ADC_ELEMENTS; // 8 channels + Batt sense
//source and destination start addresses
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_Buffer;
//send values to DMA registers
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable the DMA1 - Channel1
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = PPM_ELEMENTS; // 8 channels + 9 space + end
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM2_CCR1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)PPM_Buffer;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
// turning DMA on
DMA_Cmd(DMA1_Channel5, ENABLE);
}
void TIM2Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure ;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseStructure.TIM_Period = 22000 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 24 - 1; // 24 MHz / 24 (1 MHz tick)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_DMAConfig(TIM2, TIM_DMABase_CCR1, TIM_DMABurstLength_1Transfer);
// ''connecting'' DMA and TIM2
TIM_DMACmd(TIM2, TIM_DMA_CC1, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// turning on TIM3 and PWM outputs
TIM_Cmd(TIM2, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
// Enable the TIM2 gloabal Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM2_IRQHandler(void)
{
int i;
for (i = 1; i < PPM_ELEMENTS - 1; ++i) // Ignore first and last ppm value. Should always be 400 and 21999 respectively
{
if (i % 2 == 1)
{
PPM_Buffer[i] = PPM_Buffer[i - 1] + ADC_Buffer[(i - 1) / 2]/4 + 600;
}
else
{
PPM_Buffer[i] = PPM_Buffer[i - 1] + 400;
}
}
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
}

Posted on May 09, 2017 at 06:11

Could someone provide a short explanation of the main parts of the code, please? I have arduino code that uses interrupt on compare match to toggle the designated ppm pin. In what ways is this code different? I am just stepping into 32-bit microcontrollers. Any help will be greatly appreciated!