Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: C12832_lcd USBDevice mbed-rtos mbed mmSPI
main.cpp
00001 /*----------------------------------------------//------------------------------ 00002 student : m-moore 00003 email : gated.clock@gmail.com 00004 class : usb device drivers 00005 directory : USB_device_project 00006 file : main.cpp 00007 date : september 3, 2013. 00008 ----copyright-----------------------------------//------------------------------ 00009 licensed for personal and academic use. 00010 commercial use must be approved by the account-holder of 00011 gated.clock@gmail.com 00012 ----description---------------------------------//------------------------------ 00013 overview: 00014 program to provide round-trip communication between a python test-control 00015 program running on a pc host, and a device-under-test CPU implemented on 00016 an altera board. the pc-host communication is over USBSerial, and the 00017 altera communication is over SPI. 00018 00019 features: 00020 1. multi-threaded design, use of memory-pools to transfer data between threads. 00021 2. use of USBDevice library for communication with PC host. 00022 3. use of mmSPI custom library for communication with FPGA. 00023 4. main thread provides USBSerial communication to/from host. 00024 5. SPI processing thread provides SPI communication to/from DUT. 00025 6. mmSPI library generates non-overlapping SPI and CPU clocks. 00026 7. background diagnostic thread provides LCD & LED updates. 00027 00028 indicators: (led<3:0> = LED<1:4>) 00029 1. LCD provides running counts for SPI and CPU clock cycles. 00030 2. led0 indicates main thread processing. 00031 3. led1 indicates SPI thread processing. 00032 4. led2 indicates LCD thread processing. 00033 5. led3 indicates reply-to-host underflow (should never turn on). 00034 00035 implementation: 00036 1. main.processIncomingSerial(): accept incoming serial data from host, 00037 and map it into tFromHost structures. 00038 2. SPIprocessingThread: take the incoming data structures instances, and 00039 feed their content into mmSPI commands. 00040 3. mmSPI object: given commands/data passed from caller, 00041 map them into SPI outgoing vectors and scan them into the FPGA. 00042 4. mmSPI object: receive incoming SPI vectors from FPGA. 00043 make FPGA payload data available to caller. 00044 5. SPIprocessingThread: load tToHost structures with said FPGA payload data. 00045 6. main.processOutgoingSerial(): transfer tToHost structure data into a 00046 serial outgoing buffer, and block-transfer it to the host PC. 00047 00048 electrical: 00049 1. four pins (and ground) attached to the zigbee header, 00050 programmed as three SPI pins and the CPU clock. 00051 2. each of the four signals over twisted-pair. 00052 3. but some ribbon cable is used at the FPGA end. 00053 4. best if only the mbed application board USB cable is attached 00054 to the host; if the mbed CPU board USB cable is also attached to 00055 the host, then the python program may attempt to use the wrong USB 00056 connection. 00057 5. no particular power sequence is needed for this system to work. 00058 00059 00060 testing: 00061 the python UI provides the main testing mechanism. 00062 00063 USB connect. 00064 00. press 'CONNECT' button in UI. verify connection info in shell. 00065 00066 CPU register w/r 00067 01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms. 00068 02. press 'REG WRITE' UI button. 00069 03. press 'REG READ' UI button. 00070 04. verify that the read data is correct. 00071 00072 CPU main-memory w/r 00073 05. type an address into 'mmADR' UI entry-form. 00074 06. type data into 'mmVAL' UI entry-form. 00075 07. press 'MM WRITE' UI button. 00076 08. type a different address into 'mmADR' UI entry-form. 00077 09. type different data into 'mmVAL' UI entry-form. 00078 10. press 'MM WRITE' UI button. 00079 11. type address from (05) into 'mmADR' UI entry-form. 00080 12. press 'MM READ' UI button. 00081 13. verify that the data from (06) is seen in the 'mmVAL' entry form. 00082 14. type address from (08) into 'mmADR' UI entry-form. 00083 15. press 'MM READ' UI button. 00084 16. verify that the data from (09) is seen in the 'mmVAL' entry form. 00085 00086 CPU main-memory full load/dump. 00087 17. press 'PROGRAM' in the UI. select a program file in the dialog-popup. 00088 18. watch the load process in the shell text. 00089 19. press 'DUMP in the UI. select a main-memory dump file in the diaglog-popup. 00090 20. watch the dump process in the shell text. 00091 00092 CPU step function. 00093 21. press 'STEP' in the UI repeatedly, watch the UI display the 00094 CPU register states as the current program is executed one CPU clock 00095 at a time. 00096 00097 CPU run function. 00098 22. press 'RUN' in the UI. watch the current program run at high speed. 00099 23. press 'SLOW' in the UI. watch the current program run at slow speed. 00100 24. press 'STOP' in the UI. the program will stop execution. 00101 00102 CPU test function. 00103 25. press 'TEST' in the UI. the program will load,execute,dump,compare. 00104 26. tail -f testlog.txt to see test status. 00105 27. the test will repeat until 'STOP TEST' is pressed. 00106 28. long test performed by allowing this mode to continue. 00107 00108 UI exit function. 00109 29. press 'EXIT' in the UI. it will exit. 00110 -----includes-----------------------------------//----------------------------*/ 00111 #include "mbed.h" // general. 00112 #include "USBSerial.h" // serial over USB. 00113 #include "C12832_lcd.h" // LCD display. 00114 #include "rtos.h" // RTOS. 00115 #include "mmSPI.h" // SPI. 00116 //---defines------------------------------------//------------------------------ 00117 #define LCD1 lcd.locate(0, 0); // LCD line 1. 00118 #define LCD2 lcd.locate(0,11); // LCD line 2. 00119 #define LCD3 lcd.locate(0,22); // LCD line 3. 00120 #define LCD3 lcd.locate(0,22); // LCD line 3. 00121 #define SPI_BYTES 8 // number of SPI bytes. 00122 #define SPI_HZ 100000 // SPI frequency in Hz. 00123 #define SER_BYTES 8 // serial in/out # of bytes. 00124 #define SER_ALIGN 7 // '$' location in shift-register. 00125 #define THREAD_0_WAIT 8 // multitasking wait mS. 00126 #define THREAD_1_WAIT 2 // multitasking wait mS. 00127 #define THREAD_2_WAIT 128 // multitasking wait mS. 00128 #define HB_MODULO 64 // heartbeat slowdown factor. 00129 #define POOL_LEN 16 // memory pool dimension. 00130 #define HCMD_SETREG 1 // host command 'set register'. 00131 #define HCMD_GETREG 2 // host command 'get register'. 00132 #define HCMD_SETMM 3 // host command 'set main-memory.' 00133 #define HCMD_GETMM 4 // host command 'get main-memory.' 00134 #define HCMD_STEP 5 // host command 'step-CPU'. 00135 #define HCMD_SETIR 6 // host command 'set-IR'. 00136 #define CPU_REG_0 0 // CPU register 0. 00137 #define CPU_REG_1 1 // CPU register 1. 00138 #define CPU_REG_2 2 // CPU register 2. 00139 #define CPU_REG_3 3 // CPU register 3. 00140 #define CPU_REG_PC 4 // CPU Program Counter. 00141 #define CPU_IR_H 5 // CPU IR high-byte. 00142 #define CPU_IR_L 6 // CPU IR low-byte. 00143 //--global_definitions--------------------------//------------------------------ 00144 struct tFromHost // command from host. 00145 { 00146 char cCommand; // command from host. 00147 char cRegisterID; // which CPU register. 00148 char cRegisterValue; // write this to CPU register. 00149 char cIRValueH; // write this to IR. 00150 char cIRValueL; // write this to IR. 00151 char cMMaddress; // access this MM address. 00152 char cMMdataH; // MM content high byte. 00153 char cMMdataL; // MM content low byte. 00154 }; 00155 MemoryPool<tFromHost, POOL_LEN> mPoolFromHost; 00156 Queue <tFromHost, POOL_LEN> qFromHost; 00157 00158 //---- 00159 00160 struct tToHost // reply to host. 00161 { 00162 char cCommand; // command executed. 00163 char cRegisterID; // which CPU register read. 00164 char cRegisterValue; // data from CPU register. 00165 char cMMaddress; // which MM address read. 00166 char cMMdataH; // MM content high byte. 00167 char cMMdataL; // MM content low byte. 00168 }; 00169 MemoryPool<tToHost, POOL_LEN> mPoolToHost; 00170 Queue <tToHost, POOL_LEN> qToHost; 00171 //--global_variables----------------------------//------------------------------ 00172 char gpcSerialFromHost[SER_BYTES]; // incoming serial buffer. 00173 char gpcSerialToHost [SER_BYTES]; // outgoing serial buffer. 00174 char gcNewCommand; // new command from host. 00175 int gdRoundTrip; // +1 from host, -1 to host. 00176 tToHost * gpToHost; // to-host structure. 00177 osEvent gqToHostEvent; // incoming message event. 00178 unsigned long gulSPIclkCount; // SPI clock count. 00179 unsigned long gulCPUclkCount; // CPU clock count. 00180 //--global_instances----------------------------//------------------------------ 00181 USBSerial serial; // serial over usb. 00182 C12832_LCD lcd; // LCD display. 00183 DigitalOut led0(LED4); // thread heartbeat. 00184 DigitalOut led1(LED3); // thread heartbeat. 00185 DigitalOut led2(LED2); // thread heartbeat. 00186 DigitalOut led3(LED1); // SPI reply underflow warning. 00187 //-------prototypes-----------------------------//------------------------------ 00188 int main(); // main. 00189 void processIncomingSerial(); // process incoming host data. 00190 void processOutgoingSerial(); // process outgoing data to host. 00191 void SPIprocessingThread(void const *args); // SPI-side processing. 00192 void diagnosticThread (void const *args); // LCD and LED notifications. 00193 char ascii_nibble_to_binary(char cAscii); // ascii nibble -> binary. 00194 char binary_to_ascii_nibble(char cBinary); // binary -> ascii nibble. 00195 void clear_tFromHost(tFromHost *ptFromHost);// initialize structure. 00196 void clear_tToHost (tToHost *ptToHost); // initialize structure. 00197 //==============================================//============================== 00198 int main(void) // USBSerial processing thread. 00199 { 00200 int dHeartbeat; // heartbeat counter. 00201 int dLoop; // loop index. 00202 00203 gpToHost = NULL; // initialize global. 00204 gcNewCommand = 0; // initialize global. 00205 gdRoundTrip = 1024; // initialize global. 00206 gulSPIclkCount = 0; // initialize global. 00207 gulCPUclkCount = 0; // initialize global. 00208 dHeartbeat = 0; // initialize local. 00209 dLoop = 0; // initialize local. 00210 00211 // initialize serial-in shift-register. 00212 for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0; 00213 00214 // thread-out SPI-side processing. 00215 Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL); 00216 00217 // thread-out diagnostics. 00218 Thread thread_2(diagnosticThread,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); 00219 00220 while(1) // main loop. 00221 { 00222 processIncomingSerial(); // process data in from host. 00223 processOutgoingSerial(); // process data out to host. 00224 00225 dHeartbeat++; // thread heartbeat. 00226 if (!(dHeartbeat % HB_MODULO)) led0 = !led0; 00227 Thread::wait(THREAD_0_WAIT); // multitasking. 00228 } // main loop. 00229 } // main. 00230 /*----------------------------------------------//----------------------------*/ 00231 /* 00232 the python program running on the host is sending/receiving ascii characters 00233 which represent command/data binary nibbles. the python program will send 00234 the '$' character for command-string alignment. this function reads-in the 00235 incoming serial stream when any serial data is available, into a shift-register, 00236 and breaks upon detection of the '$' alignment character for python 00237 command-processing. at that point the shift-register will look something like 00238 [0] [1] [2] [3] [4] [5] [6] [7] 00239 '1' '2' '3' '4' x x x '$' (means write 0x34 to CPU R2). 00240 00241 00242 command-host register-number interpretation: 00243 0 = CPU R0. 00244 1 = CPU R1. 00245 2 = CPU R2. 00246 3 = CPU R3. 00247 4 = CPU program-counter. 00248 5 = CPU instruction-register high-byte. 00249 6 = CPU instruction-register low-byte. 00250 00251 instruction-register write is specially implemented, 00252 instruction-register read is implemented as two standard register-reads. 00253 00254 host-command shift-register interpretation: 00255 00256 gpcSerialFromHost[0] = command. 00257 subsequent interpretation depends on the command. 00258 00259 ---- 00260 if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register): 00261 00262 gpcSerialFromHost[1] = register number (see above). 00263 gpcSerialFromHost[2] = register content, high nibble. 00264 gpcSerialFromHost[3] = register content, low nibble. 00265 gpcSerialFromHost[4] = not used. 00266 gpcSerialFromHost[5] = not used. 00267 gpcSerialFromHost[6] = not used. 00268 00269 ---- 00270 if command = HCMD_SETIR (write-CPU-instruction-register): 00271 00272 gpcSerialFromHost[1] = IR register number, implied anyway. 00273 gpcSerialFromHost[2] = IR write value high byte high nibble. 00274 gpcSerialFromHost[3] = IR write value high byte low nibble. 00275 gpcSerialFromHost[4] = IR write value low byte high nibble. 00276 gpcSerialFromHost[5] = IR write value low byte low nibble. 00277 gpcSerialFromHost[6] = not used. 00278 00279 ---- 00280 if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory): 00281 00282 gpcSerialFromHost[1] = MM address high nibble. 00283 gpcSerialFromHost[2] = MM address low nibble. 00284 gpcSerialFromHost[3] = MM content high byte high nibble. 00285 gpcSerialFromHost[4] = MM content high byte low nibble. 00286 gpcSerialFromHost[5] = MM content low byte high nibble. 00287 gpcSerialFromHost[6] = MM content low byte low nibble. 00288 00289 the above also applies to function 'processOutgoingSerial'. 00290 */ 00291 00292 void processIncomingSerial(void) // process incoming serial data. 00293 { 00294 int dLoop; // loop index. 00295 tFromHost * pFromHost; // from-host structure. 00296 00297 while(serial.available()) // while data from host is available. 00298 { 00299 // shift-in the serial stream. 00300 for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++) 00301 gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1]; 00302 gpcSerialFromHost[SER_BYTES - 1] = serial._getc(); 00303 00304 if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned. 00305 { 00306 gcNewCommand = 1; // new host command just recognised. 00307 break; // need to process aligned data. 00308 } // data from host is aligned. 00309 } // while data from host is available. 00310 00311 // even if more data awaits from the 00312 // incoming serial stream, we now need 00313 // to process the aligned data recognised 00314 // as a command from the host. 00315 00316 if (gcNewCommand) // execute once per new command. 00317 { 00318 pFromHost = mPoolFromHost.alloc(); // allocate next pool entry. 00319 if (!pFromHost) error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); 00320 clear_tFromHost(pFromHost); // initialize structure. 00321 00322 // copy-in host message. 00323 pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]); 00324 00325 // host requests register access. 00326 if (pFromHost->cCommand == HCMD_SETREG || pFromHost->cCommand == HCMD_GETREG) 00327 { 00328 pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); 00329 pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 00330 ascii_nibble_to_binary(gpcSerialFromHost[3]); 00331 } 00332 00333 00334 if (pFromHost->cCommand == HCMD_SETIR) // host requests IR write. 00335 { 00336 pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 00337 ascii_nibble_to_binary(gpcSerialFromHost[3]); 00338 pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + 00339 ascii_nibble_to_binary(gpcSerialFromHost[5]); 00340 } 00341 00342 00343 // host requests main-memory access. 00344 if (pFromHost->cCommand == HCMD_SETMM || pFromHost->cCommand == HCMD_GETMM) 00345 { 00346 pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + 00347 ascii_nibble_to_binary(gpcSerialFromHost[2]); 00348 pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + 00349 ascii_nibble_to_binary(gpcSerialFromHost[4]); 00350 pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + 00351 ascii_nibble_to_binary(gpcSerialFromHost[6]); 00352 } // host requests main-memory access. 00353 00354 if (pFromHost->cCommand == HCMD_GETREG || pFromHost->cCommand == HCMD_GETMM) 00355 gdRoundTrip++; // expected reply to host is pending. 00356 qFromHost.put(pFromHost); // send out for processing. 00357 gcNewCommand = 0; // don't execute until next new command. 00358 } // execute once per new command. 00359 Thread::wait(THREAD_0_WAIT); // multitasking. 00360 } // processIncomingSerial 00361 /*----------------------------------------------//----------------------------*/ 00362 void processOutgoingSerial(void) // prepare/transmit data to host. 00363 { 00364 int dLoop; // loop index. 00365 00366 gqToHostEvent = qToHost.get(1); // check for reply back to host. 00367 00368 // if new reply to host: 00369 if (gqToHostEvent.status == osEventMessage) 00370 { 00371 // bring it in from the queue. 00372 gpToHost = (tToHost *) gqToHostEvent.value.p; 00373 if (!gpToHost) error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); 00374 00375 // clear outgoing buffer. 00376 for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0; 00377 00378 // the commands from the host were 00379 // looped-back into the to-host struct, 00380 // make use of them here. 00381 00382 if (gpToHost->cCommand == HCMD_GETREG) // reading from a register. 00383 { 00384 gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); 00385 gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); 00386 gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); 00387 gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); 00388 gpcSerialToHost[4] = '\n'; // signals end of transfer. 00389 00390 // transmit to the host. 00391 serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); 00392 gdRoundTrip--; // expected reply sent to host. 00393 } 00394 00395 if (gpToHost->cCommand == HCMD_GETMM) // reading from main-memory. 00396 { 00397 gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); 00398 gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); 00399 gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); 00400 gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); 00401 gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); 00402 gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); 00403 gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); 00404 gpcSerialToHost[7] = '\n'; // signals end of transfer. 00405 00406 // transmit to the host. 00407 serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); 00408 gdRoundTrip--; // expected reply sent to host. 00409 } 00410 mPoolToHost.free(gpToHost); // done with this queue entry. 00411 gpToHost = NULL; // clear pointer. 00412 } // if new reply to host. 00413 } // processOutgoingSerial. 00414 /*----------------------------------------------//----------------------------*/ 00415 // the pcSendBuffer and pcReceiveBuffer arrays are not used by this function, 00416 // but they are declared by this function, and their pointers are passed 00417 // down to the mmSPI library for its use of them. 00418 // note- the prefix 'pc' means 'pointer of type character', not 'personal computer'. 00419 00420 void SPIprocessingThread(void const *args) // process host-commands via SPI. 00421 { 00422 char pcSendBuffer [SPI_BYTES]; // SPI send buffer. 00423 char pcReceiveBuffer[SPI_BYTES]; // SPI receive buffer. 00424 int dHeartbeat; // heartbeat counter. 00425 int dMemoryRead; // read main-memory into this. 00426 int dLoop; // loop index. 00427 osEvent qFromHostEvent; // incoming message event. 00428 tFromHost * pFromHost; // message structure. 00429 tToHost * gpToHost; // message structure. 00430 mmSPI * pSPI; // SPI. 00431 00432 pFromHost = NULL; // NULL pointers. 00433 gpToHost = NULL; 00434 pSPI = NULL; 00435 dHeartbeat = 0; // clear variables. 00436 dMemoryRead = 0; 00437 dLoop = 0; 00438 // clear SPI vectors. 00439 for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer [dLoop] = 0; 00440 for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0; 00441 00442 pSPI = new mmSPI; // SPI allocation. 00443 if (!pSPI) error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); 00444 00445 pSPI->setSendBuffer (pcSendBuffer); // set SPI send buffer. 00446 pSPI->setReceiveBuffer(pcReceiveBuffer); // set SPI receive buffer. 00447 pSPI->setNumberOfBytes(SPI_BYTES); // set SPI number of bytes. 00448 pSPI->setSPIfrequency (SPI_HZ); // set SPI clock frequency. 00449 00450 while(1) // thread loop. 00451 { 00452 qFromHostEvent = qFromHost.get(1); // check for incoming host command. 00453 00454 // if new host command: 00455 if (qFromHostEvent.status == osEventMessage) 00456 { 00457 // bring it in from the queue. 00458 pFromHost = (tFromHost *) qFromHostEvent.value.p; 00459 if (!pFromHost) error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); 00460 00461 switch(pFromHost->cCommand) // host command decode. 00462 { 00463 case HCMD_SETREG : // set CPU register. 00464 { 00465 switch(pFromHost->cRegisterID) // which register to write to. 00466 { 00467 case CPU_REG_0 : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;} 00468 case CPU_REG_1 : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;} 00469 case CPU_REG_2 : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;} 00470 case CPU_REG_3 : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;} 00471 case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;} 00472 default : {break;} 00473 } // which register to write to. 00474 break; 00475 } // set CPU register. 00476 00477 case HCMD_SETIR: // set instruction register. 00478 { 00479 pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL); 00480 break; 00481 } // set instruction register. 00482 00483 case HCMD_GETREG : // get CPU register. 00484 { 00485 gpToHost = mPoolToHost.alloc(); // allocate next pool entry. 00486 if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 00487 clear_tToHost(gpToHost); // initialize structure. 00488 00489 switch(pFromHost->cRegisterID) // which register to read from. 00490 { 00491 case CPU_REG_0 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;} 00492 case CPU_REG_1 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;} 00493 case CPU_REG_2 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;} 00494 case CPU_REG_3 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;} 00495 case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;} 00496 case CPU_IR_H : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H ); break;} 00497 case CPU_IR_L : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L ); break;} 00498 default : {break;} 00499 } // which register to read from. 00500 00501 // loop-back to host. 00502 gpToHost->cCommand = pFromHost->cCommand; 00503 gpToHost->cRegisterID = pFromHost->cRegisterID; 00504 00505 qToHost.put(gpToHost); // send up for processing. 00506 break; 00507 } // get CPU register. 00508 00509 case HCMD_SETMM : // do main-memory write. 00510 { 00511 pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress); 00512 break; 00513 } // do main-memory write. 00514 00515 case HCMD_GETMM : // do main-memory read. 00516 { 00517 gpToHost = mPoolToHost.alloc(); // allocate next pool entry. 00518 if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 00519 clear_tToHost(gpToHost); // initialize structure. 00520 00521 // read from CPU memory. 00522 dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); 00523 gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF; 00524 gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF; 00525 00526 // loop-back to host. 00527 gpToHost->cCommand = pFromHost->cCommand; 00528 gpToHost->cMMaddress = pFromHost->cMMaddress; 00529 00530 qToHost.put(gpToHost); // send up for processing. 00531 break; 00532 } // do main-memory read. 00533 00534 case HCMD_STEP : // step the CPU. 00535 { 00536 pSPI->step(); 00537 break; 00538 } // step the CPU. 00539 default : break; 00540 } // host command decode. 00541 mPoolFromHost.free(pFromHost); // done with this queue entry. 00542 pFromHost = NULL; // clear pointer. 00543 } // if new host command. 00544 00545 gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable. 00546 gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable. 00547 00548 // thread heartbeat. 00549 dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1; 00550 Thread::wait(THREAD_1_WAIT); // cooperative multitasking. 00551 } // thread loop. 00552 } // SPIprocessingThread. 00553 /*----------------------------------------------//----------------------------*/ 00554 void diagnosticThread(void const *args) // LCD and LED notifications. 00555 { 00556 int dHeartbeat; // heartbeat counter. 00557 00558 dHeartbeat = 0; // initialize. 00559 led3 = 0; // initialize. 00560 00561 while(1) // thread loop. 00562 { 00563 // if message round trip 00564 // count not consistent. 00565 if (gdRoundTrip > 1025 || gdRoundTrip < 1024) led3 = 1; 00566 00567 lcd.cls(); // clear LCD display. 00568 LCD1; // lcd line 1. 00569 lcd.printf(" USB DEV CLASS PROJECT"); 00570 00571 LCD2; // lcd line 2. 00572 lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); 00573 00574 LCD3; // lcd line 3. 00575 lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); 00576 00577 dHeartbeat++; // thread heartbeat. 00578 if (!(dHeartbeat % HB_MODULO)) led2 = !led2; 00579 Thread::wait(THREAD_2_WAIT); // multitasking. 00580 } // thread loop. 00581 } // diagnosticThread. 00582 /*----------------------------------------------//----------------------------*/ 00583 char ascii_nibble_to_binary(char cAscii) // ascii nibble -> binary. 00584 { 00585 char cBinary; // converted value. 00586 00587 switch(cAscii) 00588 { 00589 case 'F' : {cBinary = 15; break;} 00590 case 'E' : {cBinary = 14; break;} 00591 case 'D' : {cBinary = 13; break;} 00592 case 'C' : {cBinary = 12; break;} 00593 case 'B' : {cBinary = 11; break;} 00594 case 'A' : {cBinary = 10; break;} 00595 case 'f' : {cBinary = 15; break;} 00596 case 'e' : {cBinary = 14; break;} 00597 case 'd' : {cBinary = 13; break;} 00598 case 'c' : {cBinary = 12; break;} 00599 case 'b' : {cBinary = 11; break;} 00600 case 'a' : {cBinary = 10; break;} 00601 case '9' : {cBinary = 9; break;} 00602 case '8' : {cBinary = 8; break;} 00603 case '7' : {cBinary = 7; break;} 00604 case '6' : {cBinary = 6; break;} 00605 case '5' : {cBinary = 5; break;} 00606 case '4' : {cBinary = 4; break;} 00607 case '3' : {cBinary = 3; break;} 00608 case '2' : {cBinary = 2; break;} 00609 case '1' : {cBinary = 1; break;} 00610 case '0' : {cBinary = 0; break;} 00611 default : {cBinary = 0; break;} 00612 } // switch(cAscii). 00613 return(cBinary); // return the binary. 00614 } // ascii_nibble_to_binary. 00615 /*----------------------------------------------//----------------------------*/ 00616 char binary_to_ascii_nibble(char cBinary) // binary -> ascii nibble. 00617 { 00618 char cAscii; // converted value. 00619 00620 switch(cBinary) 00621 { 00622 case 15 : {cAscii = 'F'; break;} 00623 case 14 : {cAscii = 'E'; break;} 00624 case 13 : {cAscii = 'D'; break;} 00625 case 12 : {cAscii = 'C'; break;} 00626 case 11 : {cAscii = 'B'; break;} 00627 case 10 : {cAscii = 'A'; break;} 00628 case 9 : {cAscii = '9'; break;} 00629 case 8 : {cAscii = '8'; break;} 00630 case 7 : {cAscii = '7'; break;} 00631 case 6 : {cAscii = '6'; break;} 00632 case 5 : {cAscii = '5'; break;} 00633 case 4 : {cAscii = '4'; break;} 00634 case 3 : {cAscii = '3'; break;} 00635 case 2 : {cAscii = '2'; break;} 00636 case 1 : {cAscii = '1'; break;} 00637 case 0 : {cAscii = '0'; break;} 00638 default : {cAscii = '0'; break;} 00639 } // switch(cBinary). 00640 return(cAscii); // return the binary. 00641 } // binary_to_ascii_nibble. 00642 /*----------------------------------------------//----------------------------*/ 00643 void clear_tFromHost(tFromHost * ptFromHost)// clear structure. 00644 { 00645 ptFromHost->cCommand = 0x00; 00646 ptFromHost->cRegisterID = 0x00; 00647 ptFromHost->cRegisterValue = 0x00; 00648 ptFromHost->cIRValueH = 0x00; 00649 ptFromHost->cIRValueL = 0x00; 00650 ptFromHost->cMMaddress = 0x00; 00651 ptFromHost->cMMdataH = 0x00; 00652 ptFromHost->cMMdataL = 0x00; 00653 } // clear_tFromHost. 00654 /*----------------------------------------------//----------------------------*/ 00655 void clear_tToHost(tToHost * ptToHost) // clear structure. 00656 { 00657 ptToHost->cCommand = 0x00; 00658 ptToHost->cRegisterID = 0x00; 00659 ptToHost->cRegisterValue = 0x00; 00660 ptToHost->cMMaddress = 0x00; 00661 ptToHost->cMMdataH = 0x00; 00662 ptToHost->cMMdataL = 0x00; 00663 } // clear_tToHost. 00664 /*----------------------------------------------//----------------------------*/
Generated on Sat Jul 16 2022 03:17:51 by
1.7.2