2014-12-22 12:35:05 +01:00
# include "driver/spi.h"
2016-09-05 20:17:13 +02:00
typedef union {
uint32 word [ 2 ] ;
uint64 dword ;
} spi_buf_t ;
static uint32_t spi_clkdiv [ 2 ] ;
2014-12-22 12:35:05 +01:00
/******************************************************************************
* 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
2017-02-06 13:55:26 +01:00
if ( spi_no = = SPI_SPI ) {
2014-12-22 12:35:05 +01:00
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
2017-02-06 13:55:26 +01:00
} else if ( spi_no = = SPI_HSPI ) {
2014-12-22 12:35:05 +01:00
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 ) < < 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
}
/******************************************************************************
* FunctionName : spi_lcd_9bit_write
* Description : SPI 9 bits 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 8 bits 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
if ( high_bit ) bytetemp = ( low_8bit > > 1 ) | 0x80 ;
else bytetemp = ( low_8bit > > 1 ) & 0x7f ;
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
}
2016-09-05 20:17:13 +02:00
/******************************************************************************
* 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
}
2017-02-06 13:55:26 +01:00
if ( spi_no = = SPI_SPI ) {
2016-09-05 20:17:13 +02:00
WRITE_PERI_REG ( PERIPHS_IO_MUX , 0x005 | ( clock_div < = 1 ? 0x100 : 0 ) ) ;
}
2017-02-06 13:55:26 +01:00
else if ( spi_no = = SPI_HSPI ) {
2016-09-05 20:17:13 +02:00
WRITE_PERI_REG ( PERIPHS_IO_MUX , 0x105 | ( clock_div < = 1 ? 0x200 : 0 ) ) ;
}
spi_clkdiv [ spi_no ] = clock_div ;
return tmp_clkdiv ;
}
2014-12-22 12:35:05 +01:00
/******************************************************************************
* 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-10-27 23:30:33 +01:00
void spi_master_init ( uint8 spi_no , unsigned cpol , unsigned cpha , uint32_t clock_div )
2014-12-22 12:35:05 +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
2016-04-02 19:26:07 +02:00
// set clock polarity (Reference: http://bbs.espressif.com/viewtopic.php?f=49&t=1570)
// phase is dependent on polarity. See Issue #1161
2016-01-14 04:39:15 +01:00
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 ) ;
}
2016-04-02 19:26:07 +02:00
2015-10-08 23:13:31 +02:00
//set clock phase
2016-04-02 19:26:07 +02:00
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 {
2016-04-02 19:26:07 +02:00
// 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 ) ;
2015-10-08 23:13:31 +02:00
}
2015-10-27 23:30:33 +01:00
CLEAR_PERI_REG_MASK ( SPI_USER ( spi_no ) , SPI_FLASH_MODE | SPI_USR_MISO | SPI_USR_ADDR | SPI_USR_COMMAND | SPI_USR_DUMMY ) ;
2014-12-22 12:35:05 +01:00
2015-10-10 22:34:36 +02:00
//clear Dual or Quad lines transmission mode
2014-12-22 12:35:05 +01:00
CLEAR_PERI_REG_MASK ( SPI_CTRL ( spi_no ) , SPI_QIO_MODE | SPI_DIO_MODE | SPI_DOUT_MODE | SPI_QOUT_MODE ) ;
2016-09-05 20:17:13 +02:00
spi_set_clkdiv ( spi_no , clock_div ) ;
2016-02-09 23:26:40 +01:00
2017-02-06 13:55:26 +01:00
if ( spi_no = = SPI_SPI ) {
2016-02-09 23:26:40 +01:00
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
}
2017-02-06 13:55:26 +01:00
else if ( spi_no = = SPI_HSPI ) {
2016-02-09 23:26:40 +01:00
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
}
2014-12-22 12:35:05 +01:00
}
2016-09-05 20:17:13 +02:00
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 )
{
2017-02-06 13:55:26 +01:00
size_t aligned_len = bitlen > > 3 ;
2016-09-05 20:17:13 +02:00
while ( READ_PERI_REG ( SPI_CMD ( spi_no ) ) & SPI_USR ) ;
2017-02-06 13:55:26 +01:00
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 ) ;
2016-09-05 20:17:13 +02:00
}
/******************************************************************************
* 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
2017-02-06 13:55:26 +01:00
* uint8 * data - pointer to data buffer , the buffer must be able to
* accept a multiple of 4 * 8 bits
2016-09-05 20:17:13 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void spi_mast_blkget ( uint8 spi_no , size_t bitlen , uint8 * data )
{
2017-02-06 13:55:26 +01:00
size_t aligned_len = bitlen > > 3 ;
2016-09-05 20:17:13 +02:00
while ( READ_PERI_REG ( SPI_CMD ( spi_no ) ) & SPI_USR ) ;
2017-02-06 13:55:26 +01:00
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 ) ;
2016-09-05 20:17:13 +02:00
}
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 ' .
2016-02-09 22:05:05 +01:00
* 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-02-09 22:05:05 +01:00
void spi_mast_set_mosi ( uint8 spi_no , uint16 offset , uint8 bitlen , uint32 data )
2015-10-08 23:13:31 +02:00
{
2016-09-05 20:17:13 +02:00
spi_buf_t spi_buf ;
2017-02-06 13:55:26 +01:00
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 ;
2016-09-05 20:17:13 +02:00
if ( wn > 15 ) {
2015-10-08 23:13:31 +02:00
return ; // out of range
}
2016-09-05 20:17:13 +02:00
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 ) ;
2017-02-06 13:55:26 +01:00
spi_buf . word [ 1 ] = swap_endianess ( spi_buf . word [ 1 ] ) ;
2016-09-05 20:17:13 +02:00
if ( wn < 15 ) {
spi_buf . word [ 0 ] = READ_PERI_REG ( SPI_W0 ( spi_no ) + ( wn + 1 ) * 4 ) ;
2017-02-06 13:55:26 +01:00
spi_buf . word [ 0 ] = swap_endianess ( spi_buf . word [ 0 ] ) ;
2015-10-08 23:13:31 +02:00
}
2016-09-05 20:17:13 +02:00
shift = 64 - ( offset & 0x1f ) - bitlen ;
spi_buf . dword & = ~ ( ( 1ULL < < bitlen ) - 1 < < shift ) ;
spi_buf . dword | = ( uint64 ) data < < shift ;
if ( wn < 15 ) {
2017-02-06 13:55:26 +01:00
WRITE_PERI_REG ( SPI_W0 ( spi_no ) + ( wn + 1 ) * 4 , swap_endianess ( spi_buf . word [ 0 ] ) ) ;
2016-09-05 20:17:13 +02:00
}
2017-02-06 13:55:26 +01:00
WRITE_PERI_REG ( SPI_W0 ( spi_no ) + wn * 4 , swap_endianess ( spi_buf . word [ 1 ] ) ) ;
2015-10-25 22:58:06 +01:00
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 ' .
2016-02-09 22:05:05 +01:00
* 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-02-09 22:05:05 +01:00
uint32 spi_mast_get_miso ( uint8 spi_no , uint16 offset , uint8 bitlen )
2015-10-10 22:34:36 +02:00
{
2016-09-05 20:17:13 +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
2016-09-05 20:17:13 +02:00
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 ) ;
2017-02-06 13:55:26 +01:00
spi_buf . word [ 1 ] = swap_endianess ( spi_buf . word [ 1 ] ) ;
2016-09-05 20:17:13 +02:00
if ( wn < 15 ) {
spi_buf . word [ 0 ] = READ_PERI_REG ( SPI_W0 ( spi_no ) + ( wn + 1 ) * 4 ) ;
2017-02-06 13:55:26 +01:00
spi_buf . word [ 0 ] = swap_endianess ( spi_buf . word [ 0 ] ) ;
2015-10-10 22:34:36 +02:00
}
2016-09-05 20:17:13 +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 .
2015-10-27 23:30:33 +01:00
* 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 .
2015-10-27 23:30:33 +01:00
* 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 ,
2015-10-27 23:30:33 +01:00
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 ) ;
2015-10-27 23:30:33 +01:00
// 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 ) ;
}
2015-10-27 23:30:33 +01:00
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 ) ;
}
2014-12-22 12:35:05 +01:00
/******************************************************************************
* FunctionName : spi_byte_write_espslave
* Description : SPI master 1 byte transmission function for esp8266 slave ,
* transmit 1 byte data to esp8266 slave buffer needs 16 bit 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 ) < < 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 1 byte data from esp8266 slave buffer needs 16 bit 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
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 ) ;
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 )
{
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
2017-02-06 13:55:26 +01:00
if ( spi_no = = SPI_SPI ) {
2014-12-22 12:35:05 +01:00
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
2017-02-06 13:55:26 +01:00
} else if ( spi_no = = SPI_HSPI ) {
2014-12-22 12:35:05 +01:00
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 ) < < 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 ) ;
/////***************************************************//////
//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 ) ) ;
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
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
2018-04-13 21:41:14 +02:00
# include "pm/swtimer.h"
2014-12-22 12:35:05 +01:00
/******************************************************************************
* FunctionName : hspi_master_readwrite_repeat
* Description : SPI master test function for reading and writing esp8266 slave buffer ,
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 ) ;
2017-02-06 13:55:26 +01:00
spi_byte_read_espslave ( SPI_HSPI , & temp ) ;
2014-12-22 12:35:05 +01:00
temp + + ;
2017-02-06 13:55:26 +01:00
spi_byte_write_espslave ( SPI_HSPI , temp ) ;
2014-12-22 12:35:05 +01:00
os_timer_setfn ( & timer2 , ( os_timer_func_t * ) hspi_master_readwrite_repeat , NULL ) ;
2018-04-13 21:41:14 +02:00
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?
2014-12-22 12:35:05 +01:00
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
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
//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 ;
if ( READ_PERI_REG ( 0x3ff00020 ) & BIT4 ) {
//following 3 lines is to clear isr signal
2017-02-06 13:55:26 +01:00
CLEAR_PERI_REG_MASK ( SPI_SLAVE ( SPI_SPI ) , 0x3ff ) ;
2014-12-22 12:35:05 +01:00
} else if ( READ_PERI_REG ( 0x3ff00020 ) & BIT7 ) { //bit7 is for hspi isr,
2017-02-06 13:55:26 +01:00
regvalue = READ_PERI_REG ( SPI_SLAVE ( SPI_HSPI ) ) ;
CLEAR_PERI_REG_MASK ( SPI_SLAVE ( SPI_HSPI ) ,
2014-12-22 12:35:05 +01:00
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 ) ;
2017-02-06 13:55:26 +01:00
SET_PERI_REG_MASK ( SPI_SLAVE ( SPI_HSPI ) , SPI_SYNC_RESET ) ;
CLEAR_PERI_REG_MASK ( SPI_SLAVE ( SPI_HSPI ) ,
2014-12-22 12:35:05 +01:00
SPI_TRANS_DONE |
SPI_SLV_WR_STA_DONE |
SPI_SLV_RD_STA_DONE |
SPI_SLV_WR_BUF_DONE |
SPI_SLV_RD_BUF_DONE ) ;
2017-02-06 13:55:26 +01:00
SET_PERI_REG_MASK ( SPI_SLAVE ( SPI_HSPI ) ,
2014-12-22 12:35:05 +01:00
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 ) ;
if ( regvalue & SPI_SLV_WR_BUF_DONE ) {
GPIO_OUTPUT_SET ( 0 , 0 ) ;
idx = 0 ;
while ( idx < 8 ) {
2017-02-06 13:55:26 +01:00
recv_data = READ_PERI_REG ( SPI_W0 ( SPI_HSPI ) + ( idx < < 2 ) ) ;
2014-12-22 12:35:05 +01:00
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);
}
} 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 ) {
2017-02-06 13:55:26 +01:00
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 ) ;
2014-12-22 12:35:05 +01:00
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 " ) ;
2017-02-06 13:55:26 +01:00
spi_slave_init ( SPI_HSPI ) ;
2014-12-22 12:35:05 +01:00
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