I suspect the problem is not with your C code but with your Makefile.
The following lines in your Makefile produce an example.o
object file.
main:
avr-gcc -g -Os -Wall -mmcu=atmega328 -c ../src/example.c
The created .o
file only contains the symbols and code from example.c
, not the additional source required to actually make it run on a target system such as interrupt vector jump tables and code to initialise the BSS RAM segment to zeros, and load your initialised data sections.
You'll need to add an additional line something like this to run the linker and produce an output object suitable for download to the AVR part. Alternatively, use avr-ld
, but you'll have to work out all the required linker options.
main.elf: example.o
avr-gcc example.o -o main.elf
You can use avr-objdump --disassemble-all <filename>
on both example.o
and main.elf
yourself to verify the different content of each file.
It's always a good idea to try to reduce your problem in steps to the most simple example possible. In this case, it would probably mean dropping into the AVR Studio software and creating a project running on the simulator using their managed build process. From there, you could them export the Makefile in use by their build process by using the 'Export Makefile' menu option. The generated makefile could then be compared with your version.
Actually, it's probably a good idea to use a Makefile similar to the one generated by AVR Studio because it has the correct rules already defined, you just have to set up some variables with regard to which objects need to be generated and the final target file name.
In general, interrupts are disabled when the processor enters an interrupt handler, and automatically re-enabled when the interrupt handler returns. (See CLI
, SEI
, and RETI
instructions in the manual for more info).
When the external interrupt is fired, the interrupt flag INTF0
in the EIFR
is set to 1. When interrupts are enabled and this bit is 1, the processor enters the interrupt handler. Inside the interrupt handler, this bit could again be set to 1, but the interrupt won't re-occur until after interrupts get re-enabled. You can also explicitly clear this bit to 0 by writing a 1 to the register. If you were inside the interrupt handler, an external event sets the bit, and you clear the bit before returning from the interrupt handler, than the interrupt will not be triggered again.
However, note that you can't actually set or clear INTF0
if you're using level-triggered interrupts -- it just matches the state of the pin at all times. If the pin is low, and interrupts are enabled, it will trigger the interrupt again. The only way to stop that is to disable interrupts (either globally, or by masking off the particular INT0
bit in EIMSK
).
Best Answer
Yes, whenever a data structure such as your task list can be accessed (modified or viewed) by more than one process, it is essential that any changes to that data structure be complete and self-consistent when viewed by any one process. This is in general called "atomic update".
A linked list is a nontrivial data structure, and updates to it require more than one machine instruction to accomplish. If the ISR interrupts the main loop when it happens to be updating the list, the ISR won't see a consistent structure. If the ISR then tries to update the list itself, chaos ensues.
One simple way to protect access to shared data is through mutual exclusivity (or "mutex" for short). In the case of a main loop vs. ISR conflict, this is easy to accomplish by means of the interrupt enable flag.
If more than one non-interrupt process wants to access the structure, you can add a binary flag to control access to the data structure, and this flag can be set by only one process at a time. However, note that updates to this flag must also be atomic, which again means disabling interrupts, so that a task switch does not occur between testing and setting the flag.