Browse Source

introduce full/half duplex transactions and add spi.send_recv()

devsaurus 8 years ago
parent
commit
7d77398921
5 changed files with 128 additions and 36 deletions
  1. 11 8
      app/driver/spi.c
  2. 1 1
      app/include/driver/spi.h
  3. 96 21
      app/modules/spi.c
  4. 18 5
      app/platform/platform.c
  5. 2 1
      app/platform/platform.h

+ 11 - 8
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)<<SPI_CLKCNT_H_S)|
 					((1&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
 
-	//set 8bit output buffer length, the buffer is the low 8bit of register"SPI_FLASH_C0"
-	WRITE_PERI_REG(SPI_USER1(spi_no), 
-					((7&SPI_USR_MOSI_BITLEN)<<SPI_USR_MOSI_BITLEN_S)|
-					((7&SPI_USR_MISO_BITLEN)<<SPI_USR_MISO_BITLEN_S));
+        if (full_duplex > 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)

+ 1 - 1
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

+ 96 - 21
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

+ 18 - 5
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) ||

+ 2 - 1
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 );