News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Trouble with USART

Started by midali, Jan 08, 2025, 02:14 AM

Previous topic - Next topic

midali

Hello to all,

I have a master with 16F1938 and slave with 18F26k20 connected via Usart . In Rx and Tx if I set all variables to bytes , I receive the correct values , but I want to sent/receive a word variables . In this case I receive :
6  4  26  4  6
16  4  26  4  6
16  4  26  4  6
16  4  26  4  6
16  4  26  4  6

Master :
Device = 16F1938

Config1 FCMEN_OFF, FOSC_INTOSC, WDTE_OFF, MCLRE_OFF, PWRTE_OFF, CP_ON, MCLRE_OFF, BOREN_OFF, CLKOUTEN_OFF, FCMEN_OFF
Config2 WRT_OFF, VCAPEN_OFF, PLLEN_OFF, STVREN_OFF, LVP_OFF

Declare  Xtal = 32
OSCCON  = %11110100 'set to 8 x 4PLL MHz

Declare Hserial_Clear  = On
Declare Hserial_Baud   =  115200

PORTC.7 = 1

Dim MyWord_1 As Word =1010
Dim MyWord_2 As Word =1020
Dim MyWord_3 As Word =1030
Dim MyWord_4 As Word =1040
Dim MyWord_5 As Word =1050
   
Main:
    HSerOut [1, MyWord_1, MyWord_2,MyWord_3,MyWord_4,MyWord_5]
    DelayMS 1000     
GoTo Main

Slave:
Device 18F26K20
                                                                                                                         
Declare  Xtal = 16
OSCCON  = %01111100

'*****************Config USART INTERUPT*************************
INTCON.7 = 1    'GIE = 1   - Enable Global Interrupts
INTCON.6 = 1    'PEIE = 1  - Peripheral/Low-Priority Interrupt Enable bit
PIE1.5   = 1    'RC1IE     - EUSART1 Receive Interrupt Enable bit

;Calculated Baudrate = 114286 @ Xtal 16MHz, Error = -0.79%
RCSTA     = 144 ; Enable continuous receive
TXSTA     = 36  ; Enable transmit, BRGH = 1
SPBRG     = 34  ; Baud Rate Generator Low Byte Value
SPBRGH    = 0   ; Baud Rate Generator High Byte Value
BAUDCON.3 = 1   ; Enable the 16 bit Baud Rate Generator
'**************************************************************
'****************Variables*************************************
TRISC  = %10000000
Dim MyWord_[5]   As Word
Dim Tempbyte     As Word
Dim RC1IF        As PIR1.5               'Eusart receive buffer is active
Dim ind          As Byte
'*************************************************************
GoTo main

'*****************Interupt routine****************************
 On_Interrupt GoTo Isr
Isr:
    Context Save

    If RC1IF = 1 Then
        Tempbyte = RCREG                 'load received buffer in Tempbyte
        If Tempbyte = 1 Or ind > 4 Then
            ind = 0           
        Else
            MyWord_[ind] = Tempbyte          'attribute a value to byte_ from header
            Inc ind
        End If
     EndIf
    PIE1.5 = 1
   
    Context Restore
'************************************************************   
'*****************Programm***********************************
main:
   Do:
       HRSOutLn Dec MyWord_[0],"  " , Dec MyWord_[1],"  ", Dec MyWord_[2], "  ",Dec MyWord_[3], "  ", Dec MyWord_[4]
   Loop
'***********************************************************

'-------------------------Set registry----------------------------
 Config_Start
