Loading ...
Sorry, an error occurred while loading the content.
 

How to get a fixed period main loop

Expand Messages
  • johnabshier
    I would like to make my main program loop run at a fixed period. My code is based on the SRS Work Shop robot code. Now I am doing the following: int main() {
    Message 1 of 5 , Mar 30, 2006
      I would like to make my main program loop run at a fixed period.
      My code is based on the SRS Work Shop robot code.
      Now I am doing the following:

      int main() {
      while(1) {
      msStart = TimerMsCur();
      speedControl();
      readSensors();
      switch (state)
      { do things based on state and sensor reading
      }
      while(!TimerCheck(msStart, _50Hz)) // this is a
      tight loop
      ; // that
      disables interrupts
      }

      I am afraid that I am losing encoder counts in the loop that calls
      TimerCheck.
      The routine that disables interrups is below:
      unsigned long TimerMsCur()
      {
      char sregSav;
      unsigned long ms;

      /* disable (delay) interrupts while we read
      s_msTimer since it's 4 bytes and we don't
      want it changing during the read! */
      sregSav = SREG; // cache register holding Global Interrupt
      Flag
      cli(); // clear Global Interrupt Flag
      ms = s_msTimer;
      SREG = sregSav; // restore register holding Global Interrupt
      Flag

      return ms;
      }

      Does anyone have a suggestion on how to have a fixed main program
      loop period?
    • Larry Barello
      The problem isn t you TimerMSCur() routine. Interrupts are off for perhaps 1 microsecond, max, in that routine. What about TimerCheck()? What does that code
      Message 2 of 5 , Mar 30, 2006
        The problem isn't you TimerMSCur() routine. Interrupts are off for perhaps
        1 microsecond, max, in that routine.

        What about TimerCheck()? What does that code look like? It should be:

        unsigned char TimerCheck(unsigned long timer, unsigned long delay)
        {
        return (timer + delay) < TimerMSCur();
        }

        Make sure everything is unsigned so the routine works correctly even if the
        timer rolls-over.

        -----------
        Larry Barello
        www.barello.net


        | -----Original Message-----
        | From: SeattleRobotics@yahoogroups.com
        | [mailto:SeattleRobotics@yahoogroups.com] On Behalf Of johnabshier
        | Sent: Thursday, March 30, 2006 10:15 AM
        | To: SeattleRobotics@yahoogroups.com
        | Subject: [SeattleRobotics] How to get a fixed period main loop
        |
        | I would like to make my main program loop run at a fixed period.
        | My code is based on the SRS Work Shop robot code.
        | Now I am doing the following:
        |
        | int main() {
        | while(1) {
        | msStart = TimerMsCur();
        | speedControl();
        | readSensors();
        | switch (state)
        | { do things based on state and sensor reading
        | }
        | while(!TimerCheck(msStart, _50Hz)) // this is a
        | tight loop
        | ; // that
        | disables interrupts
        | }
        |
        | I am afraid that I am losing encoder counts in the loop that calls
        | TimerCheck.
        | The routine that disables interrups is below:
        | unsigned long TimerMsCur()
        | {
        | char sregSav;
        | unsigned long ms;
        |
        | /* disable (delay) interrupts while we read
        | s_msTimer since it's 4 bytes and we don't
        | want it changing during the read! */
        | sregSav = SREG; // cache register holding Global Interrupt
        | Flag
        | cli(); // clear Global Interrupt Flag
        | ms = s_msTimer;
        | SREG = sregSav; // restore register holding Global Interrupt
        | Flag
        |
        | return ms;
        | }
        |
        | Does anyone have a suggestion on how to have a fixed main program
        | loop period?
        |
        |
        |
        |
        |
        | Visit the SRS Website at http://www.seattlerobotics.org
        | Yahoo! Groups Links
        |
        |
        |
        |
        |
      • daylan darby
        This looks like C code. If it it why not add inline? inline unsigned char TimerCheck(unsigned long timer, unsigned long delay) { return (timer + delay)
        Message 3 of 5 , Mar 30, 2006
          This looks like C code. If it it why not add inline?

          inline unsigned char TimerCheck(unsigned long timer, unsigned long delay)
          { return (timer + delay) < TimerMSCur(); }

          Larry Barello wrote:

          >The problem isn't you TimerMSCur() routine. Interrupts are off for perhaps
          >1 microsecond, max, in that routine.
          >
          >What about TimerCheck()? What does that code look like? It should be:
          >
          >unsigned char TimerCheck(unsigned long timer, unsigned long delay)
          >{
          > return (timer + delay) < TimerMSCur();
          >}
          >
          >Make sure everything is unsigned so the routine works correctly even if the
          >timer rolls-over.
          >
          >-----------
          >Larry Barello
          >www.barello.net
          >
          >
          >
        • Larry Barello
          In this particular case, the target processor is an AVR 8 bit CPU and the code is dealing with longs which take at least four instructions per operation (maybe
          Message 4 of 5 , Mar 30, 2006
            In this particular case, the target processor is an AVR 8 bit CPU and the
            code is dealing with longs which take at least four instructions per
            operation (maybe more if temporary values are involved).

            The cost of a procedure call in the AVR is pretty light, so in-lines don't
            make much sense unless it is a trivial routine or it is a low level hardware
            access and you want to minimize latencies as much as possible.

            SPI access to peripheral devices is one case where I do use inline as
            transfers are usually several writes & reads and I want it to be as quick as
            possible. And, as it turns out, the resulting code is probably smaller than
            a procedure call after the data shuffling is taken into account.

            // BLocks until transfer complete, defined here for ADC and other SPI device
            access.

            static inline void SPI_Write(uint8_t data)
            {
            SPDR = data;
            while (!(SPSR & _BV(SPIF)))
            ;
            }

            static inline uint8_t SPI_Read(void)
            {
            SPI_Write(0);
            return SPDR;
            }

            Cheers!

            -----------
            Larry Barello
            www.barello.net

            | -----Original Message-----
            | From: SeattleRobotics@yahoogroups.com
            | [mailto:SeattleRobotics@yahoogroups.com] On Behalf Of daylan darby
            |
            | This looks like C code. If it it why not add inline?
            |
            | inline unsigned char TimerCheck(unsigned long timer, unsigned long delay)
            | { return (timer + delay) < TimerMSCur(); }
            |
            | Larry Barello wrote:
            |
            | >The problem isn't you TimerMSCur() routine. Interrupts are off for
            | perhaps
            | >1 microsecond, max, in that routine.
          • Dave Hylands
            ... The one place I ll disagree about this is function calls from within an ISR. This is an extreme example, but here goes: #include extern
            Message 5 of 5 , Mar 30, 2006
              > The cost of a procedure call in the AVR is pretty light, so in-lines don't
              > make much sense unless it is a trivial routine or it is a low level hardware
              > access and you want to minimize latencies as much as possible.

              The one place I'll disagree about this is function calls from within an ISR.

              This is an extreme example, but here goes:

              #include <avr/interrupt.h>
              extern void foo( void );
              static int tickCount = 0;
              ISR( TIMER0_OVF_vect )
              {
              tickCount++;
              foo();
              }

              Compiled with this command line:
              avr-gcc -mmcu=atmega128 -Os -c isr.c

              produces a function which is 90 bytes long. Removing the call to foo
              produces a an ISR which is only 46 bytes long.

              Once you've added one function, adding additional functions doesn't
              cause any more huge increase, but adding the first one does.

              --
              Dave Hylands
              Vancouver, BC, Canada
              http://www.DaveHylands.com/
            Your message has been successfully submitted and would be delivered to recipients shortly.