This is an involuntary fork, created because the repository would not update mmSPI. SPI library used to communicate with an altera development board attached to four zigbee-header pins.

Dependents:   Embedded_RTOS_Project

Fork of mmSPI by Mike Moore

Revision:
35:6152c9709697
Parent:
34:d5553509f31a
Child:
36:32cdc295f859
--- a/mmSPI.cpp	Sat Aug 31 02:19:42 2013 +0000
+++ b/mmSPI.cpp	Sun Sep 01 02:29:08 2013 +0000
@@ -2,13 +2,66 @@
     student   : m-moore
     email     : gated.clock@gmail.com
     class     : usb device drivers
-    directory : mmSPI
+    directory : USB_device_project/mmSPI
     file      : mmSPI.cpp
     date      : september 3, 2013.
-------------------------------------------------//----------------------------*/
+----copyright-----------------------------------//------------------------------   
+    licensed for personal and academic use.
+    commercial use must be approved by the account-holder of
+    gated.clock@gmail.com
+----description---------------------------------//------------------------------
+    this library provides the low-level SPI data and clock signaling 
+    for communication with the altera development board, via four i/o
+    pins available on the mbed development board's zigbee header.
+    
+    this library also provides higher-level calls to send/receive register
+    and main-memory data to/from the CPU implemented in the altera.
+    
+    the SPI clock and the CPU clock are both built by this library.
+    
+    the SPI clock (*pSCLK) is generated with quarter-phase resolution,
+    although at the moment, only half-phase resolution is being used.
+    
+    within the FPGA, the SPI scan registers are called 'shadow registers'
+    because they parallel load-to/store-from the CPU registers.  
+    
+    character vectors pcSend and pcReceive are used to scan-in and scan-out
+    to/from the altera shadow registers.  note that the prefix 'pc' means
+    'pointer-of-type-character' and not 'personal-computer'.
+    
+    the shadow registers in the altera are arranged as follows:
+    
+ <-- MISO (altera-out to mbed-in)
+     ^
+     |
+   scan_08  U14_spi_control = pcSend/pcReceive[7]
+   scan_08  U08_shadowR0    = pcSend/pcReceive[6]
+   scan_08  U09_shadowR1    = pcSend/pcReceive[5]
+   scan_08  U10_shadowR2    = pcSend/pcReceive[4]
+   scan_08  U11_shadowR3    = pcSend/pcReceive[3]
+   scan_08  U12_shadowPC    = pcSend/pcReceive[2]
+   scan_16  U13_shadowIR    = pcSend/pcReceive[1:0]
+     ^
+     |
+ --> MOSI (altera-in from mbed-out)
+ 
+    when U14_spi_control<1> is high, the mbed takes over CPU operation.
+    this means that the CPU instruction decoder decodes U13_shadowIR
+    rather than the CPU's actual IR.
+    
+    when U14_spi_control<2> is high, the mbed writes into the IR.
+    this means that the CPU instruction decoder load-enable outputs
+    are gated-off so that the mbed may write into the instrucition
+    register without immediate consequence in the CPU.  writing to
+    the IR this way is more for the ability to show that it can be done,
+    rather than any likely useful purpose.
+    
+    debug/test:
+    this library was debugged by using the altera FPGA logic analyzer
+    known as 'signal tap'.  the main program uses all of the memory and
+    register access calls, which were used as an informal unit test.
+-----includes-----------------------------------//----------------------------*/
     #include "mmSPI.h"
-/*----------------------------------------------//------------------------------
-------------------------------------------------//----------------------------*/
 //==============================================//==============================
     mmSPI::mmSPI()                              // constructor.
     {
@@ -70,25 +123,44 @@
       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]
+/*
+    this method has four 'components' which may be switched on/off by the caller:
+    1. cPreCPU  = 1 means cycle the altera CPU clock once.
+    2. cPreSPI  = 1 means cycle the        SPI clock once.
+    3. cScan    = 1 means run a full SPI scan-in/scan-out cycle.
+    4. cPostCPU = 1 means cycle the alter CPU clock once, then the SPI clock once.
+    
+    in the altera, upon the falling edge of any CPU clock, a load-enable is
+    asserted into the scan registers, such that at the next rising edge of
+    the SPI clock, the scan registers perform a parallel-load of the CPU
+    registers, so that that data can subsequently be scanned back into the mbed
+    via a full SPI scan-in cycle.  (this load-enable is turned-off upon the first
+    falling edge of the subsequent SPI clock.)
+    therefore, the regular input switches to this method are (1,1,1,0).  
+    this means that the altera CPU clock will cycle,
+    and the result of that CPU operation will be parallel-loaded into the
+    shadow registers for scan into the mbed on the subsequent full-scan cycle.
+    
+    a finer level of sequencing these 'components' is needed by the 'step' method,
+    which is why they are under four-input-parameter control.                                                
+ */
     void mmSPI::transceive_vector(char cPreCPU, char cPreSPI, char cScan, char cPostCPU)
     {      
-      int  dClear;
-      int  dIndex;       
-      int  dMosiByteIndex;
-      int  dMosiBitIndex;
-      int  dMisoByteIndex;
-      int  dMisoBitIndex;
+      int  dClear;                              // clear-loop index.
+      int  dIndex;                              // total scan index.
+      int  dMosiByteIndex;                      // SPI-MOSI byte index.
+      int  dMosiBitIndex;                       // SPI-MOSI bit  index.
+      int  dMisoByteIndex;                      // SPI-MISO byte index.
+      int  dMisoBitIndex;                       // SPI-MISO bit  index.
       
-      dIndex         = (dNumBytes * 8) - 1;
-      dMosiByteIndex =  dIndex / 8;
-      dMosiBitIndex  =  dIndex % 8;
+                                                // initializations.  these are needed.
+      dIndex         = (dNumBytes * 8) - 1;     // calculate scan count.
+      dMosiByteIndex =  dIndex / 8;             // calculate current byte index.
+      dMosiBitIndex  =  dIndex % 8;             // calculate current bit  iindex.
       
+                                                // clear the SPI receive vector.
       for (dClear = 0; dClear < dNumBytes; dClear++) pcReceive[dClear] = 0;
-      
+//---
       if (cPreCPU)                              // if pre-CPU clock.
       {
         *pCPUclk = 1;                           // pulse the CPU clock.
@@ -99,7 +171,7 @@
         wait(fSPIquarterP); 
         ulCPUclkCount++;
       }                                         // if pre-CPU clock.
-      
+ //---     
       if (cPreSPI)                              // if pre-SPI pulse.
       {
         *pSCLK = 1;                             // pulse the SPI clock for parallel load.              
@@ -108,7 +180,7 @@
         *pSCLK = 0;
         ulSPIclkCount++;
       }                                         // if pre-SPI pulse.
-      
+ //---     
       if (cScan)                                // if cScan.
       {
                                                 // pre-assert MOSI.
@@ -136,7 +208,7 @@
           ulSPIclkCount++;
         }                                       // main SPI scan loop.
       }                                         // if cScan.
