Home : I/O Peripherals Library | SPI Peripheral

Description

<TODO>

Naming Conventions

<TODO>

Interface Functions

<TODO>

Example Usage

<TODO>

Configuration

<TODO>

Source Files

xperipherals_spi.h SPI peripheral interface
xperipherals_spi_1.xc SPI peripheral #1 implementation
xperipherals_spi_2.xc SPI peripheral #2 implementation
xperipherals_spi_1.xc SPI peripheral #3 implementation

Source Listings

xperipherals_spi.h

#ifndef XPERIPHERALS_SPI__INCLUDED
#define XPERIPHERALS_SPI__INCLUDED

#include "xsystem_types.h"

// SPI Peripheral Interface

// These must be defined in "xconfig.h" for each peripheral bus being used
//
// XPERIPHERALS_SPI_n                     No value
// XPERIPHERALS_SPI_n__BUS_MASTER         TRUE or FALSE
// XPERIPHERALS_SPI_n__BIT_RATE           Non-zero, non-negative integer
// XPERIPHERALS_SPI_n__CLOCKED_DATA       TRUE or FALSE
// XPERIPHERALS_SPI_n__SUPPORT_TX         TRUE or FALSE
// XPERIPHERALS_SPI_n__SUPPORT_RX         TRUE or FALSE
// XPERIPHERALS_SPI_n__SUPPORT_TIMEOUTS   TRUE or FALSE
// XPERIPHERALS_SPI_n__SCLK_BIT_POS       Non-negative integer
// XPERIPHERALS_SPI_n__MOSI_BIT_POS       Non-negative integer
// XPERIPHERALS_SPI_n__MISO_BIT_POS       Non-negative integer
// XPERIPHERALS_SPI_n__TILE_NUMBER        Integer, XS1 tile number
// XPERIPHERALS_SPI_n__SCLK_PORT          XS1 port identifier
// XPERIPHERALS_SPI_n__MOSI_PORT          XS1 port identifier
// XPERIPHERALS_SPI_n__MISO_PORT          XS1 port identifier

#define XPERIPHERALS_SPI__STATUS__EVENT_IO_DONE (  1)  // Transfer operation completed, no start/stop condition encountered
#define XPERIPHERALS_SPI__STATUS__NONE          (  0)  // I2C operation has not been started
#define XPERIPHERALS_SPI__STATUS__ERROR_UNKNOWN ( -1)  // FIXME: Just a place holder for now ...

// Master/Slave API

#define XPERIPHERALS_SPI__INTERFACE( N ) \
\
void   xperipherals_spi_##N##__initialize ( void ); \
\
/* Blocking I/O Functions (for non-event driven I/O) */ \
\
int    xperipherals_spi_##N##__write      ( xbyte mosi_data ); \
int    xperipherals_spi_##N##__read       ( xbyte& miso_data ); \
int    xperipherals_spi_##N##__transfer   ( xbyte mosi_data, xbyte& miso_data ); \
\
/* Non-Blocking I/O Functions (for event driven I/O) */ \
\
void   xperipherals_spi_##N##__begin_write( xbyte mosi_data ); /* Begin writing MOSI data */ \
void   xperipherals_spi_##N##__begin_read ( void );            /* Begin reading MISO data */ \
void   xperipherals_spi_##N##__begin_xfer ( xbyte mosi_data ); /* Begin writing MOSI data and reading MISO data */ \
select xperipherals_spi_##N##__continue_io( int& status );     /* Set pin states and check for I/O events per I2C state machine */ \
xbyte  xperipherals_spi_##N##__get_data   ( void );            /* Return MISO data */

XPERIPHERALS_SPI__INTERFACE( 1 )
XPERIPHERALS_SPI__INTERFACE( 2 )
XPERIPHERALS_SPI__INTERFACE( 3 )

#endif

xperipherals_spi_1.xc

#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <print.h>

#include "xperipherals_spi.h"

#ifdef XPERIPHERALS_SPI_1