'   FOSC = HS ; HS oscillator
'   FOSC = HSPLL ; HS oscillator, PLL enabled (Clock Frequency = 4 x FOSC1)
   FOSC = INTIO67 ; INTERNAL OSCILLATOR .PORTA.6 AND 7 I/O's
   FCMEN = OFF ; Fail-Safe Clock Monitor disabled
   IESO = OFF ; Oscillator Switchover mode disabled
   PWRT = OFF ; PWRT enabled
   BOREN = SBORDIS ; Brown-out Reset enabled and controlled by software (SBOREN is enabled)
   BORV = 18 ; VBOR set to 2.7 V nominal
   WDTEN = OFF ; WDT is controlled by SWDTEN bit of the WDTCON register
   MCLRE = OFF ; MCLR pin enabled, RE3 input pin disabled
   HFOFST = OFF ; The system clock is held off until the HF-INTOSC is stable.
   LPT1OSC = OFF ; Disabled, T1 operates in standard power mode.
   PBADEN = OFF ; PORTB<4:0> pins are configured as digital I/O on Reset
   STVREN = OFF ; Stack full/underflow will cause Reset                                                      '-aici
   LVP = OFF ; Single-Supply ICSP disabled
   XINST = OFF ; Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
   Debug = OFF ; Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins
   Cp0 = On ; Block 0 (000800-003FFFh) not code-protected
   CP1 = On ; Block 1 (004000-007FFFh) not code-protected
   CP2 = On ; Block 2 (008000-00BFFFh) not code-protected
   CP3 = On ; Block 3 (00C000-00FFFFh) not code-protected
   CPB = On ; Boot block (000000-0007FFh) not code-protected
   CPD = On ; Data EEPROM not code-protected
   WRT0 = OFF ; Block 0 (000800-003FFFh) not write-protected
   WRT1 = OFF ; Block 1 (004000-007FFFh) not write-protected
   WRT2 = OFF ; Block 2 (008000-00BFFFh) not write-protected
   WRT3 = OFF ; Block 3 (00C000-00FFFFh) not write-protected
   WRTB = OFF ; Boot block (000000-0007FFh) not write-protected
   WRTC = OFF ; Configuration registers (300000-3000FFh) not write-protected
   WRTD = OFF ; Data EEPROM not write-protected
   EBTR0 = OFF ; Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
   EBTR1 = OFF ; Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
   EBTR2 = OFF ; Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
   EBTR3 = OFF ; Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
   EBTRB = OFF ; Boot block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End


Something I made wrong and I spend a full day to solve this issue without succes . Can somebody show me the right way, please ?

Thank you !


Frizie

Sometimes is placing a pull-up resistor on the lines the solution (10k)
Ohm sweet Ohm | www.picbasic.nl

midali

Hi Frizie !

 Rx and Tx works well if I dim all variables to bytes . The comunication troubles appear when I dim  variables  to word .

John Lawton

A serial packet is an 8 bit data byte top and tailed by start and stop bits.

So you can't send a word in a serial packet, you have to split a word into two bytes then recombine them at the receiving end.

John

midali

Hi John ,

Another way to transmit a word variables via USART ?
Finally I want make a convertor from 6 x RC Pulses to standard FlySky IBUS , so it look like  : $20, $40, Word_1, Word_2........

John Lawton

Create aliases to the two bytes in each word then transmit those in your serial statement. See the 8 bit manual page 32

Assuming your word variable is called MyWord

Create byte aliases:

Dim MyWord_Hi as MyWord.HighByte
Dim MyWord_Lo as MyWord.LowByte


Then use:
HSerOut [MyWord_Hi, MyWord_Lo]

John


david

You may be better off to use a Flysky rx that has PWM, PPM and iBus outputs.  Something like the FS-iA6B.
The iBus protocol is something like this-
115200 baud rate
8N1 protocol
32 byte frame consisting of -
2 byte start  ($20,$40)
14x 2 byte channel values sent little endian
2 byte checksum/stop
Frame rate 7mS/140Hz

It's easy enough to decode iBus into discrete Word values but I don't understand your application and why you want to generate an iBus stream when a complete receiver with iBus would likely be cheaper and simpler.

Cheers,
David


midali

Hi David,

I made a device for RC that only works on Ibus. Now I want to make an adapter from classic receivers to Ibus.

This is code from PWM to Ibus adapter :

'***************** Serial port declares ********************************
Declare Hserial_Baud=115200
Declare HRSOut_Pin = PORTC.5
Declare Hserial_SPBRG=34
Declare Hserial_Clear=On

