A demo using serial interrupts with buffering in a loopback test

Dependencies:   mbed

Committer:
4180_1
Date:
Sun Dec 09 14:30:36 2012 +0000
Revision:
1:0bdf3bebb1d7
Parent:
0:023c5cda6102
Serial Interupts with buffering demo

Who changed what in which revision?

UserRevisionLine numberNew contents of line
4180_1 0:023c5cda6102 1
4180_1 0:023c5cda6102 2 #include "mbed.h"
4180_1 0:023c5cda6102 3 // Serial TX & RX interrupt loopback test using formatted IO - sprintf and sscanf
4180_1 0:023c5cda6102 4 // Connect TX to RX (p9 to p10)
4180_1 0:023c5cda6102 5 // or can also use USB and type back in the number printed out in a terminal window
4180_1 0:023c5cda6102 6 // Sends out ASCII numbers in a loop and reads them back
4180_1 0:023c5cda6102 7 // If not the same number LED4 goes on
4180_1 0:023c5cda6102 8 // LED1 and LED2 indicate RX and TX interrupt routine activity
4180_1 0:023c5cda6102 9 // LED3 changing indicate main loop running
4180_1 0:023c5cda6102 10
4180_1 0:023c5cda6102 11
4180_1 0:023c5cda6102 12 Serial device(p9, p10); // tx, rx
4180_1 0:023c5cda6102 13 // Can also use USB and type back in the number printed out in a terminal window
4180_1 0:023c5cda6102 14 // Serial monitor_device(USBTX, USBRX);
4180_1 0:023c5cda6102 15 DigitalOut led1(LED1);
4180_1 0:023c5cda6102 16 DigitalOut led2(LED2);
4180_1 0:023c5cda6102 17 DigitalOut led3(LED3);
4180_1 0:023c5cda6102 18 DigitalOut led4(LED4);
4180_1 0:023c5cda6102 19
4180_1 0:023c5cda6102 20
4180_1 0:023c5cda6102 21 void Tx_interrupt();
4180_1 0:023c5cda6102 22 void Rx_interrupt();
4180_1 0:023c5cda6102 23 void send_line();
4180_1 0:023c5cda6102 24 void read_line();
4180_1 0:023c5cda6102 25
4180_1 0:023c5cda6102 26
4180_1 0:023c5cda6102 27 // Circular buffers for serial TX and RX data - used by interrupt routines
4180_1 0:023c5cda6102 28 const int buffer_size = 255;
4180_1 0:023c5cda6102 29 // might need to increase buffer size for high baud rates
4180_1 0:023c5cda6102 30 char tx_buffer[buffer_size];
4180_1 0:023c5cda6102 31 char rx_buffer[buffer_size];
4180_1 0:023c5cda6102 32 // Circular buffer pointers
4180_1 0:023c5cda6102 33 // volatile makes read-modify-write atomic
4180_1 0:023c5cda6102 34 volatile int tx_in=0;
4180_1 0:023c5cda6102 35 volatile int tx_out=0;
4180_1 0:023c5cda6102 36 volatile int rx_in=0;
4180_1 0:023c5cda6102 37 volatile int rx_out=0;
4180_1 0:023c5cda6102 38 // Line buffers for sprintf and sscanf
4180_1 0:023c5cda6102 39 char tx_line[80];
4180_1 0:023c5cda6102 40 char rx_line[80];
4180_1 0:023c5cda6102 41
4180_1 0:023c5cda6102 42 // main test program
4180_1 0:023c5cda6102 43 int main() {
4180_1 0:023c5cda6102 44 int i=0;
4180_1 0:023c5cda6102 45 int rx_i=0;
4180_1 0:023c5cda6102 46 device.baud(9600);
4180_1 0:023c5cda6102 47
4180_1 0:023c5cda6102 48 // Setup a serial interrupt function to receive data
4180_1 0:023c5cda6102 49 device.attach(&Rx_interrupt, Serial::RxIrq);
4180_1 0:023c5cda6102 50 // Setup a serial interrupt function to transmit data
4180_1 0:023c5cda6102 51 device.attach(&Tx_interrupt, Serial::TxIrq);
4180_1 0:023c5cda6102 52
4180_1 0:023c5cda6102 53 // Formatted IO test using send and receive serial interrupts
4180_1 0:023c5cda6102 54 // with sprintf and sscanf
4180_1 0:023c5cda6102 55 while (1) {
4180_1 0:023c5cda6102 56 // Loop to generate different test values - send value in hex, decimal, and octal and then read back
4180_1 0:023c5cda6102 57 for (i=0; i<0xFFFF; i++) {
4180_1 0:023c5cda6102 58 led3=1;
4180_1 0:023c5cda6102 59 // Print ASCII number to tx line buffer in hex
4180_1 0:023c5cda6102 60 sprintf(tx_line,"%x\r\n",i);
4180_1 0:023c5cda6102 61 // Copy tx line buffer to large tx buffer for tx interrupt routine
4180_1 0:023c5cda6102 62 send_line();
4180_1 0:023c5cda6102 63 // Print ASCII number to tx line buffer in decimal
4180_1 0:023c5cda6102 64 sprintf(tx_line,"%d\r\n",i);
4180_1 0:023c5cda6102 65 // Copy tx line buffer to large tx buffer for tx interrupt routine
4180_1 0:023c5cda6102 66 send_line();
4180_1 0:023c5cda6102 67 // Print ASCII number to tx line buffer in octal
4180_1 0:023c5cda6102 68 sprintf(tx_line,"%o\r\n",i);
4180_1 0:023c5cda6102 69 // Copy tx line buffer to large tx buffer for tx interrupt routine
4180_1 0:023c5cda6102 70 send_line();
4180_1 0:023c5cda6102 71 led3=0;
4180_1 0:023c5cda6102 72 // Read a line from the large rx buffer from rx interrupt routine
4180_1 0:023c5cda6102 73 read_line();
4180_1 0:023c5cda6102 74 // Read ASCII number from rx line buffer
4180_1 0:023c5cda6102 75 sscanf(rx_line,"%x",&rx_i);
4180_1 0:023c5cda6102 76 // Check that numbers are the same
4180_1 0:023c5cda6102 77 if (i != rx_i) led4=1;
4180_1 0:023c5cda6102 78 // Read a line from the large rx buffer from rx interrupt routine
4180_1 0:023c5cda6102 79 read_line();
4180_1 0:023c5cda6102 80 // Read ASCII number from rx line buffer
4180_1 0:023c5cda6102 81 sscanf(rx_line,"%d",&rx_i);
4180_1 0:023c5cda6102 82 // Check that numbers are the same
4180_1 0:023c5cda6102 83 if (i != rx_i) led4=1;
4180_1 0:023c5cda6102 84 // Read a line from the large rx buffer from rx interrupt routine
4180_1 0:023c5cda6102 85 read_line();
4180_1 0:023c5cda6102 86 // Read ASCII number from rx line buffer
4180_1 0:023c5cda6102 87 sscanf(rx_line,"%o",&rx_i);
4180_1 0:023c5cda6102 88 // Check that numbers are the same
4180_1 0:023c5cda6102 89 if (i != rx_i) led4=1;
4180_1 0:023c5cda6102 90 }
4180_1 0:023c5cda6102 91 }
4180_1 0:023c5cda6102 92 }
4180_1 0:023c5cda6102 93
4180_1 0:023c5cda6102 94 // Copy tx line buffer to large tx buffer for tx interrupt routine
4180_1 0:023c5cda6102 95 void send_line() {
4180_1 0:023c5cda6102 96 int i;
4180_1 0:023c5cda6102 97 char temp_char;
4180_1 0:023c5cda6102 98 bool empty;
4180_1 0:023c5cda6102 99 i = 0;
4180_1 0:023c5cda6102 100 // Start Critical Section - don't interrupt while changing global buffer variables
4180_1 0:023c5cda6102 101 NVIC_DisableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 102 empty = (tx_in == tx_out);
4180_1 0:023c5cda6102 103 while ((i==0) || (tx_line[i-1] != '\n')) {
4180_1 0:023c5cda6102 104 // Wait if buffer full
4180_1 0:023c5cda6102 105 if (((tx_in + 1) % buffer_size) == tx_out) {
4180_1 0:023c5cda6102 106 // End Critical Section - need to let interrupt routine empty buffer by sending
4180_1 0:023c5cda6102 107 NVIC_EnableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 108 while (((tx_in + 1) % buffer_size) == tx_out) {
4180_1 0:023c5cda6102 109 }
4180_1 0:023c5cda6102 110 // Start Critical Section - don't interrupt while changing global buffer variables
4180_1 0:023c5cda6102 111 NVIC_DisableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 112 }
4180_1 0:023c5cda6102 113 tx_buffer[tx_in] = tx_line[i];
4180_1 0:023c5cda6102 114 i++;
4180_1 0:023c5cda6102 115 tx_in = (tx_in + 1) % buffer_size;
4180_1 0:023c5cda6102 116 }
4180_1 0:023c5cda6102 117 if (device.writeable() && (empty)) {
4180_1 0:023c5cda6102 118 temp_char = tx_buffer[tx_out];
4180_1 0:023c5cda6102 119 tx_out = (tx_out + 1) % buffer_size;
4180_1 0:023c5cda6102 120 // Send first character to start tx interrupts, if stopped
4180_1 0:023c5cda6102 121 device.putc(temp_char);
4180_1 0:023c5cda6102 122 }
4180_1 0:023c5cda6102 123 // End Critical Section
4180_1 0:023c5cda6102 124 NVIC_EnableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 125 return;
4180_1 0:023c5cda6102 126 }
4180_1 0:023c5cda6102 127
4180_1 0:023c5cda6102 128 // Read a line from the large rx buffer from rx interrupt routine
4180_1 0:023c5cda6102 129 void read_line() {
4180_1 0:023c5cda6102 130 int i;
4180_1 0:023c5cda6102 131 i = 0;
4180_1 0:023c5cda6102 132 // Start Critical Section - don't interrupt while changing global buffer variables
4180_1 0:023c5cda6102 133 NVIC_DisableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 134 // Loop reading rx buffer characters until end of line character
4180_1 0:023c5cda6102 135 while ((i==0) || (rx_line[i-1] != '\r')) {
4180_1 0:023c5cda6102 136 // Wait if buffer empty
4180_1 0:023c5cda6102 137 if (rx_in == rx_out) {
4180_1 0:023c5cda6102 138 // End Critical Section - need to allow rx interrupt to get new characters for buffer
4180_1 0:023c5cda6102 139 NVIC_EnableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 140 while (rx_in == rx_out) {
4180_1 0:023c5cda6102 141 }
4180_1 0:023c5cda6102 142 // Start Critical Section - don't interrupt while changing global buffer variables
4180_1 0:023c5cda6102 143 NVIC_DisableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 144 }
4180_1 0:023c5cda6102 145 rx_line[i] = rx_buffer[rx_out];
4180_1 0:023c5cda6102 146 i++;
4180_1 0:023c5cda6102 147 rx_out = (rx_out + 1) % buffer_size;
4180_1 0:023c5cda6102 148 }
4180_1 0:023c5cda6102 149 rx_line[i-1] = 0;
4180_1 0:023c5cda6102 150 // End Critical Section
4180_1 0:023c5cda6102 151 NVIC_EnableIRQ(UART1_IRQn);
4180_1 0:023c5cda6102 152 return;
4180_1 0:023c5cda6102 153 }
4180_1 0:023c5cda6102 154
4180_1 0:023c5cda6102 155 // Interupt Routine to read in data from serial port
4180_1 0:023c5cda6102 156 void Rx_interrupt() {
4180_1 0:023c5cda6102 157 led1=1;
4180_1 0:023c5cda6102 158 // Loop just in case more than one character is in UART's receive FIFO buffer
4180_1 0:023c5cda6102 159 // Stop if buffer full
4180_1 0:023c5cda6102 160 while ((device.readable()) || (((rx_in + 1) % buffer_size) == rx_out)) {
4180_1 0:023c5cda6102 161 rx_buffer[rx_in] = device.getc();
4180_1 0:023c5cda6102 162 // Uncomment to Echo to USB serial to watch data flow
4180_1 0:023c5cda6102 163 // monitor_device.putc(rx_buffer[rx_in]);
4180_1 0:023c5cda6102 164 rx_in = (rx_in + 1) % buffer_size;
4180_1 0:023c5cda6102 165 }
4180_1 0:023c5cda6102 166 led1=0;
4180_1 0:023c5cda6102 167 return;
4180_1 0:023c5cda6102 168 }
4180_1 0:023c5cda6102 169
4180_1 0:023c5cda6102 170 // Interupt Routine to write out data to serial port
4180_1 0:023c5cda6102 171 void Tx_interrupt() {
4180_1 0:023c5cda6102 172 led2=1;
4180_1 0:023c5cda6102 173 // Loop to fill more than one character in UART's transmit FIFO buffer
4180_1 0:023c5cda6102 174 // Stop if buffer empty
4180_1 0:023c5cda6102 175 while ((device.writeable()) && (tx_in != tx_out)) {
4180_1 0:023c5cda6102 176 device.putc(tx_buffer[tx_out]);
4180_1 0:023c5cda6102 177 tx_out = (tx_out + 1) % buffer_size;
4180_1 0:023c5cda6102 178 }
4180_1 0:023c5cda6102 179 led2=0;
4180_1 0:023c5cda6102 180 return;
4180_1 0:023c5cda6102 181 }