David Mort
/
SPI_flex
CLASS for software SPI master class instantiated on any general IO pin. Slow but flexible.
Revision 0:9e3e70548ec3, committed 2014-03-22
- Comitter:
- dtmort
- Date:
- Sat Mar 22 18:53:40 2014 +0000
- Commit message:
- Initial commit 2014.03.22
Changed in this revision
--- /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