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

Dependencies:   mbed

SPI_flex.cpp

Committer:
dtmort
Date:
2014-03-22
Revision:
0:9e3e70548ec3

File content as of revision 0:9e3e70548ec3:

/* 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    
}