From fe11e85eeaae8bb62943575e2016156ffb5c513a Mon Sep 17 00:00:00 2001 From: Raman Date: Sat, 9 Dec 2023 21:16:12 +0530 Subject: [PATCH] AVR32: Software I2C driver: Initial working commit (#8324) implemented the software I2C drivers for the AVR32 target. --- bsp/avr32/at32uc3a0256/.config | 24 ++--- bsp/avr32/at32uc3a0256/Kconfig | 20 ++++ bsp/avr32/at32uc3a0256/board.c | 6 ++ bsp/avr32/at32uc3a0256/rtconfig.h | 11 +- bsp/avr32/drivers/SConscript | 14 +-- bsp/avr32/drivers/drv_soft_i2c.c | 168 ++++++++++++++++++++++++++++++ bsp/avr32/drivers/drv_soft_i2c.h | 46 ++++++++ 7 files changed, 259 insertions(+), 30 deletions(-) create mode 100644 bsp/avr32/drivers/drv_soft_i2c.c create mode 100644 bsp/avr32/drivers/drv_soft_i2c.h diff --git a/bsp/avr32/at32uc3a0256/.config b/bsp/avr32/at32uc3a0256/.config index d46a9f938a..2b3abb1f3b 100644 --- a/bsp/avr32/at32uc3a0256/.config +++ b/bsp/avr32/at32uc3a0256/.config @@ -8,6 +8,7 @@ # CONFIG_RT_NAME_MAX=8 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set +# CONFIG_RT_USING_NANO is not set # CONFIG_RT_USING_AMP is not set # CONFIG_RT_USING_SMP is not set CONFIG_RT_CPUS_NR=1 @@ -34,10 +35,7 @@ CONFIG_RT_TIMER_THREAD_STACK_SIZE=512 # CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set # CONFIG_RT_USING_TINY_FFS is not set # CONFIG_RT_KPRINTF_USING_LONGLONG is not set -CONFIG_RT_USING_DEBUG=y -CONFIG_RT_DEBUGING_COLOR=y -# CONFIG_RT_DEBUGING_CONTEXT is not set -# CONFIG_RT_DEBUGING_INIT is not set +# CONFIG_RT_USING_DEBUG is not set # # Inter-Thread communication @@ -206,6 +204,12 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 # CONFIG_RT_USING_LWIP is not set # CONFIG_RT_USING_AT is not set +# +# Memory protection +# +# CONFIG_RT_USING_MEM_PROTECTION is not set +# CONFIG_RT_USING_HW_STACK_GUARD is not set + # # Utilities # @@ -218,17 +222,6 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set -# -# Memory management -# -# CONFIG_RT_USING_MEMBLOCK is not set - -# -# Memory protection -# -# CONFIG_RT_USING_MEM_PROTECTION is not set -# CONFIG_RT_USING_HW_STACK_GUARD is not set - # # RT-Thread Utestcases # @@ -1014,3 +1007,4 @@ CONFIG_BSP_UART1_RX_PIN_5=y # CONFIG_BSP_UART1_RX_PIN_96 is not set CONFIG_BSP_UART1_RX_PIN=5 CONFIG_BSP_UART1_RX_PIN_FUNCTION=0 +# CONFIG_BSP_USING_SOFT_I2C is not set diff --git a/bsp/avr32/at32uc3a0256/Kconfig b/bsp/avr32/at32uc3a0256/Kconfig index 513814e230..444a7e0922 100644 --- a/bsp/avr32/at32uc3a0256/Kconfig +++ b/bsp/avr32/at32uc3a0256/Kconfig @@ -132,5 +132,25 @@ menu "On-chip Peripheral Drivers" default 1 if BSP_UART1_RX_PIN_96 endif endif + + menuconfig BSP_USING_SOFT_I2C + bool "Enable I2C BUS (software simulation)" + default n + select RT_USING_I2C + select RT_USING_I2C_BITOPS + select RT_USING_PIN + if BSP_USING_SOFT_I2C + config BSP_USING_SOFT_I2C1 + bool "Enable I2C1 Bus (software simulation)" + default n + if BSP_USING_SOFT_I2C1 + config BSP_SOFT_I2C1_SCL_PIN + int "I2C1 SCL pin number (GP)" + default 30 + config BSP_SOFT_I2C1_SDA_PIN + int "I2C1 SDA pin number (GP)" + default 29 + endif + endif endmenu endmenu diff --git a/bsp/avr32/at32uc3a0256/board.c b/bsp/avr32/at32uc3a0256/board.c index 9955c39bec..64281a3ec6 100644 --- a/bsp/avr32/at32uc3a0256/board.c +++ b/bsp/avr32/at32uc3a0256/board.c @@ -8,6 +8,7 @@ * 2010-03-30 Kyle First version * 2023-10-13 Raman Gopalan Move UART specific code sections into the drv_uart files * 2023-10-20 Raman Gopalan Initialize GPIO sub-system + * 2023-12-01 Raman Gopalan Initialize software I2C sub-system */ #include @@ -18,6 +19,7 @@ #include "intc.h" #include "drv_uart.h" #include "drv_gpio.h" +#include "drv_soft_i2c.h" /** * System tick interrupt handler. @@ -78,6 +80,10 @@ void rt_hw_board_init(void) rt_hw_gpio_init(); #endif +#ifdef BSP_USING_SOFT_I2C + rt_sw_i2c_init(); +#endif + #ifdef RT_USING_CONSOLE rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #endif diff --git a/bsp/avr32/at32uc3a0256/rtconfig.h b/bsp/avr32/at32uc3a0256/rtconfig.h index 45e53b6060..77d72811d8 100644 --- a/bsp/avr32/at32uc3a0256/rtconfig.h +++ b/bsp/avr32/at32uc3a0256/rtconfig.h @@ -24,8 +24,6 @@ /* kservice optimization */ -#define RT_USING_DEBUG -#define RT_DEBUGING_COLOR /* Inter-Thread communication */ @@ -103,15 +101,12 @@ /* Network */ -/* Utilities */ - - -/* Memory management */ - - /* Memory protection */ +/* Utilities */ + + /* RT-Thread Utestcases */ diff --git a/bsp/avr32/drivers/SConscript b/bsp/avr32/drivers/SConscript index 6dd572dfb2..2ecd23b5d6 100644 --- a/bsp/avr32/drivers/SConscript +++ b/bsp/avr32/drivers/SConscript @@ -7,16 +7,16 @@ cwd = GetCurrentDir() # add the general drivers. src = [] -if GetDepend(['RT_USING_PIN']): +if GetDepend(['BSP_USING_PIN']): src += ['drv_gpio.c'] -if GetDepend(['RT_USING_SERIAL']): - if GetDepend(['RT_USING_SERIAL_V2']): - src += ['drv_uart_v2.c'] - else: - src += ['drv_uart.c'] +if GetDepend(['BSP_USING_UART']): + src += ['drv_uart.c'] -path = [cwd] +if GetDepend(['BSP_USING_SOFT_I2C']): + src += ['drv_soft_i2c.c'] + +path = [cwd] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path) diff --git a/bsp/avr32/drivers/drv_soft_i2c.c b/bsp/avr32/drivers/drv_soft_i2c.c new file mode 100644 index 0000000000..4409422445 --- /dev/null +++ b/bsp/avr32/drivers/drv_soft_i2c.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023/12/01 Raman Gopalan First version + */ +#include "drv_soft_i2c.h" + +#ifdef BSP_USING_SOFT_I2C +#define DBG_LEVEL DBG_LOG +#include +#define LOG_TAG "DRV.I2C" + +static const struct avr32_soft_i2c_config soft_i2c_config[] = +{ +#ifdef BSP_USING_SOFT_I2C1 + I2C1_BUS_CONFIG, +#endif +}; + +static struct avr32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])]; + +/** + * This function initializes the I2C pin. + * + * @param AVR32 I2C driver class. + */ +static void avr32_i2c_gpio_init(struct avr32_i2c *i2c) +{ + struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)i2c->ops.data; + + rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD); + gpio_set_gpio_open_drain_pin(cfg->scl); + + rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD); + gpio_set_gpio_open_drain_pin(cfg->sda); +} + +/** + * This function sets the SDA pin. + * + * @param AVR32 config class. + * @param The SDA pin state. + */ +static void avr32_set_sda(void *data, rt_int32_t state) +{ + struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data; + if (state) + { + gpio_set_gpio_open_drain_pin(cfg->sda); + } + else + { + gpio_clr_gpio_open_drain_pin(cfg->sda); + } +} + +/** + * This function sets the SCL pin. + * + * @param AVR32 config class. + * @param The SCL pin state. + */ +static void avr32_set_scl(void *data, rt_int32_t state) +{ + struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data; + if (state) + { + gpio_set_gpio_open_drain_pin(cfg->scl); + } + else + { + gpio_clr_gpio_open_drain_pin(cfg->scl); + } +} + +/** + * This function gets the SDA pin state. + * + * @param The SDA pin state. + */ +static rt_int32_t avr32_get_sda(void *data) +{ + struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data; + return gpio_get_gpio_open_drain_pin_output_value(cfg->sda); +} + +/** + * This function gets the SCL pin state. + * + * @param The SCL pin state. + */ +static rt_int32_t avr32_get_scl(void *data) +{ + struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data; + return gpio_get_gpio_open_drain_pin_output_value(cfg->scl); +} + +static const struct rt_i2c_bit_ops avr32_bit_ops_default = +{ + .data = RT_NULL, + .set_sda = avr32_set_sda, + .set_scl = avr32_set_scl, + .get_sda = avr32_get_sda, + .get_scl = avr32_get_scl, + .udelay = rt_hw_us_delay, + .delay_us = 1, + .timeout = 100 +}; + +/** + * If I2C is locked, this function will unlock it. + * + * @param AVR32 config class + * + * @return RT_EOK indicates successful unlock. + */ +static rt_err_t avr32_i2c_bus_unlock(const struct avr32_soft_i2c_config *cfg) +{ + rt_int32_t i = 0; + + if (PIN_LOW == gpio_get_gpio_open_drain_pin_output_value(cfg->sda)) + { + while (i++ < 9) + { + gpio_set_gpio_open_drain_pin(cfg->scl); + rt_hw_us_delay(100); + gpio_clr_gpio_open_drain_pin(cfg->scl); + rt_hw_us_delay(100); + } + } + if (PIN_LOW == gpio_get_gpio_open_drain_pin_output_value(cfg->sda)) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +/* I2C initialization function */ +int rt_sw_i2c_init(void) +{ + rt_err_t result; + rt_size_t i; + + for (i = 0; i < sizeof(i2c_obj) / sizeof(struct avr32_i2c); i++) + { + i2c_obj[i].ops = avr32_bit_ops_default; + i2c_obj[i].ops.data = (void*)&soft_i2c_config[i]; + i2c_obj[i].i2c2_bus.priv = &i2c_obj[i].ops; + avr32_i2c_gpio_init(&i2c_obj[i]); + result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name); + RT_ASSERT(result == RT_EOK); + avr32_i2c_bus_unlock(&soft_i2c_config[i]); + + LOG_D("Software simulation %s init done, pin SCL: %d, pin SDA %d", + soft_i2c_config[i].bus_name, + soft_i2c_config[i].scl, + soft_i2c_config[i].sda); + } + + return RT_EOK; +} + +#endif /* BSP_USING_SOFT_I2C */ diff --git a/bsp/avr32/drivers/drv_soft_i2c.h b/bsp/avr32/drivers/drv_soft_i2c.h new file mode 100644 index 0000000000..e5bcc77ebd --- /dev/null +++ b/bsp/avr32/drivers/drv_soft_i2c.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023/12/01 Raman Gopalan First version + */ + +#ifndef __DRV_SOFT_I2C__ +#define __DRV_SOFT_I2C__ + +#include +#include "drv_gpio.h" +#include "gpio.h" + +#ifdef BSP_USING_SOFT_I2C +/* AVR32 software I2C driver class */ +struct avr32_i2c +{ + struct rt_i2c_bit_ops ops; + struct rt_i2c_bus_device i2c2_bus; +}; + +/* AVR32 config class */ +struct avr32_soft_i2c_config +{ + rt_uint8_t scl; + rt_uint8_t sda; + const char *bus_name; +}; + +#ifdef BSP_USING_SOFT_I2C1 +#define I2C1_BUS_CONFIG \ + { \ + .scl = BSP_SOFT_I2C1_SCL_PIN, \ + .sda = BSP_SOFT_I2C1_SDA_PIN, \ + .bus_name = "i2c1", \ + } +#endif + +int rt_sw_i2c_init(void); + +#endif /* BSP_USING_SOFT_I2C */ +#endif /* #ifndef __DRV_SOFT_I2C__ */