#if XPERIPHERALS_SPI_1__BUS_MASTER

    on tile[XPERIPHERALS_SPI_1__TILE_NUMBER] : out port _xperipherals_spi_1__pin_sclk = XPERIPHERALS_SPI_1__SCLK_PORT;
    on tile[XPERIPHERALS_SPI_1__TILE_NUMBER] : out port _xperipherals_spi_1__pin_mosi = XPERIPHERALS_SPI_1__MOSI_PORT;
    on tile[XPERIPHERALS_SPI_1__TILE_NUMBER] : in  port _xperipherals_spi_1__pin_miso = XPERIPHERALS_SPI_1__MISO_PORT;

#else

    on tile[XPERIPHERALS_SPI_1__TILE_NUMBER] : in port  _xperipherals_spi_1__pin_sclk = XPERIPHERALS_SPI_1__SCLK_PORT;
    on tile[XPERIPHERALS_SPI_1__TILE_NUMBER] : out port _xperipherals_spi_1__pin_mosi = XPERIPHERALS_SPI_1__MOSI_PORT;
    on tile[XPERIPHERALS_SPI_1__TILE_NUMBER] : in  port _xperipherals_spi_1__pin_miso = XPERIPHERALS_SPI_1__MISO_PORT;

#endif

#if XPERIPHERALS_SPI_1__BUS_MASTER
static timer _xperipherals_spi_1__io_timer;
static int   _xperipherals_spi_1__io_time;
#else
static xbyte _xperipherals_spi_1__sclk;
#endif
static int   _xperipherals_spi_1__io_state;

static int   _xperipherals_spi_1__shift_cnt;
static xbyte _xperipherals_spi_1__mosi_data;
static xbyte _xperipherals_spi_1__miso_data;
static xbyte _xperipherals_spi_1__temp_data;

// <TODO> Calulate based on current system clock frequency

#define _XPERIPHERALS_SPI_1__TIME_BASE ((400000 / XPERIPHERALS_SPI_1__BIT_RATE) * 62)

#if XPERIPHERALS_SPI_1__BUS_MASTER

void xperipherals_spi_1__initialize( void )
{
    _xperipherals_spi_1__io_state = 0;
    _xperipherals_spi_1__pin_sclk <: (XPERIPHERALS_SPI_1__MODE_CPOL != 0);
    _xperipherals_spi_1__io_timer :> _xperipherals_spi_1__io_time;
    _xperipherals_spi_1__io_timer when timerafter( _xperipherals_spi_1__io_time + 10 * _XPERIPHERALS_SPI_1__TIME_BASE ) :> void;
}

void xperipherals_spi_1__begin_write( xbyte mosi_data ) { xperipherals_spi_1__begin_xfer( mosi_data ); }
void xperipherals_spi_1__begin_read ( void )            { xperipherals_spi_1__begin_xfer( 0x00 ); }

void xperipherals_spi_1__begin_xfer( xbyte mosi_data )
{
    _xperipherals_spi_1__mosi_data = mosi_data;
    _xperipherals_spi_1__pin_sclk <: !((XPERIPHERALS_SPI_1__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_1__MODE_CPHA !=0 ));
    _xperipherals_spi_1__pin_mosi <: (xbyte)(_xperipherals_spi_1__mosi_data & 1);
    _xperipherals_spi_1__miso_data = 0;
    _xperipherals_spi_1__shift_cnt = 1;
    _xperipherals_spi_1__io_timer :> _xperipherals_spi_1__io_time;
    _xperipherals_spi_1__io_state = 1;
}

//                                   +-------+       +-------+       +-------+
// CPOL = 0, CPHA = 0                |       |       |       |       |       |
//                      -------------+       +-------+       +-------+       +
//                           +---------------+---------------+---------------+
// CPOL = 0, CPHA = 0   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                      -------------+       +-------+       +-------+       +
// CPOL = 1, CPHA = 0                |       |       |       |       |       |
//                                   +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 1, CPHA = 0   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                           +-------+       +-------+       +-------+
// CPOL = 0, CPHA = 1        |       |       |       |       |       |
//                      -----+       +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 0, CPHA = 1   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                      -----+       +-------+       +-------+       +-------+
// CPOL = 1, CPHA = 1        |       |       |       |       |       |
//                           +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 1, CPHA = 1   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2

