Shop OBEX P1 Docs P2 Docs Learn Events
external interrupts too slow — Parallax Forums

external interrupts too slow

loojadeloojade Posts: 30
edited 2008-08-11 07:18 in General Discussion
hallo,

I have a problem with external interrupt of port_B. I'm using a SX28 with 50MHz clock.
In my project I must check 3 external signal (square wave) by RB.0, RB.1 and RB.2. The frequency of RB.0 is about 100Hz, RB.1 about 120Hz and RB.2 = 15Hz.

RB0 and RB1 signal come from a proximity sensors (installed in front and rear wheel of motorbike). RB2 come from engine RPM signal. All signals are very clear (0 to 5V).

In main program I increase 2 counters (16bit counter_fr and counter_rr) every 15uSec (by PAUSEUS 15). In the interrupt subroutine, I save the value of counter.
If the difference between counter_fr and counter_rr is too big (depend on value of RA port) on a extra control start on RB3. RB3 drive a power Pmos. Basically the RB3 go to 0 for 1 period of RB2 signal and come back to 1 for the next "some" periods (depend on value of RA port).

The program is the following:


[code]


'
' Program Description
'
'
'
' Device Settings
'
DEVICE SX28, OSCHS2, TURBO, STACKX, OPTIONX
FREQ 50_000_000, 45_000_000
'IRC_CAL IRC_4MHZ

'
' IO Pins
'

'fr_sensor VAR RB.0 'impulsi da sensore ruota anteriore
'rr_sensor VAR RB.1 'impulsi da sensore ruota posteriore
'rpm_sensor VAR RB.2 'impulsi da giri motore
t_control VAR RB.3 'uscita controllo MOS di potenza

'RB.3 pilota il MOS
'RA

