Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move config to struct, add nullable in port #6

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 29 additions & 32 deletions module_spi_master/src/spi_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,6 @@
// University of Illinois/NCSA Open Source License posted in
// LICENSE.txt and at <http://github.xcore.com/>

///////////////////////////////////////////////////////////////////////////////
//
// SPI master
//
// SPI modes:
// +------+------+------+-----------+
// | Mode | CPOL | CPHA | Supported |
// +------+------+------+-----------+
// | 0 | 0 | 0 | Yes |
// | 1 | 0 | 1 | Yes |
// | 2 | 1 | 0 | Yes |
// | 3 | 1 | 1 | Yes |
// +------+------+------+-----------+

#ifndef _spi_master_h_
#define _spi_master_h_
Expand All @@ -30,13 +17,39 @@
* which depend on how many slaves there are and how they're connected.
*
*/

///////////////////////////////////////////////////////////////////////////////
//
// SPI master
//
// SPI modes:
// +------+------+------+-----------+
// | Mode | CPOL | CPHA | Supported |
// +------+------+------+-----------+
// | 0 | 0 | 0 | Yes |
// | 1 | 0 | 1 | Yes |
// | 2 | 1 | 0 | Yes |
// | 3 | 1 | 1 | Yes |
// +------+------+------+-----------+
typedef enum
{
SPI_MASTER_MODE_0,
SPI_MASTER_MODE_1,
SPI_MASTER_MODE_2,
SPI_MASTER_MODE_3
}spi_master_mode_t;

typedef struct spi_master_interface
{
clock blk1;
clock blk2;
out buffered port:8 mosi;
out buffered port:8 sclk;
in buffered port:8 miso;
in buffered port:8 ?miso; //nullable resource (if you are "just" sending you can supply NULL here)
spi_master_mode_t master_mode;
unsigned mosi_high; //SD-CARD compatible setting, pulls MOSI high if true

unsigned sclk_val; //Internal usage will be set by init
} spi_master_interface;

#ifdef __spi_conf_h_exists__
Expand All @@ -55,24 +68,6 @@ typedef struct spi_master_interface
#define DEFAULT_SPI_CLOCK_DIV 8
#endif

#ifndef SPI_MASTER_MODE
/** This constant defines the SPI mode that the master operates in.
*
* See :ref:`sec_spi_modes` for the modes supported by this master, and
* the clock polarity and phase used for each.
*/
#define SPI_MASTER_MODE 3
#endif

#ifndef SPI_MASTER_SD_CARD_COMPAT
/** This constant defines the behaviour of the SPI master while receiving data.
*
* When defined as '1' the SPI master will drive the MOSI line high before
* clocking data in from the slave on the MISO line, as required by SD cards.
*/
#define SPI_MASTER_SD_CARD_COMPAT 0
#endif

/** Configure ports and clocks, clearing port buffers.
*
* Must be called before any SPI data input or output functions are used.
Expand Down Expand Up @@ -190,4 +185,6 @@ void spi_master_out_word(spi_master_interface &spi_if, unsigned int data);
*/
void spi_master_out_buffer(spi_master_interface &spi_if, const unsigned char buffer[], int num_bytes);

char spi_master_out_in_byte(spi_master_interface &spi_if, unsigned char data);

#endif
152 changes: 105 additions & 47 deletions module_spi_master/src/spi_master.xc
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,56 @@
#include <xclib.h>
#include "spi_master.h"

unsigned sclk_val;

void spi_master_init(spi_master_interface &spi_if, int spi_clock_div)
{
// configure ports and clock blocks
configure_clock_rate(spi_if.blk1, 100, spi_clock_div);
#if SPI_MASTER_MODE == 0
set_port_no_inv(spi_if.sclk);
configure_out_port(spi_if.sclk, spi_if.blk1, 0);
sclk_val = 0x55;
#elif SPI_MASTER_MODE == 1
set_port_inv(spi_if.sclk); // invert port and values used
configure_out_port(spi_if.sclk, spi_if.blk1, 1);
sclk_val = 0xAA;
#elif SPI_MASTER_MODE == 2
set_port_inv(spi_if.sclk); // invert port and values used
configure_out_port(spi_if.sclk, spi_if.blk1, 0);
sclk_val = 0x55;
#elif SPI_MASTER_MODE == 3
set_port_no_inv(spi_if.sclk);
configure_out_port(spi_if.sclk, spi_if.blk1, 1);
sclk_val = 0xAA;
#else
#error "Unrecognised SPI mode."
#endif

//Save some function call space ...
unsigned out_port_conf;
unsigned inv;

switch(spi_if.master_mode)
{
case 0:
inv=0;
out_port_conf=0;
spi_if.sclk_val = 0x55;
break;

case 1:
inv=1;
out_port_conf=1;
spi_if.sclk_val = 0xAA;
break;

case 2:
inv=1;
out_port_conf=0;
spi_if.sclk_val = 0x55;
break;

case 3:
inv=0;
out_port_conf=1;
spi_if.sclk_val = 0xAA;
break;
}

if(inv)
{
set_port_inv(spi_if.sclk);
}
else
{
set_port_no_inv(spi_if.sclk);
}

configure_out_port(spi_if.sclk, spi_if.blk1, out_port_conf);
configure_clock_src(spi_if.blk2, spi_if.sclk);
configure_out_port(spi_if.mosi, spi_if.blk2, 0);
configure_in_port(spi_if.miso, spi_if.blk2);
if(!isnull(spi_if.miso))
configure_in_port(spi_if.miso, spi_if.blk2);
clearbuf(spi_if.mosi);
clearbuf(spi_if.sclk);
start_clock(spi_if.blk1);
Expand All @@ -48,7 +70,7 @@ void spi_master_shutdown(spi_master_interface &spi_if)
set_clock_off(spi_if.blk2);
set_clock_off(spi_if.blk1);
set_port_use_off(spi_if.mosi);
set_port_use_off(spi_if.miso);
if(!isnull(spi_if.miso)) set_port_use_off(spi_if.miso);
set_port_use_off(spi_if.sclk);
}