select xperipherals_spi_1__continue_io( int& status )
{
    case _xperipherals_spi_1__io_state > 0 => _xperipherals_spi_1__io_timer when timerafter(_xperipherals_spi_1__io_time) :> _xperipherals_spi_1__io_time:

        switch( _xperipherals_spi_1__io_state )
        {
            case 1: // S1

            _xperipherals_spi_1__pin_miso :> _xperipherals_spi_1__temp_data;
            _xperipherals_spi_1__pin_sclk <: ((XPERIPHERALS_SPI_1__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_1__MODE_CPHA !=0 ));
            _xperipherals_spi_1__miso_data |=  (_xperipherals_spi_1__temp_data << _xperipherals_spi_1__shift_cnt) & 1;

            _xperipherals_spi_1__io_state = 2;
            status = XPERIPHERALS_SPI__STATUS__NONE;
            break;

            case 2: // S2

            if( _xperipherals_spi_1__shift_cnt <= 7 )
            {
                _xperipherals_spi_1__pin_sclk <: !((XPERIPHERALS_SPI_1__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_1__MODE_CPHA !=0 ));
                _xperipherals_spi_1__pin_mosi <: (xbyte)(_xperipherals_spi_1__mosi_data >> _xperipherals_spi_1__shift_cnt++) & 1;
                _xperipherals_spi_1__io_state = 1;
                status = XPERIPHERALS_SPI__STATUS__NONE;
            }
            else
            {
                _xperipherals_spi_1__pin_sclk <: !((XPERIPHERALS_SPI_1__MODE_CPOL !=0 ) ^ (XPERIPHERALS_SPI_1__MODE_CPHA !=0 ));
                _xperipherals_spi_1__io_state = 0;
                status = XPERIPHERALS_SPI__STATUS__EVENT_IO_DONE;
            }
            break;
        }
        break;
}

xbyte xperipherals_spi_1__get_data( void ) { return _xperipherals_spi_1__miso_data; }

int xperipherals_spi_1__write( xbyte mosi_data )  { xbyte tmp; return xperipherals_spi_1__transfer( mosi_data, tmp ); }
int xperipherals_spi_1__read ( xbyte& miso_data ) { return xperipherals_spi_1__transfer( 0x00, miso_data ); }

int xperipherals_spi_1__transfer( xbyte mosi_data, xbyte& miso_data )
{
    int status;
    xperipherals_spi_1__begin_write( mosi_data );
    while( TRUE ) {
        select {case xperipherals_spi_1__io_continue( status );}
        if( status != XPERIPHERALS_SPI__STATUS__NONE ) break;
    }
    return status;
}

#else

#if XPERIPHERALS_SPI_1__BUS_MASTER

void xperipherals_spi_1__initialize( void )
{
}

int xperipherals_spi_1__write( xbyte mosi_data )
{
    return 0;
}

int xperipherals_spi_1__read( xbyte& miso_data )
{
    return 0;
}

xbyte xperipherals_spi_1__transfer( xbyte mosi_data )
{
    return 0;
}

void xperipherals_spi_1__xfer_start( xbyte mosi_data )
{
    return 0;
}

select xperipherals_spi_1__xfer_done( xbool& done_flag, xbyte& miso_data )
{
    return 0;
}

void xperipherals_spi_1__begin_write( xbyte mosi_data )
{
    return 0;
}

void xperipherals_spi_1__begin_read( void )
{
    return 0;
}

void xperipherals_spi_1__begin_xfer( xbyte mosi_data )
{
    #endif
}

select xperipherals_spi_1__continue_io( int& status )
{
}

xbyte xperipherals_spi_1__get_data( void )
{
    return _xperipherals_spi_1__data;
}

#endif

#endif

xperipherals_spi_2.xc

#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <print.h>

#include "xperipherals_spi.h"

#ifdef XPERIPHERALS_SPI_2

