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
main.cpp@13:7e1688393abc, 2013-09-17 (annotated)
- Committer:
- gatedClock
- Date:
- Tue Sep 17 19:07:00 2013 +0000
- Revision:
- 13:7e1688393abc
- Parent:
- 9:81726c95be74
updates for RTOS class project.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
gatedClock | 2:08655e2bb776 | 1 | /*----------------------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 2 | student : m-moore |
gatedClock | 2:08655e2bb776 | 3 | email : gated.clock@gmail.com |
gatedClock | 13:7e1688393abc | 4 | class : embedded RTOS |
gatedClock | 2:08655e2bb776 | 5 | directory : USB_device_project |
gatedClock | 2:08655e2bb776 | 6 | file : main.cpp |
gatedClock | 13:7e1688393abc | 7 | date : september 19, 2013. |
gatedClock | 2:08655e2bb776 | 8 | ----copyright-----------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 9 | licensed for personal and academic use. |
gatedClock | 13:7e1688393abc | 10 | commercial use of original code must be approved by the account-holder of |
gatedClock | 2:08655e2bb776 | 11 | gated.clock@gmail.com |
gatedClock | 13:7e1688393abc | 12 | ----revision------------------------------------//------------------------------ |
gatedClock | 13:7e1688393abc | 13 | this is the embedded RTOS class revision. |
gatedClock | 13:7e1688393abc | 14 | changes made since the USB device class release: |
gatedClock | 13:7e1688393abc | 15 | |
gatedClock | 13:7e1688393abc | 16 | 1. a 'read all registers' feature has been added, which speeds up |
gatedClock | 13:7e1688393abc | 17 | CPU execution, since the UI obtains all of the register states after |
gatedClock | 13:7e1688393abc | 18 | each CPU clock. originally, each register was individually read. |
gatedClock | 13:7e1688393abc | 19 | now, all registers are read at once, if so requested by the python code. |
gatedClock | 13:7e1688393abc | 20 | |
gatedClock | 13:7e1688393abc | 21 | 2. some 'if' statements were changed to 'switch' statements (neatening). |
gatedClock | 13:7e1688393abc | 22 | |
gatedClock | 13:7e1688393abc | 23 | 3. added watchdog timers for the three threads. this via a meta-watchdog thread. |
gatedClock | 13:7e1688393abc | 24 | |
gatedClock | 13:7e1688393abc | 25 | 4. added #defined-based option to either boot on error detection |
gatedClock | 13:7e1688393abc | 26 | (such as malloc fail) or use error(); function. |
gatedClock | 13:7e1688393abc | 27 | |
gatedClock | 13:7e1688393abc | 28 | 5. the LCD is updated only if a display value is changed - reduced power |
gatedClock | 13:7e1688393abc | 29 | usage a little & reduces potential 'blinkieness'. |
gatedClock | 13:7e1688393abc | 30 | |
gatedClock | 13:7e1688393abc | 31 | 6. BOOT notification on LCD. |
gatedClock | 2:08655e2bb776 | 32 | ----description---------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 33 | overview: |
gatedClock | 2:08655e2bb776 | 34 | program to provide round-trip communication between a python test-control |
gatedClock | 2:08655e2bb776 | 35 | program running on a pc host, and a device-under-test CPU implemented on |
gatedClock | 2:08655e2bb776 | 36 | an altera board. the pc-host communication is over USBSerial, and the |
gatedClock | 2:08655e2bb776 | 37 | altera communication is over SPI. |
gatedClock | 2:08655e2bb776 | 38 | |
gatedClock | 2:08655e2bb776 | 39 | features: |
gatedClock | 2:08655e2bb776 | 40 | 1. multi-threaded design, use of memory-pools to transfer data between threads. |
gatedClock | 2:08655e2bb776 | 41 | 2. use of USBDevice library for communication with PC host. |
gatedClock | 2:08655e2bb776 | 42 | 3. use of mmSPI custom library for communication with FPGA. |
gatedClock | 2:08655e2bb776 | 43 | 4. main thread provides USBSerial communication to/from host. |
gatedClock | 2:08655e2bb776 | 44 | 5. SPI processing thread provides SPI communication to/from DUT. |
gatedClock | 2:08655e2bb776 | 45 | 6. mmSPI library generates non-overlapping SPI and CPU clocks. |
gatedClock | 13:7e1688393abc | 46 | 7. background diagnostic thread provides LCD & error updates. |
gatedClock | 13:7e1688393abc | 47 | 8. meta watchdog thread monitors itself & the other threads. |
gatedClock | 0:9a314675a67d | 48 | |
gatedClock | 2:08655e2bb776 | 49 | indicators: (led<3:0> = LED<1:4>) |
gatedClock | 2:08655e2bb776 | 50 | 1. LCD provides running counts for SPI and CPU clock cycles. |
gatedClock | 13:7e1688393abc | 51 | 2. led0 indicates main thread processing. |
gatedClock | 13:7e1688393abc | 52 | 3. led1 indicates SPI thread processing. |
gatedClock | 13:7e1688393abc | 53 | 4. led2 indicates LCD thread processing. |
gatedClock | 13:7e1688393abc | 54 | 5. led3 indicates watchdog thread processing. |
gatedClock | 2:08655e2bb776 | 55 | |
gatedClock | 2:08655e2bb776 | 56 | implementation: |
gatedClock | 2:08655e2bb776 | 57 | 1. main.processIncomingSerial(): accept incoming serial data from host, |
gatedClock | 2:08655e2bb776 | 58 | and map it into tFromHost structures. |
gatedClock | 2:08655e2bb776 | 59 | 2. SPIprocessingThread: take the incoming data structures instances, and |
gatedClock | 2:08655e2bb776 | 60 | feed their content into mmSPI commands. |
gatedClock | 2:08655e2bb776 | 61 | 3. mmSPI object: given commands/data passed from caller, |
gatedClock | 2:08655e2bb776 | 62 | map them into SPI outgoing vectors and scan them into the FPGA. |
gatedClock | 2:08655e2bb776 | 63 | 4. mmSPI object: receive incoming SPI vectors from FPGA. |
gatedClock | 2:08655e2bb776 | 64 | make FPGA payload data available to caller. |
gatedClock | 2:08655e2bb776 | 65 | 5. SPIprocessingThread: load tToHost structures with said FPGA payload data. |
gatedClock | 2:08655e2bb776 | 66 | 6. main.processOutgoingSerial(): transfer tToHost structure data into a |
gatedClock | 2:08655e2bb776 | 67 | serial outgoing buffer, and block-transfer it to the host PC. |
gatedClock | 2:08655e2bb776 | 68 | |
gatedClock | 2:08655e2bb776 | 69 | electrical: |
gatedClock | 2:08655e2bb776 | 70 | 1. four pins (and ground) attached to the zigbee header, |
gatedClock | 2:08655e2bb776 | 71 | programmed as three SPI pins and the CPU clock. |
gatedClock | 2:08655e2bb776 | 72 | 2. each of the four signals over twisted-pair. |
gatedClock | 2:08655e2bb776 | 73 | 3. but some ribbon cable is used at the FPGA end. |
gatedClock | 2:08655e2bb776 | 74 | 4. best if only the mbed application board USB cable is attached |
gatedClock | 2:08655e2bb776 | 75 | to the host; if the mbed CPU board USB cable is also attached to |
gatedClock | 2:08655e2bb776 | 76 | the host, then the python program may attempt to use the wrong USB |
gatedClock | 2:08655e2bb776 | 77 | connection. |
gatedClock | 2:08655e2bb776 | 78 | 5. no particular power sequence is needed for this system to work. |
gatedClock | 2:08655e2bb776 | 79 | |
gatedClock | 13:7e1688393abc | 80 | timing critical path: serial processing. the python code needs |
gatedClock | 13:7e1688393abc | 81 | a delay between serial access of 40mS conservatively. |
gatedClock | 2:08655e2bb776 | 82 | |
gatedClock | 2:08655e2bb776 | 83 | testing: |
gatedClock | 2:08655e2bb776 | 84 | the python UI provides the main testing mechanism. |
gatedClock | 2:08655e2bb776 | 85 | |
gatedClock | 2:08655e2bb776 | 86 | USB connect. |
gatedClock | 2:08655e2bb776 | 87 | 00. press 'CONNECT' button in UI. verify connection info in shell. |
gatedClock | 2:08655e2bb776 | 88 | |
gatedClock | 2:08655e2bb776 | 89 | CPU register w/r |
gatedClock | 2:08655e2bb776 | 90 | 01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms. |
gatedClock | 2:08655e2bb776 | 91 | 02. press 'REG WRITE' UI button. |
gatedClock | 2:08655e2bb776 | 92 | 03. press 'REG READ' UI button. |
gatedClock | 2:08655e2bb776 | 93 | 04. verify that the read data is correct. |
gatedClock | 2:08655e2bb776 | 94 | |
gatedClock | 2:08655e2bb776 | 95 | CPU main-memory w/r |
gatedClock | 2:08655e2bb776 | 96 | 05. type an address into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 97 | 06. type data into 'mmVAL' UI entry-form. |
gatedClock | 2:08655e2bb776 | 98 | 07. press 'MM WRITE' UI button. |
gatedClock | 2:08655e2bb776 | 99 | 08. type a different address into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 100 | 09. type different data into 'mmVAL' UI entry-form. |
gatedClock | 2:08655e2bb776 | 101 | 10. press 'MM WRITE' UI button. |
gatedClock | 2:08655e2bb776 | 102 | 11. type address from (05) into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 103 | 12. press 'MM READ' UI button. |
gatedClock | 2:08655e2bb776 | 104 | 13. verify that the data from (06) is seen in the 'mmVAL' entry form. |
gatedClock | 2:08655e2bb776 | 105 | 14. type address from (08) into 'mmADR' UI entry-form. |
gatedClock | 2:08655e2bb776 | 106 | 15. press 'MM READ' UI button. |
gatedClock | 2:08655e2bb776 | 107 | 16. verify that the data from (09) is seen in the 'mmVAL' entry form. |
gatedClock | 2:08655e2bb776 | 108 | |
gatedClock | 2:08655e2bb776 | 109 | CPU main-memory full load/dump. |
gatedClock | 2:08655e2bb776 | 110 | 17. press 'PROGRAM' in the UI. select a program file in the dialog-popup. |
gatedClock | 2:08655e2bb776 | 111 | 18. watch the load process in the shell text. |
gatedClock | 2:08655e2bb776 | 112 | 19. press 'DUMP in the UI. select a main-memory dump file in the diaglog-popup. |
gatedClock | 2:08655e2bb776 | 113 | 20. watch the dump process in the shell text. |
gatedClock | 2:08655e2bb776 | 114 | |
gatedClock | 2:08655e2bb776 | 115 | CPU step function. |
gatedClock | 2:08655e2bb776 | 116 | 21. press 'STEP' in the UI repeatedly, watch the UI display the |
gatedClock | 2:08655e2bb776 | 117 | CPU register states as the current program is executed one CPU clock |
gatedClock | 2:08655e2bb776 | 118 | at a time. |
gatedClock | 2:08655e2bb776 | 119 | |
gatedClock | 2:08655e2bb776 | 120 | CPU run function. |
gatedClock | 2:08655e2bb776 | 121 | 22. press 'RUN' in the UI. watch the current program run at high speed. |
gatedClock | 2:08655e2bb776 | 122 | 23. press 'SLOW' in the UI. watch the current program run at slow speed. |
gatedClock | 2:08655e2bb776 | 123 | 24. press 'STOP' in the UI. the program will stop execution. |
gatedClock | 2:08655e2bb776 | 124 | |
gatedClock | 2:08655e2bb776 | 125 | CPU test function. |
gatedClock | 2:08655e2bb776 | 126 | 25. press 'TEST' in the UI. the program will load,execute,dump,compare. |
gatedClock | 2:08655e2bb776 | 127 | 26. tail -f testlog.txt to see test status. |
gatedClock | 2:08655e2bb776 | 128 | 27. the test will repeat until 'STOP TEST' is pressed. |
gatedClock | 2:08655e2bb776 | 129 | 28. long test performed by allowing this mode to continue. |
gatedClock | 2:08655e2bb776 | 130 | |
gatedClock | 2:08655e2bb776 | 131 | UI exit function. |
gatedClock | 2:08655e2bb776 | 132 | 29. press 'EXIT' in the UI. it will exit. |
gatedClock | 2:08655e2bb776 | 133 | -----includes-----------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 134 | #include "mbed.h" // general. |
gatedClock | 2:08655e2bb776 | 135 | #include "USBSerial.h" // serial over USB. |
gatedClock | 2:08655e2bb776 | 136 | #include "C12832_lcd.h" // LCD display. |
gatedClock | 2:08655e2bb776 | 137 | #include "rtos.h" // RTOS. |
gatedClock | 2:08655e2bb776 | 138 | #include "mmSPI.h" // SPI. |
gatedClock | 13:7e1688393abc | 139 | #include "watchdog.h" // watchdog. |
gatedClock | 2:08655e2bb776 | 140 | //---defines------------------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 141 | #define LCD1 lcd.locate(0, 0); // LCD line 1. |
gatedClock | 2:08655e2bb776 | 142 | #define LCD2 lcd.locate(0,11); // LCD line 2. |
gatedClock | 2:08655e2bb776 | 143 | #define LCD3 lcd.locate(0,22); // LCD line 3. |
gatedClock | 2:08655e2bb776 | 144 | #define LCD3 lcd.locate(0,22); // LCD line 3. |
gatedClock | 13:7e1688393abc | 145 | #define WATCHDOG_S 10 // watchdog timeout, in seconds. |
gatedClock | 13:7e1688393abc | 146 | #define ERROR_BOOT 1 // 1 means boot rather than error(). |
gatedClock | 2:08655e2bb776 | 147 | #define SPI_BYTES 8 // number of SPI bytes. |
gatedClock | 2:08655e2bb776 | 148 | #define SPI_HZ 100000 // SPI frequency in Hz. |
gatedClock | 13:7e1688393abc | 149 | #define SER_BYTES 18 // serial in/out # of bytes. |
gatedClock | 2:08655e2bb776 | 150 | #define SER_ALIGN 7 // '$' location in shift-register. |
gatedClock | 2:08655e2bb776 | 151 | #define THREAD_0_WAIT 8 // multitasking wait mS. |
gatedClock | 2:08655e2bb776 | 152 | #define THREAD_1_WAIT 2 // multitasking wait mS. |
gatedClock | 2:08655e2bb776 | 153 | #define THREAD_2_WAIT 128 // multitasking wait mS. |
gatedClock | 13:7e1688393abc | 154 | #define THREAD_3_WAIT 128 // multitasking wait mS. |
gatedClock | 2:08655e2bb776 | 155 | #define HB_MODULO 64 // heartbeat slowdown factor. |
gatedClock | 2:08655e2bb776 | 156 | #define POOL_LEN 16 // memory pool dimension. |
gatedClock | 2:08655e2bb776 | 157 | #define HCMD_SETREG 1 // host command 'set register'. |
gatedClock | 2:08655e2bb776 | 158 | #define HCMD_GETREG 2 // host command 'get register'. |
gatedClock | 2:08655e2bb776 | 159 | #define HCMD_SETMM 3 // host command 'set main-memory.' |
gatedClock | 2:08655e2bb776 | 160 | #define HCMD_GETMM 4 // host command 'get main-memory.' |
gatedClock | 2:08655e2bb776 | 161 | #define HCMD_STEP 5 // host command 'step-CPU'. |
gatedClock | 2:08655e2bb776 | 162 | #define HCMD_SETIR 6 // host command 'set-IR'. |
gatedClock | 13:7e1688393abc | 163 | #define HCMD_GETALLREG 7 // host command 'get-all-registers'. |
gatedClock | 2:08655e2bb776 | 164 | #define CPU_REG_0 0 // CPU register 0. |
gatedClock | 2:08655e2bb776 | 165 | #define CPU_REG_1 1 // CPU register 1. |
gatedClock | 2:08655e2bb776 | 166 | #define CPU_REG_2 2 // CPU register 2. |
gatedClock | 2:08655e2bb776 | 167 | #define CPU_REG_3 3 // CPU register 3. |
gatedClock | 2:08655e2bb776 | 168 | #define CPU_REG_PC 4 // CPU Program Counter. |
gatedClock | 2:08655e2bb776 | 169 | #define CPU_IR_H 5 // CPU IR high-byte. |
gatedClock | 2:08655e2bb776 | 170 | #define CPU_IR_L 6 // CPU IR low-byte. |
gatedClock | 13:7e1688393abc | 171 | //--externals-----------------------------------//------------------------------ |
gatedClock | 13:7e1688393abc | 172 | extern "C" void mbed_reset(); // processor reset. |
gatedClock | 2:08655e2bb776 | 173 | //--global_definitions--------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 174 | struct tFromHost // command from host. |
gatedClock | 2:08655e2bb776 | 175 | { |
gatedClock | 2:08655e2bb776 | 176 | char cCommand; // command from host. |
gatedClock | 2:08655e2bb776 | 177 | char cRegisterID; // which CPU register. |
gatedClock | 2:08655e2bb776 | 178 | char cRegisterValue; // write this to CPU register. |
gatedClock | 2:08655e2bb776 | 179 | char cIRValueH; // write this to IR. |
gatedClock | 2:08655e2bb776 | 180 | char cIRValueL; // write this to IR. |
gatedClock | 2:08655e2bb776 | 181 | char cMMaddress; // access this MM address. |
gatedClock | 2:08655e2bb776 | 182 | char cMMdataH; // MM content high byte. |
gatedClock | 2:08655e2bb776 | 183 | char cMMdataL; // MM content low byte. |
gatedClock | 2:08655e2bb776 | 184 | }; |
gatedClock | 2:08655e2bb776 | 185 | MemoryPool<tFromHost, POOL_LEN> mPoolFromHost; |
gatedClock | 2:08655e2bb776 | 186 | Queue <tFromHost, POOL_LEN> qFromHost; |
gatedClock | 2:08655e2bb776 | 187 | |
gatedClock | 2:08655e2bb776 | 188 | //---- |
gatedClock | 2:08655e2bb776 | 189 | |
gatedClock | 2:08655e2bb776 | 190 | struct tToHost // reply to host. |
gatedClock | 2:08655e2bb776 | 191 | { |
gatedClock | 2:08655e2bb776 | 192 | char cCommand; // command executed. |
gatedClock | 2:08655e2bb776 | 193 | char cRegisterID; // which CPU register read. |
gatedClock | 2:08655e2bb776 | 194 | char cRegisterValue; // data from CPU register. |
gatedClock | 2:08655e2bb776 | 195 | char cMMaddress; // which MM address read. |
gatedClock | 2:08655e2bb776 | 196 | char cMMdataH; // MM content high byte. |
gatedClock | 13:7e1688393abc | 197 | char cMMdataL; // MM content low byte. |
gatedClock | 13:7e1688393abc | 198 | char cReg0; // data from R0. |
gatedClock | 13:7e1688393abc | 199 | char cReg1; // data from R1. |
gatedClock | 13:7e1688393abc | 200 | char cReg2; // data from R2. |
gatedClock | 13:7e1688393abc | 201 | char cReg3; // data from R3. |
gatedClock | 13:7e1688393abc | 202 | char cPC; // data from program counter. |
gatedClock | 13:7e1688393abc | 203 | char cIRH; // high byte from instruction register. |
gatedClock | 13:7e1688393abc | 204 | char cIRL; // low byte from instruction register. |
gatedClock | 2:08655e2bb776 | 205 | }; |
gatedClock | 2:08655e2bb776 | 206 | MemoryPool<tToHost, POOL_LEN> mPoolToHost; |
gatedClock | 2:08655e2bb776 | 207 | Queue <tToHost, POOL_LEN> qToHost; |
gatedClock | 13:7e1688393abc | 208 | |
gatedClock | 13:7e1688393abc | 209 | Queue<int, POOL_LEN> queueWatchdogThread_0; // main thread watchdog notice. |
gatedClock | 13:7e1688393abc | 210 | Queue<int, POOL_LEN> queueWatchdogThread_1; // thread 1 watchdog notice. |
gatedClock | 13:7e1688393abc | 211 | Queue<int, POOL_LEN> queueWatchdogThread_2; // thread 2 watchdog notice. |
gatedClock | 2:08655e2bb776 | 212 | //--global_variables----------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 213 | char gpcSerialFromHost[SER_BYTES]; // incoming serial buffer. |
gatedClock | 2:08655e2bb776 | 214 | char gpcSerialToHost [SER_BYTES]; // outgoing serial buffer. |
gatedClock | 2:08655e2bb776 | 215 | char gcNewCommand; // new command from host. |
gatedClock | 2:08655e2bb776 | 216 | int gdRoundTrip; // +1 from host, -1 to host. |
gatedClock | 2:08655e2bb776 | 217 | tToHost * gpToHost; // to-host structure. |
gatedClock | 2:08655e2bb776 | 218 | osEvent gqToHostEvent; // incoming message event. |
gatedClock | 2:08655e2bb776 | 219 | unsigned long gulSPIclkCount; // SPI clock count. |
gatedClock | 2:08655e2bb776 | 220 | unsigned long gulCPUclkCount; // CPU clock count. |
gatedClock | 2:08655e2bb776 | 221 | //--global_instances----------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 222 | USBSerial serial; // serial over usb. |
gatedClock | 2:08655e2bb776 | 223 | C12832_LCD lcd; // LCD display. |
gatedClock | 2:08655e2bb776 | 224 | DigitalOut led0(LED4); // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 225 | DigitalOut led1(LED3); // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 226 | DigitalOut led2(LED2); // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 227 | DigitalOut led3(LED1); // SPI reply underflow warning. |
gatedClock | 2:08655e2bb776 | 228 | //-------prototypes-----------------------------//------------------------------ |
gatedClock | 2:08655e2bb776 | 229 | int main(); // main. |
gatedClock | 2:08655e2bb776 | 230 | void processIncomingSerial(); // process incoming host data. |
gatedClock | 2:08655e2bb776 | 231 | void processOutgoingSerial(); // process outgoing data to host. |
gatedClock | 2:08655e2bb776 | 232 | void SPIprocessingThread(void const *args); // SPI-side processing. |
gatedClock | 13:7e1688393abc | 233 | void diagnosticThread (void const *args); // LCD and LED notifications. |
gatedClock | 13:7e1688393abc | 234 | void watchdogThread (void const *args); // overall watchdog. |
gatedClock | 2:08655e2bb776 | 235 | char ascii_nibble_to_binary(char cAscii); // ascii nibble -> binary. |
gatedClock | 2:08655e2bb776 | 236 | char binary_to_ascii_nibble(char cBinary); // binary -> ascii nibble. |
gatedClock | 2:08655e2bb776 | 237 | void clear_tFromHost(tFromHost *ptFromHost);// initialize structure. |
gatedClock | 2:08655e2bb776 | 238 | void clear_tToHost (tToHost *ptToHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 239 | //==============================================//============================== |
gatedClock | 2:08655e2bb776 | 240 | int main(void) // USBSerial processing thread. |
gatedClock | 2:08655e2bb776 | 241 | { |
gatedClock | 2:08655e2bb776 | 242 | int dHeartbeat; // heartbeat counter. |
gatedClock | 2:08655e2bb776 | 243 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 244 | |
gatedClock | 2:08655e2bb776 | 245 | gpToHost = NULL; // initialize global. |
gatedClock | 2:08655e2bb776 | 246 | gcNewCommand = 0; // initialize global. |
gatedClock | 2:08655e2bb776 | 247 | gdRoundTrip = 1024; // initialize global. |
gatedClock | 2:08655e2bb776 | 248 | gulSPIclkCount = 0; // initialize global. |
gatedClock | 2:08655e2bb776 | 249 | gulCPUclkCount = 0; // initialize global. |
gatedClock | 13:7e1688393abc | 250 | led0 = 0; // initialize global. |
gatedClock | 13:7e1688393abc | 251 | led1 = 0; // initialize global. |
gatedClock | 13:7e1688393abc | 252 | led2 = 0; // initialize global. |
gatedClock | 13:7e1688393abc | 253 | led3 = 0; // initialize global. |
gatedClock | 2:08655e2bb776 | 254 | dHeartbeat = 0; // initialize local. |
gatedClock | 2:08655e2bb776 | 255 | dLoop = 0; // initialize local. |
gatedClock | 13:7e1688393abc | 256 | |
gatedClock | 13:7e1688393abc | 257 | // BOOT notification. |
gatedClock | 13:7e1688393abc | 258 | lcd.cls(); LCD2; lcd.printf(" BOOT"); wait(1.0); |
gatedClock | 2:08655e2bb776 | 259 | |
gatedClock | 2:08655e2bb776 | 260 | // initialize serial-in shift-register. |
gatedClock | 2:08655e2bb776 | 261 | for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 262 | |
gatedClock | 2:08655e2bb776 | 263 | // thread-out SPI-side processing. |
gatedClock | 2:08655e2bb776 | 264 | Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL); |
gatedClock | 2:08655e2bb776 | 265 | |
gatedClock | 2:08655e2bb776 | 266 | // thread-out diagnostics. |
gatedClock | 13:7e1688393abc | 267 | Thread thread_2(diagnosticThread, NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); |
gatedClock | 13:7e1688393abc | 268 | |
gatedClock | 13:7e1688393abc | 269 | // thread-out universal watchdog. |
gatedClock | 13:7e1688393abc | 270 | Thread thread_3(watchdogThread, NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); |
gatedClock | 13:7e1688393abc | 271 | |
gatedClock | 2:08655e2bb776 | 272 | while(1) // main loop. |
gatedClock | 2:08655e2bb776 | 273 | { |
gatedClock | 2:08655e2bb776 | 274 | processIncomingSerial(); // process data in from host. |
gatedClock | 2:08655e2bb776 | 275 | processOutgoingSerial(); // process data out to host. |
gatedClock | 2:08655e2bb776 | 276 | |
gatedClock | 2:08655e2bb776 | 277 | dHeartbeat++; // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 278 | if (!(dHeartbeat % HB_MODULO)) led0 = !led0; |
gatedClock | 13:7e1688393abc | 279 | queueWatchdogThread_0.put((int *) 0,1); // adds 1mS to wait. |
gatedClock | 13:7e1688393abc | 280 | Thread::wait(THREAD_0_WAIT - 1); // multitasking. |
gatedClock | 2:08655e2bb776 | 281 | } // main loop. |
gatedClock | 2:08655e2bb776 | 282 | } // main. |
gatedClock | 2:08655e2bb776 | 283 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 284 | /* |
gatedClock | 2:08655e2bb776 | 285 | the python program running on the host is sending/receiving ascii characters |
gatedClock | 2:08655e2bb776 | 286 | which represent command/data binary nibbles. the python program will send |
gatedClock | 2:08655e2bb776 | 287 | the '$' character for command-string alignment. this function reads-in the |
gatedClock | 2:08655e2bb776 | 288 | incoming serial stream when any serial data is available, into a shift-register, |
gatedClock | 2:08655e2bb776 | 289 | and breaks upon detection of the '$' alignment character for python |
gatedClock | 2:08655e2bb776 | 290 | command-processing. at that point the shift-register will look something like |
gatedClock | 2:08655e2bb776 | 291 | [0] [1] [2] [3] [4] [5] [6] [7] |
gatedClock | 2:08655e2bb776 | 292 | '1' '2' '3' '4' x x x '$' (means write 0x34 to CPU R2). |
gatedClock | 2:08655e2bb776 | 293 | |
gatedClock | 2:08655e2bb776 | 294 | |
gatedClock | 2:08655e2bb776 | 295 | command-host register-number interpretation: |
gatedClock | 2:08655e2bb776 | 296 | 0 = CPU R0. |
gatedClock | 2:08655e2bb776 | 297 | 1 = CPU R1. |
gatedClock | 2:08655e2bb776 | 298 | 2 = CPU R2. |
gatedClock | 2:08655e2bb776 | 299 | 3 = CPU R3. |
gatedClock | 2:08655e2bb776 | 300 | 4 = CPU program-counter. |
gatedClock | 2:08655e2bb776 | 301 | 5 = CPU instruction-register high-byte. |
gatedClock | 2:08655e2bb776 | 302 | 6 = CPU instruction-register low-byte. |
gatedClock | 2:08655e2bb776 | 303 | |
gatedClock | 2:08655e2bb776 | 304 | instruction-register write is specially implemented, |
gatedClock | 2:08655e2bb776 | 305 | instruction-register read is implemented as two standard register-reads. |
gatedClock | 2:08655e2bb776 | 306 | |
gatedClock | 2:08655e2bb776 | 307 | host-command shift-register interpretation: |
gatedClock | 2:08655e2bb776 | 308 | |
gatedClock | 2:08655e2bb776 | 309 | gpcSerialFromHost[0] = command. |
gatedClock | 2:08655e2bb776 | 310 | subsequent interpretation depends on the command. |
gatedClock | 2:08655e2bb776 | 311 | |
gatedClock | 2:08655e2bb776 | 312 | ---- |
gatedClock | 2:08655e2bb776 | 313 | if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register): |
gatedClock | 2:08655e2bb776 | 314 | |
gatedClock | 2:08655e2bb776 | 315 | gpcSerialFromHost[1] = register number (see above). |
gatedClock | 2:08655e2bb776 | 316 | gpcSerialFromHost[2] = register content, high nibble. |
gatedClock | 2:08655e2bb776 | 317 | gpcSerialFromHost[3] = register content, low nibble. |
gatedClock | 2:08655e2bb776 | 318 | gpcSerialFromHost[4] = not used. |
gatedClock | 2:08655e2bb776 | 319 | gpcSerialFromHost[5] = not used. |
gatedClock | 2:08655e2bb776 | 320 | gpcSerialFromHost[6] = not used. |
gatedClock | 2:08655e2bb776 | 321 | |
gatedClock | 2:08655e2bb776 | 322 | ---- |
gatedClock | 2:08655e2bb776 | 323 | if command = HCMD_SETIR (write-CPU-instruction-register): |
gatedClock | 2:08655e2bb776 | 324 | |
gatedClock | 2:08655e2bb776 | 325 | gpcSerialFromHost[1] = IR register number, implied anyway. |
gatedClock | 2:08655e2bb776 | 326 | gpcSerialFromHost[2] = IR write value high byte high nibble. |
gatedClock | 2:08655e2bb776 | 327 | gpcSerialFromHost[3] = IR write value high byte low nibble. |
gatedClock | 2:08655e2bb776 | 328 | gpcSerialFromHost[4] = IR write value low byte high nibble. |
gatedClock | 2:08655e2bb776 | 329 | gpcSerialFromHost[5] = IR write value low byte low nibble. |
gatedClock | 2:08655e2bb776 | 330 | gpcSerialFromHost[6] = not used. |
gatedClock | 2:08655e2bb776 | 331 | |
gatedClock | 2:08655e2bb776 | 332 | ---- |
gatedClock | 2:08655e2bb776 | 333 | if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory): |
gatedClock | 2:08655e2bb776 | 334 | |
gatedClock | 2:08655e2bb776 | 335 | gpcSerialFromHost[1] = MM address high nibble. |
gatedClock | 2:08655e2bb776 | 336 | gpcSerialFromHost[2] = MM address low nibble. |
gatedClock | 2:08655e2bb776 | 337 | gpcSerialFromHost[3] = MM content high byte high nibble. |
gatedClock | 2:08655e2bb776 | 338 | gpcSerialFromHost[4] = MM content high byte low nibble. |
gatedClock | 2:08655e2bb776 | 339 | gpcSerialFromHost[5] = MM content low byte high nibble. |
gatedClock | 2:08655e2bb776 | 340 | gpcSerialFromHost[6] = MM content low byte low nibble. |
gatedClock | 2:08655e2bb776 | 341 | |
gatedClock | 2:08655e2bb776 | 342 | the above also applies to function 'processOutgoingSerial'. |
gatedClock | 2:08655e2bb776 | 343 | */ |
gatedClock | 0:9a314675a67d | 344 | |
gatedClock | 2:08655e2bb776 | 345 | void processIncomingSerial(void) // process incoming serial data. |
gatedClock | 2:08655e2bb776 | 346 | { |
gatedClock | 2:08655e2bb776 | 347 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 348 | tFromHost * pFromHost; // from-host structure. |
gatedClock | 2:08655e2bb776 | 349 | |
gatedClock | 2:08655e2bb776 | 350 | while(serial.available()) // while data from host is available. |
gatedClock | 2:08655e2bb776 | 351 | { |
gatedClock | 2:08655e2bb776 | 352 | // shift-in the serial stream. |
gatedClock | 2:08655e2bb776 | 353 | for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++) |
gatedClock | 2:08655e2bb776 | 354 | gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1]; |
gatedClock | 2:08655e2bb776 | 355 | gpcSerialFromHost[SER_BYTES - 1] = serial._getc(); |
gatedClock | 2:08655e2bb776 | 356 | |
gatedClock | 2:08655e2bb776 | 357 | if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned. |
gatedClock | 2:08655e2bb776 | 358 | { |
gatedClock | 2:08655e2bb776 | 359 | gcNewCommand = 1; // new host command just recognised. |
gatedClock | 2:08655e2bb776 | 360 | break; // need to process aligned data. |
gatedClock | 2:08655e2bb776 | 361 | } // data from host is aligned. |
gatedClock | 2:08655e2bb776 | 362 | } // while data from host is available. |
gatedClock | 2:08655e2bb776 | 363 | |
gatedClock | 2:08655e2bb776 | 364 | // even if more data awaits from the |
gatedClock | 2:08655e2bb776 | 365 | // incoming serial stream, we now need |
gatedClock | 2:08655e2bb776 | 366 | // to process the aligned data recognised |
gatedClock | 2:08655e2bb776 | 367 | // as a command from the host. |
gatedClock | 2:08655e2bb776 | 368 | |
gatedClock | 2:08655e2bb776 | 369 | if (gcNewCommand) // execute once per new command. |
gatedClock | 2:08655e2bb776 | 370 | { |
gatedClock | 2:08655e2bb776 | 371 | pFromHost = mPoolFromHost.alloc(); // allocate next pool entry. |
gatedClock | 13:7e1688393abc | 372 | if (!pFromHost) // failure detection. |
gatedClock | 13:7e1688393abc | 373 | { |
gatedClock | 13:7e1688393abc | 374 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 375 | error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); |
gatedClock | 13:7e1688393abc | 376 | } |
gatedClock | 13:7e1688393abc | 377 | |
gatedClock | 2:08655e2bb776 | 378 | clear_tFromHost(pFromHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 379 | |
gatedClock | 2:08655e2bb776 | 380 | // copy-in host message. |
gatedClock | 2:08655e2bb776 | 381 | pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]); |
gatedClock | 2:08655e2bb776 | 382 | |
gatedClock | 13:7e1688393abc | 383 | //---- |
gatedClock | 13:7e1688393abc | 384 | |
gatedClock | 13:7e1688393abc | 385 | switch(pFromHost->cCommand) // command dependency. |
gatedClock | 2:08655e2bb776 | 386 | { |
gatedClock | 13:7e1688393abc | 387 | case HCMD_SETREG : // host command 'set register'. |
gatedClock | 13:7e1688393abc | 388 | { |
gatedClock | 13:7e1688393abc | 389 | pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); |
gatedClock | 13:7e1688393abc | 390 | pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + |
gatedClock | 13:7e1688393abc | 391 | ascii_nibble_to_binary(gpcSerialFromHost[3]); |
gatedClock | 13:7e1688393abc | 392 | break; |
gatedClock | 13:7e1688393abc | 393 | } // host command 'set register'. |
gatedClock | 2:08655e2bb776 | 394 | |
gatedClock | 13:7e1688393abc | 395 | case HCMD_GETREG : // host command 'get register'. |
gatedClock | 13:7e1688393abc | 396 | { |
gatedClock | 13:7e1688393abc | 397 | pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); |
gatedClock | 13:7e1688393abc | 398 | pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + |
gatedClock | 13:7e1688393abc | 399 | ascii_nibble_to_binary(gpcSerialFromHost[3]); |
gatedClock | 13:7e1688393abc | 400 | gdRoundTrip++; // expected reply to host is pending. |
gatedClock | 13:7e1688393abc | 401 | break; |
gatedClock | 13:7e1688393abc | 402 | } // host command 'get register'. |
gatedClock | 13:7e1688393abc | 403 | |
gatedClock | 13:7e1688393abc | 404 | case HCMD_SETMM : // host command 'set main-memory.' |
gatedClock | 13:7e1688393abc | 405 | { |
gatedClock | 13:7e1688393abc | 406 | pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + |
gatedClock | 13:7e1688393abc | 407 | ascii_nibble_to_binary(gpcSerialFromHost[2]); |
gatedClock | 13:7e1688393abc | 408 | pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + |
gatedClock | 13:7e1688393abc | 409 | ascii_nibble_to_binary(gpcSerialFromHost[4]); |
gatedClock | 13:7e1688393abc | 410 | pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + |
gatedClock | 13:7e1688393abc | 411 | ascii_nibble_to_binary(gpcSerialFromHost[6]); |
gatedClock | 13:7e1688393abc | 412 | break; |
gatedClock | 13:7e1688393abc | 413 | } // host command 'set main-memory.' |
gatedClock | 13:7e1688393abc | 414 | |
gatedClock | 13:7e1688393abc | 415 | case HCMD_GETMM : // host command 'get main-memory.' |
gatedClock | 13:7e1688393abc | 416 | { |
gatedClock | 13:7e1688393abc | 417 | pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + |
gatedClock | 13:7e1688393abc | 418 | ascii_nibble_to_binary(gpcSerialFromHost[2]); |
gatedClock | 13:7e1688393abc | 419 | pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + |
gatedClock | 13:7e1688393abc | 420 | ascii_nibble_to_binary(gpcSerialFromHost[4]); |
gatedClock | 13:7e1688393abc | 421 | pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + |
gatedClock | 13:7e1688393abc | 422 | ascii_nibble_to_binary(gpcSerialFromHost[6]); |
gatedClock | 13:7e1688393abc | 423 | |
gatedClock | 13:7e1688393abc | 424 | gdRoundTrip++; // expected reply to host is pending. |
gatedClock | 13:7e1688393abc | 425 | break; |
gatedClock | 13:7e1688393abc | 426 | } // host command 'get main-memory.' |
gatedClock | 13:7e1688393abc | 427 | |
gatedClock | 13:7e1688393abc | 428 | case HCMD_STEP : // host command 'step-CPU'. |
gatedClock | 13:7e1688393abc | 429 | { |
gatedClock | 13:7e1688393abc | 430 | break; |
gatedClock | 13:7e1688393abc | 431 | } // host command 'step-CPU'. |
gatedClock | 13:7e1688393abc | 432 | |
gatedClock | 13:7e1688393abc | 433 | case HCMD_SETIR : // host command 'set-IR'. |
gatedClock | 13:7e1688393abc | 434 | { |
gatedClock | 13:7e1688393abc | 435 | pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + |
gatedClock | 13:7e1688393abc | 436 | ascii_nibble_to_binary(gpcSerialFromHost[3]); |
gatedClock | 13:7e1688393abc | 437 | pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + |
gatedClock | 13:7e1688393abc | 438 | ascii_nibble_to_binary(gpcSerialFromHost[5]); |
gatedClock | 13:7e1688393abc | 439 | break; |
gatedClock | 13:7e1688393abc | 440 | } // host command 'set-IR'. |
gatedClock | 13:7e1688393abc | 441 | |
gatedClock | 13:7e1688393abc | 442 | case HCMD_GETALLREG : // host command 'get-all-registers'. |
gatedClock | 13:7e1688393abc | 443 | { |
gatedClock | 13:7e1688393abc | 444 | gdRoundTrip++; // expected reply to host is pending. |
gatedClock | 13:7e1688393abc | 445 | break; |
gatedClock | 13:7e1688393abc | 446 | } // host command 'get-all-registers'. |
gatedClock | 2:08655e2bb776 | 447 | |
gatedClock | 13:7e1688393abc | 448 | default : // default. |
gatedClock | 13:7e1688393abc | 449 | { |
gatedClock | 13:7e1688393abc | 450 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 451 | error("\n\r processIncomingSerial : ERROR unrecognised command from host. \n\r"); |
gatedClock | 13:7e1688393abc | 452 | break; |
gatedClock | 13:7e1688393abc | 453 | } // default. |
gatedClock | 13:7e1688393abc | 454 | } // command dependency. |
gatedClock | 13:7e1688393abc | 455 | |
gatedClock | 13:7e1688393abc | 456 | //---- |
gatedClock | 13:7e1688393abc | 457 | |
gatedClock | 2:08655e2bb776 | 458 | qFromHost.put(pFromHost); // send out for processing. |
gatedClock | 2:08655e2bb776 | 459 | gcNewCommand = 0; // don't execute until next new command. |
gatedClock | 2:08655e2bb776 | 460 | } // execute once per new command. |
gatedClock | 2:08655e2bb776 | 461 | Thread::wait(THREAD_0_WAIT); // multitasking. |
gatedClock | 2:08655e2bb776 | 462 | } // processIncomingSerial |
gatedClock | 2:08655e2bb776 | 463 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 464 | void processOutgoingSerial(void) // prepare/transmit data to host. |
gatedClock | 2:08655e2bb776 | 465 | { |
gatedClock | 2:08655e2bb776 | 466 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 467 | |
gatedClock | 2:08655e2bb776 | 468 | gqToHostEvent = qToHost.get(1); // check for reply back to host. |
gatedClock | 2:08655e2bb776 | 469 | |
gatedClock | 2:08655e2bb776 | 470 | // if new reply to host: |
gatedClock | 2:08655e2bb776 | 471 | if (gqToHostEvent.status == osEventMessage) |
gatedClock | 2:08655e2bb776 | 472 | { |
gatedClock | 2:08655e2bb776 | 473 | // bring it in from the queue. |
gatedClock | 2:08655e2bb776 | 474 | gpToHost = (tToHost *) gqToHostEvent.value.p; |
gatedClock | 13:7e1688393abc | 475 | if (!gpToHost) // failure detection. |
gatedClock | 13:7e1688393abc | 476 | { |
gatedClock | 13:7e1688393abc | 477 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 478 | error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); |
gatedClock | 13:7e1688393abc | 479 | } |
gatedClock | 2:08655e2bb776 | 480 | |
gatedClock | 2:08655e2bb776 | 481 | // clear outgoing buffer. |
gatedClock | 2:08655e2bb776 | 482 | for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0; |
gatedClock | 13:7e1688393abc | 483 | |
gatedClock | 13:7e1688393abc | 484 | switch(gpToHost->cCommand) // the from-host command was looped to here. |
gatedClock | 2:08655e2bb776 | 485 | { |
gatedClock | 13:7e1688393abc | 486 | case HCMD_SETREG : // host command 'set register'. |
gatedClock | 13:7e1688393abc | 487 | { |
gatedClock | 13:7e1688393abc | 488 | break; |
gatedClock | 13:7e1688393abc | 489 | } // host command 'set register'. |
gatedClock | 13:7e1688393abc | 490 | |
gatedClock | 13:7e1688393abc | 491 | case HCMD_GETREG : // host command 'get register'. |
gatedClock | 13:7e1688393abc | 492 | { |
gatedClock | 13:7e1688393abc | 493 | gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); |
gatedClock | 13:7e1688393abc | 494 | gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); |
gatedClock | 13:7e1688393abc | 495 | gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 496 | gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 497 | gpcSerialToHost[4] = '\n'; // signals end of transfer. |
gatedClock | 13:7e1688393abc | 498 | |
gatedClock | 13:7e1688393abc | 499 | // transmit to the host. |
gatedClock | 13:7e1688393abc | 500 | serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); |
gatedClock | 13:7e1688393abc | 501 | gdRoundTrip--; // expected reply sent to host. |
gatedClock | 13:7e1688393abc | 502 | break; |
gatedClock | 13:7e1688393abc | 503 | } // host command 'get register'. |
gatedClock | 13:7e1688393abc | 504 | |
gatedClock | 13:7e1688393abc | 505 | case HCMD_SETMM : // host command 'set main-memory.' |
gatedClock | 13:7e1688393abc | 506 | { |
gatedClock | 13:7e1688393abc | 507 | break; |
gatedClock | 13:7e1688393abc | 508 | } // host command 'set main-memory.' |
gatedClock | 13:7e1688393abc | 509 | |
gatedClock | 13:7e1688393abc | 510 | case HCMD_GETMM : // host command 'get main-memory.' |
gatedClock | 13:7e1688393abc | 511 | { |
gatedClock | 13:7e1688393abc | 512 | gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); |
gatedClock | 13:7e1688393abc | 513 | gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 514 | gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 515 | gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 516 | gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 517 | gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 518 | gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 519 | gpcSerialToHost[7] = '\n'; // signals end of transfer. |
gatedClock | 2:08655e2bb776 | 520 | |
gatedClock | 2:08655e2bb776 | 521 | // transmit to the host. |
gatedClock | 13:7e1688393abc | 522 | serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); |
gatedClock | 13:7e1688393abc | 523 | gdRoundTrip--; // expected reply sent to host. |
gatedClock | 13:7e1688393abc | 524 | break; |
gatedClock | 13:7e1688393abc | 525 | } // host command 'get main-memory.' |
gatedClock | 13:7e1688393abc | 526 | |
gatedClock | 13:7e1688393abc | 527 | case HCMD_STEP : // host command 'step-CPU'. |
gatedClock | 13:7e1688393abc | 528 | { |
gatedClock | 13:7e1688393abc | 529 | break; |
gatedClock | 13:7e1688393abc | 530 | } // host command 'step-CPU'. |
gatedClock | 13:7e1688393abc | 531 | |
gatedClock | 13:7e1688393abc | 532 | case HCMD_SETIR : // host command 'set-IR'. |
gatedClock | 13:7e1688393abc | 533 | { |
gatedClock | 13:7e1688393abc | 534 | break; |
gatedClock | 13:7e1688393abc | 535 | } // host command 'set-IR'. |
gatedClock | 13:7e1688393abc | 536 | |
gatedClock | 13:7e1688393abc | 537 | case HCMD_GETALLREG : // host command 'get-all-registers'. |
gatedClock | 13:7e1688393abc | 538 | { |
gatedClock | 13:7e1688393abc | 539 | gpcSerialToHost[ 0] = binary_to_ascii_nibble( gpToHost->cCommand); |
gatedClock | 13:7e1688393abc | 540 | gpcSerialToHost[ 1] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 541 | gpcSerialToHost[ 2] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 542 | gpcSerialToHost[ 3] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 543 | gpcSerialToHost[ 4] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 544 | gpcSerialToHost[ 5] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 545 | gpcSerialToHost[ 6] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 546 | gpcSerialToHost[ 7] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 547 | gpcSerialToHost[ 8] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 548 | gpcSerialToHost[ 9] = binary_to_ascii_nibble(((gpToHost->cPC) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 549 | gpcSerialToHost[10] = binary_to_ascii_nibble(((gpToHost->cPC) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 550 | gpcSerialToHost[11] = binary_to_ascii_nibble(((gpToHost->cIRH) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 551 | gpcSerialToHost[12] = binary_to_ascii_nibble(((gpToHost->cIRH) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 552 | gpcSerialToHost[13] = binary_to_ascii_nibble(((gpToHost->cIRL) >> 4) & 0x0F); |
gatedClock | 13:7e1688393abc | 553 | gpcSerialToHost[14] = binary_to_ascii_nibble(((gpToHost->cIRL) >> 0) & 0x0F); |
gatedClock | 13:7e1688393abc | 554 | gpcSerialToHost[15] = '\n'; // signals end of transfer. |
gatedClock | 13:7e1688393abc | 555 | |
gatedClock | 2:08655e2bb776 | 556 | // transmit to the host. |
gatedClock | 13:7e1688393abc | 557 | serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); |
gatedClock | 13:7e1688393abc | 558 | gdRoundTrip--; // expected reply sent to host. |
gatedClock | 13:7e1688393abc | 559 | break; |
gatedClock | 13:7e1688393abc | 560 | } // host command 'get-all-registers'. |
gatedClock | 13:7e1688393abc | 561 | |
gatedClock | 13:7e1688393abc | 562 | default : |
gatedClock | 13:7e1688393abc | 563 | { |
gatedClock | 13:7e1688393abc | 564 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 565 | error("\n\r processOutgoingSerial : ERROR unrecognised command from host. \n\r"); |
gatedClock | 13:7e1688393abc | 566 | break; |
gatedClock | 13:7e1688393abc | 567 | } // default. |
gatedClock | 13:7e1688393abc | 568 | } // switch(gpToHost->cCommand) |
gatedClock | 13:7e1688393abc | 569 | |
gatedClock | 2:08655e2bb776 | 570 | mPoolToHost.free(gpToHost); // done with this queue entry. |
gatedClock | 2:08655e2bb776 | 571 | gpToHost = NULL; // clear pointer. |
gatedClock | 2:08655e2bb776 | 572 | } // if new reply to host. |
gatedClock | 2:08655e2bb776 | 573 | } // processOutgoingSerial. |
gatedClock | 2:08655e2bb776 | 574 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 575 | // the pcSendBuffer and pcReceiveBuffer arrays are not used by this function, |
gatedClock | 2:08655e2bb776 | 576 | // but they are declared by this function, and their pointers are passed |
gatedClock | 2:08655e2bb776 | 577 | // down to the mmSPI library for its use of them. |
gatedClock | 2:08655e2bb776 | 578 | // note- the prefix 'pc' means 'pointer of type character', not 'personal computer'. |
gatedClock | 2:08655e2bb776 | 579 | |
gatedClock | 2:08655e2bb776 | 580 | void SPIprocessingThread(void const *args) // process host-commands via SPI. |
gatedClock | 2:08655e2bb776 | 581 | { |
gatedClock | 2:08655e2bb776 | 582 | char pcSendBuffer [SPI_BYTES]; // SPI send buffer. |
gatedClock | 2:08655e2bb776 | 583 | char pcReceiveBuffer[SPI_BYTES]; // SPI receive buffer. |
gatedClock | 13:7e1688393abc | 584 | char pcRegisters [SPI_BYTES]; // fetch-all-registers vector. |
gatedClock | 2:08655e2bb776 | 585 | int dHeartbeat; // heartbeat counter. |
gatedClock | 2:08655e2bb776 | 586 | int dMemoryRead; // read main-memory into this. |
gatedClock | 2:08655e2bb776 | 587 | int dLoop; // loop index. |
gatedClock | 2:08655e2bb776 | 588 | osEvent qFromHostEvent; // incoming message event. |
gatedClock | 2:08655e2bb776 | 589 | tFromHost * pFromHost; // message structure. |
gatedClock | 2:08655e2bb776 | 590 | tToHost * gpToHost; // message structure. |
gatedClock | 2:08655e2bb776 | 591 | mmSPI * pSPI; // SPI. |
gatedClock | 2:08655e2bb776 | 592 | |
gatedClock | 2:08655e2bb776 | 593 | pFromHost = NULL; // NULL pointers. |
gatedClock | 2:08655e2bb776 | 594 | gpToHost = NULL; |
gatedClock | 2:08655e2bb776 | 595 | pSPI = NULL; |
gatedClock | 2:08655e2bb776 | 596 | dHeartbeat = 0; // clear variables. |
gatedClock | 2:08655e2bb776 | 597 | dMemoryRead = 0; |
gatedClock | 2:08655e2bb776 | 598 | dLoop = 0; |
gatedClock | 2:08655e2bb776 | 599 | // clear SPI vectors. |
gatedClock | 2:08655e2bb776 | 600 | for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer [dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 601 | for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0; |
gatedClock | 2:08655e2bb776 | 602 | |
gatedClock | 13:7e1688393abc | 603 | pSPI = new mmSPI; // SPI allocation. |
gatedClock | 13:7e1688393abc | 604 | if (!pSPI) // failure detection. |
gatedClock | 13:7e1688393abc | 605 | { |
gatedClock | 13:7e1688393abc | 606 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 607 | error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); |
gatedClock | 13:7e1688393abc | 608 | } |
gatedClock | 2:08655e2bb776 | 609 | |
gatedClock | 2:08655e2bb776 | 610 | pSPI->setSendBuffer (pcSendBuffer); // set SPI send buffer. |
gatedClock | 2:08655e2bb776 | 611 | pSPI->setReceiveBuffer(pcReceiveBuffer); // set SPI receive buffer. |
gatedClock | 2:08655e2bb776 | 612 | pSPI->setNumberOfBytes(SPI_BYTES); // set SPI number of bytes. |
gatedClock | 2:08655e2bb776 | 613 | pSPI->setSPIfrequency (SPI_HZ); // set SPI clock frequency. |
gatedClock | 2:08655e2bb776 | 614 | |
gatedClock | 2:08655e2bb776 | 615 | while(1) // thread loop. |
gatedClock | 2:08655e2bb776 | 616 | { |
gatedClock | 2:08655e2bb776 | 617 | qFromHostEvent = qFromHost.get(1); // check for incoming host command. |
gatedClock | 2:08655e2bb776 | 618 | |
gatedClock | 2:08655e2bb776 | 619 | // if new host command: |
gatedClock | 2:08655e2bb776 | 620 | if (qFromHostEvent.status == osEventMessage) |
gatedClock | 2:08655e2bb776 | 621 | { |
gatedClock | 2:08655e2bb776 | 622 | // bring it in from the queue. |
gatedClock | 2:08655e2bb776 | 623 | pFromHost = (tFromHost *) qFromHostEvent.value.p; |
gatedClock | 13:7e1688393abc | 624 | if (!pFromHost) // failure detection. |
gatedClock | 13:7e1688393abc | 625 | { |
gatedClock | 13:7e1688393abc | 626 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 627 | error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); |
gatedClock | 13:7e1688393abc | 628 | } |
gatedClock | 2:08655e2bb776 | 629 | |
gatedClock | 2:08655e2bb776 | 630 | switch(pFromHost->cCommand) // host command decode. |
gatedClock | 2:08655e2bb776 | 631 | { |
gatedClock | 2:08655e2bb776 | 632 | case HCMD_SETREG : // set CPU register. |
gatedClock | 2:08655e2bb776 | 633 | { |
gatedClock | 2:08655e2bb776 | 634 | switch(pFromHost->cRegisterID) // which register to write to. |
gatedClock | 2:08655e2bb776 | 635 | { |
gatedClock | 2:08655e2bb776 | 636 | case CPU_REG_0 : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 637 | case CPU_REG_1 : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 638 | case CPU_REG_2 : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 639 | case CPU_REG_3 : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 640 | case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;} |
gatedClock | 2:08655e2bb776 | 641 | default : {break;} |
gatedClock | 2:08655e2bb776 | 642 | } // which register to write to. |
gatedClock | 2:08655e2bb776 | 643 | break; |
gatedClock | 2:08655e2bb776 | 644 | } // set CPU register. |
gatedClock | 2:08655e2bb776 | 645 | |
gatedClock | 2:08655e2bb776 | 646 | case HCMD_SETIR: // set instruction register. |
gatedClock | 2:08655e2bb776 | 647 | { |
gatedClock | 2:08655e2bb776 | 648 | pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL); |
gatedClock | 2:08655e2bb776 | 649 | break; |
gatedClock | 2:08655e2bb776 | 650 | } // set instruction register. |
gatedClock | 2:08655e2bb776 | 651 | |
gatedClock | 2:08655e2bb776 | 652 | case HCMD_GETREG : // get CPU register. |
gatedClock | 2:08655e2bb776 | 653 | { |
gatedClock | 2:08655e2bb776 | 654 | gpToHost = mPoolToHost.alloc(); // allocate next pool entry. |
gatedClock | 13:7e1688393abc | 655 | if (!gpToHost) // failure detection. |
gatedClock | 13:7e1688393abc | 656 | { |
gatedClock | 13:7e1688393abc | 657 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 658 | error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); |
gatedClock | 13:7e1688393abc | 659 | } |
gatedClock | 13:7e1688393abc | 660 | |
gatedClock | 2:08655e2bb776 | 661 | clear_tToHost(gpToHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 662 | |
gatedClock | 2:08655e2bb776 | 663 | switch(pFromHost->cRegisterID) // which register to read from. |
gatedClock | 2:08655e2bb776 | 664 | { |
gatedClock | 2:08655e2bb776 | 665 | case CPU_REG_0 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;} |
gatedClock | 2:08655e2bb776 | 666 | case CPU_REG_1 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;} |
gatedClock | 2:08655e2bb776 | 667 | case CPU_REG_2 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;} |
gatedClock | 2:08655e2bb776 | 668 | case CPU_REG_3 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;} |
gatedClock | 2:08655e2bb776 | 669 | case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;} |
gatedClock | 2:08655e2bb776 | 670 | case CPU_IR_H : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H ); break;} |
gatedClock | 2:08655e2bb776 | 671 | case CPU_IR_L : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L ); break;} |
gatedClock | 2:08655e2bb776 | 672 | default : {break;} |
gatedClock | 2:08655e2bb776 | 673 | } // which register to read from. |
gatedClock | 2:08655e2bb776 | 674 | |
gatedClock | 2:08655e2bb776 | 675 | // loop-back to host. |
gatedClock | 2:08655e2bb776 | 676 | gpToHost->cCommand = pFromHost->cCommand; |
gatedClock | 2:08655e2bb776 | 677 | gpToHost->cRegisterID = pFromHost->cRegisterID; |
gatedClock | 2:08655e2bb776 | 678 | |
gatedClock | 2:08655e2bb776 | 679 | qToHost.put(gpToHost); // send up for processing. |
gatedClock | 2:08655e2bb776 | 680 | break; |
gatedClock | 2:08655e2bb776 | 681 | } // get CPU register. |
gatedClock | 2:08655e2bb776 | 682 | |
gatedClock | 13:7e1688393abc | 683 | case HCMD_GETALLREG : // get all CPU registers. |
gatedClock | 13:7e1688393abc | 684 | { |
gatedClock | 13:7e1688393abc | 685 | gpToHost = mPoolToHost.alloc(); // allocate next pool entry. |
gatedClock | 13:7e1688393abc | 686 | if (!gpToHost) // failure detection. |
gatedClock | 13:7e1688393abc | 687 | { |
gatedClock | 13:7e1688393abc | 688 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 689 | error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); |
gatedClock | 13:7e1688393abc | 690 | } |
gatedClock | 13:7e1688393abc | 691 | |
gatedClock | 13:7e1688393abc | 692 | clear_tToHost(gpToHost); // initialize structure. |
gatedClock | 13:7e1688393abc | 693 | |
gatedClock | 13:7e1688393abc | 694 | // tell SPI to return all reg content. |
gatedClock | 13:7e1688393abc | 695 | pSPI->read_all_registers(pcRegisters); |
gatedClock | 13:7e1688393abc | 696 | |
gatedClock | 13:7e1688393abc | 697 | gpToHost->cReg0 = pcRegisters[6]; // transfer to outgoing structure. |
gatedClock | 13:7e1688393abc | 698 | gpToHost->cReg1 = pcRegisters[5]; |
gatedClock | 13:7e1688393abc | 699 | gpToHost->cReg2 = pcRegisters[4]; |
gatedClock | 13:7e1688393abc | 700 | gpToHost->cReg3 = pcRegisters[3]; |
gatedClock | 13:7e1688393abc | 701 | gpToHost->cPC = pcRegisters[2]; |
gatedClock | 13:7e1688393abc | 702 | gpToHost->cIRH = pcRegisters[1]; |
gatedClock | 13:7e1688393abc | 703 | gpToHost->cIRL = pcRegisters[0]; |
gatedClock | 13:7e1688393abc | 704 | |
gatedClock | 13:7e1688393abc | 705 | // loop-back to host. |
gatedClock | 13:7e1688393abc | 706 | gpToHost->cCommand = pFromHost->cCommand; |
gatedClock | 13:7e1688393abc | 707 | qToHost.put(gpToHost); // send up for processing. |
gatedClock | 13:7e1688393abc | 708 | |
gatedClock | 13:7e1688393abc | 709 | break; |
gatedClock | 13:7e1688393abc | 710 | } // get all CPU registers. |
gatedClock | 13:7e1688393abc | 711 | |
gatedClock | 2:08655e2bb776 | 712 | case HCMD_SETMM : // do main-memory write. |
gatedClock | 2:08655e2bb776 | 713 | { |
gatedClock | 2:08655e2bb776 | 714 | pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress); |
gatedClock | 2:08655e2bb776 | 715 | break; |
gatedClock | 2:08655e2bb776 | 716 | } // do main-memory write. |
gatedClock | 2:08655e2bb776 | 717 | |
gatedClock | 2:08655e2bb776 | 718 | case HCMD_GETMM : // do main-memory read. |
gatedClock | 2:08655e2bb776 | 719 | { |
gatedClock | 13:7e1688393abc | 720 | gpToHost = mPoolToHost.alloc(); // allocate next pool entry. |
gatedClock | 13:7e1688393abc | 721 | if (!gpToHost) // failure detection. |
gatedClock | 13:7e1688393abc | 722 | { |
gatedClock | 13:7e1688393abc | 723 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 724 | error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); |
gatedClock | 13:7e1688393abc | 725 | } |
gatedClock | 13:7e1688393abc | 726 | |
gatedClock | 2:08655e2bb776 | 727 | clear_tToHost(gpToHost); // initialize structure. |
gatedClock | 2:08655e2bb776 | 728 | |
gatedClock | 2:08655e2bb776 | 729 | // read from CPU memory. |
gatedClock | 2:08655e2bb776 | 730 | dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); |
gatedClock | 2:08655e2bb776 | 731 | gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF; |
gatedClock | 2:08655e2bb776 | 732 | gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF; |
gatedClock | 2:08655e2bb776 | 733 | |
gatedClock | 2:08655e2bb776 | 734 | // loop-back to host. |
gatedClock | 2:08655e2bb776 | 735 | gpToHost->cCommand = pFromHost->cCommand; |
gatedClock | 2:08655e2bb776 | 736 | gpToHost->cMMaddress = pFromHost->cMMaddress; |
gatedClock | 2:08655e2bb776 | 737 | |
gatedClock | 2:08655e2bb776 | 738 | qToHost.put(gpToHost); // send up for processing. |
gatedClock | 2:08655e2bb776 | 739 | break; |
gatedClock | 2:08655e2bb776 | 740 | } // do main-memory read. |
gatedClock | 2:08655e2bb776 | 741 | |
gatedClock | 2:08655e2bb776 | 742 | case HCMD_STEP : // step the CPU. |
gatedClock | 2:08655e2bb776 | 743 | { |
gatedClock | 2:08655e2bb776 | 744 | pSPI->step(); |
gatedClock | 2:08655e2bb776 | 745 | break; |
gatedClock | 2:08655e2bb776 | 746 | } // step the CPU. |
gatedClock | 2:08655e2bb776 | 747 | default : break; |
gatedClock | 2:08655e2bb776 | 748 | } // host command decode. |
gatedClock | 2:08655e2bb776 | 749 | mPoolFromHost.free(pFromHost); // done with this queue entry. |
gatedClock | 2:08655e2bb776 | 750 | pFromHost = NULL; // clear pointer. |
gatedClock | 2:08655e2bb776 | 751 | } // if new host command. |
gatedClock | 2:08655e2bb776 | 752 | |
gatedClock | 2:08655e2bb776 | 753 | gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable. |
gatedClock | 2:08655e2bb776 | 754 | gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable. |
gatedClock | 2:08655e2bb776 | 755 | |
gatedClock | 2:08655e2bb776 | 756 | // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 757 | dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1; |
gatedClock | 13:7e1688393abc | 758 | queueWatchdogThread_1.put((int *) 0,1); // adds 1mS to wait. |
gatedClock | 13:7e1688393abc | 759 | Thread::wait(THREAD_1_WAIT - 1); // cooperative multitasking. |
gatedClock | 2:08655e2bb776 | 760 | } // thread loop. |
gatedClock | 2:08655e2bb776 | 761 | } // SPIprocessingThread. |
gatedClock | 2:08655e2bb776 | 762 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 13:7e1688393abc | 763 | void diagnosticThread(void const *args) // LCD notification & error check. |
gatedClock | 2:08655e2bb776 | 764 | { |
gatedClock | 13:7e1688393abc | 765 | // track previous values. |
gatedClock | 13:7e1688393abc | 766 | static unsigned long ulLastSPIclkCount = 1; |
gatedClock | 13:7e1688393abc | 767 | static unsigned long ulLastCPUclkCount = 1; |
gatedClock | 13:7e1688393abc | 768 | int dHeartbeat; // heartbeat counter. |
gatedClock | 13:7e1688393abc | 769 | |
gatedClock | 2:08655e2bb776 | 770 | dHeartbeat = 0; // initialize. |
gatedClock | 13:7e1688393abc | 771 | |
gatedClock | 2:08655e2bb776 | 772 | while(1) // thread loop. |
gatedClock | 2:08655e2bb776 | 773 | { |
gatedClock | 2:08655e2bb776 | 774 | // if message round trip |
gatedClock | 2:08655e2bb776 | 775 | // count not consistent. |
gatedClock | 13:7e1688393abc | 776 | if (gdRoundTrip > 1025 || gdRoundTrip < 1024) |
gatedClock | 13:7e1688393abc | 777 | { |
gatedClock | 13:7e1688393abc | 778 | if (ERROR_BOOT) mbed_reset(); else |
gatedClock | 13:7e1688393abc | 779 | error("\n\r diagnosticThread : ERROR serial reply underflow. \n\r"); |
gatedClock | 13:7e1688393abc | 780 | } |
gatedClock | 2:08655e2bb776 | 781 | |
gatedClock | 13:7e1688393abc | 782 | // update LCD only if a display |
gatedClock | 13:7e1688393abc | 783 | // value has changed. anti-blink, |
gatedClock | 13:7e1688393abc | 784 | // save a bit of power. |
gatedClock | 13:7e1688393abc | 785 | if (gulSPIclkCount != ulLastSPIclkCount || |
gatedClock | 13:7e1688393abc | 786 | gulCPUclkCount != ulLastCPUclkCount ) |
gatedClock | 13:7e1688393abc | 787 | { |
gatedClock | 13:7e1688393abc | 788 | lcd.cls(); // clear LCD display. |
gatedClock | 13:7e1688393abc | 789 | LCD1; // lcd line 1. |
gatedClock | 13:7e1688393abc | 790 | lcd.printf(" RTOS CLASS PROJECT"); |
gatedClock | 2:08655e2bb776 | 791 | |
gatedClock | 13:7e1688393abc | 792 | LCD2; // lcd line 2. |
gatedClock | 13:7e1688393abc | 793 | lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); |
gatedClock | 13:7e1688393abc | 794 | |
gatedClock | 13:7e1688393abc | 795 | LCD3; // lcd line 3. |
gatedClock | 13:7e1688393abc | 796 | lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); |
gatedClock | 13:7e1688393abc | 797 | } |
gatedClock | 13:7e1688393abc | 798 | |
gatedClock | 13:7e1688393abc | 799 | ulLastSPIclkCount = gulSPIclkCount; // pipeline. |
gatedClock | 13:7e1688393abc | 800 | ulLastCPUclkCount = gulCPUclkCount; // pipeline. |
gatedClock | 2:08655e2bb776 | 801 | |
gatedClock | 2:08655e2bb776 | 802 | dHeartbeat++; // thread heartbeat. |
gatedClock | 2:08655e2bb776 | 803 | if (!(dHeartbeat % HB_MODULO)) led2 = !led2; |
gatedClock | 13:7e1688393abc | 804 | queueWatchdogThread_2.put((int *) 0,1); // adds 1mS to wait. |
gatedClock | 13:7e1688393abc | 805 | Thread::wait(THREAD_2_WAIT - 1); // multitasking. |
gatedClock | 2:08655e2bb776 | 806 | } // thread loop. |
gatedClock | 2:08655e2bb776 | 807 | } // diagnosticThread. |
gatedClock | 2:08655e2bb776 | 808 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 13:7e1688393abc | 809 | // this is its own watchdog. |
gatedClock | 13:7e1688393abc | 810 | |
gatedClock | 13:7e1688393abc | 811 | void watchdogThread(void const *args) // overall watchdog. |
gatedClock | 13:7e1688393abc | 812 | { |
gatedClock | 13:7e1688393abc | 813 | int dHeartbeat; // heartbeat counter. |
gatedClock | 13:7e1688393abc | 814 | osEvent queueEvent; // queue event |
gatedClock | 13:7e1688393abc | 815 | Watchdog watchdog; // the one and only watchdog. |
gatedClock | 13:7e1688393abc | 816 | |
gatedClock | 13:7e1688393abc | 817 | dHeartbeat = 0; // initialize. |
gatedClock | 13:7e1688393abc | 818 | |
gatedClock | 13:7e1688393abc | 819 | watchdog.kick(WATCHDOG_S); // initialize watchdog. |
gatedClock | 13:7e1688393abc | 820 | |
gatedClock | 13:7e1688393abc | 821 | while (1) // thread loop. |
gatedClock | 13:7e1688393abc | 822 | { |
gatedClock | 13:7e1688393abc | 823 | // all other threads report-in. |
gatedClock | 13:7e1688393abc | 824 | // blocking wait on all of them. |
gatedClock | 13:7e1688393abc | 825 | queueEvent = queueWatchdogThread_0.get(osWaitForever); |
gatedClock | 13:7e1688393abc | 826 | queueEvent = queueWatchdogThread_1.get(osWaitForever); |
gatedClock | 13:7e1688393abc | 827 | queueEvent = queueWatchdogThread_2.get(osWaitForever); |
gatedClock | 13:7e1688393abc | 828 | |
gatedClock | 13:7e1688393abc | 829 | watchdog.kick(); // reset watchdog timer. |
gatedClock | 13:7e1688393abc | 830 | |
gatedClock | 13:7e1688393abc | 831 | dHeartbeat++; // thread heartbeat. |
gatedClock | 13:7e1688393abc | 832 | if (!(dHeartbeat % HB_MODULO)) led3 = !led3; |
gatedClock | 13:7e1688393abc | 833 | Thread::wait(THREAD_3_WAIT); // multitasking. |
gatedClock | 13:7e1688393abc | 834 | } // thread loop. |
gatedClock | 13:7e1688393abc | 835 | } |
gatedClock | 13:7e1688393abc | 836 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 837 | char ascii_nibble_to_binary(char cAscii) // ascii nibble -> binary. |
gatedClock | 2:08655e2bb776 | 838 | { |
gatedClock | 2:08655e2bb776 | 839 | char cBinary; // converted value. |
gatedClock | 2:08655e2bb776 | 840 | |
gatedClock | 2:08655e2bb776 | 841 | switch(cAscii) |
gatedClock | 2:08655e2bb776 | 842 | { |
gatedClock | 2:08655e2bb776 | 843 | case 'F' : {cBinary = 15; break;} |
gatedClock | 2:08655e2bb776 | 844 | case 'E' : {cBinary = 14; break;} |
gatedClock | 2:08655e2bb776 | 845 | case 'D' : {cBinary = 13; break;} |
gatedClock | 2:08655e2bb776 | 846 | case 'C' : {cBinary = 12; break;} |
gatedClock | 2:08655e2bb776 | 847 | case 'B' : {cBinary = 11; break;} |
gatedClock | 2:08655e2bb776 | 848 | case 'A' : {cBinary = 10; break;} |
gatedClock | 2:08655e2bb776 | 849 | case 'f' : {cBinary = 15; break;} |
gatedClock | 2:08655e2bb776 | 850 | case 'e' : {cBinary = 14; break;} |
gatedClock | 2:08655e2bb776 | 851 | case 'd' : {cBinary = 13; break;} |
gatedClock | 2:08655e2bb776 | 852 | case 'c' : {cBinary = 12; break;} |
gatedClock | 2:08655e2bb776 | 853 | case 'b' : {cBinary = 11; break;} |
gatedClock | 2:08655e2bb776 | 854 | case 'a' : {cBinary = 10; break;} |
gatedClock | 2:08655e2bb776 | 855 | case '9' : {cBinary = 9; break;} |
gatedClock | 2:08655e2bb776 | 856 | case '8' : {cBinary = 8; break;} |
gatedClock | 2:08655e2bb776 | 857 | case '7' : {cBinary = 7; break;} |
gatedClock | 2:08655e2bb776 | 858 | case '6' : {cBinary = 6; break;} |
gatedClock | 2:08655e2bb776 | 859 | case '5' : {cBinary = 5; break;} |
gatedClock | 2:08655e2bb776 | 860 | case '4' : {cBinary = 4; break;} |
gatedClock | 2:08655e2bb776 | 861 | case '3' : {cBinary = 3; break;} |
gatedClock | 2:08655e2bb776 | 862 | case '2' : {cBinary = 2; break;} |
gatedClock | 2:08655e2bb776 | 863 | case '1' : {cBinary = 1; break;} |
gatedClock | 2:08655e2bb776 | 864 | case '0' : {cBinary = 0; break;} |
gatedClock | 2:08655e2bb776 | 865 | default : {cBinary = 0; break;} |
gatedClock | 2:08655e2bb776 | 866 | } // switch(cAscii). |
gatedClock | 2:08655e2bb776 | 867 | return(cBinary); // return the binary. |
gatedClock | 2:08655e2bb776 | 868 | } // ascii_nibble_to_binary. |
gatedClock | 2:08655e2bb776 | 869 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 870 | char binary_to_ascii_nibble(char cBinary) // binary -> ascii nibble. |
gatedClock | 2:08655e2bb776 | 871 | { |
gatedClock | 2:08655e2bb776 | 872 | char cAscii; // converted value. |
gatedClock | 2:08655e2bb776 | 873 | |
gatedClock | 2:08655e2bb776 | 874 | switch(cBinary) |
gatedClock | 2:08655e2bb776 | 875 | { |
gatedClock | 2:08655e2bb776 | 876 | case 15 : {cAscii = 'F'; break;} |
gatedClock | 2:08655e2bb776 | 877 | case 14 : {cAscii = 'E'; break;} |
gatedClock | 2:08655e2bb776 | 878 | case 13 : {cAscii = 'D'; break;} |
gatedClock | 2:08655e2bb776 | 879 | case 12 : {cAscii = 'C'; break;} |
gatedClock | 2:08655e2bb776 | 880 | case 11 : {cAscii = 'B'; break;} |
gatedClock | 2:08655e2bb776 | 881 | case 10 : {cAscii = 'A'; break;} |
gatedClock | 2:08655e2bb776 | 882 | case 9 : {cAscii = '9'; break;} |
gatedClock | 2:08655e2bb776 | 883 | case 8 : {cAscii = '8'; break;} |
gatedClock | 2:08655e2bb776 | 884 | case 7 : {cAscii = '7'; break;} |
gatedClock | 2:08655e2bb776 | 885 | case 6 : {cAscii = '6'; break;} |
gatedClock | 2:08655e2bb776 | 886 | case 5 : {cAscii = '5'; break;} |
gatedClock | 2:08655e2bb776 | 887 | case 4 : {cAscii = '4'; break;} |
gatedClock | 2:08655e2bb776 | 888 | case 3 : {cAscii = '3'; break;} |
gatedClock | 2:08655e2bb776 | 889 | case 2 : {cAscii = '2'; break;} |
gatedClock | 2:08655e2bb776 | 890 | case 1 : {cAscii = '1'; break;} |
gatedClock | 2:08655e2bb776 | 891 | case 0 : {cAscii = '0'; break;} |
gatedClock | 2:08655e2bb776 | 892 | default : {cAscii = '0'; break;} |
gatedClock | 2:08655e2bb776 | 893 | } // switch(cBinary). |
gatedClock | 2:08655e2bb776 | 894 | return(cAscii); // return the binary. |
gatedClock | 2:08655e2bb776 | 895 | } // binary_to_ascii_nibble. |
gatedClock | 2:08655e2bb776 | 896 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 897 | void clear_tFromHost(tFromHost * ptFromHost)// clear structure. |
gatedClock | 2:08655e2bb776 | 898 | { |
gatedClock | 2:08655e2bb776 | 899 | ptFromHost->cCommand = 0x00; |
gatedClock | 2:08655e2bb776 | 900 | ptFromHost->cRegisterID = 0x00; |
gatedClock | 2:08655e2bb776 | 901 | ptFromHost->cRegisterValue = 0x00; |
gatedClock | 2:08655e2bb776 | 902 | ptFromHost->cIRValueH = 0x00; |
gatedClock | 2:08655e2bb776 | 903 | ptFromHost->cIRValueL = 0x00; |
gatedClock | 2:08655e2bb776 | 904 | ptFromHost->cMMaddress = 0x00; |
gatedClock | 2:08655e2bb776 | 905 | ptFromHost->cMMdataH = 0x00; |
gatedClock | 2:08655e2bb776 | 906 | ptFromHost->cMMdataL = 0x00; |
gatedClock | 2:08655e2bb776 | 907 | } // clear_tFromHost. |
gatedClock | 2:08655e2bb776 | 908 | /*----------------------------------------------//----------------------------*/ |
gatedClock | 2:08655e2bb776 | 909 | void clear_tToHost(tToHost * ptToHost) // clear structure. |
gatedClock | 2:08655e2bb776 | 910 | { |
gatedClock | 2:08655e2bb776 | 911 | ptToHost->cCommand = 0x00; |
gatedClock | 2:08655e2bb776 | 912 | ptToHost->cRegisterID = 0x00; |
gatedClock | 2:08655e2bb776 | 913 | ptToHost->cRegisterValue = 0x00; |
gatedClock | 2:08655e2bb776 | 914 | ptToHost->cMMaddress = 0x00; |
gatedClock | 2:08655e2bb776 | 915 | ptToHost->cMMdataH = 0x00; |
gatedClock | 2:08655e2bb776 | 916 | ptToHost->cMMdataL = 0x00; |
gatedClock | 2:08655e2bb776 | 917 | } // clear_tToHost. |
gatedClock | 2:08655e2bb776 | 918 | /*----------------------------------------------//----------------------------*/ |