'****************** Variables declares ********************************
Symbol Ch1_Rx = PORTC.2
Symbol Ch2_Rx = PORTC.1
Symbol Ch3_Rx = PORTC.0
Symbol Ch4_Rx = PORTA.2
Symbol Ch5_Rx = PORTA.4
Symbol Ch6_Rx = PORTA.5           
Symbol Time = TMR1L.Word
Dim Ch1_start As Word
Dim Ch2_start As Word
Dim Ch3_start As Word
Dim Ch4_start As Word
Dim Ch5_start As Word
Dim Ch6_start As Word
Dim Ch1_end   As Word
Dim Ch2_end   As Word
Dim Ch3_end   As Word
Dim Ch4_end   As Word
Dim Ch5_end   As Word
Dim Ch6_end   As Word
Dim Ch1       As Word
Dim Ch2       As Word
Dim Ch3       As Word
Dim Ch4       As Word
Dim Ch5       As Word
Dim Ch6       As Word
Dim flag_ch1  As Byte
Dim flag_ch2  As Byte
Dim flag_ch3  As Byte
Dim flag_ch4  As Byte
Dim flag_ch5  As Byte
Dim flag_ch6  As Byte
Dim i         As Byte
'************************ Reset values  ********************************
begin:
  T1CON=0x32 : Time = 0
  flag_ch1 = 0 : flag_ch2 = 0 : flag_ch3 = 0 : flag_ch4 = 0 : flag_ch5 = 0 : flag_ch6 = 0
'*************************Wait pulse ********************************** 
wait_pulse:
  If Ch1_Rx = 0 And Ch2_Rx = 0 And Ch3_Rx = 0 And Ch4_Rx = 0 And Ch5_Rx = 0 And Ch6_Rx = 0 Then GoTo wait_pulse         
    T1CON=0x33   
'****************** Read pulses lenght ********************************     
read_pulses: 
  If Ch1_Rx = 1 And flag_ch1 = 0 Then Ch1_start = Time : flag_ch1 = 1
  If Ch1_Rx = 0 And flag_ch1 = 1 Then Ch1_end   = Time : flag_ch1 = 2
    Ch1 = Ch1_end - Ch1_start
   
  If Ch2_Rx = 1 And flag_ch2 = 0 Then Ch2_start = Time : flag_ch2 = 1
  If Ch2_Rx = 0 And flag_ch2 = 1 Then Ch2_end   = Time : flag_ch2 = 2
    Ch2 = Ch2_end - Ch2_start
   
  If Ch3_Rx = 1 And flag_ch3 = 0 Then Ch3_start = Time : flag_ch3 = 1
  If Ch3_Rx = 0 And flag_ch3 = 1 Then Ch3_end   = Time : flag_ch3 = 2
    Ch3 = Ch3_end - Ch3_start
   
  If Ch4_Rx = 1 And flag_ch4 = 0 Then Ch4_start = Time : flag_ch4 = 1
  If Ch4_Rx = 0 And flag_ch4 = 1 Then Ch4_end   = Time : flag_ch4 = 2
    Ch4 = Ch4_end - Ch4_start
   
  If Ch5_Rx = 1 And flag_ch5 = 0 Then Ch5_start = Time : flag_ch5 = 1
  If Ch5_Rx = 0 And flag_ch5 = 1 Then Ch5_end   = Time : flag_ch5 = 2
    Ch5 = Ch5_end - Ch5_start
   
  If Ch6_Rx = 1 And flag_ch6 = 0 Then Ch6_start = Time : flag_ch6 = 1
  If Ch6_Rx = 0 And flag_ch6 = 1 Then Ch6_end   = Time : flag_ch6 = 2
    Ch6 = Ch6_end - Ch6_start                       
 
  If flag_ch1 + flag_ch2 + flag_ch3 + flag_ch4 + flag_ch5 + flag_ch6 = 12 Then   
    GoTo  serial_out
  EndIf       
   
GoTo read_pulses
'****************** Sent pulses on USART *******************************
serial_out:
     T1CON=0x32
         HRSOut $20,$40,Ch1,Ch2,Ch3,Ch4,Ch5,Ch6
