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