Transmitter Interrupts How to Handle Transmitter Interrupts Code

  • Slides: 19
Download presentation
Transmitter Interrupts • How to Handle Transmitter Interrupts? • Code to fix TX error

Transmitter Interrupts • How to Handle Transmitter Interrupts? • Code to fix TX error • Critical Regions Text: Tanenbaum 2. 3. 2

Review of Interrupts Com Port Bus

Review of Interrupts Com Port Bus

Transmitter Interrupts • Each interrupt signals readiness to output another byte of data •

Transmitter Interrupts • Each interrupt signals readiness to output another byte of data • The transmitter ISR gives another byte to output • Issues to consider: – How to distinguish the Tx from Rx interrupts since they share one interrupt line(e. g. IRQ 3 for COM 2)? – what to do when data runs out? – How to start/restart the Tx interrupt?

How to Distinguish the Interrupts? • One interrupt service routine to perform both Tx

How to Distinguish the Interrupts? • One interrupt service routine to perform both Tx and Rx functions • Check the UART’s LSR to see if Data Ready (DR) bit or the Transmit Holding Register(THRE) bit is set. Then execute the corresponding function. • Any one of the 3 situations can happen: – Both Tx and Rx interrupts are ready – Only Tx interrupt is ready – Only Rx interrupt is ready

How to Distinguish the Interrupts? • Method 1: – Check the UART LSR to

How to Distinguish the Interrupts? • Method 1: – Check the UART LSR to see if Receiver Data Ready (DR) bit or the Transmit Holding Register (THRE) bit is set. Then execute the corresponding Tx or Rx function. • Method 2: – Check the UART Interrupt Identification Register (IIR)’s bits 1 and bit 2 to see what interrupt is active bit 2 1 0 bit 1 0 1 bit 0 0 0 Interrupt Rx Data Ready Tx Holding Reg Empty – Note: Reading of IIR or writing into TX register resets only the Tx Interrupt. You still need to read the RX register to reset the Rx int