Return

In Ibus device I receive data with HserIn but I want to change it using the Usart Interupts .


pjmylle

Receiving through interrupts is simpel.
First enable interrupts (INTCON and PIE reg), Create your interrupt service routine (ISR) and check if RXif is set.
If so, read the RCREG and store it or process it. Also check if there's no frame (FERR) or overrun (EORR) error.
Clear the RCif flag and exit the ISR.
IF you're interested, I have some code to read a PPM signal. Made a converter to emulate a USB gamepad controller.
My RC transmitter was the gamepad controller and could then be used it in the simulator.
Must warn you, there's little comment in the code so you'll spend some time figuring it out.

david

Hi midali,
Just be careful  - you may find that your "classic receivers" are not all the same.  I have some basic Flysky rxs that I'm sure output Ch3 as the first channel after the end of frame.  Also, some receivers output in broadside mode - updating all PWM channels at the same time rather than serially.   Maybe I have some odd ones but if you're about to embark on a commercial product I would check out the format of a few different types of receivers in PWM mode.  PPM may be more disciplined but who uses that these days?  Sure it's serial format but it's still analog data.
No checksum needed on the iBus stream?
Good luck with your project.

Cheers,
David

pjmylle

You could use the interrupt on change feature to monitor the servo or PWM outputs of your receiver (limited by 4 on your chip if monitoring all at the same time). Let a timer run and store the port status along with the timer value in an array is the port state changes. In your main loop you could parse the data. Or are the PWM signals follow each other (they do not start at the same time), then you could OR the signals together and read them sequentially. Use a second  pin to monitor the first signal for synchronisation.
PPM if like servo signals but cascaded. The sync happens with a longer puls than the channel pulses followed by the channels value coded in puls lengths.
If you want to monitor ibus information, you could use EUSART and detect the start header and store the data in an array in the ISR. You can also detect a pause period in the reception to detect when the last byte has been received. The main loop then processes the information.

Pepe

#11
Demo proteus with interrups uart

midali

Quote from: pjmylle on Jan 08, 2025, 08:26 PMReceiving through interrupts is simpel.

The receiving byte variables in my interrupt work well . My trouble are word variables. John said right that is necessary split a word into two bytes . Its interesting to show your PPM code...thank you!

Quote from: david on Jan 08, 2025, 10:52 PM...Ch3 as the first channel after the end of frame.... 
...No checksum needed on the iBus stream?
...Good luck with your project.

Wich FlySky model have the Ch3 after the end of frame ? I don't know that!
In my devices is no need the checksum
Thank you David.

Quote from: Pepe on Jan 09, 2025, 02:28 AMDemo proteus with interrups uart

I haven't installed Proteus. With your hex files are missing out serial data to PC Terminal ...thank you Pepe

Pepe


david

#14
Hi midali,
I think you will find some of the smaller, 3 channel receivers have the channel order somewhat mixed up.
I've just checked a Hobby King HK GT2R which is a rebranded version of a Flysky receiver and it has Ch2 first followed by Ch1 followed by Ch3.  The attached shows Ch1(top), Ch2 (mid) and Ch3 (bot)
I also think you may find that the larger receivers (8-10ch) update all channels in parallel.  With 10 channels it's not possible to have all the channels fit within the 20mS frame period if using a serial format.
I have no idea what Spectrum, Frsky, Futaba and others may get up to but it could be a mine field for you.

Just a second thought on this - it may be that this channel order quirk is all in the tx.  Ch1 PWM is coming out of Ch1 on the rx so no problems there but the tx may be encoding Ch2 first and sending it then Ch 1????

Cheers,
David

Pepe

#15
Here is the Sources with Proteus example.

midali

I tested and work perfectly .
Pepe you are a great man , like many users from this forum .
I have no words to thank you for help !

pjmylle

Here it is. This does not compile anymore. Was written on an older version of proton IDE. The USB will give errors.