Comments

  • JonnyMacJonnyMac Posts: 9,215
    edited 2008-08-08 18:37
    Perhaps you have some edges so close that one fires the interrupt and the next happens while you're in the interrupt, hence is ignored. You might try a periodic interrupt at 15 microseconds that scans the inputs and checks for new 0->1 transitions, processing all changes in the ISR. Like this:

    ' =========================================================================
      INTERRUPT 66_667                              ' 15 us
    ' =========================================================================
    
    Mark_ISR:
      isrFlag = 1
    
    Scanner:
      nScan = RB & %00000111                        ' new scan
      xScan = nScan ^ oScan                         ' isolate changed pins
      xScan = xScan & nScan                         ' isolate 0->1 transitions
      oScan = nScan                                 ' save for next cycle
    
    Check_Ch1:
      IF xScan.0 = 1 THEN
        frLast = frCounter
        frCount = 0
      ELSE
        INC frCounter
      ENDIF
    
    Check_Ch2:
      IF xScan.1 = 1 THEN
        rrLast = rrCounter
        rrCounter = 0
      ELSE
        INC rrCounter
      ENDIF
    
    Check_Ch3:
      IF xScan.2 = 1 THEN
    
        ' ch3 code here
    
      ENDIF
    
      RETURNINT
    

    Post Edited (JonnyMac) : 8/8/2008 6:54:03 PM GMT
  • loojadeloojade Posts: 30
    edited 2008-08-08 20:15
    Hi JonnyMac,

    Your propouse is interesting. I'll try tomorrow (now in Italy is already night).
    In a my old project I already use 3 external interrupt with the same signal: 2 SX28, the first one to drive a LCD display and a eeprom and the second one to control the external interrupts. Basically that system worked well until 400Hz frequency for RB0 and RB1 and 200Hz for RB2. The old project did the same job as the new one. For this reason actually I don't understand why the new one don't work well.

    I want a post the code of old project (of SX28 who control external interrupts):

    [code]

    DEVICE SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
    FREQ 4_000_000
    IRC_CAL IRC_4MHZ


    'ID "GRIPOne_004"

    '
    ' IO Pins
    '

    fr_sensor VAR RB.0 'impulsi da sensore ruota anteriore
    rr_sensor VAR RB.1 'impulsi da sensore ruota posteriore
    rpm_sensor VAR RB.2 'impulsi da giri motore
    t_control VAR RC.0 'uscita controllo MOS di potenza

    'RC.0 pilota il MOS
    'RA.0 - RA.1 sono utilizzati per lo scambio dei dati con il master

    '
    ' Constants
    '

    spin_base CON 102
    rpm_limit CON 25
    limite_taglio CON 20
    controllo_ON CON 0
    controllo_OFF CON 1

    '
    ' Variables
    '
    vettore1 VAR byte(16) 'array di variabili byte del bank1
    byte1 VAR vettore1(0)
    byte2 VAR vettore1(1)
    byte4 VAR vettore1(3)
    spinning VAR vettore1(4) 'valore massimo di pinning accettato per non attivare il controllo
    taglio VAR vettore1(5) 'numero di cicli tra un taglio e l'altro
    controllo VAR vettore1(6) 'stato del controllo di trazione: 0=off, 1=on
    decimali VAR vettore1(7)
    sr VAR vettore1(8) 'sviluppo ruota posteriore (185..220 cm)
    sf VAR vettore1(9) 'sviluppo ruota anteriore (185..220 cm)
    pr VAR vettore1(10) 'impulsi ruota posteriore (3..6 impulsi/giro)
    pf VAR vettore1(11) 'impulsi ruota anteriore (3..6 impulsi/giro)
    ratio_l VAR vettore1(12)
    ratio_h VAR vettore1(13)
    spin_l VAR vettore1(14)
    spin_h VAR vettore1(15)

    vettore2 VAR byte(16) 'array di variabili byte del bank1
    cicli VAR vettore2(0)
    rpm VAR vettore2(1)
    spin_counter VAR vettore2(2)
    taglio_limit VAR vettore2(3)
    n_bit VAR vettore2(4)
    filtro_rpm VAR vettore2(5)

    word1 VAR Word
    word2 VAR Word
    word3 VAR Word
    word4 VAR Word
    counter_fr VAR Word
    counter_rr VAR Word
    last_fr VAR Word
    last_rr VAR Word
    byte_interrupt VAR byte '0=fr, 1=rr, 2=rpm
    byte3 VAR byte
    bit_rx VAR byte3.0


    '
    INTERRUPT
    '

    ISR_Start:
    WKPND_B = byte_interrupt ' get byte_interrupt

    Ch1: ' check channel
    IF byte_interrupt <> %00000001 THEN GOTO Ch2 ' if not, try next
    last_fr = counter_fr 'quando l'ingresso cambia di stato salvo il valore del contatore e azzero il contatore
    counter_fr = 0
    GOTO ISR_Exit

    Ch2:
    IF byte_interrupt <> %00000010 THEN GOTO Ch2b ' if not, try next
    last_rr = counter_rr 'quando l'ingresso cambia di stato salvo il valore del contatore e azzero il contatore
    counter_rr = 0
    GOTO ISR_Exit

    Ch2b:

    Ch3:
    IF byte_interrupt <> %00000100 THEN GOTO ISR_Exit
    IF filtro_rpm < rpm_limit THEN GOTO ISR_Exit
    filtro_rpm = 0
    IF controllo = 1 THEN
    IF taglio < taglio_limit THEN
    IF cicli < taglio THEN 'se cicli = 0 e taglio = 0 non ci deve essere controllo in ogni caso, altrimenti dipende da "controllo"
    IF cicli <= rpm THEN 'se cicli < taglio e cicli = 0 apro il MOS
    t_control = controllo_ON
    ELSE
    t_control = controllo_OFF
    ENDIF
    INC cicli
    ELSE
    cicli = 0
    ENDIF
    ELSE
    t_control = controllo_OFF
    ENDIF
    ELSE
    t_control = controllo_OFF
    ENDIF
    GOTO ISR_Exit

    ISR_Exit:
    WKEN_B = %11111000 ' prepare for new ISR
    WKPND_B = %00000000 ' clear pending

    RETURNINT


    '
    ' Subroutine Declarations
    '

    CHECK_SPINNING SUB 0 'calcola il valore spinning
    CALCOLA_RATIO SUB 0 'calcola il valore ratio dato dallo svilluppo ruote e dal numero di impulsi per giro
    LEGGI_BYTE SUB 0
    LEGGI_DATI SUB 0


    ' =========================================================================
    PROGRAM Start
    ' =========================================================================


    '
    ' Program Code
    '

    Start:
    TRIS_B = %00000111 ' imposto gli ingressi e le uscite della porta B
    TRIS_C = %00001000 ' imposto gli ingressi e le uscite della porta C
    TRIS_A = %1111 ' imposto gli ingressi e le uscite della porta A

    WKPND_B = %00000000 ' clear pending
    WKED_B = %11111111 ' falling edge detect
    WKEN_B = %11111000 ' use bits 0..2 for inputs
    WKPND_B = %00000000 ' clear pending

    'ASM 'disattivo la resistenza di pull up su tute le porte
    'mov M,#$0E 'MODE=0Eh to access port pullup registers
    '
    'mov W,#$0F 'W = 0000 1111
    'mov !RA,W 'disable pullups for RA0 and RA3
    '
    'mov W,#$FF 'W = 1111 1111
    'mov !RB,W 'disable all pullups for RB0-RB7
    '
    'mov W,#$FF 'W = 1111 1111
    'mov !RC,W 'disable all pullups for RC0-RC7
    'ENDASM

    'inizializzazione variabili
    t_control = controllo_OFF
    last_fr = 6553
    last_rr = 6553
    counter_fr = 0
    counter_rr = 0
    filtro_rpm = 0
    spin_counter = 1

    controllo = 0
    byte_interrupt = 0
    byte1 = 0
    cicli = 0

    'lettura dei parametri dal master
    PAUSE 550
    LEGGI_DATI


    Main:
    PAUSEUS 15
    IF counter_fr < 65535 THEN
    INC counter_fr
    ENDIF

    IF counter_rr < 65535 THEN
    INC counter_rr
    ENDIF

    IF filtro_rpm < 255 THEN
    INC filtro_rpm
    ENDIF

    IF RA.1 = 1 THEN
    LEGGI_DATI 'verifico in polling se il master sta inviando i dati di configrazione
    PAUSE 400
    ENDIF

    INC byte1
    IF byte1 < 200 THEN GOTO Main
    CHECK_SPINNING
    byte1 = 0


    GOTO Main

    '
    ' Subroutines Code
    '

    LEGGI_DATI:
    spinning = LEGGI_BYTE
    taglio = LEGGI_BYTE
    sf = LEGGI_BYTE
    pf = LEGGI_BYTE
    sr = LEGGI_BYTE
    pr = LEGGI_BYTE
    rpm = LEGGI_BYTE
    IF taglio = 0 THEN
    WKEN_B = %11111100 ' use bits 0..2 for inputs
    t_control = controllo_OFF
    ENDIF

    taglio = limite_taglio - taglio 'se rpm = 1 il segnale dei giri
  • loojadeloojade Posts: 30
    edited 2008-08-08 20:51
    I'm sorry, 1 more question...

    Which is the meaning of "isrFlag = 1" in the 2line of interrupt subroutine ????

    Thanks in advance
  • JonnyMacJonnyMac Posts: 9,215
    edited 2008-08-08 21:13
    You can use that flag to trigger the foreground loop every 15 microseconds (so you can remove the PAUSEUS 15 statement). Like this:

    Main:
      IF isrFlag = 0 THEN Main
      isrFlag = 0
    
      ' foreground code here
    
      GOTO Main
    
  • loojadeloojade Posts: 30
    edited 2008-08-09 07:59
    good!!! now it's clear

    Basically I moved the "INC counter" in interrupt subroutine so in the main program remain only the call to CHECK_SPINNING and LEGGI_DATI subroutines.... I think that it is easier fix like this:

    Main:
    PAUSE 3
    
    CHECK_SPINNING
    INC byte1
    IF byte1 < 200 GOTO Main
    byte1 = 0
    LEGGI_DATI
    
    GOTO Main
    
    ....
    
    
    



    Thanks a lot for your help
  • loojadeloojade Posts: 30
    edited 2008-08-11 07:18
    Hi JonnyMac,

    Your code work very well!!! I also used the IsrFlag to trigger the foreground loop and everything is perfect.
    Thank a lot
Sign In or Register to comment.