#if XPERIPHERALS_SPI_2__BUS_MASTER

    on tile[XPERIPHERALS_SPI_2__TILE_NUMBER] : out port _xperipherals_spi_2__pin_sclk = XPERIPHERALS_SPI_2__SCLK_PORT;
    on tile[XPERIPHERALS_SPI_2__TILE_NUMBER] : out port _xperipherals_spi_2__pin_mosi = XPERIPHERALS_SPI_2__MOSI_PORT;
    on tile[XPERIPHERALS_SPI_2__TILE_NUMBER] : in  port _xperipherals_spi_2__pin_miso = XPERIPHERALS_SPI_2__MISO_PORT;

#else

    on tile[XPERIPHERALS_SPI_2__TILE_NUMBER] : in port  _xperipherals_spi_2__pin_sclk = XPERIPHERALS_SPI_2__SCLK_PORT;
    on tile[XPERIPHERALS_SPI_2__TILE_NUMBER] : out port _xperipherals_spi_2__pin_mosi = XPERIPHERALS_SPI_2__MOSI_PORT;
    on tile[XPERIPHERALS_SPI_2__TILE_NUMBER] : in  port _xperipherals_spi_2__pin_miso = XPERIPHERALS_SPI_2__MISO_PORT;

#endif

#if XPERIPHERALS_SPI_2__BUS_MASTER
static timer _xperipherals_spi_2__io_timer;
static int   _xperipherals_spi_2__io_time;
#else
static xbyte _xperipherals_spi_2__sclk;
#endif
static int   _xperipherals_spi_2__io_state;

static int   _xperipherals_spi_2__shift_cnt;
static xbyte _xperipherals_spi_2__mosi_data;
static xbyte _xperipherals_spi_2__miso_data;
static xbyte _xperipherals_spi_2__temp_data;

// <TODO> Calulate based on current system clock frequency

#define _XPERIPHERALS_SPI_2__TIME_BASE ((400000 / XPERIPHERALS_SPI_2__BIT_RATE) * 62)

#if XPERIPHERALS_SPI_2__BUS_MASTER

void xperipherals_spi_2__initialize( void )
{
    _xperipherals_spi_2__io_state = 0;
    _xperipherals_spi_2__pin_sclk <: (XPERIPHERALS_SPI_2__MODE_CPOL != 0);
    _xperipherals_spi_2__io_timer :> _xperipherals_spi_2__io_time;
    _xperipherals_spi_2__io_timer when timerafter( _xperipherals_spi_2__io_time + 10 * _XPERIPHERALS_SPI_2__TIME_BASE ) :> void;
}

void xperipherals_spi_2__begin_write( xbyte mosi_data ) { xperipherals_spi_2__begin_xfer( mosi_data ); }
void xperipherals_spi_2__begin_read ( void )            { xperipherals_spi_2__begin_xfer( 0x00 ); }

void xperipherals_spi_2__begin_xfer( xbyte mosi_data )
{
    _xperipherals_spi_2__mosi_data = mosi_data;
    _xperipherals_spi_2__pin_sclk <: !((XPERIPHERALS_SPI_2__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_2__MODE_CPHA !=0 ));
    _xperipherals_spi_2__pin_mosi <: (xbyte)(_xperipherals_spi_2__mosi_data & 1);
    _xperipherals_spi_2__miso_data = 0;
    _xperipherals_spi_2__shift_cnt = 1;
    _xperipherals_spi_2__io_timer :> _xperipherals_spi_2__io_time;
    _xperipherals_spi_2__io_state = 1;
}

//                                   +-------+       +-------+       +-------+
// CPOL = 0, CPHA = 0                |       |       |       |       |       |
//                      -------------+       +-------+       +-------+       +
//                           +---------------+---------------+---------------+
// CPOL = 0, CPHA = 0   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                      -------------+       +-------+       +-------+       +
// CPOL = 1, CPHA = 0                |       |       |       |       |       |
//                                   +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 1, CPHA = 0   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                           +-------+       +-------+       +-------+
// CPOL = 0, CPHA = 1        |       |       |       |       |       |
//                      -----+       +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 0, CPHA = 1   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                      -----+       +-------+       +-------+       +-------+
// CPOL = 1, CPHA = 1        |       |       |       |       |       |
//                           +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 1, CPHA = 1   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2

