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 Mike Moore

Files at this revision

API Documentation at this revision

Comitter:
gatedClock
Date:
Tue Sep 17 19:07:00 2013 +0000
Parent:
11:480f06885f0f
Child:
14:7a310276b8b9
Commit message:
updates for RTOS class project.

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mmPython/mmUI.txt Show annotated file Show diff for this revision Revisions of this file
mmPython/mmUSBserial.txt Show annotated file Show diff for this revision Revisions of this file
mmSPI.lib Show annotated file Show diff for this revision Revisions of this file
watchdog.lib Show annotated file Show diff for this revision Revisions of this file
--- 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.
--- a/mmPython/mmUI.txt	Sun Sep 01 20:36:16 2013 +0000
+++ b/mmPython/mmUI.txt	Tue Sep 17 19:07:00 2013 +0000
@@ -75,7 +75,7 @@
             self.__isRunning   = 0              # program execution not running.
             self.__testRunning = 0              # test mode not runing.
             self.__testIter    = 0              # test mode iteration count.
-            self.__sleepVal    = 0.04           # serial transceive sleep.
+            self.__sleepVal    = 0.04           # serial transceive sleep.  3 works.
 
             
             self.uiR0      (0, 1, 10)           # label/entry widgets (x, y, width)
@@ -294,58 +294,35 @@
           def selectRegReadButtonPressed(self): # REG READ button has been pressed.
             self.refreshUI()                    # ensure proper text formats.
 
+                                                # real all registers.
+            self.__iUSB.write(self.buildReadAllRegisterCommand())
+            messageVector =   self.__iUSB.read()
 
-                                                # read R0.
-            self.__iUSB.write(self.buildReadRegisterCommand("0"))
-            fetchTextR0 =     self.__iUSB.read()
-            hexTextR0   =     self.formatRegValPayload(fetchTextR0)
-            self.__R0Entry.delete(0,99)
+                                                # parse-out the register entries.
+            hexTextR0     = "0x" + messageVector[ 1: 3]
+            hexTextR1     = "0x" + messageVector[ 3: 5]
+            hexTextR2     = "0x" + messageVector[ 5: 7]
+            hexTextR3     = "0x" + messageVector[ 7: 9]
+            hexTextPC     = "0x" + messageVector[ 9:11]
+            hexTextIR     = "0x" + messageVector[11:15]
+
+
+            self.__R0Entry.delete(0,99)         # R0 to UI.
             self.__R0Entry.insert(0,hexTextR0)
 
-                                                # read R1.
-            self.__iUSB.write(self.buildReadRegisterCommand("1"))
-            fetchTextR1 =     self.__iUSB.read()
-            hexTextR1   =     self.formatRegValPayload(fetchTextR1)
-            self.__R1Entry.delete(0,99)
+            self.__R1Entry.delete(0,99)         # R1 to UI.
             self.__R1Entry.insert(0,hexTextR1)
 
-
-                                                # read R2.
-            self.__iUSB.write(self.buildReadRegisterCommand("2"))
-            fetchTextR2 =     self.__iUSB.read()
-            hexTextR2   =     self.formatRegValPayload(fetchTextR2)
-            self.__R2Entry.delete(0,99)
+            self.__R2Entry.delete(0,99)         # R2 to UI.
             self.__R2Entry.insert(0,hexTextR2)
 
-                                                # read R3.
-            self.__iUSB.write(self.buildReadRegisterCommand("3"))
-            fetchTextR3 =     self.__iUSB.read()
-            hexTextR3   =     self.formatRegValPayload(fetchTextR3)
-            self.__R3Entry.delete(0,99)
+            self.__R3Entry.delete(0,99)         # R3 to UI.
             self.__R3Entry.insert(0,hexTextR3)
 
-
-                                                # read Program Counter.
-            self.__iUSB.write(self.buildReadRegisterCommand("4"))
-            fetchTextPC =     self.__iUSB.read()
-            hexTextPC   =     self.formatRegValPayload(fetchTextPC)
-            self.__PCEntry.delete(0,99)
+            self.__PCEntry.delete(0,99)         # PC to UI.
             self.__PCEntry.insert(0,hexTextPC)
 
