Shop OBEX P1 Docs P2 Docs Learn Events
I2C send and receive in mainline while also running code in ISR — Parallax Forums

I2C send and receive in mainline while also running code in ISR

ZootZoot Posts: 2,227
edited 2008-05-20 23:21 in General Discussion
I'm reworking my SX servo controller (http://forums.parallax.com/showthread.php?p=703230) to handle my new motor encoders, wheel odometry and PID velocity. This is in addition to existing servo control. I'm pretty much rewriting the whole thing (extending avail. pulsewidths, going to 4us resolution, freeing up space for encoder, PID, odometry code and var space).

My main motor driver (an MD22) is I2C based, and while I can configure it to accept servo pulses, I would rather use it as I2C. So..... am I correct in presuming that I can do my I2C sends to the driver in my mainline program and not worry about about my ISR? Since I2C is clocked, and I only need to send 3 bytes to the driver, and since I've shortened my ISR *radically*, this will technically work, right? Worst case might be that the I2C clock could get slooowish if the ISR is bogging things down?

I'm doing a quasi-multi-thread setup ala pjv -- with the exception of servo pulses, tx/rx and encoder ticks, the ISR only sets flags and timers for various "task-like" chores in the mainline program (i.e. servo timers are reset every 20ms by the mainline, PID updated every 50ms by the mainline, I2C sent to motor driver every 50ms in the mainline, odometry chores are done every 100ms or when the tick count is high enough to warrant it, etc.

Pseudo code:

ISR:
  update encoder ticks
  update tx/rx (4 byte buffer to/from serial port)
  update servo pulses
  dec rampFrame
  dec PIDframe
  dec ODframe
  DONE

Main:
  
  IF rampFrame = 0 THEN
        rampFrame = some constant
        update all servo target pulses with new ramped values
  ENDIF   

  IF PIDframe = 0 THEN
        PIDframe = some constant
        update PID velocity
        I2CSEND to motor driver
  ENDIF      

  IF ODframe = 0 THEN
        ODframe = some constant
        update odometry
  ENDIF      

  IF serialBuffCnt > 0 THEN
       parse and distribute incoming serial commands
       setup tx buff if response is required
  ENDIF 

  GOTO Main





Naturally I'm leaving out lots here (like the PID includes two timers -- one for the frame, one to measure actual time since last sampling, so that if the mainline "misses" a frame at the price 100ms timeout, it will still be able to decent calculations, or that I'll be staggering the initial values for the frame timers so that, most of the time, the "frames" will never all run at once).

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST

1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php

Comments

  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2008-05-20 22:52
    Zood,

    so far, i did many SX applications with an I2C master interface, and I never made the I2C code part of the ISR. The nice fact is that the master generates the SCL clock signal, and the slaves on the bus nicely sync to that clock, no matter if it is yittery or not. IOW: It absolutely does not matter if some time-critical ISR code messes up the mainline's I2C timing. So I can only confirm that you may do your I2C sends in your mainline program w/o worrying about the resulting timing errors.

    BTW: I noticed that you let the ISR update servo pulses and encoder ticks. In similar applications, I use the port B edge-detection feature, and check for port B transitions in the mainline program loop as this is usually executed at a higher repeat rate than the ISR code.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
  • ZootZoot Posts: 2,227
    edited 2008-05-20 23:21
    Somebody said...
    BTW: I noticed that you let the ISR update servo pulses and encoder ticks. In similar applications, I use the port B edge-detection feature, and check for port B transitions in the mainline program loop as this is usually executed at a higher repeat rate than the ISR code.

    I thought about this, but in this particular application I'm getting, for discussion's sake, 2-40 encoder ticks every50 ms -- pretty slow. Average speed is around 12 ticks per 50ms. The ISR will be running every 4 us.

    My rough estimate is that the mainline I2CSEND (as a master) could take from 1 - 2 ms (depending on how many bytes I choose to send and/or receive, and NOT including add'l overhead of ISRs that will surely be callled between instructions during mainline I2C transactions) so it would seem that my ISR will run much more often (more accurately, during mainline frames when I2C transactions and frame calculations are taking place).

    Additionally, my estimate is that some of the long division for my PID and odometry *could* take some hundreds of instruction cycles for each calculation -- and depending on what odometry and PID is really being calculated (if no distance has been traveled or velocity read is the same, obviously, PID and odometry do not need to be recalculated, saving some 1000s of looped instructions for divides, multiplies, etc). Add to that IREADS for sin/cosine lookups, setting up the TX buffer to respond to queries from the host, etc. and things add up a bit for the mainline.

    In short, I've been budgeting a 1ms-4ms time in the mainloop during frames execution (servos, PID, odometry) at 50mhz and upon updates from the host via serial RX...

    And that's before I possibly add in some of the 32bit math routines I've been checking out from Scenix/SXlist smile.gif Estimates there are up to 443 cycles max for each calculation (32 bit divide, 32 multiply). Not sure I'm going to go there though, unless I make the motor encoder and velocity engine it's own SX (instead of bundled in with servo control and the like).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
Sign In or Register to comment.