Embedded RTOS class project. This project allows a Python/Tk program running on a PC host to monitor/control a test-CPU programmed into an altera development board.
Dependencies: C12832_lcd USBDevice mbed-rtos mbed mmSPI-2 watchdog
Fork of USB_device_project by
Diff: main.cpp
- Revision:
- 13:7e1688393abc
- Parent:
- 9:81726c95be74
diff -r 480f06885f0f -r 7e1688393abc main.cpp --- a/main.cpp Sun Sep 01 20:36:16 2013 +0000 +++ b/main.cpp Tue Sep 17 19:07:00 2013 +0000 @@ -1,14 +1,34 @@ /*----------------------------------------------//------------------------------ student : m-moore email : gated.clock@gmail.com - class : usb device drivers + class : embedded RTOS directory : USB_device_project file : main.cpp - date : september 3, 2013. + date : september 19, 2013. ----copyright-----------------------------------//------------------------------ licensed for personal and academic use. - commercial use must be approved by the account-holder of + commercial use of original code must be approved by the account-holder of gated.clock@gmail.com +----revision------------------------------------//------------------------------ + this is the embedded RTOS class revision. + changes made since the USB device class release: + + 1. a 'read all registers' feature has been added, which speeds up + CPU execution, since the UI obtains all of the register states after + each CPU clock. originally, each register was individually read. + now, all registers are read at once, if so requested by the python code. + + 2. some 'if' statements were changed to 'switch' statements (neatening). + + 3. added watchdog timers for the three threads. this via a meta-watchdog thread. + + 4. added #defined-based option to either boot on error detection + (such as malloc fail) or use error(); function. + + 5. the LCD is updated only if a display value is changed - reduced power + usage a little & reduces potential 'blinkieness'. + + 6. BOOT notification on LCD. ----description---------------------------------//------------------------------ overview: program to provide round-trip communication between a python test-control @@ -23,14 +43,15 @@ 4. main thread provides USBSerial communication to/from host. 5. SPI processing thread provides SPI communication to/from DUT. 6. mmSPI library generates non-overlapping SPI and CPU clocks. - 7. background diagnostic thread provides LCD & LED updates. + 7. background diagnostic thread provides LCD & error updates. + 8. meta watchdog thread monitors itself & the other threads. indicators: (led<3:0> = LED<1:4>) 1. LCD provides running counts for SPI and CPU clock cycles. - 2. led0 indicates main thread processing. - 3. led1 indicates SPI thread processing. - 4. led2 indicates LCD thread processing. - 5. led3 indicates reply-to-host underflow (should never turn on). + 2. led0 indicates main thread processing. + 3. led1 indicates SPI thread processing. + 4. led2 indicates LCD thread processing. + 5. led3 indicates watchdog thread processing. implementation: 1. main.processIncomingSerial(): accept incoming serial data from host, @@ -56,6 +77,8 @@ connection. 5. no particular power sequence is needed for this system to work. + timing critical path: serial processing. the python code needs + a delay between serial access of 40mS conservatively. testing: the python UI provides the main testing mechanism. @@ -113,18 +136,22 @@ #include "C12832_lcd.h" // LCD display. #include "rtos.h" // RTOS. #include "mmSPI.h" // SPI. + #include "watchdog.h" // watchdog. //---defines------------------------------------//------------------------------ #define LCD1 lcd.locate(0, 0); // LCD line 1. #define LCD2 lcd.locate(0,11); // LCD line 2. #define LCD3 lcd.locate(0,22); // LCD line 3. #define LCD3 lcd.locate(0,22); // LCD line 3. + #define WATCHDOG_S 10 // watchdog timeout, in seconds. + #define ERROR_BOOT 1 // 1 means boot rather than error(). #define SPI_BYTES 8 // number of SPI bytes. #define SPI_HZ 100000 // SPI frequency in Hz. - #define SER_BYTES 8 // serial in/out # of bytes. + #define SER_BYTES 18 // serial in/out # of bytes. #define SER_ALIGN 7 // '$' location in shift-register. #define THREAD_0_WAIT 8 // multitasking wait mS. #define THREAD_1_WAIT 2 // multitasking wait mS. #define THREAD_2_WAIT 128 // multitasking wait mS. + #define THREAD_3_WAIT 128 // multitasking wait mS. #define HB_MODULO 64 // heartbeat slowdown factor. #define POOL_LEN 16 // memory pool dimension. #define HCMD_SETREG 1 // host command 'set register'. @@ -133,6 +160,7 @@ #define HCMD_GETMM 4 // host command 'get main-memory.' #define HCMD_STEP 5 // host command 'step-CPU'. #define HCMD_SETIR 6 // host command 'set-IR'. + #define HCMD_GETALLREG 7 // host command 'get-all-registers'. #define CPU_REG_0 0 // CPU register 0. #define CPU_REG_1 1 // CPU register 1. #define CPU_REG_2 2 // CPU register 2. @@ -140,6 +168,8 @@ #define CPU_REG_PC 4 // CPU Program Counter. #define CPU_IR_H 5 // CPU IR high-byte. #define CPU_IR_L 6 // CPU IR low-byte. +//--externals-----------------------------------//------------------------------ + extern "C" void mbed_reset(); // processor reset. //--global_definitions--------------------------//------------------------------ struct tFromHost // command from host. { @@ -164,10 +194,21 @@ char cRegisterValue; // data from CPU register. char cMMaddress; // which MM address read. char cMMdataH; // MM content high byte. - char cMMdataL; // MM content low byte. + char cMMdataL; // MM content low byte. + char cReg0; // data from R0. + char cReg1; // data from R1. + char cReg2; // data from R2. + char cReg3; // data from R3. + char cPC; // data from program counter. + char cIRH; // high byte from instruction register. + char cIRL; // low byte from instruction register. }; MemoryPool<tToHost, POOL_LEN> mPoolToHost; Queue <tToHost, POOL_LEN> qToHost; + + Queue<int, POOL_LEN> queueWatchdogThread_0; // main thread watchdog notice. + Queue<int, POOL_LEN> queueWatchdogThread_1; // thread 1 watchdog notice. + Queue<int, POOL_LEN> queueWatchdogThread_2; // thread 2 watchdog notice. //--global_variables----------------------------//------------------------------ char gpcSerialFromHost[SER_BYTES]; // incoming serial buffer. char gpcSerialToHost [SER_BYTES]; // outgoing serial buffer. @@ -189,7 +230,8 @@ void processIncomingSerial(); // process incoming host data. void processOutgoingSerial(); // process outgoing data to host. void SPIprocessingThread(void const *args); // SPI-side processing. - void diagnosticThread (void const *args); // LCD and LED notifications. + void diagnosticThread (void const *args); // LCD and LED notifications. + void watchdogThread (void const *args); // overall watchdog. char ascii_nibble_to_binary(char cAscii); // ascii nibble -> binary. char binary_to_ascii_nibble(char cBinary); // binary -> ascii nibble. void clear_tFromHost(tFromHost *ptFromHost);// initialize structure. @@ -205,8 +247,15 @@ gdRoundTrip = 1024; // initialize global. gulSPIclkCount = 0; // initialize global. gulCPUclkCount = 0; // initialize global. + led0 = 0; // initialize global. + led1 = 0; // initialize global. + led2 = 0; // initialize global. + led3 = 0; // initialize global. dHeartbeat = 0; // initialize local. dLoop = 0; // initialize local. + + // BOOT notification. + lcd.cls(); LCD2; lcd.printf(" BOOT"); wait(1.0); // initialize serial-in shift-register. for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0; @@ -215,8 +264,11 @@ Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL); // thread-out diagnostics. - Thread thread_2(diagnosticThread,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); - + Thread thread_2(diagnosticThread, NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); + + // thread-out universal watchdog. + Thread thread_3(watchdogThread, NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); + while(1) // main loop. { processIncomingSerial(); // process data in from host. @@ -224,7 +276,8 @@ dHeartbeat++; // thread heartbeat. if (!(dHeartbeat % HB_MODULO)) led0 = !led0; - Thread::wait(THREAD_0_WAIT); // multitasking. + queueWatchdogThread_0.put((int *) 0,1); // adds 1mS to wait. + Thread::wait(THREAD_0_WAIT - 1); // multitasking. } // main loop. } // main. /*----------------------------------------------//----------------------------*/ @@ -316,43 +369,92 @@ if (gcNewCommand) // execute once per new command. { pFromHost = mPoolFromHost.alloc(); // allocate next pool entry. - if (!pFromHost) error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); + if (!pFromHost) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); + } + clear_tFromHost(pFromHost); // initialize structure. // copy-in host message. pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]); - - // host requests register access. - if (pFromHost->cCommand == HCMD_SETREG || pFromHost->cCommand == HCMD_GETREG) - { - pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); - pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + - ascii_nibble_to_binary(gpcSerialFromHost[3]); - } - - if (pFromHost->cCommand == HCMD_SETIR) // host requests IR write. +//---- + + switch(pFromHost->cCommand) // command dependency. { - pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + - ascii_nibble_to_binary(gpcSerialFromHost[3]); - pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + - ascii_nibble_to_binary(gpcSerialFromHost[5]); - } - + case HCMD_SETREG : // host command 'set register'. + { + pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); + pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[3]); + break; + } // host command 'set register'. - // host requests main-memory access. - if (pFromHost->cCommand == HCMD_SETMM || pFromHost->cCommand == HCMD_GETMM) - { - pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + - ascii_nibble_to_binary(gpcSerialFromHost[2]); - pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + - ascii_nibble_to_binary(gpcSerialFromHost[4]); - pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + - ascii_nibble_to_binary(gpcSerialFromHost[6]); - } // host requests main-memory access. + case HCMD_GETREG : // host command 'get register'. + { + pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); + pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[3]); + gdRoundTrip++; // expected reply to host is pending. + break; + } // host command 'get register'. + + case HCMD_SETMM : // host command 'set main-memory.' + { + pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[2]); + pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[4]); + pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[6]); + break; + } // host command 'set main-memory.' + + case HCMD_GETMM : // host command 'get main-memory.' + { + pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[2]); + pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[4]); + pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[6]); + + gdRoundTrip++; // expected reply to host is pending. + break; + } // host command 'get main-memory.' + + case HCMD_STEP : // host command 'step-CPU'. + { + break; + } // host command 'step-CPU'. + + case HCMD_SETIR : // host command 'set-IR'. + { + pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[3]); + pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + + ascii_nibble_to_binary(gpcSerialFromHost[5]); + break; + } // host command 'set-IR'. + + case HCMD_GETALLREG : // host command 'get-all-registers'. + { + gdRoundTrip++; // expected reply to host is pending. + break; + } // host command 'get-all-registers'. - if (pFromHost->cCommand == HCMD_GETREG || pFromHost->cCommand == HCMD_GETMM) - gdRoundTrip++; // expected reply to host is pending. + default : // default. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r processIncomingSerial : ERROR unrecognised command from host. \n\r"); + break; + } // default. + } // command dependency. + +//---- + qFromHost.put(pFromHost); // send out for processing. gcNewCommand = 0; // don't execute until next new command. } // execute once per new command. @@ -370,43 +472,101 @@ { // bring it in from the queue. gpToHost = (tToHost *) gqToHostEvent.value.p; - if (!gpToHost) error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); + if (!gpToHost) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); + } // clear outgoing buffer. for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0; - - // the commands from the host were - // looped-back into the to-host struct, - // make use of them here. - - if (gpToHost->cCommand == HCMD_GETREG) // reading from a register. + + switch(gpToHost->cCommand) // the from-host command was looped to here. { - gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); - gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); - gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); - gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); - gpcSerialToHost[4] = '\n'; // signals end of transfer. + case HCMD_SETREG : // host command 'set register'. + { + break; + } // host command 'set register'. + + case HCMD_GETREG : // host command 'get register'. + { + gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); + gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); + gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); + gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); + gpcSerialToHost[4] = '\n'; // signals end of transfer. + + // transmit to the host. + serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); + gdRoundTrip--; // expected reply sent to host. + break; + } // host command 'get register'. + + case HCMD_SETMM : // host command 'set main-memory.' + { + break; + } // host command 'set main-memory.' + + case HCMD_GETMM : // host command 'get main-memory.' + { + gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); + gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); + gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); + gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); + gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); + gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); + gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); + gpcSerialToHost[7] = '\n'; // signals end of transfer. // transmit to the host. - serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); - gdRoundTrip--; // expected reply sent to host. - } - - if (gpToHost->cCommand == HCMD_GETMM) // reading from main-memory. - { - gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); - gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); - gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); - gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); - gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); - gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); - gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); - gpcSerialToHost[7] = '\n'; // signals end of transfer. - + serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); + gdRoundTrip--; // expected reply sent to host. + break; + } // host command 'get main-memory.' + + case HCMD_STEP : // host command 'step-CPU'. + { + break; + } // host command 'step-CPU'. + + case HCMD_SETIR : // host command 'set-IR'. + { + break; + } // host command 'set-IR'. + + case HCMD_GETALLREG : // host command 'get-all-registers'. + { + gpcSerialToHost[ 0] = binary_to_ascii_nibble( gpToHost->cCommand); + gpcSerialToHost[ 1] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 4) & 0x0F); + gpcSerialToHost[ 2] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 0) & 0x0F); + gpcSerialToHost[ 3] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 4) & 0x0F); + gpcSerialToHost[ 4] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 0) & 0x0F); + gpcSerialToHost[ 5] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 4) & 0x0F); + gpcSerialToHost[ 6] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 0) & 0x0F); + gpcSerialToHost[ 7] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 4) & 0x0F); + gpcSerialToHost[ 8] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 0) & 0x0F); + gpcSerialToHost[ 9] = binary_to_ascii_nibble(((gpToHost->cPC) >> 4) & 0x0F); + gpcSerialToHost[10] = binary_to_ascii_nibble(((gpToHost->cPC) >> 0) & 0x0F); + gpcSerialToHost[11] = binary_to_ascii_nibble(((gpToHost->cIRH) >> 4) & 0x0F); + gpcSerialToHost[12] = binary_to_ascii_nibble(((gpToHost->cIRH) >> 0) & 0x0F); + gpcSerialToHost[13] = binary_to_ascii_nibble(((gpToHost->cIRL) >> 4) & 0x0F); + gpcSerialToHost[14] = binary_to_ascii_nibble(((gpToHost->cIRL) >> 0) & 0x0F); + gpcSerialToHost[15] = '\n'; // signals end of transfer. + // transmit to the host. - serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); - gdRoundTrip--; // expected reply sent to host. - } + serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); + gdRoundTrip--; // expected reply sent to host. + break; + } // host command 'get-all-registers'. + + default : + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r processOutgoingSerial : ERROR unrecognised command from host. \n\r"); + break; + } // default. + } // switch(gpToHost->cCommand) + mPoolToHost.free(gpToHost); // done with this queue entry. gpToHost = NULL; // clear pointer. } // if new reply to host. @@ -421,6 +581,7 @@ { char pcSendBuffer [SPI_BYTES]; // SPI send buffer. char pcReceiveBuffer[SPI_BYTES]; // SPI receive buffer. + char pcRegisters [SPI_BYTES]; // fetch-all-registers vector. int dHeartbeat; // heartbeat counter. int dMemoryRead; // read main-memory into this. int dLoop; // loop index. @@ -439,8 +600,12 @@ for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer [dLoop] = 0; for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0; - pSPI = new mmSPI; // SPI allocation. - if (!pSPI) error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); + pSPI = new mmSPI; // SPI allocation. + if (!pSPI) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); + } pSPI->setSendBuffer (pcSendBuffer); // set SPI send buffer. pSPI->setReceiveBuffer(pcReceiveBuffer); // set SPI receive buffer. @@ -456,7 +621,11 @@ { // bring it in from the queue. pFromHost = (tFromHost *) qFromHostEvent.value.p; - if (!pFromHost) error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); + if (!pFromHost) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); + } switch(pFromHost->cCommand) // host command decode. { @@ -483,7 +652,12 @@ case HCMD_GETREG : // get CPU register. { gpToHost = mPoolToHost.alloc(); // allocate next pool entry. - if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); + if (!gpToHost) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); + } + clear_tToHost(gpToHost); // initialize structure. switch(pFromHost->cRegisterID) // which register to read from. @@ -506,6 +680,35 @@ break; } // get CPU register. + case HCMD_GETALLREG : // get all CPU registers. + { + gpToHost = mPoolToHost.alloc(); // allocate next pool entry. + if (!gpToHost) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); + } + + clear_tToHost(gpToHost); // initialize structure. + + // tell SPI to return all reg content. + pSPI->read_all_registers(pcRegisters); + + gpToHost->cReg0 = pcRegisters[6]; // transfer to outgoing structure. + gpToHost->cReg1 = pcRegisters[5]; + gpToHost->cReg2 = pcRegisters[4]; + gpToHost->cReg3 = pcRegisters[3]; + gpToHost->cPC = pcRegisters[2]; + gpToHost->cIRH = pcRegisters[1]; + gpToHost->cIRL = pcRegisters[0]; + + // loop-back to host. + gpToHost->cCommand = pFromHost->cCommand; + qToHost.put(gpToHost); // send up for processing. + + break; + } // get all CPU registers. + case HCMD_SETMM : // do main-memory write. { pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress); @@ -514,8 +717,13 @@ case HCMD_GETMM : // do main-memory read. { - gpToHost = mPoolToHost.alloc(); // allocate next pool entry. - if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); + gpToHost = mPoolToHost.alloc(); // allocate next pool entry. + if (!gpToHost) // failure detection. + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); + } + clear_tToHost(gpToHost); // initialize structure. // read from CPU memory. @@ -547,39 +755,85 @@ // thread heartbeat. dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1; - Thread::wait(THREAD_1_WAIT); // cooperative multitasking. + queueWatchdogThread_1.put((int *) 0,1); // adds 1mS to wait. + Thread::wait(THREAD_1_WAIT - 1); // cooperative multitasking. } // thread loop. } // SPIprocessingThread. /*----------------------------------------------//----------------------------*/ - void diagnosticThread(void const *args) // LCD and LED notifications. + void diagnosticThread(void const *args) // LCD notification & error check. { - int dHeartbeat; // heartbeat counter. - + // track previous values. + static unsigned long ulLastSPIclkCount = 1; + static unsigned long ulLastCPUclkCount = 1; + int dHeartbeat; // heartbeat counter. + dHeartbeat = 0; // initialize. - led3 = 0; // initialize. - + while(1) // thread loop. { // if message round trip // count not consistent. - if (gdRoundTrip > 1025 || gdRoundTrip < 1024) led3 = 1; - - lcd.cls(); // clear LCD display. - LCD1; // lcd line 1. - lcd.printf(" USB DEV CLASS PROJECT"); + if (gdRoundTrip > 1025 || gdRoundTrip < 1024) + { + if (ERROR_BOOT) mbed_reset(); else + error("\n\r diagnosticThread : ERROR serial reply underflow. \n\r"); + } - LCD2; // lcd line 2. - lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); + // update LCD only if a display + // value has changed. anti-blink, + // save a bit of power. + if (gulSPIclkCount != ulLastSPIclkCount || + gulCPUclkCount != ulLastCPUclkCount ) + { + lcd.cls(); // clear LCD display. + LCD1; // lcd line 1. + lcd.printf(" RTOS CLASS PROJECT"); - LCD3; // lcd line 3. - lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); + LCD2; // lcd line 2. + lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); + + LCD3; // lcd line 3. + lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); + } + + ulLastSPIclkCount = gulSPIclkCount; // pipeline. + ulLastCPUclkCount = gulCPUclkCount; // pipeline. dHeartbeat++; // thread heartbeat. if (!(dHeartbeat % HB_MODULO)) led2 = !led2; - Thread::wait(THREAD_2_WAIT); // multitasking. + queueWatchdogThread_2.put((int *) 0,1); // adds 1mS to wait. + Thread::wait(THREAD_2_WAIT - 1); // multitasking. } // thread loop. } // diagnosticThread. /*----------------------------------------------//----------------------------*/ + // this is its own watchdog. + + void watchdogThread(void const *args) // overall watchdog. + { + int dHeartbeat; // heartbeat counter. + osEvent queueEvent; // queue event + Watchdog watchdog; // the one and only watchdog. + + dHeartbeat = 0; // initialize. + + watchdog.kick(WATCHDOG_S); // initialize watchdog. + + while (1) // thread loop. + { + // all other threads report-in. + // blocking wait on all of them. + queueEvent = queueWatchdogThread_0.get(osWaitForever); + queueEvent = queueWatchdogThread_1.get(osWaitForever); + queueEvent = queueWatchdogThread_2.get(osWaitForever); + + watchdog.kick(); // reset watchdog timer. + + dHeartbeat++; // thread heartbeat. + if (!(dHeartbeat % HB_MODULO)) led3 = !led3; + Thread::wait(THREAD_3_WAIT); // multitasking. + } // thread loop. + } +/*----------------------------------------------//----------------------------*/ char ascii_nibble_to_binary(char cAscii) // ascii nibble -> binary. { char cBinary; // converted value.