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
00001 /*----------------------------------------------//------------------------------ 00002 student : m-moore 00003 email : gated.clock@gmail.com 00004 class : embedded RTOS 00005 directory : URTOS_project/mmSPI_RTOS 00006 file : mmSPI_RTOS.cpp 00007 date : september 19, 2013. 00008 ----copyright-----------------------------------//------------------------------ 00009 licensed for personal and academic use. 00010 commercial use of original code must be approved by the account-holder of 00011 gated.clock@gmail.com 00012 ----description---------------------------------//------------------------------ 00013 this library provides the low-level SPI data and clock signaling 00014 for communication with the altera development board, via four i/o 00015 pins available on the mbed development board's zigbee header. 00016 00017 this library also provides higher-level calls to send/receive register 00018 and main-memory data to/from the CPU implemented in the altera. 00019 00020 the SPI clock and the CPU clock are both built by this library. 00021 00022 the SPI clock (*pSCLK) is generated with quarter-phase resolution, 00023 although at the moment, only half-phase resolution is being used. 00024 00025 within the FPGA, the SPI scan registers are called 'shadow registers' 00026 because they parallel load-to/store-from the CPU registers. 00027 00028 character vectors pcSend and pcReceive are used to scan-in and scan-out 00029 to/from the altera shadow registers. note that the prefix 'pc' means 00030 'pointer-of-type-character' and not 'personal-computer'. 00031 00032 the shadow registers in the altera are arranged as follows: 00033 00034 <-- MISO (altera-out to mbed-in) 00035 ^ 00036 | 00037 scan_08 U14_spi_control = pcSend/pcReceive[7] 00038 scan_08 U08_shadowR0 = pcSend/pcReceive[6] 00039 scan_08 U09_shadowR1 = pcSend/pcReceive[5] 00040 scan_08 U10_shadowR2 = pcSend/pcReceive[4] 00041 scan_08 U11_shadowR3 = pcSend/pcReceive[3] 00042 scan_08 U12_shadowPC = pcSend/pcReceive[2] 00043 scan_16 U13_shadowIR = pcSend/pcReceive[1:0] 00044 ^ 00045 | 00046 --> MOSI (altera-in from mbed-out) 00047 00048 when U14_spi_control<1> is high, the mbed takes over CPU operation. 00049 this means that the CPU instruction decoder decodes U13_shadowIR 00050 rather than the CPU's actual IR. 00051 00052 when U14_spi_control<2> is high, the mbed writes into the IR. 00053 this means that the CPU instruction decoder load-enable outputs 00054 are gated-off so that the mbed may write into the instrucition 00055 register without immediate consequence in the CPU. writing to 00056 the IR this way is more for the ability to show that it can be done, 00057 rather than any likely useful purpose. 00058 00059 debug/test: 00060 this library was debugged by using the altera FPGA logic analyzer 00061 known as 'signal tap'. the main program uses all of the memory and 00062 register access calls, which were used as an informal unit test. 00063 -----includes-----------------------------------//----------------------------*/ 00064 #include "mmSPI_RTOS.h" 00065 //==============================================//============================== 00066 mmSPI_RTOS::mmSPI_RTOS() // constructor. 00067 { 00068 allocations(); // object allocations. 00069 00070 *pSCLK = 0; // initialize. 00071 *pCPUclk = 0; // initialize. 00072 ulSPIclkCount = 0; // initialize. 00073 ulCPUclkCount = 0; // initialize. 00074 } // constructor. 00075 //----------------------------------------------//------------------------------ 00076 mmSPI_RTOS::~mmSPI_RTOS() // destructor. 00077 { 00078 // deallocations. 00079 if (pMOSI) {delete pMOSI; pMOSI = NULL;} 00080 if (pMISO) {delete pMISO; pMISO = NULL;} 00081 if (pSCLK) {delete pSCLK; pSCLK = NULL;} 00082 if (pCPUclk) {delete pCPUclk; pCPUclk = NULL;} 00083 } // destructor. 00084 //----------------------------------------------//------------------------------ 00085 void mmSPI_RTOS::allocations(void) // object allocations. 00086 { 00087 pMOSI = new DigitalOut(mmSPI_RTOS_MOSI);// SPI MOSI pin object. 00088 if (!pMOSI) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pMOSI. \n\r"); 00089 00090 pMISO = new DigitalOut(mmSPI_RTOS_MISO);// SPI MISO pin object. 00091 if (!pMISO) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pMISO. \n\r"); 00092 00093 pSCLK = new DigitalOut(mmSPI_RTOS_SCLK);// SPI SCLK pin object. 00094 if (!pSCLK) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pSCLK. \n\r"); 00095 00096 pCPUclk = new DigitalOut(mmCPU_CLK); // SPI SCLK pin object. 00097 if (!pCPUclk) error("\n\r mmSPI_RTOS::allocations : FATAL malloc error for pCPUclk. \n\r"); 00098 } // allocations. 00099 //----------------------------------------------//------------------------------ 00100 // set SPI clock frequency. 00101 void mmSPI_RTOS::setSPIfrequency(float fFreq) 00102 { 00103 fSPIfreq = fFreq; // promote to object scope. 00104 if (fSPIfreq < .05) // don't get near divide-by-zero. 00105 error("\n\r mmSPI_RTOS::setSPIfrequency : FATAL SPI frequency set too low. \n\r"); 00106 fSPIquarterP = (1 / fSPIfreq) / 4; // figure quarter-cycle period. 00107 } 00108 //----------------------------------------------//------------------------------ 00109 // obtain SPI send buffer pointer. 00110 void mmSPI_RTOS::setSendBuffer(char * pcSendBuffer) 00111 { 00112 pcSend = pcSendBuffer; // promote to object scope. 00113 } // setSendBuffer. 00114 //----------------------------------------------//------------------------------ 00115 // obtain SPI receive buffer pointer. 00116 void mmSPI_RTOS::setReceiveBuffer(char * pcReceiveBuffer) 00117 { 00118 pcReceive = pcReceiveBuffer; // promote to object scope. 00119 } // setReceiveBuffer. 00120 //----------------------------------------------//------------------------------ 00121 // obtain number of SPI bytes. 00122 void mmSPI_RTOS::setNumberOfBytes(int dNumberOfBytes) 00123 { 00124 dNumBytes = dNumberOfBytes; // promote to object scope. 00125 } // setNumberOfBytes. 00126 //----------------------------------------------//------------------------------ 00127 /* 00128 this method has four 'components' which may be switched on/off by the caller: 00129 1. cPreCPU = 1 means cycle the altera CPU clock once. 00130 2. cPreSPI = 1 means cycle the SPI clock once. 00131 3. cScan = 1 means run a full SPI scan-in/scan-out cycle. 00132 4. cPostCPU = 1 means cycle the alter CPU clock once, then the SPI clock once. 00133 00134 in the altera, upon the falling edge of any CPU clock, a load-enable is 00135 asserted into the scan registers, such that at the next rising edge of 00136 the SPI clock, the scan registers perform a parallel-load of the CPU 00137 registers, so that that data can subsequently be scanned back into the mbed 00138 via a full SPI scan-in cycle. (this load-enable is turned-off upon the first 00139 falling edge of the subsequent SPI clock.) 00140 therefore, the regular input switches to this method are (1,1,1,0). 00141 this means that the altera CPU clock will cycle, 00142 and the result of that CPU operation will be parallel-loaded into the 00143 shadow registers for scan into the mbed on the subsequent full-scan cycle. 00144 00145 a finer level of sequencing these 'components' is needed by the 'step' method, 00146 which is why they are under four-input-parameter control. 00147 */ 00148 void mmSPI_RTOS::transceive_vector(char cPreCPU, char cPreSPI, char cScan, char cPostCPU) 00149 { 00150 int dClear; // clear-loop index. 00151 int dIndex; // total scan index. 00152 int dMosiByteIndex; // SPI-MOSI byte index. 00153 int dMosiBitIndex; // SPI-MOSI bit index. 00154 int dMisoByteIndex; // SPI-MISO byte index. 00155 int dMisoBitIndex; // SPI-MISO bit index. 00156 00157 // initializations. these are needed. 00158 dIndex = (dNumBytes * 8) - 1; // calculate scan count. 00159 dMosiByteIndex = dIndex / 8; // calculate current byte index. 00160 dMosiBitIndex = dIndex % 8; // calculate current bit iindex. 00161 00162 // clear the SPI receive vector. 00163 for (dClear = 0; dClear < dNumBytes; dClear++) pcReceive[dClear] = 0; 00164 //--- 00165 if (cPreCPU) // if pre-CPU clock. 00166 { 00167 *pCPUclk = 1; // pulse the CPU clock. 00168 wait(fSPIquarterP); 00169 wait(fSPIquarterP); 00170 *pCPUclk = 0; 00171 wait(fSPIquarterP); 00172 wait(fSPIquarterP); 00173 ulCPUclkCount++; 00174 } // if pre-CPU clock. 00175 //--- 00176 if (cPreSPI) // if pre-SPI pulse. 00177 { 00178 *pSCLK = 1; // pulse the SPI clock for parallel load. 00179 wait(fSPIquarterP); 00180 wait(fSPIquarterP); 00181 *pSCLK = 0; 00182 ulSPIclkCount++; 00183 } // if pre-SPI pulse. 00184 //--- 00185 if (cScan) // if cScan. 00186 { 00187 // pre-assert MOSI. 00188 *pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1; 00189 wait(fSPIquarterP); 00190 wait(fSPIquarterP); 00191 00192 00193 // main SPI scan loop. 00194 for (dIndex = (dNumBytes * 8) - 1; dIndex >= 0; dIndex--) 00195 { 00196 dMisoByteIndex = dIndex / 8; 00197 dMisoBitIndex = dIndex % 8; 00198 pcReceive[dMisoByteIndex] = pcReceive[dMisoByteIndex] | (*pMISO << dMisoBitIndex); 00199 *pSCLK = 1; 00200 wait(fSPIquarterP); 00201 wait(fSPIquarterP); 00202 *pSCLK = 0; 00203 if (dIndex < 0) dIndex = 0; 00204 dMosiByteIndex = (dIndex - 1) / 8; 00205 dMosiBitIndex = (dIndex - 1) % 8; 00206 *pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1; 00207 wait(fSPIquarterP); 00208 wait(fSPIquarterP); 00209 ulSPIclkCount++; 00210 } // main SPI scan loop. 00211 } // if cScan. 00212 //--- 00213 if (cPostCPU) // if post-CPU pulse. 00214 { 00215 *pCPUclk = 1; // pulse the CPU clock. 00216 wait(fSPIquarterP); 00217 wait(fSPIquarterP); 00218 *pCPUclk = 0; 00219 wait(fSPIquarterP); 00220 wait(fSPIquarterP); 00221 ulCPUclkCount++; 00222 00223 *pSCLK = 1; // clear-out the SPI parallel-load enable. 00224 wait(fSPIquarterP); 00225 wait(fSPIquarterP); 00226 *pSCLK = 0; 00227 ulSPIclkCount++; 00228 } // if post-CPU pulse. 00229 } // transceive_vector. 00230 //----------------------------------------------//------------------------------ 00231 /* 00232 cRegister -> CPU_register 00233 0 R0 00234 1 R1 00235 2 R2 00236 3 R3 00237 4 PC 00238 5 <use write_IR instead> 00239 6 <nothing> 00240 7 <nothing> 00241 00242 in order to write to a CPU register, pcSend[7] is set to 0x02, 00243 which informs the CPU instruction decoder to decode what we are 00244 here scanning into the shadow instruction-register, rather than 00245 the CPU instruction decoder decoding the regular instruction-register. 00246 here, we set-up pcSend to scan the instruction 00247 'load Rx with immediate data yy', and this is executed on the 00248 subsequent CPU clock. 00249 00250 said another way, this method writes a value into a CPU register 00251 by effectively taking over the CPU and doing a write-register-immediate. 00252 */ 00253 00254 // write to a CPU register. 00255 void mmSPI_RTOS::write_register(char cRegister, char cValue) 00256 { 00257 clear_transmit_vector(); // clear transmit vector. 00258 00259 pcSend[7] = 0x02; // mbed sends a command. 00260 00261 // align into instruction word. 00262 pcSend[1] = ((cRegister & 0x07) << 2) | 0xA0; 00263 pcSend[0] = cValue & 0xFF; // immediate value to i.w. 00264 00265 transceive_vector(1,1,1,0); // transmit command. 00266 00267 clear_transmit_vector(); // clear transmit vector. 00268 } // write_register. 00269 //----------------------------------------------//------------------------------ 00270 /* 00271 for writing to the instruction-register, this method is used. 00272 for reading from the instruction-register, the 'regular' 00273 read_register method is used, once for each of the two IR data bytes. 00274 00275 unlike method 'write_register', this method works by gating-off the 00276 outputs of the CPU instruction decoder, and having the instruction-register 00277 content loaded in from the shadow instruction-register. 00278 */ 00279 // write instruction register. 00280 void mmSPI_RTOS::write_IR(char cValueH, char cValueL) 00281 { 00282 clear_transmit_vector(); // clear transmit vector. 00283 00284 pcSend[7] = 0x06; // mbed sends a command. 00285 00286 pcSend[1] = (cValueH & 0xFF); // load IR shadow with new IR content. 00287 pcSend[0] = (cValueL & 0xFF); 00288 00289 transceive_vector(1,1,1,0); // transmit command. 00290 00291 clear_transmit_vector(); // clear transmit vector. 00292 } // write instruction register. 00293 //----------------------------------------------//------------------------------ 00294 /* 00295 cRegister -> CPU_register pcReceive 00296 0 -> R0 [6] 00297 1 -> R1 [5] 00298 2 -> R2 [4] 00299 3 -> R3 [3] 00300 4 -> PC [2] 00301 5 -> IR-H [1] 00302 6 -> IR-L [0] 00303 7 -> <never-use> 00304 00305 this method works by taking over the instruction decoder as described above, 00306 but not issuing any instruction, but the scan registers will parallel-load 00307 all of the CPU register data and scan them into pcReceive, where they are 00308 picked up below. 00309 */ 00310 // return content of a CPU register. 00311 char mmSPI_RTOS::read_register(char cRegister) 00312 { 00313 clear_transmit_vector(); // clear transmit vector. 00314 00315 pcSend[7] = 0x02; // suppress cpu operation. 00316 00317 transceive_vector(1,1,1,0); // snap & scan-out reg contents. 00318 00319 return (pcReceive[6 - cRegister]); // return the particular reg value. 00320 } // read_register. 00321 //----------------------------------------------//------------------------------ 00322 //----------------------------------------------//------------------------------ 00323 /* 00324 since the Tk UI often wants to obtain the content of all of the CPU registers, 00325 this method may be used to obtain all of them at once, speading up the UI 00326 read cycle. 00327 00328 pRegisters[6] <- pcReceive[6] = R0 00329 pRegisters[5] <- pcReceive[5] = R1 00330 pRegisters[4] <- pcReceive[4] = R2 00331 pRegisters[3] <- pcReceive[3] = R3 00332 pRegisters[2] <- pcReceive[2] = PC 00333 pRegisters[1] <- pcReceive[1] = IR-H 00334 pRegisters[0] <- pcReceive[0] = IR-L 00335 */ 00336 00337 void mmSPI_RTOS::read_all_registers(char * pcRegisters) 00338 { 00339 int dLoop; // loop index. 00340 00341 clear_transmit_vector(); // clear transmit vector. 00342 00343 pcSend[7] = 0x02; // suppress cpu operation. 00344 00345 transceive_vector(1,1,1,0); // snap & scan-out reg contents. 00346 00347 // propagate register data. 00348 for (dLoop = 0; dLoop < 7; dLoop++) pcRegisters[dLoop] = pcReceive[dLoop]; 00349 00350 } // read_all_registers. 00351 //----------------------------------------------//------------------------------ 00352 /* 00353 this method works by taking over the instruction decoder, and issuing 00354 the CPU commands which load the MM address/data into {R3,R2,R1} 00355 followed by issuing a write-pulse. 00356 */ 00357 // write a word to main-memory. 00358 void mmSPI_RTOS::write_memory(char cHData, char cLdata, char cAddress) 00359 { 00360 clear_transmit_vector(); // clear transmit vector. 00361 00362 write_register(0x03,cAddress); // R3 <- address. 00363 write_register(0x02,cHData); // R2 <- high-data. 00364 write_register(0x01,cLdata); // R1 <- low-data. 00365 00366 pcSend[7] = 0x02; // mbed sends command. 00367 pcSend[1] = 0x02; // write-enable high. 00368 pcSend[0] = 0x00; // remainder of instruction. 00369 transceive_vector(1,1,1,0); 00370 00371 pcSend[7] = 0x02; // mbed sends command. 00372 pcSend[1] = 0x00; // write-enable low. 00373 pcSend[0] = 0x00; // remainder of instruction. 00374 transceive_vector(1,1,1,0); 00375 00376 clear_transmit_vector(); // clear transmit vector. 00377 } // write_memory. 00378 //----------------------------------------------//------------------------------ 00379 /* 00380 this command works by taking over the instruction decoder, loading 00381 R3 with the MM address, then issuing load-from-MM commands so that 00382 R2,R1 are loaded with MM[R3], and then reading the result from 00383 R1,R2. 00384 */ 00385 // fetch a word from main memory. 00386 unsigned int mmSPI_RTOS::read_memory(char cAddress) 00387 { 00388 unsigned int udMemoryContent; // return variable. 00389 char cHData; // returned data-high. 00390 char cLData; // returned data-low. 00391 00392 clear_transmit_vector(); // clear transmit vector. 00393 00394 write_register(0x03,cAddress); // R3 <= address. 00395 00396 pcSend[7] = 0x02; // mbed sends command. 00397 pcSend[1] = 0xC8; // R2 <- MM[R3] 00398 pcSend[0] = 0x00; 00399 transceive_vector(1,1,1,0); // send command. 00400 00401 pcSend[7] = 0x02; // mbed sends command. 00402 pcSend[1] = 0xC4; // R1 <- MM[R3] 00403 pcSend[0] = 0x00; 00404 transceive_vector(1,1,1,0); // send command. 00405 00406 cHData = read_register(0x02); // obtain MM high-data-byte. 00407 cLData = read_register(0x01); // obtain MM low-data-byte. 00408 00409 udMemoryContent = (cHData << 8) + cLData; // build the memory word. 00410 00411 clear_transmit_vector(); // clear transmit vector. 00412 00413 return udMemoryContent; // return the memory word. 00414 } // read_memory. 00415 //----------------------------------------------//------------------------------ 00416 void mmSPI_RTOS::step(void) // step the CPU. 00417 { 00418 clear_transmit_vector(); // clear transmit vector. 00419 transceive_vector(0,0,1,0); // enable CPU mode. 00420 transceive_vector(0,0,0,1); // advance CPU, clear shadow-load. 00421 pcSend[7] = 0x02; // ready to disable CPU mode. 00422 transceive_vector(0,0,1,0); // disable CPU mode. 00423 } // step. 00424 //----------------------------------------------//------------------------------ 00425 void mmSPI_RTOS::clear_transmit_vector(void)// fill transmit buffer with 0. 00426 { 00427 int dLoop; 00428 for (dLoop = 0; dLoop < dNumBytes; dLoop++) pcSend[dLoop] = 0x00; 00429 } // clear_transmit_vector. 00430 //----------------------------------------------//------------------------------ 00431 // getters. 00432 unsigned long mmSPI_RTOS::SPIClockCount() {return ulSPIclkCount;} 00433 unsigned long mmSPI_RTOS::CPUClockCount() {return ulCPUclkCount;} 00434 //----------------------------------------------//------------------------------ 00435 00436 00437 00438 00439 00440 00441 00442
Generated on Wed Jul 13 2022 14:48:55 by
1.7.2