Problem with volatile modifier

M

Marcin Kalicinski

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
 
M

Marcin Kalicinski

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

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
 
K

Karl Heinz Buchegger

Marcin said:
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.

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
 
K

Karl Heinz Buchegger

Karl said:
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

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.
 
X

Xenos

Marcin Kalicinski said:
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

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).
 
X

Xenos

Xenos said:
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).
Here is an example:

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

Marcin Kalicinski

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

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.

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top