cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Discovery, RC Receiver, PWM Input

benjamin-chia
Associate
Posted on February 07, 2014 at 08:08

Hi,

I want to acquire a PWM input from a Futaba RC Receiver :http://www.futaba-rc.com/systems/futk6000.html Using this input I would like to test it out by varying the brightness of the onboard LED. I have tried using the Peripheral Library - PWM input but to no avail. I am getting confused with the various timers, and their respective channels. If anybody could point me in the right direction it would be much appreciated. My code is below. Thanks again!!! Ben

/*
* futaba.c
*
* Created on: 3 Feb 2014
* Author: Benjamin
*/
/*
RC PulseIn Joystick
By: Nick Poole
SparkFun Electronics
Date: 5
License: CC-BY SA 3.0 - Creative commons share-alike 3.0
use this code however you'd like, just keep this license and
attribute. L et me know if you make hugely, awesome, great changes.
*/
#include ''stm32f4xx.h''
#include ''stm32f4xx_rcc.h''
#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_tim.h''
#include ''stm32f4xx_syscfg.h''
#include ''stm32f4xx_exti.h''
#include ''misc.h''
uint32_t Current;
int ch1; // Here's where we'll keep our channel values
//int ch2;
void Delay1(__IO uint32_t nCount) {
while(nCount--) {
}
}
void TIM_Config3(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* TIM4 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* GPIOB clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/* TIM4 channel2 configuration : PB.07 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Connect TIM pin to AF2 */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4);
/*TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_TIxExternalClockConfig(TIM4, TIM_TIxExternalCLK1Source_TI1, TIM_ICPolarity_Rising, 0);*/
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal, TIM2 is 32-bit counter
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Enable the TIM4 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void initLeds10() {
/* GPIOG Peripheral clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure PG6 and PG8 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
}
int initfutaba(void){
TIM_Config3();
initLeds10();
return 0;
}
int futaba(void) {
TIM_ICInitTypeDef TIM_ICInitStructure;
/* ---------------------------------------------------------------------------
TIM4 configuration: PWM Input mode
In this example TIM4 input clock (TIM4CLK) is set to 2 * APB1 clock (PCLK1),
since APB1 prescaler is different from 1.
TIM4CLK = 2 * PCLK1
PCLK1 = HCLK / 4
=> TIM4CLK = HCLK / 2 = SystemCoreClock /2
External Signal Frequency = TIM4 counter clock / TIM4_CCR2 in Hz.
External Signal DutyCycle = (TIM4_CCR1*100)/(TIM4_CCR2) in %.
--------------------------------------------------------------------------- */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM4, &TIM_ICInitStructure);
/* Select the TIM4 Input Trigger: TI2FP2 */
TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
/* Select the slave Mode: Reset Mode */
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);
/* TIM enable counter */
TIM_Cmd(TIM4, ENABLE);
/* Enable the CC2 Interrupt Request */
TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
//ch1 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6); // Read the pulse width of
//ch1 = TIM_GetCapture2(TIM4);
TIM_SetCompare4(TIM4, Current);
//ch2 = pulseIn(6, HIGH, 25000); // each channel
/* I found that Ch1 was my left switch and that it
floats around 900 in the off position and jumps to
around 1100 in the on position */
Delay1(100);
return 0;
}
volatile uint32_t Freq[4];
void TIM4_IRQHandler(void)
{
uint32_t Delta;
static uint32_t Last[4];
if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)
{
/* Clear TIM2_CH1 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);
Current = TIM_GetCapture2(TIM4);
// Delta = Current - Last[0];
// Last[0] = Current;
// if (Delta)
// Freq[0] = 1000000 / Delta; // 1MHz clock
// ..
}
}

#discovery #stm32 #pwm-input #stm32f4
5 REPLIES 5
chen
Associate II
Posted on February 07, 2014 at 12:06

Hi

'' I would like to test it out by varying the brightness of the onboard LED.''

Not exactly very easy to see the result - you would be better to do some kind of text based output - eg USART or USB CDC (USB serial)

If you must do it this way - can you view it on an oscilloscope?

''I have tried using the Peripheral Library - PWM input but to no avail. I am getting confused with the various timers, and their respective channels. If anybody could point me in the right direction it would be much appreciated.''

OK, the timers are complicated when you go beyond the simple count, overflow, reset.

The documentation (reference manual) is essential BUT is not that helpful. Not sure if there is a Peripheral Library manual - I just read the code to work out what it is doing to the registers)

First Understand the Timer in Capture Mode OR Compare Mode.

These are the modes that allow the measuring of PWM.

Look at the block diagram for the timer(s) - you need to work out which timer is attached to which Capture/Compare reg and which input/outputs - this will determine which Timer you use.

Your PWM results will be in a pair of CCR registers.

The timer need to be configured to capture an edge into 1 CCR register.

The other (oppisite) edge needs to be capure into the other CCR register.

You can choose to program the registers directly or you can use the Peripheral Library.

You have not said which STM32F part you are using. Even so, most will be clocking 10/100 times faster that the PWM of RC signals. So I would expect there to be prescalars involved.

''My code is below.''

Sorry, I do not have time to visually debug code.

I can only help you by giving advice or guidance.

Posted on February 07, 2014 at 20:13

// Portion from
// STM32 RC Servo Demo for 168 MHz STM32F4 Discovery - sourcer32@gmail.com
/**************************************************************************************/
volatile uint16_t Reading[2]; // Readings from PB4 TIM3_CH1 (1us units)
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
Reading[0] = TIM_GetCapture1(TIM3); // Period (us) ~20000
Reading[1] = TIM_GetCapture2(TIM3); // Duty/Width (us) ~1500 or whatever (600-2400 us)
}
}
/**************************************************************************************/
void TIM3_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* GPIO clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/* Configure GPIO input for timer */
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_100MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // PB4 TIM3_CH1
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Connect TIM3 pins to AF */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_TIM3);
/* Enable the TIM3 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration - SystemCoreClock = 168000000 for 168 MHz board ABP1 @ 42 MHz (DIV4) */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; // Maximal
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* Configure PWM Input Capture */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // PB4 TIM3_CH1
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
/* Select the TIM3 Input Trigger: TI1FP1 */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
/* Select the slave Mode: Reset Mode */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
/* TIM Interrupts enable */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
}
/**************************************************************************************/

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Rogers.Gary
Senior II
Posted on February 28, 2015 at 21:59

