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.
Revision 35:6152c9709697, committed 2013-09-01
- Comitter:
- gatedClock
- Date:
- Sun Sep 01 02:29:08 2013 +0000
- Parent:
- 34:d5553509f31a
- Commit message:
- add project code.
Changed in this revision
| mmSPI.cpp | Show annotated file Show diff for this revision Revisions of this file |
| mmSPI.h | Show annotated file Show diff for this revision Revisions of this file |
--- 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)
{
--- a/mmSPI.h Sat Aug 31 02:19:42 2013 +0000
+++ b/mmSPI.h Sun Sep 01 02:29:08 2013 +0000
@@ -4,12 +4,18 @@
student : m-moore
email : gated.clock@gmail.com
class : usb device drivers
- directory : mmSPI
+ directory : USB_device_project/mmSPI
file : mmSPI.h
date : september 3, 2013.
-----description---------------------------------//------------------------------
+----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.
----notes---------------------------------------//------------------------------
- 1. the SPI interface pins are routed to the zigbee header.
------------------------------------------------//----------------------------*/
#include "mbed.h" // standard mbed.org class.
//---defines------------------------------------//------------------------------
@@ -17,9 +23,6 @@
#define mmSPI_MISO p30 // SPI interface pin.
#define mmSPI_SCLK p9 // SPI interface pin.
#define mmCPU_CLK p10 // soft CPU system clock.
-/*----------------------------------------------//------------------------------
-------------------------------------------------//----------------------------*/
-
//==============================================//==============================
class mmSPI
{
@@ -38,7 +41,7 @@
// write/read CPU registers.
void write_register(char cRegister, char cValue);
- void write_IR(char cValueH, char cValueL);
+ void write_IR (char cValueH, char cValueL);
char read_register (char cRegister);
// write/read CPU main-memory.