select xperipherals_spi_2__continue_io( int& status )
{
    case _xperipherals_spi_2__io_state > 0 => _xperipherals_spi_2__io_timer when timerafter(_xperipherals_spi_2__io_time) :> _xperipherals_spi_2__io_time:

        switch( _xperipherals_spi_2__io_state )
        {
            case 1: // S1

            _xperipherals_spi_2__pin_miso :> _xperipherals_spi_2__temp_data;
            _xperipherals_spi_2__pin_sclk <: ((XPERIPHERALS_SPI_2__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_2__MODE_CPHA !=0 ));
            _xperipherals_spi_2__miso_data |=  (_xperipherals_spi_2__temp_data << _xperipherals_spi_2__shift_cnt) & 1;

            _xperipherals_spi_2__io_state = 2;
            status = XPERIPHERALS_SPI__STATUS__NONE;
            break;

            case 2: // S2

            if( _xperipherals_spi_2__shift_cnt <= 7 )
            {
                _xperipherals_spi_2__pin_sclk <: !((XPERIPHERALS_SPI_2__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_2__MODE_CPHA !=0 ));
                _xperipherals_spi_2__pin_mosi <: (xbyte)(_xperipherals_spi_2__mosi_data >> _xperipherals_spi_2__shift_cnt++) & 1;
                _xperipherals_spi_2__io_state = 1;
                status = XPERIPHERALS_SPI__STATUS__NONE;
            }
            else
            {
                _xperipherals_spi_2__pin_sclk <: !((XPERIPHERALS_SPI_2__MODE_CPOL !=0 ) ^ (XPERIPHERALS_SPI_2__MODE_CPHA !=0 ));
                _xperipherals_spi_2__io_state = 0;
                status = XPERIPHERALS_SPI__STATUS__EVENT_IO_DONE;
            }
            break;
        }
        break;
}

xbyte xperipherals_spi_2__get_data( void ) { return _xperipherals_spi_2__miso_data; }

int xperipherals_spi_2__write( xbyte mosi_data )  { xbyte tmp; return xperipherals_spi_2__transfer( mosi_data, tmp ); }
int xperipherals_spi_2__read ( xbyte& miso_data ) { return xperipherals_spi_2__transfer( 0x00, miso_data ); }

int xperipherals_spi_2__transfer( xbyte mosi_data, xbyte& miso_data )
{
    int status;
    xperipherals_spi_2__begin_write( mosi_data );
    while( TRUE ) {
        select {case xperipherals_spi_2__io_continue( status );}
        if( status != XPERIPHERALS_SPI__STATUS__NONE ) break;
    }
    return status;
}

#else

#if XPERIPHERALS_SPI_2__BUS_MASTER

void xperipherals_spi_2__initialize( void )
{
}

int xperipherals_spi_2__write( xbyte mosi_data )
{
    return 0;
}

int xperipherals_spi_2__read( xbyte& miso_data )
{
    return 0;
}

xbyte xperipherals_spi_2__transfer( xbyte mosi_data )
{
    return 0;
}

void xperipherals_spi_2__xfer_start( xbyte mosi_data )
{
    return 0;
}

select xperipherals_spi_2__xfer_done( xbool& done_flag, xbyte& miso_data )
{
    return 0;
}

void xperipherals_spi_2__begin_write( xbyte mosi_data )
{
    return 0;
}

void xperipherals_spi_2__begin_read( void )
{
    return 0;
}

void xperipherals_spi_2__begin_xfer( xbyte mosi_data )
{
    #endif
}

select xperipherals_spi_2__continue_io( int& status )
{
}

xbyte xperipherals_spi_2__get_data( void )
{
    return _xperipherals_spi_2__data;
}

#endif

#endif

xperipherals_spi_3.xc

#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <print.h>

#include "xperipherals_spi.h"

#ifdef XPERIPHERALS_SPI_3