-                                                # read Instruction Register high.
-            self.__iUSB.write(self.buildReadRegisterCommand("5"))
-            fetchTextIRH =    self.__iUSB.read()
-            hexTextIRH   =    self.formatRegValPayload(fetchTextIRH)
-
-
-                                                # read Instruction Register low.
-            self.__iUSB.write(self.buildReadRegisterCommand("6"))
-            fetchTextIRL =    self.__iUSB.read()
-            hexTextIRL   =    self.formatRegValPayload(fetchTextIRL)
-            hexTextIR    = hexTextIRH + hexTextIRL[2:]
-
-
-            self.__IREntry.delete(0,99)         # 2-byte IR content to UI.
+            self.__IREntry.delete(0,99)         # IR to UI.
             self.__IREntry.insert(0,hexTextIR)
 
 #----
@@ -593,6 +570,15 @@
             commandText = commandText + "0000000000000"
             return(commandText)
 #-----------------------------------------------#-------------------------------
+                                                # build the command string for
+                                                # reading all CPU register values.
+          def buildReadAllRegisterCommand(self):
+
+            commandText = ""                    # build command for read register.
+            commandText = commandText + "7"     # command-code.
+            commandText = commandText + "00000000000000"
+            return(commandText)
+#-----------------------------------------------#-------------------------------
                                                 # build the command-string for
                                                 # writing a value to a CPU register.
           def buildWriteRegisterCommand(self,regNum,regVal):
@@ -738,3 +724,17 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- a/mmPython/mmUSBserial.txt	Sun Sep 01 20:36:16 2013 +0000
+++ b/mmPython/mmUSBserial.txt	Tue Sep 17 19:07:00 2013 +0000
@@ -17,7 +17,8 @@
 
             openSuccess = 1
             self.__serialPort = serial.Serial()
-            self.__serialPort.baudrate = 9600
+            self.__serialPort.baudrate = 115200 # was 9600
+            self.__serialPort.timeout  =    1   # one-second timeout.
 
             for portIndex in range(7, -1, -1):
               portString = "/dev/ttyACM" + "{}".format(portIndex)
@@ -33,19 +34,29 @@
 
             if (openSuccess): print("successfully opened port {}.").format(portString)
             else:             print("could not open any port.")
+
+            self.__SER_BYTES = 18               # same as mbed program's SER_BYTES.
 #-----------------------------------------------#-------------------------------  
           def __del__(self):                    # destructor.
             self.__serialPort.close()
             print "object destroyed."
 #-----------------------------------------------#-------------------------------
+#         the number of bytes written and read must both be SER_BYTES.
+#         the '$' must be in bit<7> of what's written.
+
           def write(self,toWrite):              # write a string.
             nowWrite = toWrite[:7]
-            nowWrite = nowWrite + "$"
+            nowWrite = nowWrite + "$"           # in <7>.
+            if (self.__SER_BYTES > 8):          # flush out with 0's.
+              for loopIndex in range (0, self.__SER_BYTES - 8):
+                nowWrite = nowWrite + "0"
+#           print("nowWrite {}").format(nowWrite)
             self.__serialPort.write(nowWrite)
             return(nowWrite)
 #-----------------------------------------------#-------------------------------
           def read(self):                       # read a string.
-            gotRead = self.__serialPort.read(8)
+            gotRead = self.__serialPort.read(self.__SER_BYTES)
+#           print("gotRead {}").format(gotRead)
             return(gotRead)
 #-----------------------------------------------#-------------------------------
 #===============================================#===============================
@@ -70,3 +81,14 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
--- a/mmSPI.lib	Sun Sep 01 20:36:16 2013 +0000
+++ b/mmSPI.lib	Tue Sep 17 19:07:00 2013 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/gatedClock/code/mmSPI/#6152c9709697
+http://mbed.org/users/gatedClock/code/mmSPI/#32cdc295f859
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/watchdog.lib	Tue Sep 17 19:07:00 2013 +0000
@@ -0,0 +1,1 @@
+watchdog#f27d373a8e28