Expand All @@ -57,15 +79,15 @@ static inline unsigned char spi_master_in_byte_internal(spi_master_interface &sp
// MSb-first bit order - SPI standard
unsigned x;

if (SPI_MASTER_SD_CARD_COMPAT)
if (spi_if.mosi_high)
{
spi_if.mosi <: 0xFF; // Pull MOSI high
}
clearbuf(spi_if.miso);
spi_if.sclk <: sclk_val;
spi_if.sclk <: sclk_val;
if(!isnull(spi_if.miso)) clearbuf(spi_if.miso);
spi_if.sclk <: spi_if.sclk_val;
spi_if.sclk <: spi_if.sclk_val;
sync(spi_if.sclk);
spi_if.miso :> x;
if(!isnull(spi_if.miso)) spi_if.miso :> x;
return bitrev(x) >> 24;
}

Expand Down Expand Up @@ -108,27 +130,63 @@ static inline void spi_master_out_byte_internal(spi_master_interface &spi_if, un
// MSb-first bit order - SPI standard
unsigned x = bitrev(data) >> 24;

#if (SPI_MASTER_MODE == 0 || SPI_MASTER_MODE == 2) // modes where CPHA == 0
// handle first bit
asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
spi_if.mosi <: x; // output first bit
asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
asm("setc res[%0], 0x200f" :: "r"(spi_if.mosi)); // set to buffering
asm("settw res[%0], %1" :: "r"(spi_if.mosi), "r"(32)); // set transfer width to 32
stop_clock(spi_if.blk2);
configure_clock_src(spi_if.blk2, spi_if.sclk);
configure_out_port(spi_if.mosi, spi_if.blk2, x);
start_clock(spi_if.blk2);

// output remaining data
spi_if.mosi <: (x >> 1);
#else
spi_if.mosi <: x;
#endif
spi_if.sclk <: sclk_val;
spi_if.sclk <: sclk_val;
if(spi_if.master_mode==0 || spi_if.master_mode==2)
{ // handle first bit
asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
spi_if.mosi <: x; // output first bit
asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
asm("setc res[%0], 0x200f" :: "r"(spi_if.mosi)); // set to buffering
asm("settw res[%0], %1" :: "r"(spi_if.mosi), "r"(32)); // set transfer width to 32
stop_clock(spi_if.blk2);
configure_clock_src(spi_if.blk2, spi_if.sclk);
configure_out_port(spi_if.mosi, spi_if.blk2, x);
start_clock(spi_if.blk2);

// output remaining data
spi_if.mosi <: (x >> 1);
}
else
{
spi_if.mosi <: x;
}

spi_if.sclk <: spi_if.sclk_val;
spi_if.sclk <: spi_if.sclk_val;
sync(spi_if.sclk);
if(!isnull(spi_if.miso)) spi_if.miso :> void;
}

unsigned char spi_master_out_in_byte(spi_master_interface &spi_if, unsigned char data)
{
// MSb-first bit order - SPI standard
unsigned x = bitrev(data) >> 24;

if (spi_if.master_mode == 0 || spi_if.master_mode == 2) // modes where CPHA == 0
{ // handle first bit
asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
spi_if.mosi <: x; // output first bit
asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
asm("setc res[%0], 0x200f" :: "r"(spi_if.mosi)); // set to buffering
asm("settw res[%0], %1" :: "r"(spi_if.mosi), "r"(32)); // set transfer width to 32
stop_clock(spi_if.blk2);
configure_clock_src(spi_if.blk2, spi_if.sclk);
configure_out_port(spi_if.mosi, spi_if.blk2, x);
start_clock(spi_if.blk2);

// output remaining data
spi_if.mosi <: (x >> 1);
}
else
{
spi_if.mosi <: x;
}
spi_if.sclk <: spi_if.sclk_val;
spi_if.sclk <: spi_if.sclk_val;
sync(spi_if.sclk);
spi_if.miso :> void;
unsigned char data_out;
spi_if.miso :> data_out;
return data_out;
}

void spi_master_out_byte(spi_master_interface &spi_if, unsigned char data)
Expand Down