#if XPERIPHERALS_SPI_3__BUS_MASTER

    on tile[XPERIPHERALS_SPI_3__TILE_NUMBER] : out port _xperipherals_spi_3__pin_sclk = XPERIPHERALS_SPI_3__SCLK_PORT;
    on tile[XPERIPHERALS_SPI_3__TILE_NUMBER] : out port _xperipherals_spi_3__pin_mosi = XPERIPHERALS_SPI_3__MOSI_PORT;
    on tile[XPERIPHERALS_SPI_3__TILE_NUMBER] : in  port _xperipherals_spi_3__pin_miso = XPERIPHERALS_SPI_3__MISO_PORT;

#else

    on tile[XPERIPHERALS_SPI_3__TILE_NUMBER] : in port  _xperipherals_spi_3__pin_sclk = XPERIPHERALS_SPI_3__SCLK_PORT;
    on tile[XPERIPHERALS_SPI_3__TILE_NUMBER] : out port _xperipherals_spi_3__pin_mosi = XPERIPHERALS_SPI_3__MOSI_PORT;
    on tile[XPERIPHERALS_SPI_3__TILE_NUMBER] : in  port _xperipherals_spi_3__pin_miso = XPERIPHERALS_SPI_3__MISO_PORT;

#endif

#if XPERIPHERALS_SPI_3__BUS_MASTER
static timer _xperipherals_spi_3__io_timer;
static int   _xperipherals_spi_3__io_time;
#else
static xbyte _xperipherals_spi_3__sclk;
#endif
static int   _xperipherals_spi_3__io_state;

static int   _xperipherals_spi_3__shift_cnt;
static xbyte _xperipherals_spi_3__mosi_data;
static xbyte _xperipherals_spi_3__miso_data;
static xbyte _xperipherals_spi_3__temp_data;

// <TODO> Calulate based on current system clock frequency

#define _XPERIPHERALS_SPI_3__TIME_BASE ((400000 / XPERIPHERALS_SPI_3__BIT_RATE) * 62)

#if XPERIPHERALS_SPI_3__BUS_MASTER

void xperipherals_spi_3__initialize( void )
{
    _xperipherals_spi_3__io_state = 0;
    _xperipherals_spi_3__pin_sclk <: (XPERIPHERALS_SPI_3__MODE_CPOL != 0);
    _xperipherals_spi_3__io_timer :> _xperipherals_spi_3__io_time;
    _xperipherals_spi_3__io_timer when timerafter( _xperipherals_spi_3__io_time + 10 * _XPERIPHERALS_SPI_3__TIME_BASE ) :> void;
}

void xperipherals_spi_3__begin_write( xbyte mosi_data ) { xperipherals_spi_3__begin_xfer( mosi_data ); }
void xperipherals_spi_3__begin_read ( void )            { xperipherals_spi_3__begin_xfer( 0x00 ); }

void xperipherals_spi_3__begin_xfer( xbyte mosi_data )
{
    _xperipherals_spi_3__mosi_data = mosi_data;
    _xperipherals_spi_3__pin_sclk <: !((XPERIPHERALS_SPI_3__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_3__MODE_CPHA !=0 ));
    _xperipherals_spi_3__pin_mosi <: (xbyte)(_xperipherals_spi_3__mosi_data & 1);
    _xperipherals_spi_3__miso_data = 0;
    _xperipherals_spi_3__shift_cnt = 1;
    _xperipherals_spi_3__io_timer :> _xperipherals_spi_3__io_time;
    _xperipherals_spi_3__io_state = 1;
}

//                                   +-------+       +-------+       +-------+
// CPOL = 0, CPHA = 0                |       |       |       |       |       |
//                      -------------+       +-------+       +-------+       +
//                           +---------------+---------------+---------------+
// CPOL = 0, CPHA = 0   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                      -------------+       +-------+       +-------+       +
// CPOL = 1, CPHA = 0                |       |       |       |       |       |
//                                   +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 1, CPHA = 0   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                           +-------+       +-------+       +-------+
// CPOL = 0, CPHA = 1        |       |       |       |       |       |
//                      -----+       +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 0, CPHA = 1   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2
//
//                      -----+       +-------+       +-------+       +-------+
// CPOL = 1, CPHA = 1        |       |       |       |       |       |
//                           +-------+       +-------+       +-------+
//                           +---------------+---------------+---------------+
// CPOL = 1, CPHA = 1   XXXXX|       0       |       1       |       2       |
//                           +---------------+---------------+---------------+
//                           Beg     S1      S2      S1      S2      S1      S2

