diff --git a/APP_Framework/Framework/transform_layer/xizi/transform.h b/APP_Framework/Framework/transform_layer/xizi/transform.h index 2b071dca2..213948288 100644 --- a/APP_Framework/Framework/transform_layer/xizi/transform.h +++ b/APP_Framework/Framework/transform_layer/xizi/transform.h @@ -183,8 +183,16 @@ typedef struct LcdStringParam string_info; }LcdWriteParam; +typedef struct +{ + uint16_t x; + uint16_t y; + uint16_t press; +}TouchDataParam; + #define PRIV_SYSTICK_GET (CurrentTicksGain()) #define PRIV_LCD_DEV "/dev/lcd_dev" +#define PRIV_TOUCH_DEV "/dev/touch_dev" #define MY_DISP_HOR_RES BSP_LCD_Y_MAX #define MY_DISP_VER_RES BSP_LCD_X_MAX /**********************mutex**************************/ diff --git a/APP_Framework/lib/lvgl/examples/porting/lv_port_indev_template.c b/APP_Framework/lib/lvgl/examples/porting/lv_port_indev_template.c index 2b7931479..716d38169 100644 --- a/APP_Framework/lib/lvgl/examples/porting/lv_port_indev_template.c +++ b/APP_Framework/lib/lvgl/examples/porting/lv_port_indev_template.c @@ -12,9 +12,18 @@ #include "lv_port_indev_template.h" #include "../../lvgl.h" +static int touch_fd = 0; +static TouchDataParam touch_data; /********************* * DEFINES *********************/ +#define LV_USE_INDEV_TOUCHPAD 0x1u +#define LV_USE_INDEV_MOUSE 0x2u +#define LV_USE_INDEV_KEYPAD 0x4u +#define LV_USE_INDEV_ENCODER 0x8u +#define LV_USE_INDEV_BUTTUN 0x10u + +#define LV_USE_INDEV LV_USE_INDEV_TOUCHPAD ///< modify this DEFINE to enable the indev device. e.g #define LV_USE_INDEV LV_USE_INDEV_TOUCHPAD | LV_USE_INDEV_KEYPAD /********************** * TYPEDEFS @@ -23,38 +32,61 @@ /********************** * STATIC PROTOTYPES **********************/ - +#if (LV_USE_INDEV & LV_USE_INDEV_TOUCHPAD) == LV_USE_INDEV_TOUCHPAD static void touchpad_init(void); static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); static bool touchpad_is_pressed(void); static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y); +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_MOUSE) == LV_USE_INDEV_MOUSE static void mouse_init(void); static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); static bool mouse_is_pressed(void); static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y); +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_KEYPAD) == LV_USE_INDEV_KEYPAD static void keypad_init(void); static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); static uint32_t keypad_get_key(void); +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_ENCODER) == LV_USE_INDEV_ENCODER static void encoder_init(void); static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); static void encoder_handler(void); +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_BUTTUN) == LV_USE_INDEV_BUTTUN static void button_init(void); static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); static int8_t button_get_pressed_id(void); static bool button_is_pressed(uint8_t id); +#endif /********************** * STATIC VARIABLES **********************/ +#if (LV_USE_INDEV & LV_USE_INDEV_TOUCHPAD) == LV_USE_INDEV_TOUCHPAD lv_indev_t * indev_touchpad; +#endif + +#if (LV_USE_INDEV & LV_USE_INDEV_MOUSE) == LV_USE_INDEV_MOUSE lv_indev_t * indev_mouse; +#endif + +#if (LV_USE_INDEV & LV_USE_INDEV_KEYPAD) == LV_USE_INDEV_KEYPAD lv_indev_t * indev_keypad; +#endif + +#if (LV_USE_INDEV & LV_USE_INDEV_ENCODER) == LV_USE_INDEV_ENCODER lv_indev_t * indev_encoder; +#endif + +#if (LV_USE_INDEV & LV_USE_INDEV_BUTTUN) == LV_USE_INDEV_BUTTUN lv_indev_t * indev_button; +#endif static int32_t encoder_diff; static lv_indev_state_t encoder_state; @@ -82,7 +114,7 @@ void lv_port_indev_init(void) */ static lv_indev_drv_t indev_drv; - +#if (LV_USE_INDEV & LV_USE_INDEV_TOUCHPAD) == LV_USE_INDEV_TOUCHPAD /*------------------ * Touchpad * -----------------*/ @@ -95,7 +127,9 @@ void lv_port_indev_init(void) indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = touchpad_read; indev_touchpad = lv_indev_drv_register(&indev_drv); +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_MOUSE) == LV_USE_INDEV_MOUSE /*------------------ * Mouse * -----------------*/ @@ -113,7 +147,9 @@ void lv_port_indev_init(void) lv_obj_t * mouse_cursor = lv_img_create(lv_scr_act()); lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME); lv_indev_set_cursor(indev_mouse, mouse_cursor); +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_KEYPAD) == LV_USE_INDEV_KEYPAD /*------------------ * Keypad * -----------------*/ @@ -131,7 +167,11 @@ void lv_port_indev_init(void) *add objects to the group with `lv_group_add_obj(group, obj)` *and assign this input device to group to navigate in it: *`lv_indev_set_group(indev_keypad, group);`*/ +#endif + + +#if (LV_USE_INDEV & LV_USE_INDEV_ENCODER) == LV_USE_INDEV_ENCODER /*------------------ * Encoder * -----------------*/ @@ -149,7 +189,9 @@ void lv_port_indev_init(void) *add objects to the group with `lv_group_add_obj(group, obj)` *and assign this input device to group to navigate in it: *`lv_indev_set_group(indev_encoder, group);`*/ +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_BUTTUN) == LV_USE_INDEV_BUTTUN /*------------------ * Button * -----------------*/ @@ -169,12 +211,13 @@ void lv_port_indev_init(void) {40, 100}, /*Button 1 -> x:40; y:100*/ }; lv_indev_set_button_points(indev_button, btn_points); +#endif } /********************** * STATIC FUNCTIONS **********************/ - +#if (LV_USE_INDEV & LV_USE_INDEV_TOUCHPAD) == LV_USE_INDEV_TOUCHPAD /*------------------ * Touchpad * -----------------*/ @@ -182,6 +225,8 @@ void lv_port_indev_init(void) /*Initialize your touchpad*/ static void touchpad_init(void) { + touch_fd = PrivOpen(PRIV_TOUCH_DEV,O_RDWR); + printf("touch fd = %d\n",touch_fd); /*Your code comes here*/ } @@ -207,8 +252,15 @@ static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) /*Return true is the touchpad is pressed*/ static bool touchpad_is_pressed(void) { + int ret; /*Your code comes here*/ - + memset(&touch_data, 0 ,sizeof(TouchDataParam)); + ret = PrivRead(touch_fd, &touch_data, 1); + if(ret && touch_data.x >= 0 && touch_data.x <= 480 && touch_data.y >= 0 && touch_data.y <= 272) + { + return true; + } + return false; } @@ -217,10 +269,12 @@ static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y) { /*Your code comes here*/ - (*x) = 0; - (*y) = 0; + (*x) = touch_data.x; + (*y) = touch_data.y; } +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_MOUSE) == LV_USE_INDEV_MOUSE /*------------------ * Mouse * -----------------*/ @@ -261,7 +315,11 @@ static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y) (*x) = 0; (*y) = 0; } +#endif + + +#if (LV_USE_INDEV & LV_USE_INDEV_KEYPAD) == LV_USE_INDEV_KEYPAD /*------------------ * Keypad * -----------------*/ @@ -319,7 +377,11 @@ static uint32_t keypad_get_key(void) return 0; } +#endif + + +#if (LV_USE_INDEV & LV_USE_INDEV_ENCODER) == LV_USE_INDEV_ENCODER /*------------------ * Encoder * -----------------*/ @@ -346,7 +408,9 @@ static void encoder_handler(void) encoder_diff += 0; encoder_state = LV_INDEV_STATE_REL; } +#endif +#if (LV_USE_INDEV & LV_USE_INDEV_BUTTUN) == LV_USE_INDEV_BUTTUN /*------------------ * Button * -----------------*/ @@ -402,7 +466,7 @@ static bool button_is_pressed(uint8_t id) return false; } - +#endif #else /*Enable this file at the top*/ /*This dummy typedef exists purely to silence -Wpedantic.*/ diff --git a/Ubiquitous/XiZi/arch/arm/cortex-m7/interrupt.c b/Ubiquitous/XiZi/arch/arm/cortex-m7/interrupt.c index db1f45812..f37418b90 100644 --- a/Ubiquitous/XiZi/arch/arm/cortex-m7/interrupt.c +++ b/Ubiquitous/XiZi/arch/arm/cortex-m7/interrupt.c @@ -20,7 +20,7 @@ #include #include - +#include "fsl_common.h" x_base __attribute__((naked)) DisableLocalInterrupt() { @@ -37,11 +37,13 @@ void __attribute__((naked)) EnableLocalInterrupt(x_base level) int32 ArchEnableHwIrq(uint32 irq_num) { + EnableIRQ(irq_num); return EOK; } int32 ArchDisableHwIrq(uint32 irq_num) { + DisableIRQ(irq_num); return EOK; } diff --git a/Ubiquitous/XiZi/board/xidatong/board.c b/Ubiquitous/XiZi/board/xidatong/board.c index 7ebe5f7f4..014925cd8 100644 --- a/Ubiquitous/XiZi/board/xidatong/board.c +++ b/Ubiquitous/XiZi/board/xidatong/board.c @@ -44,6 +44,10 @@ Modification: #include #endif +#ifdef BSP_USING_I2C +#include +#endif + #ifdef BSP_USING_CH438 #include #endif @@ -71,6 +75,10 @@ extern int ETH_BSP_Config(); extern int Imxrt1052HwLcdInit(void); #endif +#ifdef BSP_USING_TOUCH +extern int HwTouchInit(); +#endif + void BOARD_SD_Pin_Config(uint32_t speed, uint32_t strength) { IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, @@ -281,29 +289,56 @@ void SysTick_Handler(int irqn, void *arg) } DECLARE_HW_IRQ(SYSTICK_IRQN, SysTick_Handler, NONE); +struct InitSequenceDesc _board_init[] = +{ +#ifdef BSP_USING_GPIO + { "hw_pin", Imxrt1052HwGpioInit }, +#endif +#ifdef BSP_USING_CH438 + {"ch438", Imxrt1052HwCh438Init()}, +#endif + +#ifdef BSP_USING_SDIO + { "sdio", Imxrt1052HwSdioInit }, +#endif + +#ifdef BSP_USING_I2C + { "hw_i2c", Imxrt1052HwI2cInit }, +#endif + +#ifdef BSP_USING_LCD + { "hw_lcd", Imxrt1052HwLcdInit }, +#endif + +#ifdef BSP_USING_TOUCH + {"touch", HwTouchInit }, +#endif + +#ifdef BSP_USING_LWIP + {"ETH_BSP", ETH_BSP_Config}, +#endif + +#ifdef BSP_USING_WDT + { "hw_wdt", Imxrt1052HwWdgInit }, +#endif + { " NONE ",NONE }, +}; /** * This function will initial imxrt1050 board. */ void InitBoardHardware() { + int i = 0; + int ret = 0; + BOARD_ConfigMPU(); BOARD_InitPins(); BOARD_BootClockRUN(); -#ifndef BSP_USING_LWIP NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); SysTick_Config(SystemCoreClock / TICK_PER_SECOND); -#endif - -#ifdef BSP_USING_GPIO - Imxrt1052HwGpioInit(); -#endif - -#ifdef BSP_USING_LPUART - BOARD_InitUartPins(); -#endif InitBoardMemory((void *)HEAP_BEGIN, (void *)HEAP_END); @@ -323,29 +358,19 @@ void InitBoardHardware() #endif #endif -#ifdef BSP_USING_LWIP - ETH_BSP_Config(); -#endif - #ifdef BSP_USING_LPUART Imxrt1052HwUartInit(); #endif InstallConsole(KERNEL_CONSOLE_BUS_NAME, KERNEL_CONSOLE_DRV_NAME, KERNEL_CONSOLE_DEVICE_NAME); + KPrintf("\nconsole init completed.\n"); + KPrintf("board initialization......\n"); -#ifdef BSP_USING_CH438 - Imxrt1052HwCh438Init(); -#endif - -#ifdef BSP_USING_SDIO - Imxrt1052HwSdioInit(); -#endif - -#ifdef BSP_USING_LCD - Imxrt1052HwLcdInit(); -#endif -#ifdef BSP_USING_WDT - Imxrt1052HwWdgInit(); -#endif + for(i = 0; _board_init[i].fn != NONE; i++) { + ret = _board_init[i].fn(); + KPrintf("initialize %s %s\n",_board_init[i].fn_name, ret == 0 ? "success" : "failed"); + } + KPrintf("board init done.\n"); + KPrintf("start kernel...\n"); } diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig index 99e1ee6cc..223f5e966 100644 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig @@ -20,6 +20,15 @@ menuconfig BSP_USING_GPIO if BSP_USING_GPIO source "$BSP_DIR/third_party_driver/gpio/Kconfig" endif + +menuconfig BSP_USING_I2C + bool "Using I2C device" + default n + select RESOURCES_I2C + + if BSP_USING_I2C + source "$BSP_DIR/third_party_driver/i2c/Kconfig" + endif menuconfig BSP_USING_LWIP bool "Using LwIP device" @@ -47,6 +56,16 @@ menuconfig BSP_USING_LCD if BSP_USING_LCD source "$BSP_DIR/third_party_driver/lcd/Kconfig" endif +menuconfig BSP_USING_TOUCH + bool "Using TOUCH device" + default n + select RESOURCES_TOUCH + select BSP_USING_I2C + select BSP_USING_LCD + if BSP_USING_TOUCH + source "$BSP_DIR/third_party_driver/touch/Kconfig" + endif + menuconfig BSP_USING_USB bool "Using USB device" default n diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile index ab1ae8282..e7c289a05 100644 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile @@ -7,6 +7,9 @@ endif ifeq ($(CONFIG_BSP_USING_SEMC),y) SRC_DIR += semc endif +ifeq ($(CONFIG_BSP_USING_I2C),y) + SRC_DIR += i2c +endif ifeq ($(CONFIG_BSP_USING_LPUART),y) SRC_DIR += uart @@ -27,6 +30,11 @@ endif ifeq ($(CONFIG_BSP_USING_LCD),y) SRC_DIR += lcd endif + +ifeq ($(CONFIG_BSP_USING_TOUCH),y) + SRC_DIR += touch +endif + ifeq ($(CONFIG_BSP_USING_WDT),y) SRC_DIR += wdt endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/common/pin_mux.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/common/pin_mux.c index b34d446be..25904e9c0 100755 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/common/pin_mux.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/common/pin_mux.c @@ -1018,6 +1018,84 @@ void Lcd_InitPins(void) Pull Up / Down Config. Field: 100K Ohm Pull Down Hyst. Enable Field: Hysteresis Disabled */ } + +void BOARD_InitI2C1Pins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 is configured as LPI2C1_SCL */ + 1U); /* Software Input On Field: Force input path of pad GPIO_AD_B1_00 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 is configured as LPI2C1_SDA */ + 1U); /* Software Input On Field: Force input path of pad GPIO_AD_B1_01 */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 PAD functional properties : */ + 0xD8B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Enabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 22K Ohm Pull Up + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 PAD functional properties : */ + 0xD8B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Enabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 22K Ohm Pull Up + Hyst. Enable Field: Hysteresis Disabled */ +} + +void BOARD_InitUartPins(void) +{ +#ifdef BSP_USING_LPUART1 + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ +#endif +#ifdef BSP_USING_LPUART2 + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_02_LPUART2_TX, + 0U); + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_03_LPUART2_RX, + 0U); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_02_LPUART2_TX, + 0x10B0u); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_03_LPUART2_RX, + 0x10B0u); +#endif +} + /* FUNCTION ************************************************************************************************************ * * Function Name : BOARD_InitPins @@ -1029,7 +1107,19 @@ void BOARD_InitPins(void) CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ /* Software Input On Field: Input Path is determined by functionality */ SemcPinmuxConfig(); + +#ifdef BSP_USING_LPUART + BOARD_InitUartPins(); +#endif + +#ifdef BSP_USING_LCD Lcd_InitPins(); +#endif + +#ifdef BSP_USING_I2C + BOARD_InitI2C1Pins(); +#endif + IOMUXC_SetPinMux( IOMUXC_GPIO_AD_B0_03_GPIO1_IO03, /* GPIO_AD_B0_09 is configured as GPIO1_IO09 */ 0U); /* Software Input On Field: Input Path is determined by functionality */ @@ -1227,51 +1317,7 @@ void BOARD_InitPins(void) Hyst. Enable Field: Hysteresis Disabled */ } -void BOARD_InitUartPins(void) -{ -#ifdef BSP_USING_LPUART1 - IOMUXC_SetPinMux( - IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinMux( - IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinConfig( - IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */ - 0x10B0u); /* Slew Rate Field: Slow Slew Rate - Drive Strength Field: R0/6 - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Keeper - Pull Up / Down Config. Field: 100K Ohm Pull Down - Hyst. Enable Field: Hysteresis Disabled */ - IOMUXC_SetPinConfig( - IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */ - 0x10B0u); /* Slew Rate Field: Slow Slew Rate - Drive Strength Field: R0/6 - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Keeper - Pull Up / Down Config. Field: 100K Ohm Pull Down - Hyst. Enable Field: Hysteresis Disabled */ -#endif -#ifdef BSP_USING_LPUART2 - IOMUXC_SetPinMux( - IOMUXC_GPIO_AD_B1_02_LPUART2_TX, - 0U); - IOMUXC_SetPinMux( - IOMUXC_GPIO_AD_B1_03_LPUART2_RX, - 0U); - IOMUXC_SetPinConfig( - IOMUXC_GPIO_AD_B1_02_LPUART2_TX, - 0x10B0u); - IOMUXC_SetPinConfig( - IOMUXC_GPIO_AD_B1_03_LPUART2_RX, - 0x10B0u); -#endif -} + /*********************************************************************************************************************** * EOF diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c index d04c8adb3..6360d9911 100755 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c @@ -99,7 +99,6 @@ void ethernetif_clk_init(void) { const clock_enet_pll_config_t config = {.enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1}; CLOCK_InitEnetPll(&config); - SysTick_Config(USEC_TO_COUNT(1000U, CLOCK_GetFreq(kCLOCK_CoreSysClk))); } void ethernetif_gpio_init(void) diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/Kconfig b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/Kconfig new file mode 100755 index 000000000..ddc59900d --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/Kconfig @@ -0,0 +1,12 @@ +if BSP_USING_I2C + config I2C_BUS_NAME_1 + string "i2c bus 1 name" + default "i2c1" + config I2C_DRV_NAME_1 + string "i2c bus 1 driver name" + default "i2c1_drv" + config I2C_1_DEVICE_NAME_0 + string "i2c bus 1 device 0 name" + default "i2c1_dev0" +endif + diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/Makefile new file mode 100755 index 000000000..e99bb9e03 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_i2c.c hardware_i2c.c fsl_lpi2c.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/connect_i2c.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/connect_i2c.c new file mode 100755 index 000000000..85d6672fc --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/connect_i2c.c @@ -0,0 +1,179 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_i2c.c +* @brief support ok1052-c board i2c function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2022-03-01 +*/ + +#include +#include "bus_serial.h" +#include "connect_i2c.h" +#include "fsl_lpi2c.h" + +static uint32 I2cWriteData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) +{ + status_t ret; + Stm32I2cType *param = (Stm32I2cType *)i2c_dev->haldev.private_data; + ret = I2cHardwareWrite(param->base, param->slave_addr, param->sub_addr, msg->buf, msg->len); + if(kStatus_Success == ret) + return 1; + return 0; +} + +static uint32 I2cReadData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) +{ + status_t ret; + Stm32I2cType *param = (Stm32I2cType *)i2c_dev->haldev.private_data; + ret = I2cHardwareRead(param->base, i2c_dev->i2c_dev_addr, param->sub_addr, msg->buf, msg->len); + if(kStatus_Success == ret) + return 1; + return 0; +} + +static uint32 I2cInit(struct I2cDriver *i2c_drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(i2c_drv); + + struct I2cHardwareDevice *i2c_dev = (struct I2cHardwareDevice *)i2c_drv->driver.owner_bus->owner_haldev; + + if (configure_info->private_data) { + i2c_dev->i2c_dev_addr = *((uint16 *)configure_info->private_data); + return EOK; + } + + i2c_print("I2cInit need set i2c dev addr\n"); + return ERROR; +} + +static uint32 I2cDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct I2cDriver *i2c_drv = (struct I2cDriver *)drv; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = I2cInit(i2c_drv, configure_info); + break; + default: + break; + } + + return ret; +} + +/*manage the i2c device operations*/ +static const struct I2cDevDone i2c_dev_done = +{ + .dev_open = NONE, + .dev_close = NONE, + .dev_write = I2cWriteData, + .dev_read = I2cReadData, +}; + +/*Init i2c bus*/ +static int BoardI2cBusInit(struct I2cBus *i2c_bus, struct I2cDriver *i2c_driver) +{ + x_err_t ret = EOK; + + /*Init the i2c bus */ + i2c_bus->private_data = (void *)NULL; + ret = I2cBusInit(i2c_bus, I2C_BUS_NAME_1); + if (EOK != ret) { + i2c_print("BoardI2cBusInit I2cBusInit error %d\n", ret); + return ERROR; + } + + /*Init the i2c driver*/ + i2c_driver->private_data = (void *)NULL; + ret = I2cDriverInit(i2c_driver, I2C_DRV_NAME_1); + if (EOK != ret) { + i2c_print("BoardI2cBusInit I2cDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the i2c driver to the i2c bus*/ + ret = I2cDriverAttachToBus(I2C_DRV_NAME_1, I2C_BUS_NAME_1); + if (EOK != ret) { + i2c_print("BoardI2cBusInit I2cDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the i2c device to the i2c bus*/ +static int BoardI2cDevBend(void) +{ + x_err_t ret = EOK; + static struct I2cHardwareDevice i2c_device0; + memset(&i2c_device0, 0, sizeof(struct I2cHardwareDevice)); + + i2c_device0.i2c_dev_done = &i2c_dev_done; + + ret = I2cDeviceRegister(&i2c_device0, NONE, I2C_1_DEVICE_NAME_0); + if (EOK != ret) { + i2c_print("BoardI2cDevBend I2cDeviceInit device %s error %d\n", I2C_1_DEVICE_NAME_0, ret); + return ERROR; + } + + ret = I2cDeviceAttachToBus(I2C_1_DEVICE_NAME_0, I2C_BUS_NAME_1); + if (EOK != ret) { + i2c_print("BoardI2cDevBend I2cDeviceAttachToBus device %s error %d\n", I2C_1_DEVICE_NAME_0, ret); + return ERROR; + } + + return ret; +} + +/*BOARD I2C INIT*/ +int Imxrt1052HwI2cInit(void) +{ + static int init_flag = 0; + x_err_t ret = EOK; + + if(init_flag) + { + return ret; + } + init_flag = 1; + + static struct I2cBus i2c_bus; + memset(&i2c_bus, 0, sizeof(struct I2cBus)); + static struct I2cDriver i2c_driver; + memset(&i2c_driver, 0, sizeof(struct I2cDriver)); + +#ifdef BSP_USING_I2C + i2c_driver.configure = I2cDrvConfigure; + + ret = BoardI2cBusInit(&i2c_bus, &i2c_driver); + if (EOK != ret) { + i2c_print("board_i2c_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardI2cDevBend(); + if (EOK != ret) { + i2c_print("board_i2c_Init error ret %u\n", ret); + return ERROR; + } +#endif + + return ret; +} diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/connect_i2c_eeprom.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/connect_i2c_eeprom.c new file mode 100755 index 000000000..792a19273 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/connect_i2c_eeprom.c @@ -0,0 +1,76 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_i2c_eeprom.h +* @brief ok1052-c board eeprom relative codes +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2022-03-01 +*/ + +#include "board.h" +#include "connect_i2c.h" +#include "fsl_lpi2c.h" +#include "pin_mux.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define I2C_EEPROM_BASE LPI2C1 +#define I2C_EEPROM_ADDR (0xA0 >> 1) + +/******************************************************************************* + * Code + ******************************************************************************/ + +void I2cEEpromTestWrite(void) +{ + uint8_t dat[8] = {0}; + + if(I2cHardwareRead(I2C_EEPROM_BASE, I2C_EEPROM_ADDR, 0, dat, 8) == kStatus_Success) + { + i2c_print("Read from EEPROM %d %d %d %d %d %d %d %d\r\n", + dat[0], dat[1], dat[2], dat[3], dat[4], dat[5], dat[6], dat[7]); + } + + for(uint8_t i = 0; i < 8; i++) + { + dat[i] ++; + } + + if(I2cHardwareWrite(I2C_EEPROM_BASE, I2C_EEPROM_ADDR, 0, dat, 8) == kStatus_Success) + { + i2c_print("Write to EEPROM %d %d %d %d %d %d %d %d\r\n", + dat[0], dat[1], dat[2], dat[3], dat[4], dat[5], dat[6], dat[7]); + } + + memset(dat, 0, 8); + if(I2cHardwareRead(I2C_EEPROM_BASE, I2C_EEPROM_ADDR, 0, dat, 8) == kStatus_Success) + { + i2c_print("Read from EEPROM %d %d %d %d %d %d %d %d\r\n", + dat[0], dat[1], dat[2], dat[3], dat[4], dat[5], dat[6], dat[7]); + } +} + +int I2cEEpromTest(void) +{ + BOARD_InitI2C1Pins(); + I2cHardwareInit(); + I2cEEpromTestWrite(); + return 0; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)| SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)| SHELL_CMD_PARAM_NUM(0), + eeprom, I2cEEpromTest, test i2c eeprom); + diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/fsl_lpi2c.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/fsl_lpi2c.c new file mode 100755 index 000000000..3360b90ce --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/fsl_lpi2c.c @@ -0,0 +1,2247 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_lpi2c.h" +#include +#include +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.lpi2c" +#endif + +/*! @brief Common sets of flags used by the driver. */ +enum _lpi2c_flag_constants +{ + /*! All flags which are cleared by the driver upon starting a transfer. */ + kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | + kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag | + kLPI2C_MasterDataMatchFlag, + + /*! IRQ sources enabled by the non-blocking transactional API. */ + kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag | + kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag | + kLPI2C_MasterFifoErrFlag, + + /*! Errors to check for. */ + kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | + kLPI2C_MasterPinLowTimeoutFlag, + + /*! All flags which are cleared by the driver upon starting a transfer. */ + kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag | + kLPI2C_SlaveFifoErrFlag, + + /*! IRQ sources enabled by the non-blocking transactional API. */ + kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | + kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag | + kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag, + + /*! Errors to check for. */ + kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag, +}; + +/* ! @brief LPI2C master fifo commands. */ +enum _lpi2c_master_fifo_cmd +{ + kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */ + kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */ + kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */ + kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */ +}; + +/*! + * @brief Default watermark values. + * + * The default watermarks are set to zero. + */ +enum _lpi2c_default_watermarks +{ + kDefaultTxWatermark = 0, + kDefaultRxWatermark = 0, +}; + +/*! @brief States for the state machine used by transactional APIs. */ +enum _lpi2c_transfer_states +{ + kIdleState = 0, + kSendCommandState, + kIssueReadCommandState, + kTransferDataState, + kStopState, + kWaitForCompletionState, +}; + +/*! @brief Typedef for master interrupt handler. */ +typedef void (*lpi2c_master_isr_t)(LPI2C_Type *base, lpi2c_master_handle_t *handle); + +/*! @brief Typedef for slave interrupt handler. */ +typedef void (*lpi2c_slave_isr_t)(LPI2C_Type *base, lpi2c_slave_handle_t *handle); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +uint32_t LPI2C_GetInstance(LPI2C_Type *base); + +static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz, + uint32_t width_ns, + uint32_t maxCycles, + uint32_t prescaler); + +static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base); + +static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone); + +static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle); + +static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags); + +static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Array to map LPI2C instance number to base pointer. */ +static LPI2C_Type *const kLpi2cBases[] = LPI2C_BASE_PTRS; + +/*! @brief Array to map LPI2C instance number to IRQ number. */ +static IRQn_Type const kLpi2cIrqs[] = LPI2C_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Array to map LPI2C instance number to clock gate enum. */ +static clock_ip_name_t const kLpi2cClocks[] = LPI2C_CLOCKS; + +#if defined(LPI2C_PERIPH_CLOCKS) +/*! @brief Array to map LPI2C instance number to pheripheral clock gate enum. */ +static const clock_ip_name_t kLpi2cPeriphClocks[] = LPI2C_PERIPH_CLOCKS; +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointer to master IRQ handler for each instance. */ +static lpi2c_master_isr_t s_lpi2cMasterIsr; + +/*! @brief Pointers to master handles for each instance. */ +static lpi2c_master_handle_t *s_lpi2cMasterHandle[ARRAY_SIZE(kLpi2cBases)]; + +/*! @brief Pointer to slave IRQ handler for each instance. */ +static lpi2c_slave_isr_t s_lpi2cSlaveIsr; + +/*! @brief Pointers to slave handles for each instance. */ +static lpi2c_slave_handle_t *s_lpi2cSlaveHandle[ARRAY_SIZE(kLpi2cBases)]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Returns an instance number given a base address. + * + * If an invalid base address is passed, debug builds will assert. Release builds will just return + * instance number 0. + * + * @param base The LPI2C peripheral base address. + * @return LPI2C instance number starting from 0. + */ +uint32_t LPI2C_GetInstance(LPI2C_Type *base) +{ + uint32_t instance; + for (instance = 0; instance < ARRAY_SIZE(kLpi2cBases); ++instance) + { + if (kLpi2cBases[instance] == base) + { + return instance; + } + } + + assert(false); + return 0; +} + +/*! + * @brief Computes a cycle count for a given time in nanoseconds. + * @param sourceClock_Hz LPI2C functional clock frequency in Hertz. + * @param width_ns Desired with in nanoseconds. + * @param maxCycles Maximum cycle count, determined by the number of bits wide the cycle count field is. + * @param prescaler LPI2C prescaler setting. Pass 1 if the prescaler should not be used, as for slave glitch widths. + */ +static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz, + uint32_t width_ns, + uint32_t maxCycles, + uint32_t prescaler) +{ + assert(sourceClock_Hz > 0); + assert(prescaler > 0); + + uint32_t busCycle_ns = 1000000 / (sourceClock_Hz / prescaler / 1000); + uint32_t cycles = 0; + + /* Search for the cycle count just below the desired glitch width. */ + while ((((cycles + 1) * busCycle_ns) < width_ns) && (cycles + 1 < maxCycles)) + { + ++cycles; + } + + /* If we end up with zero cycles, then set the filter to a single cycle unless the */ + /* bus clock is greater than 10x the desired glitch width. */ + if ((cycles == 0) && (busCycle_ns <= (width_ns * 10))) + { + cycles = 1; + } + + return cycles; +} + +/*! + * @brief Convert provided flags to status code, and clear any errors if present. + * @param base The LPI2C peripheral base address. + * @param status Current status flags value that will be checked. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_PinLowTimeout + * @retval #kStatus_LPI2C_ArbitrationLost + * @retval #kStatus_LPI2C_Nak + * @retval #kStatus_LPI2C_FifoError + */ +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status) +{ + status_t result = kStatus_Success; + + /* Check for error. These errors cause a stop to automatically be sent. We must */ + /* clear the errors before a new transfer can start. */ + status &= kMasterErrorFlags; + if (status) + { + /* Select the correct error code. Ordered by severity, with bus issues first. */ + if (status & kLPI2C_MasterPinLowTimeoutFlag) + { + result = kStatus_LPI2C_PinLowTimeout; + } + else if (status & kLPI2C_MasterArbitrationLostFlag) + { + result = kStatus_LPI2C_ArbitrationLost; + } + else if (status & kLPI2C_MasterNackDetectFlag) + { + result = kStatus_LPI2C_Nak; + } + else if (status & kLPI2C_MasterFifoErrFlag) + { + result = kStatus_LPI2C_FifoError; + } + else + { + assert(false); + } + + /* Clear the flags. */ + LPI2C_MasterClearStatusFlags(base, status); + + /* Reset fifos. These flags clear automatically. */ + base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; + } + + return result; +} + +/*! + * @brief Wait until there is room in the tx fifo. + * @param base The LPI2C peripheral base address. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_PinLowTimeout + * @retval #kStatus_LPI2C_ArbitrationLost + * @retval #kStatus_LPI2C_Nak + * @retval #kStatus_LPI2C_FifoError + */ +static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base) +{ + uint32_t status; + size_t txCount; + size_t txFifoSize = FSL_FEATURE_LPI2C_FIFO_SIZEn(base); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + do + { + status_t result; + + /* Get the number of words in the tx fifo and compute empty slots. */ + LPI2C_MasterGetFifoCounts(base, NULL, &txCount); + txCount = txFifoSize - txCount; + + /* Check for error flags. */ + status = LPI2C_MasterGetStatusFlags(base); + result = LPI2C_MasterCheckAndClearError(base, status); + if (result) + { + return result; + } +#if LPI2C_WAIT_TIMEOUT + } while ((!txCount) && (--waitTimes)); + + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while (!txCount); +#endif + + return kStatus_Success; +} + +/*! + * @brief Make sure the bus isn't already busy. + * + * A busy bus is allowed if we are the one driving it. + * + * @param base The LPI2C peripheral base address. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_Busy + */ +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +status_t LPI2C_CheckForBusyBus(LPI2C_Type *base) +{ + uint32_t status = LPI2C_MasterGetStatusFlags(base); + if ((status & kLPI2C_MasterBusBusyFlag) && (!(status & kLPI2C_MasterBusyFlag))) + { + return kStatus_LPI2C_Busy; + } + + return kStatus_Success; +} + +/*! + * brief Provides a default configuration for the LPI2C master peripheral. + * + * This function provides the following default configuration for the LPI2C master peripheral: + * code + * masterConfig->enableMaster = true; + * masterConfig->debugEnable = false; + * masterConfig->ignoreAck = false; + * masterConfig->pinConfig = kLPI2C_2PinOpenDrain; + * masterConfig->baudRate_Hz = 100000U; + * masterConfig->busIdleTimeout_ns = 0; + * masterConfig->pinLowTimeout_ns = 0; + * masterConfig->sdaGlitchFilterWidth_ns = 0; + * masterConfig->sclGlitchFilterWidth_ns = 0; + * masterConfig->hostRequest.enable = false; + * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; + * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; + * endcode + * + * After calling this function, you can override any settings in order to customize the configuration, + * prior to initializing the master driver with LPI2C_MasterInit(). + * + * param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t. + */ +void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig) +{ + /* Initializes the configure structure to zero. */ + memset(masterConfig, 0, sizeof(*masterConfig)); + + masterConfig->enableMaster = true; + masterConfig->debugEnable = false; + masterConfig->enableDoze = true; + masterConfig->ignoreAck = false; + masterConfig->pinConfig = kLPI2C_2PinOpenDrain; + masterConfig->baudRate_Hz = 100000U; + masterConfig->busIdleTimeout_ns = 0; + masterConfig->pinLowTimeout_ns = 0; + masterConfig->sdaGlitchFilterWidth_ns = 0; + masterConfig->sclGlitchFilterWidth_ns = 0; + masterConfig->hostRequest.enable = false; + masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; + masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; +} + +/*! + * brief Initializes the LPI2C master peripheral. + * + * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user + * provided configuration. A software reset is performed prior to configuration. + * + * param base The LPI2C peripheral base address. + * param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of + * defaults + * that you can override. + * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors, + * filter widths, and timeout periods. + */ +void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz) +{ + uint32_t prescaler; + uint32_t cycles; + uint32_t cfgr2; + uint32_t value; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Ungate the clock. */ + CLOCK_EnableClock(kLpi2cClocks[instance]); +#if defined(LPI2C_PERIPH_CLOCKS) + /* Ungate the functional clock in initialize function. */ + CLOCK_EnableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset peripheral before configuring it. */ + LPI2C_MasterReset(base); + + /* Doze bit: 0 is enable, 1 is disable */ + base->MCR = LPI2C_MCR_DBGEN(masterConfig->debugEnable) | LPI2C_MCR_DOZEN(!(masterConfig->enableDoze)); + + /* host request */ + value = base->MCFGR0; + value &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK | LPI2C_MCFGR0_HRSEL_MASK)); + value |= LPI2C_MCFGR0_HREN(masterConfig->hostRequest.enable) | + LPI2C_MCFGR0_HRPOL(masterConfig->hostRequest.polarity) | + LPI2C_MCFGR0_HRSEL(masterConfig->hostRequest.source); + base->MCFGR0 = value; + + /* pin config and ignore ack */ + value = base->MCFGR1; + value &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK); + value |= LPI2C_MCFGR1_PINCFG(masterConfig->pinConfig); + value |= LPI2C_MCFGR1_IGNACK(masterConfig->ignoreAck); + base->MCFGR1 = value; + + LPI2C_MasterSetWatermarks(base, kDefaultTxWatermark, kDefaultRxWatermark); + + LPI2C_MasterSetBaudRate(base, sourceClock_Hz, masterConfig->baudRate_Hz); + + /* Configure glitch filters and bus idle and pin low timeouts. */ + prescaler = (base->MCFGR1 & LPI2C_MCFGR1_PRESCALE_MASK) >> LPI2C_MCFGR1_PRESCALE_SHIFT; + cfgr2 = base->MCFGR2; + if (masterConfig->busIdleTimeout_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->busIdleTimeout_ns, + (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler); + cfgr2 &= ~LPI2C_MCFGR2_BUSIDLE_MASK; + cfgr2 |= LPI2C_MCFGR2_BUSIDLE(cycles); + } + if (masterConfig->sdaGlitchFilterWidth_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sdaGlitchFilterWidth_ns, + (LPI2C_MCFGR2_FILTSDA_MASK >> LPI2C_MCFGR2_FILTSDA_SHIFT), 1); + cfgr2 &= ~LPI2C_MCFGR2_FILTSDA_MASK; + cfgr2 |= LPI2C_MCFGR2_FILTSDA(cycles); + } + if (masterConfig->sclGlitchFilterWidth_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sclGlitchFilterWidth_ns, + (LPI2C_MCFGR2_FILTSCL_MASK >> LPI2C_MCFGR2_FILTSCL_SHIFT), 1); + cfgr2 &= ~LPI2C_MCFGR2_FILTSCL_MASK; + cfgr2 |= LPI2C_MCFGR2_FILTSCL(cycles); + } + base->MCFGR2 = cfgr2; + if (masterConfig->pinLowTimeout_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->pinLowTimeout_ns / 256, + (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler); + base->MCFGR3 = (base->MCFGR3 & ~LPI2C_MCFGR3_PINLOW_MASK) | LPI2C_MCFGR3_PINLOW(cycles); + } + + LPI2C_MasterEnable(base, masterConfig->enableMaster); +} + +/*! + * brief Deinitializes the LPI2C master peripheral. + * + * This function disables the LPI2C master peripheral and gates the clock. It also performs a software + * reset to restore the peripheral to reset conditions. + * + * param base The LPI2C peripheral base address. + */ +void LPI2C_MasterDeinit(LPI2C_Type *base) +{ + /* Restore to reset state. */ + LPI2C_MasterReset(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Gate clock. */ + CLOCK_DisableClock(kLpi2cClocks[instance]); +#if defined(LPI2C_PERIPH_CLOCKS) + /* Gate the functional clock. */ + CLOCK_DisableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Configures LPI2C master data match feature. + * + * param base The LPI2C peripheral base address. + * param config Settings for the data match feature. + */ +void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *config) +{ + /* Disable master mode. */ + bool wasEnabled = (base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT; + LPI2C_MasterEnable(base, false); + + base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_MATCFG_MASK) | LPI2C_MCFGR1_MATCFG(config->matchMode); + base->MCFGR0 = (base->MCFGR0 & ~LPI2C_MCFGR0_RDMO_MASK) | LPI2C_MCFGR0_RDMO(config->rxDataMatchOnly); + base->MDMR = LPI2C_MDMR_MATCH0(config->match0) | LPI2C_MDMR_MATCH1(config->match1); + + /* Restore master mode. */ + if (wasEnabled) + { + LPI2C_MasterEnable(base, true); + } +} + +/*! + * brief Sets the I2C bus frequency for master transactions. + * + * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud + * rate. Do not call this function during a transfer, or the transfer is aborted. + * + * note Please note that the second parameter is the clock frequency of LPI2C module, the third + * parameter means user configured bus baudrate, this implementation is different from other I2C drivers + * which use baudrate configuration as second parameter and source clock frequency as third parameter. + * + * param base The LPI2C peripheral base address. + * param sourceClock_Hz LPI2C functional clock frequency in Hertz. + * param baudRate_Hz Requested bus frequency in Hertz. + */ +void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz) +{ + uint32_t prescale = 0; + uint32_t bestPre = 0; + uint32_t bestClkHi = 0; + uint32_t absError = 0; + uint32_t bestError = 0xffffffffu; + uint32_t value; + uint32_t clkHiCycle; + uint32_t computedRate; + int i; + bool wasEnabled; + + /* Disable master mode. */ + wasEnabled = (base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT; + LPI2C_MasterEnable(base, false); + + /* Baud rate = (sourceClock_Hz/2^prescale)/(CLKLO+1+CLKHI+1 + ROUNDDOWN((2+FILTSCL)/2^prescale) */ + /* Assume CLKLO = 2*CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2. */ + for (prescale = 1; (prescale <= 128) && (bestError != 0); prescale = 2 * prescale) + { + for (clkHiCycle = 1; clkHiCycle < 32; clkHiCycle++) + { + if (clkHiCycle == 1) + { + computedRate = (sourceClock_Hz / prescale) / (1 + 3 + 2 + 2 / prescale); + } + else + { + computedRate = (sourceClock_Hz / prescale) / (3 * clkHiCycle + 2 + 2 / prescale); + } + + absError = baudRate_Hz > computedRate ? baudRate_Hz - computedRate : computedRate - baudRate_Hz; + + if (absError < bestError) + { + bestPre = prescale; + bestClkHi = clkHiCycle; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0) + { + break; + } + } + } + } + + /* Standard, fast, fast mode plus and ultra-fast transfers. */ + value = LPI2C_MCCR0_CLKHI(bestClkHi); + + if (bestClkHi < 2) + { + value |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1); + } + else + { + value |= LPI2C_MCCR0_CLKLO(2 * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2); + } + + base->MCCR0 = value; + + for (i = 0; i < 8; i++) + { + if (bestPre == (1U << i)) + { + bestPre = i; + break; + } + } + base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) | LPI2C_MCFGR1_PRESCALE(bestPre); + + /* Restore master mode. */ + if (wasEnabled) + { + LPI2C_MasterEnable(base, true); + } +} + +/*! + * brief Sends a START signal and slave address on the I2C bus. + * + * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure + * that another master is not occupying the bus. Then a START signal is transmitted, followed by the + * 7-bit address specified in the a address parameter. Note that this function does not actually wait + * until the START and address are successfully sent on the bus before returning. + * + * param base The LPI2C peripheral base address. + * param address 7-bit slave device address, in bits [6:0]. + * param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set + * the R/w bit (bit 0) in the transmitted slave address. + * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + */ +status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir) +{ + /* Return an error if the bus is already in use not by us. */ + status_t result = LPI2C_CheckForBusyBus(base); + if (result) + { + return result; + } + + /* Clear all flags. */ + LPI2C_MasterClearStatusFlags(base, kMasterClearFlags); + + /* Turn off auto-stop option. */ + base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; + + /* Wait until there is room in the fifo. */ + result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Issue start command. */ + base->MTDR = kStartCmd | (((uint32_t)address << 1U) | (uint32_t)dir); + + return kStatus_Success; +} + +/*! + * brief Sends a STOP signal on the I2C bus. + * + * This function does not return until the STOP signal is seen on the bus, or an error occurs. + * + * param base The LPI2C peripheral base address. + * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterStop(LPI2C_Type *base) +{ + /* Wait until there is room in the fifo. */ + status_t result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Send the STOP signal */ + base->MTDR = kStopCmd; + +/* Wait for the stop detected flag to set, indicating the transfer has completed on the bus. */ +/* Also check for errors while waiting. */ +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + +#if LPI2C_WAIT_TIMEOUT + while ((result == kStatus_Success) && (--waitTimes)) +#else + while (result == kStatus_Success) +#endif + { + uint32_t status = LPI2C_MasterGetStatusFlags(base); + + /* Check for error flags. */ + result = LPI2C_MasterCheckAndClearError(base, status); + + /* Check if the stop was sent successfully. */ + if ((status & kLPI2C_MasterStopDetectFlag) && (status & kLPI2C_MasterTxReadyFlag)) + { + LPI2C_MasterClearStatusFlags(base, kLPI2C_MasterStopDetectFlag); + break; + } + } + +#if LPI2C_WAIT_TIMEOUT + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#endif + + return result; +} + +/*! + * brief Performs a polling receive transfer on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param rxBuff The pointer to the data to be transferred. + * param rxSize The length in bytes of the data to be transferred. + * retval #kStatus_Success Data was received successfully. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize) +{ + status_t result; + uint8_t *buf; + + assert(rxBuff); + + /* Handle empty read. */ + if (!rxSize) + { + return kStatus_Success; + } + + /* Wait until there is room in the command fifo. */ + result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Issue command to receive data. */ + base->MTDR = kRxDataCmd | LPI2C_MTDR_DATA(rxSize - 1); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + + /* Receive data */ + buf = (uint8_t *)rxBuff; + while (rxSize--) + { + /* Read LPI2C receive fifo register. The register includes a flag to indicate whether */ + /* the FIFO is empty, so we can both get the data and check if we need to keep reading */ + /* using a single register read. */ + uint32_t value; + do + { + /* Check for errors. */ + result = LPI2C_MasterCheckAndClearError(base, LPI2C_MasterGetStatusFlags(base)); + if (result) + { + return result; + } + + value = base->MRDR; +#if LPI2C_WAIT_TIMEOUT + } while ((value & LPI2C_MRDR_RXEMPTY_MASK) && (--waitTimes)); + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while (value & LPI2C_MRDR_RXEMPTY_MASK); +#endif + + *buf++ = value & LPI2C_MRDR_DATA_MASK; + } + + return kStatus_Success; +} + +/*! + * brief Performs a polling send transfer on the I2C bus. + * + * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may + * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this + * function returns #kStatus_LPI2C_Nak. + * + * param base The LPI2C peripheral base address. + * param txBuff The pointer to the data to be transferred. + * param txSize The length in bytes of the data to be transferred. + * retval #kStatus_Success Data was sent successfully. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or over run. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize) +{ + uint8_t *buf = (uint8_t *)txBuff; + + assert(txBuff); + + /* Send data buffer */ + while (txSize--) + { + /* Wait until there is room in the fifo. This also checks for errors. */ + status_t result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Write byte into LPI2C master data register. */ + base->MTDR = *buf++; + } + + return kStatus_Success; +} + +/*! + * brief Performs a master polling transfer on the I2C bus. + * + * note The API does not return until the transfer succeeds or fails due + * to error happens during transfer. + * + * param base The LPI2C peripheral base address. + * param transfer Pointer to the transfer structure. + * retval #kStatus_Success Data was received successfully. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer) +{ + status_t result = kStatus_Success; + uint16_t commandBuffer[7]; + uint32_t cmdCount = 0; + + assert(transfer); + assert(transfer->subaddressSize <= sizeof(transfer->subaddress)); + + /* Return an error if the bus is already in use not by us. */ + result = LPI2C_CheckForBusyBus(base); + if (result) + { + return result; + } + + /* Clear all flags. */ + LPI2C_MasterClearStatusFlags(base, kMasterClearFlags); + + /* Turn off auto-stop option. */ + base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; + + lpi2c_direction_t direction = transfer->subaddressSize ? kLPI2C_Write : transfer->direction; + if (!(transfer->flags & kLPI2C_TransferNoStartFlag)) + { + commandBuffer[cmdCount++] = + (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)direction); + } + + /* Subaddress, MSB first. */ + if (transfer->subaddressSize) + { + uint32_t subaddressRemaining = transfer->subaddressSize; + while (subaddressRemaining--) + { + uint8_t subaddressByte = (transfer->subaddress >> (8 * subaddressRemaining)) & 0xff; + commandBuffer[cmdCount++] = subaddressByte; + } + } + + /* Reads need special handling. */ + if ((transfer->dataSize) && (transfer->direction == kLPI2C_Read)) + { + /* Need to send repeated start if switching directions to read. */ + if (direction == kLPI2C_Write) + { + commandBuffer[cmdCount++] = + (uint16_t)kStartCmd | + (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read); + } + } + + /* Send command buffer */ + uint32_t index = 0; + while (cmdCount--) + { + /* Wait until there is room in the fifo. This also checks for errors. */ + result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Write byte into LPI2C master data register. */ + base->MTDR = commandBuffer[index]; + index++; + } + + /* Transmit data. */ + if ((transfer->direction == kLPI2C_Write) && (transfer->dataSize > 0)) + { + /* Send Data. */ + result = LPI2C_MasterSend(base, transfer->data, transfer->dataSize); + } + + /* Receive Data. */ + if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > 0)) + { + result = LPI2C_MasterReceive(base, transfer->data, transfer->dataSize); + } + + if (result) + { + return result; + } + + if ((transfer->flags & kLPI2C_TransferNoStopFlag) == 0) + { + result = LPI2C_MasterStop(base); + } + + return result; +} + +/*! + * brief Creates a new handle for the LPI2C master non-blocking APIs. + * + * The creation of a handle is for use with the non-blocking APIs. Once a handle + * is created, there is not a corresponding destroy handle. If the user wants to + * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called. + * + * + * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice + * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to + * enable the associated INTMUX IRQ in application. + * + * param base The LPI2C peripheral base address. + * param[out] handle Pointer to the LPI2C master driver handle. + * param callback User provided pointer to the asynchronous callback function. + * param userData User provided pointer to the application callback data. + */ +void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + lpi2c_master_transfer_callback_t callback, + void *userData) +{ + uint32_t instance; + + assert(handle); + + /* Clear out the handle. */ + memset(handle, 0, sizeof(*handle)); + + /* Look up instance number */ + instance = LPI2C_GetInstance(base); + + /* Save base and instance. */ + handle->completionCallback = callback; + handle->userData = userData; + + /* Save this handle for IRQ use. */ + s_lpi2cMasterHandle[instance] = handle; + + /* Set irq handler. */ + s_lpi2cMasterIsr = LPI2C_MasterTransferHandleIRQ; + + /* Clear internal IRQ enables and enable NVIC IRQ. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC. + In some cases the LPI2C IRQ is configured through INTMUX, user needs to enable + INTMUX IRQ in application code. */ + EnableIRQ(kLpi2cIrqs[instance]); +} + +/*! + * @brief Execute states until FIFOs are exhausted. + * @param handle Master nonblocking driver handle. + * @param[out] isDone Set to true if the transfer has completed. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_PinLowTimeout + * @retval #kStatus_LPI2C_ArbitrationLost + * @retval #kStatus_LPI2C_Nak + * @retval #kStatus_LPI2C_FifoError + */ +static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone) +{ + uint32_t status; + status_t result = kStatus_Success; + lpi2c_master_transfer_t *xfer; + size_t txCount; + size_t rxCount; + size_t txFifoSize = FSL_FEATURE_LPI2C_FIFO_SIZEn(base); + bool state_complete = false; + + /* Set default isDone return value. */ + *isDone = false; + + /* Check for errors. */ + status = LPI2C_MasterGetStatusFlags(base); + result = LPI2C_MasterCheckAndClearError(base, status); + if (result) + { + return result; + } + + /* Get pointer to private data. */ + xfer = &handle->transfer; + + /* Get fifo counts and compute room in tx fifo. */ + LPI2C_MasterGetFifoCounts(base, &rxCount, &txCount); + txCount = txFifoSize - txCount; + + while (!state_complete) + { + /* Execute the state. */ + switch (handle->state) + { + case kSendCommandState: + { + /* Make sure there is room in the tx fifo for the next command. */ + if (!txCount--) + { + state_complete = true; + break; + } + + /* Issue command. buf is a uint8_t* pointing at the uint16 command array. */ + base->MTDR = *(uint16_t *)handle->buf; + handle->buf += sizeof(uint16_t); + + /* Count down until all commands are sent. */ + if (--handle->remainingBytes == 0) + { + /* Choose next state and set up buffer pointer and count. */ + if (xfer->dataSize) + { + /* Either a send or receive transfer is next. */ + handle->state = kTransferDataState; + handle->buf = (uint8_t *)xfer->data; + handle->remainingBytes = xfer->dataSize; + if (xfer->direction == kLPI2C_Read) + { + /* Disable TX interrupt */ + LPI2C_MasterDisableInterrupts(base, kLPI2C_MasterTxReadyFlag); + } + } + else + { + /* No transfer, so move to stop state. */ + handle->state = kStopState; + } + } + break; + } + + case kIssueReadCommandState: + /* Make sure there is room in the tx fifo for the read command. */ + if (!txCount--) + { + state_complete = true; + break; + } + + base->MTDR = kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1); + + /* Move to transfer state. */ + handle->state = kTransferDataState; + if (xfer->direction == kLPI2C_Read) + { + /* Disable TX interrupt */ + LPI2C_MasterDisableInterrupts(base, kLPI2C_MasterTxReadyFlag); + } + break; + + case kTransferDataState: + if (xfer->direction == kLPI2C_Write) + { + /* Make sure there is room in the tx fifo. */ + if (!txCount--) + { + state_complete = true; + break; + } + + /* Put byte to send in fifo. */ + base->MTDR = *(handle->buf)++; + } + else + { + /* XXX handle receive sizes > 256, use kIssueReadCommandState */ + /* Make sure there is data in the rx fifo. */ + if (!rxCount--) + { + state_complete = true; + break; + } + + /* Read byte from fifo. */ + *(handle->buf)++ = base->MRDR & LPI2C_MRDR_DATA_MASK; + } + + /* Move to stop when the transfer is done. */ + if (--handle->remainingBytes == 0) + { + if (xfer->direction == kLPI2C_Write) + { + state_complete = true; + } + handle->state = kStopState; + } + break; + + case kStopState: + /* Only issue a stop transition if the caller requested it. */ + if ((xfer->flags & kLPI2C_TransferNoStopFlag) == 0) + { + /* Make sure there is room in the tx fifo for the stop command. */ + if (!txCount--) + { + state_complete = true; + break; + } + + base->MTDR = kStopCmd; + } + else + { + /* Caller doesn't want to send a stop, so we're done now. */ + *isDone = true; + state_complete = true; + break; + } + handle->state = kWaitForCompletionState; + break; + + case kWaitForCompletionState: + /* We stay in this state until the stop state is detected. */ + if (status & kLPI2C_MasterStopDetectFlag) + { + *isDone = true; + } + state_complete = true; + break; + default: + assert(false); + break; + } + } + return result; +} + +/*! + * @brief Prepares the transfer state machine and fills in the command buffer. + * @param handle Master nonblocking driver handle. + */ +static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle) +{ + lpi2c_master_transfer_t *xfer = &handle->transfer; + + /* Handle no start option. */ + if (xfer->flags & kLPI2C_TransferNoStartFlag) + { + if (xfer->direction == kLPI2C_Read) + { + /* Need to issue read command first. */ + handle->state = kIssueReadCommandState; + } + else + { + /* Start immediately in the data transfer state. */ + handle->state = kTransferDataState; + } + + handle->buf = (uint8_t *)xfer->data; + handle->remainingBytes = xfer->dataSize; + } + else + { + uint16_t *cmd = (uint16_t *)&handle->commandBuffer; + uint32_t cmdCount = 0; + + /* Initial direction depends on whether a subaddress was provided, and of course the actual */ + /* data transfer direction. */ + lpi2c_direction_t direction = xfer->subaddressSize ? kLPI2C_Write : xfer->direction; + + /* Start command. */ + cmd[cmdCount++] = + (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction); + + /* Subaddress, MSB first. */ + if (xfer->subaddressSize) + { + uint32_t subaddressRemaining = xfer->subaddressSize; + while (subaddressRemaining--) + { + uint8_t subaddressByte = (xfer->subaddress >> (8 * subaddressRemaining)) & 0xff; + cmd[cmdCount++] = subaddressByte; + } + } + + /* Reads need special handling. */ + if ((xfer->dataSize) && (xfer->direction == kLPI2C_Read)) + { + /* Need to send repeated start if switching directions to read. */ + if (direction == kLPI2C_Write) + { + cmd[cmdCount++] = (uint16_t)kStartCmd | + (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read); + } + + /* Read command. */ + cmd[cmdCount++] = kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1); + } + + /* Set up state machine for transferring the commands. */ + handle->state = kSendCommandState; + handle->remainingBytes = cmdCount; + handle->buf = (uint8_t *)&handle->commandBuffer; + } +} + +/*! + * brief Performs a non-blocking transaction on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + * param transfer The pointer to the transfer descriptor. + * retval #kStatus_Success The transaction was started successfully. + * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking + * transaction is already in progress. + */ +status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + lpi2c_master_transfer_t *transfer) +{ + status_t result; + + assert(handle); + assert(transfer); + assert(transfer->subaddressSize <= sizeof(transfer->subaddress)); + + /* Return busy if another transaction is in progress. */ + if (handle->state != kIdleState) + { + return kStatus_LPI2C_Busy; + } + + /* Return an error if the bus is already in use not by us. */ + result = LPI2C_CheckForBusyBus(base); + if (result) + { + return result; + } + + /* Disable LPI2C IRQ sources while we configure stuff. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Save transfer into handle. */ + handle->transfer = *transfer; + + /* Generate commands to send. */ + LPI2C_InitTransferStateMachine(handle); + + /* Clear all flags. */ + LPI2C_MasterClearStatusFlags(base, kMasterClearFlags); + + /* Turn off auto-stop option. */ + base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; + + /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ + LPI2C_MasterEnableInterrupts(base, kMasterIrqFlags); + + return result; +} + +/*! + * brief Returns number of bytes transferred so far. + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + * param[out] count Number of bytes transferred so far by the non-blocking transaction. + * retval #kStatus_Success + * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ +status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count) +{ + assert(handle); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state == kIdleState) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + uint8_t state; + uint16_t remainingBytes; + uint32_t dataSize; + + /* Cache some fields with IRQs disabled. This ensures all field values */ + /* are synchronized with each other during an ongoing transfer. */ + uint32_t irqs = LPI2C_MasterGetEnabledInterrupts(base); + LPI2C_MasterDisableInterrupts(base, irqs); + state = handle->state; + remainingBytes = handle->remainingBytes; + dataSize = handle->transfer.dataSize; + LPI2C_MasterEnableInterrupts(base, irqs); + + /* Get transfer count based on current transfer state. */ + switch (state) + { + case kIdleState: + case kSendCommandState: + case kIssueReadCommandState: /* XXX return correct value for this state when >256 reads are supported */ + *count = 0; + break; + + case kTransferDataState: + *count = dataSize - remainingBytes; + break; + + case kStopState: + case kWaitForCompletionState: + default: + *count = dataSize; + break; + } + + return kStatus_Success; +} + +/*! + * brief Terminates a non-blocking LPI2C master transmission early. + * + * note It is not safe to call this function from an IRQ handler that has a higher priority than the + * LPI2C peripheral's IRQ priority. + * + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + * retval #kStatus_Success A transaction was successfully aborted. + * retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress. + */ +void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle) +{ + if (handle->state != kIdleState) + { + /* Disable internal IRQ enables. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Reset fifos. */ + base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; + + /* Send a stop command to finalize the transfer. */ + base->MTDR = kStopCmd; + + /* Reset handle. */ + handle->state = kIdleState; + } +} + +/*! + * brief Reusable routine to handle master interrupts. + * note This function does not need to be called unless you are reimplementing the + * nonblocking API's interrupt handler routines to add special functionality. + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + */ +void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, lpi2c_master_handle_t *handle) +{ + bool isDone; + status_t result; + + /* Don't do anything if we don't have a valid handle. */ + if (!handle) + { + return; + } + + if (handle->state == kIdleState) + { + return; + } + + result = LPI2C_RunTransferStateMachine(base, handle, &isDone); + + if (isDone || (result != kStatus_Success)) + { + /* XXX need to handle data that may be in rx fifo below watermark level? */ + + /* XXX handle error, terminate xfer */ + + /* Disable internal IRQ enables. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Set handle to idle state. */ + handle->state = kIdleState; + + /* Invoke callback. */ + if (handle->completionCallback) + { + handle->completionCallback(base, handle, result, handle->userData); + } + } +} + +/*! + * brief Provides a default configuration for the LPI2C slave peripheral. + * + * This function provides the following default configuration for the LPI2C slave peripheral: + * code + * slaveConfig->enableSlave = true; + * slaveConfig->address0 = 0U; + * slaveConfig->address1 = 0U; + * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; + * slaveConfig->filterDozeEnable = true; + * slaveConfig->filterEnable = true; + * slaveConfig->enableGeneralCall = false; + * slaveConfig->sclStall.enableAck = false; + * slaveConfig->sclStall.enableTx = true; + * slaveConfig->sclStall.enableRx = true; + * slaveConfig->sclStall.enableAddress = true; + * slaveConfig->ignoreAck = false; + * slaveConfig->enableReceivedAddressRead = false; + * slaveConfig->sdaGlitchFilterWidth_ns = 0; + * slaveConfig->sclGlitchFilterWidth_ns = 0; + * slaveConfig->dataValidDelay_ns = 0; + * slaveConfig->clockHoldTime_ns = 0; + * endcode + * + * After calling this function, override any settings to customize the configuration, + * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the a + * address0 member of the configuration structure with the desired slave address. + * + * param[out] slaveConfig User provided configuration structure that is set to default values. Refer to + * #lpi2c_slave_config_t. + */ +void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig) +{ + /* Initializes the configure structure to zero. */ + memset(slaveConfig, 0, sizeof(*slaveConfig)); + + slaveConfig->enableSlave = true; + slaveConfig->address0 = 0U; + slaveConfig->address1 = 0U; + slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; + slaveConfig->filterDozeEnable = true; + slaveConfig->filterEnable = true; + slaveConfig->enableGeneralCall = false; + slaveConfig->sclStall.enableAck = false; + slaveConfig->sclStall.enableTx = true; + slaveConfig->sclStall.enableRx = true; + slaveConfig->sclStall.enableAddress = false; + slaveConfig->ignoreAck = false; + slaveConfig->enableReceivedAddressRead = false; + slaveConfig->sdaGlitchFilterWidth_ns = 0; /* TODO determine default width values */ + slaveConfig->sclGlitchFilterWidth_ns = 0; + slaveConfig->dataValidDelay_ns = 0; + slaveConfig->clockHoldTime_ns = 0; +} + +/*! + * brief Initializes the LPI2C slave peripheral. + * + * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user + * provided configuration. + * + * param base The LPI2C peripheral base address. + * param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults + * that you can override. + * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths, + * data valid delay, and clock hold time. + */ +void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Ungate the clock. */ + CLOCK_EnableClock(kLpi2cClocks[instance]); +#if defined(LPI2C_PERIPH_CLOCKS) + /* Ungate the functional clock in initialize function. */ + CLOCK_EnableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Restore to reset conditions. */ + LPI2C_SlaveReset(base); + + /* Configure peripheral. */ + base->SAMR = LPI2C_SAMR_ADDR0(slaveConfig->address0) | LPI2C_SAMR_ADDR1(slaveConfig->address1); + + base->SCFGR1 = + LPI2C_SCFGR1_ADDRCFG(slaveConfig->addressMatchMode) | LPI2C_SCFGR1_IGNACK(slaveConfig->ignoreAck) | + LPI2C_SCFGR1_RXCFG(slaveConfig->enableReceivedAddressRead) | LPI2C_SCFGR1_GCEN(slaveConfig->enableGeneralCall) | + LPI2C_SCFGR1_ACKSTALL(slaveConfig->sclStall.enableAck) | LPI2C_SCFGR1_TXDSTALL(slaveConfig->sclStall.enableTx) | + LPI2C_SCFGR1_RXSTALL(slaveConfig->sclStall.enableRx) | + LPI2C_SCFGR1_ADRSTALL(slaveConfig->sclStall.enableAddress); + + base->SCFGR2 = + LPI2C_SCFGR2_FILTSDA(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sdaGlitchFilterWidth_ns, + (LPI2C_SCFGR2_FILTSDA_MASK >> LPI2C_SCFGR2_FILTSDA_SHIFT), 1)) | + LPI2C_SCFGR2_FILTSCL(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sclGlitchFilterWidth_ns, + (LPI2C_SCFGR2_FILTSCL_MASK >> LPI2C_SCFGR2_FILTSCL_SHIFT), 1)) | + LPI2C_SCFGR2_DATAVD(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->dataValidDelay_ns, + (LPI2C_SCFGR2_DATAVD_MASK >> LPI2C_SCFGR2_DATAVD_SHIFT), 1)) | + LPI2C_SCFGR2_CLKHOLD(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->clockHoldTime_ns, + (LPI2C_SCFGR2_CLKHOLD_MASK >> LPI2C_SCFGR2_CLKHOLD_SHIFT), 1)); + + /* Save SCR to last so we don't enable slave until it is configured */ + base->SCR = LPI2C_SCR_FILTDZ(slaveConfig->filterDozeEnable) | LPI2C_SCR_FILTEN(slaveConfig->filterEnable) | + LPI2C_SCR_SEN(slaveConfig->enableSlave); +} + +/*! + * brief Deinitializes the LPI2C slave peripheral. + * + * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software + * reset to restore the peripheral to reset conditions. + * + * param base The LPI2C peripheral base address. + */ +void LPI2C_SlaveDeinit(LPI2C_Type *base) +{ + LPI2C_SlaveReset(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Gate the clock. */ + CLOCK_DisableClock(kLpi2cClocks[instance]); + +#if defined(LPI2C_PERIPH_CLOCKS) + /* Gate the functional clock. */ + CLOCK_DisableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * @brief Convert provided flags to status code, and clear any errors if present. + * @param base The LPI2C peripheral base address. + * @param status Current status flags value that will be checked. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_BitError + * @retval #kStatus_LPI2C_FifoError + */ +static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags) +{ + status_t result = kStatus_Success; + + flags &= kSlaveErrorFlags; + if (flags) + { + if (flags & kLPI2C_SlaveBitErrFlag) + { + result = kStatus_LPI2C_BitError; + } + else if (flags & kLPI2C_SlaveFifoErrFlag) + { + result = kStatus_LPI2C_FifoError; + } + else + { + assert(false); + } + + /* Clear the errors. */ + LPI2C_SlaveClearStatusFlags(base, flags); + } + + return result; +} + +/*! + * brief Performs a polling send transfer on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param txBuff The pointer to the data to be transferred. + * param txSize The length in bytes of the data to be transferred. + * param[out] actualTxSize + * return Error or success status returned by API. + */ +status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize) +{ + uint8_t *buf = (uint8_t *)txBuff; + size_t remaining = txSize; + + assert(txBuff); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + + /* Clear stop flag. */ + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + + while (remaining) + { + uint32_t flags; + status_t result; + + /* Wait until we can transmit. */ + do + { + /* Check for errors */ + flags = LPI2C_SlaveGetStatusFlags(base); + result = LPI2C_SlaveCheckAndClearError(base, flags); + if (result) + { + if (actualTxSize) + { + *actualTxSize = txSize - remaining; + } + return result; + } +#if LPI2C_WAIT_TIMEOUT + } while ( + (!(flags & (kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))) && + (--waitTimes)); + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while ( + !(flags & (kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))); +#endif + + /* Send a byte. */ + if (flags & kLPI2C_SlaveTxReadyFlag) + { + base->STDR = *buf++; + --remaining; + } + + /* Exit loop if we see a stop or restart in transfer*/ + if ((flags & (kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag)) && (remaining != 0U)) + { + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + break; + } + } + + if (actualTxSize) + { + *actualTxSize = txSize - remaining; + } + + return kStatus_Success; +} + +/*! + * brief Performs a polling receive transfer on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param rxBuff The pointer to the data to be transferred. + * param rxSize The length in bytes of the data to be transferred. + * param[out] actualRxSize + * return Error or success status returned by API. + */ +status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize) +{ + uint8_t *buf = (uint8_t *)rxBuff; + size_t remaining = rxSize; + + assert(rxBuff); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + + /* Clear stop flag. */ + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + + while (remaining) + { + uint32_t flags; + status_t result; + + /* Wait until we can receive. */ + do + { + /* Check for errors */ + flags = LPI2C_SlaveGetStatusFlags(base); + result = LPI2C_SlaveCheckAndClearError(base, flags); + if (result) + { + if (actualRxSize) + { + *actualRxSize = rxSize - remaining; + } + return result; + } +#if LPI2C_WAIT_TIMEOUT + } while ( + (!(flags & (kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))) && + (--waitTimes)); + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while ( + !(flags & (kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))); +#endif + + /* Receive a byte. */ + if (flags & kLPI2C_SlaveRxReadyFlag) + { + *buf++ = base->SRDR & LPI2C_SRDR_DATA_MASK; + --remaining; + } + + /* Exit loop if we see a stop or restart */ + if ((flags & (kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag)) && (remaining != 0U)) + { + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + break; + } + } + + if (actualRxSize) + { + *actualRxSize = rxSize - remaining; + } + + return kStatus_Success; +} + +/*! + * brief Creates a new handle for the LPI2C slave non-blocking APIs. + * + * The creation of a handle is for use with the non-blocking APIs. Once a handle + * is created, there is not a corresponding destroy handle. If the user wants to + * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called. + * + * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice + * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to + * enable the associated INTMUX IRQ in application. + + * param base The LPI2C peripheral base address. + * param[out] handle Pointer to the LPI2C slave driver handle. + * param callback User provided pointer to the asynchronous callback function. + * param userData User provided pointer to the application callback data. + */ +void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base, + lpi2c_slave_handle_t *handle, + lpi2c_slave_transfer_callback_t callback, + void *userData) +{ + uint32_t instance; + + assert(handle); + + /* Clear out the handle. */ + memset(handle, 0, sizeof(*handle)); + + /* Look up instance number */ + instance = LPI2C_GetInstance(base); + + /* Save base and instance. */ + handle->callback = callback; + handle->userData = userData; + + /* Save this handle for IRQ use. */ + s_lpi2cSlaveHandle[instance] = handle; + + /* Set irq handler. */ + s_lpi2cSlaveIsr = LPI2C_SlaveTransferHandleIRQ; + + /* Clear internal IRQ enables and enable NVIC IRQ. */ + LPI2C_SlaveDisableInterrupts(base, kSlaveIrqFlags); + EnableIRQ(kLpi2cIrqs[instance]); + + /* Nack by default. */ + base->STAR = LPI2C_STAR_TXNACK_MASK; +} + +/*! + * brief Starts accepting slave transfers. + * + * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing + * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the + * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked + * from the interrupt context. + * + * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to + * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive. + * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need + * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and + * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as + * a convenient way to enable all events. + * + * param base The LPI2C peripheral base address. + * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + * param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify + * which events to send to the callback. Other accepted values are 0 to get a default set of + * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events. + * + * retval #kStatus_Success Slave transfers were successfully started. + * retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle. + */ +status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask) +{ + uint32_t status; + + assert(handle); + + /* Return busy if another transaction is in progress. */ + if (handle->isBusy) + { + return kStatus_LPI2C_Busy; + } + + /* Return an error if the bus is already in use not by us. */ + status = LPI2C_SlaveGetStatusFlags(base); + if ((status & kLPI2C_SlaveBusBusyFlag) && (!(status & kLPI2C_SlaveBusyFlag))) + { + return kStatus_LPI2C_Busy; + } + + /* Disable LPI2C IRQ sources while we configure stuff. */ + LPI2C_SlaveDisableInterrupts(base, kSlaveIrqFlags); + + /* Clear transfer in handle. */ + memset(&handle->transfer, 0, sizeof(handle->transfer)); + + /* Record that we're busy. */ + handle->isBusy = true; + + /* Set up event mask. tx and rx are always enabled. */ + handle->eventMask = eventMask | kLPI2C_SlaveTransmitEvent | kLPI2C_SlaveReceiveEvent; + + /* Ack by default. */ + base->STAR = 0; + + /* Clear all flags. */ + LPI2C_SlaveClearStatusFlags(base, kSlaveClearFlags); + + /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ + LPI2C_SlaveEnableInterrupts(base, kSlaveIrqFlags); + + return kStatus_Success; +} + +/*! + * brief Gets the slave transfer status during a non-blocking transfer. + * param base The LPI2C peripheral base address. + * param handle Pointer to i2c_slave_handle_t structure. + * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not + * required. + * retval #kStatus_Success + * retval #kStatus_NoTransferInProgress + */ +status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count) +{ + assert(handle); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (!handle->isBusy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + /* For an active transfer, just return the count from the handle. */ + *count = handle->transferredCount; + + return kStatus_Success; +} + +/*! + * brief Aborts the slave non-blocking transfers. + * note This API could be called at any time to stop slave for handling the bus events. + * param base The LPI2C peripheral base address. + * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + * retval #kStatus_Success + * retval #kStatus_LPI2C_Idle + */ +void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle) +{ + assert(handle); + + /* Return idle if no transaction is in progress. */ + if (handle->isBusy) + { + /* Disable LPI2C IRQ sources. */ + LPI2C_SlaveDisableInterrupts(base, kSlaveIrqFlags); + + /* Nack by default. */ + base->STAR = LPI2C_STAR_TXNACK_MASK; + + /* Reset transfer info. */ + memset(&handle->transfer, 0, sizeof(handle->transfer)); + + /* We're no longer busy. */ + handle->isBusy = false; + } +} + +/*! + * brief Reusable routine to handle slave interrupts. + * note This function does not need to be called unless you are reimplementing the + * non blocking API's interrupt handler routines to add special functionality. + * param base The LPI2C peripheral base address. + * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + */ +void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle) +{ + uint32_t flags; + lpi2c_slave_transfer_t *xfer; + + /* Check for a valid handle in case of a spurious interrupt. */ + if (!handle) + { + return; + } + + xfer = &handle->transfer; + + /* Get status flags. */ + flags = LPI2C_SlaveGetStatusFlags(base); + + if (flags & (kLPI2C_SlaveBitErrFlag | kLPI2C_SlaveFifoErrFlag)) + { + xfer->event = kLPI2C_SlaveCompletionEvent; + xfer->completionStatus = LPI2C_SlaveCheckAndClearError(base, flags); + + if ((handle->eventMask & kLPI2C_SlaveCompletionEvent) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + return; + } + if (flags & (kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag)) + { + xfer->event = (flags & kLPI2C_SlaveRepeatedStartDetectFlag) ? kLPI2C_SlaveRepeatedStartEvent : + kLPI2C_SlaveCompletionEvent; + xfer->receivedAddress = 0; + xfer->completionStatus = kStatus_Success; + xfer->transferredCount = handle->transferredCount; + + if (xfer->event == kLPI2C_SlaveCompletionEvent) + { + handle->isBusy = false; + } + + if (handle->wasTransmit) + { + /* Subtract one from the transmit count to offset the fact that LPI2C asserts the */ + /* tx flag before it sees the nack from the master-receiver, thus causing one more */ + /* count that the master actually receives. */ + --xfer->transferredCount; + handle->wasTransmit = false; + } + + /* Clear the flag. */ + LPI2C_SlaveClearStatusFlags(base, flags & (kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag)); + + /* Revert to sending an Ack by default, in case we sent a Nack for receive. */ + base->STAR = 0; + + if ((handle->eventMask & xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clean up transfer info on completion, after the callback has been invoked. */ + memset(&handle->transfer, 0, sizeof(handle->transfer)); + } + if (flags & kLPI2C_SlaveAddressValidFlag) + { + xfer->event = kLPI2C_SlaveAddressMatchEvent; + xfer->receivedAddress = base->SASR & LPI2C_SASR_RADDR_MASK; + + /* Update handle status to busy because slave is addressed. */ + handle->isBusy = true; + if ((handle->eventMask & kLPI2C_SlaveAddressMatchEvent) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + if (flags & kLPI2C_SlaveTransmitAckFlag) + { + xfer->event = kLPI2C_SlaveTransmitAckEvent; + + if ((handle->eventMask & kLPI2C_SlaveTransmitAckEvent) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + + /* Handle transmit and receive. */ + if (flags & kLPI2C_SlaveTxReadyFlag) + { + handle->wasTransmit = true; + + /* If we're out of data, invoke callback to get more. */ + if ((!xfer->data) || (!xfer->dataSize)) + { + xfer->event = kLPI2C_SlaveTransmitEvent; + if (handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + handle->transferredCount = 0; + } + + /* Transmit a byte. */ + if ((xfer->data) && (xfer->dataSize)) + { + base->STDR = *xfer->data++; + --xfer->dataSize; + ++handle->transferredCount; + } + } + if (flags & kLPI2C_SlaveRxReadyFlag) + { + /* If we're out of room in the buffer, invoke callback to get another. */ + if ((!xfer->data) || (!xfer->dataSize)) + { + xfer->event = kLPI2C_SlaveReceiveEvent; + if (handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + handle->transferredCount = 0; + } + + /* Receive a byte. */ + if ((xfer->data) && (xfer->dataSize)) + { + *xfer->data++ = base->SRDR; + --xfer->dataSize; + ++handle->transferredCount; + } + else + { + /* We don't have any room to receive more data, so send a nack. */ + base->STAR = LPI2C_STAR_TXNACK_MASK; + } + } +} + +/*! + * @brief Shared IRQ handler that can call both master and slave ISRs. + * + * The master and slave ISRs are called through function pointers in order to decouple + * this code from the ISR functions. Without this, the linker would always pull in both + * ISRs and every function they call, even if only the functional API was used. + * + * @param base The LPI2C peripheral base address. + * @param instance The LPI2C peripheral instance number. + */ +static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance) +{ + /* Check for master IRQ. */ + if ((base->MCR & LPI2C_MCR_MEN_MASK) && s_lpi2cMasterIsr) + { + /* Master mode. */ + s_lpi2cMasterIsr(base, s_lpi2cMasterHandle[instance]); + } + + /* Check for slave IRQ. */ + if ((base->SCR & LPI2C_SCR_SEN_MASK) && s_lpi2cSlaveIsr) + { + /* Slave mode. */ + s_lpi2cSlaveIsr(base, s_lpi2cSlaveHandle[instance]); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#if defined(LPI2C0) +/* Implementation of LPI2C0 handler named in startup code. */ +void LPI2C0_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C0, 0); +} +#endif + +#if defined(LPI2C1) +/* Implementation of LPI2C1 handler named in startup code. */ +void LPI2C1_DriverIRQHandler(int irqn, void *arg) +{ + LPI2C_CommonIRQHandler(LPI2C1, 1); +} +DECLARE_HW_IRQ(LPI2C1_IRQn, LPI2C1_DriverIRQHandler, NONE); +#endif + +#if defined(LPI2C2) +/* Implementation of LPI2C2 handler named in startup code. */ +void LPI2C2_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C2, 2); +} +#endif + +#if defined(LPI2C3) +/* Implementation of LPI2C3 handler named in startup code. */ +void LPI2C3_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C3, 3); +} +#endif + +#if defined(LPI2C4) +/* Implementation of LPI2C4 handler named in startup code. */ +void LPI2C4_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C4, 4); +} +#endif + +#if defined(CM4_0__LPI2C) +/* Implementation of CM4_0__LPI2C handler named in startup code. */ +void M4_0_LPI2C_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(CM4_0__LPI2C, LPI2C_GetInstance(CM4_0__LPI2C)); +} +#endif + +#if defined(CM4__LPI2C) +/* Implementation of CM4__LPI2C handler named in startup code. */ +void M4_LPI2C_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(CM4__LPI2C, LPI2C_GetInstance(CM4__LPI2C)); +} +#endif + +#if defined(CM4_1__LPI2C) +/* Implementation of CM4_1__LPI2C handler named in startup code. */ +void M4_1_LPI2C_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(CM4_1__LPI2C, LPI2C_GetInstance(CM4_1__LPI2C)); +} +#endif + +#if defined(DMA__LPI2C0) +/* Implementation of DMA__LPI2C0 handler named in startup code. */ +void DMA_I2C0_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C0, LPI2C_GetInstance(DMA__LPI2C0)); +} +#endif + +#if defined(DMA__LPI2C1) +/* Implementation of DMA__LPI2C1 handler named in startup code. */ +void DMA_I2C1_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C1, LPI2C_GetInstance(DMA__LPI2C1)); +} +#endif + +#if defined(DMA__LPI2C2) +/* Implementation of DMA__LPI2C2 handler named in startup code. */ +void DMA_I2C2_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C2, LPI2C_GetInstance(DMA__LPI2C2)); +} +#endif + +#if defined(DMA__LPI2C3) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void DMA_I2C3_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C3, LPI2C_GetInstance(DMA__LPI2C3)); +} +#endif + +#if defined(DMA__LPI2C4) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void DMA_I2C4_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C4, LPI2C_GetInstance(DMA__LPI2C4)); +} +#endif + +#if defined(ADMA__LPI2C0) +/* Implementation of DMA__LPI2C0 handler named in startup code. */ +void ADMA_I2C0_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C0, LPI2C_GetInstance(ADMA__LPI2C0)); +} +#endif + +#if defined(ADMA__LPI2C1) +/* Implementation of DMA__LPI2C1 handler named in startup code. */ +void ADMA_I2C1_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C1, LPI2C_GetInstance(ADMA__LPI2C1)); +} +#endif + +#if defined(ADMA__LPI2C2) +/* Implementation of DMA__LPI2C2 handler named in startup code. */ +void ADMA_I2C2_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C2, LPI2C_GetInstance(ADMA__LPI2C2)); +} +#endif + +#if defined(ADMA__LPI2C3) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void ADMA_I2C3_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C3, LPI2C_GetInstance(ADMA__LPI2C3)); +} +#endif + +#if defined(ADMA__LPI2C4) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void ADMA_I2C4_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C4, LPI2C_GetInstance(ADMA__LPI2C4)); +} +#endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/hardware_i2c.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/hardware_i2c.c new file mode 100755 index 000000000..06781487f --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/i2c/hardware_i2c.c @@ -0,0 +1,94 @@ +/* + * The Clear BSD License + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** +* @file hardware_i2c.c +* @brief ok1052-c i2c board relative codes +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2022-03-01 +*/ + +#include "fsl_common.h" +#include "fsl_lpi2c.h" + +#define I2C_BASE LPI2C1 + +/* Select USB1 PLL (480 MHz) as master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_SELECT (0U) +/* Clock divider for master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_DIVIDER (5U) + +#define I2C_CLOCK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U)) +#define I2C_BAUDRATE 100000U + +void I2cHardwareInit(void) +{ + lpi2c_master_config_t masterConfig = {0}; + + LPI2C_MasterGetDefaultConfig(&masterConfig); + + /* Change the default baudrate configuration */ + masterConfig.baudRate_Hz = I2C_BAUDRATE; + + /* Initialize the LPI2C master peripheral */ + LPI2C_MasterInit(I2C_BASE, &masterConfig, I2C_CLOCK_FREQ); +} + +status_t I2cHardwareWrite(LPI2C_Type* base, uint16_t slave_addr, uint32_t subAdd, uint8_t* dataBuff, uint16_t dataLen) +{ + lpi2c_master_transfer_t xfer; + xfer.slaveAddress = slave_addr; + xfer.direction = kLPI2C_Write; + xfer.subaddress = subAdd; + xfer.subaddressSize = 0x01; + xfer.data = dataBuff; + xfer.dataSize = dataLen; + xfer.flags = kLPI2C_TransferDefaultFlag; + return LPI2C_MasterTransferBlocking(base, &xfer); +} + +status_t I2cHardwareRead(LPI2C_Type* base, uint16_t slave_addr, uint32_t subAdd, uint8_t* dataBuffer, uint16_t dataLen) +{ + lpi2c_master_transfer_t masterXfer = {0}; + masterXfer.slaveAddress = slave_addr; + masterXfer.direction = kLPI2C_Read; + masterXfer.subaddress = subAdd; + masterXfer.subaddressSize = 0x01; + masterXfer.data = dataBuffer; + masterXfer.dataSize = dataLen; + masterXfer.flags = kLPI2C_TransferDefaultFlag; + return LPI2C_MasterTransferBlocking(base, &masterXfer); +} + diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_i2c.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_i2c.h new file mode 100755 index 000000000..4ac207c5f --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_i2c.h @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2021 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_i2c.h +* @brief define ok1052-c board i2c function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_I2C_H +#define CONNECT_I2C_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct Stm32I2c +{ + LPI2C_Type* base; + uint16_t slave_addr; + uint32_t sub_addr; +}Stm32I2cType; + +#define i2c_print KPrintf + +int Imxrt1052HwI2cInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_touch.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_touch.h new file mode 100644 index 000000000..1be319f06 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_touch.h @@ -0,0 +1,61 @@ + +/** +* @file connect_touch.c +* @brief support xidatong touch function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2022-04-25 +*/ + +#ifndef CONNECT_TOUCH_H +#define CONNECT_TOUCH_H + +#include + +/* 表示读数据 */ +#define I2C_M_RD 0x0001 + +struct i2c_msg { + uint8_t addr; /*从设备的I2C设备地址 */ + uint16_t flags; /*控制标志 */ + uint16_t len; /*读写数据的长度 */ + uint8_t *buf; /*存储读写数据的指针 */ +}; + +typedef struct +{ + int X; + int Y; +}POINT; + +typedef enum _touch_event +{ + kTouch_Down = 0, /*!< The state changed to touched. */ + kTouch_Up = 1, /*!< The state changed to not touched. */ + kTouch_Contact = 2, /*!< There is a continuous touch being detected. */ + kTouch_Reserved = 3 /*!< No touch information available. */ +} touch_event_t; + +/*设定使用的电容屏IIC设备地址*/ +#define GTP_ADDRESS 0xBA + +#define GTP_MAX_HEIGHT 272 +#define GTP_MAX_WIDTH 480 +#define GTP_INT_TRIGGER 0 +#define GTP_MAX_TOUCH 5 + +#define GTP_CONFIG_MAX_LENGTH 240 +#define GTP_ADDR_LENGTH 2 + +// Registers define +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_SLEEP 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) + +int HwTouchInit(void); + +#endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/lcd/connect_lcd.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/lcd/connect_lcd.c index 5f535bb9e..ac1459aca 100644 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/lcd/connect_lcd.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/lcd/connect_lcd.c @@ -1,6 +1,6 @@ /** * @file connect_lcd.c -* @brief support aiit-arm32-board lcd function and register to bus framework +* @brief support xidatong lcd function and register to bus framework * @version 2.0 * @author AIIT XiUOS Lab * @date 2022-04-25 diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/Kconfig b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/Kconfig new file mode 100644 index 000000000..047564350 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/Kconfig @@ -0,0 +1,12 @@ +if BSP_USING_TOUCH + config TOUCH_BUS_NAME + string "touch bus name" + default "touch" + config TOUCH_DRV_NAME + string "touch bus driver name" + default "touch_drv" + config TOUCH_DEVICE_NAME + string "touch bus device name" + default "touch_dev" + +endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/Makefile new file mode 100644 index 000000000..80a85e1be --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/Makefile @@ -0,0 +1,4 @@ +SRC_FILES := connect_touch.c i2c_touch.c + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/connect_touch.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/connect_touch.c new file mode 100644 index 000000000..64fd1e9e1 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/connect_touch.c @@ -0,0 +1,451 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_touch.c +* @brief support xidatong touch function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2022-05-15 +*/ + +#include +#include +#include "i2c_touch.h" + +#define LCD_HEIGHT BSP_LCD_X_MAX +#define LCD_WIDTH BSP_LCD_Y_MAX +#define DEFAULT_NUM 0x0D + +uint8_t CTP_CFG_GT911[] = { + 0x5B,0xE0,0x01,0x10,0x01,0x0A,0x0D,0x00,0x01,0x0A, + 0x28,0x0F,0x5A,0x3C,0x03,0x05,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x28,0x09, + 0x32,0x34,0x0C,0x08,0x00,0x00,0x00,0x02,0x02,0x1D, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x28,0x55,0x94,0xC5,0x02,0x07,0x00,0x00,0x04, + 0x8D,0x2B,0x00,0x80,0x32,0x00,0x75,0x3A,0x00,0x6C, + 0x43,0x00,0x64,0x4F,0x00,0x64,0x00,0x00,0x00,0x00, + 0xF0,0x4A,0x3A,0xFF,0xFF,0x27,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,0x12, + 0x14,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x26,0x24,0x22,0x21,0x20,0x1F,0x1E,0x1D, + 0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x81,0x01 +}; +uint8_t config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH] + = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + +int touch_sem = 0; +POINT Pre_Touch_Point; + + + +static int32_t GtpI2cWrite(uint8_t client_addr,uint8_t *buf,int32_t len) +{ + struct i2c_msg msg; + int32_t ret = -1; + int32_t retries = 0; + + // GTP_DEBUG_FUNC(); + + msg.flags = !I2C_M_RD; + msg.addr = client_addr; + msg.len = len; + msg.buf = buf; + //msg.scl_rate = 300 * 1000; // for Rockchip, etc + + while(retries < 5) + { + ret = I2C_Transfer(&msg, 1); + if (ret == 1)break; + retries++; + } + if((retries >= 5)) + { + KPrintf("I2C Write: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret); + ret = -1; + } + return ret; +} +static int32_t GtpI2cRead(uint8_t client_addr, uint8_t *buf, int32_t len) +{ + struct i2c_msg msgs[2]; + int32_t ret = -1; + int32_t retries = 0; + + msgs[0].flags = !I2C_M_RD; + msgs[0].addr = client_addr; + msgs[0].len = GTP_ADDR_LENGTH; + msgs[0].buf = &buf[0]; + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = client_addr; + msgs[1].len = len - GTP_ADDR_LENGTH; + msgs[1].buf = &buf[GTP_ADDR_LENGTH]; + + while(retries < 5) + { + ret = I2C_Transfer( msgs, 2); + if(ret == 2)break; + retries++; + } + if((retries >= 5)) + { + KPrintf("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.\n", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret); + ret = -1; + } + return ret; +} +static int32_t gt91xx_Config_Write_Proc() +{ + int32_t ret = -1; + + int32_t i = 0; + uint8_t check_sum = 0; + int32_t retry = 0; + uint8_t cfg_num =0x80FE - 0x8047+1 ; + + const uint8_t* cfg_info = CTP_CFG_GT911; + + uint8_t cfg_info_len = CFG_GROUP_LEN(CTP_CFG_GT911) ; + + memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&config[GTP_ADDR_LENGTH], cfg_info,cfg_info_len); + + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg_num+GTP_ADDR_LENGTH; i++) + { + check_sum += config[i]; + } + config[ cfg_num+GTP_ADDR_LENGTH] = (~check_sum) + 1; //checksum + config[ cfg_num+GTP_ADDR_LENGTH+1] = 1; //refresh ?????? + KPrintf("Driver send config check_sum 0x%x\n",check_sum); + for (retry = 0; retry < 5; retry++) + { + ret = GtpI2cWrite(GTP_ADDRESS, config , cfg_num + GTP_ADDR_LENGTH+2); + if (ret > 0) + { + break; + } + } + return ret; +} + +/** + * @brief 触屏处理函数,轮询或者在触摸中断调用 + * @param 无 + * @retval 无 + */ +bool GetTouchEvent(POINT *touch_point,touch_event_t *touch_event) +{ + + uint8_t end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0}; + uint8_t point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF}; + uint8_t touch_num = 0; + uint8_t finger = 0; + static uint16_t pre_touch = 0; + + uint8_t client_addr=GTP_ADDRESS; + uint8_t* coor_data = NULL; + int32_t input_x = 0; + int32_t input_y = 0; + int32_t input_w = 0; + + int32_t ret = -1; + + ret = GtpI2cRead(client_addr, point_data, 12);//10字节寄存器加2字节地址 + if (ret < 0) + { + KPrintf("I2C transfer error. errno:%d\n ", ret); + return 0; + } + + finger = point_data[GTP_ADDR_LENGTH];//状态寄存器数据 + + if (finger == 0x00) //没有数据,退出 + { + return 0; + } + + if((finger & 0x80) == 0)//判断buffer status位 + { + goto exit_work_func;//坐标未就绪,数据无效 + } + + touch_num = finger & 0x0f;//坐标点数 + if (touch_num > GTP_MAX_TOUCH) + { + goto exit_work_func;//大于最大支持点数,错误退出 + } + + if (touch_num) + { + coor_data = &point_data[0 * 8 + 3]; + input_x = coor_data[1] | (coor_data[2] << 8); //x坐标 + input_y = coor_data[3] | (coor_data[4] << 8); //y坐标 + input_w = coor_data[5] | (coor_data[6] << 8); //size + touch_point->X = input_x; + touch_point->Y = input_y; + *touch_event = kTouch_Down; + Pre_Touch_Point = *touch_point; + + } + else if (pre_touch) //touch_ num=0 且pre_touch!=0 + { + *touch_point = Pre_Touch_Point; + *touch_event = kTouch_Up; + Pre_Touch_Point.X = -1; + Pre_Touch_Point.Y = -1; + } + pre_touch = touch_num; + +exit_work_func: + { + ret = GtpI2cWrite(client_addr, end_cmd, 3); + if (ret < 0) + { + KPrintf("I2C write end_cmd error!"); + } + } + return 1; +} + +int32_t GtpReadVersion(void) +{ + int32_t ret = -1; + uint8_t buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + ret = GtpI2cRead(GTP_ADDRESS, buf, sizeof(buf)); + if (ret < 0) + { + KPrintf("GTP read version failed.\n"); + return ret; + } + + if (buf[5] == 0x00) + { + KPrintf("IC1 Version: %c%c%c_%02x%02x\n", buf[2], buf[3], buf[4], buf[7], buf[6]); + } + else + { + KPrintf("IC2 Version: %c%c%c%c_%02x%02x\n", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + return ret; +} + +static int32_t GtpGetInfo(void) +{ + uint8_t opr_buf[6] = {0}; + int32_t ret = 0; + + uint16_t abs_x_max = GTP_MAX_WIDTH; + uint16_t abs_y_max = GTP_MAX_HEIGHT; + uint8_t int_trigger_type = GTP_INT_TRIGGER; + + /* config the touch as 480*272 size */ + gt91xx_Config_Write_Proc(); + + opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA+1) >> 8); + opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA+1) & 0xFF); + + ret = GtpI2cRead(GTP_ADDRESS, opr_buf, 6); + if (ret < 0) + { + return -1; + } + + abs_x_max = (opr_buf[3] << 8) + opr_buf[2]; + abs_y_max = (opr_buf[5] << 8) + opr_buf[4]; + + opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA+6) >> 8); + opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA+6) & 0xFF); + + ret = GtpI2cRead(GTP_ADDRESS, opr_buf, 3); + if (ret < 0) + { + return 0; + } + int_trigger_type = opr_buf[2] & 0x03; + + KPrintf("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x\n", + abs_x_max,abs_y_max,int_trigger_type); + + return 0; +} + +static uint32 TouchOpen(void *dev) +{ + int32_t ret = -1; + + I2C_Touch_Init(); + + ret = GtpReadVersion(); + if(ret < 0) + { + KPrintf("gtp read version error\n"); + GtpI2cDeinit(); + return ret; + } + + ret = GtpGetInfo(); + if(ret < 0) + { + KPrintf("gtp read info error\n"); + GtpI2cDeinit(); + return ret; + } + + touch_sem = KSemaphoreCreate(0); + if (touch_sem < 0) { + KPrintf("touch create sem failed .\n"); + GtpI2cDeinit(); + return -1; + } + + GTP_IRQEnable(); + return ret; +} +static uint32 TouchClose(void *dev) +{ + GTP_IRQDisable(); + + KSemaphoreDelete(touch_sem); + + GtpI2cDeinit(); + return 0; +} + +static uint32 TouchRead(void *dev, struct BusBlockReadParam *read_param) +{ + uint32 ret = -1; + x_err_t result; + POINT touch_point; + touch_event_t touch_event; + + struct TouchDataStandard *data = (struct TouchDataStandard*)read_param->buffer; + result = KSemaphoreObtain(touch_sem, 1000); + if (EOK == result) + { + if(GetTouchEvent(&touch_point, &touch_event)) + { + data->x = abs(LCD_WIDTH - touch_point.X); + data->y = abs(LCD_HEIGHT - touch_point.Y); + data->x = touch_point.X; + data->y = touch_point.Y; + g_TouchPadInputSignal = 0; + SemReleaseFlag = 0; + + read_param->read_length = read_param->size; + ret = EOK; + } + } + + return ret; +} + +static uint32 TouchConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + return 0; +} + +struct TouchDevDone touch_dev_done = +{ + .open = TouchOpen, + .close = TouchClose, + .write = NONE, + .read = TouchRead +}; + +static int BoardTouchBusInit(struct TouchBus * touch_bus, struct TouchDriver * touch_driver,const char *bus_name, const char *drv_name) +{ + x_err_t ret = EOK; + + /*Init the touch bus */ + ret = TouchBusInit(touch_bus, bus_name); + if (EOK != ret) { + KPrintf("Board_touch_init touchBusInit error %d\n", ret); + return -ERROR; + } + + /*Init the touch driver*/ + ret = TouchDriverInit(touch_driver, drv_name); + if (EOK != ret){ + KPrintf("Board_touch_init touchDriverInit error %d\n", ret); + return -ERROR; + } + + /*Attach the touch driver to the touch bus*/ + ret = TouchDriverAttachToBus(drv_name, bus_name); + if (EOK != ret){ + KPrintf("Board_touch_init TouchDriverAttachToBus error %d\n", ret); + return -ERROR; + } + + return ret; +} + +/*Attach the touch device to the touch bus*/ +static int BoardTouchDevBend(struct TouchHardwareDevice *touch_device, void *param, const char *bus_name, const char *dev_name) +{ + x_err_t ret = EOK; + + ret = TouchDeviceRegister(touch_device, param, dev_name); + if (EOK != ret){ + KPrintf("TouchDeviceRegister device %s error %d\n", dev_name, ret); + return -ERROR; + } + + ret = TouchDeviceAttachToBus(dev_name, bus_name); + if (EOK != ret) { + KPrintf("TouchDeviceAttachToBus device %s error %d\n", dev_name, ret); + return -ERROR; + } + + return ret; +} + +int HwTouchInit(void) +{ + x_err_t ret = EOK; + + static struct TouchBus touch_bus; + static struct TouchDriver touch_driver; + static struct TouchHardwareDevice touch_dev; + + memset(&touch_bus, 0, sizeof(struct TouchBus)); + memset(&touch_driver, 0, sizeof(struct TouchDriver)); + memset(&touch_dev, 0, sizeof(struct TouchHardwareDevice)); + + touch_driver.configure = TouchConfigure; + + ret = BoardTouchBusInit(&touch_bus, &touch_driver,TOUCH_BUS_NAME,TOUCH_DRV_NAME); + if (EOK != ret) { + return -ERROR; + } + + touch_dev.dev_done = &touch_dev_done; + + ret = BoardTouchDevBend(&touch_dev, NONE, TOUCH_BUS_NAME, TOUCH_DEVICE_NAME); + if (EOK != ret) { + KPrintf("board_touch_Init error ret %u\n", ret); + return -ERROR; + } + + return EOK; +} diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/i2c_touch.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/i2c_touch.c new file mode 100644 index 000000000..ba123b3b6 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/i2c_touch.c @@ -0,0 +1,356 @@ + +// #include "fsl_debug_console.h" +#include +#include "fsl_iomuxc.h" +#include "pin_mux.h" +#include "fsl_gpio.h" +#include "fsl_lpi2c.h" + +#include "i2c_touch.h" +#include + + + +/******************************************************************************* + * Definitions + ******************************************************************************/ + + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void GTP_I2C_ModeInit(void); + +static void I2C_Master_Callback(LPI2C_Type *base, lpi2c_master_handle_t *handle, status_t status, void *userData); +static uint32_t I2C_Timeout_Callback(uint8_t errorCode); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +lpi2c_master_handle_t g_m_handle; +volatile bool g_MasterCompletionFlag = false; +volatile bool g_TouchPadInputSignal = false; +volatile bool SemReleaseFlag = false; +/******************************************************************************* + * Code + ******************************************************************************/ + +/** + * @brief GT91xxоƬиλ + * @param + * @retval + */ +void GTP_ResetChip(void) +{ + /* ȰRST INTΪģʽ */ + gpio_pin_config_t rst_int_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; + + GPIO_PinInit(TOUCH_PAD_INT_GPIO, TOUCH_PAD_INT_GPIO_PIN, &rst_int_config); + + /*ʼGT9157,INTΪ͵ƽgt9157豸ַΪ0xBA*/ + + /*λΪ͵ƽΪʼ׼*/ + GPIO_PinWrite(TOUCH_PAD_INT_GPIO, TOUCH_PAD_INT_GPIO_PIN, 0U); + + //INTóж + rst_int_config.direction = kGPIO_DigitalInput; + rst_int_config.outputLogic = 0; + rst_int_config.interruptMode = kGPIO_IntFallingEdge; + + GPIO_PinInit(TOUCH_PAD_INT_GPIO, TOUCH_PAD_INT_GPIO_PIN, &rst_int_config); + + /* ʹж */ + GPIO_PortEnableInterrupts(TOUCH_PAD_INT_GPIO, 1U << TOUCH_PAD_INT_GPIO_PIN); +} + +/** +* @brief ֹоƬж +* @param +* @retval +*/ +void GTP_IRQDisable(void) +{ + DisableIRQ(GT9xx_PEN_IRQ); +} + +/** +* @brief ʹܴоƬж +* @param +* @retval +*/ +void GTP_IRQEnable(void) +{ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_14_GPIO2_IO30, /* WAKEUP is configured as GPIO5_IO00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_14_GPIO2_IO30, + 0x10B0u); + + + gpio_pin_config_t rst_int_config; + + //INTóж + rst_int_config.direction = kGPIO_DigitalInput; + rst_int_config.outputLogic = 0; + rst_int_config.interruptMode = kGPIO_IntFallingEdge; + + GPIO_PinInit(TOUCH_PAD_INT_GPIO, TOUCH_PAD_INT_GPIO_PIN, &rst_int_config); + + /* ʹж */ + GPIO_PortEnableInterrupts(TOUCH_PAD_INT_GPIO, 1U << TOUCH_PAD_INT_GPIO_PIN); + + /* ʹжIRQ */ + EnableIRQ(GT9xx_PEN_IRQ); +} + + +/** +* @brief ʼоƬʹõI2C +* @param +* @retval +*/ +void GTP_I2C_ModeInit(void) +{ + lpi2c_master_config_t masterConfig; + + /* + * masterConfig.debugEnable = false; + * masterConfig.ignoreAck = false; + * masterConfig.pinConfig = kLPI2C_2PinOpenDrain; + * masterConfig.baudRate_Hz = 100000U; + * masterConfig.busIdleTimeout_ns = 0; + * masterConfig.pinLowTimeout_ns = 0; + * masterConfig.sdaGlitchFilterWidth_ns = 0; + * masterConfig.sclGlitchFilterWidth_ns = 0; + */ + LPI2C_MasterGetDefaultConfig(&masterConfig); + + masterConfig.baudRate_Hz = GTP_I2C_BAUDRATE; + + LPI2C_MasterInit(GTP_I2C_MASTER, &masterConfig, LPI2C_MASTER_CLOCK_FREQUENCY); + + LPI2C_MasterTransferCreateHandle(GTP_I2C_MASTER, &g_m_handle, I2C_Master_Callback, NULL); + +} + +void GtpI2cDeinit(void) +{ + LPI2C_MasterDeinit(GTP_I2C_MASTER); +} + +/** + * @brief ʹIICȡ + * @param + * @arg ClientAddr:豸ַ + * @arg pBuffer:ɴӻȡݵĻָ + * @arg NumByteToRead:ȡݳ + * @retval + */ +uint32_t I2C_ReadBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint16_t NumByteToRead) +{ + lpi2c_master_transfer_t masterXfer = {0}; + status_t reVal = kStatus_Fail; + uint32_t i2c_timeout = I2CT_LONG_TIMEOUT; + + + /* subAddress = 0x00, data = pBuffer Դӻ + ʼźstart + 豸ַslaveaddress(w д) + ӵַsubAddress + + ظʼźrepeated start + 豸ַslaveaddress(r ) + + ջrx data buffer + ֹͣźstop */ + masterXfer.slaveAddress = (ClientAddr>>1); + masterXfer.direction = kLPI2C_Read; + masterXfer.subaddress = (uint32_t)0; + masterXfer.subaddressSize = 0; + masterXfer.data = pBuffer; + masterXfer.dataSize = NumByteToRead; + masterXfer.flags = kLPI2C_TransferDefaultFlag; + + reVal = LPI2C_MasterTransferNonBlocking(GTP_I2C_MASTER, &g_m_handle, &masterXfer); + if (reVal != kStatus_Success) + { + return 1; + } + /* λɱ־ */ + g_MasterCompletionFlag = false; + + /* ȴ */ + while (!g_MasterCompletionFlag) + { + if((i2c_timeout--) == 0) return I2C_Timeout_Callback(0); + + } + g_MasterCompletionFlag = false; + + return 0; +} + +/** + * @brief ʹIICд + * @param + * @arg ClientAddr:豸ַ + * @arg pBuffer:ָ + * @arg NumByteToWrite:дֽ + * @retval + */ +uint32_t I2C_WriteBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint8_t NumByteToWrite) +{ + lpi2c_master_transfer_t masterXfer = {0}; + status_t reVal = kStatus_Fail; + uint32_t i2c_timeout = I2CT_LONG_TIMEOUT; + + + /* subAddress = 0x00, data = pBuffer ӻ + ʼźstart + 豸ַslaveaddress(w д) + + ͻtx data buffer + ֹͣźstop */ + + masterXfer.slaveAddress = (ClientAddr>>1); + masterXfer.direction = kLPI2C_Write; + masterXfer.subaddress = (uint32_t)0; + masterXfer.subaddressSize = 0; + masterXfer.data = pBuffer; + masterXfer.dataSize = NumByteToWrite; + masterXfer.flags = kLPI2C_TransferDefaultFlag; + + reVal = LPI2C_MasterTransferNonBlocking(GTP_I2C_MASTER, &g_m_handle, &masterXfer); + if (reVal != kStatus_Success) + { + return 1; + } + /* λɱ־ */ + g_MasterCompletionFlag = false; + + /* ȴ */ + while (!g_MasterCompletionFlag) + { + if((i2c_timeout--) == 0) return I2C_Timeout_Callback(1); + } + g_MasterCompletionFlag = false; + + return 0; + +} + +/** + * @brief IICȴʱñϢ + * @param None. + * @retval 0xffʾIICȡʧ + */ +static uint32_t I2C_Timeout_Callback(uint8_t errorCode) +{ + /* Block communication and all processes */ + KPrintf("I2C timeout!errorCode = %d",errorCode); + + return 0xFF; +} + +/** +* @brief I2C贫ɵĻص +* @param +* @retval +*/ +static void I2C_Master_Callback(LPI2C_Type *base, lpi2c_master_handle_t *handle, status_t status, void *userData) +{ + /* յkStatus_Success־ + g_MasterCompletionFlag־ɹ */ + if (status == kStatus_Success) + { + g_MasterCompletionFlag = true; + } +} + + + +/** +* @brief żоƬʼ +* @param +* @retval +*/ +void I2C_Touch_Init(void) +{ + +// /* ʼI2C蹤ģʽ */ + GTP_I2C_ModeInit(); + + /* λоƬõַ */ + GTP_ResetChip(); +} + + +/***************************ж******************************/ +/** +* @brief оƬTOUCH_PAD_INT_GPIO_PINŵжϷ +* @param +* @retval +*/ +//void TOUCH_PAD_IRQHANDLER(void) +extern int touch_sem; +void GT9xx_PEN_IRQHandler(int irqn, void *arg) +{ + DisableIRQ(GT9xx_PEN_IRQ); + /* ȷǴоƬж */ + if(GPIO_GetPinsInterruptFlags(TOUCH_PAD_INT_GPIO) & 1U << TOUCH_PAD_INT_GPIO_PIN) + { + /* жϱ־ */ + GPIO_PortClearInterruptFlags(TOUCH_PAD_INT_GPIO, 1U << TOUCH_PAD_INT_GPIO_PIN); + /* л״̬־ */ + g_TouchPadInputSignal = true; + if(!SemReleaseFlag) + { + KSemaphoreAbandon(touch_sem); + SemReleaseFlag = true; + } + } + EnableIRQ(GT9xx_PEN_IRQ); +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +DECLARE_HW_IRQ(GT9xx_PEN_IRQ, GT9xx_PEN_IRQHandler, NONE); + + +/** + * i2c_transfer - execute a single or combined I2C message + * @msgs: One or more messages to execute before STOP is issued to + * terminate the operation; each message begins with a START. + * @num: Number of messages to be executed. + */ +int I2C_Transfer( struct i2c_msg *msgs,int num) +{ + int im = 0; + int ret = 0; + + //GTP_DEBUG_FUNC(); + + for (im = 0; ret == 0 && im != num; im++) + { + if ((msgs[im].flags&I2C_M_RD)) //flagжǶݻд + { + ret = I2C_ReadBytes(msgs[im].addr, msgs[im].buf, msgs[im].len); //IICȡ + } else + { + ret = I2C_WriteBytes(msgs[im].addr, msgs[im].buf, msgs[im].len); //IICд + } + } + + if(ret) + return ret; + + return im; //ɵĴṹ +} + + + + + + + + + + + + +/*********************************************END OF FILE**********************/ diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/i2c_touch.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/i2c_touch.h new file mode 100644 index 000000000..24759ba03 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/touch/i2c_touch.h @@ -0,0 +1,67 @@ +#ifndef __I2C_TOUCH_H +#define __I2C_TOUCH_H + +#include "fsl_common.h" +#include "fsl_lpi2c.h" +#include "board.h" +#include +extern lpi2c_master_handle_t g_m_handle; +extern volatile bool g_MasterCompletionFlag ; +extern volatile bool g_TouchPadInputSignal; +extern volatile bool SemReleaseFlag; + + + +/* Select USB1 PLL (480 MHz) as master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_SELECT (0U) +/* Clock divider for master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_DIVIDER (5U) +/* Get frequency of lpi2c clock */ +#define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U)) + +#define LPI2C_MASTER_CLOCK_FREQUENCY LPI2C_CLOCK_FREQUENCY + +#define GTP_I2C_MASTER_BASE (LPI2C1_BASE) +#define GTP_I2C_MASTER ((LPI2C_Type *)GTP_I2C_MASTER_BASE) + +#define GTP_I2C_BAUDRATE 400000U + +/* ȴʱʱ */ +#define I2CT_FLAG_TIMEOUT ((uint32_t)0x10000) +#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT)) + + +/*! @brief оƬŶ */ + +#define TOUCH_PAD_SCL_IOMUXC IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL +#define TOUCH_PAD_SDA_IOMUXC IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA + + +#define TOUCH_PAD_RST_GPIO GPIO1 +#define TOUCH_PAD_RST_GPIO_PIN (27U) +#define TOUCH_PAD_RST_IOMUXC IOMUXC_GPIO_AD_B1_11_GPIO1_IO27//IOMUXC_GPIO_AD_B1_11_GPIO1_IO27 + +#define TOUCH_PAD_INT_GPIO GPIO2 +#define TOUCH_PAD_INT_GPIO_PIN (30U) +#define TOUCH_PAD_INT_IOMUXC IOMUXC_GPIO_AD_B0_11_GPIO1_IO11 + +#define GT9xx_PEN_IRQ GPIO2_Combined_16_31_IRQn +#define GT9xx_PEN_IRQHandler GPIO2_Combined_16_31_IRQHandler + + + +//ӿ +int32_t GTP_I2C_ReadBytes(uint8_t client_addr, uint8_t *buf, int32_t len); + +void I2C_Touch_Init(void); +void GtpI2cDeinit(void); +uint32_t I2C_WriteBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint8_t NumByteToWrite); +uint32_t I2C_ReadBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint16_t NumByteToRead); +void GTP_ResetChip(void); +void GTP_IRQDisable(void); +void GTP_IRQEnable(void); +int I2C_Transfer( struct i2c_msg *msgs,int num); + + + +#endif /* __I2C_TOUCH_H */