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.
mmSPI.cpp
- Committer:
- gatedClock
- Date:
- 2013-08-30
- Revision:
- 33:59e13ec04ea8
- Parent:
- 32:5a5d9525c6c4
File content as of revision 33:59e13ec04ea8:
/*----------------------------------------------//------------------------------
student : m-moore
email : gated.clock@gmail.com
class : usb device drivers
directory : mmSPI
file : mmSPI.cpp
date : september 3, 2013.
------------------------------------------------//----------------------------*/
#include "mmSPI.h"
/*----------------------------------------------//------------------------------
------------------------------------------------//----------------------------*/
//==============================================//==============================
mmSPI::mmSPI() // constructor.
{
allocations(); // object allocations.
*pSCLK = 0; // initialize.
*pCPUclk = 0; // initialize.
ulSPIclkCount = 0; // initialize.
ulCPUclkCount = 0; // initialize.
} // constructor.
//----------------------------------------------//------------------------------
mmSPI::~mmSPI() // destructor.
{
// deallocations.
if (pMOSI) {delete pMOSI; pMOSI = NULL;}
if (pMISO) {delete pMISO; pMISO = NULL;}
if (pSCLK) {delete pSCLK; pSCLK = NULL;}
if (pCPUclk) {delete pCPUclk; pCPUclk = NULL;}
} // destructor.
//----------------------------------------------//------------------------------
void mmSPI::allocations(void) // object allocations.
{
pMOSI = new DigitalOut(mmSPI_MOSI); // SPI MOSI pin object.
if (!pMOSI) error("\n\r mmSPI::allocations : FATAL malloc error for pMOSI. \n\r");
pMISO = new DigitalOut(mmSPI_MISO); // SPI MISO pin object.
if (!pMISO) error("\n\r mmSPI::allocations : FATAL malloc error for pMISO. \n\r");
pSCLK = new DigitalOut(mmSPI_SCLK); // SPI SCLK pin object.
if (!pSCLK) error("\n\r mmSPI::allocations : FATAL malloc error for pSCLK. \n\r");
pCPUclk = new DigitalOut(mmCPU_CLK); // SPI SCLK pin object.
if (!pCPUclk) error("\n\r mmSPI::allocations : FATAL malloc error for pCPUclk. \n\r");
} // allocations.
//----------------------------------------------//------------------------------
void mmSPI::setSPIfrequency(float fFreq) // set SPI clock frequency.
{
fSPIfreq = fFreq; // promote to object scope.
if (fSPIfreq < .05) // don't get near divide-by-zero.
error("\n\r mmSPI::setSPIfrequency : FATAL SPI frequency set too low. \n\r");
fSPIquarterP = (1 / fSPIfreq) / 4; // figure quarter-cycle period.
}
//----------------------------------------------//------------------------------
// obtain SPI send buffer pointer.
void mmSPI::setSendBuffer(char * pcSendBuffer)
{
pcSend = pcSendBuffer; // promote to object scope.
} // setSendBuffer.
//----------------------------------------------//------------------------------
// obtain SPI receive buffer pointer.
void mmSPI::setReceiveBuffer(char * pcReceiveBuffer)
{
pcReceive = pcReceiveBuffer; // promote to object scope.
} // setReceiveBuffer.
//----------------------------------------------//------------------------------
// obtain number of SPI bytes.
void mmSPI::setNumberOfBytes(int dNumberOfBytes)
{
dNumBytes = dNumberOfBytes; // promote to object scope.
} // setNumberOfBytes.
//----------------------------------------------//------------------------------
// transceive a character array.
// MSB out/in first.
// normal inputs: [1,1,1,0]
// CPUstep input : [0,0,1,1]
void mmSPI::transceive_vector(char cPreCPU, char cPreSPI, char cScan, char cPostCPU)
{
int dClear;
int dIndex;
int dMosiByteIndex;
int dMosiBitIndex;
int dMisoByteIndex;
int dMisoBitIndex;
dIndex = (dNumBytes * 8) - 1;
dMosiByteIndex = dIndex / 8;
dMosiBitIndex = dIndex % 8;
for (dClear = 0; dClear < dNumBytes; dClear++) pcReceive[dClear] = 0;
if (cPreCPU) // if pre-CPU clock.
{
*pCPUclk = 1; // pulse the CPU clock.
wait(fSPIquarterP);
wait(fSPIquarterP);
*pCPUclk = 0;
wait(fSPIquarterP);
wait(fSPIquarterP);
ulCPUclkCount++;
} // if pre-CPU clock.
if (cPreSPI) // if pre-SPI pulse.
{
*pSCLK = 1; // pulse the SPI clock for parallel load.
wait(fSPIquarterP);
wait(fSPIquarterP);
*pSCLK = 0;
ulSPIclkCount++;
} // if pre-SPI pulse.
if (cScan) // if cScan.
{
// pre-assert MOSI.
*pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1;
wait(fSPIquarterP);
wait(fSPIquarterP);
// main SPI scan loop.
for (dIndex = (dNumBytes * 8) - 1; dIndex >= 0; dIndex--)
{
dMisoByteIndex = dIndex / 8;
dMisoBitIndex = dIndex % 8;
pcReceive[dMisoByteIndex] = pcReceive[dMisoByteIndex] | (*pMISO << dMisoBitIndex);
*pSCLK = 1;
wait(fSPIquarterP);
wait(fSPIquarterP);
*pSCLK = 0;
if (dIndex < 0) dIndex = 0;
dMosiByteIndex = (dIndex - 1) / 8;
dMosiBitIndex = (dIndex - 1) % 8;
*pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1;
wait(fSPIquarterP);
wait(fSPIquarterP);
ulSPIclkCount++;
} // main SPI scan loop.
} // if cScan.
if (cPostCPU) // if post-CPU pulse.
{
*pCPUclk = 1; // pulse the CPU clock.
wait(fSPIquarterP);
wait(fSPIquarterP);
*pCPUclk = 0;
wait(fSPIquarterP);
wait(fSPIquarterP);
ulCPUclkCount++;
*pSCLK = 1; // clear-out the SPI parallel-load enable.
wait(fSPIquarterP);
wait(fSPIquarterP);
*pSCLK = 0;
ulSPIclkCount++;
} // if post-CPU pulse.
} // transceive_vector.
//----------------------------------------------//------------------------------
// cRegister -> CPU_register
// 0 R0
// 1 R1
// 2 R2
// 3 R3
// 4 PC
// 5 IR
// 6 <nothing>
// 7 <nothing>
void mmSPI::write_register(char cRegister, char cValue)
{
int dLoop; // loop index.
clear_transmit_vector(); // clear transmit vector.
switch(cRegister)
{
case 5 : {pcSend[7] = 0x02; break;} // write IR-L.
case 6 : {pcSend[7] = 0x0A; break;} // write IR-H.
default: {pcSend[7] = 0x02; break;} // other register writes.
}
// align into instruction word.
pcSend[1] = ((cRegister & 0x07) << 2) | 0xA0;
pcSend[0] = cValue & 0xFF; // immediate value to i.w.
transceive_vector(1,1,1,0); // transmit command.
clear_transmit_vector(); // clear transmit vector.
} // write_register.
//----------------------------------------------//------------------------------
// cRegister -> CPU_register
// 0 -> R0
// 1 -> R1
// 2 -> R2
// 3 -> R3
// 4 -> PC
// 5 -> IR-H
// 6 -> IR-L
// 7 -> <never-use>
// returns the content of
// a CPU register.
char mmSPI::read_register(char cRegister)
{
clear_transmit_vector(); // clear transmit vector.
pcSend[7] = 0x02; // suppress cpu operation.
transceive_vector(1,1,1,0); // snap & scan-out reg contents.
return (pcReceive[6 - cRegister]); // return the particular reg value.
} // read_register.
//----------------------------------------------//------------------------------
void mmSPI::write_memory(char cHData, char cLdata, char cAddress)
{
clear_transmit_vector(); // clear transmit vector.
write_register(0x03,cAddress); // R3 <- address.
write_register(0x02,cHData); // R2 <- high-data.
write_register(0x01,cLdata); // R1 <- low-data.
pcSend[7] = 0x02; // mbed sends command.
pcSend[1] = 0x02; // write-enable high.
pcSend[0] = 0x00; // remainder of instruction.
transceive_vector(1,1,1,0);
pcSend[7] = 0x02; // mbed sends command.
pcSend[1] = 0x00; // write-enable low.
pcSend[0] = 0x00; // remainder of instruction.
transceive_vector(1,1,1,0);
clear_transmit_vector(); // clear transmit vector.
} // write_memory.
//----------------------------------------------//------------------------------
// fetch a word from main memory.
unsigned int mmSPI::read_memory(char cAddress)
{
unsigned int udMemoryContent; // return variable.
char cHData; // returned data-high.
char cLData; // returned data-low.
clear_transmit_vector(); // clear transmit vector.
write_register(0x03,cAddress); // R3 <= address.
pcSend[7] = 0x02; // mbed sends command.
pcSend[1] = 0xC8; // R2 <- MM[R3]
pcSend[0] = 0x00;
transceive_vector(1,1,1,0); // send command.
pcSend[7] = 0x02; // mbed sends command.
pcSend[1] = 0xC4; // R1 <- MM[R3]
pcSend[0] = 0x00;
transceive_vector(1,1,1,0); // send command.
cHData = read_register(0x02); // obtain MM high-data-byte.
cLData = read_register(0x01); // obtain MM low-data-byte.
udMemoryContent = (cHData << 8) + cLData; // build the memory word.
clear_transmit_vector(); // clear transmit vector.
return udMemoryContent; // return the memory word.
} // read_memory.
//----------------------------------------------//------------------------------
void mmSPI::step(void) // step the CPU.
{
clear_transmit_vector(); // clear transmit vector.
transceive_vector(0,0,1,0); // enable CPU mode.
transceive_vector(0,0,0,1); // advance CPU, clear shadow-load.
pcSend[7] = 0x02; // ready to disable CPU mode.
transceive_vector(0,0,1,0); // disable CPU mode.
} // step.
//----------------------------------------------//------------------------------
void mmSPI::clear_transmit_vector(void) // fill transmit buffer with 0.
{
int dLoop;
for (dLoop = 0; dLoop < dNumBytes; dLoop++) pcSend[dLoop] = 0x00;
} // clear_transmit_vector.
//----------------------------------------------//------------------------------
// getters.
unsigned long mmSPI::SPIClockCount() {return ulSPIclkCount;}
unsigned long mmSPI::CPUClockCount() {return ulCPUclkCount;}
//----------------------------------------------//------------------------------