clive 1,

In this PWM capture example you provided, the code runs as is, on my Discovery board. I am sending low frequency pulses to PB4 and the values are displayed.

Since I will not be able to use PB4 as it's reserved, I want switch from capture channel 1, to channel 4, on Timer 3, using PB1 as alternate mapping function. The code is below.

However, it is not capturing the signals. Why would it not work on this channel?

Thank you,

Gary

/******************************************************************/

void TIM3_Configuration(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_ICInitTypeDef TIM_ICInitStructure;

    NVIC_InitTypeDef NVIC_InitStructure;

    GPIO_InitTypeDef GPIO_InitStructure;

    /* GPIOB clock enable for capture of Schmitt - triggered LOG Amp output */

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);    

    

    /* TIM3 clock enable for capture of Schmitt - triggered LOG Amp output */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    /* Configure GPIO input for log amp capture timer */

    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_100MHz;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // PB4 TIM3_CH4

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* Connect TIM3 pins to AF */

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_TIM3);

        

    /* Enable the TIM3 global Interrupt */

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

    NVIC_Init(&NVIC_InitStructure);

 

        TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)

    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;

    

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

 

    /* Configure PWM Input Capture */

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_4; // PB1 TIM3_CH4

    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

    TIM_ICInitStructure.TIM_ICFilter = 0x0;

    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);

 

    /* Select the TIM3 Input Trigger: TI1FP1 */

    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);

 

    /* Select the slave Mode: Reset Mode */

    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

    TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);

 

    /* TIM Interrupts enable */

    TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);

 

    /* TIM3 enable counter */

    TIM_Cmd(TIM3, ENABLE);

}

Posted on February 28, 2015 at 22:33

PWM Input uses a pairing of channel 1 and 2, with either TI1 or TI2 (Timer Input (Channel))

You'd want to look at doing a regular Input Capture of the edges to use a different channel(s), but this needs more management because you now have to compute delta measurements because the timer doesn't reset.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Rogers.Gary
Senior II
Posted on February 28, 2015 at 23:35

That seems reasonable given the ''TI1/TI2'' nomenclature, and explains why it doesn't operate on Channel 4.

When I said PB4 was reserved, I meant that it was connected to a JTAG header, which uses PB4 as NJTRST.  If there's no JTAG header connected, and no pullups for JTAG on board (they're external) do you foresee any problems?

Thanks,

Gary