Device = 18F2550
On_Low_Interrupt GoTo Isr                    'link interrupt routine
On_Interrupt GoTo Isr
Xtal = 48
USBOut_Auto_Poll = On
Config_Start
PLLDIV=2
CPUDIV=OSC1_PLL2
USBDIV=2
FOSC=HSPLL_HS
FCMEN=OFF
IESO=OFF
PWRT=On
BOR=On
BORV=0
VREGEN=On         
WDT=OFF
WDTPS=32768
MCLRE=On
LPT1OSC=OFF
PBADEN=OFF
CCP2MX=OFF
STVREN=On
LVP=OFF
'ICPRT=OFF
XINST=OFF
Debug=OFF
Cp0=OFF
CP1=OFF
CP2=OFF
CP3=OFF
CPB=OFF
CPD=OFF
WRT0=OFF
WRT1=OFF
WRT2=OFF
WRT3=OFF
WRTB=OFF
WRTC=OFF
WRTD=OFF
EBTR0=OFF
EBTR1=OFF
EBTR2=OFF
EBTR3=OFF
EBTRB=OFF
Config_End
All_Digital = true
Reminders = OFF
USB_Descriptor = "gamepad.INC"
All_Digital = True

'RCSTA = $80 ' Enable serial port & continuous receive
'TXSTA = $24 ' Enable transmit, BRGH = 1
'SPBRG = 12  ' 230400 Baud @ 48MHz, 0,16%

       
Symbol T0IF = INTCON.2
Symbol T1IF = PIR1.0
Symbol T2IF = PIR1.1
Symbol T1ON = T1CON.0
Symbol IOCIF = INTCON.0
Symbol INT2IF = INTCON3.1
Symbol GIE = INTCON.7
Symbol INTEDG2 = INTCON2.4
Symbol led_Act = 1
Symbol led_inAct = 0
Symbol USB_OK = LATA.0
Symbol USB_NOK = LATA.1
Symbol PPM_OK = LATA.2
Symbol PPM_NOK = LATA.3
Symbol statusled0 = LATA.4
Symbol statusled1 = LATA.5
Symbol tmr0Reload = 220
Symbol tmr2Reload = 22
Symbol PPM_Min = 945
Symbol PPM_Max = 2055
Symbol PPM_Sync = 3500
Symbol PPM_PULSE_dif = 30
Symbol USB_data_max = 255

'recalc the constants to scale according to timer 1
Symbol PPM_Max_t = (PPM_Max * 3)'/2
Symbol PPM_Min_t = (PPM_Min * 3)'/2
Symbol PPM_Sync_t = (PPM_Sync * 3)'/2
Symbol PPM_PULSE_dif_t = PPM_PULSE_dif * 3'/2



Dim USBOUT1[8] As Byte
'Symbol led1 = PORTA.3
'Symbol led2 = PORTA.4

Dim PP0             As Byte System
'DETACHED_STATE 0
'ATTACHED_STATE 1
'POWERED_STATE 2
'DEFAULT_STATE 3
'ADDRESS_PENDING_STATE 4
'ADDRESS_STATE 5
'CONFIGURED_STATE 6
Dim divider         As Word
Dim X As Byte
Dim Y As Byte
Dim Z As Byte
Dim Ry As Byte
Dim Rx As Byte
Dim Rz As Byte
Dim buttons As Word
Dim timerdump As Word
Dim timerlow As Word
Dim timerhigh As Word
Dim tmrtmp As Byte
Dim pulse_Length As Word
Dim pulse_Length_min As Word
Dim pulse_Length_max As Word
Dim tempwrd As Word
Dim PPM_NOC_det As Byte 'number of ppm channels detected
Dim PPM_NOC As Byte 'number of ppm channels expected
Dim mathtmp As Dword
Dim time_add As Word
Dim synced As Bit
Dim learned As Bit
Dim counter1 As Byte
Dim errorcounter As Byte
Dim ppm_pulse As Bit
Dim send_to_USB As Bit
Dim USB_ready As Bit
Dim index As Byte
Dim timer As Word

