CLASS for software SPI master class instantiated on any general IO pin. Slow but flexible.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
dtmort
Date:
Sat Mar 22 18:53:40 2014 +0000
Commit message:
Initial commit 2014.03.22

Changed in this revision

SPI_flex.cpp Show annotated file Show diff for this revision Revisions of this file
SPI_flex.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPI_flex.cpp	Sat Mar 22 18:53:40 2014 +0000
@@ -0,0 +1,93 @@
+/* Class SPI_flex, Copyright 2014, David T. Mort (http://mbed.org/users/dtmort/)
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+#include "SPI_flex.h"
+#include "mbed.h"
+
+SPI_flex::SPI_flex(PinName mosi, PinName miso, PinName sclk, PinName cs):
+        _mosi(mosi), _miso(miso), _sclk(sclk), _cs(cs) {
+            _mosi=0;                            //initialize mosi pin
+            _sclk=0;                            //initialize serial clock pin
+            format();                           //initialize hardware length & mode
+            csactive();                        //initialize chip select setup active state
+            _cs=!__cs;                          //initialize chip select pin inactive
+}
+
+void SPI_flex::format(unsigned int bits, int mode){
+    BitString=bits;
+    if (mode<4){_mode=mode;}                     //test if 0-3
+    _cpol= _mode & 0x02;                         //extract clock polarity (idle state)
+    _cpha= _mode & 0x01;                         //extract clock phase (capture edge)
+}    
+
+
+void SPI_flex::csactive(bool cs){
+   __cs=cs;
+}
+
+void SPI_flex::frequency(int Hz){
+    Dcpwi= (400000-Hz)/14260;                   //set Delay clock pulse width inactive
+    Dcpwa= (400000-Hz)/14260;                   //set Delay clock pulse width active
+
+}
+
+void SPI_flex::select(void){
+    _deAssert=1;                                //initialze chip select bit counter
+    if (_cpol) _sclk=1; else _sclk=0;           //initialize sclk
+    _cs=__cs;                                   //assert chip select (SSEL)
+//    wait_us(1);                               //Tcss CS to SCLK Setup Time (+Dcpwi)  
+}    
+
+bool SPI_flex::writebit(bool bit){
+//        int id=500, ad=500;
+        int id=Dcpwi, ad=Dcpwa;                 //intialize frequency slowdown counters
+        if (_cs!=__cs)select();                 //assert cs auto-count sequence if not already engaged
+        if (_cpha) {_sclk =!_sclk;              //when 2nd clock edge capture (if CPHA=1)
+                    bit_read=_miso;}            //          read & store miso (if CPHA=1)
+        if (bit) _mosi=1; else _mosi=0;         //setup data on mosi
+        while(id){__nop(); id--;}               //Dcpwi Clock Pulse Width Inactive Delay (half period)
+        _sclk =!_sclk;                          //toggle sclk (capture edge)
+        while(ad){__nop(); ad--;}               //Dcpwa Clock Pulse Width Active Delay (half period)
+        _deAssert++;                            //advance chip select bit counter
+        if (_deAssert > BitString){deSelect();};//call function to latch data (while clock still active)
+        if (!_cpha) {_sclk =!_sclk;             //when 1st clock edge capture (if CPHA=0)
+                     bit_read=_miso;}           //          read & store miso (if CPHA=0)
+        return bit_read;
+}        
+
+uint8_t SPI_flex::writebyte(uint8_t byte){
+    int mask=0x80;                              //set MSB mask position
+    while (mask){                               //MSB -> LSB (7:0)
+        byte_read= mask &(writebit(byte & mask));  //write to mosi, read from miso
+        mask>>=1;}                              //move mask one position right
+    return byte_read;
+}
+
+uint16_t SPI_flex::writeword(uint16_t word){
+    int mask=0x8000;                            //set MSB mask position
+    while (mask){                               //MSB -> LSB (15:0)
+        word_read= mask &(writebit(word & mask));  //write to mosi, read from miso
+        mask>>=1;}                              //move mask one position right
+    return word_read;
+}
+
+ 
+
+
+void SPI_flex::deSelect(void){
+    _cs=!__cs;                                  //de-activate chip select while sclk is still active** on LSB
+    while(0){__nop();}                          //Tcspi Chip Select Pulse Inactive Time
+    _deAssert = 0;                              //reset chip select counter 
+    _mosi=0;                                    //reset mosi    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPI_flex.h	Sat Mar 22 18:53:40 2014 +0000
@@ -0,0 +1,168 @@
+/* Class SPI_flex, Copyright 2014, David T. Mort (http://mbed.org/users/dtmort/)
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+#ifndef MBED_SPI_FLEX_H
+#define MBED_SPI_FLEX_H
+ 
+#include "mbed.h"
+
+/**A software Master SPI (Serial Peripheral Interface) class
+    *   that can be instantiated on any mbed LPC1768 general IO pins (p5...p30).
+    *
+    *   Primarily optimized for driving daisy-chained serial display hardware,
+    *   it provides flexibility beyond on-board SPI hardware capabilities and some automation
+    *   at the expense of speed. Currently runs full clock speed at about 395kHz. 
+    *   Comment-out code lines testing/setting the automatic chip select for higher speed
+    *   performance if the chip select feature is not required.
+    *       - flexible bit-lengths from 0 .. 4,294,967,295. Not possible with mbed hardware.
+    *       - automation of the chip select line which enables
+    *         all external chips to be loaded with information before latching data in.
+    *       - selectable clock polarity and edge trigger (Mode 0 through Mode 3).
+    *       - selectable chip select polarity (active-low or active-high).
+    *       - latching data in while clock is still active on last bit,
+    *         **such as required by the Maxim MAX6952. This is not possible with the mbed API, 
+    *         onboard SPI or SSP hardware.
+    *       - allows one-shot loading of all daisy-chained hardware registers before latching. 
+    *         Prevents display ghosting effect.
+    * 
+    *   The MAX6952 chip requires the following sequence:
+    *
+    *       [[http://datasheets.maxim-ic.com/en/ds/MAX6952.pdf]]
+    *       -# Take CLK low.
+    *       -# Take CS low. This enables the internal 16-bit shift register.
+    *       -# Clock 16 bits of data into DIN, D15 first to D0 last, observing the setup and hold times. Bit D15 is low, indicating a write command.
+    *       -# Take CS high **(while CLK is still high after clocking in the last data bit).
+    *       -# Take CLK low.
+    *
+    * Example:
+    * @code
+    * // Send a byte to a SPI slave, and record the response
+    *
+    * // Chip select is automatic
+    *
+    * #include "mbed.h"
+    * #include "SPI_flex.h"
+    *
+    * SPI device(p5, p6, p7, p8); // mosi, miso, sclk, cs
+    *
+    * int main() {
+    *     device.frequency(300000);      //to slow clock speed if necessary
+    *     int response = device.writebyte(0xFF);
+    * }
+    * @endcode
+    */
+class SPI_flex {
+
+public:
+/**Create a software Master SPI bus instance
+    *
+    *   @param mosi Master Out Slave In pin
+    *   @param miso Master In Slave Out pin
+    *   @param sclk Serial Clock out pin
+    *   @param cs Chip Select out pin
+    */   
+    SPI_flex(PinName mosi, PinName miso, PinName sclk, PinName cs);
+
+/** Configure the SPI bus data transmission format
+    *
+    *  Constructor calls by default. Call only if change needed.
+    *
+    *  Automatically controls chip select output pin. Default is 16 bit.
+    *
+    *  @param bits Bits per SPI hardware string frame (0 .. 4,294,967,295)
+    *
+    *  @param mode Clock polarity and phase. Default is Mode 0.
+    *
+    @code
+    Mode | POL | PHA
+    -----|-----|----
+      0  |  0  | 0
+      1  |  0  | 1
+      2  |  1  | 0
+      3  |  1  | 1
+    @endcode
+    */
+    void format(unsigned int bits=16, int mode=0);
+
+/** Set active state of the SPI bus chip select pin
+    *
+    *  Constructor calls by default. Call only if change needed.
+    *
+    *   @param cs 0 (default) for active-low, 1 for active-high
+    */
+    void csactive(bool cs=0);
+    
+/** Set the SPI bus clock frequency.
+    *   Is maximum by default. Call only if change needed.
+    *   
+    *   Result will not be exact and may jump in 5Khz increments
+    *    due to integer rounding.
+    *
+    *   @param Hz Hertz 395,000 is approximate maximum (and default speed)
+    */
+    void frequency(int Hz=400000);
+
+
+/** Send a single bit on the SPI bus MOSI pin and read response on MISO pin
+    *
+    *   @param bit Boolean one or zero, TRUE or FALSE
+    *   @returns Boolean one or zero read from MISO from external hardware 
+    */
+    bool writebit(bool bit);
+
+/** Send a byte on the SPI bus MOSI pin and read response on MISO pin
+    *
+    *   MSB first out, LSB last out (7:0)
+    *
+    *   @param byte An 8-bit value
+    *   @returns 8-bit value read from MISO from external hardware
+    */
+    uint8_t writebyte(uint8_t byte);
+
+/** Send a word on the SPI bus MOSI pin and read response on MISO pin
+    *
+    *   MSB first out, LSB last out (15:0)
+    *
+    *   @param word A 16-bit value
+    *   @returns 16-bit value read from MISO from external hardware
+    */
+    uint16_t writeword(uint16_t word);
+
+
+    
+//protected:
+
+private:
+
+    void select(void);              //activates chip select sequence, called by writebit() function
+    void deSelect(void);            //deactivates chip select, called by writebit() function
+    DigitalOut      _mosi;          //master out slave in, pin
+    DigitalIn       _miso;          //master in slave out, pin
+    DigitalOut      _sclk;          //serial clock, pin
+    DigitalOut      _cs;            //chip select, pin
+    bool            __cs;           //chip select active state, operating setup
+    bool            _cpol;          //clock polarity, operating setup
+    bool            _cpha;          //clock phase, operating setup
+    int             _mode;          //mode 0,1,2 or 3, operating setup
+    unsigned int    _deAssert;      //counts-up bits sent for chip select, placeholder
+    unsigned int    BitString;      //# serialized bits sent to hardware string, controls chip select activation
+    unsigned int    BitStream;      //# bits to hardware from source data, not used yet
+    bool            bit_read;       //bit value read from miso pin
+    uint8_t         byte_read;      //byte value read from miso pin
+    uint16_t        word_read;      //word value read from miso pin
+    int             Dcpwi;          //Delay clock pulse width inactive, for freqency adjustments
+    int             Dcpwa;          //Delay clock pulse width active, for freqency adjustments
+
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Mar 22 18:53:40 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/dc225afb6914
\ No newline at end of file