Thursday, March 8, 2012

A few things to know about using interrupts on the XMEGA (or, RTFM, seriously)

In my further adventures in XMEGA migration, I hit a couple of roadblocks (which will likely be hilariously obvious to most).  They relate to the use of interrupts, and they are as follows:

A: the XMEGA has a multi-level interrupt handler.  This is pretty neat; it means that you can set different interrupts to different priorities, with higher-priority interrupts able to interrupt lower-priority ones.  Of course, this means that enabling interrupts is slightly more involved than just setting the global interrupt enable bit (sei()); specifically, you need to enable each of the levels of interrupt (Low, Medium and High) by setting the appropriate bits in PMIC_CTRL.  This one is an obvious case of 'didn't read the manual'; I assumed that the default behavior of the interrupt controller would be identical to the TINY/MEGA controller.

B: don't EVER enable interrupts without specifying the corresponding interrupt routines.  This one is a little less certain than the last bit of advice, because it is borne out of my investigation of some flaky behavior I observed.

Specifically, I was trying to verify that I understood/could correctly use the real-time clock (RTC) peripheral.  My test would consist of initializing the RTC (and clocks, and ports, and USARTs) and transmitting a few bytes over the serial port every time the RTC overflow interrupt occurred. To make sure that the device was working otherwise, every 250ms it would output another character to prove that any problems were with the RTC implementation, and not the device setup code.

The check bytes were being sent... but the RTC interrupt was not being called.  To check that interrupts in general were working, I changed the interrupt routine vector to another counter's overflow, which I had not disabled from a previous bit of investigation.  It worked; and when I added another interrupt handler (one for both the RTC overflow and the counter overflow), both worked.  All I can figure is that the lack of a valid interrupt routine for the counter overflow (in the case where I had programmed a routine for the RTC overflow) meant that the interrupt handler was never apprised of the completion of the counter overflow interrupt routine (though a RETI instruction), so any subsequent interrupts were not handled because the controller thought that the original interrupt was still being executed.  This is predicated on the assumption that all unspecified interrupt vectors are by default handled by a simple RET instruction (which would leave the interrupt flag set, which makes a certain sort of sense as a default behavior); if true, it explains the behavior I observed.

The simplest solution is (at least for the AVR Studio/AVR-GCC environments) is to always specify a BADISR routine (that is, a default routine for otherwise unspecified interrupts).  This seems to take care of my problems, even with the counter overflow interrupt still enabled.


No comments:

Post a Comment