added data structures
added audio support added rfid support added spi support
This commit is contained in:
312
io/SPI.h
Normal file
312
io/SPI.h
Normal file
@@ -0,0 +1,312 @@
|
||||
#ifndef SPI_H
|
||||
#define SPI_H
|
||||
|
||||
// https://github.com/MetalPhreak/ESP8266_SPI_Driver/blob/master/include/driver/spi.h
|
||||
// http://d.av.id.au/blog/esp8266-hardware-spi-driver-code-library/
|
||||
|
||||
// MTDI GPIO12 MISO (DIN) D6
|
||||
// MTCK GPIO13 MOSI (DOUT) D7
|
||||
// MTMS GPIO14 CLOCK D5
|
||||
// MTDO GPIO15 CS / SS D8
|
||||
|
||||
// http://www.14core.com/wp-content/uploads/2015/06/Node-MCU-Pin-Out-Diagram1.png
|
||||
|
||||
extern "C" {
|
||||
#include "eagle_soc.h"
|
||||
#include "driver/spi_register.h"
|
||||
}
|
||||
|
||||
|
||||
class SPI {
|
||||
|
||||
// user SPI
|
||||
#define spi_no 1
|
||||
|
||||
#define SPI_CLK_USE_DIV 0
|
||||
#define SPI_CLK_80MHZ_NODIV 1
|
||||
|
||||
#define SPI_BYTE_ORDER_HIGH_TO_LOW 1
|
||||
#define SPI_BYTE_ORDER_LOW_TO_HIGH 0
|
||||
|
||||
//Define some default SPI clock settings
|
||||
#define SPI_CLK_PREDIV 4
|
||||
#define SPI_CLK_CNTDIV 1
|
||||
#define SPI_CLK_FREQ CPU_CLK_FREQ/(SPI_CLK_PREDIV*SPI_CLK_CNTDIV) // 80 / 20 = 4 MHz
|
||||
|
||||
public:
|
||||
|
||||
SPI() {
|
||||
init();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool isBusy() const {
|
||||
return READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR;
|
||||
}
|
||||
|
||||
void sendByte(const uint8_t byte) {
|
||||
send(8, byte);
|
||||
}
|
||||
|
||||
void sendWord(const uint16_t word) {
|
||||
send(16, word);
|
||||
}
|
||||
|
||||
uint8_t readByte() {
|
||||
return read(8);
|
||||
}
|
||||
|
||||
uint16_t readWord() {
|
||||
return read(16);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void send(const uint8_t bits, const uint32_t val) {
|
||||
|
||||
// wait for SPI to be free
|
||||
while(isBusy()) {;}
|
||||
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO|SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_DUMMY);
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); // MOSI only (write only)
|
||||
|
||||
const uint32_t addr_bits = 0;
|
||||
const uint32_t dout_bits = bits;
|
||||
const uint32_t din_bits = 0;
|
||||
const uint32_t dummy_bits = 0;
|
||||
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no), ((addr_bits-1)&SPI_USR_ADDR_BITLEN)<<SPI_USR_ADDR_BITLEN_S | //Number of bits in Address
|
||||
((dout_bits-1)&SPI_USR_MOSI_BITLEN)<<SPI_USR_MOSI_BITLEN_S | //Number of bits to Send
|
||||
((din_bits-1)&SPI_USR_MISO_BITLEN)<<SPI_USR_MISO_BITLEN_S | //Number of bits to receive
|
||||
((dummy_bits-1)&SPI_USR_DUMMY_CYCLELEN)<<SPI_USR_DUMMY_CYCLELEN_S); //Number of Dummy bits to insert
|
||||
|
||||
//if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), val);
|
||||
//}
|
||||
|
||||
// start transfer
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
|
||||
// do NOT wait for the transfer to finish! -> faster
|
||||
//while (isBusy()) {;}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t read(const uint8_t bits) {
|
||||
|
||||
// wait for SPI to be free
|
||||
while(isBusy()) {;}
|
||||
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO|SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_DUMMY);
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); // MISO only (read only)
|
||||
|
||||
const uint32_t addr_bits = 0;
|
||||
const uint32_t dout_bits = 0;
|
||||
const uint32_t din_bits = bits;
|
||||
const uint32_t dummy_bits = 0;
|
||||
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no), ((addr_bits-1)&SPI_USR_ADDR_BITLEN)<<SPI_USR_ADDR_BITLEN_S | //Number of bits in Address
|
||||
((dout_bits-1)&SPI_USR_MOSI_BITLEN)<<SPI_USR_MOSI_BITLEN_S | //Number of bits to Send
|
||||
((din_bits-1)&SPI_USR_MISO_BITLEN)<<SPI_USR_MISO_BITLEN_S | //Number of bits to receive
|
||||
((dummy_bits-1)&SPI_USR_DUMMY_CYCLELEN)<<SPI_USR_DUMMY_CYCLELEN_S); //Number of Dummy bits to insert
|
||||
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
|
||||
// wait for the reading to finish
|
||||
while (isBusy()) {;}
|
||||
|
||||
//if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) {
|
||||
// return READ_PERI_REG(SPI_W0(spi_no)) >> (32-din_bits); //Assuming data in is written to MSB. TBC
|
||||
//} else {
|
||||
return READ_PERI_REG(SPI_W0(spi_no)); //Read in the same way as DOUT is sent. Note existing contents of SPI_W0 remain unless overwritten!
|
||||
//}
|
||||
|
||||
return 0; //something went wrong
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init() {
|
||||
|
||||
spi_init_gpio(SPI_CLK_USE_DIV);
|
||||
spi_clock(SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
|
||||
spi_tx_byte_order(SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
spi_rx_byte_order(SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
|
||||
|
||||
}
|
||||
|
||||
void spi_init_gpio(const bool fullSpeed){
|
||||
|
||||
uint32 clock_div_flag = 0;
|
||||
if (fullSpeed) {
|
||||
clock_div_flag = 0x0001;
|
||||
}
|
||||
|
||||
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105|(clock_div_flag<<9)); //Set bit 9 if 80MHz sysclock required
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); //GPIO12 is HSPI MISO pin (Master Data In)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); //GPIO13 is HSPI MOSI pin (Master Data Out)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); //GPIO14 is HSPI CLK pin (Clock)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); //GPIO15 is HSPI CS pin (Chip Select / Slave Select)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
uint32 spi_transaction(uint8 spi_no, uint8 cmd_bits, uint16 cmd_data, uint32 addr_bits, uint32 addr_data, uint32 dout_bits, uint32 dout_data,
|
||||
uint32 din_bits, uint32 dummy_bits){
|
||||
|
||||
if(spi_no > 1) return 0; //Check for a valid SPI
|
||||
|
||||
//code for custom Chip Select as GPIO PIN here
|
||||
|
||||
while(spi_busy(spi_no)); //wait for SPI to be ready
|
||||
|
||||
//########## Enable SPI Functions ##########//
|
||||
//disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO|SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_DUMMY);
|
||||
|
||||
//enable functions based on number of bits. 0 bits = disabled.
|
||||
//This is rather inefficient but allows for a very generic function.
|
||||
//CMD ADDR and MOSI are set below to save on an extra if statement.
|
||||
// if(cmd_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);}
|
||||
// if(addr_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR);}
|
||||
if(din_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);}
|
||||
if(dummy_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY);}
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//########## Setup Bitlengths ##########//
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no), ((addr_bits-1)&SPI_USR_ADDR_BITLEN)<<SPI_USR_ADDR_BITLEN_S | //Number of bits in Address
|
||||
((dout_bits-1)&SPI_USR_MOSI_BITLEN)<<SPI_USR_MOSI_BITLEN_S | //Number of bits to Send
|
||||
((din_bits-1)&SPI_USR_MISO_BITLEN)<<SPI_USR_MISO_BITLEN_S | //Number of bits to receive
|
||||
((dummy_bits-1)&SPI_USR_DUMMY_CYCLELEN)<<SPI_USR_DUMMY_CYCLELEN_S); //Number of Dummy bits to insert
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//########## Setup Command Data ##########//
|
||||
if(cmd_bits) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND); //enable COMMAND function in SPI module
|
||||
uint16 command = cmd_data << (16-cmd_bits); //align command data to high bits
|
||||
command = ((command>>8)&0xff) | ((command<<8)&0xff00); //swap byte order
|
||||
WRITE_PERI_REG(SPI_USER2(spi_no), ((((cmd_bits-1)&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S) | command&SPI_USR_COMMAND_VALUE));
|
||||
}
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//########## Setup Address Data ##########//
|
||||
if(addr_bits){
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR); //enable ADDRess function in SPI module
|
||||
WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data<<(32-addr_bits)); //align address data to high bits
|
||||
}
|
||||
|
||||
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//########## Setup DOUT data ##########//
|
||||
if(dout_bits) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); //enable MOSI function in SPI module
|
||||
//copy data to W0
|
||||
if(READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data<<(32-dout_bits));
|
||||
} else {
|
||||
|
||||
uint8 dout_extra_bits = dout_bits%8;
|
||||
|
||||
if(dout_extra_bits){
|
||||
//if your data isn't a byte multiple (8/16/24/32 bits)and you don't have SPI_WR_BYTE_ORDER set, you need this to move the non-8bit remainder to the MSBs
|
||||
//not sure if there's even a use case for this, but it's here if you need it...
|
||||
//for example, 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output as if it were 0x0DA4,
|
||||
//of which 0xA4, and then 0x0 would be shifted out (first 8 bits of low byte, then 4 MSB bits of high byte - ie reverse byte order).
|
||||
//The code below shifts it out as 0xA4 followed by 0xD as you might require.
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), ((0xFFFFFFFF<<(dout_bits - dout_extra_bits)&dout_data)<<(8-dout_extra_bits) | (0xFFFFFFFF>>(32-(dout_bits - dout_extra_bits)))&dout_data));
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//########## Begin SPI Transaction ##########//
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//########## Return DIN data ##########//
|
||||
if(din_bits) {
|
||||
while(spi_busy(spi_no)); //wait for SPI transaction to complete
|
||||
|
||||
if(READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) {
|
||||
return READ_PERI_REG(SPI_W0(spi_no)) >> (32-din_bits); //Assuming data in is written to MSB. TBC
|
||||
} else {
|
||||
return READ_PERI_REG(SPI_W0(spi_no)); //Read in the same way as DOUT is sent. Note existing contents of SPI_W0 remain unless overwritten!
|
||||
}
|
||||
|
||||
return 0; //something went wrong
|
||||
}
|
||||
//########## END SECTION ##########//
|
||||
|
||||
//Transaction completed
|
||||
return 1; //success
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void spi_clock(const uint16 prediv, const uint8 cntdiv){
|
||||
|
||||
if ( (prediv==0) | (cntdiv==0) ) {
|
||||
|
||||
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); // full speed
|
||||
|
||||
} else {
|
||||
|
||||
WRITE_PERI_REG(SPI_CLOCK(spi_no),
|
||||
(((prediv-1)&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|
|
||||
(((cntdiv-1)&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
|
||||
(((cntdiv>>1)&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
|
||||
((0&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void spi_mode(const uint8 spi_cpha, const uint8 spi_cpol) {
|
||||
|
||||
if(!spi_cpha == !spi_cpol) {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
|
||||
} else {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
|
||||
}
|
||||
|
||||
if (spi_cpol) {
|
||||
SET_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void spi_tx_byte_order(const uint8 byte_order){
|
||||
if (byte_order){
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void spi_rx_byte_order(const uint8 byte_order){
|
||||
if (byte_order){
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#undef spi_no
|
||||
|
||||
#endif // SPI_H
|
||||
Reference in New Issue
Block a user