Dim PPM_status As Byte
'bit 0 = rising edge detected
'bit 1 = falling edge detected
'bit 2 = pulse error [1 = error, 0 = no error]
'bit 3 = polarity p [0 = negative pulses, 1 = positive pulses]
'bit 4 = low time pulse width match
'bit 5 = high time pulse width match
'bit 6 = channels counted [0 = channels not counted, 1 = channels counted]
'bit 7 = sync detected
 
'DelayMS 1000
TRISA = %11000000
PORTA = 0
TRISB = %11111111
TRISC = %10111010       
LATA = 0
Clear

T0IF = 0
TMR0H = tmr0Reload
TMR0L = 0
T0CON = %10001000
T1CON = %10100001   '1/4 prescaler 16b int osc => 3ms timer
T2CON = 127         '16 post & prescaler interrupt every 5ms

USB_OK = led_Act
PPM_NOK = led_Act
DelayMS 500
USB_OK = led_inAct
PPM_NOK = led_inAct
USB_NOK = led_Act
PPM_OK = led_Act
DelayMS 500
USB_NOK = led_inAct
PPM_OK = led_inAct

'USB_OK = led_Act
'DelayMS 250
'USB_OK = led_inAct
'USB_NOK = led_Act
'DelayMS 250
'USB_NOK = led_inAct
'PPM_OK = led_Act
'DelayMS 250
'PPM_OK = led_inAct
'PPM_NOK = led_Act
'DelayMS 250
'PPM_NOK = led_inAct
DelayMS 250

INTCON = 0
INTCON2 = 128 'disable portb pullups
INTCON3 = %10010000 'enable int2 interrupts
GIE = 1

main:
    If T1IF = 1 Then
        If learned = 0 Then
            counter1 = 0
        Else
            Inc errorcounter
        EndIf
        If USB_ready = 1 Then 'when usb is ready
            Clear USBOUT1
            GoSub send_report 'send blank report
        EndIf
        T1IF = 0
    EndIf   
        If (PPM_status & $03) != 0 Then 'edge detected
'bit 0 = rising edge detected
'bit 1 = falling edge detected
'bit 2 = pulse error [1 = error, 0 = no error]
'bit 3 = polarity p [0 = negative pulses, 1 = positive pulses]
'bit 4 = low time pulse width match
'bit 5 = high time pulse width match
'bit 6 = low vs high timing [0 = L < H, 1 = L > H]
'bit 7 = sync detected
            tempwrd = timerlow + timerhigh
            PPM_status = PPM_status & %00001111
            If tempwrd > PPM_Sync_t Then PPM_status.7 = 1  'measured time larger than sync time
           
            If timerhigh < pulse_Length_max Then 'high time matches pulse time
                If timerhigh > pulse_Length_min Then PPM_status.5 = 1
            EndIf
            If timerlow < pulse_Length_max Then 'low time matches pulse time
                If timerlow > pulse_Length_min Then PPM_status.4 = 1
            EndIf
           
            If timerlow > timerhigh Then PPM_status.6 = 1 'low vs high timing   
                               
            If (PPM_status & %00111000) = %00001000 Then PPM_status.2 = 1 'timing error detected pol doesn't match pulse time
            If (PPM_status & %00111000) = %00010100 Then PPM_status.2 = 1 'timing error detected pol doesn't match pulse time
            If tempwrd < PPM_Min_t Then PPM_status.2 = 1 'minimum timing error detected
            If tempwrd > PPM_Max_t Then
                If PPM_status.7 = 0 Then PPM_status.2 = 1 'maximum timing error detected
            EndIf

            If (PPM_status & %10101110) = %00101010 Then 'no sync, positive pulse, falling edge, no error and pos polarity detected
                Inc PPM_NOC_det
                ppm_pulse = 1
            ElseIf (PPM_status & %10011101) = %00010001 Then 'no sync, negative pulse, rising edge, no error and neg polarity detected
                Inc PPM_NOC_det
                ppm_pulse = 1
            EndIf
           
            If learned = 1 Then
                If PPM_status.2 = 1 Then 'error detected
                    If tempwrd > PPM_Max_t Then 'time below maximum allowed time
                        'added here   
                        tempwrd = tempwrd + time_add
                        PPM_status.2 = 0
                    Else
                        'error here drop frame
                        PPM_NOC_det = 0
                        GoTo frame2_end
                    EndIf
                Else
                    If (PPM_status & %11111111) = %11101010 Then 'positive pulse, sync, falling edge, no error and pos polarity detected
                        GoTo frame2
                    ElseIf (PPM_status & %11111111) = %10010001 Then 'negative pulse, sync, rising edge, no error and neg polarity detected
                        GoTo frame2
                    ElseIf (PPM_status & %10111011) = %10000010 Then 'sync and falling edge detected and polarity
                        PPM_NOC_det = 0
                    ElseIf (PPM_status & %10111011) = %10001001 Then 'sync and rising edge detected and polarity
                        PPM_NOC_det = 0
                    ElseIf ppm_pulse = 1 Then
                        GoSub calc_servo
                        ppm_pulse = 0
                    EndIf
                    GoTo frame2_end
