Home
Luke's Weblog - Interrupts [entries|archive|friends|userinfo]
Luke Gorrie

[ website | My Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Interrupts [Apr. 8th, 2008|06:17 pm]
Previous Entry Add to Memories Tell a Friend Next Entry
[Tags|]
[Current Location |kathmandu]

Today I got interrupt-driven network I/O working.

There's actually a little more to interrupts than I'd realised. We have two separate bits of hardware dealing with them: the CAN network controller sets interrupt signals based on the CAN bus status (data to receive? ready to transmit?) and the Vectored Interrupt Controller (VIC) decides how these signals should affect the CPU's execution.

I'm using the CAN interrupts to track the bus status and using the VIC to temporarily disable interrupts when they're inconvenient, i.e. when I'm accessing a data structure that's shared between ISR (Interrupt Service Routine) and non-ISR code. These data structures are FIFO queues based on the ring code that I posted before.

The tricky part was figuring out exactly when the CAN controller sets and clears interrupt status. Looks like it's based on discrete events (e.g. CAN frame successfully sent on the bus) rather than just conditions (CAN transmit buffer is empty).

Here's the code for receiving data from the CAN bus:

\ Is there a CAN frame ready to receive?
: can-rx? ( -- flag )
    CAN-GSR can@ $1 and  0 <>
;

\ Return the number of bytes of data in incoming CAN frame. 
: can-dlen ( -- n )
    CAN-RFS can@
    16 rshift $F and
    8 min
;

\ Free CAN Rx hardware buffers
: can-ack-rx ( -- ) $4 ( RRB ) CAN-CMR can! ;

\ Receive a CAN frame (blocking)
: can-rx ( -- dB dA len id )
    BEGIN can-rx? UNTIL
    CAN-RDB can@  CAN-RDA can@  can-dlen  CAN-RID can@
    can-ack-rx
;
And here's the interrupt service routine that wakes up when a frame becomes available on the bus and puts it onto the RX queue for application-level processing:
\ Read a CAN frame from the controller and put it on the RX queue.
: can-rx-isr ( -- )
    can-rx-ring ring-full? IF
        can-disable-rx-interrupt
    ELSE
        can-rx can-rx-ring >ring
    THEN
;
Here're the words that non-interrupt code uses to temporarily mask out CAN interrupts to safely access the RX queue:
$4100000 ( CAN1-RX CAN1-TX ) CONSTANT CAN-interrupts
: mask-can{ ( -- ) CAN-interrupts disable-interrupts ;
: }mask-can ( -- ) CAN-interrupts enable-interrupts ;
And here's the non-interrupt code that reads frames from the queue:
: can-dequeue? ( -- flag )
    mask-can{  can-rx-ring ring-empty? not  }mask-can
;

: can-dequeue ( -- dB dA len id )
    BEGIN can-dequeue? UNTIL
    mask-can{
        can-rx-ring ring>
    }mask-can
    can-enable-rx-interrupt
;
How do other people's Forth-based interrupt handlers look?
LinkReply

Comments:
[User Picture]From: [info]leon03
2008-04-09 06:13 am (UTC)

(Link)

Well, soon I shall be delving into such issues myself. However, my new toy hasn't arrived yet, and I haven't started.

So is this Forth system generate native code, or is it a threaded interpreter?