Using State-Machines in Low-Power Embedded Systems - Part II

In the last part I've described a basic system design based on state machines, timers and queues. In this short update I extend the existing design with a radio transmitting the measured temperature to a central server. The updated hardware diagram looks as follows:

One new hardware signal is the /RTS line indicating readiness of the radio. The other one is an output signal to drive the radio into sleep mode and back into active mode.

The updated state machine works as follows. To keep the battery driven system running as long as possible the radio is in low-power mode most of the time. Only just before sending the µC wakes-up the radio in Step2a. The falling edge of the /RTS signal indicates the radio readiness which leads into Step2. In Step2 transmission takes place on interrupt basis (started by putchar()). During transmission /RTS is high. If transmission is over /RTS goes to low again. If this happens the radio is switched off again. In case transmission couldn’t completed the radio is switched off latest after 200ms. In Step3 we wait for 5s then the board signals the successful transmission with a short blink code (state BlinkGood). An then the cycle begins again. Output PORT1/Bit1 is used for debugging purposes. In low power mode just the LED blinks two times slowly to indicate low battery.

To feed in the /RTS signal into the state machine a new interrupt handler was added as shown below:

#pragma vector=PORT2_VECTOR __interrupt void Port_2(void) { if(fifoPut(&buf1, evFallingEdgeRTS)){ globalErrHandler(); // buffer full }else{ P2IFG &= ~RADIO_RTS; disableRtsIRQ(); // wake up main routine to process state machines __bic_SR_register_on_exit(LPM3_bits); } }

Listing 1: The falling edge event is put into the fifo queue. The state machine takes out event by event from that queue processing the events.

The main part of the UART code is the putchar() function and the transmit interrupt.

// Send a character via serial interface. If no transmission is running // the character is directly put into the tx register, otherwise enqueued. void putchar(uint8_t cByte) { TX_INT_DISABLE; // disable transmit interrupt (in IE2) if(fifoIsEmpty(&txbuf) && (!txrunning)){ // queue empty and no transmission running txrunning=true; TXBUF0 = cByte; // load tx register, inc index }else{ fifoPut(&txbuf, cByte); } TX_INT_ENABLE; // enable interrupt (in IE2) } // UART0 TX ISR. // The isr takes out the next char from the fifo. #pragma vector=USART0TX_VECTOR __interrupt void usart0_tx (void){ static uint8_t txchar; bool empty = fifoGet(&txbuf,&txchar); _EINT(); if(!empty){ TXBUF0 = txchar; }else{// buffer empty, nothing to do txrunning=false; } }

The updated state machine design was created with the built-in state machine editor of SinelaboreRT. The reason is simple: I wanted to use the development environment CCS from Texas Instruments on Linux. And Cadifra is only available on Windows. But this was no problem because every state machine can be automatically migrated to the internal editor. Those of you not knowing CCS should really take a look on it. It has some really cool features - e.g. the power measurement option to just name one.

Let me know if you are interested in the complete source code or need more explanation.

Have fun! Peter

~~DISCUSSION:closed|Leave your comments~~