frame2:
                    If PPM_NOC_det = PPM_NOC Then
                        'usb out
                        send_to_USB = 1
                    Else
                        Inc errorcounter
                    EndIf
                    PPM_NOC_det = 0

frame2_end: 
                EndIf     
                time_add = tempwrd         
            Else
                If counter1 = 0 Then 'polarity detection
                    If (PPM_status & %11000011) = %11000010 Then 'positive pulse, sync and falling edge detected
                        PPM_status.3 = 1 'set positive pol
                        pulse_Length_max = timerhigh + PPM_PULSE_dif_t
                        pulse_Length_min = timerhigh - PPM_PULSE_dif_t
                        Inc counter1
                        PPM_status.2 = 0 'reset error, error is set because pulse length was unknown
                        PPM_NOC_det = 0
                    ElseIf (PPM_status & %11000011) = %10000001 Then 'negative pulse, sync and rising edge detected
                        PPM_status.3 = 0  'set negative pol
                        pulse_Length_max = timerlow + PPM_PULSE_dif_t
                        pulse_Length_min = timerlow - PPM_PULSE_dif_t
                        Inc counter1
                        PPM_status.2 = 0 'reset error, error is set because pulse length was unknown
                        PPM_NOC_det = 0
                    EndIf
                Else
                    If (PPM_status & %10111111) = %10101010 Then 'positive pulse, sync, falling edge, no error and pos polarity detected
                        Inc counter1
                        timer = 0
                        GoTo frame
                    ElseIf (PPM_status & %10111111) = %10010001 Then 'negative pulse, sync, rising edge, no error and neg polarity detected
                        Inc counter1
                        timer = 0
                        GoTo frame 
                    'as the framecheck did not pass and we have a valid sync, something is wrong
                    ElseIf (PPM_status & %10111011) = %10000010 Then 'sync and falling edge detected and polarity
                        counter1 = 0
                        PPM_NOC_det = 0
                    ElseIf (PPM_status & %10111011) = %10001001 Then 'sync and rising edge detected and polarity
                        counter1 = 0
                        PPM_NOC_det = 0
                    EndIf
                    GoTo frame_end
frame:               
                    If counter1 = 2 Then
                        PPM_NOC = PPM_NOC_det
                    ElseIf PPM_NOC_det != PPM_NOC Then
                        counter1 = 0
                        PPM_status.2 = 0
                    ElseIf counter1 = 4 Then
                        learned = 1
                        errorcounter = 0
                    EndIf
                    PPM_NOC_det = 0
