spiport.c 4.79 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*
 * spiport.c
 *
 * Created: 2/7/2018 10:51:42 AM
 *  Author: Jake
 */ 

#include "spiport.h"

spiport_t spi_new(Sercom *com, PortGroup *port, uint32_t miso_pin, uint32_t mosi_pin, uint32_t sck_pin, uint32_t csn_pin, uint32_t apbx, uint32_t peripheral){
	spiport_t spi;
	
	spi.com = com;
	spi.port = port;
	
	spi.miso_pin = miso_pin;
	spi.miso_bm = (uint32_t)(1 << miso_pin);
	spi.mosi_pin = mosi_pin;
	spi.mosi_bm = (uint32_t)(1 << mosi_pin);
	spi.sck_pin = sck_pin;
	spi.sck_bm = (uint32_t)(1 << sck_pin);
	spi.csn_pin = csn_pin;
	spi.csn_bm = (uint32_t)(1 << csn_pin);
	
	spi.apbx = apbx;
	spi.peripheral = peripheral;
	
	return spi;
}

void spi_init(spiport_t *spi, uint32_t gclknum, uint32_t gclkidcore, uint8_t baud, uint8_t dipo, uint8_t dopo, uint8_t csnhardware, uint8_t cpha, uint8_t cpol, uint8_t lsbfirst){
	// to add to this lib: doc, cleaning, options properly enumerated: do when doing AS5147
	// clk is unmasked (external to this lib)
	// do pin configs
Jake Read's avatar
Jake Read committed
35
	spi->port->DIRCLR.reg = spi->miso_bm;
36
	spi->port->PINCFG[spi->miso_pin].bit.PMUXEN = 1;
Jake Read's avatar
Jake Read committed
37
	spi->port->DIRSET.reg = spi->mosi_bm | spi->sck_bm | spi->csn_bm;
38 39 40 41 42
	spi->port->PINCFG[spi->mosi_pin].bit.PMUXEN = 1;
	spi->port->PINCFG[spi->sck_pin].bit.PMUXEN = 1;
	
	if(csnhardware){
		spi->port->PINCFG[spi->csn_pin].bit.PMUXEN = 1;
Jake Read's avatar
Jake Read committed
43
		spi->com->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_MSSEN;
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
		if(spi->csn_pin % 2){ // yes if odd
			spi->port->PMUX[spi->csn_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
			} else {
			spi->port->PMUX[spi->csn_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
		}
	}else{
		spi->port->OUTSET.reg = spi->csn_bm; // set hi to start! - this should properly depend on our CPHA !
	}
	
	if(spi->miso_pin % 2){ // yes if odd
		spi->port->PMUX[spi->miso_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
	} else {
		spi->port->PMUX[spi->miso_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
	}
	
	if(spi->mosi_pin % 2){ // yes if odd
		spi->port->PMUX[spi->mosi_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
		} else {
		spi->port->PMUX[spi->mosi_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
	}
	
	if(spi->sck_pin % 2){ // yes if odd
		spi->port->PMUX[spi->sck_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
		} else {
		spi->port->PMUX[spi->sck_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
	}
	
	// build a clock for
	GCLK->GENCTRL[gclknum].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) | GCLK_GENCTRL_GENEN;
	while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclknum));
	GCLK->PCHCTRL[gclkidcore].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(gclknum);
	
	// now some SERCOM
	// tmc spi is clock inactive hi
	// tmc spi latches data on the rising edge of sck and drives data out on the next falling edge
	spi->com->SPI.CTRLA.bit.ENABLE = 0;
	// master, data in pinout, data out pinout
	spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x03);
	if(cpol){
		spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_CPOL;
	}
	if(cpha){
		spi->com->SPI.CTRLA.reg	|= SERCOM_SPI_CTRLA_CPHA;
	}
	if(lsbfirst){
		SERCOM0->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_DORD; // 0 MSB, 1 LSB
	}
	spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_DIPO(dipo) | SERCOM_SPI_CTRLA_DOPO(dopo);
	// these to defaults, but here for show
	//SERCOM0->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_CHSIZE(0x0); // 8 bits character - 0x0, so no need to set
	// BAUD
	// f_baud = f_ref / (2 * (BAUD +1)) so BAUD = f_ref / (2 * f_baud) - 1
	spi->com->SPI.BAUD.reg |= SERCOM_SPI_BAUD_BAUD(baud);
	// use hardware slave select, enable receiver
	spi->com->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_RXEN; //SERCOM_SPI_CTRLB_MSSEN | 
	// 8 or 32 bits
	// do if(bits)
	//spi->com->SPI.CTRLC.reg |= SERCOM_SPI_CTRLC_DATA32B;
	//spi->com->SPI.LENGTH.reg |= SERCOM_SPI_LENGTH_LENEN | SERCOM_SPI_LENGTH_LEN(20);
	
	// turnt it up
	spi->com->SPI.CTRLA.bit.ENABLE = 1;
}

void spi_txchar_polled(spiport_t *spi, uint8_t data){
	while(!(spi->com->SPI.INTFLAG.bit.DRE));
	spi->com->SPI.DATA.reg = SERCOM_SPI_DATA_DATA(data);
}

void spi_txchars_polled(spiport_t *spi, uint8_t *data, uint8_t length){
	spi->port->OUTCLR.reg = spi->csn_bm;
	for(int i = 0; i < length; i ++){
		spi_txchar_polled(spi, data[i]);
	}
Jake Read's avatar
Jake Read committed
118 119 120 121 122 123 124 125 126 127 128 129 130
	while(!spi->com->SPI.INTFLAG.bit.TXC); // wait for complete of last byte before
	spi->port->OUTSET.reg = spi->csn_bm;
}

void spi_txrxchars_polled(spiport_t *spi, uint8_t *data_tx, uint8_t length, uint8_t *data_rx){
	spi->port->OUTCLR.reg = spi->csn_bm;
	for(int i = 0; i < length; i ++){
		while(!(spi->com->SPI.INTFLAG.bit.DRE));
		spi->com->SPI.DATA.reg = SERCOM_SPI_DATA_DATA(data_tx[i]);
		while(!(spi->com->SPI.INTFLAG.bit.RXC)); // wait for data to come out of rx buffer
		data_rx[i] = spi->com->SPI.DATA.reg;
	}
	while(!spi->com->SPI.INTFLAG.bit.TXC); // wait for complete of last byte before
131 132 133 134
	spi->port->OUTSET.reg = spi->csn_bm;
}

void spi_txrxchar_polled(spiport_t *spi, uint8_t data, uint8_t *rxdata){
Jake Read's avatar
Jake Read committed
135
	// not yet bc so far have not needed single receive
136
}