-      
+ //---     
       if (cPostCPU)                             // if post-CPU pulse.
       {
         *pCPUclk = 1;                           // pulse the CPU clock.
@@ -155,16 +227,30 @@
       }                                         // 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>
+/*
+   cRegister  ->  CPU_register  
+      0            R0
+      1            R1
+      2            R2
+      3            R3
+      4            PC
+      5         <use write_IR instead>
+      6         <nothing>
+      7         <nothing>
+      
+    in order to write to a CPU register, pcSend[7] is set to 0x02,
+    which informs the CPU instruction decoder to decode what we are
+    here scanning into the shadow instruction-register, rather than
+    the CPU instruction decoder decoding the regular instruction-register.
+    here, we set-up pcSend to scan the instruction 
+    'load Rx with immediate data yy', and this is executed on the
+    subsequent CPU clock.  
+    
+    said another way, this method writes a value into a CPU register
+    by effectively taking over the CPU and doing a write-register-immediate.
+*/
 
+                                                // write to a CPU register.
     void mmSPI::write_register(char cRegister, char cValue)
     {     
       clear_transmit_vector();                  // clear transmit vector.
@@ -179,7 +265,16 @@
  
       clear_transmit_vector();                  // clear transmit vector.
     }                                           // write_register.
-//----------------------------------------------//------------------------------   
+//----------------------------------------------//------------------------------  
+/*  
+    for writing to the instruction-register, this method is used.
+    for reading from the instruction-register, the 'regular' 
+    read_register method is used, once for each of the two IR data bytes.
+    
+    unlike method 'write_register', this method works by gating-off the
+    outputs of the CPU instruction decoder, and having the instruction-register
+    content loaded in from the shadow instruction-register.
+*/
                                                 // write instruction register.
     void mmSPI::write_IR(char cValueH, char cValueL)
     {
@@ -195,18 +290,24 @@
       clear_transmit_vector();                  // clear transmit vector.    
     }                                           // write instruction 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)
+/*
+  cRegister  ->  CPU_register   pcReceive
+      0      ->    R0             [6]
+      1      ->    R1             [5]
+      2      ->    R2             [4]
+      3      ->    R3             [3]
+      4      ->    PC             [2]
+      5      ->    IR-H           [1]
+      6      ->    IR-L           [0]
+      7      ->  <never-use>
+      
+    this method works by taking over the instruction decoder as described above,
+    but not issuing any instruction, but the scan registers will parallel-load
+    all of the CPU register data and scan them into pcReceive, where they are
+    picked up below.
+*/
+
+    char mmSPI::read_register(char cRegister)   // return content of a CPU register.
     { 
       clear_transmit_vector();                  // clear transmit vector.
       
@@ -217,6 +318,12 @@
       return (pcReceive[6 - cRegister]);        // return the particular reg value.
     }                                           // read_register.
 //----------------------------------------------//------------------------------
+/*
+    this method works by taking over the instruction decoder, and issuing
+    the CPU commands which load the MM address/data into {R3,R2,R1}
+    followed by issuing a write-pulse.
+*/
+                                                // write a word to main-memory.
     void mmSPI::write_memory(char cHData, char cLdata, char cAddress)
     {
       clear_transmit_vector();                  // clear transmit vector.
@@ -238,6 +345,12 @@
       clear_transmit_vector();                  // clear transmit vector. 
     }                                           // write_memory.
 //----------------------------------------------//------------------------------
+/*
+    this command works by taking over the instruction decoder, loading
+    R3 with the MM address, then issuing load-from-MM commands so that
+    R2,R1 are loaded with MM[R3], and then reading the result from
+    R1,R2.
+*/
                                                 // fetch a word from main memory.
     unsigned int mmSPI::read_memory(char cAddress)
     {