Example of Using IIR iir = inpt(baseport + UART_IIR); switch (iir & UART_IIR_ID) {

Example of Using IIR iir = inpt(baseport + UART_IIR); switch (iir & UART_IIR_ID) { case UART_IIR_RDI: …. case UART_IIR_THRI: …. default: …. } bit-wise operator /* mask the 2 -bit ID field */ /* it's a receiver int */ /* do Rx function */ /* it is a transmitter int */ /* do Tx function */ /* no need to reset Tx int */ /* do default function */

Code Modifications to fix VM error • The virtual machine does not emulate exactly

Code Modifications to fix VM error • The virtual machine does not emulate exactly all the hardware functions • For the transmitter, you have to constantly kick start the transmitter interrupt to generate more transmit interrupts, • e. g. in the transmitter ISR code: c = this_buffer[cursor++]; /* get next character from app */ outpt(COM 1_BASE+UART_IER, 0); /* disable all interrupts */ outpt(COM 1_BASE+UART_IER, UART_IER_THRI); /* kickstart TX interrupt */ outpt(COM 1_BASE+UART_TX, c); /* output the character */

What to Do when Tx Data Runs Out ? • THRE bit set to

What to Do when Tx Data Runs Out ? • THRE bit set to 1 when the UART hardware is ready to accept a new character for transmission. • THRE bit set to 0 after UART_Tx register is loaded with a new character. • If there is a Tx interrupt, dequeue a character and output it. • Shut down the Tx interrupt when queue is empty. • Rx interrupts need to be on continuously. Tx interrupts go on and off depending on output availability.

The Transmitter Strategy • Set up interrupt gate in IDT, but leave Tx interrupt

The Transmitter Strategy • Set up interrupt gate in IDT, but leave Tx interrupt off in the UART. • To load a string (n chars) into queue: – 1. Load the first part of the string into the output buffer (i. e. enqueue the chars until the queue is full (Qmax)). – 2. Turn Tx interrupt on in the UART_IER. – 3. While the interrupt is ongoing, loop over the enqueuing of the rest of the chars. – 4. Return when all chars have been enqueued. • To output the chars in the queue: – 1. Check if the queue is empty. – 2. If there are chars, dequeue one and output it to UART_TX. – 3. If there none, shut down Tx interrupt in the UART_IER.

An Example • write(TTY 1, “ 123456789”, 9) with nchar = 9 and Qmax

An Example • write(TTY 1, “ 123456789”, 9) with nchar = 9 and Qmax = 6 – 1. “ 123456” put in queue during the setup in ttywrite – 2. “ 123” output , one by one, by ISR – 3. “ 789” get loaded in the queue in ttywrite – 4. ttywrite returns after all nchar in queue – 5. ttywrite has returned, but 6 chars “ 456789” are still in the queue. They are outputted one by ISR

Timeline Representation Outb: 1 2 3 4 5 6 7 8 9 ISR: ttywrite:

Timeline Representation Outb: 1 2 3 4 5 6 7 8 9 ISR: ttywrite: setup testio: loop of enq’s ttywrite rest of testio Note: 1. Still have a busy loop in ttywrite, i. e. loop of enq’s 2. OK for hw 1. Fix it later using a scheduler 3. Could have a race condition due to concurrent activities on modifying the queues

The Race Condition • 2 concurrent activities occur when executing ttywrite – ttywrite looping

The Race Condition • 2 concurrent activities occur when executing ttywrite – ttywrite looping on enqueues – intermittent ISR executing a dequeue – working with the same queue (tty->tbuf) • Interrupt can occur between 2 machine instructions. • in ttywrite if (enqueue( &(tty->tbuf), buf[i])) i++; • during enqueue function, ISR calling dequeue function can mess up the queue data structure

How to Avoid the Race Condition • This part of program is called critical

How to Avoid the Race Condition • This part of program is called critical region or critical section when it accesses shared memory. • Use mutual exclusion to make sure one part of program is using the shared variable while the other part is excluded from doing the same thing. • Four conditions to provide mutual exclusion: – No two processes simultaneously in critical region – No assumptions made about speeds or numbers of CPUs – No process running outside its critical region may block another process – No process must wait forever to enter its critical region

Mutual Exclusion Using Critical Regions

Mutual Exclusion Using Critical Regions

Mutual Exclusion with Busy Waiting • • • Disabling Interrupts Locked Variables Strict Alternation

Mutual Exclusion with Busy Waiting • • • Disabling Interrupts Locked Variables Strict Alternation Peterson’s Solution Test and Set Lock (TSL)

Turning off Interrupts in ttywrite • We can turn off interrupts during the execution

Turning off Interrupts in ttywrite • We can turn off interrupts during the execution of enqueue and turn them on when enqueue is done • How to do it: cli(); /* disable interrupts in CPU by setting IF=0 in EFLAGS*/ enqueue(…); /* critical region code */ sti(); /* or set_eflags(save_eflags) to re-enable interrupts */

Turning off Interrupts in printf • Important to turn off interrupts before using printf

Turning off Interrupts in printf • Important to turn off interrupts before using printf • Prevent part of the code to do programmed I/O and another one doing interrupt-driven I/O using the Tx of the UART • kprintf(…) is the printf routine that turns off interrupts: int saved_eflags; save_eflags = get_eflags(); cli(); printf(…); /* SAPC-library printf uses programmed I/O */ set_eflags(saved_eflags);

Echoes • Characters to be echoed are generated in the input interrupt handler •

Echoes • Characters to be echoed are generated in the input interrupt handler • One copy is enqueued in the input queue and another in an output echo queue • When the Tx ISR runs, it should look first in the echo queue. The user sees the echo as soon as possible

Pointers in Writing ISR · Don’t forget to ack the device. · Don’t forget

Pointers in Writing ISR · Don’t forget to ack the device. · Don’t forget to ack the PIC (send EOI) · You’re running with IF=0, so no need for cli(). Just leave interrupts off (iret will restore IF=1) · Do as little as possible in the int handler—you’re running on borrowed time, at least in the OS case. · You do need to use global variables to communicate with the program-level code. Interrupt handlers have no parameters. · The global data accessed both from interrupt handlers and program-level code causes “critical sections” in the program-level code, needing mutex protection, i. e. , turning IF=0 during the critical section. · If more than one device is on the same IRQ, check the status of each and service all that are “ready” in the same interrupt. (If you do only one, you might miss the other, because the IRQ signals overlapped and appeared as only one to the PIC. ) This point is relevant to the transmitter and receiver of a UART.