/* spis.c D.J.Whale 19/07/2014 * * Software SPI driver built on top of gpio */ /***** INCLUDES *****/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "system.h" #include "spi.h" #include "gpio.h" #include "delay.h" /***** MACROS *****/ #define CLOCK_ACTIVE() gpio_write(config.sclk, config.cpol?0:1) #define CLOCK_IDLE() gpio_write(config.sclk, config.cpol?1:0) #define SELECTED() gpio_write(config.cs, config.spol?1:0) #define NOT_SELECTED() gpio_write(config.cs, config.spol?0:1) //TODO: Posix specific, won't work on Arduino #define FAIL(msg) do { \ fprintf(stderr, "%s", msg); \ exit(-1); \ } while (0) /***** VARIABLES *****/ static SPI_CONFIG config; void spi_init_defaults(void) { #define CS 7 //CE1 #define SCLK 11 #define MOSI 10 #define MISO 9 /* ms */ #define TSETTLE (1) /* us settle */ #define THOLD (1) /* us hold */ #define TFREQ (1) /* us half clock */ SPI_CONFIG defaultConfig = {CS, SCLK, MOSI, MISO, SPI_SPOL0, SPI_CPOL0, SPI_CPHA0, TSETTLE, THOLD, TFREQ}; spi_init(&defaultConfig); } void spi_init(SPI_CONFIG* pConfig) { /* It's a standalone library, so init GPIO also */ gpio_init(); memcpy(&config, pConfig, sizeof(SPI_CONFIG)); //TODO: Implement CPHA1 if (config.cpha != 0) { FAIL("error: CPHA 1 not yet supported"); } gpio_setout(config.sclk); CLOCK_IDLE(); gpio_setout(config.mosi); gpio_low(config.mosi); gpio_setin(config.miso); gpio_setout(config.cs); NOT_SELECTED(); } void spi_finished(void) { gpio_setin(config.mosi); gpio_setin(config.sclk); gpio_setin(config.cs); } void spi_select(void) { SELECTED(); delayus(config.tSettle); } void spi_deselect(void) { NOT_SELECTED(); delayus(config.tSettle); } int spi_byte(uint8_t txbyte) { uint8_t rxbyte = 0; uint8_t bitno; uint8_t bit ; //TODO: Implement CPHA1 for (bitno=0; bitno<8; bitno++) { /* Transmit MSB first */ bit = ((txbyte & 0x80) != 0x00); txbyte <<= 1; gpio_write(config.mosi, bit); delayus(config.tSettle); CLOCK_ACTIVE(); delayus(config.tHold); delayus(config.tFreq); /* Read MSB first */ bit = gpio_read(config.miso); rxbyte = (rxbyte<<1) | bit; CLOCK_IDLE(); delayus(config.tFreq); } return rxbyte; } void spi_frame(uint8_t* pTx, uint8_t* pRx, uint8_t count) { uint8_t tx = 0; uint8_t rx; while (count > 0) { if (pTx != NULL) { tx = *(pTx++); } rx = spi_byte(tx); if (pRx != NULL) { *(pRx++) = rx; } count--; } } /***** END OF FILE *****/