select xperipherals_spi_3__continue_io( int& status )
{
    case _xperipherals_spi_3__io_state > 0 => _xperipherals_spi_3__io_timer when timerafter(_xperipherals_spi_3__io_time) :> _xperipherals_spi_3__io_time:

        switch( _xperipherals_spi_3__io_state )
        {
            case 1: // S1

            _xperipherals_spi_3__pin_miso :> _xperipherals_spi_3__temp_data;
            _xperipherals_spi_3__pin_sclk <: ((XPERIPHERALS_SPI_3__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_3__MODE_CPHA !=0 ));
            _xperipherals_spi_3__miso_data |=  (_xperipherals_spi_3__temp_data << _xperipherals_spi_3__shift_cnt) & 1;

            _xperipherals_spi_3__io_state = 2;
            status = XPERIPHERALS_SPI__STATUS__NONE;
            break;

            case 2: // S2

            if( _xperipherals_spi_3__shift_cnt <= 7 )
            {
                _xperipherals_spi_3__pin_sclk <: !((XPERIPHERALS_SPI_3__MODE_CPOL !=0) ^ (XPERIPHERALS_SPI_3__MODE_CPHA !=0 ));
                _xperipherals_spi_3__pin_mosi <: (xbyte)(_xperipherals_spi_3__mosi_data >> _xperipherals_spi_3__shift_cnt++) & 1;
                _xperipherals_spi_3__io_state = 1;
                status = XPERIPHERALS_SPI__STATUS__NONE;
            }
            else
            {
                _xperipherals_spi_3__pin_sclk <: !((XPERIPHERALS_SPI_3__MODE_CPOL !=0 ) ^ (XPERIPHERALS_SPI_3__MODE_CPHA !=0 ));
                _xperipherals_spi_3__io_state = 0;
                status = XPERIPHERALS_SPI__STATUS__EVENT_IO_DONE;
            }
            break;
        }
        break;
}

xbyte xperipherals_spi_3__get_data( void ) { return _xperipherals_spi_3__miso_data; }

int xperipherals_spi_3__write( xbyte mosi_data )  { xbyte tmp; return xperipherals_spi_3__transfer( mosi_data, tmp ); }
int xperipherals_spi_3__read ( xbyte& miso_data ) { return xperipherals_spi_3__transfer( 0x00, miso_data ); }

int xperipherals_spi_3__transfer( xbyte mosi_data, xbyte& miso_data )
{
    int status;
    xperipherals_spi_3__begin_write( mosi_data );
    while( TRUE ) {
        select {case xperipherals_spi_3__io_continue( status );}
        if( status != XPERIPHERALS_SPI__STATUS__NONE ) break;
    }
    return status;
}

#else

#if XPERIPHERALS_SPI_3__BUS_MASTER

void xperipherals_spi_3__initialize( void )
{
}

int xperipherals_spi_3__write( xbyte mosi_data )
{
    return 0;
}

int xperipherals_spi_3__read( xbyte& miso_data )
{
    return 0;
}

xbyte xperipherals_spi_3__transfer( xbyte mosi_data )
{
    return 0;
}

void xperipherals_spi_3__xfer_start( xbyte mosi_data )
{
    return 0;
}

select xperipherals_spi_3__xfer_done( xbool& done_flag, xbyte& miso_data )
{
    return 0;
}

void xperipherals_spi_3__begin_write( xbyte mosi_data )
{
    return 0;
}

void xperipherals_spi_3__begin_read( void )
{
    return 0;
}

void xperipherals_spi_3__begin_xfer( xbyte mosi_data )
{
    #endif
}

select xperipherals_spi_3__continue_io( int& status )
{
}

xbyte xperipherals_spi_3__get_data( void )
{
    return _xperipherals_spi_3__data;
}

#endif

#endif