From 6b3f038db3849fe03d0d329490fe1db3a93a7e7d Mon Sep 17 00:00:00 2001 From: Bogdan Marinescu Date: Wed, 21 Jul 2010 20:21:55 +0000 Subject: [PATCH] added support for the I2C interface. UNTESTED, for now enabled only for the STR9 platform. Documentation will follow shortly --- SConstruct | 2 +- inc/platform.h | 29 +- src/common.c | 10 + src/modules/auxmods.h | 4 + src/modules/i2c.c | 154 ++++++++ src/platform/stm32/platform.c | 2 + src/platform/str9/91x_i2c.c | 615 ++++++++++++++++++++++++++++++ src/platform/str9/91x_i2c.h | 112 ++++++ src/platform/str9/conf.py | 2 +- src/platform/str9/platform.c | 89 +++++ src/platform/str9/platform_conf.h | 2 + 11 files changed, 1017 insertions(+), 4 deletions(-) create mode 100644 src/modules/i2c.c create mode 100755 src/platform/str9/91x_i2c.c create mode 100644 src/platform/str9/91x_i2c.h diff --git a/SConstruct b/SConstruct index 675ad0a6..ec1199c6 100644 --- a/SConstruct +++ b/SConstruct @@ -383,7 +383,7 @@ if not GetOption( 'help' ): comp.Append(CPPPATH = ['src/fatfs']) # Lua module files - module_names = "pio.c spi.c tmr.c pd.c uart.c term.c pwm.c lpack.c bit.c net.c cpu.c adc.c can.c luarpc.c bitarray.c elua.c" + module_names = "pio.c spi.c tmr.c pd.c uart.c term.c pwm.c lpack.c bit.c net.c cpu.c adc.c can.c luarpc.c bitarray.c elua.c i2c.c" module_files = " " + " ".join( [ "src/modules/%s" % name for name in module_names.split() ] ) # Remote file system files diff --git a/inc/platform.h b/inc/platform.h index 97dd402b..308171f5 100644 --- a/inc/platform.h +++ b/inc/platform.h @@ -211,8 +211,8 @@ enum }; // Functions requiring platform-specific implementation -int platform_adc_update_sequence( ); -int platform_adc_start_sequence( ); +int platform_adc_update_sequence(); +int platform_adc_start_sequence(); void platform_adc_stop( unsigned id ); u32 platform_adc_setclock( unsigned id, u32 frequency); @@ -221,6 +221,31 @@ int platform_adc_exists( unsigned id ); int platform_adc_check_timer_id( unsigned id, unsigned timer_id ); u32 platform_adc_op( unsigned id, int op, u32 data ); +// ***************************************************************************** +// I2C platform interface + +// I2C speed +enum +{ + PLATFORM_I2C_SPEED_SLOW = 100000, + PLATFORM_I2C_SPEED_FAST = 400000 +}; + +// I2C direction +enum +{ + PLATFORM_I2C_DIRECTION_TRANSMITTER, + PLATFORM_I2C_DIRECTION_RECEIVER +}; + +int platform_i2c_exists( unsigned id ); +u32 platform_i2c_setup( unsigned id, u32 speed ); +void platform_i2c_send_start( unsigned id ); +void platform_i2c_send_stop( unsigned id ); +int platform_i2c_send_address( unsigned id, u16 address, int direction ); +int platform_i2c_send_byte( unsigned id, u8 data ); +int platform_i2c_recv_byte( unsigned id, int ack ); + // ***************************************************************************** // Ethernet specific functions diff --git a/src/common.c b/src/common.c index 702dc44e..364260e3 100644 --- a/src/common.c +++ b/src/common.c @@ -461,6 +461,16 @@ void* platform_get_last_free_ram( unsigned id ) return ( void* )p; } +// I2C support +int platform_i2c_exists( unsigned id ) +{ +#ifndef NUM_I2C + return 0; +#else + return id < NUM_I2C; +#endif +} + // **************************************************************************** // Misc support unsigned int intlog2( unsigned int v ) diff --git a/src/modules/auxmods.h b/src/modules/auxmods.h index 925943f1..d59fb6a4 100644 --- a/src/modules/auxmods.h +++ b/src/modules/auxmods.h @@ -54,6 +54,9 @@ LUALIB_API int ( luaopen_bitarray )( lua_State *L ); #define AUXLIB_ELUA "elua" LUALIB_API int ( luaopen_elua )( lua_State *L ); +#define AUXLIB_I2C "i2c" +LUALIB_API int ( luaopen_i2c )( lua_State *L ); + // Helper macros #define MOD_CHECK_ID( mod, id )\ if( !platform_ ## mod ## _exists( id ) )\ @@ -68,3 +71,4 @@ LUALIB_API int ( luaopen_elua )( lua_State *L ); lua_setfield( L, -2, name ) #endif + diff --git a/src/modules/i2c.c b/src/modules/i2c.c new file mode 100644 index 00000000..dc059b18 --- /dev/null +++ b/src/modules/i2c.c @@ -0,0 +1,154 @@ +// Module for interfacing with the I2C interface + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +#include "platform.h" +#include "auxmods.h" +#include "lrotable.h" +#include +#include + +// Lua: speed = i2c.setup( id, speed ) +static int i2c_setup( lua_State *L ) +{ + unsigned id = luaL_checkinteger( L, 1 ); + u32 speed = ( u32 )luaL_checkinteger( L, 2 ); + + MOD_CHECK_ID( i2c, id ); + lua_pushinteger( L, platform_i2c_setup( id, speed ) ); + return 1; +} + +// Lua: i2c.start( id ) +static int i2c_start( lua_State *L ) +{ + unsigned id = luaL_checkinteger( L, 1 ); + + MOD_CHECK_ID( i2c, id ); + platform_i2c_send_start( id ); + return 0; +} + +// Lua: i2c.stop( id ) +static int i2c_stop( lua_State *L ) +{ + unsigned id = luaL_checkinteger( L, 1 ); + + MOD_CHECK_ID( i2c, id ); + platform_i2c_send_stop( id ); + return 0; +} + +// Lua: i2c.address( id, address, direction ) +static int i2c_address( lua_State *L ) +{ + unsigned id = luaL_checkinteger( L, 1 ); + u16 address = ( u16 )luaL_checkinteger( L, 2 ); + int direction = luaL_checkinteger( L, 3 ); + + MOD_CHECK_ID( i2c, id ); + lua_pushboolean( L, platform_i2c_send_address( id, address, direction ) ); + return 1; +} + +// Lua: wrote = i2c.write( id, string | table | 8-bit number ) +static int i2c_write( lua_State *L ) +{ + unsigned id = luaL_checkinteger( L, 1 ); + const char *pdata; + size_t datalen, i; + int numdata; + u32 wrote; + + MOD_CHECK_ID( i2c, id ); + if( lua_isnumber( L, 2 ) ) + { + numdata = ( int )luaL_checkinteger( L, 2 ); + if( numdata < 0 || numdata > 255 ) + return luaL_error( L, "numeric data can be between 0 and 255" ); + wrote = platform_i2c_send_byte( id, numdata ); + } + else if( lua_istable( L, 2 ) ) + { + datalen = lua_objlen( L, 2 ); + for( i = 0; i < datalen; i ++ ) + { + lua_rawgeti( L, 2, i + 1 ); + numdata = luaL_checkinteger( L, -1 ); + lua_pop( L, 1 ); + if( numdata < 0 || numdata > 255 ) + return luaL_error( L, "numeric data can be between 0 and 255" ); + if( platform_i2c_send_byte( id, numdata ) == 0 ) + break; + } + wrote = i; + } + else + { + pdata = luaL_checklstring( L, 2, &datalen ); + for( i = 0; i < datalen; i ++ ) + if( platform_i2c_send_byte( id, pdata[ i ] ) == 0 ) + break; + wrote = i; + } + lua_pushinteger( L, wrote ); + return 1; +} + +// Lua: read = i2c.read( id, size ) +static int i2c_read( lua_State *L ) +{ + unsigned id = luaL_checkinteger( L, 1 ); + u32 size = ( u32 )luaL_checkinteger( L, 2 ), i; + luaL_Buffer b; + int data; + + MOD_CHECK_ID( i2c, id ); + luaL_buffinit( L, &b ); + for( i = 0; i < size; i ++ ) + if( ( data = platform_i2c_recv_byte( id, i < size - 1 ) ) == -1 ) + break; + else + luaL_addchar( &b, ( char )data ); + luaL_pushresult( &b ); + return 1; +} + +// Module function map +#define MIN_OPT_LEVEL 2 +#include "lrodefs.h" +const LUA_REG_TYPE i2c_map[] = +{ + { LSTRKEY( "setup" ), LFUNCVAL( i2c_setup ) }, + { LSTRKEY( "start" ), LFUNCVAL( i2c_start ) }, + { LSTRKEY( "stop" ), LFUNCVAL( i2c_stop ) }, + { LSTRKEY( "address" ), LFUNCVAL( i2c_address ) }, + { LSTRKEY( "write" ), LFUNCVAL( i2c_write ) }, + { LSTRKEY( "read" ), LFUNCVAL( i2c_read ) }, +#if LUA_OPTIMIZE_MEMORY > 0 + { LSTRKEY( "SPEED_FAST" ), LNUMVAL( PLATFORM_I2C_SPEED_FAST ) }, + { LSTRKEY( "SPEED_SLOW" ), LNUMVAL( PLATFORM_I2C_SPEED_SLOW ) }, + { LSTRKEY( "TRANSMITTER" ), LNUMVAL( PLATFORM_I2C_DIRECTION_TRANSMITTER ) }, + { LSTRKEY( "RECEIVER" ), LNUMVAL( PLATFORM_I2C_DIRECTION_RECEIVER ) }, +#endif + { LNILKEY, LNILVAL } +}; + +LUALIB_API int luaopen_i2c( lua_State *L ) +{ +#if LUA_OPTIMIZE_MEMORY > 0 + return 0; +#else // #if LUA_OPTIMIZE_MEMORY > 0 + luaL_register( L, AUXLIB_I2C, i2c_map ); + + // Add the stop bits and parity constants (for uart.setup) + MOD_REG_NUMBER( L, "SPEED_FAST", PLATFORM_I2C_SPEED_FAST ); + MOD_REG_NUMBER( L, "SPEED_SLOW", PLATFORM_I2C_SPEED_SLOW ); + MOD_REG_NUMBER( L, "TRANSMITTER", PLATFORM_I2C_DIRECTION_TRANSMITTER ); + MOD_REG_NUMBER( L, "RECEIVER", PLATFORM_I2C_DIRECTION_RECEIVER ); + + return 1; +#endif // #if LUA_OPTIMIZE_MEMORY > 0 +} + diff --git a/src/platform/stm32/platform.c b/src/platform/stm32/platform.c index 90066af1..9c2efb79 100755 --- a/src/platform/stm32/platform.c +++ b/src/platform/stm32/platform.c @@ -1221,3 +1221,5 @@ int platform_adc_start_sequence( ) } #endif // ifdef BUILD_ADC + + diff --git a/src/platform/str9/91x_i2c.c b/src/platform/str9/91x_i2c.c new file mode 100755 index 00000000..9abed06a --- /dev/null +++ b/src/platform/str9/91x_i2c.c @@ -0,0 +1,615 @@ +/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** +* File Name : 91x_i2c.c +* Author : MCD Application Team +* Version : V2.1 +* Date : 12/22/2008 +* Description : This file provides all the I2C firmware functions. +******************************************************************************** +* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "91x_i2c.h" +#include "91x_scu.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* I2C IT enable */ +#define I2C_IT_Enable 0x01 +#define I2C_IT_Disable 0xFE + +/* I2C Peripheral Enable/Disable */ +#define I2C_PE_Set 0x20 +#define I2C_PE_Reset 0xDF + +/* Address direction bit */ +#define I2C_ADD0_Set 0x01 +#define I2C_ADD0_Reset 0xFE + +/* I2C START Enable/Disable */ +#define I2C_Start_Enable 0x08 +#define I2C_Start_Disable 0xF7 + +/* I2C STOP Enable/Disable */ +#define I2C_Stop_Enable 0x02 +#define I2C_Stop_Disable 0xFD + +/* I2C Masks */ +#define I2C_Frequency_Mask 0x1F +#define I2C_AddressHigh_Mask 0xF9 +#define I2C_OwnAddress_Mask 0x0300 +#define I2C_StandardMode_Mask 0x7f +#define I2C_FastMode_Mask 0x80 +#define I2C_Event_Mask 0x3FFF +#define I2C_HeaderSet_Mask 0xF1 +#define I2C_HeaderReset_Mask 0xFE + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/******************************************************************************* +* Function Name : I2C_DeInit +* Description : Deinitializes the I2C peripheral registers to their default +* reset values. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* Output : None +* Return : None +*******************************************************************************/ +void I2C_DeInit(I2C_TypeDef* I2Cx) +{ + if (I2Cx == I2C0) + { + /* Reset the I2C0 registers values */ + SCU_APBPeriphReset(__I2C0, ENABLE); + SCU_APBPeriphReset(__I2C0, DISABLE); + } + if (I2Cx == I2C1) + { + /* Reset the I2C1 registers values */ + SCU_APBPeriphReset(__I2C1, ENABLE); + SCU_APBPeriphReset(__I2C1, DISABLE); + } +} + +/******************************************************************************* +* Function Name : I2C_Init +* Description : Initializes the I2C peripheral according to the specified +* parameters in the I2C_InitTypeDef structure. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* +* - I2C_InitStruct: pointer to an I2C_InitTypeDef structure that +* contains the configuration information for the specified I2C +* peripheral. +* Output : None +* Return : None +*******************************************************************************/ +void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct) +{ + u16 wResult = 0x0F; + u32 dPCLK = SCU_GetPCLKFreqValue() * 1000; + + /* Get PCLK frequency value */ + dPCLK = SCU_GetPCLKFreqValue()*1000; + /* Disable I2C peripheral to set FR[2:0] bits */ + I2C_Cmd (I2Cx, DISABLE); + /* Clear frequency FR[2:0] bits */ + I2Cx->OAR2 &= I2C_Frequency_Mask; + /* Set frequency bits depending on PCLK value */ + if ((dPCLK <1667000) & (dPCLK > 10000000)) + I2Cx->OAR2 |= 0x20; + else if (dPCLK < 26670000) + I2Cx->OAR2 |= 0x40; + else if (dPCLK < 40000000) + I2Cx->OAR2 |= 0x60; + else if (dPCLK < 53330000) + I2Cx->OAR2 |= 0x80; + else if (dPCLK < 66000000) + I2Cx->OAR2 |= 0xA0; + else if (dPCLK < 80000000) + I2Cx->OAR2 |= 0xC0; + else if (dPCLK < 100000000) + I2Cx->OAR2 |= 0xE0; + I2C_Cmd (I2Cx, ENABLE); + + /* Configure general call */ + if (I2C_InitStruct->I2C_GeneralCall == I2C_GeneralCall_Enable) + { + /* Enable general call */ + I2Cx->CR |= I2C_GeneralCall_Enable; + } + else + { + /* Disable general call */ + I2Cx->CR &= I2C_GeneralCall_Disable; + } + /* Configure acknowledgement */ + if (I2C_InitStruct->I2C_Ack == I2C_Ack_Enable) + { + /* Enable acknowledgement */ + I2Cx->CR |= I2C_Ack_Enable; + } + else + { + /* Disable acknowledgement */ + I2Cx->CR &= I2C_Ack_Disable; + } + + /* Configure LSB own address */ + I2Cx->OAR1 = I2C_InitStruct->I2C_OwnAddress; + /* Clear MSB own address ADD[9:8] bits */ + I2Cx->OAR2 &= I2C_AddressHigh_Mask; + /* Set MSB own address value */ + I2Cx->OAR2 |= (I2C_InitStruct->I2C_OwnAddress & I2C_OwnAddress_Mask)>>7; + + /* Configure speed in standard mode */ + if (I2C_InitStruct->I2C_CLKSpeed <= 100000) + { + /* Standard mode speed calculate */ + wResult = ((dPCLK/I2C_InitStruct->I2C_CLKSpeed)-7)/2; + /* Set speed value and clear FM/SM bit for standard mode in LSB clock divider */ + I2Cx->CCR = wResult & I2C_StandardMode_Mask; + } + /* Configure speed in fast mode */ + else if (I2C_InitStruct->I2C_CLKSpeed <= 400000) + { + /* Fast mode speed calculate */ + wResult = ((dPCLK/I2C_InitStruct->I2C_CLKSpeed)-9)/3; + /* Set speed value and set FM/SM bit for fast mode in LSB clock divider */ + I2Cx->CCR = wResult | I2C_FastMode_Mask; + } + /* Set speed in MSB clock divider */ + I2Cx->ECCR = wResult >>7; +} + +/******************************************************************************* +* Function Name : I2C_StructInit +* Description : Initialize the I2C Init Structure parameters +* Input : - I2C_InitStruct: pointer to an I2C_InitTypeDef structure + which will be initialized. +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct) +{ + /* Initialize the I2C_CLKSpeed member */ + I2C_InitStruct->I2C_CLKSpeed = 5000; + + /* Initialize the I2C_OwnAddress member */ + I2C_InitStruct->I2C_OwnAddress = 0x0; + + /* Initialize the I2C_GeneralCall member */ + I2C_InitStruct->I2C_GeneralCall = I2C_GeneralCall_Disable; + + /* Initialize the I2C_Ack member */ + I2C_InitStruct->I2C_Ack = I2C_Ack_Disable; +} + +/******************************************************************************* +* Function Name : I2C_Cmd +* Description : Enables or disables the specified I2C peripheral. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - NewState: new state of the I2C peripheral. This parameter +* can be: ENABLE or DISABLE. +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + if (NewState == ENABLE) + { + /* Enable the I2C peripheral by setting twice the PE bit on the CR register */ + I2Cx->CR |= I2C_PE_Set; + I2Cx->CR |= I2C_PE_Set; + } + else + { + /* Disable the I2C peripheral */ + I2Cx->CR &= I2C_PE_Reset; + } +} + +/******************************************************************************* +* Function Name : I2C_GenerateSTART +* Description : Generates I2C communication START condition. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* +* - NewState: new state of the Start condition. This parameter +* can be: ENABLE or DISABLE. +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_GenerateStart(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + if (NewState == ENABLE) + { + /* Generate a START condition */ + I2Cx->CR |= I2C_Start_Enable; + } + else + { + /* Disable the START condition generation */ + I2Cx->CR &= I2C_Start_Disable; + } +} + +/******************************************************************************* +* Function Name : I2C_GenerateSTOP +* Description : Generates I2C communication STOP condition. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* +* - NewState: new state of the Stop condition. This parameter +* can be: ENABLE or DISABLE. +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + if (NewState == ENABLE) + { + /* Generate a SIOP condition */ + I2Cx->CR |= I2C_Stop_Enable; + } + else + { + /* Disable the STOP condition generation */ + I2Cx->CR &= I2C_Stop_Disable; + } +} + +/******************************************************************************* +* Function Name : I2C_AcknowledgeConfig +* Description : Enables or disables I2C acknowledge feature. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - NewState: new state of the Acknowledgement. This parameter +* can be: ENABLE or DISABLE. +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_AcknowledgeConfig(I2C_TypeDef *I2Cx, FunctionalState NewState) +{ + if (NewState == ENABLE) + { + /* Enable the acknowledgement */ + I2Cx->CR |= I2C_Ack_Enable; + } + else + { + /* Disable the acknowledgement */ + I2Cx->CR &= I2C_Ack_Disable; + } +} + +/******************************************************************************* +* Function Name : I2C_ITConfig +* Description : Enables or disables I2C interrupt feature. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - NewState: new state of the specified I2C interrupt. +* This parameter can be: ENABLE or DISABLE. +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_ITConfig(I2C_TypeDef *I2Cx, FunctionalState NewState) +{ + if (NewState == ENABLE) + { + /* Enable the I2C interrupt */ + I2Cx->CR |= I2C_IT_Enable; + } + else + { + /* Disable the I2C interrupt */ + I2Cx->CR &= I2C_IT_Disable; + } +} + +/******************************************************************************* +* Function Name : I2C_ReadRegister +* Description : Reads any I2C register and returns its value. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - I2C_Register: the I2C register to be read. This parameter +* can be one of the following values: +* - I2C_CR: CR register. +* - I2C_SR1: SR1 register. +* - I2C_SR2: SR2 register. +* - I2C_CCR: CCR register. +* - I2C_OAR1: OAR1 register. +* - I2C_OAR2: OAR2 register. +* - I2C_DR: DR register. +* - I2C_ECCR: ECCR register. +* Output : None +* Return : The value of the register passed as parameter +*******************************************************************************/ +u8 I2C_ReadRegister(I2C_TypeDef* I2Cx, u8 I2C_Register) +{ + /* Return the selected register value */ + if (I2Cx == I2C0) + { + return (*(u8 *)(I2C0_BASE + I2C_Register)); + } + if (I2Cx == I2C1) + { + return (*(u8 *)(I2C1_BASE + I2C_Register)); + } + return 0; +} + +/******************************************************************************* +* Function Name : I2C_GetFlagStatus +* Description : Checks whether the specified I2C flag is set or not. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - I2C_FLAG: flag to check. This parameter can be one of the +* following values: +* - I2C_FLAG_SB: Start bit flag +* - I2C_FLAG_M_SL: Master/Slave flag +* - I2C_FLAG_ADSL: Adress matched flag +* - I2C_FLAG_BTF: Byte transfer finished flag +* - I2C_FLAG_BUSY: Bus busy flag +* - I2C_FLAG_TRA: Transmitter/Receiver flag +* - I2C_FLAG_ADD10: 10-bit addressing in Master mode flag +* - I2C_FLAG_EVF: Event flag +* - I2C_FLAG_GCAL: General call flag +* - I2C_FLAG_BERR: Bus error flag +* - I2C_FLAG_ARLO: Arbitration lost flag +* - I2C_FLAG_STOPF: Stop detection flag +* - I2C_FLAG_AF: Acknowledge failure flag +* - I2C_FLAG_ENDAD: End of address transmission flag +* - I2C_FLAG_ACK: Acknowledge enable flag +* Output : None +* Return : The NewState of the I2C_Flag (SET or RESET). +*******************************************************************************/ +FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, u16 I2C_FLAG) +{ + u16 wFlag1=0, wFlag2=0, wTmp=0; + + wFlag1 = I2Cx->SR2; + wFlag1 = wFlag1<<8; + wFlag2 = I2Cx->CR & 0x04; + + /* Get all the I2C flags in a unique register*/ + wTmp = (((I2Cx->SR1 | (wFlag1)) & I2C_Event_Mask) | (wFlag2<<12)); + + /* Check the status of the specified I2C flag */ + if((wTmp & I2C_FLAG) != RESET) + { + /* Return SET if I2C_FLAG is set */ + return SET; + } + else + { + /* Return RESET if I2C_FLAG is reset */ + return RESET; + } +} + +/******************************************************************************* +* Function Name : I2C_ClearFlag +* Description : Clears the I2C Flag passed as a parameter +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - I2C_FLAG: flag to check. This parameter can be one of the +* following values: +* - I2C_FLAG_SB: Start bit flag +* - I2C_FLAG_M_SL: Master/Slave flag +* - I2C_FLAG_ADSL: Adress matched flag +* - I2C_FLAG_BTF: Byte transfer finished flag +* - I2C_FLAG_BUSY: Bus busy flag +* - I2C_FLAG_TRA: Transmitter/Receiver flag +* - I2C_FLAG_ADD10: 10-bit addressing in Master mode flag +* - I2C_FLAG_EVF: Event flag +* - I2C_FLAG_GCAL: General call flag +* - I2C_FLAG_BERR: Bus error flag +* - I2C_FLAG_ARLO: Arbitration lost flag +* - I2C_FLAG_STOPF: Stop detection flag +* - I2C_FLAG_AF: Acknowledge failure flag +* - I2C_FLAG_ENDAD: End of address transmission flag +* - I2C_FLAG_ACK: Acknowledge enable flag +* - parameter needed in the case that the flag to be cleared +* need a write in one register +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_ClearFlag(I2C_TypeDef* I2Cx, u16 I2C_FLAG, ...) +{ + u8 bTmp = (u8)*((u32 *) & I2C_FLAG + sizeof(I2C_FLAG)); + + /* flags that need a read of the SR2 register to be cleared */ + if ((I2C_FLAG==I2C_FLAG_ADD10) || (I2C_FLAG==I2C_FLAG_EVF) || (I2C_FLAG==I2C_FLAG_BERR) || (I2C_FLAG==I2C_FLAG_ARLO) | + (I2C_FLAG==I2C_FLAG_STOPF) ||(I2C_FLAG==I2C_FLAG_AF) || (I2C_FLAG==I2C_FLAG_ENDAD)) + { + /* Read the SR2 register */ + I2Cx->SR2; + + /* Two flags need a second step to be cleared */ + switch (I2C_FLAG) + { + case I2C_FLAG_ADD10: + /* Send the MSB 10bit address passed as second parameter */ + I2Cx->DR = bTmp; + break; + case I2C_FLAG_ENDAD: + /* Write to the I2C_CR register by setting PE bit */ + I2Cx->CR |= I2C_PE_Set; + break; + } + } + + /* flags that need a read of the SR1 register to be cleared */ + else if (I2C_FLAG==I2C_FLAG_SB || I2C_FLAG==I2C_FLAG_ADSL || I2C_FLAG==I2C_FLAG_BTF || I2C_FLAG==I2C_FLAG_TRA) + { + /* Read the SR1 register */ + (void)I2Cx->SR1; + + /* three flags need a second step to be cleared */ + if (I2C_FLAG == I2C_FLAG_SB) + { + /* Send the address byte passed as second parameter */ + I2Cx->DR = bTmp; + } + else if (I2C_FLAG==I2C_FLAG_BTF || I2C_FLAG==I2C_FLAG_TRA) + { + /* return the received byte in the variable passed as second parameter */ + bTmp=I2Cx->DR; + } + } + + /* flags that need to disable the I2C interface */ + else if ( I2C_FLAG==I2C_FLAG_M_SL || I2C_FLAG==I2C_FLAG_GCAL) + { + I2C_Cmd(I2Cx, DISABLE); + I2C_Cmd(I2Cx, ENABLE); + } +} + +/******************************************************************************* +* Function Name : I2C_Send7bitAddress +* Description : Transmits the address byte to select the slave device. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - Address: specifies the slave address which will be transmitted +* - Direction: specifies whether the I2C device will be a +* Transmitter or a Receiver. This parameter can be one of the +* following values +* - I2C_MODE_TRANSMITTER: Transmitter mode +* - I2C_MODE_RECEIVER: Receiver mode +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, u8 Address, u8 Direction) +{ + /* Test on the direction to define the read/write bit */ + if (Direction == I2C_MODE_RECEIVER) + { + /* Set the address bit0 for read */ + Address |= I2C_ADD0_Set; + } + else + { + /* Reset the address bit0 for write */ + Address &= I2C_ADD0_Reset; + } + /* Send the address */ + I2Cx->DR = Address; +} + +/******************************************************************************* +* Function Name : I2C_SendData +* Description : Send a data byte. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - bData : the byte to be sent +* Output : None +* Return : None. +*******************************************************************************/ +void I2C_SendData(I2C_TypeDef* I2Cx, u8 bData) +{ + /* Write in the DR register the byte to be sent */ + I2Cx->DR = bData; +} + +/******************************************************************************* +* Function Name : I2C_ReceiveData +* Description : Read the received byte. +* Input : - I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* Output : None +* Return : The received byte +*******************************************************************************/ +u8 I2C_ReceiveData(I2C_TypeDef* I2Cx) +{ + /* Return from the DR register the received byte */ + return I2Cx->DR; +} + +/******************************************************************************* +* Function Name : I2C_GetLastEvent +* Description : Get the Last happened I2C Event. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* Output : None +* Return : The Last happened Event. +*******************************************************************************/ +u16 I2C_GetLastEvent(I2C_TypeDef* I2Cx) +{ + u16 wFlag1=0, wFlag2 =0, wLastEvent=0; + wFlag2 = I2Cx->SR1; + wFlag1 = I2Cx->SR2; + wFlag1 = wFlag1<<8; + /* Get the last event value from I2C status register */ + wLastEvent = ((( wFlag2 | (wFlag1)) & I2C_Event_Mask)); + /* Return the last event */ + return wLastEvent; +} + +/******************************************************************************* +* Function Name : I2C_CheckEvent +* Description : Checks whether the Last I2C Event is equal to the one passed +* as parameter. +* Input :- I2Cx: I2C peripheral can be: +* - I2C0 +* - I2C1 +* - I2C_EVENT: the event to check. This parameter can be one of +* the following values: +* - I2C_EVENT_SLAVE_ADDRESS_MATCHED +* - I2C_EVENT_SLAVE_BYTE_RECEIVED +* - I2C_EVENT_SLAVE_BYTE_TRANSMITTED +* - I2C_EVENT_MASTER_MODE_SELECT +* - I2C_EVENT_MASTER_MODE_SELECTED +* - I2C_EVENT_MASTER_BYTE_RECEIVED +* - I2C_EVENT_MASTER_BYTE_TRANSMITTED +* - I2C_EVENT_MASTER_MODE_ADDRESS10 +* - I2C_EVENT_SLAVE_STOP_DETECTED +* - I2C_EVENT_SLAVE_ACK_FAILURE + - I2C_EV31 +* Output : None +* Return : An ErrorStatus enumuration value: +* - SUCCESS: Last event is equal to the I2C_Event +* - ERROR: Last event is different from the I2C_Event +*******************************************************************************/ +ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx,u16 I2C_EVENT) +{ + u16 wLastEvent = I2C_GetLastEvent(I2Cx); + + /* Check whther the last event is equal to I2C_EVENT */ + if (wLastEvent == I2C_EVENT) + { + /* Return SUCCESS when last event is equal to I2C_EVENT */ + return SUCCESS; + } + else + { + /* Return ERROR when last event is different from I2C_EVENT */ + return ERROR; + } +} + +/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/src/platform/str9/91x_i2c.h b/src/platform/str9/91x_i2c.h new file mode 100644 index 00000000..7e083bcc --- /dev/null +++ b/src/platform/str9/91x_i2c.h @@ -0,0 +1,112 @@ +/******************** (C) COPYRIGHT 2006 STMicroelectronics ******************** +* File Name : 91x_i2c.h +* Author : MCD Application Team +* Date First Issued : 05/18/2006 : Version 1.0 +* Description : This file contains all the functions prototypes for the +* I2C software library. +******************************************************************************** +* History: +* 05/24/2006 : Version 1.1 +* 05/18/2006 : Version 1.0 +******************************************************************************** +* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Define to prevent recursive inclusion ------------------------------------ */ +#ifndef __91x_I2C_H +#define __91x_I2C_H + +/* Includes ----------------------------------------------------------------- */ +#include "91x_map.h" + +/* Exported types ----------------------------------------------------------- */ +/* I2C Init structure definition */ +typedef struct +{ + u32 I2C_CLKSpeed; + u16 I2C_OwnAddress; + u8 I2C_GeneralCall; + u8 I2C_Ack; +}I2C_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ +#define I2C_GeneralCall_Enable 0x10 +#define I2C_GeneralCall_Disable 0xEF +/* Acknowledgement */ +#define I2C_Ack_Enable 0x04 +#define I2C_Ack_Disable 0xFB + +/* I2C Flags */ +#define I2C_FLAG_SB 0x0001 +#define I2C_FLAG_M_SL 0x0002 +#define I2C_FLAG_ADSL 0x0004 +#define I2C_FLAG_BTF 0x0008 +#define I2C_FLAG_BUSY 0x0010 +#define I2C_FLAG_TRA 0x0020 +#define I2C_FLAG_ADD10 0x0040 +#define I2C_FLAG_EVF 0x0080 +#define I2C_FLAG_GCAL 0x0100 +#define I2C_FLAG_BERR 0x0200 +#define I2C_FLAG_ARLO 0x0400 +#define I2C_FLAG_STOPF 0x0800 +#define I2C_FLAG_AF 0x1000 +#define I2C_FLAG_ENDAD 0x2000 +#define I2C_FLAG_ACK 0x4000 + +/* I2C Events */ +#define I2C_EVENT_SLAVE_ADDRESS_MATCHED ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_ADSL) +#define I2C_EVENT_SLAVE_BYTE_RECEIVED ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_BTF ) +#define I2C_EVENT_SLAVE_BYTE_TRANSMITTED ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_BTF | I2C_FLAG_TRA ) +#define I2C_EVENT_MASTER_MODE_SELECT ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_SB ) +#define I2C_EVENT_MASTER_MODE_SELECTED ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_ENDAD ) +#define I2C_EVENT_MASTER_BYTE_RECEIVED ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_BTF ) +#define I2C_EVENT_MASTER_BYTE_TRANSMITTED ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_BTF | I2C_FLAG_TRA ) +#define I2C_EVENT_MASTER_MODE_ADDRESS10 ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL |I2C_FLAG_ADD10 ) +#define I2C_EVENT_SLAVE_STOP_DETECTED I2C_FLAG_STOPF +#define I2C_EVENT_SLAVE_ACK_FAILURE ( I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_BTF | I2C_FLAG_TRA | I2C_FLAG_AF) + +#define I2C_BUS_ERROR_DETECTED I2C_FLAG_BERR +#define I2C_ARBITRATION_LOST I2C_FLAG_ARLO +#define I2C_SLAVE_GENERAL_CALL (I2C_FLAG_BUSY | I2C_FLAG_GCAL) + +/* Master/Receiver Mode */ +#define I2C_MODE_TRANSMITTER 0x00 +#define I2C_MODE_RECEIVER 0x01 + +/* I2C Registers offset */ +#define I2C_CR 0x00 +#define I2C_SR1 0x04 +#define I2C_SR2 0x08 +#define I2C_CCR 0x0C +#define I2C_OAR1 0x10 +#define I2C_OAR2 0x14 +#define I2C_DR 0x18 +#define I2C_ECCR 0x1C + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void I2C_DeInit(I2C_TypeDef* I2Cx); +void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct); +void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct); +void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_GenerateStart(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_AcknowledgeConfig(I2C_TypeDef *I2Cx, FunctionalState NewState); +void I2C_ITConfig(I2C_TypeDef *I2Cx, FunctionalState NewState); +void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, u8 Address, u8 Direction); +u8 I2C_ReadRegister(I2C_TypeDef* I2Cx, u8 I2C_Register); +FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, u16 I2C_FLAG); +void I2C_ClearFlag(I2C_TypeDef* I2Cx, u16 I2C_FLAG, ...); +void I2C_SendData(I2C_TypeDef* I2Cx, u8 bData); +u8 I2C_ReceiveData(I2C_TypeDef* I2Cx); +u16 I2C_GetLastEvent(I2C_TypeDef* I2Cx); +ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx,u16 I2C_Event); + +#endif /* __91x_I2C_H */ + +/******************* (C) COPYRIGHT 2006 STMicroelectronics *****END OF FILE****/ diff --git a/src/platform/str9/conf.py b/src/platform/str9/conf.py index 8432d1af..2f1e3c62 100644 --- a/src/platform/str9/conf.py +++ b/src/platform/str9/conf.py @@ -2,7 +2,7 @@ cpumode = ARGUMENTS.get( 'cpumode', 'arm' ).lower() -specific_files = "startup912.s startup_generic.s platform.c 91x_scu.c 91x_fmi.c 91x_gpio.c 91x_uart.c 91x_tim.c 91x_vic.c interrupt.c str9_pio.c" +specific_files = "startup912.s startup_generic.s platform.c 91x_scu.c 91x_fmi.c 91x_gpio.c 91x_uart.c 91x_tim.c 91x_vic.c interrupt.c str9_pio.c 91x_i2c.c" # Check CPU if comp[ 'cpu' ] == 'STR912FAW44': diff --git a/src/platform/str9/platform.c b/src/platform/str9/platform.c index 73208e97..edb48c04 100644 --- a/src/platform/str9/platform.c +++ b/src/platform/str9/platform.c @@ -19,6 +19,7 @@ #include "platform_conf.h" #include "91x_vic.h" #include "lrotable.h" +#include "91x_i2c.h" // **************************************************************************** // Platform initialization @@ -60,6 +61,10 @@ static void platform_config_scu() // Enable the GPIO clocks SCU_APBPeriphClockConfig(__GPIO_ALL, ENABLE); + + // Enable the I2C clocks + SCU_APBPeriphClockConfig(__I2C0, ENABLE); + SCU_APBPeriphClockConfig(__I2C1, ENABLE); } // Port/pin definitions of the eLua UART connection for different boards @@ -421,6 +426,90 @@ void platform_cpu_disable_interrupts() disable_ints(); } +// **************************************************************************** +// I2C support +static const GPIO_TypeDef* i2c_port_data[] = { GPIO1, GPIO2 }; +static const I2C_TypeDef* i2cs[] = { I2C0, I2C1 }; +static const u8 i2c_clock_pin[] = { GPIO_Pin_4, GPIO_Pin_2 }; +static const u8 i2c_data_pin[] = { GPIO_Pin_6, GPIO_Pin_3 }; + +u32 platform_i2c_setup( unsigned id, u32 speed ) +{ + GPIO_InitTypeDef GPIO_InitStructure; + I2C_InitTypeDef I2C_InitStructure; + + // Setup PIO + GPIO_StructInit( &GPIO_InitStructure ); + GPIO_InitStructure.GPIO_Pin = i2c_clock_pin[ id ] | i2c_data_pin[ id ]; + GPIO_InitStructure.GPIO_Type = GPIO_Type_OpenCollector; + GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; + GPIO_InitStructure.GPIO_Alternate = id == 0 ? GPIO_OutputAlt3 : GPIO_OutputAlt2; + GPIO_Init( ( GPIO_TypeDef* )i2c_port_data[ id ], &GPIO_InitStructure ); + + // Setup and interface + I2C_StructInit( &I2C_InitStructure ); + I2C_InitStructure.I2C_GeneralCall = I2C_GeneralCall_Disable; + I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; + I2C_InitStructure.I2C_CLKSpeed = speed; + I2C_InitStructure.I2C_OwnAddress = 0XA0 + id; // dummy, shouldn't matter + I2C_Init( ( I2C_TypeDef* )i2cs[ id ], &I2C_InitStructure ); + + // Return actual speed + return speed; +} + +void platform_i2c_send_start( unsigned id ) +{ + I2C_TypeDef *pi2c = ( I2C_TypeDef* )i2cs[ id ]; + + while( I2C_GetFlagStatus( pi2c, I2C_FLAG_BUSY ) ); + I2C_GenerateStart( pi2c, ENABLE ); + while( !I2C_CheckEvent( pi2c, I2C_EVENT_MASTER_MODE_SELECT ) ); +} + +void platform_i2c_send_stop( unsigned id ) +{ + I2C_TypeDef *pi2c = ( I2C_TypeDef* )i2cs[ id ]; + + while( I2C_GetFlagStatus( pi2c, I2C_FLAG_BUSY ) ); + I2C_GenerateSTOP( pi2c, ENABLE ); +} + +int platform_i2c_send_address( unsigned id, u16 address, int direction) +{ + I2C_TypeDef *pi2c = ( I2C_TypeDef* )i2cs[ id ]; + + while( I2C_GetFlagStatus( pi2c, I2C_FLAG_BUSY ) ); + I2C_Send7bitAddress( pi2c, address, direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ? I2C_MODE_TRANSMITTER : I2C_MODE_RECEIVER ); + while( !I2C_CheckEvent( pi2c, I2C_EVENT_MASTER_MODE_SELECTED ) ) + if( I2C_GetFlagStatus( pi2c, I2C_FLAG_AF ) == SET ) + return 0; + return 1; +} + +int platform_i2c_send_byte( unsigned id, u8 data ) +{ + I2C_TypeDef *pi2c = ( I2C_TypeDef* )i2cs[ id ]; + + while( I2C_GetFlagStatus( pi2c, I2C_FLAG_BUSY ) ); + I2C_SendData( pi2c, data ); + while( !I2C_CheckEvent( pi2c, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) ) + if( I2C_GetFlagStatus( pi2c, I2C_FLAG_AF ) == SET ) + return 0; + return 1; +} + +int platform_i2c_recv_byte( unsigned id, int ack ) +{ + I2C_TypeDef *pi2c = ( I2C_TypeDef* )i2cs[ id ]; + + while( I2C_GetFlagStatus( pi2c, I2C_FLAG_BUSY ) ); + I2C_AcknowledgeConfig( pi2c, ack ? ENABLE : DISABLE ); + if( I2C_CheckEvent( pi2c, I2C_EVENT_MASTER_BYTE_RECEIVED ) ) + return I2C_ReceiveData( pi2c ); + return -1; +} + // **************************************************************************** // Platform specific modules go here diff --git a/src/platform/str9/platform_conf.h b/src/platform/str9/platform_conf.h index 7dbeb48f..51e8c8f4 100644 --- a/src/platform/str9/platform_conf.h +++ b/src/platform/str9/platform_conf.h @@ -46,6 +46,7 @@ #define NUM_PWM 4 #define NUM_ADC 0 #define NUM_CAN 0 +#define NUM_I2C 2 // RPC boot options #define RPC_UART_ID CON_UART_ID @@ -96,6 +97,7 @@ u32 SCU_GetMCLKFreqValue(); _ROM( AUXLIB_BIT, luaopen_bit, bit_map )\ _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map)\ _ROM( AUXLIB_CPU, luaopen_elua, elua_map)\ + _ROM( AUXLIB_I2C, luaopen_i2c, i2c_map)\ RPCLINE\ _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map)\ _ROM( LUA_MATHLIBNAME, luaopen_math, math_map )\