CS452 - Real-Time Programming - Spring 2012
Lecture 13 - Hardware Interrupts
Public Service Annoucements
- Assignment 3
Hardware Interrupts
Vectored Operation
General Idea
The standard way of programming the ICU requires the kernel to query the
ICU. Sometimes (!), this is unacceptably inefficient. Then, you have another
alternative, vectored interrupts.
Relevant registers:
- there are 16 pairs that you write
| Register Name |
Offset |
R/W |
Description |
Comments |
| VICxVectAddry |
0x100+4y |
R/W |
Vector address for interrupt y |
Entry point of ISR for interrupt y |
| VICxVectCntly |
0x200+4y |
R/W |
Control register for interrupt y |
Bit[0-4]: interrupt source for interrupt y
Bit[5]: enable vectored interrupt y |
- There is one pair used by the program
| Register Name |
Offset |
R/W |
Description |
| VICxVectAddr |
0x030 |
R/W |
Read: address of vector for highest priority interrupt
Write: service complete, enable priority hardware
|
| VICxDefVectAddr |
0x034 |
R/W |
Default vector address |
- The first is the address (ISR entry point) of the highest priority
interrupt. Write it during interrupt processing to get the current
highest priority interrupt.
- The second would normally be 0x34, the entry point of the
kernel.
Procedure
Initialization
- Write kernel entry point into VICxDefVectAddr
- If desired write special entry point into VICxVectAddry
- When ready to accept interrupts write source and enable into
VICxVectCntly
When an interrupt occurs
- Read VICxVectAddr to find address
- Move result to PC
ldr pc, #<VicVectAddr>
(Note that this is similar to the instruction in 0x014. Could we do it
all in one?)
- Before interrupts are re-enabled write VICxVectAddr to start priority
hardware
Answer to question.
Look carefully at what's in 0x18
Clock Server
Primitives
int Time( )
- Clock server starts at zero when it initializes
- Unit of time is tick
int Delay( int ticks )
- Note error returns
- You might want to add an error for negative arguments
- ticks is usually calculated, and a negative value is an early
warning of falling behind.
int DelayUntil( int ticks )
- Can be constructed from the above two primitives.
Implementation
main( ) {
notifier = Create( HIGHEST, ... );
time = 0
Send( notifier, &evtType, ... );
FOREVER {
Receive( &requester, &request, ... );
switch ( request.type ) {
case NOTIFIER:
Reply( notifier, ... )
time++;
break;
case TIME_REQUEST:
Reply( requester, time,... )
break;
case DELAY_REQUEST:
Add requester to list of suspended tasks
break;
}
Check list of suspended tasks and reply
}
}
Comments:
- You need a common request type, or possibly a union.
- You should notice a typical server pattern.
- Notifier updates data
- Client who can be serviced now is serviced
- Client who needs service in the future is suspended
- List of suspended tasks is checked regularly
- It's normal to sort the list of suspended tasks. Why?
HALT versus an Idle Task
What do you do when there are no tasks to run?
- Idle task
- lowest priority
- diagnose system
- search for ETI
- STANDBY/HALT
- turns off CPU clock
- save power (battery)
- provided two ways
- through System Controller Co-processor
- Use MCR instruction, to access co-processor 15.
- can only be executed in privileged modes
- through EP9302
- write location
0x80930008 (HALT) or
0x8093000c (STANDBY)
- bit must be set in
0x80930080
- IRQ path is asynchronous, so it works when the clock is off
- but interrupts must be enabled
- therefore you want to be in user mode
- See pdf for some details.
Serial I/O
See pdf.
FIFO
Why do FIFOs exist in UARTS?
The Big Blunder
To use the FIFO effectively you must be able to turn off the transmitter
& receiver independently.
But look at UARTE in UARTxCtrl
- UART Enable.
- If this bit is set to 1, the UART is enabled.
- Data transmission and reception occurs for UART signals.
The Little Blunder
`It is assumed that various configuration registers for the UART are not
written more than once in quick succession, in order to insure proper
synchronization of configuration information across the implementation. Such
registers include UART1Ctrl and UART1LinCtrlHigh. ... In between the two
writes, at least two UARTCLK periods must occur. Under worst case conditions,
at least 55 HCLK periods must separate the two writes. The simplest way to
due [sic] this is separate the two writes by 55 NOPs.'
Why does this occur?
- CPU clocked by CPU clock
- System buses clocked by several different clocks
- UART clocked by its own clock
- The clocks were not suitably synchronized
Why doesn't anybody care?
- UARTs are used at the beginning of the development process
- Once other I/O (ethernet, USB, etc.) is working, UARTs are no longer
used, except by the boot loader
Interrupts
Five interrupts in the device
These interrupts are separately enabled and disabled.
- Transmit
- FIFO enabled
- Asserted when transmit FIFO is less than half full.
- Cleared when transmit FIFO is more than half full.
- FIFO disabled
- Asserted when holding register is empty
- Cleared on write to the holding register
- Not conditioned by enable.
- Receive
- FIFO enabled
- Asserted when receive FIFO is half full
- Cleared when receive FIFO is read to less than half full.
- FIFO disabled
- Asserted when receive buffer is full
- Cleared when receive buffer is read
- Modem status
- Asserted when hardware flow control bits change
- Cleared when the modem status register is written
- Receive timeout
- Asserted when receive FIFO is not empty and 32 bit periods pass
with no new data
- Cleared when all data has been read from FIFO
- Combined
- OR of the four above interrupts
- Asserted when at least one of the above interrupts is asserted
- Cleared when all the above interrupts are not asserted.
Three inputs to the PIC
- Transmit
- Receive
- Combined
Easy way to use interrupts
Enable only combined; read UART registers to decide what to do.
Think of the receive and transmit parts of the UART as separate state
machines
- Base the state machine on bits in the status registers
- Make a separate state machine for flow control
Return to: