add SPI transaction support

This commit is contained in:
devsaurus 2015-10-08 23:13:31 +02:00
parent 8c419b8a3b
commit 9cde0bbb83
5 changed files with 256 additions and 24 deletions

View File

@ -85,26 +85,27 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, unsigned databi
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_DOUTDIN|SPI_USR_MOSI);
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_DOUTDIN|SPI_USR_MOSI|
SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER);
//set clock polarity
// TODO: This doesn't work
//if (cpol == 1) {
// SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_HIGH_MODE<<SPI_CK_OUT_HIGH_MODE_S));
//} else {
// SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_LOW_MODE<<SPI_CK_OUT_LOW_MODE_S));
//}
//os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
//set clock polarity
// TODO: This doesn't work
//if (cpol == 1) {
// SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_HIGH_MODE<<SPI_CK_OUT_HIGH_MODE_S));
//} else {
// SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_LOW_MODE<<SPI_CK_OUT_LOW_MODE_S));
//}
//os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
//set clock phase
if (cpha == 1) {
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);
} else {
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);
}
//set clock phase
if (cpha == 1) {
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);
} else {
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);
}
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE|SPI_WR_BYTE_ORDER|SPI_USR_MISO|
SPI_RD_BYTE_ORDER|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE|SPI_USR_MISO|
SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);
//clear Daul 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);
@ -151,6 +152,126 @@ void spi_mast_byte_write(uint8 spi_no, uint8 *data)
*data = (uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);
}
/******************************************************************************
* 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
* uint8 offset - offset into MOSI buffer (number of bits)
* uint8 bitlen - valid number of bits in data
* uint32 data - data to be written into buffer
*******************************************************************************/
void spi_mast_set_mosi(uint8 spi_no, uint8 offset, uint8 bitlen, uint32 data)
{
uint8 wn, wn_offset, wn_bitlen;
uint32 wn_data;
if (spi_no > 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);
}
/******************************************************************************
* 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.
* uint8 mosi_bitlen - Valid number of bits in MOSI buffer.
* uint8 dummy_bitlen - Number of dummy cycles.
* uint8 miso_bitlen - number of bits to be captured in MISO buffer.
*******************************************************************************/
void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 addr_bitlen, uint32 addr_data,
uint8 mosi_bitlen, uint8 dummy_bitlen, uint8 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
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_MOSI|SPI_USR_DUMMY|SPI_USR_MISO);
// 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);
}
// 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,

View File

@ -22,6 +22,10 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, unsigned databi
//use spi send 8bit data
void spi_mast_byte_write(uint8 spi_no,uint8 *data);
void spi_set_mosi(uint8 spi_no, uint8 offset, uint8 bitlen, uint32 data);
void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8 addr_bitlen, uint32 addr_data,
uint8 mosi_bitlen, uint8 dummy_bitlen, uint8 miso_bitlen);
//transmit data to esp8266 slave buffer,which needs 16bit transmission ,
//first byte is master command 0x04, second byte is master data
void spi_byte_write_espslave(uint8 spi_no,uint8 data);

View File

@ -57,7 +57,7 @@ static int spi_send( lua_State *L )
MOD_CHECK_ID( spi, id );
if( lua_gettop( L ) < 2 )
return luaL_error( L, "wrong arg type" );
return luaL_error( L, "too few args" );
for( argn = 2; argn <= lua_gettop( L ); argn ++ )
{
@ -68,7 +68,7 @@ static int spi_send( lua_State *L )
numdata = ( int )luaL_checkinteger( L, argn );
if( numdata < 0 || numdata > 255 )
return luaL_error( L, "wrong arg range" );
platform_spi_send_recv( id, numdata );
platform_spi_transaction( id, 8, numdata, 0, 0, 0, 0, 0 );
wrote ++;
}
else if( lua_istable( L, argn ) )
@ -81,7 +81,7 @@ static int spi_send( lua_State *L )
lua_pop( L, 1 );
if( numdata < 0 || numdata > 255 )
return luaL_error( L, "wrong arg range" );
platform_spi_send_recv( id, numdata );
platform_spi_transaction( id, 8, numdata, 0, 0, 0, 0, 0 );
}
wrote += i;
if( i < datalen )
@ -91,7 +91,7 @@ static int spi_send( lua_State *L )
{
pdata = luaL_checklstring( L, argn, &datalen );
for( i = 0; i < datalen; i ++ )
platform_spi_send_recv( id, pdata[ i ] );
platform_spi_transaction( id, 8, pdata[ i ], 0, 0, 0, 0, 0 );
wrote += i;
if( i < datalen )
break;
@ -126,14 +126,89 @@ static int spi_recv( lua_State *L )
return 1;
}
// Lua: spi.set_mosi( id, offset, bitlen, data1, [data2], ..., [datan] )
static int spi_set_mosi( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
unsigned offset = luaL_checkinteger( L, 2 );
unsigned bitlen = luaL_checkinteger( L, 3 );
unsigned argn;
MOD_CHECK_ID( spi, id );
if (offset < 0 || offset > 511) {
return luaL_error( L, "offset out of range" );
}
if (bitlen < 1 || bitlen > 32) {
return luaL_error( L, "bitlen out of range" );
}
if (lua_gettop( L ) < 4) {
return luaL_error( L, "too few args" );
}
for (argn = 4; argn <= lua_gettop( L ); argn++, offset += bitlen )
{
u32 data = luaL_checkinteger(L, argn );
if (offset + bitlen > 512)
return luaL_error( L, "data range exceeded > 512 bits" );
if (platform_spi_set_mosi( id, offset, bitlen, data ) != PLATFORM_OK)
return luaL_error( L, "failed" );
}
return 0;
}
// Lua: spi.transaction( id, cmd_bitlen, cmd_data, addr_bitlen, addr_data, mosi_bitlen, dummy_bitlen, miso_bitlen )
static int spi_transaction( lua_State *L )
{
unsigned id = luaL_checkinteger( L, 1 );
unsigned cmd_bitlen = luaL_checkinteger( L, 2 );
u32 cmd_data = luaL_checkinteger( L, 3 );
unsigned addr_bitlen = luaL_checkinteger( L, 4 );
u32 addr_data = luaL_checkinteger( L, 5 );
unsigned mosi_bitlen = luaL_checkinteger( L, 6 );
unsigned dummy_bitlen = luaL_checkinteger( L, 7 );
unsigned miso_bitlen = luaL_checkinteger( L, 8 );
MOD_CHECK_ID( spi, id );
if (cmd_bitlen < 0 || cmd_bitlen > 16) {
return luaL_error( L, "cmd_bitlen out of range" );
}
if (addr_bitlen < 0 || addr_bitlen > 32) {
return luaL_error( L, "addr_bitlen out of range" );
}
if (mosi_bitlen < 0 || mosi_bitlen > 512) {
return luaL_error( L, "mosi_bitlen out of range" );
}
if (dummy_bitlen < 0 || dummy_bitlen > 256) {
return luaL_error( L, "dummy_bitlen out of range" );
}
if (miso_bitlen < 0 || miso_bitlen > 511) {
return luaL_error( L, "miso_bitlen out of range" );
}
if (platform_spi_transaction( id, cmd_bitlen, cmd_data, addr_bitlen, addr_data,
mosi_bitlen, dummy_bitlen, miso_bitlen) != PLATFORM_OK)
return luaL_error( L, "failed" );
return 0;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE spi_map[] =
{
{ LSTRKEY( "setup" ), LFUNCVAL( spi_setup ) },
{ LSTRKEY( "send" ), LFUNCVAL( spi_send ) },
{ LSTRKEY( "recv" ), LFUNCVAL( spi_recv ) },
{ LSTRKEY( "setup" ), LFUNCVAL( spi_setup ) },
{ LSTRKEY( "send" ), LFUNCVAL( spi_send ) },
{ LSTRKEY( "recv" ), LFUNCVAL( spi_recv ) },
{ LSTRKEY( "set_mosi" ), LFUNCVAL( spi_set_mosi ) },
{ LSTRKEY( "transaction" ), LFUNCVAL( spi_transaction ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "MASTER" ), LNUMVAL( PLATFORM_SPI_MASTER ) },
{ LSTRKEY( "SLAVE" ), LNUMVAL( PLATFORM_SPI_SLAVE) },

View File

@ -449,6 +449,32 @@ spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data )
return data;
}
int platform_spi_set_mosi( uint8_t id, uint8_t offset, uint8_t bitlen, spi_data_type data )
{
if (offset + bitlen > 512)
return PLATFORM_ERR;
spi_mast_set_mosi( id, offset, bitlen, data );
return PLATFORM_OK;
}
int platform_spi_transaction( uint8_t id, uint8_t cmd_bitlen, spi_data_type cmd_data,
uint8_t addr_bitlen, spi_data_type addr_data,
uint8_t mosi_bitlen, uint8_t dummy_bitlen, uint8_t miso_bitlen )
{
if ((cmd_bitlen > 16) ||
(addr_bitlen > 32) ||
(mosi_bitlen > 512) ||
(dummy_bitlen > 256) ||
(miso_bitlen > 512))
return PLATFORM_ERR;
spi_mast_transaction( id, cmd_bitlen, cmd_data, addr_bitlen, addr_data, mosi_bitlen, dummy_bitlen, miso_bitlen );
return PLATFORM_OK;
}
// ****************************************************************************
// Flash access functions

View File

@ -103,6 +103,12 @@ uint32_t platform_spi_setup( unsigned id, int mode, unsigned cpol, unsigned cpha
spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data );
void platform_spi_select( unsigned id, int is_select );
int platform_spi_set_mosi( uint8_t id, uint8_t offset, uint8_t bitlen, spi_data_type data );
int platform_spi_transaction( uint8_t id, uint8_t cmd_bitlen, spi_data_type cmd_data,
uint8_t addr_bitlen, spi_data_type addr_data,
uint8_t mosi_bitlen, uint8_t dummy_bitlen, uint8_t miso_bitlen );
// *****************************************************************************
// UART subsection