diff --git a/module_spi_master/src/spi_master.h b/module_spi_master/src/spi_master.h index 4567f5f..f0b7f82 100644 --- a/module_spi_master/src/spi_master.h +++ b/module_spi_master/src/spi_master.h @@ -3,19 +3,6 @@ // University of Illinois/NCSA Open Source License posted in // LICENSE.txt and at -/////////////////////////////////////////////////////////////////////////////// -// -// 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_ @@ -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__ @@ -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. @@ -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 diff --git a/module_spi_master/src/spi_master.xc b/module_spi_master/src/spi_master.xc index 5202e13..f165727 100644 --- a/module_spi_master/src/spi_master.xc +++ b/module_spi_master/src/spi_master.xc @@ -9,34 +9,56 @@ #include #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); @@ -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); } @@ -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; } @@ -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)