UART

<< Keyboard   ·    Home   ·   Demo Mode >>

The execution of the Interrupt routine takes a lot of time, and it would probably slow down the UART communication to a few hundred bytes per second. This is valid both for polling and interrupt service, as the interrupt for UART must have the lower priority than the OCx Interrupt routine. That is why the UART service i integrated in OCx Interrupt routine. It polls the state of SFR flags and reads/writes bytes to the SFR buffers after each horizontal sync.

Routine uart_service does that. It is not placed in the subroutine, but used as macro and (together with Keyboard routine) placed several times in the Interrupt routine. This macro is named EXTRAJOB. You should note that this macro has no arguments and that it might be organized as the subroutine, but reason for using macro is the execution speed.

There are two 256-byte (128-word) circular buffers: RX_CIRCULAR and TX_CIRCULAR. They are aligned to the full 256-byte pages in the program. Although UART uses 8-bit communication, circular buffers are organized as 128 words, so the 9-bit UART modes are covered. In fact, PIC24 and dsPIC33 family has 16-bit RX and TX buffers, so the whole 16-bit buffers are read/written from/to the circular buffers.

The UART service program is very short and simple, and no UART status bits are serviced by the Interrupt routine. User can check the error status for the whole received packet in the main program, outside the Interrupt routine.

UART interface is not initialized in this program. User has to do that, according to his own requirements.

Only UART 1 is covered in this routine. UART 2 is ignored.

Interrupt routine uses 8-bit variable RX_WR to write the received word into the RX circular buffer, and the user uses the 8-bit variable RX_RD to read the circular buffer. Default values for both RX_WR and RX_RD are 0 (only the low bytes of pointers are written, as the circular buffers are aligned with the whole pages). After the byte is received, interrupt routine increments the variable RX_WR by two (mod 256).

If the RX_CIRCULAR is full (contains 127 unread words), the received byte is not written in the circular buffer. It is lost and there is no notification.

User has to compare 8-bit values of RX_RD with RX_RD. If they are equal, that means that there is no word ready in the buffer. If they are different, the user reads the word from the position RX_RD and increments RX_RD by two (mod 256).

Subroutine RX_TEST does exactly that (listing attached). On return, Carry Flag (SR,#C)  is reset if the word is received. In that case, 16-bit register W1 contains the received word. If the Carry Flag is set, that means that no word was received.

This is the supposed way to use this subroutine:

1. Call RX_TEST.
2. Test Carry Flag, If it is set, W1 contains the word from U1RXREG.
3. If Carry Flag is reset, nothing was received. User should loop to step 1 or (more likely) try later.

To place the word in the TX circular buffer, user first has to check if TX_WR+2 (8-bit contents of TX_WR incremented by 2 mod 256) is equal to TX_RD. If they are equal, that means that the TX circular buffer is full (it contains 127 word in pending state) and that no word was placed in the buffer. If they are not equal, the word in 16-bit register W1 has to be placed in the circular buffer at the address determined by TX_WR. After that, user must increment pointer TX_WR by two.

 Default values for both TX_WR and TX_RD are 0 (only the low bytes of pointers are written, as the circular buffers are aligned with the whole pages). After each byte is transferred to the UART interface, interrupt routine increments TX_RD by two (mod 256).

Subroutine TX_TEST does that (listing attached). If the buffer is not full, it places W1 in the buffer, increments TX_WR by two, resets Carry Flag (SR,#C) and returns from the subroutine. If the buffer is full, it only sets Carry Flag and returns.

When the byte (or 9-bit word) is ready in 16-bit register W1 to be transmitted, this is the supposed way to use this subroutine:

1. Call TX_TEST with the byte (or 9-bit word) in 16-bit register W1.
2. Test Carry Flag, If it is reset, everything is OK and the word is placed in circular buffer.
3. If Carry Flag is set, that means that the circular buffer was full and that W1 was not placed in it. User should loop to step 1 or save W1 somewhere and try later.

Both subroutines should be used outside the interrupt routine.

 Note: Sorry, this part of the program was not tested yet. 

Here is the listing for RX_TEST and TX_TEST subroutines:

                                                                                  

rx_test:                                                                          
      mov    #RX_CIRCULAR,w0 ; preset high address byte for RX circular buffer    
      mov.b  RX_RD,WREG      ; get low address byte from the pointer              
      cp.b   RX_WR           ; compare pointers                                   
      bra    z,no_rx         ; nothing was received                               
      mov    [w0++],w1       ; read byte from RX circular buffer                  
      mov.b  w0,RX_RD        ; update RX_RD pointer                               
      bset   SR,#C           ; SET C (notify that word was received)              
      return                 ; received word is in w1                             
no_rx:                                                                            
      bclr   SR,#C           ; CLR C (notify that nothing was received)           
      return                                                                      
                                                                                  
                                                                                  
                                                                                  
tx_test:                                                                          
      mov    #TX_CIRCULAR,w0 ; preset high address byte for TX circular buffer    
      inc2.b TX_WR,WREG      ; get low address byte +2mod256 from the pointer     
      cp.b   TX_RD           ; compare pointers                                   
      bra    z,no_room       ; no room in tx circular buffer                      
      mov.b  WREG,TX_WR      ; update TX_WR pointer                               
      mov    w1,[--w0]       ; put word in TX circular buffer                     
      bclr   SR,#C           ; CLR C (notify that word was placed in circ buffer) 
      return                                                                      
no_room:                                                                          
      bset   SR,#C           ; SET C (notify that tx circular buffer was full)    
      return                                                                      
                                                                                  

<< Keyboard   ·    Home   ·   Demo Mode >>