nodemcu-firmware/app/driver/spi.c

750 lines
28 KiB
C
Raw Normal View History

#include "driver/spi.h"
typedef union {
uint32 word[2];
uint64 dword;
} spi_buf_t;
static uint32_t spi_clkdiv[2];
/******************************************************************************
* 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)
{
2019-02-17 19:26:29 +01:00
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_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
2019-02-17 19:26:29 +01:00
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==SPI_HSPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
2019-02-17 19:26:29 +01:00
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
2019-02-17 19:26:29 +01:00
WRITE_PERI_REG(SPI_CLOCK(spi_no),
((1&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|
((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
2019-02-17 19:26:29 +01:00
}
/******************************************************************************
* FunctionName : spi_lcd_9bit_write
* Description : SPI 9bits transmission function for driving LCD TM035PDZV36
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint8 high_bit - first high bit of the data, 0 is for "0",the other value 1-255 is for "1"
* uint8 low_8bit- the rest 8bits of the data.
*******************************************************************************/
void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)
{
uint32 regvalue;
uint8 bytetemp;
if(spi_no>1) return; //handle invalid input number
2019-02-17 19:26:29 +01:00
if(high_bit) bytetemp=(low_8bit>>1)|0x80;
else bytetemp=(low_8bit>>1)&0x7f;
2019-02-17 19:26:29 +01:00
regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
if(low_8bit&0x01) regvalue|=BIT15; //write the 9th bit
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR); //waiting for spi module available
WRITE_PERI_REG(SPI_USER2(spi_no), regvalue); //write command and command length into spi reg
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); //transmission start
}
/******************************************************************************
* FunctionName : spi_set_clkdiv
* Description : Set the clock divider
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint32 clock_div - new clock divider
* Returns : uint32 - previous clock divider
*******************************************************************************/
uint32_t spi_set_clkdiv(uint8 spi_no, uint32_t clock_div)
{
uint32_t tmp_clkdiv;
if (spi_no > 1) return 0; //handle invalid input number
tmp_clkdiv = spi_clkdiv[spi_no];
if (clock_div > 1) {
uint8 i, k;
i = (clock_div / 40) ? (clock_div / 40) : 1;
k = clock_div / i;
WRITE_PERI_REG(SPI_CLOCK(spi_no),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
} else {
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
}
if(spi_no==SPI_SPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div <= 1 ? 0x100 : 0));
}
else if(spi_no==SPI_HSPI){
2019-02-17 19:26:29 +01:00
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div <= 1 ? 0x200 : 0));
}
spi_clkdiv[spi_no] = clock_div;
return tmp_clkdiv;
}
/******************************************************************************
* FunctionName : spi_master_init
* Description : SPI master initial function for common byte units transmission
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
*******************************************************************************/
void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div)
{
2019-02-17 19:26:29 +01:00
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
2016-06-15 21:01:52 +02:00
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER);
2015-10-08 23:13:31 +02:00
// 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);
}
2019-02-17 19:26:29 +01:00
2015-10-08 23:13:31 +02:00
//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);
2015-10-08 23:13:31 +02:00
} else {
// Mode 2: MOSI is set on rising edge of clock
2019-02-17 19:26:29 +01:00
// Mode 1: MOSI is set on rising edge of clock
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE);
2015-10-08 23:13:31 +02:00
}
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE|SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);
2015-10-10 22:34:36 +02:00
//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_set_clkdiv(spi_no, clock_div);
if(spi_no==SPI_SPI){
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
2019-02-17 19:26:29 +01:00
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==SPI_HSPI){
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
2019-02-17 19:26:29 +01:00
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
}
}
void spi_mast_byte_order(uint8 spi_no, uint8 order)
{
if(spi_no > 1)
return;
if (order == SPI_ORDER_MSB) {
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER | SPI_WR_BYTE_ORDER);
} else if (order == SPI_ORDER_LSB) {
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER | SPI_WR_BYTE_ORDER);
}
}
/******************************************************************************
* FunctionName : spi_mast_blkset
* Description : Copy a block of data to the MOSI FIFO
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* size_t bitlen - number of bits to copy, multiple of 8
* uint8 *data - pointer to data buffer
*******************************************************************************/
void spi_mast_blkset(uint8 spi_no, size_t bitlen, const uint8 *data)
{
size_t aligned_len = bitlen >> 3;
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
if (aligned_len % 4) {
// length for memcpy needs to be aligned to uint32 bounday
// otherwise single byte writes are issued to the register and corrupt data
aligned_len += 4 - (aligned_len % 4);
}
os_memcpy((void *)SPI_W0(spi_no), (const void *)data, aligned_len);
}
/******************************************************************************
* FunctionName : spi_mast_blkget
* Description : Copy a block of data from the MISO FIFO
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* size_t bitlen - number of bits to copy, multiple of 8
* uint8 *data - pointer to data buffer, the buffer must be able to
* accept a multiple of 4*8 bits
*******************************************************************************/
void spi_mast_blkget(uint8 spi_no, size_t bitlen, uint8 *data)
{
size_t aligned_len = bitlen >> 3;
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
if (aligned_len % 4) {
// length for memcpy needs to be aligned to uint32 bounday
// otherwise single byte reads are issued to the register and corrupt data
aligned_len += 4 - (aligned_len % 4);
}
os_memcpy((void *)data, (void *)SPI_W0(spi_no), aligned_len);
}
static uint32 swap_endianess(uint32 n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
}
2015-10-08 23:13:31 +02:00
/******************************************************************************
* FunctionName : spi_mast_set_mosi
* Description : Enter provided data into MOSI buffer.
* The data is regarded as a sequence of bits with length 'bitlen'.
* It will be written left-aligned starting from position 'offset'.
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint16 offset - offset into MOSI buffer (number of bits)
* uint8 bitlen - valid number of bits in data
2015-10-08 23:13:31 +02:00
* uint32 data - data to be written into buffer
*******************************************************************************/
void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data)
2015-10-08 23:13:31 +02:00
{
spi_buf_t spi_buf;
uint8 wn, shift;
2015-10-08 23:13:31 +02:00
if (spi_no > 1)
return; // handle invalid input number
if (bitlen > 32)
return; // handle invalid input number
// determine which SPI_Wn register is addressed
wn = offset >> 5;
if (wn > 15) {
2015-10-08 23:13:31 +02:00
return; // out of range
}
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// transfer Wn to buf
spi_buf.word[1] = READ_PERI_REG(SPI_W0(spi_no) + wn*4);
spi_buf.word[1] = swap_endianess(spi_buf.word[1]);
if (wn < 15) {
spi_buf.word[0] = READ_PERI_REG(SPI_W0(spi_no) + (wn+1)*4);
spi_buf.word[0] = swap_endianess(spi_buf.word[0]);
2015-10-08 23:13:31 +02:00
}
shift = 64 - (offset & 0x1f) - bitlen;
spi_buf.dword &= ~((1ULL << bitlen)-1 << shift);
spi_buf.dword |= (uint64)data << shift;
if (wn < 15) {
WRITE_PERI_REG(SPI_W0(spi_no) + (wn+1)*4, swap_endianess(spi_buf.word[0]));
}
WRITE_PERI_REG(SPI_W0(spi_no) + wn*4, swap_endianess(spi_buf.word[1]));
return;
2015-10-08 23:13:31 +02:00
}
2015-10-10 22:34:36 +02:00
/******************************************************************************
* 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
2015-10-10 22:34:36 +02:00
*******************************************************************************/
uint32 spi_mast_get_miso(uint8 spi_no, uint16 offset, uint8 bitlen)
2015-10-10 22:34:36 +02:00
{
uint8 wn;
spi_buf_t spi_buf;
uint32 result;
2015-10-10 22:34:36 +02:00
if (spi_no > 1)
return 0; // handle invalid input number
// determine which SPI_Wn register is addressed
wn = offset >> 5;
if (wn > 15)
return 0; // out of range
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// transfer Wn to buf
spi_buf.word[1] = READ_PERI_REG(SPI_W0(spi_no) + wn*4);
spi_buf.word[1] = swap_endianess(spi_buf.word[1]);
if (wn < 15) {
spi_buf.word[0] = READ_PERI_REG(SPI_W0(spi_no) + (wn+1)*4);
spi_buf.word[0] = swap_endianess(spi_buf.word[0]);
2015-10-10 22:34:36 +02:00
}
result = (uint32)(spi_buf.dword >> (64 - ((offset & 0x1f) + bitlen)));
result &= (1UL << bitlen)-1;
return result;
2015-10-10 22:34:36 +02:00
}
2015-10-08 23:13:31 +02:00
/******************************************************************************
* 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.
2015-10-08 23:13:31 +02:00
* 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.
2015-10-08 23:13:31 +02:00
*******************************************************************************/
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)
2015-10-08 23:13:31 +02:00
{
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);
2015-10-08 23:13:31 +02:00
// 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);
}
2015-10-08 23:13:31 +02:00
// 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
2019-02-17 19:26:29 +01:00
WRITE_PERI_REG(SPI_USER2(spi_no),
((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|4);
WRITE_PERI_REG(SPI_W0(spi_no), (uint32)(data));
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
}
/******************************************************************************
* FunctionName : spi_byte_read_espslave
* Description : SPI master 1 byte read function for esp8266 slave,
* read 1byte data from esp8266 slave buffer needs 16bit transmission ,
* first byte is command 0x06 to read slave buffer, second byte is recieved data
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint8* data- recieved data address
*******************************************************************************/
void spi_byte_read_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_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
2019-02-17 19:26:29 +01:00
WRITE_PERI_REG(SPI_USER2(spi_no),
((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|6);
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
2019-02-17 19:26:29 +01:00
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
*data=(uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);
}
/******************************************************************************
* FunctionName : spi_slave_init
* Description : SPI slave mode initial funtion, including mode setting,
* IO setting, transmission interrupt opening, interrupt function registration
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
*******************************************************************************/
void spi_slave_init(uint8 spi_no)
{
2019-02-17 19:26:29 +01:00
uint32 regvalue;
if(spi_no>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_SPI){
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
2019-02-17 19:26:29 +01:00
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==SPI_HSPI){
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
2019-02-17 19:26:29 +01:00
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
2019-02-17 19:26:29 +01:00
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);
2019-02-17 19:26:29 +01:00
//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
2019-02-17 19:26:29 +01:00
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)<<SPI_MOSI_DELAY_NUM_S) ;//delay num
os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
WRITE_PERI_REG(SPI_CLOCK(spi_no), 0);
2019-02-17 19:26:29 +01:00
/////***************************************************//////
//set 8 bit slave command length, because slave must have at least one bit addr,
//8 bit slave+8bit addr, so master device first 2 bytes can be regarded as a command
//and the following bytes are datas,
//32 bytes input wil be stored in SPI_FLASH_C0-C7
//32 bytes output data should be set to SPI_FLASH_C8-C15
WRITE_PERI_REG(SPI_USER2(spi_no), (0x7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S); //0x70000000
//set 8 bit slave recieve buffer length, the buffer is SPI_FLASH_C0-C7
//set 8 bit slave status register, which is the low 8 bit of register "SPI_FLASH_STATUS"
SET_PERI_REG_MASK(SPI_SLAVE1(spi_no), ((0xff&SPI_SLV_BUF_BITLEN)<< SPI_SLV_BUF_BITLEN_S)|
((0x7&SPI_SLV_STATUS_BITLEN)<<SPI_SLV_STATUS_BITLEN_S)|
((0x7&SPI_SLV_WR_ADDR_BITLEN)<<SPI_SLV_WR_ADDR_BITLEN_S)|
((0x7&SPI_SLV_RD_ADDR_BITLEN)<<SPI_SLV_RD_ADDR_BITLEN_S));
2019-02-17 19:26:29 +01:00
SET_PERI_REG_MASK(SPI_PIN(spi_no),BIT19);//BIT19
//maybe enable slave transmission liston
SET_PERI_REG_MASK(SPI_CMD(spi_no),SPI_USR);
//register level2 isr function, which contains spi, hspi and i2s events
ETS_SPI_INTR_ATTACH(spi_slave_isr_handler,NULL);
//enable level2 isr, which contains spi, hspi and i2s events
2019-02-17 19:26:29 +01:00
ETS_SPI_INTR_ENABLE();
}
/* =============================================================================================
* code below is for spi slave r/w testcase with 2 r/w state lines connected to the spi master mcu
* replace with your own process functions
* find "add system_os_post here" in spi_slave_isr_handler.
* =============================================================================================
*/
#ifdef SPI_SLAVE_DEBUG
#include "pm/swtimer.h"
/******************************************************************************
* FunctionName : hspi_master_readwrite_repeat
* Description : SPI master test function for reading and writing esp8266 slave buffer,
2019-02-17 19:26:29 +01:00
the function uses HSPI module
*******************************************************************************/
os_timer_t timer2;
void hspi_master_readwrite_repeat(void)
{
static uint8 data=0;
uint8 temp;
os_timer_disarm(&timer2);
spi_byte_read_espslave(SPI_HSPI,&temp);
temp++;
spi_byte_write_espslave(SPI_HSPI,temp);
os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL);
SWTIMER_REGISTER_CB_PTR(hspi_master_readwrite_repeat, SWTIMER_RESUME);
//hspi_master_readwrite_repeat timer will be resumed on wake up, maybe data will still be in buffer?
os_timer_arm(&timer2, 500, 0);
}
#endif
/******************************************************************************
* FunctionName : spi_slave_isr_handler
* Description : SPI interrupt function, SPI HSPI and I2S interrupt can trig this function
2019-02-17 19:26:29 +01:00
some basic operation like clear isr flag has been done,
and it is availible for adding user coder in the funtion
* Parameters : void *para- function parameter address, which has been registered in function spi_slave_init
*******************************************************************************/
#include "gpio.h"
#include "user_interface.h"
#include "mem.h"
static uint8 spi_data[32] = {0};
static uint8 idx = 0;
static uint8 spi_flg = 0;
#define SPI_MISO
#define SPI_QUEUE_LEN 8
os_event_t * spiQueue;
#define MOSI 0
#define MISO 1
#define STATUS_R_IN_WR 2
#define STATUS_W 3
#define TR_DONE_ALONE 4
#define WR_RD 5
#define DATA_ERROR 6
#define STATUS_R_IN_RD 7
//init the two intr line of slave
2019-02-17 19:26:29 +01:00
//gpio0: wr_ready ,and
//gpio2: rd_ready , controlled by slave
void ICACHE_FLASH_ATTR
gpio_init()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
//PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
GPIO_OUTPUT_SET(0, 1);
GPIO_OUTPUT_SET(2, 0);
//GPIO_OUTPUT_SET(4, 1);
}
void spi_slave_isr_handler(void *para)
{
uint32 regvalue,calvalue;
static uint8 state =0;
uint32 recv_data,send_data;
2019-02-17 19:26:29 +01:00
if(READ_PERI_REG(0x3ff00020)&BIT4){
//following 3 lines is to clear isr signal
CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI_SPI), 0x3ff);
}else if(READ_PERI_REG(0x3ff00020)&BIT7){ //bit7 is for hspi isr,
regvalue=READ_PERI_REG(SPI_SLAVE(SPI_HSPI));
2019-02-17 19:26:29 +01:00
CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI_HSPI),
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
SET_PERI_REG_MASK(SPI_SLAVE(SPI_HSPI), SPI_SYNC_RESET);
2019-02-17 19:26:29 +01:00
CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI_HSPI),
SPI_TRANS_DONE|
SPI_SLV_WR_STA_DONE|
SPI_SLV_RD_STA_DONE|
SPI_SLV_WR_BUF_DONE|
2019-02-17 19:26:29 +01:00
SPI_SLV_RD_BUF_DONE);
SET_PERI_REG_MASK(SPI_SLAVE(SPI_HSPI),
SPI_TRANS_DONE_EN|
SPI_SLV_WR_STA_DONE_EN|
SPI_SLV_RD_STA_DONE_EN|
SPI_SLV_WR_BUF_DONE_EN|
SPI_SLV_RD_BUF_DONE_EN);
2019-02-17 19:26:29 +01:00
if(regvalue&SPI_SLV_WR_BUF_DONE){
GPIO_OUTPUT_SET(0, 0);
idx=0;
while(idx<8){
recv_data=READ_PERI_REG(SPI_W0(SPI_HSPI)+(idx<<2));
spi_data[idx<<2] = recv_data&0xff;
spi_data[(idx<<2)+1] = (recv_data>>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);
}
2019-02-17 19:26:29 +01:00
}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(SPI_HSPI),0x05040302);
WRITE_PERI_REG(SPI_W9(SPI_HSPI),0x09080706);
WRITE_PERI_REG(SPI_W10(SPI_HSPI),0x0d0c0b0a);
WRITE_PERI_REG(SPI_W11(SPI_HSPI),0x11100f0e);
WRITE_PERI_REG(SPI_W12(SPI_HSPI),0x15141312);
WRITE_PERI_REG(SPI_W13(SPI_HSPI),0x19181716);
WRITE_PERI_REG(SPI_W14(SPI_HSPI),0x1d1c1b1a);
WRITE_PERI_REG(SPI_W15(SPI_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);
2019-02-17 19:26:29 +01:00
break;
case TR_DONE_ALONE:
os_printf("TD ALO ERR,Reg:%08x\n",e->par);
2019-02-17 19:26:29 +01:00
break;
case WR_RD:
os_printf("WR&RD ERR,Reg:%08x\n",e->par);
2019-02-17 19:26:29 +01:00
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);
2019-02-17 19:26:29 +01:00
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(SPI_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
2019-02-17 19:26:29 +01:00
//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