Skip to content

lib_spi: Use hardware SPI

Richard Hodges edited this page Jul 19, 2020 · 2 revisions

This library makes it easier to use the hardware SPI, and use multiple devices with different SPI configurations. Each SPI configuration has its own SPI context, and the library changes SPI settings as needed. NOTE that you may need to change the SPI configuration before you assert the SPI device's *enable pin. You can use c spi_config(SPI_CTX *ctx); to do this.

Set up the SPI context, set the TX and/or RX buffer pointers, and call spi_init(SPI_CTX *ctx). To do an SPI transaction, set the tx_count and rx_count to zero or the number of bytes to send or receive. Then call spi_start(SPI_CTX *ctx), a non-blocking function that returns immediately. You can use spi_wait(SPI_CTX *ctx) to wait for the end of the transaction. Be sure to wait before de-asserting the SPI *enable pin.

You can see the SPI text and example code here: https://github.com/unfrozen/stm8_tests/blob/master/test_spi.c

/*
 *  SPI context
 */

typedef struct {
    int		tx_count;	/* TX bytes to send */
    int		rx_count;	/* RX bytes to get */
    char	*tx_buf;	/* TX buffer, ignored if tx_count is zero  */
    char	*rx_buf;	/* RX buffer, ignored if rx_count is zero  */
    char	config;		/* see config values below */
    char	state;		/* IDLE, READ, WRITE, or RW */
    char	flag_bidir;	/* set if one pin (MOSI) is both RX & TX */
    char	flag_done;	/* set when SPI transaction is almost done */
} SPI_CTX;

/*
 * Note that flag_done is set when the read is complete, or the write buffer
 * is empty. When writing, the SPI will still be sending the last bits.
 * If you need to know that the SPI is inactive, use spi_wait() to be sure.
 */

/*
 *  Initialize SPI
 */
void spi_init(SPI_CTX *);

/*
 *  Start SPI transaction
 *  in:  SPI context
 *  out: status code
 *
 *  NOTE: This function will wait (block) if there is current transaction.
 *  NOTE: If bidirectional I/O, do not combine RX and TX in transaction.
 */
char spi_start(SPI_CTX *);

/*
 *  Wait for previous SPI transaction to finish.
 */
void spi_wait(void);

/*
 *  Reconfigure SPI for changed context.
 *
 *  The spi_start() function will do this if needed, but if you have an
 *  enable pin for the SPI device, you may need to change the configuration
 *  before you assert the enable pin. A glitch in the SPI clock and/or MOSI
 *  pin may upset the device.
 */
void spi_config(SPI_CTX *);

/* SPI bit endian */

#define SPI_MSB_FIRST	0x00
#define SPI_LSB_FIRST	0x80
/*
 * SPI CLOCK SPEED
 */
#define SPI_8MHZ	0x00
#define SPI_4MHZ	0x08
#define SPI_2MHZ	0x10
#define SPI_1MHZ	0x18
#define SPI_500K	0x20
#define SPI_250K	0x28
#define SPI_125K	0x30
#define SPI_62K		0x38

/* SPI level when idle */

#define SPI_IDLE_0	0x00	/* Clock is low when idle. */
#define SPI_IDLE_1	0x02	/* Clock is high when idle. */

/* SPI "polarity", data on clock edge 1 or 2? */

#define SPI_EDGE_1	0x00	/* Data is valid on 1st clock edge from idle. */
#define SPI_EDGE_2	0x01	/* Data is valid on 2nd clock edge from idle. */