Problem with volatile modifier

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Marcin Kalicinski

    #1

    Problem with volatile modifier

    Hi all,

    I have a problem with 'volatile' use in C++.

    The function get_clocks() below tries to use a 16 bit hardware counter to
    count time. The counter overflows very often. But an interrupt is generated
    everytime the counter overflows, and function handler() counts these
    overflows in variable n_overflows.

    The problem is that during calculation of time value in get_clocks()
    function (marked by *** in the code), an overflow interrupt can happen
    modifying n_overflows value. This will render the calculation useless
    because value read from timer and n_overflows would not correspond to the
    same point of time. To prevent that I use another variable called flag. The
    flag is set by the interrupt handler to inform get_clocks function that
    overflow occured. The function then retries the time calculation by
    rereading values from the timer (the hardware timer counter is mapped to
    memory address 0x10000000).

    The problem is that it does not work. Sometimes time value returned from
    get_clocks() is less than the previously acquired (by roughly 2^16 what
    indicates a problem with n_overflow counter). I suspect there might be
    something wrong with my use of volatile modifier.

    Here's the relevant code:

    volatile unsigned long n_overflows;
    volatile bool flag;

    // Overflow interrupt handler
    void handler() {
    ++n_overflows;
    flag = true;
    }

    // Function to get the number of clock ticks passed
    unsigned long get_clocks() {
    unsigned long r;
    do {
    flag = false;
    r = n_overflows << 16 +
    *(volatile unsigned short *)0x10000000; // ***
    } while (flag);
    return r;
    }

    thanks,
    Marcin


  • Marcin Kalicinski

    #2
    Re: Problem with volatile modifier

    > r = n_overflows << 16 +[color=blue]
    > *(volatile unsigned short *)0x10000000; // ***[/color]

    This piece of code is actually:

    r = (n_overflows << 16) + *(volatile unsigned short *)0x10000000;

    so there is no problem with operator precedence. I have removed the
    parentheses accidentally when formatting the code.

    Best regards,
    Marcin


    Comment

    • Karl Heinz Buchegger

      #3
      Re: Problem with volatile modifier

      Marcin Kalicinski wrote:[color=blue]
      >
      > Hi all,
      >
      >
      > The problem is that it does not work. Sometimes time value returned from
      > get_clocks() is less than the previously acquired (by roughly 2^16 what
      > indicates a problem with n_overflow counter). I suspect there might be
      > something wrong with my use of volatile modifier.[/color]

      volatile has nothing to do with it.
      Your problem is that there are 2 tasks accessing the same variables
      variables. You need some synchronization mechanism to control that.
      Standard C++ has no provisions for that. BUt youcan check your
      development environment for methods of thread synchonization.
      Keywords would be: critical section, semaphore, mutex


      --
      Karl Heinz Buchegger
      kbuchegg@gascad .at

      Comment

      • Karl Heinz Buchegger

        #4
        Re: Problem with volatile modifier

        Karl Heinz Buchegger wrote:[color=blue]
        >
        > Marcin Kalicinski wrote:[color=green]
        > >
        > > Hi all,
        > >
        > >
        > > The problem is that it does not work. Sometimes time value returned from
        > > get_clocks() is less than the previously acquired (by roughly 2^16 what
        > > indicates a problem with n_overflow counter). I suspect there might be
        > > something wrong with my use of volatile modifier.[/color]
        >
        > volatile has nothing to do with it.
        > Your problem is that there are 2 tasks accessing the same variables
        > variables. You need some synchronization mechanism to control that.
        > Standard C++ has no provisions for that. But you can check your
        > development environment for methods of thread synchonization.
        > Keywords would be: critical section, semaphore, mutex
        >[/color]

        On a rethink I no longer think this will lead you somewhere.
        I expect your problem to be a hardware and/or operating system
        problem. The counter is reset to 0, the interrupt gets generated
        but is pending. So you sometimes end up with: the clock has
        already been reset to 0, but the interrupt hasn't been processed
        right now to increment no_overflows. What you need to achive
        is to make the hardware increment paired with interrupt
        handling and an atomic operation.

        --
        Karl Heinz Buchegger
        kbuchegg@gascad .at

        Comment

        • Xenos

          #5
          Re: Problem with volatile modifier


          "Marcin Kalicinski" <kalita@poczta. onet.pl> wrote in message
          news:cjhc8f$7jd $1@korweta.task .gda.pl...[color=blue]
          > Hi all,
          >
          > I have a problem with 'volatile' use in C++.
          >
          > The function get_clocks() below tries to use a 16 bit hardware counter to
          > count time. The counter overflows very often. But an interrupt is[/color]
          generated[color=blue]
          > everytime the counter overflows, and function handler() counts these
          > overflows in variable n_overflows.
          >
          > The problem is that during calculation of time value in get_clocks()
          > function (marked by *** in the code), an overflow interrupt can happen
          > modifying n_overflows value. This will render the calculation useless
          > because value read from timer and n_overflows would not correspond to the
          > same point of time. To prevent that I use another variable called flag.[/color]
          The[color=blue]
          > flag is set by the interrupt handler to inform get_clocks function that
          > overflow occured. The function then retries the time calculation by
          > rereading values from the timer (the hardware timer counter is mapped to
          > memory address 0x10000000).
          >
          > The problem is that it does not work. Sometimes time value returned from
          > get_clocks() is less than the previously acquired (by roughly 2^16 what
          > indicates a problem with n_overflow counter). I suspect there might be
          > something wrong with my use of volatile modifier.
          >
          > Here's the relevant code:
          >
          > volatile unsigned long n_overflows;
          > volatile bool flag;
          >
          > // Overflow interrupt handler
          > void handler() {
          > ++n_overflows;
          > flag = true;
          > }
          >
          > // Function to get the number of clock ticks passed
          > unsigned long get_clocks() {
          > unsigned long r;
          > do {
          > flag = false;
          > r = n_overflows << 16 +
          > *(volatile unsigned short *)0x10000000; // ***
          > } while (flag);
          > return r;
          > }
          >
          > thanks,
          > Marcin
          >
          >[/color]

          This is a common problem (trying to read a clock and its roll over count
          atomically_, and your approach is flawed, as you have two threads of
          execution trying to update flag. What you have to do is read both in a
          loop, exiting when two consective reads are the same for both, then you know
          that reads are not out of sync. with each other (one didn't change while you
          read the other).



          Comment

          • Xenos

            #6
            Re: Problem with volatile modifier


            "Xenos" <dont.spam.me@s pamhate.com> wrote in message
            news:cjhkka$skq 3@cui1.lmms.lmc o.com...[color=blue]
            > This is a common problem (trying to read a clock and its roll over count
            > atomically_, and your approach is flawed, as you have two threads of
            > execution trying to update flag. What you have to do is read both in a
            > loop, exiting when two consective reads are the same for both, then you[/color]
            know[color=blue]
            > that reads are not out of sync. with each other (one didn't change while[/color]
            you[color=blue]
            > read the other).
            >[/color]
            Here is an example:

            int clock, rolls;
            do
            {
            clock = read_clock();
            rolls = read_rolls();
            } while (clock != read_clock());



            Comment

            • Marcin Kalicinski

              #7
              Re: Problem with volatile modifier

              > int clock, rolls;[color=blue]
              > do
              > {
              > clock = read_clock();
              > rolls = read_rolls();
              > } while (clock != read_clock());[/color]

              This approach will create an infinite loop because clock is updated by
              hardware very often (roughly at the speed of CPU clock) and will certainly
              change between two read_clock() calls in the above loop. So, the condition
              in while will always be met.
              [color=blue][color=green]
              > > atomically_, and your approach is flawed, as you have two threads of
              > > execution trying to update flag. What you have to do is read both in a
              > > loop, exiting when two consective reads are the same for both, then[/color][/color]

              No, I don't have threads. The situation is different because interrupts are
              synchronous unlike threads. If interrupt handler is executing, the main
              program is stopped until the handler finishes. Handler cannot be interrupted
              in the middle (at least not to return control back to main program).

              What I think now is that my approach to use this little hardware clock as a
              long-term timer is doomed, because from time to time other interrupts with
              greater priority happen, and prevent calling of handler() on clock overflow.
              Thus, the clock misses some overflows.

              Best regards,
              Marcin


              Comment

              Working...