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.
Dependents: RTOS_project RTOS_project_fork_01 RTOS_project_fork_02
mmSPI_RTOS.cpp@0:7b8e6b90c874, 2013-09-17 (annotated)
- Committer:
- gatedClock
- Date:
- Tue Sep 17 20:40:03 2013 +0000
- Revision:
- 0:7b8e6b90c874
update.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| gatedClock | 0:7b8e6b90c874 | 1 | /*----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 2 | student : m-moore |
| gatedClock | 0:7b8e6b90c874 | 3 | email : gated.clock@gmail.com |
| gatedClock | 0:7b8e6b90c874 | 4 | class : embedded RTOS |
| gatedClock | 0:7b8e6b90c874 | 5 | directory : URTOS_project/mmSPI_RTOS |
| gatedClock | 0:7b8e6b90c874 | 6 | file : mmSPI_RTOS.cpp |
| gatedClock | 0:7b8e6b90c874 | 7 | date : september 19, 2013. |
| gatedClock | 0:7b8e6b90c874 | 8 | ----copyright-----------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 9 | licensed for personal and academic use. |
| gatedClock | 0:7b8e6b90c874 | 10 | commercial use of original code must be approved by the account-holder of |
| gatedClock | 0:7b8e6b90c874 | 11 | gated.clock@gmail.com |
| gatedClock | 0:7b8e6b90c874 | 12 | ----description---------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 13 | this library provides the low-level SPI data and clock signaling |
| gatedClock | 0:7b8e6b90c874 | 14 | for communication with the altera development board, via four i/o |
| gatedClock | 0:7b8e6b90c874 | 15 | pins available on the mbed development board's zigbee header. |
| gatedClock | 0:7b8e6b90c874 | 16 | |
| gatedClock | 0:7b8e6b90c874 | 17 | this library also provides higher-level calls to send/receive register |
| gatedClock | 0:7b8e6b90c874 | 18 | and main-memory data to/from the CPU implemented in the altera. |
| gatedClock | 0:7b8e6b90c874 | 19 | |
| gatedClock | 0:7b8e6b90c874 | 20 | the SPI clock and the CPU clock are both built by this library. |
| gatedClock | 0:7b8e6b90c874 | 21 | |
| gatedClock | 0:7b8e6b90c874 | 22 | the SPI clock (*pSCLK) is generated with quarter-phase resolution, |
| gatedClock | 0:7b8e6b90c874 | 23 | although at the moment, only half-phase resolution is being used. |
| gatedClock | 0:7b8e6b90c874 | 24 | |
| gatedClock | 0:7b8e6b90c874 | 25 | within the FPGA, the SPI scan registers are called 'shadow registers' |
| gatedClock | 0:7b8e6b90c874 | 26 | because they parallel load-to/store-from the CPU registers. |
| gatedClock | 0:7b8e6b90c874 | 27 | |
| gatedClock | 0:7b8e6b90c874 | 28 | character vectors pcSend and pcReceive are used to scan-in and scan-out |
| gatedClock | 0:7b8e6b90c874 | 29 | to/from the altera shadow registers. note that the prefix 'pc' means |
| gatedClock | 0:7b8e6b90c874 | 30 | 'pointer-of-type-character' and not 'personal-computer'. |
| gatedClock | 0:7b8e6b90c874 | 31 | |
| gatedClock | 0:7b8e6b90c874 | 32 | the shadow registers in the altera are arranged as follows: |
| gatedClock | 0:7b8e6b90c874 | 33 | |
| gatedClock | 0:7b8e6b90c874 | 34 | <-- MISO (altera-out to mbed-in) |
| gatedClock | 0:7b8e6b90c874 | 35 | ^ |
| gatedClock | 0:7b8e6b90c874 | 36 | | |
| gatedClock | 0:7b8e6b90c874 | 37 | scan_08 U14_spi_control = pcSend/pcReceive[7] |
| gatedClock | 0:7b8e6b90c874 | 38 | scan_08 U08_shadowR0 = pcSend/pcReceive[6] |
| gatedClock | 0:7b8e6b90c874 | 39 | scan_08 U09_shadowR1 = pcSend/pcReceive[5] |
| gatedClock | 0:7b8e6b90c874 | 40 | scan_08 U10_shadowR2 = pcSend/pcReceive[4] |
| gatedClock | 0:7b8e6b90c874 | 41 | scan_08 U11_shadowR3 = pcSend/pcReceive[3] |
| gatedClock | 0:7b8e6b90c874 | 42 | scan_08 U12_shadowPC = pcSend/pcReceive[2] |
| gatedClock | 0:7b8e6b90c874 | 43 | scan_16 U13_shadowIR = pcSend/pcReceive[1:0] |
| gatedClock | 0:7b8e6b90c874 | 44 | ^ |
| gatedClock | 0:7b8e6b90c874 | 45 | | |
| gatedClock | 0:7b8e6b90c874 | 46 | --> MOSI (altera-in from mbed-out) |
| gatedClock | 0:7b8e6b90c874 | 47 | |
| gatedClock | 0:7b8e6b90c874 | 48 | when U14_spi_control<1> is high, the mbed takes over CPU operation. |
| gatedClock | 0:7b8e6b90c874 | 49 | this means that the CPU instruction decoder decodes U13_shadowIR |
| gatedClock | 0:7b8e6b90c874 | 50 | rather than the CPU's actual IR. |
| gatedClock | 0:7b8e6b90c874 | 51 | |
| gatedClock | 0:7b8e6b90c874 | 52 | when U14_spi_control<2> is high, the mbed writes into the IR. |
| gatedClock | 0:7b8e6b90c874 | 53 | this means that the CPU instruction decoder load-enable outputs |
| gatedClock | 0:7b8e6b90c874 | 54 | are gated-off so that the mbed may write into the instrucition |
| gatedClock | 0:7b8e6b90c874 | 55 | register without immediate consequence in the CPU. writing to |
| gatedClock | 0:7b8e6b90c874 | 56 | the IR this way is more for the ability to show that it can be done, |
| gatedClock | 0:7b8e6b90c874 | 57 | rather than any likely useful purpose. |
| gatedClock | 0:7b8e6b90c874 | 58 | |
| gatedClock | 0:7b8e6b90c874 | 59 | debug/test: |
| gatedClock | 0:7b8e6b90c874 | 60 | this library was debugged by using the altera FPGA logic analyzer |
| gatedClock | 0:7b8e6b90c874 | 61 | known as 'signal tap'. the main program uses all of the memory and |
| gatedClock | 0:7b8e6b90c874 | 62 | register access calls, which were used as an informal unit test. |
| gatedClock | 0:7b8e6b90c874 | 63 | -----includes-----------------------------------//----------------------------*/ |
| gatedClock | 0:7b8e6b90c874 | 64 | #include "mmSPI_RTOS.h" |
| gatedClock | 0:7b8e6b90c874 | 65 | //==============================================//============================== |
| gatedClock | 0:7b8e6b90c874 | 66 | mmSPI_RTOS::mmSPI_RTOS() // constructor. |
| gatedClock | 0:7b8e6b90c874 | 67 | { |
| gatedClock | 0:7b8e6b90c874 | 68 | allocations(); // object allocations. |
| gatedClock | 0:7b8e6b90c874 | 69 | |
| gatedClock | 0:7b8e6b90c874 | 70 | *pSCLK = 0; // initialize. |
| gatedClock | 0:7b8e6b90c874 | 71 | *pCPUclk = 0; // initialize. |
| gatedClock | 0:7b8e6b90c874 | 72 | ulSPIclkCount = 0; // initialize. |
| gatedClock | 0:7b8e6b90c874 | 73 | ulCPUclkCount = 0; // initialize. |
| gatedClock | 0:7b8e6b90c874 | 74 | } // constructor. |
| gatedClock | 0:7b8e6b90c874 | 75 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 76 | mmSPI_RTOS::~mmSPI_RTOS() // destructor. |
| gatedClock | 0:7b8e6b90c874 | 77 | { |
| gatedClock | 0:7b8e6b90c874 | 78 | // deallocations. |
| gatedClock | 0:7b8e6b90c874 | 79 | if (pMOSI) {delete pMOSI; pMOSI = NULL;} |
| gatedClock | 0:7b8e6b90c874 | 80 | if (pMISO) {delete pMISO; pMISO = NULL;} |
| gatedClock | 0:7b8e6b90c874 | 81 | if (pSCLK) {delete pSCLK; pSCLK = NULL;} |
| gatedClock | 0:7b8e6b90c874 | 82 | if (pCPUclk) {delete pCPUclk; pCPUclk = NULL;} |
| gatedClock | 0:7b8e6b90c874 | 83 | } // destructor. |
| gatedClock | 0:7b8e6b90c874 | 84 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 85 | void mmSPI_RTOS::allocations(void) // object allocations. |
| gatedClock | 0:7b8e6b90c874 | 86 | { |
| gatedClock | 0:7b8e6b90c874 | 87 | pMOSI = new DigitalOut(mmSPI_RTOS_MOSI);// SPI MOSI pin object. |
| gatedClock | 0:7b8e6b90c874 | 88 | if (!pMOSI) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pMOSI. \n\r"); |
| gatedClock | 0:7b8e6b90c874 | 89 | |
| gatedClock | 0:7b8e6b90c874 | 90 | pMISO = new DigitalOut(mmSPI_RTOS_MISO);// SPI MISO pin object. |
| gatedClock | 0:7b8e6b90c874 | 91 | if (!pMISO) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pMISO. \n\r"); |
| gatedClock | 0:7b8e6b90c874 | 92 | |
| gatedClock | 0:7b8e6b90c874 | 93 | pSCLK = new DigitalOut(mmSPI_RTOS_SCLK);// SPI SCLK pin object. |
| gatedClock | 0:7b8e6b90c874 | 94 | if (!pSCLK) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pSCLK. \n\r"); |
| gatedClock | 0:7b8e6b90c874 | 95 | |
| gatedClock | 0:7b8e6b90c874 | 96 | pCPUclk = new DigitalOut(mmCPU_CLK); // SPI SCLK pin object. |
| gatedClock | 0:7b8e6b90c874 | 97 | if (!pCPUclk) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pCPUclk. \n\r"); |
| gatedClock | 0:7b8e6b90c874 | 98 | } // allocations. |
| gatedClock | 0:7b8e6b90c874 | 99 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 100 | // set SPI clock frequency. |
| gatedClock | 0:7b8e6b90c874 | 101 | void mmSPI_RTOS::setSPIfrequency(float fFreq) |
| gatedClock | 0:7b8e6b90c874 | 102 | { |
| gatedClock | 0:7b8e6b90c874 | 103 | fSPIfreq = fFreq; // promote to object scope. |
| gatedClock | 0:7b8e6b90c874 | 104 | if (fSPIfreq < .05) // don't get near divide-by-zero. |
| gatedClock | 0:7b8e6b90c874 | 105 | error("\n\r mmSPI_RTOS::setSPIfrequency : FATAL SPI frequency set too low. \n\r"); |
| gatedClock | 0:7b8e6b90c874 | 106 | fSPIquarterP = (1 / fSPIfreq) / 4; // figure quarter-cycle period. |
| gatedClock | 0:7b8e6b90c874 | 107 | } |
| gatedClock | 0:7b8e6b90c874 | 108 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 109 | // obtain SPI send buffer pointer. |
| gatedClock | 0:7b8e6b90c874 | 110 | void mmSPI_RTOS::setSendBuffer(char * pcSendBuffer) |
| gatedClock | 0:7b8e6b90c874 | 111 | { |
| gatedClock | 0:7b8e6b90c874 | 112 | pcSend = pcSendBuffer; // promote to object scope. |
| gatedClock | 0:7b8e6b90c874 | 113 | } // setSendBuffer. |
| gatedClock | 0:7b8e6b90c874 | 114 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 115 | // obtain SPI receive buffer pointer. |
| gatedClock | 0:7b8e6b90c874 | 116 | void mmSPI_RTOS::setReceiveBuffer(char * pcReceiveBuffer) |
| gatedClock | 0:7b8e6b90c874 | 117 | { |
| gatedClock | 0:7b8e6b90c874 | 118 | pcReceive = pcReceiveBuffer; // promote to object scope. |
| gatedClock | 0:7b8e6b90c874 | 119 | } // setReceiveBuffer. |
| gatedClock | 0:7b8e6b90c874 | 120 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 121 | // obtain number of SPI bytes. |
| gatedClock | 0:7b8e6b90c874 | 122 | void mmSPI_RTOS::setNumberOfBytes(int dNumberOfBytes) |
| gatedClock | 0:7b8e6b90c874 | 123 | { |
| gatedClock | 0:7b8e6b90c874 | 124 | dNumBytes = dNumberOfBytes; // promote to object scope. |
| gatedClock | 0:7b8e6b90c874 | 125 | } // setNumberOfBytes. |
| gatedClock | 0:7b8e6b90c874 | 126 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 127 | /* |
| gatedClock | 0:7b8e6b90c874 | 128 | this method has four 'components' which may be switched on/off by the caller: |
| gatedClock | 0:7b8e6b90c874 | 129 | 1. cPreCPU = 1 means cycle the altera CPU clock once. |
| gatedClock | 0:7b8e6b90c874 | 130 | 2. cPreSPI = 1 means cycle the SPI clock once. |
| gatedClock | 0:7b8e6b90c874 | 131 | 3. cScan = 1 means run a full SPI scan-in/scan-out cycle. |
| gatedClock | 0:7b8e6b90c874 | 132 | 4. cPostCPU = 1 means cycle the alter CPU clock once, then the SPI clock once. |
| gatedClock | 0:7b8e6b90c874 | 133 | |
| gatedClock | 0:7b8e6b90c874 | 134 | in the altera, upon the falling edge of any CPU clock, a load-enable is |
| gatedClock | 0:7b8e6b90c874 | 135 | asserted into the scan registers, such that at the next rising edge of |
| gatedClock | 0:7b8e6b90c874 | 136 | the SPI clock, the scan registers perform a parallel-load of the CPU |
| gatedClock | 0:7b8e6b90c874 | 137 | registers, so that that data can subsequently be scanned back into the mbed |
| gatedClock | 0:7b8e6b90c874 | 138 | via a full SPI scan-in cycle. (this load-enable is turned-off upon the first |
| gatedClock | 0:7b8e6b90c874 | 139 | falling edge of the subsequent SPI clock.) |
| gatedClock | 0:7b8e6b90c874 | 140 | therefore, the regular input switches to this method are (1,1,1,0). |
| gatedClock | 0:7b8e6b90c874 | 141 | this means that the altera CPU clock will cycle, |
| gatedClock | 0:7b8e6b90c874 | 142 | and the result of that CPU operation will be parallel-loaded into the |
| gatedClock | 0:7b8e6b90c874 | 143 | shadow registers for scan into the mbed on the subsequent full-scan cycle. |
| gatedClock | 0:7b8e6b90c874 | 144 | |
| gatedClock | 0:7b8e6b90c874 | 145 | a finer level of sequencing these 'components' is needed by the 'step' method, |
| gatedClock | 0:7b8e6b90c874 | 146 | which is why they are under four-input-parameter control. |
| gatedClock | 0:7b8e6b90c874 | 147 | */ |
| gatedClock | 0:7b8e6b90c874 | 148 | void mmSPI_RTOS::transceive_vector(char cPreCPU, char cPreSPI, char cScan, char cPostCPU) |
| gatedClock | 0:7b8e6b90c874 | 149 | { |
| gatedClock | 0:7b8e6b90c874 | 150 | int dClear; // clear-loop index. |
| gatedClock | 0:7b8e6b90c874 | 151 | int dIndex; // total scan index. |
| gatedClock | 0:7b8e6b90c874 | 152 | int dMosiByteIndex; // SPI-MOSI byte index. |
| gatedClock | 0:7b8e6b90c874 | 153 | int dMosiBitIndex; // SPI-MOSI bit index. |
| gatedClock | 0:7b8e6b90c874 | 154 | int dMisoByteIndex; // SPI-MISO byte index. |
| gatedClock | 0:7b8e6b90c874 | 155 | int dMisoBitIndex; // SPI-MISO bit index. |
| gatedClock | 0:7b8e6b90c874 | 156 | |
| gatedClock | 0:7b8e6b90c874 | 157 | // initializations. these are needed. |
| gatedClock | 0:7b8e6b90c874 | 158 | dIndex = (dNumBytes * 8) - 1; // calculate scan count. |
| gatedClock | 0:7b8e6b90c874 | 159 | dMosiByteIndex = dIndex / 8; // calculate current byte index. |
| gatedClock | 0:7b8e6b90c874 | 160 | dMosiBitIndex = dIndex % 8; // calculate current bit iindex. |
| gatedClock | 0:7b8e6b90c874 | 161 | |
| gatedClock | 0:7b8e6b90c874 | 162 | // clear the SPI receive vector. |
| gatedClock | 0:7b8e6b90c874 | 163 | for (dClear = 0; dClear < dNumBytes; dClear++) pcReceive[dClear] = 0; |
| gatedClock | 0:7b8e6b90c874 | 164 | //--- |
| gatedClock | 0:7b8e6b90c874 | 165 | if (cPreCPU) // if pre-CPU clock. |
| gatedClock | 0:7b8e6b90c874 | 166 | { |
| gatedClock | 0:7b8e6b90c874 | 167 | *pCPUclk = 1; // pulse the CPU clock. |
| gatedClock | 0:7b8e6b90c874 | 168 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 169 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 170 | *pCPUclk = 0; |
| gatedClock | 0:7b8e6b90c874 | 171 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 172 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 173 | ulCPUclkCount++; |
| gatedClock | 0:7b8e6b90c874 | 174 | } // if pre-CPU clock. |
| gatedClock | 0:7b8e6b90c874 | 175 | //--- |
| gatedClock | 0:7b8e6b90c874 | 176 | if (cPreSPI) // if pre-SPI pulse. |
| gatedClock | 0:7b8e6b90c874 | 177 | { |
| gatedClock | 0:7b8e6b90c874 | 178 | *pSCLK = 1; // pulse the SPI clock for parallel load. |
| gatedClock | 0:7b8e6b90c874 | 179 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 180 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 181 | *pSCLK = 0; |
| gatedClock | 0:7b8e6b90c874 | 182 | ulSPIclkCount++; |
| gatedClock | 0:7b8e6b90c874 | 183 | } // if pre-SPI pulse. |
| gatedClock | 0:7b8e6b90c874 | 184 | //--- |
| gatedClock | 0:7b8e6b90c874 | 185 | if (cScan) // if cScan. |
| gatedClock | 0:7b8e6b90c874 | 186 | { |
| gatedClock | 0:7b8e6b90c874 | 187 | // pre-assert MOSI. |
| gatedClock | 0:7b8e6b90c874 | 188 | *pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1; |
| gatedClock | 0:7b8e6b90c874 | 189 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 190 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 191 | |
| gatedClock | 0:7b8e6b90c874 | 192 | |
| gatedClock | 0:7b8e6b90c874 | 193 | // main SPI scan loop. |
| gatedClock | 0:7b8e6b90c874 | 194 | for (dIndex = (dNumBytes * 8) - 1; dIndex >= 0; dIndex--) |
| gatedClock | 0:7b8e6b90c874 | 195 | { |
| gatedClock | 0:7b8e6b90c874 | 196 | dMisoByteIndex = dIndex / 8; |
| gatedClock | 0:7b8e6b90c874 | 197 | dMisoBitIndex = dIndex % 8; |
| gatedClock | 0:7b8e6b90c874 | 198 | pcReceive[dMisoByteIndex] = pcReceive[dMisoByteIndex] | (*pMISO << dMisoBitIndex); |
| gatedClock | 0:7b8e6b90c874 | 199 | *pSCLK = 1; |
| gatedClock | 0:7b8e6b90c874 | 200 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 201 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 202 | *pSCLK = 0; |
| gatedClock | 0:7b8e6b90c874 | 203 | if (dIndex < 0) dIndex = 0; |
| gatedClock | 0:7b8e6b90c874 | 204 | dMosiByteIndex = (dIndex - 1) / 8; |
| gatedClock | 0:7b8e6b90c874 | 205 | dMosiBitIndex = (dIndex - 1) % 8; |
| gatedClock | 0:7b8e6b90c874 | 206 | *pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1; |
| gatedClock | 0:7b8e6b90c874 | 207 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 208 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 209 | ulSPIclkCount++; |
| gatedClock | 0:7b8e6b90c874 | 210 | } // main SPI scan loop. |
| gatedClock | 0:7b8e6b90c874 | 211 | } // if cScan. |
| gatedClock | 0:7b8e6b90c874 | 212 | //--- |
| gatedClock | 0:7b8e6b90c874 | 213 | if (cPostCPU) // if post-CPU pulse. |
| gatedClock | 0:7b8e6b90c874 | 214 | { |
| gatedClock | 0:7b8e6b90c874 | 215 | *pCPUclk = 1; // pulse the CPU clock. |
| gatedClock | 0:7b8e6b90c874 | 216 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 217 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 218 | *pCPUclk = 0; |
| gatedClock | 0:7b8e6b90c874 | 219 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 220 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 221 | ulCPUclkCount++; |
| gatedClock | 0:7b8e6b90c874 | 222 | |
| gatedClock | 0:7b8e6b90c874 | 223 | *pSCLK = 1; // clear-out the SPI parallel-load enable. |
| gatedClock | 0:7b8e6b90c874 | 224 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 225 | wait(fSPIquarterP); |
| gatedClock | 0:7b8e6b90c874 | 226 | *pSCLK = 0; |
| gatedClock | 0:7b8e6b90c874 | 227 | ulSPIclkCount++; |
| gatedClock | 0:7b8e6b90c874 | 228 | } // if post-CPU pulse. |
| gatedClock | 0:7b8e6b90c874 | 229 | } // transceive_vector. |
| gatedClock | 0:7b8e6b90c874 | 230 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 231 | /* |
| gatedClock | 0:7b8e6b90c874 | 232 | cRegister -> CPU_register |
| gatedClock | 0:7b8e6b90c874 | 233 | 0 R0 |
| gatedClock | 0:7b8e6b90c874 | 234 | 1 R1 |
| gatedClock | 0:7b8e6b90c874 | 235 | 2 R2 |
| gatedClock | 0:7b8e6b90c874 | 236 | 3 R3 |
| gatedClock | 0:7b8e6b90c874 | 237 | 4 PC |
| gatedClock | 0:7b8e6b90c874 | 238 | 5 <use write_IR instead> |
| gatedClock | 0:7b8e6b90c874 | 239 | 6 <nothing> |
| gatedClock | 0:7b8e6b90c874 | 240 | 7 <nothing> |
| gatedClock | 0:7b8e6b90c874 | 241 | |
| gatedClock | 0:7b8e6b90c874 | 242 | in order to write to a CPU register, pcSend[7] is set to 0x02, |
| gatedClock | 0:7b8e6b90c874 | 243 | which informs the CPU instruction decoder to decode what we are |
| gatedClock | 0:7b8e6b90c874 | 244 | here scanning into the shadow instruction-register, rather than |
| gatedClock | 0:7b8e6b90c874 | 245 | the CPU instruction decoder decoding the regular instruction-register. |
| gatedClock | 0:7b8e6b90c874 | 246 | here, we set-up pcSend to scan the instruction |
| gatedClock | 0:7b8e6b90c874 | 247 | 'load Rx with immediate data yy', and this is executed on the |
| gatedClock | 0:7b8e6b90c874 | 248 | subsequent CPU clock. |
| gatedClock | 0:7b8e6b90c874 | 249 | |
| gatedClock | 0:7b8e6b90c874 | 250 | said another way, this method writes a value into a CPU register |
| gatedClock | 0:7b8e6b90c874 | 251 | by effectively taking over the CPU and doing a write-register-immediate. |
| gatedClock | 0:7b8e6b90c874 | 252 | */ |
| gatedClock | 0:7b8e6b90c874 | 253 | |
| gatedClock | 0:7b8e6b90c874 | 254 | // write to a CPU register. |
| gatedClock | 0:7b8e6b90c874 | 255 | void mmSPI_RTOS::write_register(char cRegister, char cValue) |
| gatedClock | 0:7b8e6b90c874 | 256 | { |
| gatedClock | 0:7b8e6b90c874 | 257 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 258 | |
| gatedClock | 0:7b8e6b90c874 | 259 | pcSend[7] = 0x02; // mbed sends a command. |
| gatedClock | 0:7b8e6b90c874 | 260 | |
| gatedClock | 0:7b8e6b90c874 | 261 | // align into instruction word. |
| gatedClock | 0:7b8e6b90c874 | 262 | pcSend[1] = ((cRegister & 0x07) << 2) | 0xA0; |
| gatedClock | 0:7b8e6b90c874 | 263 | pcSend[0] = cValue & 0xFF; // immediate value to i.w. |
| gatedClock | 0:7b8e6b90c874 | 264 | |
| gatedClock | 0:7b8e6b90c874 | 265 | transceive_vector(1,1,1,0); // transmit command. |
| gatedClock | 0:7b8e6b90c874 | 266 | |
| gatedClock | 0:7b8e6b90c874 | 267 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 268 | } // write_register. |
| gatedClock | 0:7b8e6b90c874 | 269 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 270 | /* |
| gatedClock | 0:7b8e6b90c874 | 271 | for writing to the instruction-register, this method is used. |
| gatedClock | 0:7b8e6b90c874 | 272 | for reading from the instruction-register, the 'regular' |
| gatedClock | 0:7b8e6b90c874 | 273 | read_register method is used, once for each of the two IR data bytes. |
| gatedClock | 0:7b8e6b90c874 | 274 | |
| gatedClock | 0:7b8e6b90c874 | 275 | unlike method 'write_register', this method works by gating-off the |
| gatedClock | 0:7b8e6b90c874 | 276 | outputs of the CPU instruction decoder, and having the instruction-register |
| gatedClock | 0:7b8e6b90c874 | 277 | content loaded in from the shadow instruction-register. |
| gatedClock | 0:7b8e6b90c874 | 278 | */ |
| gatedClock | 0:7b8e6b90c874 | 279 | // write instruction register. |
| gatedClock | 0:7b8e6b90c874 | 280 | void mmSPI_RTOS::write_IR(char cValueH, char cValueL) |
| gatedClock | 0:7b8e6b90c874 | 281 | { |
| gatedClock | 0:7b8e6b90c874 | 282 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 283 | |
| gatedClock | 0:7b8e6b90c874 | 284 | pcSend[7] = 0x06; // mbed sends a command. |
| gatedClock | 0:7b8e6b90c874 | 285 | |
| gatedClock | 0:7b8e6b90c874 | 286 | pcSend[1] = (cValueH & 0xFF); // load IR shadow with new IR content. |
| gatedClock | 0:7b8e6b90c874 | 287 | pcSend[0] = (cValueL & 0xFF); |
| gatedClock | 0:7b8e6b90c874 | 288 | |
| gatedClock | 0:7b8e6b90c874 | 289 | transceive_vector(1,1,1,0); // transmit command. |
| gatedClock | 0:7b8e6b90c874 | 290 | |
| gatedClock | 0:7b8e6b90c874 | 291 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 292 | } // write instruction register. |
| gatedClock | 0:7b8e6b90c874 | 293 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 294 | /* |
| gatedClock | 0:7b8e6b90c874 | 295 | cRegister -> CPU_register pcReceive |
| gatedClock | 0:7b8e6b90c874 | 296 | 0 -> R0 [6] |
| gatedClock | 0:7b8e6b90c874 | 297 | 1 -> R1 [5] |
| gatedClock | 0:7b8e6b90c874 | 298 | 2 -> R2 [4] |
| gatedClock | 0:7b8e6b90c874 | 299 | 3 -> R3 [3] |
| gatedClock | 0:7b8e6b90c874 | 300 | 4 -> PC [2] |
| gatedClock | 0:7b8e6b90c874 | 301 | 5 -> IR-H [1] |
| gatedClock | 0:7b8e6b90c874 | 302 | 6 -> IR-L [0] |
| gatedClock | 0:7b8e6b90c874 | 303 | 7 -> <never-use> |
| gatedClock | 0:7b8e6b90c874 | 304 | |
| gatedClock | 0:7b8e6b90c874 | 305 | this method works by taking over the instruction decoder as described above, |
| gatedClock | 0:7b8e6b90c874 | 306 | but not issuing any instruction, but the scan registers will parallel-load |
| gatedClock | 0:7b8e6b90c874 | 307 | all of the CPU register data and scan them into pcReceive, where they are |
| gatedClock | 0:7b8e6b90c874 | 308 | picked up below. |
| gatedClock | 0:7b8e6b90c874 | 309 | */ |
| gatedClock | 0:7b8e6b90c874 | 310 | // return content of a CPU register. |
| gatedClock | 0:7b8e6b90c874 | 311 | char mmSPI_RTOS::read_register(char cRegister) |
| gatedClock | 0:7b8e6b90c874 | 312 | { |
| gatedClock | 0:7b8e6b90c874 | 313 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 314 | |
| gatedClock | 0:7b8e6b90c874 | 315 | pcSend[7] = 0x02; // suppress cpu operation. |
| gatedClock | 0:7b8e6b90c874 | 316 | |
| gatedClock | 0:7b8e6b90c874 | 317 | transceive_vector(1,1,1,0); // snap & scan-out reg contents. |
| gatedClock | 0:7b8e6b90c874 | 318 | |
| gatedClock | 0:7b8e6b90c874 | 319 | return (pcReceive[6 - cRegister]); // return the particular reg value. |
| gatedClock | 0:7b8e6b90c874 | 320 | } // read_register. |
| gatedClock | 0:7b8e6b90c874 | 321 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 322 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 323 | /* |
| gatedClock | 0:7b8e6b90c874 | 324 | since the Tk UI often wants to obtain the content of all of the CPU registers, |
| gatedClock | 0:7b8e6b90c874 | 325 | this method may be used to obtain all of them at once, speading up the UI |
| gatedClock | 0:7b8e6b90c874 | 326 | read cycle. |
| gatedClock | 0:7b8e6b90c874 | 327 | |
| gatedClock | 0:7b8e6b90c874 | 328 | pRegisters[6] <- pcReceive[6] = R0 |
| gatedClock | 0:7b8e6b90c874 | 329 | pRegisters[5] <- pcReceive[5] = R1 |
| gatedClock | 0:7b8e6b90c874 | 330 | pRegisters[4] <- pcReceive[4] = R2 |
| gatedClock | 0:7b8e6b90c874 | 331 | pRegisters[3] <- pcReceive[3] = R3 |
| gatedClock | 0:7b8e6b90c874 | 332 | pRegisters[2] <- pcReceive[2] = PC |
| gatedClock | 0:7b8e6b90c874 | 333 | pRegisters[1] <- pcReceive[1] = IR-H |
| gatedClock | 0:7b8e6b90c874 | 334 | pRegisters[0] <- pcReceive[0] = IR-L |
| gatedClock | 0:7b8e6b90c874 | 335 | */ |
| gatedClock | 0:7b8e6b90c874 | 336 | |
| gatedClock | 0:7b8e6b90c874 | 337 | void mmSPI_RTOS::read_all_registers(char * pcRegisters) |
| gatedClock | 0:7b8e6b90c874 | 338 | { |
| gatedClock | 0:7b8e6b90c874 | 339 | int dLoop; // loop index. |
| gatedClock | 0:7b8e6b90c874 | 340 | |
| gatedClock | 0:7b8e6b90c874 | 341 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 342 | |
| gatedClock | 0:7b8e6b90c874 | 343 | pcSend[7] = 0x02; // suppress cpu operation. |
| gatedClock | 0:7b8e6b90c874 | 344 | |
| gatedClock | 0:7b8e6b90c874 | 345 | transceive_vector(1,1,1,0); // snap & scan-out reg contents. |
| gatedClock | 0:7b8e6b90c874 | 346 | |
| gatedClock | 0:7b8e6b90c874 | 347 | // propagate register data. |
| gatedClock | 0:7b8e6b90c874 | 348 | for (dLoop = 0; dLoop < 7; dLoop++) pcRegisters[dLoop] = pcReceive[dLoop]; |
| gatedClock | 0:7b8e6b90c874 | 349 | |
| gatedClock | 0:7b8e6b90c874 | 350 | } // read_all_registers. |
| gatedClock | 0:7b8e6b90c874 | 351 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 352 | /* |
| gatedClock | 0:7b8e6b90c874 | 353 | this method works by taking over the instruction decoder, and issuing |
| gatedClock | 0:7b8e6b90c874 | 354 | the CPU commands which load the MM address/data into {R3,R2,R1} |
| gatedClock | 0:7b8e6b90c874 | 355 | followed by issuing a write-pulse. |
| gatedClock | 0:7b8e6b90c874 | 356 | */ |
| gatedClock | 0:7b8e6b90c874 | 357 | // write a word to main-memory. |
| gatedClock | 0:7b8e6b90c874 | 358 | void mmSPI_RTOS::write_memory(char cHData, char cLdata, char cAddress) |
| gatedClock | 0:7b8e6b90c874 | 359 | { |
| gatedClock | 0:7b8e6b90c874 | 360 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 361 | |
| gatedClock | 0:7b8e6b90c874 | 362 | write_register(0x03,cAddress); // R3 <- address. |
| gatedClock | 0:7b8e6b90c874 | 363 | write_register(0x02,cHData); // R2 <- high-data. |
| gatedClock | 0:7b8e6b90c874 | 364 | write_register(0x01,cLdata); // R1 <- low-data. |
| gatedClock | 0:7b8e6b90c874 | 365 | |
| gatedClock | 0:7b8e6b90c874 | 366 | pcSend[7] = 0x02; // mbed sends command. |
| gatedClock | 0:7b8e6b90c874 | 367 | pcSend[1] = 0x02; // write-enable high. |
| gatedClock | 0:7b8e6b90c874 | 368 | pcSend[0] = 0x00; // remainder of instruction. |
| gatedClock | 0:7b8e6b90c874 | 369 | transceive_vector(1,1,1,0); |
| gatedClock | 0:7b8e6b90c874 | 370 | |
| gatedClock | 0:7b8e6b90c874 | 371 | pcSend[7] = 0x02; // mbed sends command. |
| gatedClock | 0:7b8e6b90c874 | 372 | pcSend[1] = 0x00; // write-enable low. |
| gatedClock | 0:7b8e6b90c874 | 373 | pcSend[0] = 0x00; // remainder of instruction. |
| gatedClock | 0:7b8e6b90c874 | 374 | transceive_vector(1,1,1,0); |
| gatedClock | 0:7b8e6b90c874 | 375 | |
| gatedClock | 0:7b8e6b90c874 | 376 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 377 | } // write_memory. |
| gatedClock | 0:7b8e6b90c874 | 378 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 379 | /* |
| gatedClock | 0:7b8e6b90c874 | 380 | this command works by taking over the instruction decoder, loading |
| gatedClock | 0:7b8e6b90c874 | 381 | R3 with the MM address, then issuing load-from-MM commands so that |
| gatedClock | 0:7b8e6b90c874 | 382 | R2,R1 are loaded with MM[R3], and then reading the result from |
| gatedClock | 0:7b8e6b90c874 | 383 | R1,R2. |
| gatedClock | 0:7b8e6b90c874 | 384 | */ |
| gatedClock | 0:7b8e6b90c874 | 385 | // fetch a word from main memory. |
| gatedClock | 0:7b8e6b90c874 | 386 | unsigned int mmSPI_RTOS::read_memory(char cAddress) |
| gatedClock | 0:7b8e6b90c874 | 387 | { |
| gatedClock | 0:7b8e6b90c874 | 388 | unsigned int udMemoryContent; // return variable. |
| gatedClock | 0:7b8e6b90c874 | 389 | char cHData; // returned data-high. |
| gatedClock | 0:7b8e6b90c874 | 390 | char cLData; // returned data-low. |
| gatedClock | 0:7b8e6b90c874 | 391 | |
| gatedClock | 0:7b8e6b90c874 | 392 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 393 | |
| gatedClock | 0:7b8e6b90c874 | 394 | write_register(0x03,cAddress); // R3 <= address. |
| gatedClock | 0:7b8e6b90c874 | 395 | |
| gatedClock | 0:7b8e6b90c874 | 396 | pcSend[7] = 0x02; // mbed sends command. |
| gatedClock | 0:7b8e6b90c874 | 397 | pcSend[1] = 0xC8; // R2 <- MM[R3] |
| gatedClock | 0:7b8e6b90c874 | 398 | pcSend[0] = 0x00; |
| gatedClock | 0:7b8e6b90c874 | 399 | transceive_vector(1,1,1,0); // send command. |
| gatedClock | 0:7b8e6b90c874 | 400 | |
| gatedClock | 0:7b8e6b90c874 | 401 | pcSend[7] = 0x02; // mbed sends command. |
| gatedClock | 0:7b8e6b90c874 | 402 | pcSend[1] = 0xC4; // R1 <- MM[R3] |
| gatedClock | 0:7b8e6b90c874 | 403 | pcSend[0] = 0x00; |
| gatedClock | 0:7b8e6b90c874 | 404 | transceive_vector(1,1,1,0); // send command. |
| gatedClock | 0:7b8e6b90c874 | 405 | |
| gatedClock | 0:7b8e6b90c874 | 406 | cHData = read_register(0x02); // obtain MM high-data-byte. |
| gatedClock | 0:7b8e6b90c874 | 407 | cLData = read_register(0x01); // obtain MM low-data-byte. |
| gatedClock | 0:7b8e6b90c874 | 408 | |
| gatedClock | 0:7b8e6b90c874 | 409 | udMemoryContent = (cHData << 8) + cLData; // build the memory word. |
| gatedClock | 0:7b8e6b90c874 | 410 | |
| gatedClock | 0:7b8e6b90c874 | 411 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 412 | |
| gatedClock | 0:7b8e6b90c874 | 413 | return udMemoryContent; // return the memory word. |
| gatedClock | 0:7b8e6b90c874 | 414 | } // read_memory. |
| gatedClock | 0:7b8e6b90c874 | 415 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 416 | void mmSPI_RTOS::step(void) // step the CPU. |
| gatedClock | 0:7b8e6b90c874 | 417 | { |
| gatedClock | 0:7b8e6b90c874 | 418 | clear_transmit_vector(); // clear transmit vector. |
| gatedClock | 0:7b8e6b90c874 | 419 | transceive_vector(0,0,1,0); // enable CPU mode. |
| gatedClock | 0:7b8e6b90c874 | 420 | transceive_vector(0,0,0,1); // advance CPU, clear shadow-load. |
| gatedClock | 0:7b8e6b90c874 | 421 | pcSend[7] = 0x02; // ready to disable CPU mode. |
| gatedClock | 0:7b8e6b90c874 | 422 | transceive_vector(0,0,1,0); // disable CPU mode. |
| gatedClock | 0:7b8e6b90c874 | 423 | } // step. |
| gatedClock | 0:7b8e6b90c874 | 424 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 425 | void mmSPI_RTOS::clear_transmit_vector(void)// fill transmit buffer with 0. |
| gatedClock | 0:7b8e6b90c874 | 426 | { |
| gatedClock | 0:7b8e6b90c874 | 427 | int dLoop; |
| gatedClock | 0:7b8e6b90c874 | 428 | for (dLoop = 0; dLoop < dNumBytes; dLoop++) pcSend[dLoop] = 0x00; |
| gatedClock | 0:7b8e6b90c874 | 429 | } // clear_transmit_vector. |
| gatedClock | 0:7b8e6b90c874 | 430 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 431 | // getters. |
| gatedClock | 0:7b8e6b90c874 | 432 | unsigned long mmSPI_RTOS::SPIClockCount() {return ulSPIclkCount;} |
| gatedClock | 0:7b8e6b90c874 | 433 | unsigned long mmSPI_RTOS::CPUClockCount() {return ulCPUclkCount;} |
| gatedClock | 0:7b8e6b90c874 | 434 | //----------------------------------------------//------------------------------ |
| gatedClock | 0:7b8e6b90c874 | 435 | |
| gatedClock | 0:7b8e6b90c874 | 436 | |
| gatedClock | 0:7b8e6b90c874 | 437 | |
| gatedClock | 0:7b8e6b90c874 | 438 | |
| gatedClock | 0:7b8e6b90c874 | 439 | |
| gatedClock | 0:7b8e6b90c874 | 440 | |
| gatedClock | 0:7b8e6b90c874 | 441 | |
| gatedClock | 0:7b8e6b90c874 | 442 |