#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)< 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)<> (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)<>8)&0xff) | ((command<<8)&0xff00); //swap byte order WRITE_PERI_REG(SPI_USER2(spi_no), ((((cmd_bits-1)&SPI_USR_COMMAND_BITLEN)<>(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)<>1)&SPI_CLKCNT_H)<