Using UAV DevBoard serial port Tx interrupts

UAV DevBoard Pilots:This topic concerns an efficient way to transfer data through the transmitter of a USART using transmit interrupts.There are two general approaches to sending out a message through a USART. The simplest way to do it, but not the most efficient, is to transfer a byte at a time to the transmit buffer of the USART, and wait for the transmitter to be ready before transferring another byte. This method is fine if there is not much data to be sent. This is the method that I use in my firmware to send messages to the GPS to initialize it. Since only a few short messages are sent only during initialization, it is not worth the trouble to be efficient.However, telemetry traffic is another matter. If you would like to send a lot of data through a USART on a regular basis, the extra programming effort of using transmit interrupts pays off in efficiency.Conceptually, the idea is simple: use the empty-Tx-buffer interrupt to trigger the transfer of the data to the transmit buffer. That way, your firmware can be off doing something else between characters.As an example, I have modified the roll-pitch-yaw demo for the UAV DevBoard to use transmit interrupts to pump out GPS data and direction-cosine data through the spare serial port.Here are some of the highlights of the C code:When you are ready to send a message, prepare it and place it in a transmit buffer, as shown in the following routine. Then, simply transfer only the first byte of the message to the USART transmitter:void debug_output( void ){unsigned char txchar ;db_index = 0 ;sprintf( debug_buffer , "lat: %li, long: %li, alt: %li\r\nrmat: %i, %i, %i, %i, %i, %i, %i, %i, %i\r\n" ,lat_gps.WW , long_gps.WW , alt_sl_gps.WW ,rmat[0] , rmat[1] , rmat[2] ,rmat[3] , rmat[4] , rmat[5] ,rmat[6] , rmat[7] , rmat[8] ) ;txchar = debug_buffer[ db_index++ ] ;U1TXREG = txchar ;return ;}Some of you may be wondering why I did not transfer the byte directly to the transmitter with a statement such as:U1TXREG = debug_buffer[ db_index++ ] ;The reason is that the Microchip C compiler is too smart for its own good, or maybe not smart enough. It updates db_index after the transfer of the byte to U1TXREG. That is too late, because a Tx interrupt will be generated immediately.The statement U1TXREG = txchar will transfer the first character to the transmitter, and trigger a Tx interrupt. After that, whenever the transmitter is ready for another character, it will generate another interrupt. The interrupt service routine responds as follows:void __attribute__((__interrupt__,__no_auto_psv__)) _U1TXInterrupt(void){unsigned char txchar ;IFS0bits.U1TXIF = 0 ; // clear the interrupttxchar = debug_buffer[ db_index++ ] ;if ( txchar ) U1TXREG = txchar ;return ;}The example in this case is for an ASCII message. The sprintf() call places a 0 at the end of the message, which is used to detect the end of the message, and completes the transfer.A binary message would be handled a little differently. In that case, you would need to use a message length variable to detect the end of message.-Bill

You need to be a member of diydrones to add comments!

Join diydrones

Email me when people reply –


  • I tested the code using UC00A uart converter.
    But i never can see any response in the hyperterminal in my computer.
    you put the value of txchar into U1TXREG variable,but i can not see U1TXREG value in debug mode.
    this register is always 0.
    what problem is that?
    van you kindly explain it?
    thank you and regards
  • Hi Bill,

    I noticed in option.h that I can select #define SERIAL_OUTPUT_FORMAT/Serial_Ardustation.

    Would this mean that the Ardustation work with his actual code?
    Are the received data the same as from Ardupilot?
    If yes I suppose that antenna tracking works too, right?

    Thanks and best reards,

  • It seems quite a good way to send the telemetry to ground with a Xbee

    As I am quite new in C30
    But I just wondering about db_index it seems to be declared local in void debug_output( void )

    I suppose its declared global somewhere else to be modified in _U1TXInterrupt(void)

    so the code could be :

    void debug_output( void )
    unsigned char txchar ;
    // commented db_index = 0 ;
    sprintf( debug_buffer , "lat: %li, long: %li, alt: %li\r\nrmat: %i, %i, %i, %i, %i, %i, %i, %i, %i\r\n" ,
    lat_gps.WW , long_gps.WW , alt_sl_gps.WW ,
    rmat[0] , rmat[1] , rmat[2] ,
    rmat[3] , rmat[4] , rmat[5] ,
    rmat[6] , rmat[7] , rmat[8] ) ;
    txchar = debug_buffer[ 0] ; // modified im am not sure about it ??
    U1TXREG = txchar ;
    return ;

This reply was deleted.