frame_end:
                    If counter1 != 0 Then
                        If PPM_status.2 = 1 Then
                            counter1 = 0
                            PPM_status.2 = 0
                        EndIf
                    EndIf   
                EndIf
            EndIf
            PPM_status = PPM_status & $FC 'reset edge detected bits     
    EndIf

    If errorcounter = 5 Then
        learned = 0
        counter1 = 0
        errorcounter = 0
        Clear USBOUT1
    EndIf

    If send_to_USB = 1 And USB_ready = 1 Then
        GoSub send_report
        send_to_USB = 0
    EndIf
   
    If learned = 1 Then
        If PPM_status.2 = 1 Then
            PPM_OK = led_Act
            PPM_NOK = led_Act
        Else
            PPM_OK = led_Act
            PPM_NOK = led_inAct
        EndIf
    Else
       PPM_OK = led_inAct
       PPM_NOK = led_Act
    EndIf
   
    If T0IF = 1 Then
        USBPoll
        TMR0H = tmr0Reload
        TMR0L = 0
       
        If divider = 200 Then 'wait fot usb coms to stabilize
            USB_ready = 1
        Else
            USB_ready = 0
            If PP0 = 6 Then
                Inc divider
            Else
                divider = 0
            EndIf
        EndIf
       
        If USB_ready = 1 Then
            USB_OK = led_Act
            USB_NOK = led_inAct
        Else
            USB_OK = led_inAct
            USB_NOK = led_Act
        EndIf
        If PP0 = 6 Then T0IF = 0
    EndIf   
   
    If T2IF = 1 Then
        Inc timer
        If timer = 10000 Then 'approx 5 sec
            errorcounter = 0
        EndIf
        TMR2 = tmr2Reload
        T2IF = 0
    EndIf   
GoTo main

send_report:   
    tmrtmp = T0CON  'we store the old timer 0 config
    T0CON = 0       'polling intervall is 1ms!!!
    TMR0H = 192
    TMR0L = 0
    T0IF = 0
    T0CON = %10001000 'reassign timer 0 to interrupt the loops when usb coms fail, 5ms time-out
    Repeat
        USBOut 1, USBOUT1, 8
        If T0IF = 1 Then GoTo usb_fail
    Until STATUS.0 = 0
    Repeat
        If T0IF = 1 Then GoTo usb_fail
    Until UIR.3 = 1 ' Wait for the USB bus to finish
    TMR0H = tmr0Reload       'reset timer 0 and restore settings
    TMR0L = 0
    T0CON = tmrtmp           'restore timer config to original value
    T0IF = 0
Return

usb_fail:
    T0IF = 0
    TMR0H = 0
    TMR0L = 0
    T0CON = tmrtmp
    Call MODULE@DISABLE
    divider = 0
    USB_ready = 0
    USB_OK = led_inAct 'indicate usb fail with only usb_inack active
    USB_NOK = led_Act
    'HSerOut ["USB_FAIL",13]
Return

calc_servo:
    statusled0 = 1
    If tempwrd < PPM_Min_t Then tempwrd = PPM_Min_t 'constrain to ppm_min_t
    If tempwrd > PPM_Max_t Then tempwrd = PPM_Max_t 'constrain to ppm_max_t
    tempwrd = tempwrd - PPM_Min_t
    mathtmp = tempwrd * USB_data_max
    mathtmp = mathtmp / (PPM_Max_t - PPM_Min_t)
   
    If PPM_NOC_det < 9 Then USBOUT1[PPM_NOC_det - 1] = mathtmp.LowByte
    statusled0 = 0
Return

Isr:
Context Save  'takes 2.5 µs to complete
    If INT2IF = 1 Then
        timerdump.LowByte = TMR1L
        timerdump.HighByte = TMR1H   
        TMR1H = 0
        TMR1L = 0 'reset timer
        T1IF = 0
        If INTEDG2 = 1 Then 'riging edge                                                                                                       ,;
            'low timing passed 
            INTEDG2 = 0 'set next interrupt to falling edge
            timerlow = timerdump
            PPM_status.0 = 1
        Else  'falling edge
            'high timing passed
            INTEDG2 = 1 'set next interrupt to rising edge
            timerhigh = timerdump
            PPM_status.1 = 1
        EndIf
        WREG = PORTB
        INT2IF = 0
    EndIf
Context Restore

Would like to add the schematic but can't figure out how to do this on this forum.

Pepe

 I am glad that my knowledge has been useful to you.