An RTOS-friendly Serial interface Its primary benefit is that it never hogs the CPU. An amusing alternative to the traditional ring-bufferd interrupt-serviced systems, it uses short mbed-rtos queues to buffer characters to and from the UART, and a thread to service the transmitter. Short interrupt service routines enqueue received characters and signal the transmit thread when the transmitter is available. WARNING: Do not create RTOS-Serial objects before the RTOS is running! Put them inside your main() block or another function, not in the global initialization.
Dependents: Test_RDM880_rfid_reader
Diff: rtos_serial.cpp
- Revision:
- 12:be7883573c91
- Parent:
- 11:bc067b42f8e0
- Child:
- 13:2fb32235253c
--- a/rtos_serial.cpp Thu Oct 24 05:34:47 2013 +0000 +++ b/rtos_serial.cpp Thu Oct 24 17:30:52 2013 +0000 @@ -28,25 +28,18 @@ */ #include "rtos_serial.h" +#define START_THREAD 0x80 + RTOS_Serial::RTOS_Serial(PinName tx, PinName rx, const char *name) - : Serial(tx, rx, name) + : RawSerial(tx, rx), name(name), + _tx_thread(&RTOS_Serial::threadStarter, (void *) this, + osPriorityNormal, RTOS_SERIAL_TX_THREAD_STACK_SIZE) { uart_number = get_index(); const PinName leds[] = {LED1,LED2,LED3,LED4}; ledp = new DigitalOut(leds[uart_number]); -#ifdef RTOS_SERIAL_TX_THREAD - tx_emitter_threadp = new Thread(tx_emitter, (void *) this, - osPriorityNormal, RTOS_SERIAL_TX_THREAD_STACK_SIZE); -#endif -// rx_isr_pFP = attach(this, &RTOS_Serial::rx_isr, RxIrq); -// tx_isr_pFP = attach(this, &RTOS_Serial::tx_isr, TxIrq); - attach(this, &RTOS_Serial::rx_isr, RxIrq); - attach(this, &RTOS_Serial::tx_isr, TxIrq); -#ifdef RTOS_SERIAL_TX_THREAD - tx_emitter_threadp->signal_set(0x01); // "prime the pump" of the tx-ready signals -#else - Serial::_putc('*'); //DEBUG -#endif + for (int i=0; i<1; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5); + _tx_thread.signal_set(START_THREAD); } #if 0 @@ -64,8 +57,8 @@ std::printf("returned %d]", b); std::fflush(stdout); #endif #ifdef RTOS_SERIAL_TX_THREAD - tx_emitter_threadp->terminate(); - std::printf("[tx_emitter_thread 0x%x terminated]", tx_emitter_threadp); std::fflush(stdout); + _tx_thread.terminate(); + std::printf("[tx_emitter_thread 0x%x terminated]", &_tx_thread); std::fflush(stdout); delete tx_emitter_threadp; std::printf("[tx_emitter_threadp deleted]"); std::fflush(stdout); #endif @@ -100,7 +93,7 @@ } int RTOS_Serial::parent_putc(int c) { - return Serial::_putc(c); + return RawSerial::putc(c); } int RTOS_Serial::getc() { @@ -117,31 +110,31 @@ } void RTOS_Serial::rx_isr(){ - rx_q.put((int *) _getc()); // returns immediately even if queue was full + rx_q.put((int *) RawSerial::getc()); // returns immediately even if queue was full } void RTOS_Serial::tx_isr(){ -#ifdef RTOS_SERIAL_TX_THREAD - tx_emitter_threadp->signal_set(0x1); -#else - osEvent evt; - evt = tx_q.get(); // BUG: This will wait forever in ISR! - if (evt.status == osEventMessage) { - *ledp = 1; - parent_putc(evt.value.v); - *ledp = 0; - } /*else { - std::printf("\r\nRTOS_Serial::tx_emitter() evt.status %d\n", evt.status); - }*/ -#endif + _tx_thread.signal_set(0x1); } -#ifdef RTOS_SERIAL_TX_THREAD -// tx_emitter is a class method + +void RTOS_Serial::threadStarter(void const *p) { + RTOS_Serial *instance = (RTOS_Serial*)p; + instance->_tx_thread.signal_set(0x01); // "prime the pump" of the tx-ready signals + instance->tx_emitter(instance); +} + void RTOS_Serial::tx_emitter(void const *argument){ RTOS_Serial *sp = (RTOS_Serial *) argument; osEvent evt; //osStatus status; + _tx_thread.signal_wait(START_THREAD); + for (int i=0; i<2; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5); + attach(this, &RTOS_Serial::rx_isr, RxIrq); + for (int i=0; i<3; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5); + attach(this, &RTOS_Serial::tx_isr, TxIrq); + for (int i=0; i<4; i++) { *ledp=1; wait(0.1); *ledp=0; wait(0.1); }; wait(0.5); + while(true){ evt = sp->tx_q.get(); if (evt.status == osEventMessage) { @@ -163,4 +156,3 @@ *(sp->ledp) = 0; } } -#endif