1
votes

I have a very simple program which is giving me a headache.

Some background: I am programing an arduino Uno "Atmega328P" in atmelstudio 6. I am using a JTAGICE mkII in debugwire mode to program and debug. I have also used this method to use the arduino libraries to make things easier.

I wrote a simple program to just count transitions on one of the external interrupt pins. In my case im using INT0_vect. The value im pointing to, just increments for every transition.

The problem is using a global pointer in an ISR. You may be thinking that I forgot to add the volatile keyword but you would be wrong.

The ISR is serviced for every transition but wouldn't change the value. I couldnt figure out why so I stepped through the program and found out that my pointer points to R00, one of the working registers. This should be fine but before the ISR is serviced R00 is pushed to the stack R00 is incremented and the previous value is restored.

I have no idea why this would be the case. As I said I am using a "volatile uint8_t*" which should be a pointer to a volatile uint8_t.

This is what the code looks like:

#include "Arduino.h"
void setup();
void loop();
void update();

volatile uint8_t* Count;
void setup()
{
    *Count = 0;
    attachInterrupt(0,update, CHANGE);  // makes ISR call update
}
void loop()
{
//  delay(1000);
}
 void update()
{
    (*Count)++;
}

The main loop calls setup once then loop repeatedly.
attach interrupt is a macro which sets up the interrupt then effectively creates this:

`ISR(INT0_vect){update();}`

Some additional info:

  • I am using -Os for both the c++ and c compilers.
  • avr-gcc Full Options: -funsigned-char -funsigned-bitfields -DF_CPU=16000000UL -I"../../../../arduino-1.0.5/hardware/arduino/cores/arduino" -I"../../../../arduino-1.0.5/hardware/arduino/variants/standard" -Os -fdata-sections -ffunction-sections -fpack-struct -fshort-enums -Wall -c -std=gnu99 -fno-exceptions -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -mmcu=atmega328p
  • avr-g++ Full Options: -funsigned-char -funsigned-bitfields -DF_CPU=16000000UL -I"../../../../arduino-1.0.5/hardware/arduino/cores/arduino" -I"../../../../arduino-1.0.5/hardware/arduino/variants/standard" -Os -fdata-sections -ffunction-sections -fpack-struct -fshort-enums -Wall -c -fno-exceptions -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -mmcu=atmega328p
  • avr-g++ Linker Options: -Wl,-Map="$(OutputFileName).map" -Wl,--start-group -Wl,-lm -Wl,-lcore -Wl,--end-group -Wl,-L"../../../ArduinoCore" -Wl,--gc-sections -mmcu=atmega328p
2
Hard to say what's wrong without seeing the relevant pieces of code. - Captain Obvlious
Ill add what ive got but its hard to read because of the arduino macros. - MrR
You don't initialize the Count pointer, what's it pointing at? And should it be a pointer at all? - Mark Ransom

2 Answers

0
votes

Since the Count pointer is a global variable that isn't explicitly initialized, it's set to 0x0, which happens to be the address that the Atmega328P maps register R00 to.

A function marked with the ISR() macro indicates to the compiler that it's a C ISR handler. In order for the compiler to arrange for C code to execute the ISR without destroying the state of whatever might have been running when the ISR fired, it has to add some prologue code to save some of the CPU's register state (and corresponding epilogue to restore that state for when the ISR function returns) so that the interrupted execution path isn't corrupted. Therefore, the ISR() designation causes the compiler to save and restore register R00 (and other registers) on the stack.

The combination of these two situations is why R00 gets saved on the stack, your ISR then increments it, then R00 is restored from the stack.

If you don't want that to happen, you can use the ISR_NAKED attribute to tell the compiler not to generate prologue or epilogue code. However, if your ISR handle doesn't properly save and restore the register state, whatever is running in the foreground will likely not behave very well.

So, set Count to point to some location you've allocated for the counter. Alternatively, make Count a simple variable instead of a pointer and deal with it directly in the ISR.

A nice overview of avr-gcc's interrupt handling support can be found here: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

0
votes

In embedded applications, a popular idiom for accessing registers is to use a pointer and assign it an address:

uint32_t volatile * const uart_rx = 0xFFFFD000;

The volatile qualifier tells the compiler that the contents pointed at will change without the program's knowledge.

Reading from the UART receive register would look like: uint32_t register_value = *uart_rx;

If the hardware item is 8-bit you should use a uint8_t type.

The truth is in the assembly language generated by the compiler.

If this doesn't answer your issue, please edit your post and add more details.