SPI library used to communicate with an altera development board attached to four zigbee-header pins.

mmSPI.cpp

Committer:
gatedClock
Date:
2013-08-26
Revision:
32:5a5d9525c6c4
Parent:
31:ea7b25e494b5
Child:
33:59e13ec04ea8
Child:
34:d5553509f31a

File content as of revision 32:5a5d9525c6c4:

/*----------------------------------------------//------------------------------
    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         <meta, don't do>
//      6         <nothing>
//      7         <nothing>

    void mmSPI::write_register(char cRegister, char cValue)
    {     
      int dLoop;                                // loop index.
      
      clear_transmit_vector();                  // clear transmit vector.
      
      pcSend[7] = 0x02;                         // mbed sends a command.
      
                                                // 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;}
//----------------------------------------------//------------------------------