Mike Moore
/
RTOS_project_fork_01
embedded RTOS class project.
Fork of RTOS_project by
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 /*----------------------------------------------//------------------------------ 00002 student : m-moore 00003 email : gated.clock@gmail.com 00004 class : embedded RTOS 00005 directory : RTOS_project 00006 file : main.cpp 00007 date : september 19, 2013. 00008 ----copyright-----------------------------------//------------------------------ 00009 licensed for personal and academic use. 00010 commercial use of original code must be approved by the account-holder of 00011 gated.clock@gmail.com 00012 ----revision------------------------------------//------------------------------ 00013 this is the embedded RTOS class revision. 00014 changes made since the USB device class release: 00015 00016 1. a 'read all registers' feature has been added, which speeds up 00017 CPU execution, since the UI obtains all of the register states after 00018 each CPU clock. originally, each register was individually read. 00019 now, all registers are read at once, if so requested by the python code. 00020 00021 2. some 'if' statements were changed to 'switch' statements (neatening). 00022 00023 3. added watchdog timers for the three threads. this via a meta-watchdog thread. 00024 00025 4. added #defined-based option to either boot on error detection 00026 (such as malloc fail) or use error(); function. 00027 00028 5. the LCD is updated only if a display value is changed - reduced power 00029 usage a little & reduces potential 'blinkieness'. 00030 00031 6. BOOT notification on LCD. 00032 ----description---------------------------------//------------------------------ 00033 overview: 00034 program to provide round-trip communication between a python test-control 00035 program running on a pc host, and a device-under-test CPU implemented on 00036 an altera board. the pc-host communication is over USBSerial, and the 00037 altera communication is over SPI. 00038 00039 features: 00040 1. multi-threaded design, use of memory-pools to transfer data between threads. 00041 2. use of USBDevice library for communication with PC host. 00042 3. use of mmSPI_RTOS custom library for communication with FPGA. 00043 4. main thread provides USBSerial communication to/from host. 00044 5. SPI processing thread provides SPI communication to/from DUT. 00045 6. mmSPI_RTOS library generates non-overlapping SPI and CPU clocks. 00046 7. background diagnostic thread provides LCD & error updates. 00047 8. meta watchdog thread monitors itself & the other threads. 00048 00049 indicators: (led<3:0> = LED<1:4>) 00050 1. LCD provides running counts for SPI and CPU clock cycles. 00051 2. led0 indicates main thread processing. 00052 3. led1 indicates SPI thread processing. 00053 4. led2 indicates LCD thread processing. 00054 5. led3 indicates watchdog thread processing. 00055 00056 implementation: 00057 1. main.processIncomingSerial(): accept incoming serial data from host, 00058 and map it into tFromHost structures. 00059 2. SPIprocessingThread: take the incoming data structures instances, and 00060 feed their content into mmSPI_RTOS commands. 00061 3. mmSPI_RTOS object: given commands/data passed from caller, 00062 map them into SPI outgoing vectors and scan them into the FPGA. 00063 4. mmSPI_RTOS object: receive incoming SPI vectors from FPGA. 00064 make FPGA payload data available to caller. 00065 5. SPIprocessingThread: load tToHost structures with said FPGA payload data. 00066 6. main.processOutgoingSerial(): transfer tToHost structure data into a 00067 serial outgoing buffer, and block-transfer it to the host PC. 00068 00069 electrical: 00070 1. four pins (and ground) attached to the zigbee header, 00071 programmed as three SPI pins and the CPU clock. 00072 2. each of the four signals over twisted-pair. 00073 3. but some ribbon cable is used at the FPGA end. 00074 4. best if only the mbed application board USB cable is attached 00075 to the host; if the mbed CPU board USB cable is also attached to 00076 the host, then the python program may attempt to use the wrong USB 00077 connection. 00078 5. no particular power sequence is needed for this system to work. 00079 00080 timing critical path: serial processing. the python code needs 00081 a delay between serial access of 40mS conservatively. 00082 00083 testing: 00084 the python UI provides the main testing mechanism. 00085 00086 USB connect. 00087 00. press 'CONNECT' button in UI. verify connection info in shell. 00088 00089 CPU register w/r 00090 01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms. 00091 02. press 'REG WRITE' UI button. 00092 03. press 'REG READ' UI button. 00093 04. verify that the read data is correct. 00094 00095 CPU main-memory w/r 00096 05. type an address into 'mmADR' UI entry-form. 00097 06. type data into 'mmVAL' UI entry-form. 00098 07. press 'MM WRITE' UI button. 00099 08. type a different address into 'mmADR' UI entry-form. 00100 09. type different data into 'mmVAL' UI entry-form. 00101 10. press 'MM WRITE' UI button. 00102 11. type address from (05) into 'mmADR' UI entry-form. 00103 12. press 'MM READ' UI button. 00104 13. verify that the data from (06) is seen in the 'mmVAL' entry form. 00105 14. type address from (08) into 'mmADR' UI entry-form. 00106 15. press 'MM READ' UI button. 00107 16. verify that the data from (09) is seen in the 'mmVAL' entry form. 00108 00109 CPU main-memory full load/dump. 00110 17. press 'PROGRAM' in the UI. select a program file in the dialog-popup. 00111 18. watch the load process in the shell text. 00112 19. press 'DUMP in the UI. select a main-memory dump file in the diaglog-popup. 00113 20. watch the dump process in the shell text. 00114 00115 CPU step function. 00116 21. press 'STEP' in the UI repeatedly, watch the UI display the 00117 CPU register states as the current program is executed one CPU clock 00118 at a time. 00119 00120 CPU run function. 00121 22. press 'RUN' in the UI. watch the current program run at high speed. 00122 23. press 'SLOW' in the UI. watch the current program run at slow speed. 00123 24. press 'STOP' in the UI. the program will stop execution. 00124 00125 CPU test function. 00126 25. press 'TEST' in the UI. the program will load,execute,dump,compare. 00127 26. tail -f testlog.txt to see test status. 00128 27. the test will repeat until 'STOP TEST' is pressed. 00129 28. long test performed by allowing this mode to continue. 00130 00131 UI exit function. 00132 29. press 'EXIT' in the UI. it will exit. 00133 -----includes-----------------------------------//----------------------------*/ 00134 #include "mbed.h" // general. 00135 #include "USBSerial.h" // serial over USB. 00136 #include "C12832_lcd.h" // LCD display. 00137 #include "rtos.h" // RTOS. 00138 #include "mmSPI_RTOS.h" // SPI. 00139 #include "watchdog_RTOS.h" // watchdog. 00140 //---defines------------------------------------//------------------------------ 00141 #define LCD1 lcd.locate(0, 0); // LCD line 1. 00142 #define LCD2 lcd.locate(0,11); // LCD line 2. 00143 #define LCD3 lcd.locate(0,22); // LCD line 3. 00144 #define LCD3 lcd.locate(0,22); // LCD line 3. 00145 #define WATCHDOG_S 10 // watchdog timeout, in seconds. 00146 #define ERROR_BOOT 1 // 1 means boot rather than error(). 00147 #define SPI_BYTES 8 // number of SPI bytes. 00148 #define SPI_HZ 100000 // SPI frequency in Hz. 00149 #define SER_BYTES 18 // serial in/out # of bytes. 00150 #define SER_ALIGN 7 // '$' location in shift-register. 00151 #define THREAD_0_WAIT 8 // multitasking wait mS. 00152 #define THREAD_1_WAIT 2 // multitasking wait mS. 00153 #define THREAD_2_WAIT 128 // multitasking wait mS. 00154 #define THREAD_3_WAIT 128 // multitasking wait mS. 00155 #define HB_MODULO 64 // heartbeat slowdown factor. 00156 #define POOL_LEN 16 // memory pool dimension. 00157 #define HCMD_SETREG 1 // host command 'set register'. 00158 #define HCMD_GETREG 2 // host command 'get register'. 00159 #define HCMD_SETMM 3 // host command 'set main-memory.' 00160 #define HCMD_GETMM 4 // host command 'get main-memory.' 00161 #define HCMD_STEP 5 // host command 'step-CPU'. 00162 #define HCMD_SETIR 6 // host command 'set-IR'. 00163 #define HCMD_GETALLREG 7 // host command 'get-all-registers'. 00164 #define CPU_REG_0 0 // CPU register 0. 00165 #define CPU_REG_1 1 // CPU register 1. 00166 #define CPU_REG_2 2 // CPU register 2. 00167 #define CPU_REG_3 3 // CPU register 3. 00168 #define CPU_REG_PC 4 // CPU Program Counter. 00169 #define CPU_IR_H 5 // CPU IR high-byte. 00170 #define CPU_IR_L 6 // CPU IR low-byte. 00171 //--externals-----------------------------------//------------------------------ 00172 extern "C" void mbed_reset(); // processor reset. 00173 //--global_definitions--------------------------//------------------------------ 00174 struct tFromHost // command from host. 00175 { 00176 char cCommand; // command from host. 00177 char cRegisterID; // which CPU register. 00178 char cRegisterValue; // write this to CPU register. 00179 char cIRValueH; // write this to IR. 00180 char cIRValueL; // write this to IR. 00181 char cMMaddress; // access this MM address. 00182 char cMMdataH; // MM content high byte. 00183 char cMMdataL; // MM content low byte. 00184 }; 00185 MemoryPool<tFromHost, POOL_LEN> mPoolFromHost; 00186 Queue <tFromHost, POOL_LEN> qFromHost; 00187 00188 //---- 00189 00190 struct tToHost // reply to host. 00191 { 00192 char cCommand; // command executed. 00193 char cRegisterID; // which CPU register read. 00194 char cRegisterValue; // data from CPU register. 00195 char cMMaddress; // which MM address read. 00196 char cMMdataH; // MM content high byte. 00197 char cMMdataL; // MM content low byte. 00198 char cReg0; // data from R0. 00199 char cReg1; // data from R1. 00200 char cReg2; // data from R2. 00201 char cReg3; // data from R3. 00202 char cPC; // data from program counter. 00203 char cIRH; // high byte from instruction register. 00204 char cIRL; // low byte from instruction register. 00205 }; 00206 MemoryPool<tToHost, POOL_LEN> mPoolToHost; 00207 Queue <tToHost, POOL_LEN> qToHost; 00208 00209 Queue<int, POOL_LEN> queueWatchdogThread_0; // main thread watchdog notice. 00210 Queue<int, POOL_LEN> queueWatchdogThread_1; // thread 1 watchdog notice. 00211 Queue<int, POOL_LEN> queueWatchdogThread_2; // thread 2 watchdog notice. 00212 //--global_variables----------------------------//------------------------------ 00213 char gpcSerialFromHost[SER_BYTES]; // incoming serial buffer. 00214 char gpcSerialToHost [SER_BYTES]; // outgoing serial buffer. 00215 char gcNewCommand; // new command from host. 00216 int gdRoundTrip; // +1 from host, -1 to host. 00217 tToHost * gpToHost; // to-host structure. 00218 osEvent gqToHostEvent; // incoming message event. 00219 unsigned long gulSPIclkCount; // SPI clock count. 00220 unsigned long gulCPUclkCount; // CPU clock count. 00221 //--global_instances----------------------------//------------------------------ 00222 USBSerial serial; // serial over usb. 00223 C12832_LCD lcd; // LCD display. 00224 DigitalOut led0(LED4); // thread heartbeat. 00225 DigitalOut led1(LED3); // thread heartbeat. 00226 DigitalOut led2(LED2); // thread heartbeat. 00227 DigitalOut led3(LED1); // SPI reply underflow warning. 00228 //-------prototypes-----------------------------//------------------------------ 00229 int main(); // main. 00230 void processIncomingSerial(); // process incoming host data. 00231 void processOutgoingSerial(); // process outgoing data to host. 00232 void SPIprocessingThread(void const *args); // SPI-side processing. 00233 void diagnosticThread (void const *args); // LCD and LED notifications. 00234 void watchdogThread (void const *args); // overall watchdog. 00235 char ascii_nibble_to_binary(char cAscii); // ascii nibble -> binary. 00236 char binary_to_ascii_nibble(char cBinary); // binary -> ascii nibble. 00237 void clear_tFromHost(tFromHost *ptFromHost);// initialize structure. 00238 void clear_tToHost (tToHost *ptToHost); // initialize structure. 00239 //==============================================//============================== 00240 int main(void) // USBSerial processing thread. 00241 { 00242 int dHeartbeat; // heartbeat counter. 00243 int dLoop; // loop index. 00244 00245 gpToHost = NULL; // initialize global. 00246 gcNewCommand = 0; // initialize global. 00247 gdRoundTrip = 1024; // initialize global. 00248 gulSPIclkCount = 0; // initialize global. 00249 gulCPUclkCount = 0; // initialize global. 00250 led0 = 0; // initialize global. 00251 led1 = 0; // initialize global. 00252 led2 = 0; // initialize global. 00253 led3 = 0; // initialize global. 00254 dHeartbeat = 0; // initialize local. 00255 dLoop = 0; // initialize local. 00256 00257 // BOOT notification. 00258 lcd.cls(); LCD2; lcd.printf(" BOOT"); wait(1.0); 00259 00260 // initialize serial-in shift-register. 00261 for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0; 00262 00263 // thread-out SPI-side processing. 00264 Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL); 00265 00266 // thread-out diagnostics. 00267 Thread thread_2(diagnosticThread, NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); 00268 00269 // thread-out universal watchdog. 00270 Thread thread_3(watchdogThread, NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); 00271 00272 while(1) // main loop. 00273 { 00274 processIncomingSerial(); // process data in from host. 00275 processOutgoingSerial(); // process data out to host. 00276 00277 dHeartbeat++; // thread heartbeat. 00278 if (!(dHeartbeat % HB_MODULO)) led0 = !led0; 00279 queueWatchdogThread_0.put((int *) 0,1); // adds 1mS to wait. 00280 Thread::wait(THREAD_0_WAIT - 1); // multitasking. 00281 } // main loop. 00282 } // main. 00283 /*----------------------------------------------//----------------------------*/ 00284 /* 00285 the python program running on the host is sending/receiving ascii characters 00286 which represent command/data binary nibbles. the python program will send 00287 the '$' character for command-string alignment. this function reads-in the 00288 incoming serial stream when any serial data is available, into a shift-register, 00289 and breaks upon detection of the '$' alignment character for python 00290 command-processing. at that point the shift-register will look something like 00291 [0] [1] [2] [3] [4] [5] [6] [7] 00292 '1' '2' '3' '4' x x x '$' (means write 0x34 to CPU R2). 00293 00294 00295 command-host register-number interpretation: 00296 0 = CPU R0. 00297 1 = CPU R1. 00298 2 = CPU R2. 00299 3 = CPU R3. 00300 4 = CPU program-counter. 00301 5 = CPU instruction-register high-byte. 00302 6 = CPU instruction-register low-byte. 00303 00304 instruction-register write is specially implemented, 00305 instruction-register read is implemented as two standard register-reads. 00306 00307 host-command shift-register interpretation: 00308 00309 gpcSerialFromHost[0] = command. 00310 subsequent interpretation depends on the command. 00311 00312 ---- 00313 if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register): 00314 00315 gpcSerialFromHost[1] = register number (see above). 00316 gpcSerialFromHost[2] = register content, high nibble. 00317 gpcSerialFromHost[3] = register content, low nibble. 00318 gpcSerialFromHost[4] = not used. 00319 gpcSerialFromHost[5] = not used. 00320 gpcSerialFromHost[6] = not used. 00321 00322 ---- 00323 if command = HCMD_SETIR (write-CPU-instruction-register): 00324 00325 gpcSerialFromHost[1] = IR register number, implied anyway. 00326 gpcSerialFromHost[2] = IR write value high byte high nibble. 00327 gpcSerialFromHost[3] = IR write value high byte low nibble. 00328 gpcSerialFromHost[4] = IR write value low byte high nibble. 00329 gpcSerialFromHost[5] = IR write value low byte low nibble. 00330 gpcSerialFromHost[6] = not used. 00331 00332 ---- 00333 if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory): 00334 00335 gpcSerialFromHost[1] = MM address high nibble. 00336 gpcSerialFromHost[2] = MM address low nibble. 00337 gpcSerialFromHost[3] = MM content high byte high nibble. 00338 gpcSerialFromHost[4] = MM content high byte low nibble. 00339 gpcSerialFromHost[5] = MM content low byte high nibble. 00340 gpcSerialFromHost[6] = MM content low byte low nibble. 00341 00342 the above also applies to function 'processOutgoingSerial'. 00343 */ 00344 00345 void processIncomingSerial(void) // process incoming serial data. 00346 { 00347 int dLoop; // loop index. 00348 tFromHost * pFromHost; // from-host structure. 00349 00350 while(serial.available()) // while data from host is available. 00351 { 00352 // shift-in the serial stream. 00353 for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++) 00354 gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1]; 00355 gpcSerialFromHost[SER_BYTES - 1] = serial._getc(); 00356 00357 if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned. 00358 { 00359 gcNewCommand = 1; // new host command just recognised. 00360 break; // need to process aligned data. 00361 } // data from host is aligned. 00362 } // while data from host is available. 00363 00364 // even if more data awaits from the 00365 // incoming serial stream, we now need 00366 // to process the aligned data recognised 00367 // as a command from the host. 00368 00369 if (gcNewCommand) // execute once per new command. 00370 { 00371 pFromHost = mPoolFromHost.alloc(); // allocate next pool entry. 00372 if (!pFromHost) // failure detection. 00373 { 00374 if (ERROR_BOOT) mbed_reset(); else 00375 error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); 00376 } 00377 00378 clear_tFromHost(pFromHost); // initialize structure. 00379 00380 // copy-in host message. 00381 pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]); 00382 00383 //---- 00384 00385 switch(pFromHost->cCommand) // command dependency. 00386 { 00387 case HCMD_SETREG : // host command 'set register'. 00388 { 00389 pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); 00390 pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 00391 ascii_nibble_to_binary(gpcSerialFromHost[3]); 00392 break; 00393 } // host command 'set register'. 00394 00395 case HCMD_GETREG : // host command 'get register'. 00396 { 00397 pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); 00398 pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 00399 ascii_nibble_to_binary(gpcSerialFromHost[3]); 00400 gdRoundTrip++; // expected reply to host is pending. 00401 break; 00402 } // host command 'get register'. 00403 00404 case HCMD_SETMM : // host command 'set main-memory.' 00405 { 00406 pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + 00407 ascii_nibble_to_binary(gpcSerialFromHost[2]); 00408 pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + 00409 ascii_nibble_to_binary(gpcSerialFromHost[4]); 00410 pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + 00411 ascii_nibble_to_binary(gpcSerialFromHost[6]); 00412 break; 00413 } // host command 'set main-memory.' 00414 00415 case HCMD_GETMM : // host command 'get main-memory.' 00416 { 00417 pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + 00418 ascii_nibble_to_binary(gpcSerialFromHost[2]); 00419 pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + 00420 ascii_nibble_to_binary(gpcSerialFromHost[4]); 00421 pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + 00422 ascii_nibble_to_binary(gpcSerialFromHost[6]); 00423 00424 gdRoundTrip++; // expected reply to host is pending. 00425 break; 00426 } // host command 'get main-memory.' 00427 00428 case HCMD_STEP : // host command 'step-CPU'. 00429 { 00430 break; 00431 } // host command 'step-CPU'. 00432 00433 case HCMD_SETIR : // host command 'set-IR'. 00434 { 00435 pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 00436 ascii_nibble_to_binary(gpcSerialFromHost[3]); 00437 pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + 00438 ascii_nibble_to_binary(gpcSerialFromHost[5]); 00439 break; 00440 } // host command 'set-IR'. 00441 00442 case HCMD_GETALLREG : // host command 'get-all-registers'. 00443 { 00444 gdRoundTrip++; // expected reply to host is pending. 00445 break; 00446 } // host command 'get-all-registers'. 00447 00448 default : // default. 00449 { 00450 if (ERROR_BOOT) mbed_reset(); else 00451 error("\n\r processIncomingSerial : ERROR unrecognised command from host. \n\r"); 00452 break; 00453 } // default. 00454 } // command dependency. 00455 00456 //---- 00457 00458 qFromHost.put(pFromHost); // send out for processing. 00459 gcNewCommand = 0; // don't execute until next new command. 00460 } // execute once per new command. 00461 Thread::wait(THREAD_0_WAIT); // multitasking. 00462 } // processIncomingSerial 00463 /*----------------------------------------------//----------------------------*/ 00464 void processOutgoingSerial(void) // prepare/transmit data to host. 00465 { 00466 int dLoop; // loop index. 00467 00468 gqToHostEvent = qToHost.get(1); // check for reply back to host. 00469 00470 // if new reply to host: 00471 if (gqToHostEvent.status == osEventMessage) 00472 { 00473 // bring it in from the queue. 00474 gpToHost = (tToHost *) gqToHostEvent.value.p; 00475 if (!gpToHost) // failure detection. 00476 { 00477 if (ERROR_BOOT) mbed_reset(); else 00478 error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); 00479 } 00480 00481 // clear outgoing buffer. 00482 for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0; 00483 00484 switch(gpToHost->cCommand) // the from-host command was looped to here. 00485 { 00486 case HCMD_SETREG : // host command 'set register'. 00487 { 00488 break; 00489 } // host command 'set register'. 00490 00491 case HCMD_GETREG : // host command 'get register'. 00492 { 00493 gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); 00494 gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); 00495 gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); 00496 gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); 00497 gpcSerialToHost[4] = '\n'; // signals end of transfer. 00498 00499 // transmit to the host. 00500 serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); 00501 gdRoundTrip--; // expected reply sent to host. 00502 break; 00503 } // host command 'get register'. 00504 00505 case HCMD_SETMM : // host command 'set main-memory.' 00506 { 00507 break; 00508 } // host command 'set main-memory.' 00509 00510 case HCMD_GETMM : // host command 'get main-memory.' 00511 { 00512 gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); 00513 gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); 00514 gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); 00515 gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); 00516 gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); 00517 gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); 00518 gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); 00519 gpcSerialToHost[7] = '\n'; // signals end of transfer. 00520 00521 // transmit to the host. 00522 serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); 00523 gdRoundTrip--; // expected reply sent to host. 00524 break; 00525 } // host command 'get main-memory.' 00526 00527 case HCMD_STEP : // host command 'step-CPU'. 00528 { 00529 break; 00530 } // host command 'step-CPU'. 00531 00532 case HCMD_SETIR : // host command 'set-IR'. 00533 { 00534 break; 00535 } // host command 'set-IR'. 00536 00537 case HCMD_GETALLREG : // host command 'get-all-registers'. 00538 { 00539 gpcSerialToHost[ 0] = binary_to_ascii_nibble( gpToHost->cCommand); 00540 gpcSerialToHost[ 1] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 4) & 0x0F); 00541 gpcSerialToHost[ 2] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 0) & 0x0F); 00542 gpcSerialToHost[ 3] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 4) & 0x0F); 00543 gpcSerialToHost[ 4] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 0) & 0x0F); 00544 gpcSerialToHost[ 5] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 4) & 0x0F); 00545 gpcSerialToHost[ 6] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 0) & 0x0F); 00546 gpcSerialToHost[ 7] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 4) & 0x0F); 00547 gpcSerialToHost[ 8] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 0) & 0x0F); 00548 gpcSerialToHost[ 9] = binary_to_ascii_nibble(((gpToHost->cPC) >> 4) & 0x0F); 00549 gpcSerialToHost[10] = binary_to_ascii_nibble(((gpToHost->cPC) >> 0) & 0x0F); 00550 gpcSerialToHost[11] = binary_to_ascii_nibble(((gpToHost->cIRH) >> 4) & 0x0F); 00551 gpcSerialToHost[12] = binary_to_ascii_nibble(((gpToHost->cIRH) >> 0) & 0x0F); 00552 gpcSerialToHost[13] = binary_to_ascii_nibble(((gpToHost->cIRL) >> 4) & 0x0F); 00553 gpcSerialToHost[14] = binary_to_ascii_nibble(((gpToHost->cIRL) >> 0) & 0x0F); 00554 gpcSerialToHost[15] = '\n'; // signals end of transfer. 00555 00556 // transmit to the host. 00557 serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); 00558 gdRoundTrip--; // expected reply sent to host. 00559 break; 00560 } // host command 'get-all-registers'. 00561 00562 default : 00563 { 00564 if (ERROR_BOOT) mbed_reset(); else 00565 error("\n\r processOutgoingSerial : ERROR unrecognised command from host. \n\r"); 00566 break; 00567 } // default. 00568 } // switch(gpToHost->cCommand) 00569 00570 mPoolToHost.free(gpToHost); // done with this queue entry. 00571 gpToHost = NULL; // clear pointer. 00572 } // if new reply to host. 00573 } // processOutgoingSerial. 00574 /*----------------------------------------------//----------------------------*/ 00575 // the pcSendBuffer and pcReceiveBuffer arrays are not used by this function, 00576 // but they are declared by this function, and their pointers are passed 00577 // down to the mmSPI_RTOS library for its use of them. 00578 // note- the prefix 'pc' means 'pointer of type character', not 'personal computer'. 00579 00580 void SPIprocessingThread(void const *args) // process host-commands via SPI. 00581 { 00582 char pcSendBuffer [SPI_BYTES]; // SPI send buffer. 00583 char pcReceiveBuffer[SPI_BYTES]; // SPI receive buffer. 00584 char pcRegisters [SPI_BYTES]; // fetch-all-registers vector. 00585 int dHeartbeat; // heartbeat counter. 00586 int dMemoryRead; // read main-memory into this. 00587 int dLoop; // loop index. 00588 osEvent qFromHostEvent; // incoming message event. 00589 tFromHost * pFromHost; // message structure. 00590 tToHost * gpToHost; // message structure. 00591 mmSPI_RTOS * pSPI; // SPI. 00592 00593 pFromHost = NULL; // NULL pointers. 00594 gpToHost = NULL; 00595 pSPI = NULL; 00596 dHeartbeat = 0; // clear variables. 00597 dMemoryRead = 0; 00598 dLoop = 0; 00599 // clear SPI vectors. 00600 for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer [dLoop] = 0; 00601 for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0; 00602 00603 pSPI = new mmSPI_RTOS; // SPI allocation. 00604 if (!pSPI) // failure detection. 00605 { 00606 if (ERROR_BOOT) mbed_reset(); else 00607 error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); 00608 } 00609 00610 pSPI->setSendBuffer (pcSendBuffer); // set SPI send buffer. 00611 pSPI->setReceiveBuffer(pcReceiveBuffer); // set SPI receive buffer. 00612 pSPI->setNumberOfBytes(SPI_BYTES); // set SPI number of bytes. 00613 pSPI->setSPIfrequency (SPI_HZ); // set SPI clock frequency. 00614 00615 while(1) // thread loop. 00616 { 00617 qFromHostEvent = qFromHost.get(1); // check for incoming host command. 00618 00619 // if new host command: 00620 if (qFromHostEvent.status == osEventMessage) 00621 { 00622 // bring it in from the queue. 00623 pFromHost = (tFromHost *) qFromHostEvent.value.p; 00624 if (!pFromHost) // failure detection. 00625 { 00626 if (ERROR_BOOT) mbed_reset(); else 00627 error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); 00628 } 00629 00630 switch(pFromHost->cCommand) // host command decode. 00631 { 00632 case HCMD_SETREG : // set CPU register. 00633 { 00634 switch(pFromHost->cRegisterID) // which register to write to. 00635 { 00636 case CPU_REG_0 : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;} 00637 case CPU_REG_1 : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;} 00638 case CPU_REG_2 : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;} 00639 case CPU_REG_3 : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;} 00640 case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;} 00641 default : {break;} 00642 } // which register to write to. 00643 break; 00644 } // set CPU register. 00645 00646 case HCMD_SETIR: // set instruction register. 00647 { 00648 pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL); 00649 break; 00650 } // set instruction register. 00651 00652 case HCMD_GETREG : // get CPU register. 00653 { 00654 gpToHost = mPoolToHost.alloc(); // allocate next pool entry. 00655 if (!gpToHost) // failure detection. 00656 { 00657 if (ERROR_BOOT) mbed_reset(); else 00658 error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 00659 } 00660 00661 clear_tToHost(gpToHost); // initialize structure. 00662 00663 switch(pFromHost->cRegisterID) // which register to read from. 00664 { 00665 case CPU_REG_0 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;} 00666 case CPU_REG_1 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;} 00667 case CPU_REG_2 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;} 00668 case CPU_REG_3 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;} 00669 case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;} 00670 case CPU_IR_H : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H ); break;} 00671 case CPU_IR_L : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L ); break;} 00672 default : {break;} 00673 } // which register to read from. 00674 00675 // loop-back to host. 00676 gpToHost->cCommand = pFromHost->cCommand; 00677 gpToHost->cRegisterID = pFromHost->cRegisterID; 00678 00679 qToHost.put(gpToHost); // send up for processing. 00680 break; 00681 } // get CPU register. 00682 00683 case HCMD_GETALLREG : // get all CPU registers. 00684 { 00685 gpToHost = mPoolToHost.alloc(); // allocate next pool entry. 00686 if (!gpToHost) // failure detection. 00687 { 00688 if (ERROR_BOOT) mbed_reset(); else 00689 error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 00690 } 00691 00692 clear_tToHost(gpToHost); // initialize structure. 00693 00694 // tell SPI to return all reg content. 00695 pSPI->read_all_registers(pcRegisters); 00696 00697 gpToHost->cReg0 = pcRegisters[6]; // transfer to outgoing structure. 00698 gpToHost->cReg1 = pcRegisters[5]; 00699 gpToHost->cReg2 = pcRegisters[4]; 00700 gpToHost->cReg3 = pcRegisters[3]; 00701 gpToHost->cPC = pcRegisters[2]; 00702 gpToHost->cIRH = pcRegisters[1]; 00703 gpToHost->cIRL = pcRegisters[0]; 00704 00705 // loop-back to host. 00706 gpToHost->cCommand = pFromHost->cCommand; 00707 qToHost.put(gpToHost); // send up for processing. 00708 00709 break; 00710 } // get all CPU registers. 00711 00712 case HCMD_SETMM : // do main-memory write. 00713 { 00714 pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress); 00715 break; 00716 } // do main-memory write. 00717 00718 case HCMD_GETMM : // do main-memory read. 00719 { 00720 gpToHost = mPoolToHost.alloc(); // allocate next pool entry. 00721 if (!gpToHost) // failure detection. 00722 { 00723 if (ERROR_BOOT) mbed_reset(); else 00724 error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 00725 } 00726 00727 clear_tToHost(gpToHost); // initialize structure. 00728 00729 // read from CPU memory. 00730 dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); 00731 gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF; 00732 gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF; 00733 00734 // loop-back to host. 00735 gpToHost->cCommand = pFromHost->cCommand; 00736 gpToHost->cMMaddress = pFromHost->cMMaddress; 00737 00738 qToHost.put(gpToHost); // send up for processing. 00739 break; 00740 } // do main-memory read. 00741 00742 case HCMD_STEP : // step the CPU. 00743 { 00744 pSPI->step(); 00745 break; 00746 } // step the CPU. 00747 default : break; 00748 } // host command decode. 00749 mPoolFromHost.free(pFromHost); // done with this queue entry. 00750 pFromHost = NULL; // clear pointer. 00751 } // if new host command. 00752 00753 gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable. 00754 gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable. 00755 00756 // thread heartbeat. 00757 dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1; 00758 queueWatchdogThread_1.put((int *) 0,1); // adds 1mS to wait. 00759 Thread::wait(THREAD_1_WAIT - 1); // cooperative multitasking. 00760 } // thread loop. 00761 } // SPIprocessingThread. 00762 /*----------------------------------------------//----------------------------*/ 00763 void diagnosticThread(void const *args) // LCD notification & error check. 00764 { 00765 // track previous values. 00766 static unsigned long ulLastSPIclkCount = 1; 00767 static unsigned long ulLastCPUclkCount = 1; 00768 int dHeartbeat; // heartbeat counter. 00769 00770 dHeartbeat = 0; // initialize. 00771 00772 while(1) // thread loop. 00773 { 00774 // if message round trip 00775 // count not consistent. 00776 if (gdRoundTrip > 1025 || gdRoundTrip < 1024) 00777 { 00778 if (ERROR_BOOT) mbed_reset(); else 00779 error("\n\r diagnosticThread : ERROR serial reply underflow. \n\r"); 00780 } 00781 00782 // update LCD only if a display 00783 // value has changed. anti-blink, 00784 // save a bit of power. 00785 if (gulSPIclkCount != ulLastSPIclkCount || 00786 gulCPUclkCount != ulLastCPUclkCount ) 00787 { 00788 lcd.cls(); // clear LCD display. 00789 LCD1; // lcd line 1. 00790 lcd.printf(" RTOS CLASS PROJECT"); 00791 00792 LCD2; // lcd line 2. 00793 lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); 00794 00795 LCD3; // lcd line 3. 00796 lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); 00797 } 00798 00799 ulLastSPIclkCount = gulSPIclkCount; // pipeline. 00800 ulLastCPUclkCount = gulCPUclkCount; // pipeline. 00801 00802 dHeartbeat++; // thread heartbeat. 00803 if (!(dHeartbeat % HB_MODULO)) led2 = !led2; 00804 queueWatchdogThread_2.put((int *) 0,1); // adds 1mS to wait. 00805 Thread::wait(THREAD_2_WAIT - 1); // multitasking. 00806 } // thread loop. 00807 } // diagnosticThread. 00808 /*----------------------------------------------//----------------------------*/ 00809 // this is its own watchdog. 00810 00811 void watchdogThread(void const *args) // overall watchdog. 00812 { 00813 int dHeartbeat; // heartbeat counter. 00814 Watchdog_RTOS watchdog; // the one and only watchdog. 00815 00816 dHeartbeat = 0; // initialize. 00817 00818 watchdog.kick(WATCHDOG_S); // initialize watchdog. 00819 00820 while (1) // thread loop. 00821 { 00822 // all other threads report-in. 00823 // blocking wait on all of them. 00824 queueWatchdogThread_0.get(osWaitForever); 00825 queueWatchdogThread_1.get(osWaitForever); 00826 queueWatchdogThread_2.get(osWaitForever); 00827 00828 watchdog.kick(); // reset watchdog timer. 00829 00830 dHeartbeat++; // thread heartbeat. 00831 if (!(dHeartbeat % HB_MODULO)) led3 = !led3; 00832 Thread::wait(THREAD_3_WAIT); // multitasking. 00833 } // thread loop. 00834 } 00835 /*----------------------------------------------//----------------------------*/ 00836 char ascii_nibble_to_binary(char cAscii) // ascii nibble -> binary. 00837 { 00838 char cBinary; // converted value. 00839 00840 switch(cAscii) 00841 { 00842 case 'F' : {cBinary = 15; break;} 00843 case 'E' : {cBinary = 14; break;} 00844 case 'D' : {cBinary = 13; break;} 00845 case 'C' : {cBinary = 12; break;} 00846 case 'B' : {cBinary = 11; break;} 00847 case 'A' : {cBinary = 10; break;} 00848 case 'f' : {cBinary = 15; break;} 00849 case 'e' : {cBinary = 14; break;} 00850 case 'd' : {cBinary = 13; break;} 00851 case 'c' : {cBinary = 12; break;} 00852 case 'b' : {cBinary = 11; break;} 00853 case 'a' : {cBinary = 10; break;} 00854 case '9' : {cBinary = 9; break;} 00855 case '8' : {cBinary = 8; break;} 00856 case '7' : {cBinary = 7; break;} 00857 case '6' : {cBinary = 6; break;} 00858 case '5' : {cBinary = 5; break;} 00859 case '4' : {cBinary = 4; break;} 00860 case '3' : {cBinary = 3; break;} 00861 case '2' : {cBinary = 2; break;} 00862 case '1' : {cBinary = 1; break;} 00863 case '0' : {cBinary = 0; break;} 00864 default : {cBinary = 0; break;} 00865 } // switch(cAscii). 00866 return(cBinary); // return the binary. 00867 } // ascii_nibble_to_binary. 00868 /*----------------------------------------------//----------------------------*/ 00869 char binary_to_ascii_nibble(char cBinary) // binary -> ascii nibble. 00870 { 00871 char cAscii; // converted value. 00872 00873 switch(cBinary) 00874 { 00875 case 15 : {cAscii = 'F'; break;} 00876 case 14 : {cAscii = 'E'; break;} 00877 case 13 : {cAscii = 'D'; break;} 00878 case 12 : {cAscii = 'C'; break;} 00879 case 11 : {cAscii = 'B'; break;} 00880 case 10 : {cAscii = 'A'; break;} 00881 case 9 : {cAscii = '9'; break;} 00882 case 8 : {cAscii = '8'; break;} 00883 case 7 : {cAscii = '7'; break;} 00884 case 6 : {cAscii = '6'; break;} 00885 case 5 : {cAscii = '5'; break;} 00886 case 4 : {cAscii = '4'; break;} 00887 case 3 : {cAscii = '3'; break;} 00888 case 2 : {cAscii = '2'; break;} 00889 case 1 : {cAscii = '1'; break;} 00890 case 0 : {cAscii = '0'; break;} 00891 default : {cAscii = '0'; break;} 00892 } // switch(cBinary). 00893 return(cAscii); // return the binary. 00894 } // binary_to_ascii_nibble. 00895 /*----------------------------------------------//----------------------------*/ 00896 void clear_tFromHost(tFromHost * ptFromHost)// clear structure. 00897 { 00898 ptFromHost->cCommand = 0x00; 00899 ptFromHost->cRegisterID = 0x00; 00900 ptFromHost->cRegisterValue = 0x00; 00901 ptFromHost->cIRValueH = 0x00; 00902 ptFromHost->cIRValueL = 0x00; 00903 ptFromHost->cMMaddress = 0x00; 00904 ptFromHost->cMMdataH = 0x00; 00905 ptFromHost->cMMdataL = 0x00; 00906 } // clear_tFromHost. 00907 /*----------------------------------------------//----------------------------*/ 00908 void clear_tToHost(tToHost * ptToHost) // clear structure. 00909 { 00910 ptToHost->cCommand = 0x00; 00911 ptToHost->cRegisterID = 0x00; 00912 ptToHost->cRegisterValue = 0x00; 00913 ptToHost->cMMaddress = 0x00; 00914 ptToHost->cMMdataH = 0x00; 00915 ptToHost->cMMdataL = 0x00; 00916 ptToHost->cReg0 = 0x00; 00917 ptToHost->cReg1 = 0x00; 00918 ptToHost->cReg2 = 0x00; 00919 ptToHost->cReg3 = 0x00; 00920 ptToHost->cPC = 0x00; 00921 ptToHost->cIRH = 0x00; 00922 ptToHost->cIRL = 0x00; 00923 } // clear_tToHost. 00924 /*----------------------------------------------//----------------------------*/
Generated on Tue Jul 12 2022 20:17:29 by 1.7.2