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

mmSPI.cpp

Committer:
gatedClock
Date:
2013-08-19
Revision:
18:4a29cad91540
Parent:
17:b81c0c1f312f
Child:
19:c2b753533b93

File content as of revision 18:4a29cad91540:

/*----------------------------------------------//------------------------------
    student   : m-moore
    class     : external SPI interface
    directory : mmSPI
    file      : mmSPI.cpp
------------------------------------------------//----------------------------*/
    #include "mmSPI.h"
/*----------------------------------------------//------------------------------
------------------------------------------------//----------------------------*/
//==============================================//==============================
//  consider resetting the fpga around here, because
//  the micro may be wiggling these signals before here.
    mmSPI::mmSPI()                              // constructor.
    {
      allocations();                            // object allocations.
      
      *pSCLK   = 0;                             // initialize.
      *pCPUclk = 0;                             // initialize.
    }
//----------------------------------------------//------------------------------    
    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;}
    } 
//----------------------------------------------//------------------------------
    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");
    } 
//----------------------------------------------//------------------------------    
    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.
    }
//----------------------------------------------//------------------------------
//  we're not going for speed, so lets go for good setup / hold.

                                                // send/receive a byte over SPI.
                                                // MSB out/in first.
    void mmSPI::transceive_byte(char *cReceive, char *cSend)
    {
      *cReceive = 0;                            // clear receive byte.                                    
      for (dLoop01 = 7; dLoop01 >= 0; dLoop01--)// loop for 8 bits in the byte.
      {
        *pSCLK = 0;                             // SPI clock negedge.
        wait(fSPIquarterP);                     // until middle of clock low.
        *pMOSI = (*cSend >> dLoop01) & 1;       // assert MOSI.
                                                // capture MISO.
        *cReceive = *cReceive | (*pMISO << dLoop01);        
        wait(fSPIquarterP);                     // finish-out cycle.
        *pSCLK = 1;                             // SPI clock posedge.
        wait(fSPIquarterP);                     // finish-out cycle.
        wait(fSPIquarterP);                     // finish-out cycle.
      }
    }
//----------------------------------------------//------------------------------
                                                // transceive a character array.
                                                // limit is 256 characters.
                                                // MSB out/in first.
    void mmSPI::transceive_vector(char *cReceive, char *cSend, char cNumBytes)
    {       
    

    
      for (dLoop02 = (cNumBytes - 1); dLoop02 >= 0; dLoop02--)
      transceive_byte(&(cReceive[dLoop02]), &(cSend[dLoop02]));
      
   
      
      *pCPUclk = 1;                             // pulse the CPU clock.
      wait(fSPIquarterP); 
      wait(fSPIquarterP);     
      *pCPUclk = 0;  
      wait(fSPIquarterP); 
      wait(fSPIquarterP); 
      
      
      
      if (0)
      {
        *pSCLK = 1;                              
        wait(fSPIquarterP); 
        wait(fSPIquarterP); 
        *pSCLK = 0;
        wait(fSPIquarterP); 
        wait(fSPIquarterP); 
      }  
    }
//----------------------------------------------//------------------------------
                                                // transceive a character array.
                                                // limit is 256 characters.
                                                // MSB out/in first.
    void mmSPI::transceive_vector2(char *pcReceive, char *pcSend, int dNumBytes)
    {      
      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;
      
      
      *pCPUclk = 1;                             // pulse the CPU clock.
      wait(fSPIquarterP); 
      wait(fSPIquarterP);     
      *pCPUclk = 0;  
      wait(fSPIquarterP); 
      wait(fSPIquarterP); 
      
      *pSCLK = 1;                               // pulse the SPI clock for parallel load.              
      wait(fSPIquarterP); 
      wait(fSPIquarterP); 
      *pSCLK = 0;
                                                // pre-assert MOSI.
      *pMOSI = ((pcSend[dMosiByteIndex]) >> dMosiBitIndex) & 1;
      wait(fSPIquarterP); 
      wait(fSPIquarterP); 
      
      
      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);
      }
    }
//----------------------------------------------//------------------------------
                                                // transceive a character array.
                                                // limit is 256 characters.
                                                // MSB out/in first.
    void mmSPI::test_toggle_cpu_clock(void)
    {    
      DigitalOut led0(LED4);
      while (1)
      {
        *pCPUclk = 1;  led0 = 1;
        wait(1.0);
        *pCPUclk = 0;  led0 = 0;
        wait(1.0);
      }
    }
//----------------------------------------------//------------------------------
    void mmSPI::force_write(char cDataHIgh, char cDataLow, char cAddress)
    {
      char pcReceive[8];
      char pcSend   [8];
      int  dLoop;
      
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0;
      
      
                                                // high data to R2.
      pcSend[7] = 0x02; pcSend[1] = 0xA8; pcSend[0] = cDataHIgh;   
      transceive_vector(pcReceive, pcSend, 8);


                                                 // low  data to R1.
      pcSend[7] = 0x02; pcSend[1] = 0xA4; pcSend[0] = cDataLow; 
      transceive_vector(pcReceive, pcSend, 8);  
        
        
                                                // address to R3.
      pcSend[7] = 0x02; pcSend[1] = 0xAC; pcSend[0] = cAddress; 
      transceive_vector(pcReceive, pcSend, 8);
        
        
                                                     
      pcSend[7] = 0x02; pcSend[1] = 0x02;  pcSend[0] = 0;   // WE high.
      transceive_vector(pcReceive, pcSend, 8);
        
      pcSend[7] = 0x02; pcSend[1] = 0x00;   pcSend[0] = 0;  // WE low. 
      transceive_vector(pcReceive, pcSend, 8);

    }
