diff --git a/app/driver/spi.c b/app/driver/spi.c index f458e2ef..ed0bd2ba 100644 --- a/app/driver/spi.c +++ b/app/driver/spi.c @@ -64,7 +64,7 @@ void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit) * 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) +void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div, uint8 full_duplex) { uint32 regvalue; @@ -85,8 +85,7 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_ 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| - SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER); + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER); //set clock polarity // TODO: This doesn't work @@ -105,7 +104,7 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_ } CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE|SPI_USR_MISO| - SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY); + SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY|SPI_DOUTDIN); //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); @@ -126,10 +125,10 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_ ((0&SPI_CLKCNT_H)< 0) + { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN); + } } /****************************************************************************** @@ -186,6 +185,8 @@ void spi_mast_set_mosi(uint8 spi_no, uint8 offset, uint8 bitlen, uint32 data) wn_bitlen = bitlen; wn_data = data; } while (bitlen > 0); + + return; } /****************************************************************************** @@ -205,6 +206,8 @@ uint32 spi_mast_get_miso(uint8 spi_no, uint8 offset, uint8 bitlen) 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) diff --git a/app/include/driver/spi.h b/app/include/driver/spi.h index 5eb8faa5..22c9d400 100644 --- a/app/include/driver/spi.h +++ b/app/include/driver/spi.h @@ -18,7 +18,7 @@ void spi_lcd_mode_init(uint8 spi_no); void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit); //spi master init funtion -void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div); +void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div, uint8 full_duplex); // fill MOSI buffer void spi_set_mosi(uint8 spi_no, uint8 offset, uint8 bitlen, uint32 data); // retrieve data from MISO buffer diff --git a/app/modules/spi.c b/app/modules/spi.c index 6c98f7c2..46394cf7 100644 --- a/app/modules/spi.c +++ b/app/modules/spi.c @@ -9,15 +9,16 @@ static u8 spi_databits[NUM_SPI] = {0, 0}; -// Lua: = spi.setup( id, mode, cpol, cpha, databits, clock_div ) +// Lua: = spi.setup( id, mode, cpol, cpha, databits, clock_div, [full_duplex] ) static int spi_setup( lua_State *L ) { - int id = luaL_checkinteger( L, 1 ); - int mode = luaL_checkinteger( L, 2 ); - int cpol = luaL_checkinteger( L, 3 ); - int cpha = luaL_checkinteger( L, 4 ); - int databits = luaL_checkinteger( L, 5 ); - u32 clock_div = luaL_checkinteger( L, 6 ); + int id = luaL_checkinteger( L, 1 ); + int mode = luaL_checkinteger( L, 2 ); + int cpol = luaL_checkinteger( L, 3 ); + int cpha = luaL_checkinteger( L, 4 ); + int databits = luaL_checkinteger( L, 5 ); + u32 clock_div = luaL_checkinteger( L, 6 ); + int full_duplex = luaL_optinteger( L, 7, 1 ); MOD_CHECK_ID( spi, id ); @@ -42,65 +43,134 @@ static int spi_setup( lua_State *L ) clock_div = 8; } + if (full_duplex != 0 && full_duplex != 1) { + return luaL_error( L, "out of range" ); + } + spi_databits[id] = databits; - u32 res = platform_spi_setup(id, mode, cpol, cpha, clock_div); + u32 res = platform_spi_setup(id, mode, cpol, cpha, clock_div, full_duplex); lua_pushinteger( L, res ); return 1; } -// Lua: wrote = spi.send( id, data1, [data2], ..., [datan] ) -// data can be either a string, a table or an 8-bit number -static int spi_send( lua_State *L ) +static int spi_generic_send_recv( lua_State *L, u8 recv ) { unsigned id = luaL_checkinteger( L, 1 ); const char *pdata; size_t datalen, i; - int numdata; + u32 numdata; u32 wrote = 0; - unsigned argn; + int pushed = 1; + unsigned argn, tos; MOD_CHECK_ID( spi, id ); - if( lua_gettop( L ) < 2 ) + if( (tos = lua_gettop( L )) < 2 ) return luaL_error( L, "wrong arg type" ); - for( argn = 2; argn <= lua_gettop( L ); argn ++ ) + // prepare first returned item 'wrote' - value is yet unknown + // position on stack is tos+1 + lua_pushinteger( L, 0 ); + + for( argn = 2; argn <= tos; argn ++ ) { + // *** Send integer value and return received data as integer *** // lua_isnumber() would silently convert a string of digits to an integer // whereas here strings are handled separately. if( lua_type( L, argn ) == LUA_TNUMBER ) { - numdata = ( int )luaL_checkinteger( L, argn ); - platform_spi_send( id, spi_databits[id], numdata ); + numdata = luaL_checkinteger( L, argn ); + if (recv > 0) + { + lua_pushinteger( L, platform_spi_send_recv( id, spi_databits[id], numdata ) ); + pushed ++; + } + else + { + platform_spi_send( id, spi_databits[id], numdata ); + } wrote ++; } + + // *** Send table elements and return received data items as a table *** else if( lua_istable( L, argn ) ) { datalen = lua_objlen( L, argn ); + + if (recv > 0 && datalen > 0) { + // create a table for the received data + lua_createtable( L, datalen, 0 ); + pushed ++; + } + for( i = 0; i < datalen; i ++ ) { lua_rawgeti( L, argn, i + 1 ); - numdata = ( int )luaL_checkinteger( L, -1 ); + numdata = luaL_checkinteger( L, -1 ); lua_pop( L, 1 ); - platform_spi_send( id, spi_databits[id], numdata ); + if (recv > 0) { + lua_pushinteger( L, platform_spi_send_recv( id, spi_databits[id], numdata ) ); + lua_rawseti( L, -1, i + 1 ); + } + else + { + platform_spi_send( id, spi_databits[id], numdata ); + } } wrote += i; if( i < datalen ) break; } + + // *** Send characters of a string and return received data items as string *** else { + luaL_Buffer b; + pdata = luaL_checklstring( L, argn, &datalen ); + if (recv > 0) { + luaL_buffinit( L, &b ); + } + for( i = 0; i < datalen; i ++ ) - platform_spi_send( id, spi_databits[id], pdata[ i ] ); + { + if (recv > 0) + { + luaL_addchar( &b, (char)platform_spi_send_recv( id, spi_databits[id], pdata[ i ] ) ); + } + else + { + platform_spi_send( id, spi_databits[id], pdata[ i ] ); + } + } + if (recv > 0 && datalen > 0) { + luaL_pushresult( &b ); + pushed ++; + } wrote += i; if( i < datalen ) break; } } + // update item 'wrote' on stack lua_pushinteger( L, wrote ); - return 1; + lua_replace( L, tos+1 ); + return pushed; +} + +// Lua: wrote = spi.send( id, data1, [data2], ..., [datan] ) +// data can be either a string, a table or an 8-bit number +static int spi_send( lua_State *L ) +{ + return spi_generic_send_recv( L, 0 ); +} + +// Lua: wrote, [data1], ..., [datan] = spi.send_recv( id, data1, [data2], ..., [datan] ) +// data can be either a string, a table or an 8-bit number +static int spi_send_recv( lua_State *L ) +{ + return spi_generic_send_recv( L, 1 ); } // Lua: read = spi.recv( id, size ) @@ -246,6 +316,7 @@ const LUA_REG_TYPE spi_map[] = { { LSTRKEY( "setup" ), LFUNCVAL( spi_setup ) }, { LSTRKEY( "send" ), LFUNCVAL( spi_send ) }, + { LSTRKEY( "send_recv" ), LFUNCVAL( spi_send_recv ) }, { LSTRKEY( "recv" ), LFUNCVAL( spi_recv ) }, { LSTRKEY( "set_mosi" ), LFUNCVAL( spi_set_mosi ) }, { LSTRKEY( "get_miso" ), LFUNCVAL( spi_get_miso ) }, @@ -258,6 +329,8 @@ const LUA_REG_TYPE spi_map[] = { LSTRKEY( "CPOL_LOW" ), LNUMVAL( PLATFORM_SPI_CPOL_LOW) }, { LSTRKEY( "CPOL_HIGH" ), LNUMVAL( PLATFORM_SPI_CPOL_HIGH) }, { LSTRKEY( "DATABITS_8" ), LNUMVAL( 8 ) }, + { LSTRKEY( "HALFDUPLEX" ), LNUMVAL( 0 ) }, + { LSTRKEY( "FULLDUPLEX" ), LNUMVAL( 1 ) }, #endif // #if LUA_OPTIMIZE_MEMORY > 0 { LNILKEY, LNILVAL } }; @@ -277,6 +350,8 @@ LUALIB_API int luaopen_spi( lua_State *L ) MOD_REG_NUMBER( L, "CPOL_LOW" , PLATFORM_SPI_CPOL_LOW); MOD_REG_NUMBER( L, "CPOL_HIGH", PLATFORM_SPI_CPOL_HIGH); MOD_REG_NUMBER( L, "DATABITS_8", 8 ); + MOD_REG_NUMBER( L, "HALFDUPLEX", 0 ); + MOD_REG_NUMBER( L, "FULLDUPLEX", 1 ); return 1; #endif // #if LUA_OPTIMIZE_MEMORY > 0 diff --git a/app/platform/platform.c b/app/platform/platform.c index aa7fdc85..04963f48 100644 --- a/app/platform/platform.c +++ b/app/platform/platform.c @@ -435,11 +435,15 @@ int platform_i2c_recv_byte( unsigned id, int ack ){ return r; } +static uint8_t platform_spi_fdplx[NUM_SPI] = {0, 0}; + // ***************************************************************************** // SPI platform interface -uint32_t platform_spi_setup( uint8_t id, int mode, unsigned cpol, unsigned cpha, uint32_t clock_div) +uint32_t platform_spi_setup( uint8_t id, int mode, unsigned cpol, unsigned cpha, + uint32_t clock_div, uint8 full_duplex ) { - spi_master_init(id, cpol, cpha, clock_div); + platform_spi_fdplx[id] = full_duplex; + spi_master_init( id, cpol, cpha, clock_div, full_duplex ); return 1; } @@ -449,10 +453,19 @@ int platform_spi_send( uint8_t id, uint8_t bitlen, spi_data_type data ) return PLATFORM_ERR; spi_mast_transaction( id, 0, 0, bitlen, data, 0, 0, 0 ); - return PLATFORM_OK; } +spi_data_type platform_spi_send_recv( uint8_t id, uint8_t bitlen, spi_data_type data ) +{ + if (bitlen > 32) + return 0; + + spi_mast_set_mosi( id, 0, bitlen, data ); + spi_mast_transaction( id, 0, 0, 0, 0, bitlen, 0, platform_spi_fdplx[id] > 0 ? 0 : bitlen ); + return spi_mast_get_miso( id, 0, bitlen ); +} + int platform_spi_set_mosi( uint8_t id, uint8_t offset, uint8_t bitlen, spi_data_type data ) { if (offset + bitlen > 512) @@ -472,8 +485,8 @@ spi_data_type platform_spi_get_miso( uint8_t id, uint8_t offset, uint8_t bitlen } 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 ) + 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) || diff --git a/app/platform/platform.h b/app/platform/platform.h index 42db1bfa..5fb607bc 100644 --- a/app/platform/platform.h +++ b/app/platform/platform.h @@ -96,8 +96,9 @@ typedef uint32_t spi_data_type; // The platform SPI functions int platform_spi_exists( unsigned id ); -uint32_t platform_spi_setup( uint8_t id, int mode, unsigned cpol, unsigned cpha, uint32_t clock_div); +uint32_t platform_spi_setup( uint8_t id, int mode, unsigned cpol, unsigned cpha, uint32_t clock_div, uint8_t full_duplex); int platform_spi_send( uint8_t id, uint8_t bitlen, spi_data_type data ); +spi_data_type platform_spi_send_recv( uint8_t id, uint8_t bitlen, 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 );