Bf54x interrupts
From RFID Guardian
There are two levels of interrupts:
- core interrupts (CEC)
- system interrupts (SIC)
Contents |
CEC (Core interrupts)
There are 16 levels of interrupts: IVG0 .. IVG15. Lower-numbered interrupts can preempt higher-number interrupts.
- IVG0 .. IVG6
- are dedicated interrupt levels (emulation, reset, NMI, exception, reserved, hardware error, core timer)
- IVG7 .. IVG13 (IVG14)
- SIC interrupts can be arbitrary bound to these 7 (or 8) CEC interrupts
- (IVG14,) IVG15
- are commonly reserved for software interrupts -- syscalls, or running in priviledged mode
SIC (System interrupts)
Peripherals each have an IRQ; e.g. UART1 status interrupt is 30.
A SIC IRQ must be assigned to one of IVG7..IVG13(14). This uses the MMRs SIC_IARx, four bits for each SIC IRQ. The eCos BlackFin interrupt code provides an API for this:
| #define HAL_SIC_INT_ASSIGN(sic_int, core_int) hal_sic_int_assign(sic_int, core_int) |
| /* assign @param sic_int to core interrupt @param core_int */ |
| void hal_sic_int_assign(int sic_int, int core_int); |
| /* query core interrupt assigned to @param sic_int */ |
| int hal_sic_core_int(int sic_int); |
core_int must be in the range 7..14. sic_int is in the range 0..95 for BF54x.
At initialisation time, the mapping from SIC interrupts to CEC interrupts is done according to the definitions in the .ecc build file: CYGNUM_HAL_BFIN_SIC_ASSIGN_PIID_0 .. CYGNUM_HAL_BFIN_SIC_ASSIGN_PIID_95 in the case of bf54x.
eCos interrupt handlers
Liesk has two interrupt implementations:
- simple interrupt implementation: at most one eCos interrupt handler is tied to a CEC interrupt number
- extended interrupt implementation: arbitrary vector numbers for eCos interrupts, and free mapping of eCos interrupts to CEC interrupts.
Since we have more than 7 or 8 interrupt sources, we will use the Extended Interrupt implementation.
modify extended interrupt implementation?
I don't know how the Extended implementation maps SIC interrupts to CEC interrupts. I also don't know if there is a predetermined relation between the eCos vectors and the SIC interrupts.
I would like to propose modification of the Extended implementation:
- the eCos vectors 1-on-1 map to the SIC interrupts in the Extended implementation, offset by CYGNUM_HAL_VECTOR_SIC_BASE; the vectors below CYGNUM_HAL_VECTOR_SIC_BASE follow the Simple implementation
- the SIC interrupts map to the CEC interrupts as in the Simple implementation
- if only one handler is registered, the Extended implementation uses a fastpath that resembles the Simple path; the difference is that eCos expects the SIC interrupt value as its vector i.s.o. the CEC interrupt
- if multiple handlers are registered, the Extended implementation uses the dispatcher 'trampoline' with the bitset that indicates the SIC ints that belong to this CEC int.
We can choose which handler type to invoke dynamically (i.e. while the interrupts are registered one by one through the eCos kernel API).
GPIO interrupts
GPIO interrupts are routed through a GPIO interrupt block, in BF54x a PINT. It is in principle possible to assign one GPIO pin to multiple pints, and the interface reflects that: it uses a bitmap to specify bindings to a PINT. Now, I think it is complete nonsense to have one pin be tied to multiple PINTs, and have multiple interrupts raised when on the interrupt condition of that pin.
New idea (not yet implemented): TODO assign a GPIO to at most one PINT.
Caveat: not all permutations are possible. PINT bytes bind to one block (8 pins) of GPIOs. The interface allows any set of simultaneous bindings. The PINT structure allows only a limited subset of bindings. TODO: check that the API functions return -1 or whatever if an impossible binding is attempted.
New idea (not yet implemented): assign GPIO interrupt handlers to ISRs above the actual SIC-based ISR_MAX, one interrupt per GPIO. The interrupt attach notices this and diverts the interrupt attach to the GPIO system.
So, in the Extended implementation the vector layout would be for BF54x:
| vector | public | CEC | SIC |
|---|---|---|---|
| non-SIC interrupts | 0 .. 6 | 0 .. 6 | n/a |
| SIC interrupts offset by 7 | 7 .. 102 | 7 .. 13 | 0 .. 95 |
| GPIO interrupts, GPIO offset by 103 | 103 .. 254 | 7 .. 13 | PINT0..3 |
The GPIOs have four SIC interrupt IRQs, each assigned to a PINT:
- PINT0 19
- PINT1 20
- PINT2 94
- PINT3 95
The default .ecc mapping in the simple interrupt scheme follows the manufacturer default:
- CYGNUM_HAL_BFIN_SIC_ASSIGN_PIID_19 5 (+ 7 = CEC interrupt 12)
- CYGNUM_HAL_BFIN_SIC_ASSIGN_PIID_20 5 (+ 7 = CEC interrupt 12)
- CYGNUM_HAL_BFIN_SIC_ASSIGN_PIID_94 5 (+ 7 = CEC interrupt 12)
- CYGNUM_HAL_BFIN_SIC_ASSIGN_PIID_95 5 (+ 7 = CEC interrupt 12)
There is an API to find the CEC vector for a GPIO port (block of 16 GPIO pins, like 'A' or 'F') and pint assignment:
| int cyg_hal_gpio_intr_vector(port, channel_mask); |
where channel_mask is as in cyg_hal_gpio_interrupt_assign().
Prioritization of interrupts for the devices
Top priority:
- Receive GPIO PINT interrupt from RFID devices
- DMA transfer between CPU and RFID devices
Other devices that use an interrupt are, in descending order:
- EPPI?
- sound?
- Ethernet send/receive ready
- USB
- BlueTooth (dis)connected
- SDCard
- Real-time clocks for thread_timed_wait and sleep
- User buttons (3)
- wake up from standby/low power (1 button)
- Touchscreen (SPI?)
- UART1 as stdin/
- Battery low, brown-out
These are so many that it seems implausible that we will ever be able to reduce them to 7 so a one-to-one mapping of interrupts to IVGs is possible. So we will use the 'Extended Interrupt Mapping' implemented by André Liesk, which provides a mechanism to multiplex interrupts over one IVG. TODO: if there is only one source for a CEC interrupt, can the Extended Handling be bypassed?
We have 4 GPIO interrupt channels, PINT0..PINT3. But there will probably more than 4 devices that use an interrupt; e.g. all user buttons will share one, and the battery status/power button too, and...
| pin | GPIO PINT | device |
|---|---|---|
| PA10,PA11 | PINT0 | Receive GPIO PINT interrupt from RFID devices |
| ... | DMA transfer between CPU and RFID devices | |
| ... | EPPI? | |
| PE12 | PINT2 | Ethernet send/receive ready |
| PA13,...? | ... USB | |
| PB2/PB3 or PB6/PB7 | UART3 BlueTooth; or use separate ATTN GPIO (TBD)? | |
| TBD: UNIMPL | ... Real-time clocks for thread_timed_wait and sleep | |
| PD10,PD11,PD12 | PINT3 | User buttons |
| ... | PINT3 | button wake up from standby/low power |
| PD6 | PINT2 | Touchscreen (control is SPI) |
| PE9/PE10 or PH0/PH1 | ... UART1 as stdin/ | |
| PA12 | PINT1 | BATT_FAULT |
| NMI | BAT_STATUS Battery low, brown-out |
And must this assignment be done in the .ecc file? Or in some config file? I think the assignment can/must be done statically.