//----------------------------------------------//------------------------------

    void mmSPI::force_read(char cAddress)
    {
      char pcReceive[8];
      char pcSend   [8];
      int  dLoop;
      
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0;
      
 
        
        
                                                // address to R3.
      pcSend[7] = 0x02; pcSend[1] = 0xAC; pcSend[0] = cAddress; 
      transceive_vector(pcReceive, pcSend, 8);
        
                                                // R2 gets data-H from memory.
      pcSend[7] = 0x02; pcSend[1] = 0xC8; pcSend[0] = cAddress; 
      transceive_vector(pcReceive, pcSend, 8);
      
                                                // R1 gets data-L from memory.
      pcSend[7] = 0x02; pcSend[1] = 0xC4; pcSend[0] = cAddress; 
      transceive_vector(pcReceive, pcSend, 8);
      
      
      
      
 //       pcSend[7] = 0x02;                       // force IR.
//        pcSend[1] = 0xA4;                       // R1 <- immediate.
//        pcSend[0] = 0xEE;                       // immediate value.
 ///       transceive_vector(pcReceive, pcSend, 8);     
      
      
      
                                                // no-op scan.
      pcSend[7] = 0x02; pcSend[1] = 0x0; pcSend[0] = 0;  
      transceive_vector(pcReceive, pcSend, 8);
  
    }
//----------------------------------------------//------------------------------
    void mmSPI::write_register(char cRegister, char cValue, char * pcReceive, char * pcSend)
    {     
      int dLoop;                                // loop index.
      
                                                // clear transmit vector.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00; 
      
      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_vector2(pcReceive, pcSend, 8); // transmit command.
 
                                                // clear transmit vector.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00; 
    }
//----------------------------------------------//------------------------------
                                                // returns the content of
                                                // a CPU register.
    char mmSPI::read_register(char cRegister, char * pcReceive, char * pcSend)
    { 
      int dLoop;                                // send all 0.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00;    
                   
      transceive_vector2(pcReceive, pcSend, 8); // snap & scan-out reg contents.
      
      return (pcReceive[cRegister]);            // return the particular reg value.
    }
//----------------------------------------------//------------------------------
    void mmSPI::write_memory(char cHData, char cLdata, char cAddress, char * pcReceive, char * pcSend)
    {
      int dLoop;                                // loop index.
    
                                                // clear transmit vector.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00;   
 
                                                // R3 <- address.
                                                // R2 <- high-data.
                                                // R1 <- low-data.
      write_register(0x03,cAddress, pcReceive, pcSend); 
      write_register(0x02,cHData,   pcReceive, pcSend);
      write_register(0x01,cLdata,   pcReceive, pcSend);
  
      pcSend[7] = 0x02;                         // write-enable high.
      pcSend[1] = 0x02;
      pcSend[0] = 0x00;
         
      
      transceive_vector2(pcReceive, pcSend, 8);
      
      pcSend[7] = 0x02;                         // write-enable low.
      pcSend[1] = 0x00;
      pcSend[0] = 0x00;
      transceive_vector2(pcReceive, pcSend, 8);   
      
                                                // clear transmit vector.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00; 
    }
//----------------------------------------------//------------------------------
                                                // fetch a word from main memory.
    unsigned int mmSPI::read_memory(char cAddress, char * pcReceive, char * pcSend)
    {
      int          dLoop;                       // loop index.   
      unsigned int udMemoryContent;             // return variable.
      char         cHData;                      // returned data-high.
      char         cLData;                      // returned data-low.
    
                                                // clear transmit vector.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00;  
      
                                                // R3 <- address.
      write_register(0x03,cAddress, pcReceive, pcSend);
      
      pcSend[7] = 0x02;                         // mbed sends command.
      pcSend[1] = 0x68;                         // R2 <- MM[R3]
      pcSend[0] = 0x00;
      transceive_vector2(pcReceive, pcSend, 8); // send command. 
      
      pcSend[7] = 0x02;                         // mbed sends command.
      pcSend[1] = 0x64;                         // R1 <- MM[R3]
      pcSend[0] = 0x00;
      transceive_vector2(pcReceive, pcSend, 8); // send command.      
           
                                                // obtain MM content.
      cHData = read_register(0x02, pcReceive, pcSend);  
      cLData = read_register(0x01, pcReceive, pcSend);    
    
                                                
      udMemoryContent = (cHData << 8) + cLData; // build the memory word.
      
                                                // clear transmit vector.
      for (dLoop = 0; dLoop < 8; dLoop++) pcSend[dLoop] = 0x00;
    
      return udMemoryContent;                   // return the memory word.
    }
//----------------------------------------------//------------------------------


    void mmSPI::write_pulse(char * pcReceive, char * pcSend)
    {     
      pcSend[7] = 0x02;                         // write-enable high.
      pcSend[1] = 0x02;
      pcSend[0] = 0x00;
      transceive_vector2(pcReceive, pcSend, 8);
      
      pcSend[7] = 0x02;                         // write-enable low.
      pcSend[1] = 0x00;
      pcSend[0] = 0x00;
      transceive_vector2(pcReceive, pcSend, 8);
 
      pcSend[7] = 0x00;
      pcSend[6] = 0x00;
      pcSend[5] = 0x00;
      pcSend[4] = 0x00;
      pcSend[3] = 0x00;
      pcSend[2] = 0x00;
      pcSend[1] = 0x00;
      pcSend[0] = 0x00;
    }
//----------------------------------------------//------------------------------