#include "driver/spi.h" /****************************************************************************** * FunctionName : spi_lcd_mode_init * Description : SPI master initial function for driving LCD TM035PDZV36 * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid *******************************************************************************/ void spi_lcd_mode_init(uint8 spi_no) { uint32 regvalue; if(spi_no>1) return; //handle invalid input number //bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock //bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock if(spi_no==SPI){ WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005); //clear bit9,and bit8 PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode }else if(spi_no==HSPI){ WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9 PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode } SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND); CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE); // SPI clock=CPU clock/8 WRITE_PERI_REG(SPI_CLOCK(spi_no), ((1&SPI_CLKDIV_PRE)<1) return; //handle invalid input number if(high_bit) bytetemp=(low_8bit>>1)|0x80; else bytetemp=(low_8bit>>1)&0x7f; regvalue= ((8&SPI_USR_COMMAND_BITLEN)<1) return; //handle invalid input number SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER|SPI_DOUTDIN); // set clock polarity (Reference: http://bbs.espressif.com/viewtopic.php?f=49&t=1570) // phase is dependent on polarity. See Issue #1161 if (cpol == 1) { SET_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE); } else { CLEAR_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE); } //set clock phase if (cpha == cpol) { // Mode 3: MOSI is set on falling edge of clock // Mode 0: MOSI is set on falling edge of clock CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE); SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_I_EDGE); } else { // Mode 2: MOSI is set on rising edge of clock // Mode 1: MOSI is set on rising edge of clock SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE); CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_I_EDGE); } CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE|SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY); //clear Dual or Quad lines transmission mode CLEAR_PERI_REG_MASK(SPI_CTRL(spi_no), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE); // SPI clock = CPU clock / clock_div // the divider needs to be a multiple of 2 to get a proper waveform shape if ((clock_div & 0x01) != 0) { // bump the divider to the next N*2 clock_div += 0x02; } clock_div >>= 1; // clip to maximum possible CLKDIV_PRE clock_div = clock_div > SPI_CLKDIV_PRE ? SPI_CLKDIV_PRE : clock_div - 1; WRITE_PERI_REG(SPI_CLOCK(spi_no), ((clock_div&SPI_CLKDIV_PRE)< 1) return; // handle invalid input number if (bitlen > 32) return; // handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR); // determine which SPI_Wn register is addressed wn = offset >> 5; if (wn > 15) return; // out of range wn_offset = offset & 0x1f; if (32 - wn_offset < bitlen) { // splitting required wn_bitlen = 32 - wn_offset; wn_data = data >> (bitlen - wn_bitlen); } else { wn_bitlen = bitlen; wn_data = data; } do { // write payload data to SPI_Wn SET_PERI_REG_BITS(REG_SPI_BASE(spi_no) +0x40 + wn*4, BIT(wn_bitlen) - 1, wn_data, 32 - (wn_offset + wn_bitlen)); // prepare writing of dangling data part wn += 1; wn_offset = 0; if (wn <= 15) bitlen -= wn_bitlen; else bitlen = 0; // force abort wn_bitlen = bitlen; wn_data = data; } while (bitlen > 0); return; } /****************************************************************************** * FunctionName : spi_mast_get_miso * Description : Retrieve data from MISO buffer. * The data is regarded as a sequence of bits with length 'bitlen'. * It will be read starting left-aligned from position 'offset'. * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid * uint16 offset - offset into MISO buffer (number of bits) * uint8 bitlen - requested number of bits in data *******************************************************************************/ uint32 spi_mast_get_miso(uint8 spi_no, uint16 offset, uint8 bitlen) { uint8 wn, wn_offset, wn_bitlen; uint32 wn_data = 0; if (spi_no > 1) return 0; // handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR); // determine which SPI_Wn register is addressed wn = offset >> 5; if (wn > 15) return 0; // out of range wn_offset = offset & 0x1f; if (bitlen > (32 - wn_offset)) { // splitting required wn_bitlen = 32 - wn_offset; } else { wn_bitlen = bitlen; } do { wn_data |= (READ_PERI_REG(REG_SPI_BASE(spi_no) +0x40 + wn*4) >> (32 - (wn_offset + wn_bitlen))) & (BIT(wn_bitlen) - 1); // prepare reading of dangling data part wn_data <<= bitlen - wn_bitlen; wn += 1; wn_offset = 0; if (wn <= 15) bitlen -= wn_bitlen; else bitlen = 0; // force abort wn_bitlen = bitlen; } while (bitlen > 0); return wn_data; } /****************************************************************************** * FunctionName : spi_mast_transaction * Description : Start a transaction and wait for completion. * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid * uint8 cmd_bitlen - Valid number of bits in cmd_data. * uint16 cmd_data - Command data. * uint8 addr_bitlen - Valid number of bits in addr_data. * uint32 addr_data - Address data. * uint16 mosi_bitlen - Valid number of bits in MOSI buffer. * uint8 dummy_bitlen - Number of dummy cycles. * sint16 miso_bitlen - number of bits to be captured in MISO buffer. * negative value activates full-duplex mode. *******************************************************************************/ void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 addr_bitlen, uint32 addr_data, uint16 mosi_bitlen, uint8 dummy_bitlen, sint16 miso_bitlen) { if (spi_no > 1) return; // handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR); // default disable COMMAND, ADDR, MOSI, DUMMY, MISO, and DOUTDIN (aka full-duplex) CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_MOSI|SPI_USR_DUMMY|SPI_USR_MISO|SPI_DOUTDIN); // default set bit lengths WRITE_PERI_REG(SPI_USER1(spi_no), ((addr_bitlen - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S | ((mosi_bitlen - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | ((dummy_bitlen - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S | ((miso_bitlen - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S); // handle the transaction components if (cmd_bitlen > 0) { uint16 cmd = cmd_data << (16 - cmd_bitlen); // align to MSB cmd = (cmd >> 8) | (cmd << 8); // swap byte order WRITE_PERI_REG(SPI_USER2(spi_no), ((cmd_bitlen - 1 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | (cmd & SPI_USR_COMMAND_VALUE)); SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND); } if (addr_bitlen > 0) { WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bitlen)); SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR); } if (mosi_bitlen > 0) { SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); } if (dummy_bitlen > 0) { SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY); } if (miso_bitlen > 0) { SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); } else if (miso_bitlen < 0) { SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN); } // start transaction SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR); } /****************************************************************************** * FunctionName : spi_byte_write_espslave * Description : SPI master 1 byte transmission function for esp8266 slave, * transmit 1byte data to esp8266 slave buffer needs 16bit transmission , * first byte is command 0x04 to write slave buffer, second byte is data * Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid * uint8 data- transmitted data *******************************************************************************/ void spi_byte_write_espslave(uint8 spi_no,uint8 data) { uint32 regvalue; if(spi_no>1) return; //handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_DUMMY); //SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1, // bit15-0 is cmd value. //0x70000000 is for 8bits cmd, 0x04 is eps8266 slave write cmd value WRITE_PERI_REG(SPI_USER2(spi_no), ((7&SPI_USR_COMMAND_BITLEN)<1) return; //handle invalid input number while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_ADDR|SPI_USR_DUMMY); //SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1, // bit15-0 is cmd value. //0x70000000 is for 8bits cmd, 0x06 is eps8266 slave read cmd value WRITE_PERI_REG(SPI_USER2(spi_no), ((7&SPI_USR_COMMAND_BITLEN)<1) return; //handle invalid input number //clear bit9,bit8 of reg PERIPHS_IO_MUX //bit9 should be cleared when HSPI clock doesn't equal CPU clock //bit8 should be cleared when SPI clock doesn't equal CPU clock ////WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9//TEST if(spi_no==SPI){ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode }else if(spi_no==HSPI){ PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode } //regvalue=READ_PERI_REG(SPI_FLASH_SLAVE(spi_no)); //slave mode,slave use buffers which are register "SPI_FLASH_C0~C15", enable trans done isr //set bit 30 bit 29 bit9,bit9 is trans done isr mask SET_PERI_REG_MASK( SPI_SLAVE(spi_no), SPI_SLAVE_MODE|SPI_SLV_WR_RD_BUF_EN| SPI_SLV_WR_BUF_DONE_EN|SPI_SLV_RD_BUF_DONE_EN| SPI_SLV_WR_STA_DONE_EN|SPI_SLV_RD_STA_DONE_EN| SPI_TRANS_DONE_EN); //disable general trans intr //CLEAR_PERI_REG_MASK(SPI_SLAVE(spi_no),SPI_TRANS_DONE_EN); CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);//disable flash operation mode SET_PERI_REG_MASK(SPI_USER(spi_no),SPI_USR_MISO_HIGHPART);//SLAVE SEND DATA BUFFER IN C8-C15 //////**************RUN WHEN SLAVE RECIEVE*******************/////// //tow lines below is to configure spi timing. SET_PERI_REG_MASK(SPI_CTRL2(spi_no),(0x2&SPI_MOSI_DELAY_NUM)<>8)&0xff; spi_data[(idx<<2)+2] = (recv_data>>16)&0xff; spi_data[(idx<<2)+3] = (recv_data>>24)&0xff; idx++; } //add system_os_post here GPIO_OUTPUT_SET(0, 1); } if(regvalue&SPI_SLV_RD_BUF_DONE){ //it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended. GPIO_OUTPUT_SET(2, 0); //add system_os_post here //system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue); } }else if(READ_PERI_REG(0x3ff00020)&BIT9){ //bit7 is for i2s isr, } } #ifdef SPI_SLAVE_DEBUG void ICACHE_FLASH_ATTR set_miso_data() { if(GPIO_INPUT_GET(2)==0){ WRITE_PERI_REG(SPI_W8(HSPI),0x05040302); WRITE_PERI_REG(SPI_W9(HSPI),0x09080706); WRITE_PERI_REG(SPI_W10(HSPI),0x0d0c0b0a); WRITE_PERI_REG(SPI_W11(HSPI),0x11100f0e); WRITE_PERI_REG(SPI_W12(HSPI),0x15141312); WRITE_PERI_REG(SPI_W13(HSPI),0x19181716); WRITE_PERI_REG(SPI_W14(HSPI),0x1d1c1b1a); WRITE_PERI_REG(SPI_W15(HSPI),0x21201f1e); GPIO_OUTPUT_SET(2, 1); } } void ICACHE_FLASH_ATTR disp_spi_data() { uint8 i = 0; for(i=0;i<32;i++){ os_printf("data %d : 0x%02x\n\r",i,spi_data[i]); } //os_printf("d31:0x%02x\n\r",spi_data[31]); } void ICACHE_FLASH_ATTR spi_task(os_event_t *e) { uint8 data; switch(e->sig){ case MOSI: disp_spi_data(); break; case STATUS_R_IN_WR : os_printf("SR ERR in WRPR,Reg:%08x \n",e->par); break; case STATUS_W: os_printf("SW ERR,Reg:%08x\n",e->par); break; case TR_DONE_ALONE: os_printf("TD ALO ERR,Reg:%08x\n",e->par); break; case WR_RD: os_printf("WR&RD ERR,Reg:%08x\n",e->par); break; case DATA_ERROR: os_printf("Data ERR,Reg:%08x\n",e->par); break; case STATUS_R_IN_RD : os_printf("SR ERR in RDPR,Reg:%08x\n",e->par); break; default: break; } } void ICACHE_FLASH_ATTR spi_task_init(void) { spiQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*SPI_QUEUE_LEN); system_os_task(spi_task,USER_TASK_PRIO_1,spiQueue,SPI_QUEUE_LEN); } os_timer_t spi_timer_test; void ICACHE_FLASH_ATTR spi_test_init() { os_printf("spi init\n\r"); spi_slave_init(HSPI); os_printf("gpio init\n\r"); gpio_init(); os_printf("spi task init \n\r"); spi_task_init(); #ifdef SPI_MISO os_printf("spi miso init\n\r"); set_miso_data(); #endif //os_timer_disarm(&spi_timer_test); //os_timer_setfn(&spi_timer_test, (os_timer_func_t *)set_miso_data, NULL);//wjl //os_timer_arm(&spi_timer_test,50,1); } #endif