STM32F407VG Working code for reading 8 ch R/C PPM receiver
Posted: 08 Jul 2012 17:17
Hi,
This was the last step on getting all peripherals working in order to make my first STM32F407 autopilot. You can see all other examples in previous posts: DMA USART for Rx and TX, Dma mode for all 3 ADC's. For Pwm output for motors/servo mE team has already given one clear example.
Here we go: reading of PPM output of any R/C receiver, no matter PCM, 2.4Ghz FHSS etc, as all of them are sending on the output, pulse between 1 to 2 ms 50-70 times /s.
Timers TIM1 and TIM8 are used in Input Capture Mode, triggered in both edges:
For different registers settings please read Reference manual. In this example, I used one port pin as PWM output in order to feed the inputs of the TIM1, TIM8 (simulating one R/C output).
All four inputs from TIM1 and TIM8 are used. Total of 8 inputs.
program PWM_RC_Input
Dim rc1,rc2,rc3,rc4,rc5,rc6,rc7,rc8 as word
Dim rco1,rco2,rco3,rco4,rco5,rco6,rco7,rco8 as word
Dim flag1,flag2,flag3,flag4,flag5,flag6,flag7,flag8 as bit
Dim rc_out1,rc_out2,rc_out3,rc_out4 as word
Dim rc_out5,rc_out6,rc_out7,rc_out8 as word
Dim nr as byte
Dim print_txt as string[10]
Dim pwm_period as word
Dim current_duty as word
Dim Led3 as sbit at GPIOD_ODR.B13
'*****************************************
'Interrupt routine for capture ; keep it as small as possible
sub procedure RC_TIM1() iv IVT_INT_TIM1_CC ics ICS_AUTO
if TIM1_SR.1=1 then
rc5 = TIM1_CCR1
flag5=1
end if
if TIM1_SR.2=1 then
rc6 = TIM1_CCR2
flag6=1
end if
if TIM1_SR.3=1 then
rc7 = TIM1_CCR3
flag7=1
end if
if TIM1_SR.4=1 then
rc8 = TIM1_CCR4
flag8=1
end if
end sub
sub procedure RC_TIM8() iv IVT_INT_TIM8_CC ics ICS_AUTO
if TIM8_SR.1=1 then
rc1 = TIM8_CCR1
flag1=1
end if
if TIM8_SR.2=1 then
rc2 = TIM8_CCR2
flag2=1
end if
if TIM8_SR.3=1 then
rc3 = TIM8_CCR3
flag3=1
end if
if TIM8_SR.4=1 then
rc4 = TIM8_CCR4
flag4=1
end if
end sub
'*****************************************
main:
Rem Enable high performance mode, System frequency up to 168 MHz
RCC_APB1ENR.PWREN=1
'*******************************************************************************
UART2_Init_Advanced(256000, _UART_8_BIT_DATA, _UART_NOPARITY, _UART_ONE_STOPBIT, @_GPIO_MODULE_USART2_PD56)
'*******************************************************************************
GPIO_Digital_Output(@GPIOD_BASE, _GPIO_PINMASK_13) ' Set PORTD.13 (Led3) as digital output
'******************************
rem generated PPM output signal signal
current_duty=4600 ' 4600 for about 1ms and 9200 for 2ms
PWM_TIM2_Init(70) ' 70Hz (Futaba 2.4Ghz receiver refresh rate is approx 65Hz)
PWM_TIM2_Set_Duty(current_duty, _PWM_NON_INVERTED, _PWM_CHANNEL2)
PWM_TIM2_Start(_PWM_CHANNEL2, @_GPIO_MODULE_TIM2_CH2_PB3)
PWM_TIM2_Set_Duty(current_duty, _PWM_NON_INVERTED, _PWM_CHANNEL2)
'*******************************************************************************
rem Enable TIM1 and TIM8 Peripheral Clock
RCC_APB2ENR.TIM1EN=1
RCC_APB2ENR.TIM8EN=1
'*****************************
rem Enable Port_A and Port_C Peripheral Clock
RCC_AHB1ENR.GPIOAEN=1
RCC_AHB1ENR.GPIOCEN=1
'*****************************
rem Configure the R/C input pins
rem config in alternate function
GPIOA_MODER.17=1 GPIOA_MODER.19=1 GPIOA_MODER.21=1 GPIOA_MODER.23=1
GPIOC_MODER.13=1 GPIOC_MODER.15=1 GPIOC_MODER.17=1 GPIOC_MODER.19=1
rem config pin speed 50Mhz
'GPIOA_OSPEEDR.17=1 GPIOA_OSPEEDR.19=1 GPIOA_OSPEEDR.21=1 GPIOA_OSPEEDR.23=1
rem config pullup/pulldn to PULL DOWN
GPIOA_PUPDR.17=1 GPIOA_PUPDR.19=1 GPIOA_PUPDR.21=1 GPIOA_PUPDR.23=1
GPIOC_PUPDR.13=1 GPIOC_PUPDR.15=1 GPIOC_PUPDR.17=1 GPIOC_PUPDR.19=1
rem alternate function for PortA TIM1 is AF1 and PortC TIM8 is AF3
GPIOA_AFRH.0=1 GPIOA_AFRH.4=1 GPIOA_AFRH.8=1 GPIOA_AFRH.12=1
GPIOC_AFRL.24=1 GPIOC_AFRL.25=1 GPIOC_AFRL.28=1 GPIOC_AFRL.29=1
GPIOC_AFRH.0=1 GPIOC_AFRH.1=1 GPIOC_AFRH.4=1 GPIOC_AFRH.5=1
'*****************************
rem Configure TIM1 and TIM8 for Input Capture
rem Clk prescaler AHB2/(PSC+1)
TIM1_PSC=167 ' we have 1us resolution (1000 to 2000us )
TIM8_PSC=167
rem Select the Active input (CC1S,CC2S,CC3S,CC4S),CC1 on TI1,CC2 on TI2...
TIM1_CCMR1O.8=1 TIM1_CCMR1O.0=1 TIM1_CCMR2O.8=1 TIM1_CCMR2O.0=1
TIM8_CCMR1O.8=1 TIM8_CCMR1O.0=1 TIM8_CCMR2O.8=1 TIM8_CCMR2O.0=1
'*****************************
rem Select the edge of the active transition on the TIx channel (CC1P and CC1NP) ;both edges
TIM1_CCER.1=1 TIM1_CCER.3=1 TIM1_CCER.5=1 TIM1_CCER.7=1
TIM1_CCER.9=1 TIM1_CCER.11=1 TIM1_CCER.13=1 TIM1_CCER.15=1
TIM8_CCER.1=1 TIM8_CCER.3=1 TIM8_CCER.5=1 TIM8_CCER.7=1
TIM8_CCER.9=1 TIM8_CCER.11=1 TIM8_CCER.13=1 TIM8_CCER.15=1
'*******************************
rem Enable capture from the counter in to the capture register (CCxE)
TIM1_CCER.12=1 TIM1_CCER.8=1 TIM1_CCER.4=1 TIM1_CCER.0=1
TIM8_CCER.12=1 TIM8_CCER.8=1 TIM8_CCER.4=1 TIM8_CCER.0=1
rem Enable interrupt request by setting CCxIE bit
TIM1_DIER.1=1 TIM1_DIER.2=1 TIM1_DIER.3=1 TIM1_DIER.4=1
TIM8_DIER.1=1 TIM8_DIER.2=1 TIM8_DIER.3=1 TIM8_DIER.4=1
'******************************************************
Delay_ms(1000)
UART2_Write_Text("R/C Input Capture Test")
UART2_Write(13)
UART2_Write(10)
Delay_ms(1000)
'******************************************************
rem Start TIM1 and TIM8
TIM1_CR1.0=1
TIM8_CR1.0=1
rem Enable interrupts
EnableInterrupts()
NVIC_IntEnable(IVT_INT_TIM1_CC)
NVIC_IntEnable(IVT_INT_TIM8_CC)
'******************************************************
while True
'*******************************************************
'**************** R/C PPM INPUT ************************
'*******************************************************
if flag1=1 then
flag1=0
if (rc1-rco1) > 700 then
if (rc1-rco1)<2300 then
rc_out1=rc1-rco1
end if
end if
rco1=rc1
WordToStr(rc_out1, print_txt)
UART2_Write_Text("rc1= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'**********************
if flag2=1 then
flag2=0
if (rc2-rco2) > 700 then
if (rc2-rco2)<2300 then
rc_out2=rc2-rco2
end if
end if
rco2=rc2
WordToStr(rc_out2, print_txt)
UART2_Write_Text("rc2= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'*********************
if flag3=1 then
flag3=0
if (rc3-rco3) > 700 then
if (rc3-rco3)<2300 then
rc_out3=rc3-rco3
end if
end if
rco3=rc3
WordToStr(rc_out3, print_txt)
UART2_Write_Text("rc3= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'*********************
if flag4=1 then
flag4=0
if (rc4-rco4) > 700 then
if (rc4-rco4)<2300 then
rc_out4=rc4-rco4
end if
end if
rco4=rc4
WordToStr(rc_out4, print_txt)
UART2_Write_Text("rc4= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'************************
'************************
if flag5=1 then
flag5=0
if (rc5-rco5) > 700 then
if (rc5-rco5)<2300 then
rc_out5=rc5-rco5
end if
end if
rco5=rc5
WordToStr(rc_out5, print_txt)
UART2_Write_Text("rc5= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'**************************
if flag6=1 then
flag6=0
if (rc6-rco6) > 700 then
if (rc6-rco6)<2300 then
rc_out6=rc6-rco6
end if
end if
rco6=rc6
WordToStr(rc_out6, print_txt)
UART2_Write_Text("rc6= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'************************
if flag7=1 then
flag7=0
if (rc7-rco7) > 700 then
if (rc7-rco7)<2300 then
rc_out7=rc7-rco7
end if
end if
rco7=rc7
WordToStr(rc_out7, print_txt)
UART2_Write_Text("rc7= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'************************
if flag8=1 then
flag8=0
if (rc8-rco8) > 700 then
if (rc8-rco8)<2300 then
rc_out8=rc8-rco8
end if
end if
rco8=rc8
WordToStr(rc_out8, print_txt)
UART2_Write_Text("rc8= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'****************************************************
'************ END R/C PPM Input *********************
'****************************************************
wend
end.
Cheers,
Sergiu
This was the last step on getting all peripherals working in order to make my first STM32F407 autopilot. You can see all other examples in previous posts: DMA USART for Rx and TX, Dma mode for all 3 ADC's. For Pwm output for motors/servo mE team has already given one clear example.
Here we go: reading of PPM output of any R/C receiver, no matter PCM, 2.4Ghz FHSS etc, as all of them are sending on the output, pulse between 1 to 2 ms 50-70 times /s.
Timers TIM1 and TIM8 are used in Input Capture Mode, triggered in both edges:
For different registers settings please read Reference manual. In this example, I used one port pin as PWM output in order to feed the inputs of the TIM1, TIM8 (simulating one R/C output).
All four inputs from TIM1 and TIM8 are used. Total of 8 inputs.
program PWM_RC_Input
Dim rc1,rc2,rc3,rc4,rc5,rc6,rc7,rc8 as word
Dim rco1,rco2,rco3,rco4,rco5,rco6,rco7,rco8 as word
Dim flag1,flag2,flag3,flag4,flag5,flag6,flag7,flag8 as bit
Dim rc_out1,rc_out2,rc_out3,rc_out4 as word
Dim rc_out5,rc_out6,rc_out7,rc_out8 as word
Dim nr as byte
Dim print_txt as string[10]
Dim pwm_period as word
Dim current_duty as word
Dim Led3 as sbit at GPIOD_ODR.B13
'*****************************************
'Interrupt routine for capture ; keep it as small as possible
sub procedure RC_TIM1() iv IVT_INT_TIM1_CC ics ICS_AUTO
if TIM1_SR.1=1 then
rc5 = TIM1_CCR1
flag5=1
end if
if TIM1_SR.2=1 then
rc6 = TIM1_CCR2
flag6=1
end if
if TIM1_SR.3=1 then
rc7 = TIM1_CCR3
flag7=1
end if
if TIM1_SR.4=1 then
rc8 = TIM1_CCR4
flag8=1
end if
end sub
sub procedure RC_TIM8() iv IVT_INT_TIM8_CC ics ICS_AUTO
if TIM8_SR.1=1 then
rc1 = TIM8_CCR1
flag1=1
end if
if TIM8_SR.2=1 then
rc2 = TIM8_CCR2
flag2=1
end if
if TIM8_SR.3=1 then
rc3 = TIM8_CCR3
flag3=1
end if
if TIM8_SR.4=1 then
rc4 = TIM8_CCR4
flag4=1
end if
end sub
'*****************************************
main:
Rem Enable high performance mode, System frequency up to 168 MHz
RCC_APB1ENR.PWREN=1
'*******************************************************************************
UART2_Init_Advanced(256000, _UART_8_BIT_DATA, _UART_NOPARITY, _UART_ONE_STOPBIT, @_GPIO_MODULE_USART2_PD56)
'*******************************************************************************
GPIO_Digital_Output(@GPIOD_BASE, _GPIO_PINMASK_13) ' Set PORTD.13 (Led3) as digital output
'******************************
rem generated PPM output signal signal
current_duty=4600 ' 4600 for about 1ms and 9200 for 2ms
PWM_TIM2_Init(70) ' 70Hz (Futaba 2.4Ghz receiver refresh rate is approx 65Hz)
PWM_TIM2_Set_Duty(current_duty, _PWM_NON_INVERTED, _PWM_CHANNEL2)
PWM_TIM2_Start(_PWM_CHANNEL2, @_GPIO_MODULE_TIM2_CH2_PB3)
PWM_TIM2_Set_Duty(current_duty, _PWM_NON_INVERTED, _PWM_CHANNEL2)
'*******************************************************************************
rem Enable TIM1 and TIM8 Peripheral Clock
RCC_APB2ENR.TIM1EN=1
RCC_APB2ENR.TIM8EN=1
'*****************************
rem Enable Port_A and Port_C Peripheral Clock
RCC_AHB1ENR.GPIOAEN=1
RCC_AHB1ENR.GPIOCEN=1
'*****************************
rem Configure the R/C input pins
rem config in alternate function
GPIOA_MODER.17=1 GPIOA_MODER.19=1 GPIOA_MODER.21=1 GPIOA_MODER.23=1
GPIOC_MODER.13=1 GPIOC_MODER.15=1 GPIOC_MODER.17=1 GPIOC_MODER.19=1
rem config pin speed 50Mhz
'GPIOA_OSPEEDR.17=1 GPIOA_OSPEEDR.19=1 GPIOA_OSPEEDR.21=1 GPIOA_OSPEEDR.23=1
rem config pullup/pulldn to PULL DOWN
GPIOA_PUPDR.17=1 GPIOA_PUPDR.19=1 GPIOA_PUPDR.21=1 GPIOA_PUPDR.23=1
GPIOC_PUPDR.13=1 GPIOC_PUPDR.15=1 GPIOC_PUPDR.17=1 GPIOC_PUPDR.19=1
rem alternate function for PortA TIM1 is AF1 and PortC TIM8 is AF3
GPIOA_AFRH.0=1 GPIOA_AFRH.4=1 GPIOA_AFRH.8=1 GPIOA_AFRH.12=1
GPIOC_AFRL.24=1 GPIOC_AFRL.25=1 GPIOC_AFRL.28=1 GPIOC_AFRL.29=1
GPIOC_AFRH.0=1 GPIOC_AFRH.1=1 GPIOC_AFRH.4=1 GPIOC_AFRH.5=1
'*****************************
rem Configure TIM1 and TIM8 for Input Capture
rem Clk prescaler AHB2/(PSC+1)
TIM1_PSC=167 ' we have 1us resolution (1000 to 2000us )
TIM8_PSC=167
rem Select the Active input (CC1S,CC2S,CC3S,CC4S),CC1 on TI1,CC2 on TI2...
TIM1_CCMR1O.8=1 TIM1_CCMR1O.0=1 TIM1_CCMR2O.8=1 TIM1_CCMR2O.0=1
TIM8_CCMR1O.8=1 TIM8_CCMR1O.0=1 TIM8_CCMR2O.8=1 TIM8_CCMR2O.0=1
'*****************************
rem Select the edge of the active transition on the TIx channel (CC1P and CC1NP) ;both edges
TIM1_CCER.1=1 TIM1_CCER.3=1 TIM1_CCER.5=1 TIM1_CCER.7=1
TIM1_CCER.9=1 TIM1_CCER.11=1 TIM1_CCER.13=1 TIM1_CCER.15=1
TIM8_CCER.1=1 TIM8_CCER.3=1 TIM8_CCER.5=1 TIM8_CCER.7=1
TIM8_CCER.9=1 TIM8_CCER.11=1 TIM8_CCER.13=1 TIM8_CCER.15=1
'*******************************
rem Enable capture from the counter in to the capture register (CCxE)
TIM1_CCER.12=1 TIM1_CCER.8=1 TIM1_CCER.4=1 TIM1_CCER.0=1
TIM8_CCER.12=1 TIM8_CCER.8=1 TIM8_CCER.4=1 TIM8_CCER.0=1
rem Enable interrupt request by setting CCxIE bit
TIM1_DIER.1=1 TIM1_DIER.2=1 TIM1_DIER.3=1 TIM1_DIER.4=1
TIM8_DIER.1=1 TIM8_DIER.2=1 TIM8_DIER.3=1 TIM8_DIER.4=1
'******************************************************
Delay_ms(1000)
UART2_Write_Text("R/C Input Capture Test")
UART2_Write(13)
UART2_Write(10)
Delay_ms(1000)
'******************************************************
rem Start TIM1 and TIM8
TIM1_CR1.0=1
TIM8_CR1.0=1
rem Enable interrupts
EnableInterrupts()
NVIC_IntEnable(IVT_INT_TIM1_CC)
NVIC_IntEnable(IVT_INT_TIM8_CC)
'******************************************************
while True
'*******************************************************
'**************** R/C PPM INPUT ************************
'*******************************************************
if flag1=1 then
flag1=0
if (rc1-rco1) > 700 then
if (rc1-rco1)<2300 then
rc_out1=rc1-rco1
end if
end if
rco1=rc1
WordToStr(rc_out1, print_txt)
UART2_Write_Text("rc1= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'**********************
if flag2=1 then
flag2=0
if (rc2-rco2) > 700 then
if (rc2-rco2)<2300 then
rc_out2=rc2-rco2
end if
end if
rco2=rc2
WordToStr(rc_out2, print_txt)
UART2_Write_Text("rc2= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'*********************
if flag3=1 then
flag3=0
if (rc3-rco3) > 700 then
if (rc3-rco3)<2300 then
rc_out3=rc3-rco3
end if
end if
rco3=rc3
WordToStr(rc_out3, print_txt)
UART2_Write_Text("rc3= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'*********************
if flag4=1 then
flag4=0
if (rc4-rco4) > 700 then
if (rc4-rco4)<2300 then
rc_out4=rc4-rco4
end if
end if
rco4=rc4
WordToStr(rc_out4, print_txt)
UART2_Write_Text("rc4= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'************************
'************************
if flag5=1 then
flag5=0
if (rc5-rco5) > 700 then
if (rc5-rco5)<2300 then
rc_out5=rc5-rco5
end if
end if
rco5=rc5
WordToStr(rc_out5, print_txt)
UART2_Write_Text("rc5= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'**************************
if flag6=1 then
flag6=0
if (rc6-rco6) > 700 then
if (rc6-rco6)<2300 then
rc_out6=rc6-rco6
end if
end if
rco6=rc6
WordToStr(rc_out6, print_txt)
UART2_Write_Text("rc6= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'************************
if flag7=1 then
flag7=0
if (rc7-rco7) > 700 then
if (rc7-rco7)<2300 then
rc_out7=rc7-rco7
end if
end if
rco7=rc7
WordToStr(rc_out7, print_txt)
UART2_Write_Text("rc7= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'************************
if flag8=1 then
flag8=0
if (rc8-rco8) > 700 then
if (rc8-rco8)<2300 then
rc_out8=rc8-rco8
end if
end if
rco8=rc8
WordToStr(rc_out8, print_txt)
UART2_Write_Text("rc8= ")
UART2_Write_Text(print_txt)
UART2_Write(13)
UART2_Write(10)
end if
'****************************************************
'************ END R/C PPM Input *********************
'****************************************************
wend
end.
Cheers,
Sergiu