Newer
Older
pyenergenie / src / energenie / drv / spis.c
/* 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"
#include "trace.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)


/***** 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)
  {
    TRACE_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 *****/