At an interrupt barrier, the host must be able to ensure that no
interrupt generated before reaching the barrier is still pending and
will be delivered after crossing the barrier.
For this, we introduce the following concept:
- interrupts have a serial number. This number is sent to the host
on EP 1 (currently bulk) to signal the interrupt, instead of the
zero byte we used previously.
- the new request ATUSB_SPI_WRITE2_SYNC returns the interrupt
serial number from after the register write (the register write
itself is the interrupt barrier).
- the host can now check if the serial indicated from bulk and the
serial from ATUSB_SPI_WRITE2_SYNC are the same. If yes, interrupts
are synchronized. If not, it has to wait for the interrupt to be
signaled on EP 1.
We should also consider the case that the interrupt serial has gotten
ahead of ATUSB_SPI_WRITE2_SYNC. But that seems to happen rarely. In
any case, it's something for the host driver to worry about, not for
the firmware.
- board.h (irq_serial), board_app.c (irq_serial, INT0_vect): count
the interrupt serial number and return it when signaling the
interrupt
- include/atusb/ep0.h (ATUSB_SPI_WRITE2_SYNC), ep0.c (my_setup):
new request ATUSB_SPI_WRITE2_SYNC that does a register write, then
returns the interrupt serial
- board_app.c (INT0_vect): always read IRQ_STATUS, even if an
interrupt is already enqueued
- board_app.c (INT0_vect): if an interrupt is enqueued, accumulate
the interrupts signaled since
- board_app.c (irqs_more): when a pending transfer completes, send
interrupts accumulated since (if any)
- board.h (gpio_cleanup), board_app.c (gpio_cleanup): restore INT0
when done manipulating GPIOs
- board.c (gpio): updated comment explaining how to restore INT0
- include/atusb/ep0.h (enum atspi_requests), ep0.c
(ATUSB_GPIO_CLEANUP): new request to return to normal operation
after ATUSB_GPIO
Since GPIO manipulations may cause stray INT0 activity, we turn off
INT0 handing on ATUSB_GPIO. The MCU must be reset to restore access
to INT0.
There are still issues to resolve with the GPIO test. It may turn
out that there's a less invasive solution than just turning off
INT0 completely.
- board_app.c (gpio): mask INT0 before manipulating GPIOs
- board_app.c (board_app_init): make it clearer that EIMSK is a bit
mask
- board.h (board_app_init), board_app.c (board_app_init): new function
for application-specific board initialization
- atusb.c (main): call board_app_init
- board_app.c (INT0_vect): on RF interrupt, read REG_IRQ_STATUS and
send the status byte on EP1
- board_app.c (board_app_init): set up interrupt on rising edge of
INT0 (INT_RF)
- descr.c (config_descriptor): added EP1 as bulk IN
Note: this change surprisingly _increases_ the DFU wait in the boot
loader. Not yet sure why.
- boot.c (main): move the interrupt vectors to the boot loader
section
- atusb.c (main): move the interrupt vectors to the application
section
- boot.c (main): enable global interrupts while looping (disable
them before jumping to the application)
- board_app.c (__timer_read, timer_read): removed wrapped since
we're now always called with interrupts disabled
- usb/atu2.c (ep_init): enable endpoint interrupts
- usb/atu2.c (usb_init): enable device interrupts
- usb/atu2.c (usb_poll, USB_GEN_vect, USB_COM_vect): moved poll
loop code into separate handlers for device and endpoint
interrupts
- boot.c (main), atusb.c (main): removed call to usb_poll
- board.c (board_init), board_app.h (timer_init), board_app.c
(timer_init): moved timer initialization from board_init to
new function timer_init
- atusb.c (main): call timer_init
- spi.h (spi_off), spi.c: disable the UART
- spi.c (spi_initialized, spi_begin, spi_init): initialize the UART
if necessary
- board_app.c (gpio): call spi_off to disable the UART instead of
open-coding the operation
- board_app.c (gpio): don't explicitly re-enable the UART but defer it
to the next communication