diff --git a/.mxproject b/.mxproject index 12fe049..023c53e 100644 --- a/.mxproject +++ b/.mxproject @@ -1,14 +1,14 @@ [PreviousLibFiles] -LibFiles=Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f407xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;Drivers\CMSIS\Include\cachel1_armv7.h;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm55.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_cm85.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\core_starmc1.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\pac_armv81.h;Drivers\CMSIS\Include\pmu_armv8.h;Drivers\CMSIS\Include\tz_context.h; +LibFiles=Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_i2c.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_i2c_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_rcc_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_bus.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_rcc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_system.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_utils.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_flash_ramfunc.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_gpio_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_gpio.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dma.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_dmamux.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_pwr_ex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_pwr.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_cortex.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal.h;Drivers\STM32F4xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_def.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_exti.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_spi.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_hal_uart.h;Drivers\STM32F4xx_HAL_Driver\Inc\stm32f4xx_ll_usart.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f407xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h;Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;Drivers\CMSIS\Include\cachel1_armv7.h;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm55.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_cm85.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\core_starmc1.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\pac_armv81.h;Drivers\CMSIS\Include\pmu_armv8.h;Drivers\CMSIS\Include\tz_context.h; [PreviousUsedKeilFiles] -SourceFiles=..\Src\main.c;..\Src\gpio.c;..\Src\spi.c;..\Src\usart.c;..\Src\stm32f4xx_it.c;..\Src\stm32f4xx_hal_msp.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;;; +SourceFiles=..\Src\main.c;..\Src\gpio.c;..\Src\dma.c;..\Src\i2c.c;..\Src\spi.c;..\Src\usart.c;..\Src\stm32f4xx_it.c;..\Src\stm32f4xx_hal_msp.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_i2c_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_flash_ramfunc.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_cortex.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_spi.c;..\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_uart.c;..\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c;..\\Src\system_stm32f4xx.c;;; HeaderPath=..\Drivers\STM32F4xx_HAL_Driver\Inc;..\Drivers\STM32F4xx_HAL_Driver\Inc\Legacy;..\Drivers\CMSIS\Device\ST\STM32F4xx\Include;..\Drivers\CMSIS\Include;..\Inc; CDefines=USE_HAL_DRIVER;STM32F407xx;USE_HAL_DRIVER;USE_HAL_DRIVER; [PreviousGenFiles] HeaderPath=..\Inc -HeaderFiles=gpio.h;spi.h;usart.h;stm32f4xx_it.h;stm32f4xx_hal_conf.h;main.h; +HeaderFiles=gpio.h;dma.h;i2c.h;spi.h;usart.h;stm32f4xx_it.h;stm32f4xx_hal_conf.h;main.h; SourcePath=..\Src -SourceFiles=gpio.c;spi.c;usart.c;stm32f4xx_it.c;stm32f4xx_hal_msp.c;main.c; +SourceFiles=gpio.c;dma.c;i2c.c;spi.c;usart.c;stm32f4xx_it.c;stm32f4xx_hal_msp.c;main.c; diff --git a/AGENTS.md b/AGENTS.md index cc6274f..f0337b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,14 +2,44 @@ ## 项目概述 -STM32F407ZGTx (Cortex-M4 FPU) 基础固件项目,集成 CH395F 以太网控制器 SPI 驱动(CH395F 自带 MAC+PHY 及 TCP/IP 协议栈固件)。 +STM32F407ZGTx (Cortex-M4 FPU) 基础固件项目,集成 CH395F 以太网控制器 SPI 驱动、GD5F2GQ5UE SPI NAND Flash 存储(含 FlashDB KVDB/TSDB 数据库)和 TPAFE5160 16位8通道同步采样 ADC 并行接口驱动。 + +## 目录结构 + +``` +STM32F4-Base/ +├── Src/ # CubeMX 生成的外设初始化 + main +├── Inc/ # CubeMX 生成的头文件 +├── Drivers/ +│ ├── BSP/ +│ │ ├── CH395F/ # CH395F 以太网芯片驱动(手写) +│ │ ├── GD5F2GQ5UE/ # GD5F2GQ5UE NAND Flash 驱动(手写) +│ │ │ ├── gd5f2gq5ue.h/c # 底层 SPI 驱动 +│ │ │ ├── fal_flash_gd5f2gq5ue.c # FAL 设备适配层 +│ │ │ ├── fal_cfg.h # FAL 设备表 + 分区表 +│ │ │ └── fdb_cfg.h # FlashDB 功能配置 +│ │ └── TPAFE5160/ # TPAFE5160 ADC 并行接口驱动(手写) +│ ├── STM32F4xx_HAL_Driver/ # ST HAL 库(CubeMX 生成) +│ └── CMSIS/ # ARM CMSIS(CubeMX 生成) +├── Lib/ +│ └── FlashDB/ # FlashDB 数据库库(v2.2.99) +│ ├── src/ # FlashDB 核心源码 +│ ├── inc/ # FlashDB 头文件 +│ └── port/fal/ # FAL 抽象层 +├── MDK-ARM/ # Keil MDK 工程文件 +├── docs/ # 参考文档 +└── STM32F407-Demo.ioc # STM32CubeMX 项目源文件 +``` ## 关键文件 | 路径 | 说明 | |---|---| | `Src/main.c` | 程序入口,初始化序列及主循环 | -| `Src/ch395f.c` / `Inc/ch395f.h` | CH395F 以太网芯片 SPI 驱动(核心自定义代码) | +| `Drivers/BSP/CH395F/ch395f.c/h` | CH395F 以太网芯片 SPI 驱动 | +| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c/h` | GD5F2GQ5UE NAND Flash SPI 驱动 | +| `Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c` | FAL 设备适配层 | +| `Drivers/BSP/TPAFE5160/tpafe5160.c/h` | TPAFE5160 ADC 并行接口驱动 | | `MDK-ARM/STM32F407-Demo.uvprojx` | Keil MDK 项目文件 | | `STM32F407-Demo.ioc` | STM32CubeMX 项目源文件 | @@ -27,12 +57,14 @@ STM32F407ZGTx (Cortex-M4 FPU) 基础固件项目,集成 CH395F 以太网控制 - **主频:** HSE 25MHz → PLL 168MHz (4/168/2) - **6 个 LED:** PC4, PC5, PB1, PB2, PF11, PF12(低电平点亮) - **CH395F:** SPI2 (PB12 CS, PB13 SCK, PB14 SDO, PB15 SDI) +- **GD5F2GQ5UE:** SPI1 (PE0 CS, PB3 SCK, PB4 MISO, PB5 MOSI, PB8 WP, PE1 HOLD) +- **TPAFE5160:** 并行16位 (PG0-PG15 数据, PD3 RD, PD4 CONVST, PD7 BUSY, PD1 FRSTDATA, PF13-15 OS[2:0]) - **USART1:** PA9 TX, PA10 RX (115200bps) ## 启动顺序 ``` -HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() → MX_SPI2_Init() → ch395f_reset() → ch395f_init() +HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() → MX_SPI2_Init() → MX_SPI1_Init() → gd5f2gq5ue_init() → fdb_kvdb_init() ``` ## 代码规范 @@ -43,13 +75,54 @@ HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() - 命名:小写字母+下划线;全局变量 `g_` 前缀,静态 `s_`,指针 `p_`,数组 `a_` - 函数注释块需包含:函数功能、入口参数、返回值、限定条件、函数说明 - 大括号:K&R 风格(左大括号不换行) +- 文件头注释:模块名称、功能、平台、作者、日期、修改记录 +- 头文件保护宏:`__MODULE_NAME_H` 格式,带 `extern "C"` ## 注意 -- `Inc/` 和 `Src/` 中 CubeMX 生成的文件(gpio, spi, usart, stm32f4xx_it, main 的骨架)带有 `USER CODE BEGIN`/`END` 标记,自定义代码应写在这些区域之间以免被 CubeMX 重新生成时覆盖 -- `ch395f.c`/`ch395f.h` 为纯手工代码,不受 CubeMX 保护 +- `Inc/` 和 `Src/` 中 CubeMX 生成的文件带有 `USER CODE BEGIN`/`END` 标记,自定义代码应写在这些区域之间 +- `ch395f.c/h`、`gd5f2gq5ue.c/h`、`fal_flash_gd5f2gq5ue.c` 为纯手工代码,不受 CubeMX 保护 +- `tpafe5160.c/h` 为纯手工代码,不受 CubeMX 保护 +- CH395F 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹 +- GD5F2GQ5UE 的 `gd5f2gq5ue.c` 中声明了 `extern SPI_HandleTypeDef hspi1`,需确保 SPI1 已初始化 +- FlashDB 使用 FAL 模式,`fdb_cfg.h` 中定义 `FDB_USING_FAL_MODE`,`fal_cfg.h` 中定义分区表 +- FlashDB 详细使用说明见 `FlashDB使用说明.md` +- `sd2506.c/h` 为纯手工代码,不受 CubeMX 保护 + +## CH395F 驱动关键点 + +- 初始化必须按手册9.2.1节顺序:`SET_MAC` → `SET_IP/GWIP/MASK` → `INIT_CH395` → `SET_PHY` +- **IP/网关/掩码必须在 `INIT_CH395` 之前设置**,INIT 会读取并锁定当前寄存器值到协议栈,之后再设 IP 无效 +- **`SET_PHY` 必须在 `INIT_CH395` 之后**,它会复位 MAC/PHY 建立物理链路,不影响已锁定的协议栈参数 +- **`CMD_PING_ENABLE` 不需要显式调用**,INIT 后默认可用 - 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹 -- CH395F 命令执行时序参考 `ch395f.h` 中命令码注释及 `CH395F.md` + +## GD5F2GQ5UE 驱动关键点 + +- SPI Mode 0(CPOL=0, CPHA=0),时钟 42MHz +- 初始化必须按顺序:复位 → 读 ID → 使能 ECC(B0h=10h)→ 解除块保护(A0h=00h) +- SET_FEATURE 命令前必须先发写使能(06h) +- 块擦除(D8h)参数是字节地址(块编号 × 128KB),不是块编号 +- 读取 ID(9Fh)返回 3 字节,第 0 字节无意义,第 1 字节 MID,第 2 字节 DID + +## FlashDB 分区规划 + +| 分区名 | 偏移 | 大小 | 用途 | +|--------|------|------|------| +| fdb_kvdb1 | 0 | 64MB | KVDB 键值数据库 | +| fdb_tsdb1 | 64MB | 64MB | TSDB 时序数据库 | + +## TPAFE5160 驱动关键点 + +- AD7606 P2P 兼容替代品,并行接口协议一致 +- 并行模式:CS 接地(始终选中),PAR/SER/BYTE SEL 接 GND(并行),DB15/BYTE SEL 接 GND(非字节模式) +- 数据总线 DB[15:0] 接 GPIOG[15:0],通过 `(uint16_t)GPIOG->IDR` 一次读取16位 +- CONVST 上升沿触发全部8通道同步采样,BUSY 高电平表示转换中 +- RD 下降沿输出通道数据,按通道1~8顺序依次输出 +- FRSTDATA 在第一个 RD 下降沿变高,指示通道1数据就绪 +- 过采样 OS[2:0] 在 BUSY 下降沿锁存,无过采样时 tCONV=1.74µs,64倍过采样时 tCONV=167µs +- 读取时序:168MHz 下 GPIO 写操作 + 5个 NOP (~30ns) 覆盖 t10=22ns 和 t14=21ns 要求 +- 硬件 RANGE 接 GND → ±5V 量程,LSB=152.59µV ## 已知问题 @@ -57,11 +130,4 @@ HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() CH395F 与 RTL8305NBI-CG 直连(经网络变压器)时,自动协商始终失败(返回 `PHY_DISCONN`),但强制 100M 全双工工作正常。强制 10M 全双工同样失败。 -**诊断结果:** -- Auto-Neg: `0x01 (DISCONNECTED)` -- Force 100M-FULL: `0x08 (LINK OK)` -- Force 10M-FULL: `0x01 (DISCONNECTED)` - **解决方案:** 初始化协议栈后调用 `ch395f_set_phy(CH395F_PHY_100M_FULL)` 跳过自动协商。 - -**推测根因:** 不同厂家 PHY 直连时的自动协商实现差异(CH395F WCH 固件 vs RTL8305NBI Realtek 硬件),物理层正常。 diff --git a/Drivers/BSP/CH395F/ch395f.c b/Drivers/BSP/CH395F/ch395f.c index 38f28fa..44fd117 100644 --- a/Drivers/BSP/CH395F/ch395f.c +++ b/Drivers/BSP/CH395F/ch395f.c @@ -493,6 +493,27 @@ void ch395f_set_phy(uint8_t phystat) ch395f_spi_end(); } +/* + * 函数功能:使能/关闭 CH395 响应 PING + * 入口参数:enable - 1 使能 PING 响应,0 关闭 + * 限定条件:芯片已初始化 + * 函数说明:手册 5.37 CMD_PING_ENABLE,默认关闭 + */ +void ch395f_ping_enable(uint8_t enable) +{ + /* 开始 SPI 事务 */ + ch395f_spi_begin(); + + /* 发送 PING 使能命令 */ + ch395f_write_cmd(CH395F_CMD_PING_ENABLE); + + /* 发送使能标志 */ + ch395f_write_data(enable); + + /* 结束 SPI 事务 */ + ch395f_spi_end(); +} + /* * 函数功能:启用/禁用 DHCP * 入口参数:enable - 1 启用,0 禁用 uint8_t diff --git a/Drivers/BSP/CH395F/ch395f.h b/Drivers/BSP/CH395F/ch395f.h index bf008f5..f965ad6 100644 --- a/Drivers/BSP/CH395F/ch395f.h +++ b/Drivers/BSP/CH395F/ch395f.h @@ -350,6 +350,14 @@ uint8_t ch395f_get_phy_status(void); */ void ch395f_set_phy(uint8_t phystat); +/* + * 函数功能:使能/关闭 CH395 响应 PING + * 入口参数:enable - 1 使能 PING 响应,0 关闭 + * 限定条件:芯片已初始化 + * 函数说明:手册 5.37 CMD_PING_ENABLE,默认关闭 + */ +void ch395f_ping_enable(uint8_t enable); + /* * 函数声明区 - DHCP */ diff --git a/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h b/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h index 4b07ac1..c9769b7 100644 --- a/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h +++ b/Drivers/BSP/GD5F2GQ5UE/fal_cfg.h @@ -1,35 +1,51 @@ -/** - ****************************************************************************** - * @file fal_cfg.h - * @brief FAL 配置:Flash 设备表 + 分区表 - ****************************************************************************** - */ +#ifndef __FAL_CFG_H +#define __FAL_CFG_H -#ifndef _FAL_CFG_H_ -#define _FAL_CFG_H_ +/* + * 模块名称:FAL 配置 + * 模块功能:定义 FAL Flash 设备表和分区表 + * 适用平台:STM32F407ZGT6 + * 作者:王建锋 + * 创建日期:2026-07-16 + * 修改记录: + * 2026-07-16 王建锋 创建初始版本 + */ +#ifdef __cplusplus +extern "C" { +#endif + +/* FAL 调试开关:0-关闭,1-开启 */ #define FAL_DEBUG 0 +/* 启用分区表配置 */ #define FAL_PART_HAS_TABLE_CFG -/* ===================== Flash 设备表 ===================== */ +/* ======================== Flash 设备表 ======================== */ + extern const struct fal_flash_dev gd5f2gq5ue_flash; -#define FAL_FLASH_DEV_TABLE \ -{ \ - &gd5f2gq5ue_flash, \ +#define FAL_FLASH_DEV_TABLE \ +{ \ + &gd5f2gq5ue_flash, \ } -/* ===================== 分区表 ===================== */ -/* 分区名称 设备名称 偏移 大小 */ -/* KVDB: 64MB @ 0 */ -/* TSDB: 64MB @ 64MB */ +/* ======================== 分区表 ======================== */ +/* + * 分区名称 设备名称 偏移 大小 + * KVDB: 64MB @ 0 + * TSDB: 64MB @ 64MB + */ #ifdef FAL_PART_HAS_TABLE_CFG -#define FAL_PART_TABLE \ -{ \ - {FAL_PART_MAGIC_WORD, "fdb_kvdb1", "gd5f2gq5ue", 0, 64*1024*1024, 0}, \ - {FAL_PART_MAGIC_WORD, "fdb_tsdb1", "gd5f2gq5ue", 64*1024*1024, 64*1024*1024, 0}, \ +#define FAL_PART_TABLE \ +{ \ + {FAL_PART_MAGIC_WORD, "fdb_kvdb1", "gd5f2gq5ue", 0, 64*1024*1024, 0}, \ + {FAL_PART_MAGIC_WORD, "fdb_tsdb1", "gd5f2gq5ue", 64*1024*1024, 64*1024*1024, 0}, \ } #endif -#endif /* _FAL_CFG_H_ */ +#ifdef __cplusplus +} +#endif + +#endif /* __FAL_CFG_H */ diff --git a/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c index ff3ec9e..cbb93d1 100644 --- a/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c @@ -1,42 +1,80 @@ -/** - ****************************************************************************** - * @file fal_flash_gd5f2gq5ue.c - * @brief FAL 端口:GD5F2GQ5UE SPI NAND Flash 适配层 - ****************************************************************************** - */ +/* + * 模块名称:FAL Flash 设备适配 + * 模块功能:将 GD5F2GQ5UE 驱动接口适配到 FAL 框架 + * 适用平台:STM32F407ZGT6 + * 作者:王建锋 + * 创建日期:2026-07-16 + * 修改记录: + * 2026-07-16 王建锋 创建初始版本 + */ +/* 头文件包含区 */ #include "fal_def.h" #include "gd5f2gq5ue.h" -/* ===================== FAL Flash 设备操作函数 ===================== */ +/* ======================== FAL 操作函数适配 ======================== */ +/* + * 函数功能:Flash 设备初始化适配 + * 入口参数:无 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:SPI 和 GPIO 已由 CubeMX 初始化完成 + * 函数说明:调用底层驱动的初始化函数 + */ static int gd5f_fal_init(void) { return gd5f2gq5ue_init(); } -static int gd5f_fal_read(long offset, uint8_t *buf, size_t size) +/* + * 函数功能:Flash 读取适配 + * 入口参数:offset - 起始字节偏移 long + * p_buf - 数据缓冲区 uint8_t* + * size - 读取字节数 size_t + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f_fal_init() 已成功调用 + * 函数说明:直接转发到底层驱动的读取函数 + */ +static int gd5f_fal_read(long offset, uint8_t *p_buf, size_t size) { - return gd5f2gq5ue_read(offset, buf, size); + return gd5f2gq5ue_read(offset, p_buf, size); } -static int gd5f_fal_write(long offset, const uint8_t *buf, size_t size) +/* + * 函数功能:Flash 写入适配 + * 入口参数:offset - 起始字节偏移 long + * p_buf - 数据缓冲区 const uint8_t* + * size - 写入字节数 size_t + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:目标区域已擦除 + * 函数说明:直接转发到底层驱动的写入函数 + */ +static int gd5f_fal_write(long offset, const uint8_t *p_buf, size_t size) { - return gd5f2gq5ue_write(offset, buf, size); + return gd5f2gq5ue_write(offset, p_buf, size); } +/* + * 函数功能:Flash 擦除适配 + * 入口参数:offset - 起始字节偏移 long + * size - 擦除字节数 size_t + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f_fal_init() 已成功调用 + * 函数说明:直接转发到底层驱动的擦除函数 + */ static int gd5f_fal_erase(long offset, size_t size) { return gd5f2gq5ue_erase(offset, size); } -/* ===================== FAL Flash 设备定义 ===================== */ +/* ======================== FAL Flash 设备定义 ======================== */ +/* GD5F2GQ5UE FAL 设备实例,总容量256MB,块大小128KB */ const struct fal_flash_dev gd5f2gq5ue_flash = { .name = "gd5f2gq5ue", .addr = 0, - .len = GD5F_TOTAL_SIZE, /* 256MB */ - .blk_size = GD5F_BLOCK_SIZE, /* 128KB */ + .len = GD5F_TOTAL_SIZE, + .blk_size = GD5F_BLOCK_SIZE, .ops = { .init = gd5f_fal_init, .read = gd5f_fal_read, diff --git a/Drivers/BSP/GD5F2GQ5UE/fdb_cfg.h b/Drivers/BSP/GD5F2GQ5UE/fdb_cfg.h index 3644272..62075b5 100644 --- a/Drivers/BSP/GD5F2GQ5UE/fdb_cfg.h +++ b/Drivers/BSP/GD5F2GQ5UE/fdb_cfg.h @@ -1,20 +1,25 @@ -/** - ****************************************************************************** - * @file fdb_cfg.h - * @brief FlashDB 配置文件 - ****************************************************************************** - */ +#ifndef __FDB_CFG_H +#define __FDB_CFG_H -#ifndef _FDB_CFG_H_ -#define _FDB_CFG_H_ +/* + * 模块名称:FlashDB 配置 + * 模块功能:配置 FlashDB 数据库功能开关和参数 + * 适用平台:STM32F407ZGT6 + * 作者:王建锋 + * 创建日期:2026-07-16 + * 修改记录: + * 2026-07-16 王建锋 创建初始版本 + */ + +#ifdef __cplusplus +extern "C" { +#endif /* 启用 KVDB(键值数据库) */ #define FDB_USING_KVDB -#ifdef FDB_USING_KVDB -/* 当 KVDB 版本号变化时自动更新到最新默认值 */ +/* KVDB 版本号变化时自动更新到最新默认值(默认关闭) */ /* #define FDB_KV_AUTO_UPDATE */ -#endif /* 启用 TSDB(时序数据库) */ #define FDB_USING_TSDB @@ -22,11 +27,14 @@ /* 使用 FAL 存储模式(非文件模式) */ #define FDB_USING_FAL_MODE -/* Flash 写入粒度(单位:bit) - * STM32F4 = 8(字节可编程) */ -#define FDB_WRITE_GRAN 8 +/* Flash 写入粒度,单位:bit,STM32F4 字节可编程 = 8 */ +#define FDB_WRITE_GRAN 8 -/* 调试输出 */ -#define FDB_DEBUG_ENABLE +/* 调试输出使能 */ +/*#define FDB_DEBUG_ENABLE*/ -#endif /* _FDB_CFG_H_ */ +#ifdef __cplusplus +} +#endif + +#endif /* __FDB_CFG_H */ diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c index 9e66c38..44f6985 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c @@ -1,350 +1,450 @@ -/** - ****************************************************************************** - * @file gd5f2gq5ue.c - * @brief GD5F2GQ5UE SPI NAND Flash 驱动实现 - ****************************************************************************** - */ +/* + * 模块名称:GD5F2GQ5UE SPI NAND Flash 驱动 + * 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口 + * 适用平台:STM32F407ZGT6 + SPI1 硬件 SPI + * 作者:王建锋 + * 创建日期:2026-07-16 + * 修改记录: + * 2026-07-16 王建锋 创建初始版本 + * 2026-07-17 王建锋 切换硬件 SPI,修正擦除地址,参考 NuttX 驱动 + */ +/* 头文件包含区 */ #include "gd5f2gq5ue.h" #include +/* 私有宏定义区 */ +#define GD5F_SPI_TIMEOUT 100 + +/* 外部 SPI 句柄声明 */ extern SPI_HandleTypeDef hspi1; -/* ===================== 内部辅助函数 ===================== */ +/* ======================== 私有函数声明 ======================== */ -/** - * @brief SPI 发送/接收单字节 - */ -static uint8_t gd5f_spi_xfer(uint8_t tx) -{ - uint8_t rx; - HAL_SPI_TransmitReceive(&hspi1, &tx, &rx, 1, 100); - return rx; -} +static int gd5f_wait_busy(uint32_t timeout_ms); +static int gd5f_write_enable(void); +static int gd5f_read_status(uint8_t *p_status); +static int gd5f_page_read(uint32_t page_addr); +static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, + size_t size); +static int gd5f_page_program(uint32_t page_addr, uint16_t column, + const uint8_t *p_buf, size_t size); +static int gd5f_set_feature(uint8_t addr, uint8_t data); +static int gd5f_block_erase(uint32_t block_addr); -/** - * @brief SPI 发送缓冲区 - */ -static void gd5f_spi_tx(const uint8_t *buf, size_t len) -{ - HAL_SPI_Transmit(&hspi1, (uint8_t *)buf, len, 100); -} +/* ======================== 私有函数定义 ======================== */ -/** - * @brief SPI 接收缓冲区 - */ -static void gd5f_spi_rx(uint8_t *buf, size_t len) -{ - HAL_SPI_Receive(&hspi1, buf, len, 100); -} - -/** - * @brief 等待操作完成(OIP 位清零) - * @param timeout_ms: 超时时间(毫秒) - * @retval GD5F_OK 成功, GD5F_BUSY_TIMEOUT 超时 +/* + * 函数功能:等待芯片操作完成(轮询 OIP 位) + * 入口参数:timeout_ms - 超时时间 uint32_t > 0 + * 返回值:0 - 操作完成,-2 - 超时 + * 限定条件:SPI 已初始化 + * 函数说明:循环读取状态寄存器直到 OIP 位清零或超时 */ static int gd5f_wait_busy(uint32_t timeout_ms) { uint8_t cmd = GD5F_CMD_GET_FEATURE; uint8_t addr = GD5F_REG_STATUS; - uint8_t status; - uint32_t tickstart = HAL_GetTick(); + uint8_t status = 0; + uint32_t tick_start = HAL_GetTick(); while (1) { GD5F_CS_LOW(); - gd5f_spi_tx(&cmd, 1); - gd5f_spi_tx(&addr, 1); - gd5f_spi_rx(&status, 1); + HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT); + HAL_SPI_Transmit(&hspi1, &addr, 1, GD5F_SPI_TIMEOUT); + HAL_SPI_Receive(&hspi1, &status, 1, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); if ((status & GD5F_STATUS_OIP) == 0) { return GD5F_OK; } - - if ((HAL_GetTick() - tickstart) >= timeout_ms) { + if ((HAL_GetTick() - tick_start) >= timeout_ms) { return GD5F_BUSY_TIMEOUT; } } } -/** - * @brief 写使能 +/* + * 函数功能:发送写使能命令 + * 入口参数:无 + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:CS# 拉低后发送 06h 命令再拉高 */ static int gd5f_write_enable(void) { uint8_t cmd = GD5F_CMD_WRITE_ENABLE; + GD5F_CS_LOW(); - gd5f_spi_tx(&cmd, 1); + HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); + return GD5F_OK; } -/** - * @brief 读取状态寄存器 +/* + * 函数功能:读取状态寄存器 + * 入口参数:p_status - 状态值输出指针 uint8_t* 不为 NULL + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:发送 0Fh + C0h 地址后读取1字节状态值 */ -static int gd5f_read_status(uint8_t *status) +static int gd5f_read_status(uint8_t *p_status) { uint8_t cmd = GD5F_CMD_GET_FEATURE; uint8_t addr = GD5F_REG_STATUS; + GD5F_CS_LOW(); - gd5f_spi_tx(&cmd, 1); - gd5f_spi_tx(&addr, 1); - gd5f_spi_rx(status, 1); + HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT); + HAL_SPI_Transmit(&hspi1, &addr, 1, GD5F_SPI_TIMEOUT); + HAL_SPI_Receive(&hspi1, p_status, 1, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); + return GD5F_OK; } -/** - * @brief 页读取到缓存(Page Read to Cache) - * @param page_addr: 页地址(行地址,包含 block + page) +/* + * 函数功能:页读取(将数据从存储阵列加载到内部缓存) + * 入口参数:page_addr - 页地址 uint32_t + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:SPI 已初始化 + * 函数说明:发送 13h + 3字节行地址,等待 OIP 清零 */ static int gd5f_page_read(uint32_t page_addr) { uint8_t cmd[4]; + cmd[0] = GD5F_CMD_PAGE_READ; cmd[1] = (page_addr >> 16) & 0xFF; cmd[2] = (page_addr >> 8) & 0xFF; cmd[3] = page_addr & 0xFF; GD5F_CS_LOW(); - gd5f_spi_tx(cmd, 4); + HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); return gd5f_wait_busy(100); } -/** - * @brief 从缓存读取数据(Read from Cache) - * @param column: 列地址(页内偏移) - * @param buf: 数据缓冲区 - * @param size: 读取字节数 +/* + * 函数功能:从内部缓存读取数据 + * 入口参数:column - 列地址(页内偏移) uint16_t 0 - 2047 + * p_buf - 数据输出缓冲区 uint8_t* 不为 NULL + * size - 读取字节数 size_t > 0 + * 返回值:0 - 成功 + * 限定条件:必须先调用 gd5f_page_read 完成数据加载 + * 函数说明:发送 0Bh + 2字节列地址 +1字节 dummy 后读取数据 */ -static int gd5f_read_from_cache(uint16_t column, uint8_t *buf, size_t size) +static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, + size_t size) { - uint8_t cmd[5]; + uint8_t cmd[4]; + cmd[0] = GD5F_CMD_READ_FROM_CACHE; cmd[1] = (column >> 8) & 0xFF; cmd[2] = column & 0xFF; - cmd[3] = 0x00; /* dummy byte */ + cmd[3] = 0x00; GD5F_CS_LOW(); - gd5f_spi_tx(cmd, 4); - gd5f_spi_rx(buf, size); + HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT); + HAL_SPI_Receive(&hspi1, p_buf, size, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); return GD5F_OK; } -/** - * @brief 页编程(从缓存写入阵列) - * @param page_addr: 页地址 - * @param column: 列地址 - * @param buf: 数据缓冲区 - * @param size: 写入字节数 +/* + * 函数功能:页编程(将数据写入指定页) + * 入口参数:page_addr - 页地址 uint32_t + * column - 列地址 uint16_t 0 - 2047 + * p_buf - 数据缓冲区 const uint8_t* + * size - 写入字节数 size_t > 0 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:目标区域已擦除 + * 函数说明:1. 写使能 - 02h 加载数据 - 10h 执行编程 - 等待完成 + * 2. 编程完成后检查 P_FAIL 位 */ -static int gd5f_page_program(uint32_t page_addr, uint16_t column, const uint8_t *buf, size_t size) +static int gd5f_page_program(uint32_t page_addr, uint16_t column, + const uint8_t *p_buf, size_t size) { - int ret; + int ret = GD5F_OK; uint8_t cmd[4]; + uint8_t status = 0; - /* 1. 写使能 */ gd5f_write_enable(); - /* 2. 数据加载到缓存 (Program Load) */ cmd[0] = GD5F_CMD_PROGRAM_LOAD; cmd[1] = (column >> 8) & 0xFF; cmd[2] = column & 0xFF; GD5F_CS_LOW(); - gd5f_spi_tx(cmd, 3); - gd5f_spi_tx(buf, size); + HAL_SPI_Transmit(&hspi1, cmd, 3, GD5F_SPI_TIMEOUT); + HAL_SPI_Transmit(&hspi1, (uint8_t *)p_buf, size, + GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); - /* 3. 编程执行 (Program Execute) */ cmd[0] = GD5F_CMD_PROGRAM_EXEC; cmd[1] = (page_addr >> 16) & 0xFF; cmd[2] = (page_addr >> 8) & 0xFF; cmd[3] = page_addr & 0xFF; GD5F_CS_LOW(); - gd5f_spi_tx(cmd, 4); + HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); - /* 4. 等待完成 */ ret = gd5f_wait_busy(1000); - if (ret != GD5F_OK) return ret; + if (ret != GD5F_OK) { + return ret; + } - /* 5. 检查编程结果 */ - uint8_t status; gd5f_read_status(&status); if (status & GD5F_STATUS_P_FAIL) { - /* 清除 P_FAIL:写使能 + 读状态 */ - gd5f_write_enable(); return GD5F_PROGRAM_FAIL; } return GD5F_OK; } -/** - * @brief 块擦除 - * @param block_addr: 块地址 (0 ~ 2047) +/* + * 函数功能:设置 Feature 寄存器 + * 入口参数:addr - 寄存器地址 uint8_t + * data - 写入数据 uint8_t + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:先写使能,发送 1Fh + 地址 + 数据,等待操作完成 + */ +static int gd5f_set_feature(uint8_t addr, uint8_t data) +{ + uint8_t cmd[3]; + + gd5f_write_enable(); + + cmd[0] = GD5F_CMD_SET_FEATURE; + cmd[1] = addr; + cmd[2] = data; + + GD5F_CS_LOW(); + HAL_SPI_Transmit(&hspi1, cmd, 3, GD5F_SPI_TIMEOUT); + GD5F_CS_HIGH(); + + gd5f_wait_busy(100); + + return GD5F_OK; +} + +/* + * 函数功能:块擦除(擦除128KB块) + * 入口参数:block_addr - 块编号 uint32_t 0 - 2047 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已调用 + * 函数说明:1. 写使能 - D8h + 3字节字节地址 - 等待完成 + * 2. 擦除完成后检查 E_FAIL 位 */ static int gd5f_block_erase(uint32_t block_addr) { - int ret; + int ret = GD5F_OK; uint8_t cmd[4]; + uint8_t status = 0; + uint32_t byte_addr = block_addr * GD5F_BLOCK_SIZE; - /* 1. 写使能 */ gd5f_write_enable(); - /* 2. 块擦除命令 */ cmd[0] = GD5F_CMD_BLOCK_ERASE; - cmd[1] = (block_addr >> 8) & 0xFF; - cmd[2] = block_addr & 0xFF; - cmd[3] = 0x00; + cmd[1] = (byte_addr >> 16) & 0xFF; + cmd[2] = (byte_addr >> 8) & 0xFF; + cmd[3] = byte_addr & 0xFF; GD5F_CS_LOW(); - gd5f_spi_tx(cmd, 4); + HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); - /* 3. 等待完成(擦除较慢) */ ret = gd5f_wait_busy(5000); - if (ret != GD5F_OK) return ret; + if (ret != GD5F_OK) { + return ret; + } - /* 4. 检查擦除结果 */ - uint8_t status; gd5f_read_status(&status); if (status & GD5F_STATUS_E_FAIL) { - gd5f_write_enable(); return GD5F_ERASE_FAIL; } return GD5F_OK; } -/* ===================== 公共接口实现 ===================== */ +/* ======================== 公共函数定义 ======================== */ +/* + * 函数功能:初始化 GD5F2GQ5UE + * 入口参数:无 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:SPI1 和相关 GPIO 已由 CubeMX 初始化完成 + * 函数说明:1. 发送复位命令并等待完成 + * 2. 读取芯片 ID 并校验 + * 3. 使能内部 ECC (B0h bit4) + * 4. 解除所有块保护 (A0h = 0x00) + */ int gd5f2gq5ue_init(void) { - int ret; - uint8_t mid, did; + int ret = GD5F_OK; + uint8_t mid = 0; + uint8_t did = 0; - /* 确保控制引脚处于非激活状态 */ GD5F_CS_HIGH(); GD5F_WP_HIGH(); GD5F_HOLD_HIGH(); - /* 小延时等待上电稳定 */ HAL_Delay(10); - /* 复位芯片 */ ret = gd5f2gq5ue_reset(); - if (ret != GD5F_OK) return ret; + if (ret != GD5F_OK) { + return ret; + } HAL_Delay(5); - /* 读取 ID 验证通信 */ ret = gd5f2gq5ue_read_id(&mid, &did); - if (ret != GD5F_OK) return ret; + if (ret != GD5F_OK) { + return ret; + } if (mid != GD5F_MANUFACTURER_ID || did != GD5F_DEVICE_ID) { return GD5F_ID_MISMATCH; } + gd5f_set_feature(0xB0, 0x10); + gd5f_wait_busy(100); + + gd5f_set_feature(GD5F_REG_PROTECT, 0x00); + gd5f_wait_busy(100); + return GD5F_OK; } +/* + * 函数功能:读取芯片 ID(MID + DID) + * 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL + * did - 设备 ID 输出指针 uint8_t* 不为 NULL + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID + */ int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did) { uint8_t cmd = GD5F_CMD_READ_ID; - uint8_t id_buf[3]; + uint8_t id_buf[3] = {0}; GD5F_CS_LOW(); - gd5f_spi_tx(&cmd, 1); - gd5f_spi_rx(id_buf, 3); /* dummy + MID + DID */ + HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT); + HAL_SPI_Receive(&hspi1, id_buf, 3, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); - *mid = id_buf[1]; /* id_buf[0] = dummy */ + *mid = id_buf[1]; *did = id_buf[2]; return GD5F_OK; } -int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size) +/* + * 函数功能:从 NAND 读取数据(支持跨页) + * 入口参数:offset - 起始字节偏移 long 0 ~ 总容量-1 + * p_buf - 数据缓冲区 uint8_t* 不为 NULL + * size - 读取字节数 size_t > 0 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已成功调用 + * 函数说明:自动处理跨页读取 + */ +int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size) { - int ret; + int ret = GD5F_OK; while (size > 0) { - /* 计算页地址和列偏移 */ uint32_t page_addr = offset / GD5F_PAGE_SIZE; uint16_t column = offset % GD5F_PAGE_SIZE; - - /* 本次读取字节数(不超过当前页剩余空间) */ size_t bytes = GD5F_PAGE_SIZE - column; - if (bytes > size) bytes = size; - /* Page Read to Cache */ + if (bytes > size) { + bytes = size; + } + ret = gd5f_page_read(page_addr); - if (ret != GD5F_OK) return ret; + if (ret != GD5F_OK) { + return ret; + } - /* Read from Cache */ - ret = gd5f_read_from_cache(column, buf, bytes); - if (ret != GD5F_OK) return ret; + ret = gd5f_read_from_cache(column, p_buf, bytes); + if (ret != GD5F_OK) { + return ret; + } offset += bytes; - buf += bytes; + p_buf += bytes; size -= bytes; } return GD5F_OK; } -int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size) +/* + * 函数功能:向 NAND 写入数据(支持跨页) + * 入口参数:offset - 起始字节偏移 long 0 ~ 总容量-1 + * p_buf - 数据缓冲区 const uint8_t* 不为 NULL + * size - 写入字节数 size_t > 0 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已成功调用,目标区域已擦除 + * 函数说明:自动处理跨页写入 + */ +int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size) { - int ret; + int ret = GD5F_OK; while (size > 0) { - /* 计算页地址和列偏移 */ uint32_t page_addr = offset / GD5F_PAGE_SIZE; uint16_t column = offset % GD5F_PAGE_SIZE; - - /* 本次写入字节数(不超过当前页剩余空间) */ size_t bytes = GD5F_PAGE_SIZE - column; - if (bytes > size) bytes = size; - /* 页编程 */ - ret = gd5f_page_program(page_addr, column, buf, bytes); - if (ret != GD5F_OK) return ret; + if (bytes > size) { + bytes = size; + } + + ret = gd5f_page_program(page_addr, column, p_buf, bytes); + if (ret != GD5F_OK) { + return ret; + } offset += bytes; - buf += bytes; + p_buf += bytes; size -= bytes; } return GD5F_OK; } +/* + * 函数功能:擦除块(按块擦除,最小单位 128KB) + * 入口参数:offset - 起始字节偏移 long 必须块对齐 + * size - 擦除字节数 size_t 必须块大小整数倍 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已成功调用 + * 函数说明:擦除操作以块为单位 + */ int gd5f2gq5ue_erase(long offset, size_t size) { - int ret; + int ret = GD5F_OK; - /* 擦除起始地址必须块对齐 */ if (offset % GD5F_BLOCK_SIZE != 0) { return GD5F_ERROR; } - - /* 擦除大小必须为块大小的整数倍 */ if (size % GD5F_BLOCK_SIZE != 0) { return GD5F_ERROR; } - /* 逐块擦除 */ while (size > 0) { uint32_t block_addr = offset / GD5F_BLOCK_SIZE; ret = gd5f_block_erase(block_addr); - if (ret != GD5F_OK) return ret; + if (ret != GD5F_OK) { + return ret; + } offset += GD5F_BLOCK_SIZE; size -= GD5F_BLOCK_SIZE; @@ -353,12 +453,19 @@ int gd5f2gq5ue_erase(long offset, size_t size) return GD5F_OK; } +/* + * 函数功能:复位芯片 + * 入口参数:无 + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:发送 FFh 复位命令后等待 5ms + */ int gd5f2gq5ue_reset(void) { uint8_t cmd = GD5F_CMD_RESET; GD5F_CS_LOW(); - gd5f_spi_tx(&cmd, 1); + HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); HAL_Delay(5); diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h index ba9eb93..9fdc309 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h @@ -1,75 +1,70 @@ -/** - ****************************************************************************** - * @file gd5f2gq5ue.h - * @brief GD5F2GQ5UE SPI NAND Flash 驱动头文件 - ****************************************************************************** - */ - #ifndef __GD5F2GQ5UE_H #define __GD5F2GQ5UE_H +/* + * 模块名称:GD5F2GQ5UE SPI NAND Flash 驱动 + * 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口 + * 适用平台:STM32F407ZGT6 + SPI1 硬件 SPI + * 作者:王建锋 + * 创建日期:2026-07-16 + * 修改记录: + * 2026-07-16 王建锋 创建初始版本 + * 2026-07-17 王建锋 切换为硬件 SPI,修正擦除地址,参考 NuttX 驱动 + */ + #ifdef __cplusplus extern "C" { #endif #include "main.h" -#include "spi.h" -/* ===================== 硬件引脚定义 ===================== */ -#define GD5F_CS_LOW() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_RESET) -#define GD5F_CS_HIGH() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_SET) -#define GD5F_WP_HIGH() HAL_GPIO_WritePin(GD_WP_GPIO_Port, GD_WP_Pin, GPIO_PIN_SET) -#define GD5F_HOLD_HIGH() HAL_GPIO_WritePin(GD_HOLD_GPIO_Port, GD_HOLD_Pin, GPIO_PIN_SET) +/* ======================== 宏定义 ======================== */ -/* ===================== SPI 命令码 ===================== */ +/* SPI 命令码 */ #define GD5F_CMD_WRITE_ENABLE 0x06 #define GD5F_CMD_WRITE_DISABLE 0x04 #define GD5F_CMD_GET_FEATURE 0x0F #define GD5F_CMD_SET_FEATURE 0x1F #define GD5F_CMD_READ_ID 0x9F #define GD5F_CMD_PAGE_READ 0x13 -#define GD5F_CMD_READ_FROM_CACHE 0x0B /* Fast Read, 1 dummy byte */ +#define GD5F_CMD_READ_FROM_CACHE 0x0B #define GD5F_CMD_PROGRAM_LOAD 0x02 #define GD5F_CMD_PROGRAM_EXEC 0x10 #define GD5F_CMD_BLOCK_ERASE 0xD8 #define GD5F_CMD_RESET 0xFF -/* ===================== 寄存器地址 ===================== */ -#define GD5F_REG_STATUS 0xC0 +/* 寄存器地址 */ #define GD5F_REG_PROTECT 0xA0 #define GD5F_REG_FEATURE 0xB0 +#define GD5F_REG_STATUS 0xC0 #define GD5F_REG_DRIVER 0xD0 -/* ===================== 状态位定义 ===================== */ -#define GD5F_STATUS_OIP (1 << 0) /* 操作进行中 */ -#define GD5F_STATUS_WEL (1 << 1) /* 写使能锁存 */ -#define GD5F_STATUS_E_FAIL (1 << 2) /* 擦除失败 */ -#define GD5F_STATUS_P_FAIL (1 << 3) /* 编程失败 */ -#define GD5F_STATUS_BIT4 (1 << 4) -#define GD5F_STATUS_ECCS0 (1 << 5) -#define GD5F_STATUS_ECCS1 (1 << 6) -#define GD5F_STATUS_ECCSE0 (1 << 4) /* ECC 单 bit 错误低位 */ -#define GD5F_STATUS_ECCSE1 (1 << 5) /* ECC 单 bit 错误高位 */ -#define GD5F_STATUS_ECCSE2 (1 << 6) /* ECC 单 bit 错误高位 */ +/* 状态位定义 */ +#define GD5F_STATUS_OIP (1 << 0) +#define GD5F_STATUS_WEL (1 << 1) +#define GD5F_STATUS_E_FAIL (1 << 2) +#define GD5F_STATUS_P_FAIL (1 << 3) +#define GD5F_STATUS_ECCS0 (1 << 4) +#define GD5F_STATUS_ECCS1 (1 << 5) -/* ===================== Feature 位定义 ===================== */ +/* Feature 位定义 */ #define GD5F_FEATURE_ECC_EN (1 << 4) -#define GD5F_FEATURE_QE (1 << 0) /* Quad Enable, B0[0] */ +#define GD5F_FEATURE_QE (1 << 0) -/* ===================== 芯片参数 ===================== */ -#define GD5F_PAGE_SIZE 2048 /* 主数据区字节数 */ -#define GD5F_SPARE_SIZE 64 /* ECC 启用时 spare 区 */ -#define GD5F_TOTAL_PAGE_SIZE 2112 /* 2048 + 64 */ +/* 芯片参数 */ +#define GD5F_PAGE_SIZE 2048 +#define GD5F_SPARE_SIZE 64 +#define GD5F_TOTAL_PAGE_SIZE 2112 #define GD5F_PAGES_PER_BLOCK 64 -#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) /* 128KB */ +#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) #define GD5F_TOTAL_BLOCKS 2048 -#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE) /* 256MB */ +#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE) /* 制造商 ID 和设备 ID */ #define GD5F_MANUFACTURER_ID 0xC8 #define GD5F_DEVICE_ID 0x52 -/* ===================== 返回值定义 ===================== */ +/* 返回值定义 */ #define GD5F_OK 0 #define GD5F_ERROR -1 #define GD5F_BUSY_TIMEOUT -2 @@ -78,51 +73,74 @@ extern "C" { #define GD5F_ERASE_FAIL -5 #define GD5F_ID_MISMATCH -6 -/* ===================== 公共接口函数 ===================== */ +/* 控制引脚宏 */ +#define GD5F_CS_LOW() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_RESET) +#define GD5F_CS_HIGH() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_SET) +#define GD5F_WP_HIGH() HAL_GPIO_WritePin(GD_WP_GPIO_Port, GD_WP_Pin, GPIO_PIN_SET) +#define GD5F_HOLD_HIGH() HAL_GPIO_WritePin(GD_HOLD_GPIO_Port, GD_HOLD_Pin, GPIO_PIN_SET) -/** - * @brief 初始化 GD5F2GQ5UE(SPI + GPIO + 读 ID 验证) - * @retval GD5F_OK 成功, 其他为错误码 +/* ======================== 函数声明 ======================== */ + +/* + * 函数功能:初始化 GD5F2GQ5UE(读 ID + 使能 ECC + 解除块保护) + * 入口参数:无 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:SPI1 和相关 GPIO 已由 CubeMX 初始化完成 + * 函数说明:1. 发送复位命令并等待完成 + * 2. 读取芯片 ID 并校验 + * 3. 使能内部 ECC (B0h bit4) + * 4. 解除所有块保护 (A0h = 0x00) */ int gd5f2gq5ue_init(void); -/** - * @brief 读取芯片 ID(MID + DID) - * @param mid: 制造商 ID 输出指针 - * @param did: 设备 ID 输出指针 - * @retval GD5F_OK 成功 +/* + * 函数功能:读取芯片 ID(MID + DID) + * 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL + * did - 设备 ID 输出指针 uint8_t* 不为 NULL + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID */ int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did); -/** - * @brief 从 NAND 读取数据(支持跨页) - * @param offset: 起始字节偏移(相对于 Flash 起始地址) - * @param buf: 数据缓冲区 - * @param size: 读取字节数 - * @retval GD5F_OK 成功 +/* + * 函数功能:从 NAND 读取数据(支持跨页) + * 入口参数:offset - 起始字节偏移 long 0 - GD5F_TOTAL_SIZE-1 + * buf - 数据缓冲区 uint8_t* 不为 NULL + * size - 读取字节数 size_t > 0 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已成功调用 + * 函数说明:自动处理跨页读取,每次读取不超过当前页剩余空间 */ int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size); -/** - * @brief 向 NAND 写入数据(支持跨页) - * @param offset: 起始字节偏移 - * @param buf: 数据缓冲区 - * @param size: 写入字节数 - * @retval GD5F_OK 成功 +/* + * 函数功能:向 NAND 写入数据(支持跨页) + * 入口参数:offset - 起始字节偏移 long 0 - GD5F_TOTAL_SIZE-1 + * buf - 数据缓冲区 uint8_t* 不为 NULL + * size - 写入字节数 size_t > 0 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已成功调用,目标区域已擦除 + * 函数说明:自动处理跨页写入,每次写入不超过当前页剩余空间 */ int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size); -/** - * @brief 擦除块(按块擦除,最小单位 128KB) - * @param offset: 起始字节偏移(必须块对齐) - * @param size: 擦除字节数(必须为块大小的整数倍) - * @retval GD5F_OK 成功 +/* + * 函数功能:擦除块(按块擦除,最小单位 128KB) + * 入口参数:offset - 起始字节偏移 long 必须 GD5F_BLOCK_SIZE 对齐 + * size - 擦除字节数 size_t 必须 GD5F_BLOCK_SIZE 整数倍 + * 返回值:0 - 成功,其他 - 错误码 + * 限定条件:gd5f2gq5ue_init() 已成功调用 + * 函数说明:擦除操作以块为单位,offset 和 size 必须块对齐 */ int gd5f2gq5ue_erase(long offset, size_t size); -/** - * @brief 复位芯片 - * @retval GD5F_OK 成功 +/* + * 函数功能:复位芯片 + * 入口参数:无 + * 返回值:0 - 成功 + * 限定条件:SPI 已初始化 + * 函数说明:发送 FFh 复位命令后等待 5ms */ int gd5f2gq5ue_reset(void); diff --git a/Drivers/BSP/RS485/rs485.c b/Drivers/BSP/RS485/rs485.c new file mode 100644 index 0000000..0ed85cb --- /dev/null +++ b/Drivers/BSP/RS485/rs485.c @@ -0,0 +1,133 @@ +/* + * 模块名称:RS-485 半双工通信驱动 + * 模块功能:RS-485 半双工通信驱动实现,核心要点: + * 1. 发送前拉高 DE(切换到发送态) + * 2. HAL_UART_Transmit 内部已等待 TC(发送完成)标志 + * 3. 发送完毕后拉低 DE(切回接收态) + * 4. 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收 + * 参考:ST AN3070 应用笔记、controllerstech.com RS485 教程 + * 适用平台:STM32F4 系列 + * 作者:王建锋 + * 创建日期:2026-07-18 + * 修改记录: + * 2026-07-18 王建锋 创建初始版本 + */ + +#include "rs485.h" + +/* + * 内部辅助宏 - 方向控制 + */ +#define RS485_DIR_TX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_SET) +#define RS485_DIR_RX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_RESET) + +/* + * 公共函数实现 + */ + +/* + * 函数功能:初始化 RS-485 句柄 + * 入口参数:handle - RS-485 句柄指针 + * huart - UART 外设句柄 + * dir_port - DE 引脚 GPIO 端口 + * dir_pin - DE 引脚 GPIO 编号 + * 返回值:无 + * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 + * 函数说明:初始化后立即将 DE 拉低,使 RS-485 收发器处于接收状态 + */ +void rs485_init(rs485_handle_t *handle, + UART_HandleTypeDef *huart, + GPIO_TypeDef *dir_port, + uint16_t dir_pin) +{ + handle->huart = huart; + handle->dir_port = dir_port; + handle->dir_pin = dir_pin; + handle->rx_size = 0; + + /* 默认进入接收状态 */ + RS485_DIR_RX(handle); +} + +/* + * 函数功能:阻塞方式发送数据 + * 入口参数:handle - RS-485 句柄指针 + * data - 待发送数据缓冲区 + * len - 待发送字节数 + * timeout - 发送超时(ms),传 0 使用默认值 + * 返回值:HAL_OK / HAL_TIMEOUT / HAL_ERROR + * 限定条件:须在主循环或 RTOS 任务中调用,不可在 UART 中断中调用 + * 函数说明: + * 时序:DE=HIGH → UART 发送 N 字节 → 等 TC → DE=LOW + * HAL_UART_Transmit 内部会等待 TXE(发送寄存器空)逐字节搬数据, + * 最后还会等待 TC(发送完成)标志,确保最后一字节的停止位已移出。 + * 因此返回后再拉低 DE 是安全的 + */ +HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle, + const uint8_t *data, + uint16_t len, + uint32_t timeout) +{ + HAL_StatusTypeDef status; + + if (timeout == 0U) { + timeout = RS485_TIMEOUT_DEFAULT; + } + + /* 1. 切换到发送状态 */ + RS485_DIR_TX(handle); + + /* 2. 阻塞发送(内部等待 TC) */ + status = HAL_UART_Transmit(handle->huart, + (uint8_t *)data, + len, + timeout); + + /* 3. 发送完毕或超时,切回接收状态 */ + RS485_DIR_RX(handle); + + return status; +} + +/* + * 函数功能:启动中断方式接收(IDLE 空闲帧检测) + * 入口参数:handle - RS-485 句柄指针 + * buf - 接收缓冲区 + * buf_size - 缓冲区最大容量 + * 返回值:HAL_OK / HAL_ERROR + * 限定条件:UART 须已开启全局中断(NVIC 使能) + * 函数说明: + * 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。 + * 当 UART 总线空闲超过 1 个字符时间后,硬件触发 IDLE 中断, + * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。 + * 用户须在该回调中重新调用本函数重新开启接收 + */ +HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle, + uint8_t *buf, + uint16_t buf_size) +{ + handle->rx_size = 0; + return HAL_UARTEx_ReceiveToIdle_IT(handle->huart, buf, buf_size); +} + +/* + * 函数功能:缓存最近一次接收的字节数 + * 入口参数:handle - RS-485 句柄指针 + * size - 本次接收到的字节数 + * 返回值:无 + * 限定条件:须在 HAL_UARTEx_RxEventCallback 中调用 + */ +void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size) +{ + handle->rx_size = size; +} + +/* + * 函数功能:获取最近一次接收的字节数 + * 入口参数:handle - RS-485 句柄指针 + * 返回值:字节数 + */ +uint16_t rs485_rx_get_size(const rs485_handle_t *handle) +{ + return handle->rx_size; +} diff --git a/Drivers/BSP/RS485/rs485.h b/Drivers/BSP/RS485/rs485.h new file mode 100644 index 0000000..b27fd76 --- /dev/null +++ b/Drivers/BSP/RS485/rs485.h @@ -0,0 +1,110 @@ +/* + * 模块名称:RS-485 半双工通信驱动 + * 模块功能:RS-485 半双工通信驱动,封装任意 UART 外设实现 485 方向控制, + * 提供阻塞发送、中断接收(IDLE 空闲帧检测)、DMA 发送等功能。 + * 参考 ST AN3070 应用笔记《IO-Link master: USART communication》 + * 及 controllerstech.com RS485 教程 + * 适用平台:STM32F4 系列 + * 作者:王建锋 + * 创建日期:2026-07-18 + * 修改记录: + * 2026-07-18 王建锋 创建初始版本 + */ + +#ifndef __RS485_H +#define __RS485_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "main.h" + +/* + * 常量定义 + */ +#define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时(ms) */ + +/* + * RS-485 句柄结构体 + * 将任意 UART + 任意 GPIO 组合绑定为一个 RS-485 半双工通信实例 + */ +typedef struct { + UART_HandleTypeDef *huart; /* UART 外设句柄 */ + GPIO_TypeDef *dir_port; /* 方向控制 GPIO 端口 */ + uint16_t dir_pin; /* 方向控制 GPIO 引脚号 */ + volatile uint16_t rx_size; /* 最近一次接收的字节数 */ +} rs485_handle_t; + +/* + * 公共函数声明 + */ + +/* + * 函数功能:初始化 RS-485 句柄,绑定 UART 和方向控制引脚 + * 入口参数:handle - RS-485 句柄指针 + * huart - UART 外设句柄指针(已由 CubeMX 初始化) + * dir_port - 方向控制 GPIO 端口(如 GPIOD) + * dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0) + * 返回值:无 + * 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化 + * 函数说明:初始化后默认处于接收状态(DE 引脚拉低) + */ +void rs485_init(rs485_handle_t *handle, + UART_HandleTypeDef *huart, + GPIO_TypeDef *dir_port, + uint16_t dir_pin); + +/* + * 函数功能:阻塞方式发送数据 + * 入口参数:handle - RS-485 句柄指针 + * data - 待发送数据缓冲区 + * len - 待发送字节数 + * timeout - 发送超时(ms),传 0 使用 RS485_TIMEOUT_DEFAULT + * 返回值:HAL_OK / HAL_TIMEOUT / HAL_ERROR + * 限定条件:在主循环或任务中调用,不可在 UART 中断中调用 + * 函数说明:发送前自动拉高 DE,发送完成后等待 TC 标志再拉低 DE, + * 确保最后一字节完全移出后再切换到接收状态 + */ +HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle, + const uint8_t *data, + uint16_t len, + uint32_t timeout); + +/* + * 函数功能:启动中断方式接收(IDLE 空闲帧检测) + * 入口参数:handle - RS-485 句柄指针 + * buf - 接收缓冲区 + * buf_size - 缓冲区大小 + * 返回值:HAL_OK / HAL_ERROR + * 限定条件:UART 须已开启全局中断,NVIC 中须使能对应 UART 中断 + * 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收, + * 收到完整帧后在 RxEventCallback 中通知用户。 + * 用户须在回调中重新调用本函数重新开启接收 + */ +HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle, + uint8_t *buf, + uint16_t buf_size); + +/* + * 函数功能:将 RS-485 句柄与 HAL 回调关联 + * 入口参数:handle - RS-485 句柄指针 + * 返回值:无 + * 限定条件:须在 HAL_UART_RxCpltCallback / HAL_UARTEx_RxEventCallback 中调用 + * 函数说明:将 HAL 回调中接收到的数据大小回写到句柄的 rx_size 字段 + */ +void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size); + +/* + * 函数功能:获取最近一次接收的字节数 + * 入口参数:handle - RS-485 句柄指针 + * 返回值:最近一次接收的字节数 + * 限定条件:须在 HAL_UARTEx_RxEventCallback 触发后调用 + */ +uint16_t rs485_rx_get_size(const rs485_handle_t *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* __RS485_H */ diff --git a/Drivers/BSP/SD2506/sd2506.c b/Drivers/BSP/SD2506/sd2506.c new file mode 100644 index 0000000..990fec5 --- /dev/null +++ b/Drivers/BSP/SD2506/sd2506.c @@ -0,0 +1,381 @@ +/* + * 模块名称:SD2506API-G RTC 实时时钟驱动 + * 模块功能:SD2506API-G 高精度温补实时时钟模块 I2C 驱动 + * 适用平台:STM32F407ZGT6,I2C1 接口 (PB6-SCL, PB7-SDA) + * 作者:王建锋 + * 创建日期:2026-07-17 + * 修改记录: + * 2026-07-17 王建锋 创建初始版本,参考 SD2506API-G Ver2.0 手册 + */ + +#include "sd2506.h" +#include "i2c.h" +#include + +extern I2C_HandleTypeDef hi2c1; + +/* ======================== 内部辅助函数 ======================== */ + +uint8_t sd2506_bcd_to_dec(uint8_t bcd) +{ + return ((bcd >> 4) * 10) + (bcd & 0x0FU); +} + +uint8_t sd2506_dec_to_bcd(uint8_t dec) +{ + return ((dec / 10) << 4) | (dec % 10); +} + +/* + * 写单字节寄存器 + * reg: 寄存器地址 (00H~79H) + * val: 写入值 + * 返回: 0=成功, -2=I2C错误 + */ +static int sd2506_write_reg(uint8_t reg, uint8_t val) +{ + if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg, + I2C_MEMADD_SIZE_8BIT, &val, 1, + SD2506_I2C_TIMEOUT_MS) != HAL_OK) { + return SD2506_I2C_ERROR; + } + return SD2506_OK; +} + +/* + * 读单字节寄存器 + * reg: 寄存器地址 (00H~79H) + * val: 读取值指针 + * 返回: 0=成功, -2=I2C错误 + */ +static int sd2506_read_reg(uint8_t reg, uint8_t *val) +{ + if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg, + I2C_MEMADD_SIZE_8BIT, val, 1, + SD2506_I2C_TIMEOUT_MS) != HAL_OK) { + return SD2506_I2C_ERROR; + } + return SD2506_OK; +} + +/* + * 写多字节寄存器 (从 reg 开始连续写入 len 字节) + * reg: 起始寄存器地址 + * data: 数据缓冲区 + * len: 数据长度 + * 返回: 0=成功, -2=I2C错误 + */ +static int sd2506_write_regs(uint8_t reg, const uint8_t *data, uint8_t len) +{ + if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg, + I2C_MEMADD_SIZE_8BIT, (uint8_t *)data, len, + SD2506_I2C_TIMEOUT_MS) != HAL_OK) { + return SD2506_I2C_ERROR; + } + return SD2506_OK; +} + +/* + * 读多字节寄存器 (从 reg 开始连续读取 len 字节) + * reg: 起始寄存器地址 + * data: 数据缓冲区 + * len: 数据长度 + * 返回: 0=成功, -2=I2C错误 + */ +static int sd2506_read_regs(uint8_t reg, uint8_t *data, uint8_t len) +{ + if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg, + I2C_MEMADD_SIZE_8BIT, data, len, + SD2506_I2C_TIMEOUT_MS) != HAL_OK) { + return SD2506_I2C_ERROR; + } + return SD2506_OK; +} + +/* + * 开启写保护 (允许写入 00H~71H 寄存器) + * 顺序: 先写 WRTC1=1, 再写 WRTC2=1 + WRTC3=1 + */ +static int sd2506_write_enable(void) +{ + int ret; + + /* 先置 WRTC1=1 (bit6=1), 其它位参考手册: 0x84 */ + ret = sd2506_write_reg(SD2506_REG_CTR1, 0x84U); + if (ret != SD2506_OK) return ret; + + /* 再置 WRTC2=1(bit5) + WRTC3=1(bit4): 0x8C */ + ret = sd2506_write_reg(SD2506_REG_CTR2, 0x8CU); + if (ret != SD2506_OK) return ret; + + return SD2506_OK; +} + +/* + * 关闭写保护 (禁止写入 00H~71H 寄存器) + * 顺序: 先写 WRTC2=0 + WRTC3=0, 再写 WRTC1=0 + */ +static int sd2506_write_disable(void) +{ + int ret; + + /* 先清 WRTC2=0, WRTC3=0: 0x00 */ + ret = sd2506_write_reg(SD2506_REG_CTR2, 0x00U); + if (ret != SD2506_OK) return ret; + + /* 再清 WRTC1=0, 同时 ARST=1 使能自动复位: 0x20 */ + ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF); + if (ret != SD2506_OK) return ret; + + return SD2506_OK; +} + +/* ======================== 公共 API 实现 ======================== */ + +int sd2506_init(void) +{ + int ret; + uint8_t id[8]; + + /* 验证 I2C 通信: 尝试读取 8 字节 ID */ + ret = sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE); + if (ret != SD2506_OK) { + return ret; + } + + /* 上电重置充电寄存器 18H = 82H (开启充电, 5K电阻) + * 手册强烈建议每次上电时重置此值 */ + ret = sd2506_write_reg(SD2506_REG_CHARGE, 0x82U); + if (ret != SD2506_OK) { + return ret; + } + + /* 配置: 24小时制, 自动复位使能 + * 0FH = 0x20 (bit5=ARST=1, 其它标志位清零) + * 写入时需注意: 写允许状态下 0FH 的 WRTC 位必须为1 + * 此处直接写入 0x20 即可 (ARST=1, 无 WRTC 位) */ + ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF); + if (ret != SD2506_OK) { + return ret; + } + + return SD2506_OK; +} + +int sd2506_set_time(const sd2506_time_t *time) +{ + int ret; + uint8_t buf[7]; + + if (time == NULL) { + return SD2506_ERROR; + } + + /* 组装 7 字节时间数据 (BCD 码) */ + buf[0] = sd2506_dec_to_bcd(time->second); /* 00H: 秒 */ + buf[1] = sd2506_dec_to_bcd(time->minute); /* 01H: 分 */ + buf[2] = sd2506_dec_to_bcd(time->hour) | 0x80U; /* 02H: 时 (bit7=1, 24小时制) */ + buf[3] = sd2506_dec_to_bcd(time->week); /* 03H: 星期 */ + buf[4] = sd2506_dec_to_bcd(time->day); /* 04H: 日 */ + buf[5] = sd2506_dec_to_bcd(time->month); /* 05H: 月 */ + buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 06H: 年 */ + + /* 开启写保护 */ + ret = sd2506_write_enable(); + if (ret != SD2506_OK) return ret; + + /* 一次性写入 7 字节时间数据 (00H~06H) + * 手册要求: 不可单独写某一个时间寄存器,否则可能引起错误进位 */ + ret = sd2506_write_regs(SD2506_REG_SEC, buf, 7); + if (ret != SD2506_OK) return ret; + + /* 关闭写保护 */ + ret = sd2506_write_disable(); + if (ret != SD2506_OK) return ret; + + return SD2506_OK; +} + +int sd2506_get_time(sd2506_time_t *time) +{ + int ret; + uint8_t buf[7]; + + if (time == NULL) { + return SD2506_ERROR; + } + + /* 一次读取 7 字节时间数据 (00H~06H) + * 手册说明: 读取时所有实时数据被锁存,避免错读 */ + ret = sd2506_read_regs(SD2506_REG_SEC, buf, 7); + if (ret != SD2506_OK) { + return ret; + } + + time->second = sd2506_bcd_to_dec(buf[0] & 0x7FU); /* 00H: 秒 */ + time->minute = sd2506_bcd_to_dec(buf[1] & 0x7FU); /* 01H: 分 */ + time->hour = sd2506_bcd_to_dec(buf[2] & 0x7FU); /* 02H: 屏蔽 bit7 (12/24标志) */ + time->week = sd2506_bcd_to_dec(buf[3] & 0x07U); /* 03H: 星期 */ + time->day = sd2506_bcd_to_dec(buf[4] & 0x3FU); /* 04H: 日 */ + time->month = sd2506_bcd_to_dec(buf[5] & 0x1FU); /* 05H: 月 */ + time->year = sd2506_bcd_to_dec(buf[6]) + 2000U; /* 06H: 年 */ + + return SD2506_OK; +} + +int sd2506_get_temperature(int8_t *temp) +{ + int ret; + uint8_t val; + + if (temp == NULL) { + return SD2506_ERROR; + } + + ret = sd2506_read_reg(SD2506_REG_TEMP, &val); + if (ret != SD2506_OK) { + return ret; + } + + /* bit7 为符号位, 其余为温度值 */ + if (val & 0x80U) { + /* 负温度: 取补码 */ + *temp = (int8_t)(val | 0xF0U); + } else { + /* 正温度 */ + *temp = (int8_t)(val & 0x7FU); + } + + return SD2506_OK; +} + +int sd2506_get_battery_voltage(uint16_t *voltage) +{ + int ret; + uint8_t val_high, val_low; + + if (voltage == NULL) { + return SD2506_ERROR; + } + + /* 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL) */ + ret = sd2506_read_reg(SD2506_REG_CTR5, &val_high); + if (ret != SD2506_OK) return ret; + + ret = sd2506_read_reg(SD2506_REG_BAT_VAL, &val_low); + if (ret != SD2506_OK) return ret; + + /* 组合 9 位: bit8=BAT8_VAL(1AH bit7), bit7~0=BAT_VL(1BH) + * 如 1AH=80H, 1BH=30H => 电压 = 0x130 = 304 => 3.04V => 3040mV */ + uint16_t raw = ((val_high & 0x80U) << 1) | val_low; + *voltage = raw * 10; /* 转换为毫伏 (raw 单位 0.01V) */ + + return SD2506_OK; +} + +int sd2506_get_id(uint8_t id[8]) +{ + if (id == NULL) { + return SD2506_ERROR; + } + + return sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE); +} + +int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len) +{ + if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) { + return SD2506_ERROR; + } + + if (addr + len > SD2506_SRAM_SIZE) { + return SD2506_ERROR; + } + + return sd2506_read_regs(SD2506_REG_SRAM_START + addr, buf, len); +} + +int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len) +{ + if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) { + return SD2506_ERROR; + } + + if (addr + len > SD2506_SRAM_SIZE) { + return SD2506_ERROR; + } + + /* SRAM 无需开写保护即可写入 (写保护仅对 00H~71H 有效, SRAM 是 2CH~71H) + * 但为安全起见, SRAM 写入也走写保护流程 */ + int ret; + ret = sd2506_write_enable(); + if (ret != SD2506_OK) return ret; + + ret = sd2506_write_regs(SD2506_REG_SRAM_START + addr, buf, len); + if (ret != SD2506_OK) return ret; + + ret = sd2506_write_disable(); + return ret; +} + +int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask) +{ + int ret; + uint8_t buf[8]; + + if (time == NULL) { + return SD2506_ERROR; + } + + /* 组装 8 字节报警数据 (07H~0EH) */ + buf[0] = sd2506_dec_to_bcd(time->second) & 0x7FU; /* 07H: 秒报警 */ + buf[1] = sd2506_dec_to_bcd(time->minute) & 0x7FU; /* 08H: 分报警 */ + buf[2] = sd2506_dec_to_bcd(time->hour) & 0x3FU; /* 09H: 时报警 (最高位始终为0) */ + buf[3] = 0x00U; /* 0AH: 星期报警 */ + buf[4] = sd2506_dec_to_bcd(time->day) & 0x3FU; /* 0BH: 日报警 */ + buf[5] = sd2506_dec_to_bcd(time->month) & 0x1FU; /* 0CH: 月报警 */ + buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 0DH: 年报警 */ + buf[7] = mask; /* 0EH: 报警允许 */ + + /* 开启写保护 */ + ret = sd2506_write_enable(); + if (ret != SD2506_OK) return ret; + + /* 写入报警寄存器 (07H~0EH) */ + ret = sd2506_write_regs(SD2506_REG_AL_SEC, buf, 8); + if (ret != SD2506_OK) return ret; + + /* 使能报警中断: CTR2 的 INTAE=1, INTS1=0, INTS0=1, IM=1 (周期性) */ + ret = sd2506_write_reg(SD2506_REG_CTR2, + SD2506_CTR2_INTAE | SD2506_CTR2_INTS0 | SD2506_CTR2_IM); + if (ret != SD2506_OK) return ret; + + /* 关闭写保护 */ + ret = sd2506_write_disable(); + if (ret != SD2506_OK) return ret; + + return SD2506_OK; +} + +int sd2506_clear_alarm(void) +{ + int ret; + uint8_t val; + + /* 读取 CTR1, ARST=1 时自动清除 INTAF */ + ret = sd2506_read_reg(SD2506_REG_CTR1, &val); + if (ret != SD2506_OK) { + return ret; + } + + return SD2506_OK; +} + +int sd2506_read_ctr1(uint8_t *val) +{ + if (val == NULL) { + return SD2506_ERROR; + } + + return sd2506_read_reg(SD2506_REG_CTR1, val); +} diff --git a/Drivers/BSP/SD2506/sd2506.h b/Drivers/BSP/SD2506/sd2506.h new file mode 100644 index 0000000..827d5d7 --- /dev/null +++ b/Drivers/BSP/SD2506/sd2506.h @@ -0,0 +1,296 @@ +/* + * 模块名称:SD2506API-G RTC 实时时钟驱动 + * 模块功能:SD2506API-G 高精度温补实时时钟模块 I2C 驱动,提供时间读写、 + * 温度读取、电池电压检测、ID 读取等功能 + * 适用平台:STM32F407ZGT6,I2C1 接口 (PB6-SCL, PB7-SDA) + * 作者:王建锋 + * 创建日期:2026-07-17 + * 修改记录: + * 2026-07-17 王建锋 创建初始版本,参考 SD2506API-G Ver2.0 手册 + */ + +#ifndef __SD2506_H +#define __SD2506_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "main.h" + +/* ======================== I2C 地址 ======================== */ + +/* + * SD2506API-G 7位器件地址: 0x32 + * HAL库使用8位地址: 写 0x64, 读 0x65 + */ +#define SD2506_I2C_ADDR 0x32U +#define SD2506_I2C_ADDR_WRITE 0x64U +#define SD2506_I2C_ADDR_READ 0x65U + +/* ======================== 寄存器地址定义 ======================== */ + +/* 实时时钟寄存器 (00H~06H) */ +#define SD2506_REG_SEC 0x00U /* 秒 00~59 BCD */ +#define SD2506_REG_MIN 0x01U /* 分 00~59 BCD */ +#define SD2506_REG_HOUR 0x02U /* 时 00~23 BCD, bit7=12/24 */ +#define SD2506_REG_WEEK 0x03U /* 星期 00~06 BCD */ +#define SD2506_REG_DAY 0x04U /* 日 01~31 BCD */ +#define SD2506_REG_MON 0x05U /* 月 01~12 BCD */ +#define SD2506_REG_YEAR 0x06U /* 年 00~99 BCD */ + +/* 报警寄存器 (07H~0EH) */ +#define SD2506_REG_AL_SEC 0x07U /* 秒报警 */ +#define SD2506_REG_AL_MIN 0x08U /* 分报警 */ +#define SD2506_REG_AL_HOUR 0x09U /* 时报警 */ +#define SD2506_REG_AL_WEEK 0x0AU /* 星期报警 */ +#define SD2506_REG_AL_DAY 0x0BU /* 日报警 */ +#define SD2506_REG_AL_MON 0x0CU /* 月报警 */ +#define SD2506_REG_AL_YEAR 0x0DU /* 年报警 */ +#define SD2506_REG_AL_EN 0x0EU /* 报警允许寄存器 */ + +/* 控制寄存器 */ +#define SD2506_REG_CTR1 0x0FH /* 控制寄存器1 */ +#define SD2506_REG_CTR2 0x10U /* 控制寄存器2 */ +#define SD2506_REG_CTR3 0x11U /* 控制寄存器3 */ + +/* 倒计时寄存器 (13H~15H) */ +#define SD2506_REG_CNT0 0x13U /* 倒计时字节0 (LSB) */ +#define SD2506_REG_CNT1 0x14U /* 倒计时字节1 */ +#define SD2506_REG_CNT2 0x15U /* 倒计时字节2 (MSB) */ + +/* 温度寄存器 */ +#define SD2506_REG_TEMP 0x16U /* 温度值 (bit7=符号位) */ +#define SD2506_REG_AGTC 0x17U /* IIC控制寄存器 AGTC */ +#define SD2506_REG_CHARGE 0x18U /* 充电选择寄存器 */ +#define SD2506_REG_CTR4 0x19U /* 扩展控制寄存器 CTR4 */ +#define SD2506_REG_CTR5 0x1AU /* 控制寄存器 CTR5 */ +#define SD2506_REG_BAT_VAL 0x1BU /* 电池电压低8位 */ + +/* 温度报警及历史 */ +#define SD2506_REG_TEMP_AL 0x1CU /* 低温报警温度值 */ +#define SD2506_REG_TEMP_AH 0x1DU /* 高温报警温度值 */ +#define SD2506_REG_TEMP_HIS_L 0x1EU /* 历史低温 */ +#define SD2506_REG_TEMP_HIS_H 0x1FU /* 历史高温 */ + +/* 用户 SRAM (2CH~71H) */ +#define SD2506_REG_SRAM_START 0x2CU +#define SD2506_REG_SRAM_END 0x71U +#define SD2506_SRAM_SIZE 70U /* 70字节 */ + +/* ID 码 (72H~79H) */ +#define SD2506_REG_ID_START 0x72U +#define SD2506_REG_ID_END 0x79U +#define SD2506_ID_SIZE 8U /* 8字节 */ + +/* ======================== 控制位定义 ======================== */ + +/* 控制寄存器 1 (0FH) */ +#define SD2506_CTR1_ARST (1U << 5) /* 自动复位使能 */ +#define SD2506_CTR1_INTAF (1U << 3) /* 报警中断标志 */ +#define SD2506_CTR1_INTDF (1U << 2) /* 倒计时中断标志 */ +#define SD2506_CTR1_BLF (1U << 0) /* 电池欠压标志 */ + +/* 控制寄存器 2 (10H) */ +#define SD2506_CTR2_INTAE (1U << 5) /* 报警中断允许 */ +#define SD2506_CTR2_INTFE (1U << 4) /* 频率中断允许 */ +#define SD2506_CTR2_INTDE (1U << 3) /* 倒计时中断允许 */ +#define SD2506_CTR2_IM (1U << 2) /* 中断模式: 0=单事件, 1=周期 */ +#define SD2506_CTR2_INTS1 (1U << 1) /* INT输出选择 bit1 */ +#define SD2506_CTR2_INTS0 (1U << 0) /* INT输出选择 bit0 */ + +/* 报警允许寄存器 (0EH) */ +#define SD2506_AL_EN_EAY (1U << 6) /* 年报警允许 */ +#define SD2506_AL_EN_EAMO (1U << 5) /* 月报警允许 */ +#define SD2506_AL_EN_EAD (1U << 4) /* 日报警允许 */ +#define SD2506_AL_EN_EAW (1U << 3) /* 星期报警允许 */ +#define SD2506_AL_EN_EAH (1U << 2) /* 时报警允许 */ +#define SD2506_AL_EN_EAMN (1U << 1) /* 分报警允许 */ +#define SD2506_AL_EN_EAS (1U << 0) /* 秒报警允许 */ + +/* 24/12小时制位 */ +#define SD2506_HOUR_24 (1U << 7) /* bit7=1 表示24小时制 */ + +/* ======================== 充电配置 ======================== */ + +/* 充电寄存器 (18H) 建议上电写入值: 0x82 (开启充电, 断开) */ +#define SD2506_CHARGE_EN (1U << 7) /* 充电允许位 */ +#define SD2506_CHARGE_2K (0U << 0) /* 2K电阻 */ +#define SD2506_CHARGE_5K (1U << 0) /* 5K电阻 */ + +/* ======================== 写保护配置 ======================== */ + +/* 写允许时 0FH 寄存器建议值: 0xFF (WRTC1=1, WRTC2=1, WRTC3=1) */ +#define SD2506_CTR1_WRITE_ON 0xFFU +/* 写禁止时 0FH 寄存器建议值: 0x7B (WRTC1=0, WRTC2=0, WRTC3=0, ARST=1) */ +#define SD2506_CTR1_WRITE_OFF 0x7BU + +/* ======================== 返回值定义 ======================== */ + +#define SD2506_OK 0 +#define SD2506_ERROR -1 +#define SD2506_I2C_ERROR -2 + +/* ======================== 超时时间 ======================== */ + +#define SD2506_I2C_TIMEOUT_MS 100 + +/* ======================== 数据结构 ======================== */ + +/* + * RTC 时间日期结构体 + * year: 2000~2099 + * month: 1~12 + * day: 1~31 + * hour: 0~23 (24小时制) + * minute: 0~59 + * second: 0~59 + * week: 0~6 (0=星期天, 1=星期一, ..., 6=星期六) + */ +typedef struct { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t week; +} sd2506_time_t; + +/* ======================== 函数声明 ======================== */ + +/* + * 函数功能:初始化 SD2506API-G RTC + * 入口参数:无 + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:CubeMX 已完成 I2C1 初始化 + * 函数说明:1. 读取芯片 ID 验证通信 + * 2. 上电重置充电寄存器 18H=82H + * 3. 配置 24 小时制、开自动复位 + */ +int sd2506_init(void); + +/* + * 函数功能:设置 RTC 时间日期 + * 入口参数:time - 时间结构体指针,包含要设置的时间 + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:1. 先开写保护 + * 2. 一次性写入 7 字节时间数据 (00H~06H) + * 3. 关闭写保护 + * 注意:不可单独写某一个时间寄存器 + */ +int sd2506_set_time(const sd2506_time_t *time); + +/* + * 函数功能:读取 RTC 时间日期 + * 入口参数:time - 时间结构体指针,用于存储读取结果 + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:1. 一次读取 7 字节时间数据 (00H~06H) + * 2. BCD 转十进制 + * 3. 屏蔽小时 bit7 (12/24标志位) + */ +int sd2506_get_time(sd2506_time_t *time); + +/* + * 函数功能:读取芯片内部温度 + * 入口参数:temp - 温度输出指针 (整数部分, 有符号) + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:读取 16H 寄存器,bit7 为符号位,范围 -40~+85 + */ +int sd2506_get_temperature(int8_t *temp); + +/* + * 函数功能:读取电池电压 (毫伏) + * 入口参数:voltage - 电压输出指针 (单位: mV) + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:1. 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL) + * 2. 组合 9 位数据得到电压值 (如 0x135 = 309 = 3.09V) + */ +int sd2506_get_battery_voltage(uint16_t *voltage); + +/* + * 函数功能:读取芯片 8 字节 ID + * 入口参数:id - 8 字节输出缓冲区 + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:读取 72H~79H 共 8 字节唯一 ID + */ +int sd2506_get_id(uint8_t id[8]); + +/* + * 函数功能:读取用户 SRAM 数据 + * 入口参数:addr - SRAM 起始地址 (0~69) + * buf - 数据输出缓冲区 + * len - 读取长度 (1~70) + * 返回值:0 - 成功,-2 - I2C 通信错误,-1 - 参数错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H + */ +int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len); + +/* + * 函数功能:写入用户 SRAM 数据 + * 入口参数:addr - SRAM 起始地址 (0~69) + * buf - 数据输入缓冲区 + * len - 写入长度 (1~70) + * 返回值:0 - 成功,-2 - I2C 通信错误,-1 - 参数错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H + * SRAM 无需开写保护即可写入 + */ +int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len); + +/* + * 函数功能:设置报警中断 + * 入口参数:time - 报警时间结构体 + * mask - 报警匹配掩码 (SD2506_AL_EN_xxx 位或组合) + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:1. 开写保护 + * 2. 写入报警寄存器 (07H~0EH) + * 3. 使能报警中断 INTAE + * 4. 关写保护 + */ +int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask); + +/* + * 函数功能:清除报警中断标志 + * 入口参数:无 + * 返回值:0 - 成功,-2 - I2C 通信错误 + * 限定条件:sd2506_init() 已调用 + * 函数说明:读取 CTR1 自动清除 INTAF (ARST=1 时) + */ +int sd2506_clear_alarm(void); + +/* + * 函数功能:读取当前 0FH 控制寄存器1 状态 + * 入口参数:val - 输出值指针 + * 返回值:0 - 成功,-2 - I2C 通信错误 + */ +int sd2506_read_ctr1(uint8_t *val); + +/* + * 函数功能:BCD 码转十进制 + * 入口参数:bcd - BCD 码值 + * 返回值:十进制值 + * 函数说明:内部辅助函数 + */ +uint8_t sd2506_bcd_to_dec(uint8_t bcd); + +/* + * 函数功能:十进制转 BCD 码 + * 入口参数:dec - 十进制值 + * 返回值:BCD 码值 + * 函数说明:内部辅助函数 + */ +uint8_t sd2506_dec_to_bcd(uint8_t dec); + +#ifdef __cplusplus +} +#endif + +#endif /* __SD2506_H */ diff --git a/Drivers/BSP/TPAFE5160/tpafe5160.c b/Drivers/BSP/TPAFE5160/tpafe5160.c new file mode 100644 index 0000000..08e94a9 --- /dev/null +++ b/Drivers/BSP/TPAFE5160/tpafe5160.c @@ -0,0 +1,354 @@ +/* + * 模块名称:TPAFE5160 16位8通道同步采样ADC驱动 + * 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口 + * 适用平台:STM32F407ZGT6,并行16位数据总线接 GPIOG[15:0] + * 作者:王建锋 + * 创建日期:2026-07-17 + * 修改记录: + * 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册 + * 2026-07-17 王建锋 增加 EXTI 中断读取模式 + */ + +/* 头文件包含区 */ +#include "tpafe5160.h" + +/* ======================== 私有宏定义 ======================== */ + +/* + * 并行读取时序延时 (168MHz 主频,1 NOP ≈ 5.95ns) + * + * TPAFE5160 并行时序要求 (VDRIVE > 2.7V): + * t10 (RD 低脉宽) ≥ 22ns + * t11 (RD 高脉宽) ≥ 10ns + * t14 (数据访问时间) ≤ 21ns (从 RD 下降沿算起) + * t15 (数据保持时间) ≥ 6ns (从 RD 下降沿算起) + * + * GPIO 写操作本身约 1 个 AHB 周期 (~6ns), + * 加上端口延迟 (~12-18ns),实际 RD 引脚翻转滞后约 18-24ns。 + * 因此 NOP 延时只需覆盖数据建立时间即可。 + */ +#define TP_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP() + +/* RD 低脉宽延时:GPIO写(~6ns) + 5NOP(~30ns) > 22ns */ +#define TP_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TP_NOP_5(); } while (0) + +/* RD 高脉宽延时:GPIO写(~6ns) + 3NOP(~18ns) > 10ns */ +#define TP_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0) + +/* CONVST 脉冲延时:上升沿前需保证低电平,5NOP 覆盖 t5 ≥ 20ns */ +#define TP_CONVST_PULSE() do { \ + TPAFE5160_CONVST_LOW(); \ + TP_NOP_5(); \ + TPAFE5160_CONVST_HIGH(); \ + TP_NOP_5(); \ +} while (0) + +/* ======================== 私有函数声明 ======================== */ + +static void tpafe5160_read_channels(uint8_t count, int16_t *buf); + +/* ======================== 公共函数定义 ======================== */ + +/* + * 函数功能:初始化 TPAFE5160(设置过采样、等待就绪) + * 入口参数:无 + * 返回值:0 - 成功,-2 - BUSY 超时 + * 限定条件:CubeMX 已完成 GPIO 初始化 + * 函数说明:1. 设置过采样为无过采样 (000) + * 2. 确保 RD 为高、CONVST 为低 + * 3. 等待 BUSY 释放(转换空闲) + */ +int tpafe5160_init(void) +{ + /* 设置默认过采样:无过采样 (OS[2:0] = 000) */ + tpafe5160_set_os(TP_OS_NONE); + + /* 确保控制引脚处于空闲状态 */ + TPAFE5160_RD_HIGH(); + TPAFE5160_CONVST_LOW(); + + /* 等待 BUSY 释放,确保上电后无残留转换 */ + return tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS); +} + +/* + * 函数功能:设置过采样率 + * 入口参数:os - 过采样率枚举值 tpafe5160_os_t + * 返回值:无 + * 限定条件:GPIO 已初始化 + * 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次 BUSY 下降沿锁存生效 + */ +void tpafe5160_set_os(tpafe5160_os_t os) +{ + TPAFE5160_OS0(os & 0x01); /* OS0 = bit0 */ + TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */ + TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */ +} + +/* + * 函数功能:启动一次转换(CONVST 上升沿触发) + * 入口参数:无 + * 返回值:无 + * 限定条件:GPIO 已初始化 + * 函数说明:产生 CONVST 脉冲上升沿,启动全部8通道同步采样与转换 + */ +void tpafe5160_start_conv(void) +{ + TP_CONVST_PULSE(); +} + +/* + * 函数功能:等待转换完成 + * 入口参数:timeout_ms - 超时时间 uint32_t > 0 + * 返回值:0 - 转换完成,-2 - 超时 + * 限定条件:已调用 tpafe5160_start_conv() + * 函数说明:轮询 BUSY 引脚等待下降沿 + */ +int tpafe5160_wait_busy(uint32_t timeout_ms) +{ + uint32_t tick_start = HAL_GetTick(); + + /* 等待 BUSY 释放(低电平表示空闲) */ + while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) { + if ((HAL_GetTick() - tick_start) >= timeout_ms) { + return TPAFE5160_BUSY_TIMEOUT; + } + } + + return TPAFE5160_OK; +} + +/* + * 函数功能:查询当前是否正在转换 + * 入口参数:无 + * 返回值:1 - 正在转换,0 - 空闲 + * 限定条件:GPIO 已初始化 + * 函数说明:读取 BUSY 引脚电平 + */ +uint8_t tpafe5160_is_busy(void) +{ + return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0; +} + +/* + * 函数功能:读取全部8通道转换结果 + * 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL + * 返回值:0 - 成功,-2 - BUSY 超时 + * 限定条件:GPIO 已初始化 + * 函数说明:1. 启动转换并等待 BUSY 释放 + * 2. 连续8次拉低RD读取各通道数据 + * 3. 通过 FRSTDATA 验证第一通道 + */ +int tpafe5160_read_all(int16_t *buf) +{ + int ret; + + /* 启动转换 */ + tpafe5160_start_conv(); + + /* 等待转换完成 */ + ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS); + if (ret != TPAFE5160_OK) { + return ret; + } + + /* 连续读取8个通道 */ + tpafe5160_read_channels(TPAFE5160_CH_NUM, buf); + + return TPAFE5160_OK; +} + +/* + * 函数功能:读取指定通道的转换结果 + * 入口参数:channel - 通道号 uint8_t 0 - 7 + * value - 输出指针 int16_t* 不为 NULL + * 返回值:0 - 成功,-1 - 通道号无效,-2 - BUSY 超时 + * 限定条件:GPIO 已初始化 + * 函数说明:启动转换并等待完成后,连续读取至指定通道 + */ +int tpafe5160_read_channel(uint8_t channel, int16_t *value) +{ + int ret; + int16_t buf[TPAFE5160_CH_NUM]; + + if (channel >= TPAFE5160_CH_NUM || value == NULL) { + return TPAFE5160_ERROR; + } + + ret = tpafe5160_read_all(buf); + if (ret != TPAFE5160_OK) { + return ret; + } + + *value = buf[channel]; + return TPAFE5160_OK; +} + +/* + * 函数功能:原始ADC值转电压值 + * 入口参数:raw - ADC原始值 int16_t 有符号补码 + * 返回值:电压值 float 单位 V + * 限定条件:无 + * 函数说明:±5V量程时 LSB = 10V / 65536 ≈ 152.59μV + * ±10V量程时 LSB = 20V / 65536 ≈ 305.18μV + * 硬件 RANGE 引脚接 GND,默认 ±5V 量程 + */ +float tpafe5160_to_voltage(int16_t raw) +{ + /* RANGE 接 GND → ±5V 量程,满量程 10V */ + return (float)raw * (10.0f / 65536.0f); +} + +/* + * 函数功能:直接读取并行数据总线(不启动转换) + * 入口参数:无 + * 返回值:16位原始数据 uint16_t + * 限定条件:RD 为低或 CS 与 RD 已拉低 + * 函数说明:读取 GPIOG->IDR 低16位,对应 DB[15:0] + */ +uint16_t tpafe5160_read_bus(void) +{ + return TPAFE5160_READ_BUS(); +} + +/* ======================== 私有函数定义 ======================== */ + +/* + * 函数功能:通过 RD 脉冲连续读取多个通道数据 + * 入口参数:count - 要读取的通道数 uint8_t 1 - 8 + * buf - 输出缓冲区 int16_t* 不为 NULL + * 返回值:无 + * 限定条件:转换已完成(BUSY 为低),RD 初始为高 + * 函数说明:每次 RD 下降沿输出一个通道数据,按通道1~8顺序输出 + * DB[15:0] 直接接 GPIOG[15:0],通过 IDR 寄存器一次读取 + * + * 时序关键点 (VDRIVE > 2.7V, 168MHz 主频): + * GPIO 写操作 ~6ns + 端口延迟 ~18ns → RD 引脚实际翻转约 24ns 后 + * t14 数据建立 ≤ 21ns → 数据在 RD 下降沿后 21ns 内有效 + * 5 个 NOP (~30ns) 覆盖建立时间 + */ +static void tpafe5160_read_channels(uint8_t count, int16_t *buf) +{ + uint8_t i; + + for (i = 0; i < count; i++) { + /* RD 下降沿:ADC 输出当前通道数据到 DB[15:0] */ + TP_RD_LOW_DLY(); + + /* 读取16位并行数据 */ + buf[i] = (int16_t)TPAFE5160_READ_BUS(); + + /* RD 上升沿:准备下一通道 */ + TP_RD_HIGH_DLY(); + } +} + +/* ======================== 中断模式实现 ======================== */ + +/* 双缓冲区:ISR 写 s_buf_b,主循环读 s_buf_a */ +static int16_t s_buf_a[TPAFE5160_CH_NUM]; +static int16_t s_buf_b[TPAFE5160_CH_NUM]; +static volatile uint8_t s_ready = 0; +static volatile uint8_t s_buf_sel = 0; /* 0 = 写 B / 读 A, 1 = 写 A / 读 B */ + +/* + * 函数功能:使能 BUSY EXTI 中断(运行时重使能用) + * 入口参数:无 + * 返回值:无 + * 限定条件:CubeMX 已完成 GPIO 和 NVIC 配置 + * 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用 + */ +void tpafe5160_irq_enable(void) +{ + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); +} + +/* + * 函数功能:关闭 BUSY EXTI 中断 + * 入口参数:无 + * 返回值:无 + * 限定条件:已调用 tpafe5160_irq_enable() + * 函数说明:仅禁用 NVIC 中断,GPIO 配置保持 CubeMX 设定 + */ +void tpafe5160_irq_disable(void) +{ + HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); +} + +/* + * 函数功能:启动转换(中断模式) + * 入口参数:无 + * 返回值:无 + * 限定条件:已调用 tpafe5160_irq_enable() + * 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据 + */ +void tpafe5160_start_conv_irq(void) +{ + s_ready = 0; + TP_CONVST_PULSE(); +} + +/* + * 函数功能:检查是否有新的转换数据 + * 入口参数:无 + * 返回值:1 - 数据就绪,0 - 无新数据 + * 限定条件:中断模式已启用 + * 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除 + */ +uint8_t tpafe5160_data_ready(void) +{ + return s_ready; +} + +/* + * 函数功能:清除数据就绪标志 + * 入口参数:无 + * 返回值:无 + * 限定条件:中断模式已启用 + * 函数说明:主循环处理完数据后调用 + */ +void tpafe5160_clear_ready(void) +{ + s_ready = 0; +} + +/* + * 函数功能:获取数据缓冲区指针 + * 入口参数:无 + * 返回值:int16_t[8] 数据缓冲区的 const 指针 + * 限定条件:tpafe5160_data_ready() 返回 1 时调用 + * 函数说明:双缓冲切换,ISR 写另一个缓冲区,主循环安全读取当前缓冲区 + */ +const int16_t* tpafe5160_get_buf(void) +{ + return (s_buf_sel == 0) ? s_buf_a : s_buf_b; +} + +/* + * 函数功能:BUSY 下降沿 EXTI 回调(由 HAL_GPIO_EXTI_IRQHandler 调用) + * 入口参数:GPIO_Pin - 触发中断的引脚号 + * 返回值:无 + * 限定条件:BUSY EXTI 已使能 + * 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz) + */ +void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) +{ + if (GPIO_Pin != TP_BUSY_Pin) { + return; + } + + /* 双缓冲切换:ISR 写与主循环读不同的缓冲区 */ + int16_t *p_wr = (s_buf_sel == 0) ? s_buf_b : s_buf_a; + + /* 连续读取8个通道,约 0.5µs @ 168MHz */ + uint8_t i; + for (i = 0; i < TPAFE5160_CH_NUM; i++) { + TP_RD_LOW_DLY(); + p_wr[i] = (int16_t)TPAFE5160_READ_BUS(); + TP_RD_HIGH_DLY(); + } + + /* 切换缓冲区并标记就绪 */ + s_buf_sel ^= 1; + s_ready = 1; +} diff --git a/Drivers/BSP/TPAFE5160/tpafe5160.h b/Drivers/BSP/TPAFE5160/tpafe5160.h new file mode 100644 index 0000000..8fc391b --- /dev/null +++ b/Drivers/BSP/TPAFE5160/tpafe5160.h @@ -0,0 +1,224 @@ +#ifndef __TPAFE5160_H +#define __TPAFE5160_H + +/* + * 模块名称:TPAFE5160 16位8通道同步采样ADC驱动 + * 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口 + * 适用平台:STM32F407ZGT6,并行16位数据总线接 GPIOG[15:0] + * 作者:王建锋 + * 创建日期:2026-07-17 + * 修改记录: + * 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册 + * 2026-07-17 王建锋 增加 EXTI 中断读取模式 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "main.h" + +/* ======================== 宏定义 ======================== */ + +/* 通道数量 */ +#define TPAFE5160_CH_NUM 8 + +/* 控制引脚操作宏 —— RD (PD3) */ +#define TPAFE5160_RD_LOW() HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_RESET) +#define TPAFE5160_RD_HIGH() HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_SET) + +/* 控制引脚操作宏 —— CONVST (PD4) */ +#define TPAFE5160_CONVST_LOW() HAL_GPIO_WritePin(TP_CONVST_GPIO_Port, TP_CONVST_Pin, GPIO_PIN_RESET) +#define TPAFE5160_CONVST_HIGH() HAL_GPIO_WritePin(TP_CONVST_GPIO_Port, TP_CONVST_Pin, GPIO_PIN_SET) + +/* 状态引脚读取宏 */ +#define TPAFE5160_BUSY_READ() HAL_GPIO_ReadPin(TP_BUSY_GPIO_Port, TP_BUSY_Pin) +#define TPAFE5160_FRSTDATA_READ() HAL_GPIO_ReadPin(TP_FRSTDATA_GPIO_Port, TP_FRSTDATA_Pin) + +/* 过采样引脚操作宏 —— OS0 (PF13), OS1 (PF14), OS2 (PF15) */ +#define TPAFE5160_OS0(val) HAL_GPIO_WritePin(TP_OS0_GPIO_Port, TP_OS0_Pin, \ + (val) ? GPIO_PIN_SET : GPIO_PIN_RESET) +#define TPAFE5160_OS1(val) HAL_GPIO_WritePin(TP_OS1_GPIO_Port, TP_OS1_Pin, \ + (val) ? GPIO_PIN_SET : GPIO_PIN_RESET) +#define TPAFE5160_OS2(val) HAL_GPIO_WritePin(TP_OS2_GPIO_Port, TP_OS2_Pin, \ + (val) ? GPIO_PIN_SET : GPIO_PIN_RESET) + +/* 并行数据总线读取 —— DB[15:0] 接 GPIOG[15:0],单次读取16位 */ +#define TPAFE5160_READ_BUS() ((uint16_t)GPIOG->IDR) + +/* 过采样率枚举 (OS[2:0] 编码,OS2为MSB, OS0为LSB) */ +typedef enum { + TP_OS_NONE = 0, /* 000 — 无过采样,350 kSPS */ + TP_OS_X2 = 1, /* 001 — 2倍过采样,175 kSPS */ + TP_OS_X4 = 2, /* 010 — 4倍过采样,87.5 kSPS */ + TP_OS_X8 = 3, /* 011 — 8倍过采样,43.75 kSPS */ + TP_OS_X16 = 4, /* 100 — 16倍过采样,21.875 kSPS */ + TP_OS_X32 = 5, /* 101 — 32倍过采样,10.94 kSPS */ + TP_OS_X64 = 6, /* 110 — 64倍过采样,5.47 kSPS */ + TP_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz),350 kSPS */ +} tpafe5160_os_t; + +/* 输入量程枚举 */ +typedef enum { + TP_RANGE_5V = 0, /* ±5V (RANGE = LOW) */ + TP_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */ +} tpafe5160_range_t; + +/* 返回值定义 */ +#define TPAFE5160_OK 0 +#define TPAFE5160_ERROR -1 +#define TPAFE5160_BUSY_TIMEOUT -2 + +/* 默认超时时间 (ms) */ +#define TPAFE5160_CONV_TIMEOUT_MS 10 + +/* ======================== 函数声明 ======================== */ + +/* + * 函数功能:初始化 TPAFE5160(设置过采样、等待就绪) + * 入口参数:无 + * 返回值:0 - 成功,-2 - BUSY 超时 + * 限定条件:CubeMX 已完成 GPIO 初始化 + * 函数说明:1. 设置过采样为无过采样 (000) + * 2. 确保 RD 为高、CONVST 为低 + * 3. 等待 BUSY 释放(转换空闲) + */ +int tpafe5160_init(void); + +/* + * 函数功能:设置过采样率 + * 入口参数:os - 过采样率枚举值 tpafe5160_os_t + * 返回值:无 + * 限定条件:GPIO 已初始化 + * 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次转换时生效 + */ +void tpafe5160_set_os(tpafe5160_os_t os); + +/* + * 函数功能:启动一次转换(CONVST 上升沿触发) + * 入口参数:无 + * 返回值:无 + * 限定条件:GPIO 已初始化 + * 函数说明:产生 CONVST 脉冲上升沿,启动全部8通道同步采样与转换 + */ +void tpafe5160_start_conv(void); + +/* + * 函数功能:等待转换完成 + * 入口参数:timeout_ms - 超时时间 uint32_t > 0 + * 返回值:0 - 转换完成,-2 - 超时 + * 限定条件:已调用 tpafe5160_start_conv() + * 函数说明:轮询 BUSY 引脚等待下降沿 + */ +int tpafe5160_wait_busy(uint32_t timeout_ms); + +/* + * 函数功能:查询当前是否正在转换 + * 入口参数:无 + * 返回值:1 - 正在转换,0 - 空闲 + * 限定条件:GPIO 已初始化 + * 函数说明:读取 BUSY 引脚电平 + */ +uint8_t tpafe5160_is_busy(void); + +/* + * 函数功能:读取全部8通道转换结果 + * 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL + * 返回值:0 - 成功,-2 - BUSY 超时 + * 限定条件:GPIO 已初始化 + * 函数说明:1. 启动转换并等待 BUSY 释放 + * 2. 连续8次拉低RD读取各通道数据 + * 3. 通过 FRSTDATA 验证第一通道 + */ +int tpafe5160_read_all(int16_t *buf); + +/* + * 函数功能:读取指定通道的转换结果 + * 入口参数:channel - 通道号 uint8_t 0 - 7 + * value - 输出指针 int16_t* 不为 NULL + * 返回值:0 - 成功,-1 - 通道号无效,-2 - BUSY 超时 + * 限定条件:GPIO 已初始化 + * 函数说明:启动转换并等待完成后,连续读取至指定通道 + */ +int tpafe5160_read_channel(uint8_t channel, int16_t *value); + +/* + * 函数功能:原始ADC值转电压值 + * 入口参数:raw - ADC原始值 int16_t 有符号补码 + * 返回值:电压值 float 单位 V + * 限定条件:无 + * 函数说明:±5V量程时 LSB=152.59μV,±10V量程时 LSB=305.18μV + * 默认使用 ±5V 量程 (RANGE 接 GND) + */ +float tpafe5160_to_voltage(int16_t raw); + +/* + * 函数功能:直接读取并行数据总线(不启动转换) + * 入口参数:无 + * 返回值:16位原始数据 uint16_t + * 限定条件:RD 为低或CS与RD已拉低 + * 函数说明:用于读取当前总线上的数据,需自行控制RD时序 + */ +uint16_t tpafe5160_read_bus(void); + +/* ======================== 中断模式 API ======================== */ + +/* + * 函数功能:使能 BUSY EXTI 中断(运行时重使能用) + * 入口参数:无 + * 返回值:无 + * 限定条件:CubeMX 已完成 GPIO 和 NVIC 配置 + * 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用 + */ +void tpafe5160_irq_enable(void); + +/* + * 函数功能:关闭 BUSY EXTI 中断 + * 入口参数:无 + * 返回值:无 + * 限定条件:已调用 tpafe5160_irq_enable() + * 函数说明:仅禁用 NVIC 中断,GPIO 配置保持 CubeMX 设定 + */ +void tpafe5160_irq_disable(void); + +/* + * 函数功能:启动转换(中断模式) + * 入口参数:无 + * 返回值:无 + * 限定条件:已调用 tpafe5160_irq_enable() + * 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据 + */ +void tpafe5160_start_conv_irq(void); + +/* + * 函数功能:检查是否有新的转换数据 + * 入口参数:无 + * 返回值:1 - 数据就绪,0 - 无新数据 + * 限定条件:中断模式已启用 + * 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除 + */ +uint8_t tpafe5160_data_ready(void); + +/* + * 函数功能:清除数据就绪标志 + * 入口参数:无 + * 返回值:无 + * 限定条件:中断模式已启用 + * 函数说明:主循环处理完数据后调用 + */ +void tpafe5160_clear_ready(void); + +/* + * 函数功能:获取数据缓冲区指针 + * 入口参数:无 + * 返回值:int16_t[8] 数据缓冲区的 const 指针 + * 限定条件:tpafe5160_data_ready() 返回 1 时调用 + * 函数说明:缓冲区由 EXTI 回调写入,主循环只读 + */ +const int16_t* tpafe5160_get_buf(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __TPAFE5160_H */ diff --git a/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h new file mode 100644 index 0000000..9a7a67e --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h @@ -0,0 +1,741 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c.h + * @author MCD Application Team + * @brief Header file of I2C HAL module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_I2C_H +#define __STM32F4xx_HAL_I2C_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup I2C + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup I2C_Exported_Types I2C Exported Types + * @{ + */ + +/** @defgroup I2C_Configuration_Structure_definition I2C Configuration Structure definition + * @brief I2C Configuration Structure definition + * @{ + */ +typedef struct +{ + uint32_t ClockSpeed; /*!< Specifies the clock frequency. + This parameter must be set to a value lower than 400kHz */ + + uint32_t DutyCycle; /*!< Specifies the I2C fast mode duty cycle. + This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */ + + uint32_t OwnAddress1; /*!< Specifies the first device own address. + This parameter can be a 7-bit or 10-bit address. */ + + uint32_t AddressingMode; /*!< Specifies if 7-bit or 10-bit addressing mode is selected. + This parameter can be a value of @ref I2C_addressing_mode */ + + uint32_t DualAddressMode; /*!< Specifies if dual addressing mode is selected. + This parameter can be a value of @ref I2C_dual_addressing_mode */ + + uint32_t OwnAddress2; /*!< Specifies the second device own address if dual addressing mode is selected + This parameter can be a 7-bit address. */ + + uint32_t GeneralCallMode; /*!< Specifies if general call mode is selected. + This parameter can be a value of @ref I2C_general_call_addressing_mode */ + + uint32_t NoStretchMode; /*!< Specifies if nostretch mode is selected. + This parameter can be a value of @ref I2C_nostretch_mode */ + +} I2C_InitTypeDef; + +/** + * @} + */ + +/** @defgroup HAL_state_structure_definition HAL state structure definition + * @brief HAL State structure definition + * @note HAL I2C State value coding follow below described bitmap : + * b7-b6 Error information + * 00 : No Error + * 01 : Abort (Abort user request on going) + * 10 : Timeout + * 11 : Error + * b5 Peripheral initialization status + * 0 : Reset (Peripheral not initialized) + * 1 : Init done (Peripheral initialized and ready to use. HAL I2C Init function called) + * b4 (not used) + * x : Should be set to 0 + * b3 + * 0 : Ready or Busy (No Listen mode ongoing) + * 1 : Listen (Peripheral in Address Listen Mode) + * b2 Intrinsic process state + * 0 : Ready + * 1 : Busy (Peripheral busy with some configuration or internal operations) + * b1 Rx state + * 0 : Ready (no Rx operation ongoing) + * 1 : Busy (Rx operation ongoing) + * b0 Tx state + * 0 : Ready (no Tx operation ongoing) + * 1 : Busy (Tx operation ongoing) + * @{ + */ +typedef enum +{ + HAL_I2C_STATE_RESET = 0x00U, /*!< Peripheral is not yet Initialized */ + HAL_I2C_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use */ + HAL_I2C_STATE_BUSY = 0x24U, /*!< An internal process is ongoing */ + HAL_I2C_STATE_BUSY_TX = 0x21U, /*!< Data Transmission process is ongoing */ + HAL_I2C_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing */ + HAL_I2C_STATE_LISTEN = 0x28U, /*!< Address Listen Mode is ongoing */ + HAL_I2C_STATE_BUSY_TX_LISTEN = 0x29U, /*!< Address Listen Mode and Data Transmission + process is ongoing */ + HAL_I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /*!< Address Listen Mode and Data Reception + process is ongoing */ + HAL_I2C_STATE_ABORT = 0x60U, /*!< Abort user request ongoing */ + HAL_I2C_STATE_TIMEOUT = 0xA0U, /*!< Timeout state */ + HAL_I2C_STATE_ERROR = 0xE0U /*!< Error */ + +} HAL_I2C_StateTypeDef; + +/** + * @} + */ + +/** @defgroup HAL_mode_structure_definition HAL mode structure definition + * @brief HAL Mode structure definition + * @note HAL I2C Mode value coding follow below described bitmap :\n + * b7 (not used)\n + * x : Should be set to 0\n + * b6\n + * 0 : None\n + * 1 : Memory (HAL I2C communication is in Memory Mode)\n + * b5\n + * 0 : None\n + * 1 : Slave (HAL I2C communication is in Slave Mode)\n + * b4\n + * 0 : None\n + * 1 : Master (HAL I2C communication is in Master Mode)\n + * b3-b2-b1-b0 (not used)\n + * xxxx : Should be set to 0000 + * @{ + */ +typedef enum +{ + HAL_I2C_MODE_NONE = 0x00U, /*!< No I2C communication on going */ + HAL_I2C_MODE_MASTER = 0x10U, /*!< I2C communication is in Master Mode */ + HAL_I2C_MODE_SLAVE = 0x20U, /*!< I2C communication is in Slave Mode */ + HAL_I2C_MODE_MEM = 0x40U /*!< I2C communication is in Memory Mode */ + +} HAL_I2C_ModeTypeDef; + +/** + * @} + */ + +/** @defgroup I2C_Error_Code_definition I2C Error Code definition + * @brief I2C Error Code definition + * @{ + */ +#define HAL_I2C_ERROR_NONE 0x00000000U /*!< No error */ +#define HAL_I2C_ERROR_BERR 0x00000001U /*!< BERR error */ +#define HAL_I2C_ERROR_ARLO 0x00000002U /*!< ARLO error */ +#define HAL_I2C_ERROR_AF 0x00000004U /*!< AF error */ +#define HAL_I2C_ERROR_OVR 0x00000008U /*!< OVR error */ +#define HAL_I2C_ERROR_DMA 0x00000010U /*!< DMA transfer error */ +#define HAL_I2C_ERROR_TIMEOUT 0x00000020U /*!< Timeout Error */ +#define HAL_I2C_ERROR_SIZE 0x00000040U /*!< Size Management error */ +#define HAL_I2C_ERROR_DMA_PARAM 0x00000080U /*!< DMA Parameter Error */ +#define HAL_I2C_WRONG_START 0x00000200U /*!< Wrong start Error */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) +#define HAL_I2C_ERROR_INVALID_CALLBACK 0x00000100U /*!< Invalid Callback error */ +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** @defgroup I2C_handle_Structure_definition I2C handle Structure definition + * @brief I2C handle Structure definition + * @{ + */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) +typedef struct __I2C_HandleTypeDef +#else +typedef struct +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ +{ + I2C_TypeDef *Instance; /*!< I2C registers base address */ + + I2C_InitTypeDef Init; /*!< I2C communication parameters */ + + uint8_t *pBuffPtr; /*!< Pointer to I2C transfer buffer */ + + uint16_t XferSize; /*!< I2C transfer size */ + + __IO uint16_t XferCount; /*!< I2C transfer counter */ + + __IO uint32_t XferOptions; /*!< I2C transfer options */ + + __IO uint32_t PreviousState; /*!< I2C communication Previous state and mode + context for internal usage */ + + DMA_HandleTypeDef *hdmatx; /*!< I2C Tx DMA handle parameters */ + + DMA_HandleTypeDef *hdmarx; /*!< I2C Rx DMA handle parameters */ + + HAL_LockTypeDef Lock; /*!< I2C locking object */ + + __IO HAL_I2C_StateTypeDef State; /*!< I2C communication state */ + + __IO HAL_I2C_ModeTypeDef Mode; /*!< I2C communication mode */ + + __IO uint32_t ErrorCode; /*!< I2C Error code */ + + __IO uint32_t Devaddress; /*!< I2C Target device address */ + + __IO uint32_t Memaddress; /*!< I2C Target memory address */ + + __IO uint32_t MemaddSize; /*!< I2C Target memory address size */ + + __IO uint32_t EventCount; /*!< I2C Event counter */ + + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + void (* MasterTxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Master Tx Transfer completed callback */ + void (* MasterRxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Master Rx Transfer completed callback */ + void (* SlaveTxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Slave Tx Transfer completed callback */ + void (* SlaveRxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Slave Rx Transfer completed callback */ + void (* ListenCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Listen Complete callback */ + void (* MemTxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Memory Tx Transfer completed callback */ + void (* MemRxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Memory Rx Transfer completed callback */ + void (* ErrorCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Error callback */ + void (* AbortCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Abort callback */ + + void (* AddrCallback)(struct __I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); /*!< I2C Slave Address Match callback */ + + void (* MspInitCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Msp Init callback */ + void (* MspDeInitCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Msp DeInit callback */ + +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ +} I2C_HandleTypeDef; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) +/** + * @brief HAL I2C Callback ID enumeration definition + */ +typedef enum +{ + HAL_I2C_MASTER_TX_COMPLETE_CB_ID = 0x00U, /*!< I2C Master Tx Transfer completed callback ID */ + HAL_I2C_MASTER_RX_COMPLETE_CB_ID = 0x01U, /*!< I2C Master Rx Transfer completed callback ID */ + HAL_I2C_SLAVE_TX_COMPLETE_CB_ID = 0x02U, /*!< I2C Slave Tx Transfer completed callback ID */ + HAL_I2C_SLAVE_RX_COMPLETE_CB_ID = 0x03U, /*!< I2C Slave Rx Transfer completed callback ID */ + HAL_I2C_LISTEN_COMPLETE_CB_ID = 0x04U, /*!< I2C Listen Complete callback ID */ + HAL_I2C_MEM_TX_COMPLETE_CB_ID = 0x05U, /*!< I2C Memory Tx Transfer callback ID */ + HAL_I2C_MEM_RX_COMPLETE_CB_ID = 0x06U, /*!< I2C Memory Rx Transfer completed callback ID */ + HAL_I2C_ERROR_CB_ID = 0x07U, /*!< I2C Error callback ID */ + HAL_I2C_ABORT_CB_ID = 0x08U, /*!< I2C Abort callback ID */ + + HAL_I2C_MSPINIT_CB_ID = 0x09U, /*!< I2C Msp Init callback ID */ + HAL_I2C_MSPDEINIT_CB_ID = 0x0AU /*!< I2C Msp DeInit callback ID */ + +} HAL_I2C_CallbackIDTypeDef; + +/** + * @brief HAL I2C Callback pointer definition + */ +typedef void (*pI2C_CallbackTypeDef)(I2C_HandleTypeDef *hi2c); /*!< pointer to an I2C callback function */ +typedef void (*pI2C_AddrCallbackTypeDef)(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); /*!< pointer to an I2C Address Match callback function */ + +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** + * @} + */ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup I2C_Exported_Constants I2C Exported Constants + * @{ + */ + +/** @defgroup I2C_duty_cycle_in_fast_mode I2C duty cycle in fast mode + * @{ + */ +#define I2C_DUTYCYCLE_2 0x00000000U +#define I2C_DUTYCYCLE_16_9 I2C_CCR_DUTY +/** + * @} + */ + +/** @defgroup I2C_addressing_mode I2C addressing mode + * @{ + */ +#define I2C_ADDRESSINGMODE_7BIT 0x00004000U +#define I2C_ADDRESSINGMODE_10BIT (I2C_OAR1_ADDMODE | 0x00004000U) +/** + * @} + */ + +/** @defgroup I2C_dual_addressing_mode I2C dual addressing mode + * @{ + */ +#define I2C_DUALADDRESS_DISABLE 0x00000000U +#define I2C_DUALADDRESS_ENABLE I2C_OAR2_ENDUAL +/** + * @} + */ + +/** @defgroup I2C_general_call_addressing_mode I2C general call addressing mode + * @{ + */ +#define I2C_GENERALCALL_DISABLE 0x00000000U +#define I2C_GENERALCALL_ENABLE I2C_CR1_ENGC +/** + * @} + */ + +/** @defgroup I2C_nostretch_mode I2C nostretch mode + * @{ + */ +#define I2C_NOSTRETCH_DISABLE 0x00000000U +#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH +/** + * @} + */ + +/** @defgroup I2C_Memory_Address_Size I2C Memory Address Size + * @{ + */ +#define I2C_MEMADD_SIZE_8BIT 0x00000001U +#define I2C_MEMADD_SIZE_16BIT 0x00000010U +/** + * @} + */ + +/** @defgroup I2C_XferDirection_definition I2C XferDirection definition + * @{ + */ +#define I2C_DIRECTION_RECEIVE 0x00000000U +#define I2C_DIRECTION_TRANSMIT 0x00000001U +/** + * @} + */ + +/** @defgroup I2C_XferOptions_definition I2C XferOptions definition + * @{ + */ +#define I2C_FIRST_FRAME 0x00000001U +#define I2C_FIRST_AND_NEXT_FRAME 0x00000002U +#define I2C_NEXT_FRAME 0x00000004U +#define I2C_FIRST_AND_LAST_FRAME 0x00000008U +#define I2C_LAST_FRAME_NO_STOP 0x00000010U +#define I2C_LAST_FRAME 0x00000020U + +/* List of XferOptions in usage of : + * 1- Restart condition in all use cases (direction change or not) + */ +#define I2C_OTHER_FRAME (0x00AA0000U) +#define I2C_OTHER_AND_LAST_FRAME (0xAA000000U) +/** + * @} + */ + +/** @defgroup I2C_Interrupt_configuration_definition I2C Interrupt configuration definition + * @brief I2C Interrupt definition + * Elements values convention: 0xXXXXXXXX + * - XXXXXXXX : Interrupt control mask + * @{ + */ +#define I2C_IT_BUF I2C_CR2_ITBUFEN +#define I2C_IT_EVT I2C_CR2_ITEVTEN +#define I2C_IT_ERR I2C_CR2_ITERREN +/** + * @} + */ + +/** @defgroup I2C_Flag_definition I2C Flag definition + * @{ + */ + +#define I2C_FLAG_OVR 0x00010800U +#define I2C_FLAG_AF 0x00010400U +#define I2C_FLAG_ARLO 0x00010200U +#define I2C_FLAG_BERR 0x00010100U +#define I2C_FLAG_TXE 0x00010080U +#define I2C_FLAG_RXNE 0x00010040U +#define I2C_FLAG_STOPF 0x00010010U +#define I2C_FLAG_ADD10 0x00010008U +#define I2C_FLAG_BTF 0x00010004U +#define I2C_FLAG_ADDR 0x00010002U +#define I2C_FLAG_SB 0x00010001U +#define I2C_FLAG_DUALF 0x00100080U +#define I2C_FLAG_GENCALL 0x00100010U +#define I2C_FLAG_TRA 0x00100004U +#define I2C_FLAG_BUSY 0x00100002U +#define I2C_FLAG_MSL 0x00100001U +/** + * @} + */ + +/** + * @} + */ + +/* Exported macros -----------------------------------------------------------*/ + +/** @defgroup I2C_Exported_Macros I2C Exported Macros + * @{ + */ + +/** @brief Reset I2C handle state. + * @param __HANDLE__ specifies the I2C Handle. + * @retval None + */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) +#define __HAL_I2C_RESET_HANDLE_STATE(__HANDLE__) do{ \ + (__HANDLE__)->State = HAL_I2C_STATE_RESET; \ + (__HANDLE__)->MspInitCallback = NULL; \ + (__HANDLE__)->MspDeInitCallback = NULL; \ + } while(0) +#else +#define __HAL_I2C_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_I2C_STATE_RESET) +#endif + +/** @brief Enable or disable the specified I2C interrupts. + * @param __HANDLE__ specifies the I2C Handle. + * @param __INTERRUPT__ specifies the interrupt source to enable or disable. + * This parameter can be one of the following values: + * @arg I2C_IT_BUF: Buffer interrupt enable + * @arg I2C_IT_EVT: Event interrupt enable + * @arg I2C_IT_ERR: Error interrupt enable + * @retval None + */ +#define __HAL_I2C_ENABLE_IT(__HANDLE__, __INTERRUPT__) SET_BIT((__HANDLE__)->Instance->CR2,(__INTERRUPT__)) +#define __HAL_I2C_DISABLE_IT(__HANDLE__, __INTERRUPT__) CLEAR_BIT((__HANDLE__)->Instance->CR2, (__INTERRUPT__)) + +/** @brief Checks if the specified I2C interrupt source is enabled or disabled. + * @param __HANDLE__ specifies the I2C Handle. + * @param __INTERRUPT__ specifies the I2C interrupt source to check. + * This parameter can be one of the following values: + * @arg I2C_IT_BUF: Buffer interrupt enable + * @arg I2C_IT_EVT: Event interrupt enable + * @arg I2C_IT_ERR: Error interrupt enable + * @retval The new state of __INTERRUPT__ (TRUE or FALSE). + */ +#define __HAL_I2C_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->CR2 & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET) + +/** @brief Checks whether the specified I2C flag is set or not. + * @param __HANDLE__ specifies the I2C Handle. + * @param __FLAG__ specifies the flag to check. + * This parameter can be one of the following values: + * @arg I2C_FLAG_OVR: Overrun/Underrun flag + * @arg I2C_FLAG_AF: Acknowledge failure flag + * @arg I2C_FLAG_ARLO: Arbitration lost flag + * @arg I2C_FLAG_BERR: Bus error flag + * @arg I2C_FLAG_TXE: Data register empty flag + * @arg I2C_FLAG_RXNE: Data register not empty flag + * @arg I2C_FLAG_STOPF: Stop detection flag + * @arg I2C_FLAG_ADD10: 10-bit header sent flag + * @arg I2C_FLAG_BTF: Byte transfer finished flag + * @arg I2C_FLAG_ADDR: Address sent flag + * Address matched flag + * @arg I2C_FLAG_SB: Start bit flag + * @arg I2C_FLAG_DUALF: Dual flag + * @arg I2C_FLAG_GENCALL: General call header flag + * @arg I2C_FLAG_TRA: Transmitter/Receiver flag + * @arg I2C_FLAG_BUSY: Bus busy flag + * @arg I2C_FLAG_MSL: Master/Slave flag + * @retval The new state of __FLAG__ (TRUE or FALSE). + */ +#define __HAL_I2C_GET_FLAG(__HANDLE__, __FLAG__) ((((uint8_t)((__FLAG__) >> 16U)) == 0x01U) ? \ + (((((__HANDLE__)->Instance->SR1) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)) ? SET : RESET) : \ + (((((__HANDLE__)->Instance->SR2) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)) ? SET : RESET)) + +/** @brief Clears the I2C pending flags which are cleared by writing 0 in a specific bit. + * @param __HANDLE__ specifies the I2C Handle. + * @param __FLAG__ specifies the flag to clear. + * This parameter can be any combination of the following values: + * @arg I2C_FLAG_OVR: Overrun/Underrun flag (Slave mode) + * @arg I2C_FLAG_AF: Acknowledge failure flag + * @arg I2C_FLAG_ARLO: Arbitration lost flag (Master mode) + * @arg I2C_FLAG_BERR: Bus error flag + * @retval None + */ +#define __HAL_I2C_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->SR1 = ~((__FLAG__) & I2C_FLAG_MASK)) + +/** @brief Clears the I2C ADDR pending flag. + * @param __HANDLE__ specifies the I2C Handle. + * This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral. + * @retval None + */ +#define __HAL_I2C_CLEAR_ADDRFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg = 0x00U; \ + tmpreg = (__HANDLE__)->Instance->SR1; \ + tmpreg = (__HANDLE__)->Instance->SR2; \ + UNUSED(tmpreg); \ + } while(0) + +/** @brief Clears the I2C STOPF pending flag. + * @param __HANDLE__ specifies the I2C Handle. + * @retval None + */ +#define __HAL_I2C_CLEAR_STOPFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg = 0x00U; \ + tmpreg = (__HANDLE__)->Instance->SR1; \ + SET_BIT((__HANDLE__)->Instance->CR1, I2C_CR1_PE); \ + UNUSED(tmpreg); \ + } while(0) + +/** @brief Enable the specified I2C peripheral. + * @param __HANDLE__ specifies the I2C Handle. + * @retval None + */ +#define __HAL_I2C_ENABLE(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CR1, I2C_CR1_PE) + +/** @brief Disable the specified I2C peripheral. + * @param __HANDLE__ specifies the I2C Handle. + * @retval None + */ +#define __HAL_I2C_DISABLE(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CR1, I2C_CR1_PE) + +/** + * @} + */ + +/* Include I2C HAL Extension module */ +#include "stm32f4xx_hal_i2c_ex.h" + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup I2C_Exported_Functions + * @{ + */ + +/** @addtogroup I2C_Exported_Functions_Group1 Initialization and de-initialization functions + * @{ + */ +/* Initialization and de-initialization functions******************************/ +HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c); +HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c); + +/* Callbacks Register/UnRegister functions ***********************************/ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) +HAL_StatusTypeDef HAL_I2C_RegisterCallback(I2C_HandleTypeDef *hi2c, HAL_I2C_CallbackIDTypeDef CallbackID, pI2C_CallbackTypeDef pCallback); +HAL_StatusTypeDef HAL_I2C_UnRegisterCallback(I2C_HandleTypeDef *hi2c, HAL_I2C_CallbackIDTypeDef CallbackID); + +HAL_StatusTypeDef HAL_I2C_RegisterAddrCallback(I2C_HandleTypeDef *hi2c, pI2C_AddrCallbackTypeDef pCallback); +HAL_StatusTypeDef HAL_I2C_UnRegisterAddrCallback(I2C_HandleTypeDef *hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** @addtogroup I2C_Exported_Functions_Group2 Input and Output operation functions + * @{ + */ +/* IO operation functions ****************************************************/ +/******* Blocking mode: Polling */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout); + +/******* Non-Blocking mode: Interrupt */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); + +HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c); +HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c); +HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress); + +/******* Non-Blocking mode: DMA */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); + +HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); +/** + * @} + */ + +/** @addtogroup I2C_IRQ_Handler_and_Callbacks IRQ Handler and Callbacks + * @{ + */ +/******* I2C IRQHandler and Callbacks used in non blocking modes (Interrupt and DMA) */ +void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c); +void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); +void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c); +void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c); +/** + * @} + */ + +/** @addtogroup I2C_Exported_Functions_Group3 Peripheral State, Mode and Error functions + * @{ + */ +/* Peripheral State, Mode and Error functions *********************************/ +HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c); +HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c); +uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c); + +/** + * @} + */ + +/** + * @} + */ +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup I2C_Private_Constants I2C Private Constants + * @{ + */ +#define I2C_FLAG_MASK 0x0000FFFFU +#define I2C_MIN_PCLK_FREQ_STANDARD 2000000U /*!< 2 MHz */ +#define I2C_MIN_PCLK_FREQ_FAST 4000000U /*!< 4 MHz */ +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup I2C_Private_Macros I2C Private Macros + * @{ + */ + +#define I2C_MIN_PCLK_FREQ(__PCLK__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__PCLK__) < I2C_MIN_PCLK_FREQ_STANDARD) : ((__PCLK__) < I2C_MIN_PCLK_FREQ_FAST)) +#define I2C_CCR_CALCULATION(__PCLK__, __SPEED__, __COEFF__) (((((__PCLK__) - 1U)/((__SPEED__) * (__COEFF__))) + 1U) & I2C_CCR_CCR) +#define I2C_FREQRANGE(__PCLK__) ((__PCLK__)/1000000U) +#define I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U)) +#define I2C_SPEED_STANDARD(__PCLK__, __SPEED__) ((I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U) < 4U)? 4U:I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U)) +#define I2C_SPEED_FAST(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__DUTYCYCLE__) == I2C_DUTYCYCLE_2)? I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 3U) : (I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 25U) | I2C_DUTYCYCLE_16_9)) +#define I2C_SPEED(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__SPEED__) <= 100000U)? (I2C_SPEED_STANDARD((__PCLK__), (__SPEED__))) : \ + ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__)) & I2C_CCR_CCR) == 0U)? 1U : \ + ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__))) | I2C_CCR_FS)) + +#define I2C_7BIT_ADD_WRITE(__ADDRESS__) ((uint8_t)((__ADDRESS__) & (uint8_t)(~I2C_OAR1_ADD0))) +#define I2C_7BIT_ADD_READ(__ADDRESS__) ((uint8_t)((__ADDRESS__) | I2C_OAR1_ADD0)) + +#define I2C_10BIT_ADDRESS(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF))) +#define I2C_10BIT_HEADER_WRITE(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)0x00F0))) +#define I2C_10BIT_HEADER_READ(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)(0x00F1)))) + +#define I2C_MEM_ADD_MSB(__ADDRESS__) ((uint8_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0xFF00)) >> 8))) +#define I2C_MEM_ADD_LSB(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF))) + +/** @defgroup I2C_IS_RTC_Definitions I2C Private macros to check input parameters + * @{ + */ +#define IS_I2C_DUTY_CYCLE(CYCLE) (((CYCLE) == I2C_DUTYCYCLE_2) || \ + ((CYCLE) == I2C_DUTYCYCLE_16_9)) +#define IS_I2C_ADDRESSING_MODE(ADDRESS) (((ADDRESS) == I2C_ADDRESSINGMODE_7BIT) || \ + ((ADDRESS) == I2C_ADDRESSINGMODE_10BIT)) +#define IS_I2C_DUAL_ADDRESS(ADDRESS) (((ADDRESS) == I2C_DUALADDRESS_DISABLE) || \ + ((ADDRESS) == I2C_DUALADDRESS_ENABLE)) +#define IS_I2C_GENERAL_CALL(CALL) (((CALL) == I2C_GENERALCALL_DISABLE) || \ + ((CALL) == I2C_GENERALCALL_ENABLE)) +#define IS_I2C_NO_STRETCH(STRETCH) (((STRETCH) == I2C_NOSTRETCH_DISABLE) || \ + ((STRETCH) == I2C_NOSTRETCH_ENABLE)) +#define IS_I2C_MEMADD_SIZE(SIZE) (((SIZE) == I2C_MEMADD_SIZE_8BIT) || \ + ((SIZE) == I2C_MEMADD_SIZE_16BIT)) +#define IS_I2C_CLOCK_SPEED(SPEED) (((SPEED) > 0U) && ((SPEED) <= 400000U)) +#define IS_I2C_OWN_ADDRESS1(ADDRESS1) (((ADDRESS1) & 0xFFFFFC00U) == 0U) +#define IS_I2C_OWN_ADDRESS2(ADDRESS2) (((ADDRESS2) & 0xFFFFFF01U) == 0U) +#define IS_I2C_TRANSFER_OPTIONS_REQUEST(REQUEST) (((REQUEST) == I2C_FIRST_FRAME) || \ + ((REQUEST) == I2C_FIRST_AND_NEXT_FRAME) || \ + ((REQUEST) == I2C_NEXT_FRAME) || \ + ((REQUEST) == I2C_FIRST_AND_LAST_FRAME) || \ + ((REQUEST) == I2C_LAST_FRAME) || \ + ((REQUEST) == I2C_LAST_FRAME_NO_STOP) || \ + IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(REQUEST)) + +#define IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(REQUEST) (((REQUEST) == I2C_OTHER_FRAME) || \ + ((REQUEST) == I2C_OTHER_AND_LAST_FRAME)) + +#define I2C_CHECK_FLAG(__ISR__, __FLAG__) ((((__ISR__) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)) ? SET : RESET) +#define I2C_CHECK_IT_SOURCE(__CR1__, __IT__) ((((__CR1__) & (__IT__)) == (__IT__)) ? SET : RESET) +/** + * @} + */ + +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup I2C_Private_Functions I2C Private Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __STM32F4xx_HAL_I2C_H */ + diff --git a/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h new file mode 100644 index 0000000..31ad99c --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c_ex.h @@ -0,0 +1,115 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c_ex.h + * @author MCD Application Team + * @brief Header file of I2C HAL Extension module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_I2C_EX_H +#define __STM32F4xx_HAL_I2C_EX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(I2C_FLTR_ANOFF)&&defined(I2C_FLTR_DNF) +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup I2CEx + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/** @defgroup I2CEx_Exported_Constants I2C Exported Constants + * @{ + */ + +/** @defgroup I2CEx_Analog_Filter I2C Analog Filter + * @{ + */ +#define I2C_ANALOGFILTER_ENABLE 0x00000000U +#define I2C_ANALOGFILTER_DISABLE I2C_FLTR_ANOFF +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup I2CEx_Exported_Functions + * @{ + */ + +/** @addtogroup I2CEx_Exported_Functions_Group1 + * @{ + */ +/* Peripheral Control functions ************************************************/ +HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter); +HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter); +/** + * @} + */ + +/** + * @} + */ +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup I2CEx_Private_Constants I2C Private Constants + * @{ + */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup I2CEx_Private_Macros I2C Private Macros + * @{ + */ +#define IS_I2C_ANALOG_FILTER(FILTER) (((FILTER) == I2C_ANALOGFILTER_ENABLE) || \ + ((FILTER) == I2C_ANALOGFILTER_DISABLE)) +#define IS_I2C_DIGITAL_FILTER(FILTER) ((FILTER) <= 0x0000000FU) +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_I2C_EX_H */ + + diff --git a/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h new file mode 100644 index 0000000..92d4a74 --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_i2c.h @@ -0,0 +1,1890 @@ +/** + ****************************************************************************** + * @file stm32f4xx_ll_i2c.h + * @author MCD Application Team + * @brief Header file of I2C LL module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_LL_I2C_H +#define __STM32F4xx_LL_I2C_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx.h" + +/** @addtogroup STM32F4xx_LL_Driver + * @{ + */ + +#if defined (I2C1) || defined (I2C2) || defined (I2C3) + +/** @defgroup I2C_LL I2C + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup I2C_LL_Private_Constants I2C Private Constants + * @{ + */ + +/* Defines used to perform compute and check in the macros */ +#define LL_I2C_MAX_SPEED_STANDARD 100000U +#define LL_I2C_MAX_SPEED_FAST 400000U +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup I2C_LL_Private_Macros I2C Private Macros + * @{ + */ +/** + * @} + */ +#endif /*USE_FULL_LL_DRIVER*/ + +/* Exported types ------------------------------------------------------------*/ +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup I2C_LL_ES_INIT I2C Exported Init structure + * @{ + */ +typedef struct +{ + uint32_t PeripheralMode; /*!< Specifies the peripheral mode. + This parameter can be a value of @ref I2C_LL_EC_PERIPHERAL_MODE + + This feature can be modified afterwards using unitary function @ref LL_I2C_SetMode(). */ + + uint32_t ClockSpeed; /*!< Specifies the clock frequency. + This parameter must be set to a value lower than 400kHz (in Hz) + + This feature can be modified afterwards using unitary function @ref LL_I2C_SetClockPeriod() + or @ref LL_I2C_SetDutyCycle() or @ref LL_I2C_SetClockSpeedMode() or @ref LL_I2C_ConfigSpeed(). */ + + uint32_t DutyCycle; /*!< Specifies the I2C fast mode duty cycle. + This parameter can be a value of @ref I2C_LL_EC_DUTYCYCLE + + This feature can be modified afterwards using unitary function @ref LL_I2C_SetDutyCycle(). */ + +#if defined(I2C_FLTR_ANOFF)&&defined(I2C_FLTR_DNF) + uint32_t AnalogFilter; /*!< Enables or disables analog noise filter. + This parameter can be a value of @ref I2C_LL_EC_ANALOGFILTER_SELECTION + + This feature can be modified afterwards using unitary functions @ref LL_I2C_EnableAnalogFilter() or LL_I2C_DisableAnalogFilter(). */ + + uint32_t DigitalFilter; /*!< Configures the digital noise filter. + This parameter can be a number between Min_Data = 0x00 and Max_Data = 0x0F + + This feature can be modified afterwards using unitary function @ref LL_I2C_SetDigitalFilter(). */ + +#endif + uint32_t OwnAddress1; /*!< Specifies the device own address 1. + This parameter must be a value between Min_Data = 0x00 and Max_Data = 0x3FF + + This feature can be modified afterwards using unitary function @ref LL_I2C_SetOwnAddress1(). */ + + uint32_t TypeAcknowledge; /*!< Specifies the ACKnowledge or Non ACKnowledge condition after the address receive match code or next received byte. + This parameter can be a value of @ref I2C_LL_EC_I2C_ACKNOWLEDGE + + This feature can be modified afterwards using unitary function @ref LL_I2C_AcknowledgeNextData(). */ + + uint32_t OwnAddrSize; /*!< Specifies the device own address 1 size (7-bit or 10-bit). + This parameter can be a value of @ref I2C_LL_EC_OWNADDRESS1 + + This feature can be modified afterwards using unitary function @ref LL_I2C_SetOwnAddress1(). */ +} LL_I2C_InitTypeDef; +/** + * @} + */ +#endif /*USE_FULL_LL_DRIVER*/ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup I2C_LL_Exported_Constants I2C Exported Constants + * @{ + */ + +/** @defgroup I2C_LL_EC_GET_FLAG Get Flags Defines + * @brief Flags defines which can be used with LL_I2C_ReadReg function + * @{ + */ +#define LL_I2C_SR1_SB I2C_SR1_SB /*!< Start Bit (master mode) */ +#define LL_I2C_SR1_ADDR I2C_SR1_ADDR /*!< Address sent (master mode) or + Address matched flag (slave mode) */ +#define LL_I2C_SR1_BTF I2C_SR1_BTF /*!< Byte Transfer Finished flag */ +#define LL_I2C_SR1_ADD10 I2C_SR1_ADD10 /*!< 10-bit header sent (master mode) */ +#define LL_I2C_SR1_STOPF I2C_SR1_STOPF /*!< Stop detection flag (slave mode) */ +#define LL_I2C_SR1_RXNE I2C_SR1_RXNE /*!< Data register not empty (receivers) */ +#define LL_I2C_SR1_TXE I2C_SR1_TXE /*!< Data register empty (transmitters) */ +#define LL_I2C_SR1_BERR I2C_SR1_BERR /*!< Bus error */ +#define LL_I2C_SR1_ARLO I2C_SR1_ARLO /*!< Arbitration lost */ +#define LL_I2C_SR1_AF I2C_SR1_AF /*!< Acknowledge failure flag */ +#define LL_I2C_SR1_OVR I2C_SR1_OVR /*!< Overrun/Underrun */ +#define LL_I2C_SR1_PECERR I2C_ISR_PECERR /*!< PEC Error in reception (SMBus mode) */ +#define LL_I2C_SR1_TIMEOUT I2C_ISR_TIMEOUT /*!< Timeout detection flag (SMBus mode) */ +#define LL_I2C_SR1_SMALERT I2C_ISR_SMALERT /*!< SMBus alert (SMBus mode) */ +#define LL_I2C_SR2_MSL I2C_SR2_MSL /*!< Master/Slave flag */ +#define LL_I2C_SR2_BUSY I2C_SR2_BUSY /*!< Bus busy flag */ +#define LL_I2C_SR2_TRA I2C_SR2_TRA /*!< Transmitter/receiver direction */ +#define LL_I2C_SR2_GENCALL I2C_SR2_GENCALL /*!< General call address (Slave mode) */ +#define LL_I2C_SR2_SMBDEFAULT I2C_SR2_SMBDEFAULT /*!< SMBus Device default address (Slave mode) */ +#define LL_I2C_SR2_SMBHOST I2C_SR2_SMBHOST /*!< SMBus Host address (Slave mode) */ +#define LL_I2C_SR2_DUALF I2C_SR2_DUALF /*!< Dual flag (Slave mode) */ +/** + * @} + */ + +/** @defgroup I2C_LL_EC_IT IT Defines + * @brief IT defines which can be used with LL_I2C_ReadReg and LL_I2C_WriteReg functions + * @{ + */ +#define LL_I2C_CR2_ITEVTEN I2C_CR2_ITEVTEN /*!< Events interrupts enable */ +#define LL_I2C_CR2_ITBUFEN I2C_CR2_ITBUFEN /*!< Buffer interrupts enable */ +#define LL_I2C_CR2_ITERREN I2C_CR2_ITERREN /*!< Error interrupts enable */ +/** + * @} + */ + +#if defined(I2C_FLTR_ANOFF) +/** @defgroup I2C_LL_EC_ANALOGFILTER_SELECTION Analog Filter Selection + * @{ + */ +#define LL_I2C_ANALOGFILTER_ENABLE 0x00000000U /*!< Analog filter is enabled. */ +#define LL_I2C_ANALOGFILTER_DISABLE I2C_FLTR_ANOFF /*!< Analog filter is disabled.*/ +/** + * @} + */ + +#endif +/** @defgroup I2C_LL_EC_OWNADDRESS1 Own Address 1 Length + * @{ + */ +#define LL_I2C_OWNADDRESS1_7BIT 0x00004000U /*!< Own address 1 is a 7-bit address. */ +#define LL_I2C_OWNADDRESS1_10BIT (uint32_t)(I2C_OAR1_ADDMODE | 0x00004000U) /*!< Own address 1 is a 10-bit address. */ +/** + * @} + */ + +/** @defgroup I2C_LL_EC_DUTYCYCLE Fast Mode Duty Cycle + * @{ + */ +#define LL_I2C_DUTYCYCLE_2 0x00000000U /*!< I2C fast mode Tlow/Thigh = 2 */ +#define LL_I2C_DUTYCYCLE_16_9 I2C_CCR_DUTY /*!< I2C fast mode Tlow/Thigh = 16/9 */ +/** + * @} + */ + +/** @defgroup I2C_LL_EC_CLOCK_SPEED_MODE Master Clock Speed Mode + * @{ + */ +#define LL_I2C_CLOCK_SPEED_STANDARD_MODE 0x00000000U /*!< Master clock speed range is standard mode */ +#define LL_I2C_CLOCK_SPEED_FAST_MODE I2C_CCR_FS /*!< Master clock speed range is fast mode */ +/** + * @} + */ + +/** @defgroup I2C_LL_EC_PERIPHERAL_MODE Peripheral Mode + * @{ + */ +#define LL_I2C_MODE_I2C 0x00000000U /*!< I2C Master or Slave mode */ +#define LL_I2C_MODE_SMBUS_HOST (uint32_t)(I2C_CR1_SMBUS | I2C_CR1_SMBTYPE | I2C_CR1_ENARP) /*!< SMBus Host address acknowledge */ +#define LL_I2C_MODE_SMBUS_DEVICE I2C_CR1_SMBUS /*!< SMBus Device default mode (Default address not acknowledge) */ +#define LL_I2C_MODE_SMBUS_DEVICE_ARP (uint32_t)(I2C_CR1_SMBUS | I2C_CR1_ENARP) /*!< SMBus Device Default address acknowledge */ +/** + * @} + */ + +/** @defgroup I2C_LL_EC_I2C_ACKNOWLEDGE Acknowledge Generation + * @{ + */ +#define LL_I2C_ACK I2C_CR1_ACK /*!< ACK is sent after current received byte. */ +#define LL_I2C_NACK 0x00000000U /*!< NACK is sent after current received byte.*/ +/** + * @} + */ + +/** @defgroup I2C_LL_EC_DIRECTION Read Write Direction + * @{ + */ +#define LL_I2C_DIRECTION_WRITE I2C_SR2_TRA /*!< Bus is in write transfer */ +#define LL_I2C_DIRECTION_READ 0x00000000U /*!< Bus is in read transfer */ +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup I2C_LL_Exported_Macros I2C Exported Macros + * @{ + */ + +/** @defgroup I2C_LL_EM_WRITE_READ Common Write and read registers Macros + * @{ + */ + +/** + * @brief Write a value in I2C register + * @param __INSTANCE__ I2C Instance + * @param __REG__ Register to be written + * @param __VALUE__ Value to be written in the register + * @retval None + */ +#define LL_I2C_WriteReg(__INSTANCE__, __REG__, __VALUE__) WRITE_REG(__INSTANCE__->__REG__, (__VALUE__)) + +/** + * @brief Read a value in I2C register + * @param __INSTANCE__ I2C Instance + * @param __REG__ Register to be read + * @retval Register value + */ +#define LL_I2C_ReadReg(__INSTANCE__, __REG__) READ_REG(__INSTANCE__->__REG__) +/** + * @} + */ + +/** @defgroup I2C_LL_EM_Exported_Macros_Helper Exported Macros Helper + * @{ + */ + +/** + * @brief Convert Peripheral Clock Frequency in Mhz. + * @param __PCLK__ This parameter must be a value of peripheral clock (in Hz). + * @retval Value of peripheral clock (in Mhz) + */ +#define __LL_I2C_FREQ_HZ_TO_MHZ(__PCLK__) (uint32_t)((__PCLK__)/1000000U) + +/** + * @brief Convert Peripheral Clock Frequency in Hz. + * @param __PCLK__ This parameter must be a value of peripheral clock (in Mhz). + * @retval Value of peripheral clock (in Hz) + */ +#define __LL_I2C_FREQ_MHZ_TO_HZ(__PCLK__) (uint32_t)((__PCLK__)*1000000U) + +/** + * @brief Compute I2C Clock rising time. + * @param __FREQRANGE__ This parameter must be a value of peripheral clock (in Mhz). + * @param __SPEED__ This parameter must be a value lower than 400kHz (in Hz). + * @retval Value between Min_Data=0x02 and Max_Data=0x3F + */ +#define __LL_I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (uint32_t)(((__SPEED__) <= LL_I2C_MAX_SPEED_STANDARD) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U)) + +/** + * @brief Compute Speed clock range to a Clock Control Register (I2C_CCR_CCR) value. + * @param __PCLK__ This parameter must be a value of peripheral clock (in Hz). + * @param __SPEED__ This parameter must be a value lower than 400kHz (in Hz). + * @param __DUTYCYCLE__ This parameter can be one of the following values: + * @arg @ref LL_I2C_DUTYCYCLE_2 + * @arg @ref LL_I2C_DUTYCYCLE_16_9 + * @retval Value between Min_Data=0x004 and Max_Data=0xFFF, except in FAST DUTY mode where Min_Data=0x001. + */ +#define __LL_I2C_SPEED_TO_CCR(__PCLK__, __SPEED__, __DUTYCYCLE__) (uint32_t)(((__SPEED__) <= LL_I2C_MAX_SPEED_STANDARD)? \ + (__LL_I2C_SPEED_STANDARD_TO_CCR((__PCLK__), (__SPEED__))) : \ + (__LL_I2C_SPEED_FAST_TO_CCR((__PCLK__), (__SPEED__), (__DUTYCYCLE__)))) + +/** + * @brief Compute Speed Standard clock range to a Clock Control Register (I2C_CCR_CCR) value. + * @param __PCLK__ This parameter must be a value of peripheral clock (in Hz). + * @param __SPEED__ This parameter must be a value lower than 100kHz (in Hz). + * @retval Value between Min_Data=0x004 and Max_Data=0xFFF. + */ +#define __LL_I2C_SPEED_STANDARD_TO_CCR(__PCLK__, __SPEED__) (uint32_t)(((((__PCLK__)/((__SPEED__) << 1U)) & I2C_CCR_CCR) < 4U)? 4U:((__PCLK__) / ((__SPEED__) << 1U))) + +/** + * @brief Compute Speed Fast clock range to a Clock Control Register (I2C_CCR_CCR) value. + * @param __PCLK__ This parameter must be a value of peripheral clock (in Hz). + * @param __SPEED__ This parameter must be a value between Min_Data=100Khz and Max_Data=400Khz (in Hz). + * @param __DUTYCYCLE__ This parameter can be one of the following values: + * @arg @ref LL_I2C_DUTYCYCLE_2 + * @arg @ref LL_I2C_DUTYCYCLE_16_9 + * @retval Value between Min_Data=0x001 and Max_Data=0xFFF + */ +#define __LL_I2C_SPEED_FAST_TO_CCR(__PCLK__, __SPEED__, __DUTYCYCLE__) (uint32_t)(((__DUTYCYCLE__) == LL_I2C_DUTYCYCLE_2)? \ + (((((__PCLK__) / ((__SPEED__) * 3U)) & I2C_CCR_CCR) == 0U)? 1U:((__PCLK__) / ((__SPEED__) * 3U))) : \ + (((((__PCLK__) / ((__SPEED__) * 25U)) & I2C_CCR_CCR) == 0U)? 1U:((__PCLK__) / ((__SPEED__) * 25U)))) + +/** + * @brief Get the Least significant bits of a 10-Bits address. + * @param __ADDRESS__ This parameter must be a value of a 10-Bits slave address. + * @retval Value between Min_Data=0x00 and Max_Data=0xFF + */ +#define __LL_I2C_10BIT_ADDRESS(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)(0x00FF)))) + +/** + * @brief Convert a 10-Bits address to a 10-Bits header with Write direction. + * @param __ADDRESS__ This parameter must be a value of a 10-Bits slave address. + * @retval Value between Min_Data=0xF0 and Max_Data=0xF6 + */ +#define __LL_I2C_10BIT_HEADER_WRITE(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)(0x0300))) >> 7) | (uint16_t)(0xF0)))) + +/** + * @brief Convert a 10-Bits address to a 10-Bits header with Read direction. + * @param __ADDRESS__ This parameter must be a value of a 10-Bits slave address. + * @retval Value between Min_Data=0xF1 and Max_Data=0xF7 + */ +#define __LL_I2C_10BIT_HEADER_READ(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)(0x0300))) >> 7) | (uint16_t)(0xF1)))) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @defgroup I2C_LL_Exported_Functions I2C Exported Functions + * @{ + */ + +/** @defgroup I2C_LL_EF_Configuration Configuration + * @{ + */ + +/** + * @brief Enable I2C peripheral (PE = 1). + * @rmtoll CR1 PE LL_I2C_Enable + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_Enable(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_PE); +} + +/** + * @brief Disable I2C peripheral (PE = 0). + * @rmtoll CR1 PE LL_I2C_Disable + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_Disable(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_PE); +} + +/** + * @brief Check if the I2C peripheral is enabled or disabled. + * @rmtoll CR1 PE LL_I2C_IsEnabled + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabled(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_PE) == (I2C_CR1_PE)); +} + +#if defined(I2C_FLTR_ANOFF)&&defined(I2C_FLTR_DNF) +/** + * @brief Configure Noise Filters (Analog and Digital). + * @note If the analog filter is also enabled, the digital filter is added to analog filter. + * The filters can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll FLTR ANOFF LL_I2C_ConfigFilters\n + * FLTR DNF LL_I2C_ConfigFilters + * @param I2Cx I2C Instance. + * @param AnalogFilter This parameter can be one of the following values: + * @arg @ref LL_I2C_ANALOGFILTER_ENABLE + * @arg @ref LL_I2C_ANALOGFILTER_DISABLE + * @param DigitalFilter This parameter must be a value between Min_Data=0x00 (Digital filter disabled) and Max_Data=0x0F (Digital filter enabled and filtering capability up to 15*TPCLK1) + * This parameter is used to configure the digital noise filter on SDA and SCL input. The digital filter will suppress the spikes with a length of up to DNF[3:0]*TPCLK1. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ConfigFilters(I2C_TypeDef *I2Cx, uint32_t AnalogFilter, uint32_t DigitalFilter) +{ + MODIFY_REG(I2Cx->FLTR, I2C_FLTR_ANOFF | I2C_FLTR_DNF, AnalogFilter | DigitalFilter); +} +#endif +#if defined(I2C_FLTR_DNF) + +/** + * @brief Configure Digital Noise Filter. + * @note If the analog filter is also enabled, the digital filter is added to analog filter. + * This filter can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll FLTR DNF LL_I2C_SetDigitalFilter + * @param I2Cx I2C Instance. + * @param DigitalFilter This parameter must be a value between Min_Data=0x00 (Digital filter disabled) and Max_Data=0x0F (Digital filter enabled and filtering capability up to 15*TPCLK1) + * This parameter is used to configure the digital noise filter on SDA and SCL input. The digital filter will suppress the spikes with a length of up to DNF[3:0]*TPCLK1. + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetDigitalFilter(I2C_TypeDef *I2Cx, uint32_t DigitalFilter) +{ + MODIFY_REG(I2Cx->FLTR, I2C_FLTR_DNF, DigitalFilter); +} + +/** + * @brief Get the current Digital Noise Filter configuration. + * @rmtoll FLTR DNF LL_I2C_GetDigitalFilter + * @param I2Cx I2C Instance. + * @retval Value between Min_Data=0x0 and Max_Data=0xF + */ +__STATIC_INLINE uint32_t LL_I2C_GetDigitalFilter(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->FLTR, I2C_FLTR_DNF)); +} +#endif +#if defined(I2C_FLTR_ANOFF) + +/** + * @brief Enable Analog Noise Filter. + * @note This filter can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll FLTR ANOFF LL_I2C_EnableAnalogFilter + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableAnalogFilter(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->FLTR, I2C_FLTR_ANOFF); +} + +/** + * @brief Disable Analog Noise Filter. + * @note This filter can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll FLTR ANOFF LL_I2C_DisableAnalogFilter + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableAnalogFilter(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->FLTR, I2C_FLTR_ANOFF); +} + +/** + * @brief Check if Analog Noise Filter is enabled or disabled. + * @rmtoll FLTR ANOFF LL_I2C_IsEnabledAnalogFilter + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledAnalogFilter(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->FLTR, I2C_FLTR_ANOFF) == (I2C_FLTR_ANOFF)); +} +#endif + +/** + * @brief Enable DMA transmission requests. + * @rmtoll CR2 DMAEN LL_I2C_EnableDMAReq_TX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableDMAReq_TX(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_DMAEN); +} + +/** + * @brief Disable DMA transmission requests. + * @rmtoll CR2 DMAEN LL_I2C_DisableDMAReq_TX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableDMAReq_TX(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_DMAEN); +} + +/** + * @brief Check if DMA transmission requests are enabled or disabled. + * @rmtoll CR2 DMAEN LL_I2C_IsEnabledDMAReq_TX + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledDMAReq_TX(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_DMAEN) == (I2C_CR2_DMAEN)); +} + +/** + * @brief Enable DMA reception requests. + * @rmtoll CR2 DMAEN LL_I2C_EnableDMAReq_RX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableDMAReq_RX(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_DMAEN); +} + +/** + * @brief Disable DMA reception requests. + * @rmtoll CR2 DMAEN LL_I2C_DisableDMAReq_RX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableDMAReq_RX(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_DMAEN); +} + +/** + * @brief Check if DMA reception requests are enabled or disabled. + * @rmtoll CR2 DMAEN LL_I2C_IsEnabledDMAReq_RX + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledDMAReq_RX(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_DMAEN) == (I2C_CR2_DMAEN)); +} + +/** + * @brief Get the data register address used for DMA transfer. + * @rmtoll DR DR LL_I2C_DMA_GetRegAddr + * @param I2Cx I2C Instance. + * @retval Address of data register + */ +__STATIC_INLINE uint32_t LL_I2C_DMA_GetRegAddr(I2C_TypeDef *I2Cx) +{ + return (uint32_t) & (I2Cx->DR); +} + +/** + * @brief Enable Clock stretching. + * @note This bit can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll CR1 NOSTRETCH LL_I2C_EnableClockStretching + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableClockStretching(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_NOSTRETCH); +} + +/** + * @brief Disable Clock stretching. + * @note This bit can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll CR1 NOSTRETCH LL_I2C_DisableClockStretching + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableClockStretching(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_NOSTRETCH); +} + +/** + * @brief Check if Clock stretching is enabled or disabled. + * @rmtoll CR1 NOSTRETCH LL_I2C_IsEnabledClockStretching + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledClockStretching(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_NOSTRETCH) != (I2C_CR1_NOSTRETCH)); +} + +/** + * @brief Enable General Call. + * @note When enabled the Address 0x00 is ACKed. + * @rmtoll CR1 ENGC LL_I2C_EnableGeneralCall + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableGeneralCall(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_ENGC); +} + +/** + * @brief Disable General Call. + * @note When disabled the Address 0x00 is NACKed. + * @rmtoll CR1 ENGC LL_I2C_DisableGeneralCall + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableGeneralCall(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_ENGC); +} + +/** + * @brief Check if General Call is enabled or disabled. + * @rmtoll CR1 ENGC LL_I2C_IsEnabledGeneralCall + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledGeneralCall(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_ENGC) == (I2C_CR1_ENGC)); +} + +/** + * @brief Set the Own Address1. + * @rmtoll OAR1 ADD0 LL_I2C_SetOwnAddress1\n + * OAR1 ADD1_7 LL_I2C_SetOwnAddress1\n + * OAR1 ADD8_9 LL_I2C_SetOwnAddress1\n + * OAR1 ADDMODE LL_I2C_SetOwnAddress1 + * @param I2Cx I2C Instance. + * @param OwnAddress1 This parameter must be a value between Min_Data=0 and Max_Data=0x3FF. + * @param OwnAddrSize This parameter can be one of the following values: + * @arg @ref LL_I2C_OWNADDRESS1_7BIT + * @arg @ref LL_I2C_OWNADDRESS1_10BIT + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetOwnAddress1(I2C_TypeDef *I2Cx, uint32_t OwnAddress1, uint32_t OwnAddrSize) +{ + MODIFY_REG(I2Cx->OAR1, I2C_OAR1_ADD0 | I2C_OAR1_ADD1_7 | I2C_OAR1_ADD8_9 | I2C_OAR1_ADDMODE, OwnAddress1 | OwnAddrSize); +} + +/** + * @brief Set the 7bits Own Address2. + * @note This action has no effect if own address2 is enabled. + * @rmtoll OAR2 ADD2 LL_I2C_SetOwnAddress2 + * @param I2Cx I2C Instance. + * @param OwnAddress2 This parameter must be a value between Min_Data=0 and Max_Data=0x7F. + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetOwnAddress2(I2C_TypeDef *I2Cx, uint32_t OwnAddress2) +{ + MODIFY_REG(I2Cx->OAR2, I2C_OAR2_ADD2, OwnAddress2); +} + +/** + * @brief Enable acknowledge on Own Address2 match address. + * @rmtoll OAR2 ENDUAL LL_I2C_EnableOwnAddress2 + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableOwnAddress2(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->OAR2, I2C_OAR2_ENDUAL); +} + +/** + * @brief Disable acknowledge on Own Address2 match address. + * @rmtoll OAR2 ENDUAL LL_I2C_DisableOwnAddress2 + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableOwnAddress2(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->OAR2, I2C_OAR2_ENDUAL); +} + +/** + * @brief Check if Own Address1 acknowledge is enabled or disabled. + * @rmtoll OAR2 ENDUAL LL_I2C_IsEnabledOwnAddress2 + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledOwnAddress2(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->OAR2, I2C_OAR2_ENDUAL) == (I2C_OAR2_ENDUAL)); +} + +/** + * @brief Configure the Peripheral clock frequency. + * @rmtoll CR2 FREQ LL_I2C_SetPeriphClock + * @param I2Cx I2C Instance. + * @param PeriphClock Peripheral Clock (in Hz) + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetPeriphClock(I2C_TypeDef *I2Cx, uint32_t PeriphClock) +{ + MODIFY_REG(I2Cx->CR2, I2C_CR2_FREQ, __LL_I2C_FREQ_HZ_TO_MHZ(PeriphClock)); +} + +/** + * @brief Get the Peripheral clock frequency. + * @rmtoll CR2 FREQ LL_I2C_GetPeriphClock + * @param I2Cx I2C Instance. + * @retval Value of Peripheral Clock (in Hz) + */ +__STATIC_INLINE uint32_t LL_I2C_GetPeriphClock(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(__LL_I2C_FREQ_MHZ_TO_HZ(READ_BIT(I2Cx->CR2, I2C_CR2_FREQ))); +} + +/** + * @brief Configure the Duty cycle (Fast mode only). + * @rmtoll CCR DUTY LL_I2C_SetDutyCycle + * @param I2Cx I2C Instance. + * @param DutyCycle This parameter can be one of the following values: + * @arg @ref LL_I2C_DUTYCYCLE_2 + * @arg @ref LL_I2C_DUTYCYCLE_16_9 + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetDutyCycle(I2C_TypeDef *I2Cx, uint32_t DutyCycle) +{ + MODIFY_REG(I2Cx->CCR, I2C_CCR_DUTY, DutyCycle); +} + +/** + * @brief Get the Duty cycle (Fast mode only). + * @rmtoll CCR DUTY LL_I2C_GetDutyCycle + * @param I2Cx I2C Instance. + * @retval Returned value can be one of the following values: + * @arg @ref LL_I2C_DUTYCYCLE_2 + * @arg @ref LL_I2C_DUTYCYCLE_16_9 + */ +__STATIC_INLINE uint32_t LL_I2C_GetDutyCycle(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->CCR, I2C_CCR_DUTY)); +} + +/** + * @brief Configure the I2C master clock speed mode. + * @rmtoll CCR FS LL_I2C_SetClockSpeedMode + * @param I2Cx I2C Instance. + * @param ClockSpeedMode This parameter can be one of the following values: + * @arg @ref LL_I2C_CLOCK_SPEED_STANDARD_MODE + * @arg @ref LL_I2C_CLOCK_SPEED_FAST_MODE + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetClockSpeedMode(I2C_TypeDef *I2Cx, uint32_t ClockSpeedMode) +{ + MODIFY_REG(I2Cx->CCR, I2C_CCR_FS, ClockSpeedMode); +} + +/** + * @brief Get the the I2C master speed mode. + * @rmtoll CCR FS LL_I2C_GetClockSpeedMode + * @param I2Cx I2C Instance. + * @retval Returned value can be one of the following values: + * @arg @ref LL_I2C_CLOCK_SPEED_STANDARD_MODE + * @arg @ref LL_I2C_CLOCK_SPEED_FAST_MODE + */ +__STATIC_INLINE uint32_t LL_I2C_GetClockSpeedMode(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->CCR, I2C_CCR_FS)); +} + +/** + * @brief Configure the SCL, SDA rising time. + * @note This bit can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll TRISE TRISE LL_I2C_SetRiseTime + * @param I2Cx I2C Instance. + * @param RiseTime This parameter must be a value between Min_Data=0x02 and Max_Data=0x3F. + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetRiseTime(I2C_TypeDef *I2Cx, uint32_t RiseTime) +{ + MODIFY_REG(I2Cx->TRISE, I2C_TRISE_TRISE, RiseTime); +} + +/** + * @brief Get the SCL, SDA rising time. + * @rmtoll TRISE TRISE LL_I2C_GetRiseTime + * @param I2Cx I2C Instance. + * @retval Value between Min_Data=0x02 and Max_Data=0x3F + */ +__STATIC_INLINE uint32_t LL_I2C_GetRiseTime(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->TRISE, I2C_TRISE_TRISE)); +} + +/** + * @brief Configure the SCL high and low period. + * @note This bit can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll CCR CCR LL_I2C_SetClockPeriod + * @param I2Cx I2C Instance. + * @param ClockPeriod This parameter must be a value between Min_Data=0x004 and Max_Data=0xFFF, except in FAST DUTY mode where Min_Data=0x001. + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetClockPeriod(I2C_TypeDef *I2Cx, uint32_t ClockPeriod) +{ + MODIFY_REG(I2Cx->CCR, I2C_CCR_CCR, ClockPeriod); +} + +/** + * @brief Get the SCL high and low period. + * @rmtoll CCR CCR LL_I2C_GetClockPeriod + * @param I2Cx I2C Instance. + * @retval Value between Min_Data=0x004 and Max_Data=0xFFF, except in FAST DUTY mode where Min_Data=0x001. + */ +__STATIC_INLINE uint32_t LL_I2C_GetClockPeriod(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->CCR, I2C_CCR_CCR)); +} + +/** + * @brief Configure the SCL speed. + * @note This bit can only be programmed when the I2C is disabled (PE = 0). + * @rmtoll CR2 FREQ LL_I2C_ConfigSpeed\n + * TRISE TRISE LL_I2C_ConfigSpeed\n + * CCR FS LL_I2C_ConfigSpeed\n + * CCR DUTY LL_I2C_ConfigSpeed\n + * CCR CCR LL_I2C_ConfigSpeed + * @param I2Cx I2C Instance. + * @param PeriphClock Peripheral Clock (in Hz) + * @param ClockSpeed This parameter must be a value lower than 400kHz (in Hz). + * @param DutyCycle This parameter can be one of the following values: + * @arg @ref LL_I2C_DUTYCYCLE_2 + * @arg @ref LL_I2C_DUTYCYCLE_16_9 + * @retval None + */ +__STATIC_INLINE void LL_I2C_ConfigSpeed(I2C_TypeDef *I2Cx, uint32_t PeriphClock, uint32_t ClockSpeed, + uint32_t DutyCycle) +{ + uint32_t freqrange = 0x0U; + uint32_t clockconfig = 0x0U; + + /* Compute frequency range */ + freqrange = __LL_I2C_FREQ_HZ_TO_MHZ(PeriphClock); + + /* Configure I2Cx: Frequency range register */ + MODIFY_REG(I2Cx->CR2, I2C_CR2_FREQ, freqrange); + + /* Configure I2Cx: Rise Time register */ + MODIFY_REG(I2Cx->TRISE, I2C_TRISE_TRISE, __LL_I2C_RISE_TIME(freqrange, ClockSpeed)); + + /* Configure Speed mode, Duty Cycle and Clock control register value */ + if (ClockSpeed > LL_I2C_MAX_SPEED_STANDARD) + { + /* Set Speed mode at fast and duty cycle for Clock Speed request in fast clock range */ + clockconfig = LL_I2C_CLOCK_SPEED_FAST_MODE | \ + __LL_I2C_SPEED_FAST_TO_CCR(PeriphClock, ClockSpeed, DutyCycle) | \ + DutyCycle; + } + else + { + /* Set Speed mode at standard for Clock Speed request in standard clock range */ + clockconfig = LL_I2C_CLOCK_SPEED_STANDARD_MODE | \ + __LL_I2C_SPEED_STANDARD_TO_CCR(PeriphClock, ClockSpeed); + } + + /* Configure I2Cx: Clock control register */ + MODIFY_REG(I2Cx->CCR, (I2C_CCR_FS | I2C_CCR_DUTY | I2C_CCR_CCR), clockconfig); +} + +/** + * @brief Configure peripheral mode. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 SMBUS LL_I2C_SetMode\n + * CR1 SMBTYPE LL_I2C_SetMode\n + * CR1 ENARP LL_I2C_SetMode + * @param I2Cx I2C Instance. + * @param PeripheralMode This parameter can be one of the following values: + * @arg @ref LL_I2C_MODE_I2C + * @arg @ref LL_I2C_MODE_SMBUS_HOST + * @arg @ref LL_I2C_MODE_SMBUS_DEVICE + * @arg @ref LL_I2C_MODE_SMBUS_DEVICE_ARP + * @retval None + */ +__STATIC_INLINE void LL_I2C_SetMode(I2C_TypeDef *I2Cx, uint32_t PeripheralMode) +{ + MODIFY_REG(I2Cx->CR1, I2C_CR1_SMBUS | I2C_CR1_SMBTYPE | I2C_CR1_ENARP, PeripheralMode); +} + +/** + * @brief Get peripheral mode. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 SMBUS LL_I2C_GetMode\n + * CR1 SMBTYPE LL_I2C_GetMode\n + * CR1 ENARP LL_I2C_GetMode + * @param I2Cx I2C Instance. + * @retval Returned value can be one of the following values: + * @arg @ref LL_I2C_MODE_I2C + * @arg @ref LL_I2C_MODE_SMBUS_HOST + * @arg @ref LL_I2C_MODE_SMBUS_DEVICE + * @arg @ref LL_I2C_MODE_SMBUS_DEVICE_ARP + */ +__STATIC_INLINE uint32_t LL_I2C_GetMode(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->CR1, I2C_CR1_SMBUS | I2C_CR1_SMBTYPE | I2C_CR1_ENARP)); +} + +/** + * @brief Enable SMBus alert (Host or Device mode) + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note SMBus Device mode: + * - SMBus Alert pin is drived low and + * Alert Response Address Header acknowledge is enabled. + * SMBus Host mode: + * - SMBus Alert pin management is supported. + * @rmtoll CR1 ALERT LL_I2C_EnableSMBusAlert + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableSMBusAlert(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_ALERT); +} + +/** + * @brief Disable SMBus alert (Host or Device mode) + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note SMBus Device mode: + * - SMBus Alert pin is not drived (can be used as a standard GPIO) and + * Alert Response Address Header acknowledge is disabled. + * SMBus Host mode: + * - SMBus Alert pin management is not supported. + * @rmtoll CR1 ALERT LL_I2C_DisableSMBusAlert + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableSMBusAlert(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_ALERT); +} + +/** + * @brief Check if SMBus alert (Host or Device mode) is enabled or disabled. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 ALERT LL_I2C_IsEnabledSMBusAlert + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledSMBusAlert(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_ALERT) == (I2C_CR1_ALERT)); +} + +/** + * @brief Enable SMBus Packet Error Calculation (PEC). + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 ENPEC LL_I2C_EnableSMBusPEC + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableSMBusPEC(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_ENPEC); +} + +/** + * @brief Disable SMBus Packet Error Calculation (PEC). + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 ENPEC LL_I2C_DisableSMBusPEC + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableSMBusPEC(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_ENPEC); +} + +/** + * @brief Check if SMBus Packet Error Calculation (PEC) is enabled or disabled. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 ENPEC LL_I2C_IsEnabledSMBusPEC + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledSMBusPEC(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_ENPEC) == (I2C_CR1_ENPEC)); +} + +/** + * @} + */ + +/** @defgroup I2C_LL_EF_IT_Management IT_Management + * @{ + */ + +/** + * @brief Enable TXE interrupt. + * @rmtoll CR2 ITEVTEN LL_I2C_EnableIT_TX\n + * CR2 ITBUFEN LL_I2C_EnableIT_TX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableIT_TX(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN); +} + +/** + * @brief Disable TXE interrupt. + * @rmtoll CR2 ITEVTEN LL_I2C_DisableIT_TX\n + * CR2 ITBUFEN LL_I2C_DisableIT_TX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableIT_TX(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN); +} + +/** + * @brief Check if the TXE Interrupt is enabled or disabled. + * @rmtoll CR2 ITEVTEN LL_I2C_IsEnabledIT_TX\n + * CR2 ITBUFEN LL_I2C_IsEnabledIT_TX + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledIT_TX(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN) == (I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN)); +} + +/** + * @brief Enable RXNE interrupt. + * @rmtoll CR2 ITEVTEN LL_I2C_EnableIT_RX\n + * CR2 ITBUFEN LL_I2C_EnableIT_RX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableIT_RX(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN); +} + +/** + * @brief Disable RXNE interrupt. + * @rmtoll CR2 ITEVTEN LL_I2C_DisableIT_RX\n + * CR2 ITBUFEN LL_I2C_DisableIT_RX + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableIT_RX(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN); +} + +/** + * @brief Check if the RXNE Interrupt is enabled or disabled. + * @rmtoll CR2 ITEVTEN LL_I2C_IsEnabledIT_RX\n + * CR2 ITBUFEN LL_I2C_IsEnabledIT_RX + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledIT_RX(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN) == (I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN)); +} + +/** + * @brief Enable Events interrupts. + * @note Any of these events will generate interrupt : + * Start Bit (SB) + * Address sent, Address matched (ADDR) + * 10-bit header sent (ADD10) + * Stop detection (STOPF) + * Byte transfer finished (BTF) + * + * @note Any of these events will generate interrupt if Buffer interrupts are enabled too(using unitary function @ref LL_I2C_EnableIT_BUF()) : + * Receive buffer not empty (RXNE) + * Transmit buffer empty (TXE) + * @rmtoll CR2 ITEVTEN LL_I2C_EnableIT_EVT + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableIT_EVT(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN); +} + +/** + * @brief Disable Events interrupts. + * @note Any of these events will generate interrupt : + * Start Bit (SB) + * Address sent, Address matched (ADDR) + * 10-bit header sent (ADD10) + * Stop detection (STOPF) + * Byte transfer finished (BTF) + * Receive buffer not empty (RXNE) + * Transmit buffer empty (TXE) + * @rmtoll CR2 ITEVTEN LL_I2C_DisableIT_EVT + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableIT_EVT(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN); +} + +/** + * @brief Check if Events interrupts are enabled or disabled. + * @rmtoll CR2 ITEVTEN LL_I2C_IsEnabledIT_EVT + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledIT_EVT(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_ITEVTEN) == (I2C_CR2_ITEVTEN)); +} + +/** + * @brief Enable Buffer interrupts. + * @note Any of these Buffer events will generate interrupt if Events interrupts are enabled too(using unitary function @ref LL_I2C_EnableIT_EVT()) : + * Receive buffer not empty (RXNE) + * Transmit buffer empty (TXE) + * @rmtoll CR2 ITBUFEN LL_I2C_EnableIT_BUF + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableIT_BUF(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_ITBUFEN); +} + +/** + * @brief Disable Buffer interrupts. + * @note Any of these Buffer events will generate interrupt : + * Receive buffer not empty (RXNE) + * Transmit buffer empty (TXE) + * @rmtoll CR2 ITBUFEN LL_I2C_DisableIT_BUF + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableIT_BUF(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_ITBUFEN); +} + +/** + * @brief Check if Buffer interrupts are enabled or disabled. + * @rmtoll CR2 ITBUFEN LL_I2C_IsEnabledIT_BUF + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledIT_BUF(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_ITBUFEN) == (I2C_CR2_ITBUFEN)); +} + +/** + * @brief Enable Error interrupts. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note Any of these errors will generate interrupt : + * Bus Error detection (BERR) + * Arbitration Loss (ARLO) + * Acknowledge Failure(AF) + * Overrun/Underrun (OVR) + * SMBus Timeout detection (TIMEOUT) + * SMBus PEC error detection (PECERR) + * SMBus Alert pin event detection (SMBALERT) + * @rmtoll CR2 ITERREN LL_I2C_EnableIT_ERR + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableIT_ERR(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_ITERREN); +} + +/** + * @brief Disable Error interrupts. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note Any of these errors will generate interrupt : + * Bus Error detection (BERR) + * Arbitration Loss (ARLO) + * Acknowledge Failure(AF) + * Overrun/Underrun (OVR) + * SMBus Timeout detection (TIMEOUT) + * SMBus PEC error detection (PECERR) + * SMBus Alert pin event detection (SMBALERT) + * @rmtoll CR2 ITERREN LL_I2C_DisableIT_ERR + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableIT_ERR(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_ITERREN); +} + +/** + * @brief Check if Error interrupts are enabled or disabled. + * @rmtoll CR2 ITERREN LL_I2C_IsEnabledIT_ERR + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledIT_ERR(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_ITERREN) == (I2C_CR2_ITERREN)); +} + +/** + * @} + */ + +/** @defgroup I2C_LL_EF_FLAG_management FLAG_management + * @{ + */ + +/** + * @brief Indicate the status of Transmit data register empty flag. + * @note RESET: When next data is written in Transmit data register. + * SET: When Transmit data register is empty. + * @rmtoll SR1 TXE LL_I2C_IsActiveFlag_TXE + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_TXE(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_TXE) == (I2C_SR1_TXE)); +} + +/** + * @brief Indicate the status of Byte Transfer Finished flag. + * RESET: When Data byte transfer not done. + * SET: When Data byte transfer succeeded. + * @rmtoll SR1 BTF LL_I2C_IsActiveFlag_BTF + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_BTF(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_BTF) == (I2C_SR1_BTF)); +} + +/** + * @brief Indicate the status of Receive data register not empty flag. + * @note RESET: When Receive data register is read. + * SET: When the received data is copied in Receive data register. + * @rmtoll SR1 RXNE LL_I2C_IsActiveFlag_RXNE + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_RXNE(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_RXNE) == (I2C_SR1_RXNE)); +} + +/** + * @brief Indicate the status of Start Bit (master mode). + * @note RESET: When No Start condition. + * SET: When Start condition is generated. + * @rmtoll SR1 SB LL_I2C_IsActiveFlag_SB + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_SB(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_SB) == (I2C_SR1_SB)); +} + +/** + * @brief Indicate the status of Address sent (master mode) or Address matched flag (slave mode). + * @note RESET: Clear default value. + * SET: When the address is fully sent (master mode) or when the received slave address matched with one of the enabled slave address (slave mode). + * @rmtoll SR1 ADDR LL_I2C_IsActiveFlag_ADDR + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_ADDR(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_ADDR) == (I2C_SR1_ADDR)); +} + +/** + * @brief Indicate the status of 10-bit header sent (master mode). + * @note RESET: When no ADD10 event occurred. + * SET: When the master has sent the first address byte (header). + * @rmtoll SR1 ADD10 LL_I2C_IsActiveFlag_ADD10 + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_ADD10(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_ADD10) == (I2C_SR1_ADD10)); +} + +/** + * @brief Indicate the status of Acknowledge failure flag. + * @note RESET: No acknowledge failure. + * SET: When an acknowledge failure is received after a byte transmission. + * @rmtoll SR1 AF LL_I2C_IsActiveFlag_AF + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_AF(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_AF) == (I2C_SR1_AF)); +} + +/** + * @brief Indicate the status of Stop detection flag (slave mode). + * @note RESET: Clear default value. + * SET: When a Stop condition is detected. + * @rmtoll SR1 STOPF LL_I2C_IsActiveFlag_STOP + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_STOP(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_STOPF) == (I2C_SR1_STOPF)); +} + +/** + * @brief Indicate the status of Bus error flag. + * @note RESET: Clear default value. + * SET: When a misplaced Start or Stop condition is detected. + * @rmtoll SR1 BERR LL_I2C_IsActiveFlag_BERR + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_BERR(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_BERR) == (I2C_SR1_BERR)); +} + +/** + * @brief Indicate the status of Arbitration lost flag. + * @note RESET: Clear default value. + * SET: When arbitration lost. + * @rmtoll SR1 ARLO LL_I2C_IsActiveFlag_ARLO + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_ARLO(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_ARLO) == (I2C_SR1_ARLO)); +} + +/** + * @brief Indicate the status of Overrun/Underrun flag. + * @note RESET: Clear default value. + * SET: When an overrun/underrun error occurs (Clock Stretching Disabled). + * @rmtoll SR1 OVR LL_I2C_IsActiveFlag_OVR + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_OVR(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_OVR) == (I2C_SR1_OVR)); +} + +/** + * @brief Indicate the status of SMBus PEC error flag in reception. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll SR1 PECERR LL_I2C_IsActiveSMBusFlag_PECERR + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveSMBusFlag_PECERR(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_PECERR) == (I2C_SR1_PECERR)); +} + +/** + * @brief Indicate the status of SMBus Timeout detection flag. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll SR1 TIMEOUT LL_I2C_IsActiveSMBusFlag_TIMEOUT + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveSMBusFlag_TIMEOUT(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_TIMEOUT) == (I2C_SR1_TIMEOUT)); +} + +/** + * @brief Indicate the status of SMBus alert flag. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll SR1 SMBALERT LL_I2C_IsActiveSMBusFlag_ALERT + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveSMBusFlag_ALERT(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR1, I2C_SR1_SMBALERT) == (I2C_SR1_SMBALERT)); +} + +/** + * @brief Indicate the status of Bus Busy flag. + * @note RESET: Clear default value. + * SET: When a Start condition is detected. + * @rmtoll SR2 BUSY LL_I2C_IsActiveFlag_BUSY + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_BUSY(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR2, I2C_SR2_BUSY) == (I2C_SR2_BUSY)); +} + +/** + * @brief Indicate the status of Dual flag. + * @note RESET: Received address matched with OAR1. + * SET: Received address matched with OAR2. + * @rmtoll SR2 DUALF LL_I2C_IsActiveFlag_DUAL + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_DUAL(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR2, I2C_SR2_DUALF) == (I2C_SR2_DUALF)); +} + +/** + * @brief Indicate the status of SMBus Host address reception (Slave mode). + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note RESET: No SMBus Host address + * SET: SMBus Host address received. + * @note This status is cleared by hardware after a STOP condition or repeated START condition. + * @rmtoll SR2 SMBHOST LL_I2C_IsActiveSMBusFlag_SMBHOST + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveSMBusFlag_SMBHOST(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR2, I2C_SR2_SMBHOST) == (I2C_SR2_SMBHOST)); +} + +/** + * @brief Indicate the status of SMBus Device default address reception (Slave mode). + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note RESET: No SMBus Device default address + * SET: SMBus Device default address received. + * @note This status is cleared by hardware after a STOP condition or repeated START condition. + * @rmtoll SR2 SMBDEFAULT LL_I2C_IsActiveSMBusFlag_SMBDEFAULT + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveSMBusFlag_SMBDEFAULT(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR2, I2C_SR2_SMBDEFAULT) == (I2C_SR2_SMBDEFAULT)); +} + +/** + * @brief Indicate the status of General call address reception (Slave mode). + * @note RESET: No General call address + * SET: General call address received. + * @note This status is cleared by hardware after a STOP condition or repeated START condition. + * @rmtoll SR2 GENCALL LL_I2C_IsActiveFlag_GENCALL + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_GENCALL(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR2, I2C_SR2_GENCALL) == (I2C_SR2_GENCALL)); +} + +/** + * @brief Indicate the status of Master/Slave flag. + * @note RESET: Slave Mode. + * SET: Master Mode. + * @rmtoll SR2 MSL LL_I2C_IsActiveFlag_MSL + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsActiveFlag_MSL(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->SR2, I2C_SR2_MSL) == (I2C_SR2_MSL)); +} + +/** + * @brief Clear Address Matched flag. + * @note Clearing this flag is done by a read access to the I2Cx_SR1 + * register followed by a read access to the I2Cx_SR2 register. + * @rmtoll SR1 ADDR LL_I2C_ClearFlag_ADDR + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearFlag_ADDR(I2C_TypeDef *I2Cx) +{ + __IO uint32_t tmpreg; + tmpreg = I2Cx->SR1; + (void) tmpreg; + tmpreg = I2Cx->SR2; + (void) tmpreg; +} + +/** + * @brief Clear Acknowledge failure flag. + * @rmtoll SR1 AF LL_I2C_ClearFlag_AF + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearFlag_AF(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_AF); +} + +/** + * @brief Clear Stop detection flag. + * @note Clearing this flag is done by a read access to the I2Cx_SR1 + * register followed by a write access to I2Cx_CR1 register. + * @rmtoll SR1 STOPF LL_I2C_ClearFlag_STOP\n + * CR1 PE LL_I2C_ClearFlag_STOP + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearFlag_STOP(I2C_TypeDef *I2Cx) +{ + __IO uint32_t tmpreg; + tmpreg = I2Cx->SR1; + (void) tmpreg; + SET_BIT(I2Cx->CR1, I2C_CR1_PE); +} + +/** + * @brief Clear Bus error flag. + * @rmtoll SR1 BERR LL_I2C_ClearFlag_BERR + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearFlag_BERR(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_BERR); +} + +/** + * @brief Clear Arbitration lost flag. + * @rmtoll SR1 ARLO LL_I2C_ClearFlag_ARLO + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearFlag_ARLO(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_ARLO); +} + +/** + * @brief Clear Overrun/Underrun flag. + * @rmtoll SR1 OVR LL_I2C_ClearFlag_OVR + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearFlag_OVR(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_OVR); +} + +/** + * @brief Clear SMBus PEC error flag. + * @rmtoll SR1 PECERR LL_I2C_ClearSMBusFlag_PECERR + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearSMBusFlag_PECERR(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_PECERR); +} + +/** + * @brief Clear SMBus Timeout detection flag. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll SR1 TIMEOUT LL_I2C_ClearSMBusFlag_TIMEOUT + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearSMBusFlag_TIMEOUT(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_TIMEOUT); +} + +/** + * @brief Clear SMBus Alert flag. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll SR1 SMBALERT LL_I2C_ClearSMBusFlag_ALERT + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_ClearSMBusFlag_ALERT(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->SR1, I2C_SR1_SMBALERT); +} + +/** + * @} + */ + +/** @defgroup I2C_LL_EF_Data_Management Data_Management + * @{ + */ + +/** + * @brief Enable Reset of I2C peripheral. + * @rmtoll CR1 SWRST LL_I2C_EnableReset + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableReset(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_SWRST); +} + +/** + * @brief Disable Reset of I2C peripheral. + * @rmtoll CR1 SWRST LL_I2C_DisableReset + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableReset(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_SWRST); +} + +/** + * @brief Check if the I2C peripheral is under reset state or not. + * @rmtoll CR1 SWRST LL_I2C_IsResetEnabled + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsResetEnabled(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_SWRST) == (I2C_CR1_SWRST)); +} + +/** + * @brief Prepare the generation of a ACKnowledge or Non ACKnowledge condition after the address receive match code or next received byte. + * @note Usage in Slave or Master mode. + * @rmtoll CR1 ACK LL_I2C_AcknowledgeNextData + * @param I2Cx I2C Instance. + * @param TypeAcknowledge This parameter can be one of the following values: + * @arg @ref LL_I2C_ACK + * @arg @ref LL_I2C_NACK + * @retval None + */ +__STATIC_INLINE void LL_I2C_AcknowledgeNextData(I2C_TypeDef *I2Cx, uint32_t TypeAcknowledge) +{ + MODIFY_REG(I2Cx->CR1, I2C_CR1_ACK, TypeAcknowledge); +} + +/** + * @brief Generate a START or RESTART condition + * @note The START bit can be set even if bus is BUSY or I2C is in slave mode. + * This action has no effect when RELOAD is set. + * @rmtoll CR1 START LL_I2C_GenerateStartCondition + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_GenerateStartCondition(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_START); +} + +/** + * @brief Generate a STOP condition after the current byte transfer (master mode). + * @rmtoll CR1 STOP LL_I2C_GenerateStopCondition + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_GenerateStopCondition(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_STOP); +} + +/** + * @brief Enable bit POS (master/host mode). + * @note In that case, the ACK bit controls the (N)ACK of the next byte received or the PEC bit indicates that the next byte in shift register is a PEC. + * @rmtoll CR1 POS LL_I2C_EnableBitPOS + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableBitPOS(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_POS); +} + +/** + * @brief Disable bit POS (master/host mode). + * @note In that case, the ACK bit controls the (N)ACK of the current byte received or the PEC bit indicates that the current byte in shift register is a PEC. + * @rmtoll CR1 POS LL_I2C_DisableBitPOS + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableBitPOS(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_POS); +} + +/** + * @brief Check if bit POS is enabled or disabled. + * @rmtoll CR1 POS LL_I2C_IsEnabledBitPOS + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledBitPOS(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_POS) == (I2C_CR1_POS)); +} + +/** + * @brief Indicate the value of transfer direction. + * @note RESET: Bus is in read transfer (peripheral point of view). + * SET: Bus is in write transfer (peripheral point of view). + * @rmtoll SR2 TRA LL_I2C_GetTransferDirection + * @param I2Cx I2C Instance. + * @retval Returned value can be one of the following values: + * @arg @ref LL_I2C_DIRECTION_WRITE + * @arg @ref LL_I2C_DIRECTION_READ + */ +__STATIC_INLINE uint32_t LL_I2C_GetTransferDirection(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->SR2, I2C_SR2_TRA)); +} + +/** + * @brief Enable DMA last transfer. + * @note This action mean that next DMA EOT is the last transfer. + * @rmtoll CR2 LAST LL_I2C_EnableLastDMA + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableLastDMA(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR2, I2C_CR2_LAST); +} + +/** + * @brief Disable DMA last transfer. + * @note This action mean that next DMA EOT is not the last transfer. + * @rmtoll CR2 LAST LL_I2C_DisableLastDMA + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableLastDMA(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR2, I2C_CR2_LAST); +} + +/** + * @brief Check if DMA last transfer is enabled or disabled. + * @rmtoll CR2 LAST LL_I2C_IsEnabledLastDMA + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledLastDMA(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR2, I2C_CR2_LAST) == (I2C_CR2_LAST)); +} + +/** + * @brief Enable transfer or internal comparison of the SMBus Packet Error byte (transmission or reception mode). + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @note This feature is cleared by hardware when the PEC byte is transferred or compared, + * or by a START or STOP condition, it is also cleared by software. + * @rmtoll CR1 PEC LL_I2C_EnableSMBusPECCompare + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_EnableSMBusPECCompare(I2C_TypeDef *I2Cx) +{ + SET_BIT(I2Cx->CR1, I2C_CR1_PEC); +} + +/** + * @brief Disable transfer or internal comparison of the SMBus Packet Error byte (transmission or reception mode). + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 PEC LL_I2C_DisableSMBusPECCompare + * @param I2Cx I2C Instance. + * @retval None + */ +__STATIC_INLINE void LL_I2C_DisableSMBusPECCompare(I2C_TypeDef *I2Cx) +{ + CLEAR_BIT(I2Cx->CR1, I2C_CR1_PEC); +} + +/** + * @brief Check if the SMBus Packet Error byte transfer or internal comparison is requested or not. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll CR1 PEC LL_I2C_IsEnabledSMBusPECCompare + * @param I2Cx I2C Instance. + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_I2C_IsEnabledSMBusPECCompare(I2C_TypeDef *I2Cx) +{ + return (READ_BIT(I2Cx->CR1, I2C_CR1_PEC) == (I2C_CR1_PEC)); +} + +/** + * @brief Get the SMBus Packet Error byte calculated. + * @note Macro IS_SMBUS_ALL_INSTANCE(I2Cx) can be used to check whether or not + * SMBus feature is supported by the I2Cx Instance. + * @rmtoll SR2 PEC LL_I2C_GetSMBusPEC + * @param I2Cx I2C Instance. + * @retval Value between Min_Data=0x00 and Max_Data=0xFF + */ +__STATIC_INLINE uint32_t LL_I2C_GetSMBusPEC(I2C_TypeDef *I2Cx) +{ + return (uint32_t)(READ_BIT(I2Cx->SR2, I2C_SR2_PEC) >> I2C_SR2_PEC_Pos); +} + +/** + * @brief Read Receive Data register. + * @rmtoll DR DR LL_I2C_ReceiveData8 + * @param I2Cx I2C Instance. + * @retval Value between Min_Data=0x0 and Max_Data=0xFF + */ +__STATIC_INLINE uint8_t LL_I2C_ReceiveData8(I2C_TypeDef *I2Cx) +{ + return (uint8_t)(READ_BIT(I2Cx->DR, I2C_DR_DR)); +} + +/** + * @brief Write in Transmit Data Register . + * @rmtoll DR DR LL_I2C_TransmitData8 + * @param I2Cx I2C Instance. + * @param Data Value between Min_Data=0x0 and Max_Data=0xFF + * @retval None + */ +__STATIC_INLINE void LL_I2C_TransmitData8(I2C_TypeDef *I2Cx, uint8_t Data) +{ + MODIFY_REG(I2Cx->DR, I2C_DR_DR, Data); +} + +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup I2C_LL_EF_Init Initialization and de-initialization functions + * @{ + */ + +uint32_t LL_I2C_Init(I2C_TypeDef *I2Cx, LL_I2C_InitTypeDef *I2C_InitStruct); +uint32_t LL_I2C_DeInit(I2C_TypeDef *I2Cx); +void LL_I2C_StructInit(LL_I2C_InitTypeDef *I2C_InitStruct); + + +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** + * @} + */ + +/** + * @} + */ + +#endif /* I2C1 || I2C2 || I2C3 */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_LL_I2C_H */ + diff --git a/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c new file mode 100644 index 0000000..d3f4262 --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c @@ -0,0 +1,7567 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c.c + * @author MCD Application Team + * @brief I2C HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Inter Integrated Circuit (I2C) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral State, Mode and Error functions + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + The I2C HAL driver can be used as follows: + + (#) Declare a I2C_HandleTypeDef handle structure, for example: + I2C_HandleTypeDef hi2c; + + (#)Initialize the I2C low level resources by implementing the HAL_I2C_MspInit() API: + (##) Enable the I2Cx interface clock + (##) I2C pins configuration + (+++) Enable the clock for the I2C GPIOs + (+++) Configure I2C pins as alternate function open-drain + (##) NVIC configuration if you need to use interrupt process + (+++) Configure the I2Cx interrupt priority + (+++) Enable the NVIC I2C IRQ Channel + (##) DMA Configuration if you need to use DMA process + (+++) Declare a DMA_HandleTypeDef handle structure for the transmit or receive stream + (+++) Enable the DMAx interface clock using + (+++) Configure the DMA handle parameters + (+++) Configure the DMA Tx or Rx stream + (+++) Associate the initialized DMA handle to the hi2c DMA Tx or Rx handle + (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on + the DMA Tx or Rx stream + + (#) Configure the Communication Speed, Duty cycle, Addressing mode, Own Address1, + Dual Addressing mode, Own Address2, General call and Nostretch mode in the hi2c Init structure. + + (#) Initialize the I2C registers by calling the HAL_I2C_Init(), configures also the low level Hardware + (GPIO, CLOCK, NVIC...etc) by calling the customized HAL_I2C_MspInit() API. + + (#) To check if target device is ready for communication, use the function HAL_I2C_IsDeviceReady() + + (#) For I2C IO and IO MEM operations, three operation modes are available within this driver : + + *** Polling mode IO operation *** + ================================= + [..] + (+) Transmit in master mode an amount of data in blocking mode using HAL_I2C_Master_Transmit() + (+) Receive in master mode an amount of data in blocking mode using HAL_I2C_Master_Receive() + (+) Transmit in slave mode an amount of data in blocking mode using HAL_I2C_Slave_Transmit() + (+) Receive in slave mode an amount of data in blocking mode using HAL_I2C_Slave_Receive() + + *** Polling mode IO MEM operation *** + ===================================== + [..] + (+) Write an amount of data in blocking mode to a specific memory address using HAL_I2C_Mem_Write() + (+) Read an amount of data in blocking mode from a specific memory address using HAL_I2C_Mem_Read() + + + *** Interrupt mode IO operation *** + =================================== + [..] + (+) Transmit in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Transmit_IT() + (+) At transmission end of transfer, HAL_I2C_MasterTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback() + (+) Receive in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Receive_IT() + (+) At reception end of transfer, HAL_I2C_MasterRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback() + (+) Transmit in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Transmit_IT() + (+) At transmission end of transfer, HAL_I2C_SlaveTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback() + (+) Receive in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Receive_IT() + (+) At reception end of transfer, HAL_I2C_SlaveRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback() + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback() + (+) Abort a master or memory I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + + *** Interrupt mode or DMA mode IO sequential operation *** + ========================================================== + [..] + (@) These interfaces allow to manage a sequential transfer with a repeated start condition + when a direction change during transfer + [..] + (+) A specific option field manage the different steps of a sequential transfer + (+) Option field values are defined through I2C_XferOptions_definition and are listed below: + (++) I2C_FIRST_AND_LAST_FRAME: No sequential usage, functional is same as associated interfaces in no sequential mode + (++) I2C_FIRST_FRAME: Sequential usage, this option allow to manage a sequence with start condition, address + and data to transfer without a final stop condition + (++) I2C_FIRST_AND_NEXT_FRAME: Sequential usage (Master only), this option allow to manage a sequence with start condition, address + and data to transfer without a final stop condition, an then permit a call the same master sequential interface + several times (like HAL_I2C_Master_Seq_Transmit_IT() then HAL_I2C_Master_Seq_Transmit_IT() + or HAL_I2C_Master_Seq_Transmit_DMA() then HAL_I2C_Master_Seq_Transmit_DMA()) + (++) I2C_NEXT_FRAME: Sequential usage, this option allow to manage a sequence with a restart condition, address + and with new data to transfer if the direction change or manage only the new data to transfer + if no direction change and without a final stop condition in both cases + (++) I2C_LAST_FRAME: Sequential usage, this option allow to manage a sequance with a restart condition, address + and with new data to transfer if the direction change or manage only the new data to transfer + if no direction change and with a final stop condition in both cases + (++) I2C_LAST_FRAME_NO_STOP: Sequential usage (Master only), this option allow to manage a restart condition after several call of the same master sequential + interface several times (link with option I2C_FIRST_AND_NEXT_FRAME). + Usage can, transfer several bytes one by one using HAL_I2C_Master_Seq_Transmit_IT(option I2C_FIRST_AND_NEXT_FRAME then I2C_NEXT_FRAME) + or HAL_I2C_Master_Seq_Receive_IT(option I2C_FIRST_AND_NEXT_FRAME then I2C_NEXT_FRAME) + or HAL_I2C_Master_Seq_Transmit_DMA(option I2C_FIRST_AND_NEXT_FRAME then I2C_NEXT_FRAME) + or HAL_I2C_Master_Seq_Receive_DMA(option I2C_FIRST_AND_NEXT_FRAME then I2C_NEXT_FRAME). + Then usage of this option I2C_LAST_FRAME_NO_STOP at the last Transmit or Receive sequence permit to call the opposite interface Receive or Transmit + without stopping the communication and so generate a restart condition. + (++) I2C_OTHER_FRAME: Sequential usage (Master only), this option allow to manage a restart condition after each call of the same master sequential + interface. + Usage can, transfer several bytes one by one with a restart with slave address between each bytes using HAL_I2C_Master_Seq_Transmit_IT(option I2C_FIRST_FRAME then I2C_OTHER_FRAME) + or HAL_I2C_Master_Seq_Receive_IT(option I2C_FIRST_FRAME then I2C_OTHER_FRAME) + or HAL_I2C_Master_Seq_Transmit_DMA(option I2C_FIRST_FRAME then I2C_OTHER_FRAME) + or HAL_I2C_Master_Seq_Receive_DMA(option I2C_FIRST_FRAME then I2C_OTHER_FRAME). + Then usage of this option I2C_OTHER_AND_LAST_FRAME at the last frame to help automatic generation of STOP condition. + + (+) Different sequential I2C interfaces are listed below: + (++) Sequential transmit in master I2C mode an amount of data in non-blocking mode using HAL_I2C_Master_Seq_Transmit_IT() + or using HAL_I2C_Master_Seq_Transmit_DMA() + (+++) At transmission end of current frame transfer, HAL_I2C_MasterTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback() + (++) Sequential receive in master I2C mode an amount of data in non-blocking mode using HAL_I2C_Master_Seq_Receive_IT() + or using HAL_I2C_Master_Seq_Receive_DMA() + (+++) At reception end of current frame transfer, HAL_I2C_MasterRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback() + (++) Abort a master or memory IT or DMA I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (+++) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + (++) Enable/disable the Address listen mode in slave I2C mode using HAL_I2C_EnableListen_IT() HAL_I2C_DisableListen_IT() + (+++) When address slave I2C match, HAL_I2C_AddrCallback() is executed and user can + add his own code to check the Address Match Code and the transmission direction request by master (Write/Read). + (+++) At Listen mode end HAL_I2C_ListenCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_ListenCpltCallback() + (++) Sequential transmit in slave I2C mode an amount of data in non-blocking mode using HAL_I2C_Slave_Seq_Transmit_IT() + or using HAL_I2C_Slave_Seq_Transmit_DMA() + (+++) At transmission end of current frame transfer, HAL_I2C_SlaveTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback() + (++) Sequential receive in slave I2C mode an amount of data in non-blocking mode using HAL_I2C_Slave_Seq_Receive_IT() + or using HAL_I2C_Slave_Seq_Receive_DMA() + (+++) At reception end of current frame transfer, HAL_I2C_SlaveRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback() + (++) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback() + + *** Interrupt mode IO MEM operation *** + ======================================= + [..] + (+) Write an amount of data in non-blocking mode with Interrupt to a specific memory address using + HAL_I2C_Mem_Write_IT() + (+) At Memory end of write transfer, HAL_I2C_MemTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback() + (+) Read an amount of data in non-blocking mode with Interrupt from a specific memory address using + HAL_I2C_Mem_Read_IT() + (+) At Memory end of read transfer, HAL_I2C_MemRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback() + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback() + + *** DMA mode IO operation *** + ============================== + [..] + (+) Transmit in master mode an amount of data in non-blocking mode (DMA) using + HAL_I2C_Master_Transmit_DMA() + (+) At transmission end of transfer, HAL_I2C_MasterTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterTxCpltCallback() + (+) Receive in master mode an amount of data in non-blocking mode (DMA) using + HAL_I2C_Master_Receive_DMA() + (+) At reception end of transfer, HAL_I2C_MasterRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MasterRxCpltCallback() + (+) Transmit in slave mode an amount of data in non-blocking mode (DMA) using + HAL_I2C_Slave_Transmit_DMA() + (+) At transmission end of transfer, HAL_I2C_SlaveTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback() + (+) Receive in slave mode an amount of data in non-blocking mode (DMA) using + HAL_I2C_Slave_Receive_DMA() + (+) At reception end of transfer, HAL_I2C_SlaveRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback() + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback() + (+) Abort a master or memory I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT() + (+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_AbortCpltCallback() + + *** DMA mode IO MEM operation *** + ================================= + [..] + (+) Write an amount of data in non-blocking mode with DMA to a specific memory address using + HAL_I2C_Mem_Write_DMA() + (+) At Memory end of write transfer, HAL_I2C_MemTxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MemTxCpltCallback() + (+) Read an amount of data in non-blocking mode with DMA from a specific memory address using + HAL_I2C_Mem_Read_DMA() + (+) At Memory end of read transfer, HAL_I2C_MemRxCpltCallback() is executed and user can + add his own code by customization of function pointer HAL_I2C_MemRxCpltCallback() + (+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_I2C_ErrorCallback() + + + *** I2C HAL driver macros list *** + ================================== + [..] + Below the list of most used macros in I2C HAL driver. + + (+) __HAL_I2C_ENABLE: Enable the I2C peripheral + (+) __HAL_I2C_DISABLE: Disable the I2C peripheral + (+) __HAL_I2C_GET_FLAG: Checks whether the specified I2C flag is set or not + (+) __HAL_I2C_CLEAR_FLAG: Clear the specified I2C pending flag + (+) __HAL_I2C_ENABLE_IT: Enable the specified I2C interrupt + (+) __HAL_I2C_DISABLE_IT: Disable the specified I2C interrupt + + *** Callback registration *** + ============================================= + [..] + The compilation flag USE_HAL_I2C_REGISTER_CALLBACKS when set to 1 + allows the user to configure dynamically the driver callbacks. + Use Functions HAL_I2C_RegisterCallback() or HAL_I2C_RegisterAddrCallback() + to register an interrupt callback. + [..] + Function HAL_I2C_RegisterCallback() allows to register following callbacks: + (+) MasterTxCpltCallback : callback for Master transmission end of transfer. + (+) MasterRxCpltCallback : callback for Master reception end of transfer. + (+) SlaveTxCpltCallback : callback for Slave transmission end of transfer. + (+) SlaveRxCpltCallback : callback for Slave reception end of transfer. + (+) ListenCpltCallback : callback for end of listen mode. + (+) MemTxCpltCallback : callback for Memory transmission end of transfer. + (+) MemRxCpltCallback : callback for Memory reception end of transfer. + (+) ErrorCallback : callback for error detection. + (+) AbortCpltCallback : callback for abort completion process. + (+) MspInitCallback : callback for Msp Init. + (+) MspDeInitCallback : callback for Msp DeInit. + This function takes as parameters the HAL peripheral handle, the Callback ID + and a pointer to the user callback function. + [..] + For specific callback AddrCallback use dedicated register callbacks : HAL_I2C_RegisterAddrCallback(). + [..] + Use function HAL_I2C_UnRegisterCallback to reset a callback to the default + weak function. + HAL_I2C_UnRegisterCallback takes as parameters the HAL peripheral handle, + and the Callback ID. + This function allows to reset following callbacks: + (+) MasterTxCpltCallback : callback for Master transmission end of transfer. + (+) MasterRxCpltCallback : callback for Master reception end of transfer. + (+) SlaveTxCpltCallback : callback for Slave transmission end of transfer. + (+) SlaveRxCpltCallback : callback for Slave reception end of transfer. + (+) ListenCpltCallback : callback for end of listen mode. + (+) MemTxCpltCallback : callback for Memory transmission end of transfer. + (+) MemRxCpltCallback : callback for Memory reception end of transfer. + (+) ErrorCallback : callback for error detection. + (+) AbortCpltCallback : callback for abort completion process. + (+) MspInitCallback : callback for Msp Init. + (+) MspDeInitCallback : callback for Msp DeInit. + [..] + For callback AddrCallback use dedicated register callbacks : HAL_I2C_UnRegisterAddrCallback(). + [..] + By default, after the HAL_I2C_Init() and when the state is HAL_I2C_STATE_RESET + all callbacks are set to the corresponding weak functions: + examples HAL_I2C_MasterTxCpltCallback(), HAL_I2C_MasterRxCpltCallback(). + Exception done for MspInit and MspDeInit functions that are + reset to the legacy weak functions in the HAL_I2C_Init()/ HAL_I2C_DeInit() only when + these callbacks are null (not registered beforehand). + If MspInit or MspDeInit are not null, the HAL_I2C_Init()/ HAL_I2C_DeInit() + keep and use the user MspInit/MspDeInit callbacks (registered beforehand) whatever the state. + [..] + Callbacks can be registered/unregistered in HAL_I2C_STATE_READY state only. + Exception done MspInit/MspDeInit functions that can be registered/unregistered + in HAL_I2C_STATE_READY or HAL_I2C_STATE_RESET state, + thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit. + Then, the user first registers the MspInit/MspDeInit user callbacks + using HAL_I2C_RegisterCallback() before calling HAL_I2C_DeInit() + or HAL_I2C_Init() function. + [..] + When the compilation flag USE_HAL_I2C_REGISTER_CALLBACKS is set to 0 or + not defined, the callback registration feature is not available and all callbacks + are set to the corresponding weak functions. + + + + [..] + (@) You can refer to the I2C HAL driver header file for more useful macros + + @endverbatim + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup I2C I2C + * @brief I2C HAL module driver + * @{ + */ + +#ifdef HAL_I2C_MODULE_ENABLED + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @defgroup I2C_Private_Define I2C Private Define + * @{ + */ +#define I2C_TIMEOUT_FLAG 35U /*!< Timeout 35 ms */ +#define I2C_TIMEOUT_BUSY_FLAG 25U /*!< Timeout 25 ms */ +#define I2C_TIMEOUT_STOP_FLAG 5U /*!< Timeout 5 ms */ +#define I2C_NO_OPTION_FRAME 0xFFFF0000U /*!< XferOptions default value */ + +/* Private define for @ref PreviousState usage */ +#define I2C_STATE_MSK ((uint32_t)((uint32_t)((uint32_t)HAL_I2C_STATE_BUSY_TX | (uint32_t)HAL_I2C_STATE_BUSY_RX) & (uint32_t)(~((uint32_t)HAL_I2C_STATE_READY)))) /*!< Mask State define, keep only RX and TX bits */ +#define I2C_STATE_NONE ((uint32_t)(HAL_I2C_MODE_NONE)) /*!< Default Value */ +#define I2C_STATE_MASTER_BUSY_TX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MASTER)) /*!< Master Busy TX, combinaison of State LSB and Mode enum */ +#define I2C_STATE_MASTER_BUSY_RX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MASTER)) /*!< Master Busy RX, combinaison of State LSB and Mode enum */ +#define I2C_STATE_SLAVE_BUSY_TX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_SLAVE)) /*!< Slave Busy TX, combinaison of State LSB and Mode enum */ +#define I2C_STATE_SLAVE_BUSY_RX ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_SLAVE)) /*!< Slave Busy RX, combinaison of State LSB and Mode enum */ + +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ +/** @addtogroup I2C_Private_Macros + * @{ + */ +/* Macro to get remaining data to transfer on DMA side */ +#define I2C_GET_DMA_REMAIN_DATA(__HANDLE__) __HAL_DMA_GET_COUNTER(__HANDLE__) +/** + * @} + */ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ + +/** @defgroup I2C_Private_Functions I2C Private Functions + * @{ + */ +/* Private functions to handle DMA transfer */ +static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma); +static void I2C_DMAError(DMA_HandleTypeDef *hdma); +static void I2C_DMAAbort(DMA_HandleTypeDef *hdma); + +static void I2C_ITError(I2C_HandleTypeDef *hi2c); + +static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart); + +/* Private functions to handle flags during polling transfer */ +static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart); +static HAL_StatusTypeDef I2C_WaitOnSTOPRequestThroughIT(I2C_HandleTypeDef *hi2c); +static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c); + +/* Private functions for I2C transfer IRQ handler */ +static void I2C_MasterTransmit_TXE(I2C_HandleTypeDef *hi2c); +static void I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c); +static void I2C_MasterReceive_RXNE(I2C_HandleTypeDef *hi2c); +static void I2C_MasterReceive_BTF(I2C_HandleTypeDef *hi2c); +static void I2C_Master_SB(I2C_HandleTypeDef *hi2c); +static void I2C_Master_ADD10(I2C_HandleTypeDef *hi2c); +static void I2C_Master_ADDR(I2C_HandleTypeDef *hi2c); + +static void I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c); +static void I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c); +static void I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c); +static void I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c); +static void I2C_Slave_ADDR(I2C_HandleTypeDef *hi2c, uint32_t IT2Flags); +static void I2C_Slave_STOPF(I2C_HandleTypeDef *hi2c); +static void I2C_Slave_AF(I2C_HandleTypeDef *hi2c); + +static void I2C_MemoryTransmit_TXE_BTF(I2C_HandleTypeDef *hi2c); + +/* Private function to Convert Specific options */ +static void I2C_ConvertOtherXferOptions(I2C_HandleTypeDef *hi2c); + +/* Private function to flush DR register */ +static void I2C_Flush_DR(I2C_HandleTypeDef *hi2c); +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @defgroup I2C_Exported_Functions I2C Exported Functions + * @{ + */ + +/** @defgroup I2C_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and de-initialization functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to initialize and + deinitialize the I2Cx peripheral: + + (+) User must Implement HAL_I2C_MspInit() function in which he configures + all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC). + + (+) Call the function HAL_I2C_Init() to configure the selected device with + the selected configuration: + (++) Communication Speed + (++) Duty cycle + (++) Addressing mode + (++) Own Address 1 + (++) Dual Addressing mode + (++) Own Address 2 + (++) General call mode + (++) Nostretch mode + + (+) Call the function HAL_I2C_DeInit() to restore the default configuration + of the selected I2Cx peripheral. + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the I2C according to the specified parameters + * in the I2C_InitTypeDef and initialize the associated handle. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c) +{ + uint32_t freqrange; + uint32_t pclk1; + + /* Check the I2C handle allocation */ + if (hi2c == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_I2C_CLOCK_SPEED(hi2c->Init.ClockSpeed)); + assert_param(IS_I2C_DUTY_CYCLE(hi2c->Init.DutyCycle)); + assert_param(IS_I2C_OWN_ADDRESS1(hi2c->Init.OwnAddress1)); + assert_param(IS_I2C_ADDRESSING_MODE(hi2c->Init.AddressingMode)); + assert_param(IS_I2C_DUAL_ADDRESS(hi2c->Init.DualAddressMode)); + assert_param(IS_I2C_OWN_ADDRESS2(hi2c->Init.OwnAddress2)); + assert_param(IS_I2C_GENERAL_CALL(hi2c->Init.GeneralCallMode)); + assert_param(IS_I2C_NO_STRETCH(hi2c->Init.NoStretchMode)); + + if (hi2c->State == HAL_I2C_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + hi2c->Lock = HAL_UNLOCKED; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + /* Init the I2C Callback settings */ + hi2c->MasterTxCpltCallback = HAL_I2C_MasterTxCpltCallback; /* Legacy weak MasterTxCpltCallback */ + hi2c->MasterRxCpltCallback = HAL_I2C_MasterRxCpltCallback; /* Legacy weak MasterRxCpltCallback */ + hi2c->SlaveTxCpltCallback = HAL_I2C_SlaveTxCpltCallback; /* Legacy weak SlaveTxCpltCallback */ + hi2c->SlaveRxCpltCallback = HAL_I2C_SlaveRxCpltCallback; /* Legacy weak SlaveRxCpltCallback */ + hi2c->ListenCpltCallback = HAL_I2C_ListenCpltCallback; /* Legacy weak ListenCpltCallback */ + hi2c->MemTxCpltCallback = HAL_I2C_MemTxCpltCallback; /* Legacy weak MemTxCpltCallback */ + hi2c->MemRxCpltCallback = HAL_I2C_MemRxCpltCallback; /* Legacy weak MemRxCpltCallback */ + hi2c->ErrorCallback = HAL_I2C_ErrorCallback; /* Legacy weak ErrorCallback */ + hi2c->AbortCpltCallback = HAL_I2C_AbortCpltCallback; /* Legacy weak AbortCpltCallback */ + hi2c->AddrCallback = HAL_I2C_AddrCallback; /* Legacy weak AddrCallback */ + + if (hi2c->MspInitCallback == NULL) + { + hi2c->MspInitCallback = HAL_I2C_MspInit; /* Legacy weak MspInit */ + } + + /* Init the low level hardware : GPIO, CLOCK, NVIC */ + hi2c->MspInitCallback(hi2c); +#else + /* Init the low level hardware : GPIO, CLOCK, NVIC */ + HAL_I2C_MspInit(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + __HAL_I2C_DISABLE(hi2c); + + /*Reset I2C*/ + hi2c->Instance->CR1 |= I2C_CR1_SWRST; + hi2c->Instance->CR1 &= ~I2C_CR1_SWRST; + + /* Get PCLK1 frequency */ + pclk1 = HAL_RCC_GetPCLK1Freq(); + + /* Check the minimum allowed PCLK1 frequency */ + if (I2C_MIN_PCLK_FREQ(pclk1, hi2c->Init.ClockSpeed) == 1U) + { + return HAL_ERROR; + } + + /* Calculate frequency range */ + freqrange = I2C_FREQRANGE(pclk1); + + /*---------------------------- I2Cx CR2 Configuration ----------------------*/ + /* Configure I2Cx: Frequency range */ + MODIFY_REG(hi2c->Instance->CR2, I2C_CR2_FREQ, freqrange); + + /*---------------------------- I2Cx TRISE Configuration --------------------*/ + /* Configure I2Cx: Rise Time */ + MODIFY_REG(hi2c->Instance->TRISE, I2C_TRISE_TRISE, I2C_RISE_TIME(freqrange, hi2c->Init.ClockSpeed)); + + /*---------------------------- I2Cx CCR Configuration ----------------------*/ + /* Configure I2Cx: Speed */ + MODIFY_REG(hi2c->Instance->CCR, (I2C_CCR_FS | I2C_CCR_DUTY | I2C_CCR_CCR), I2C_SPEED(pclk1, hi2c->Init.ClockSpeed, hi2c->Init.DutyCycle)); + + /*---------------------------- I2Cx CR1 Configuration ----------------------*/ + /* Configure I2Cx: Generalcall and NoStretch mode */ + MODIFY_REG(hi2c->Instance->CR1, (I2C_CR1_ENGC | I2C_CR1_NOSTRETCH), (hi2c->Init.GeneralCallMode | hi2c->Init.NoStretchMode)); + + /*---------------------------- I2Cx OAR1 Configuration ---------------------*/ + /* Configure I2Cx: Own Address1 and addressing mode */ + MODIFY_REG(hi2c->Instance->OAR1, (I2C_OAR1_ADDMODE | I2C_OAR1_ADD8_9 | I2C_OAR1_ADD1_7 | I2C_OAR1_ADD0), (hi2c->Init.AddressingMode | hi2c->Init.OwnAddress1)); + + /*---------------------------- I2Cx OAR2 Configuration ---------------------*/ + /* Configure I2Cx: Dual mode and Own Address2 */ + MODIFY_REG(hi2c->Instance->OAR2, (I2C_OAR2_ENDUAL | I2C_OAR2_ADD2), (hi2c->Init.DualAddressMode | hi2c->Init.OwnAddress2)); + + /* Enable the selected I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->Mode = HAL_I2C_MODE_NONE; + + return HAL_OK; +} + +/** + * @brief DeInitialize the I2C peripheral. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c) +{ + /* Check the I2C handle allocation */ + if (hi2c == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the I2C Peripheral Clock */ + __HAL_I2C_DISABLE(hi2c); + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + if (hi2c->MspDeInitCallback == NULL) + { + hi2c->MspDeInitCallback = HAL_I2C_MspDeInit; /* Legacy weak MspDeInit */ + } + + /* DeInit the low level hardware: GPIO, CLOCK, NVIC */ + hi2c->MspDeInitCallback(hi2c); +#else + /* DeInit the low level hardware: GPIO, CLOCK, NVIC */ + HAL_I2C_MspDeInit(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->State = HAL_I2C_STATE_RESET; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Release Lock */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; +} + +/** + * @brief Initialize the I2C MSP. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MspInit could be implemented in the user file + */ +} + +/** + * @brief DeInitialize the I2C MSP. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MspDeInit could be implemented in the user file + */ +} + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) +/** + * @brief Register a User I2C Callback + * To be used instead of the weak predefined callback + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param CallbackID ID of the callback to be registered + * This parameter can be one of the following values: + * @arg @ref HAL_I2C_MASTER_TX_COMPLETE_CB_ID Master Tx Transfer completed callback ID + * @arg @ref HAL_I2C_MASTER_RX_COMPLETE_CB_ID Master Rx Transfer completed callback ID + * @arg @ref HAL_I2C_SLAVE_TX_COMPLETE_CB_ID Slave Tx Transfer completed callback ID + * @arg @ref HAL_I2C_SLAVE_RX_COMPLETE_CB_ID Slave Rx Transfer completed callback ID + * @arg @ref HAL_I2C_LISTEN_COMPLETE_CB_ID Listen Complete callback ID + * @arg @ref HAL_I2C_MEM_TX_COMPLETE_CB_ID Memory Tx Transfer callback ID + * @arg @ref HAL_I2C_MEM_RX_COMPLETE_CB_ID Memory Rx Transfer completed callback ID + * @arg @ref HAL_I2C_ERROR_CB_ID Error callback ID + * @arg @ref HAL_I2C_ABORT_CB_ID Abort callback ID + * @arg @ref HAL_I2C_MSPINIT_CB_ID MspInit callback ID + * @arg @ref HAL_I2C_MSPDEINIT_CB_ID MspDeInit callback ID + * @param pCallback pointer to the Callback function + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_RegisterCallback(I2C_HandleTypeDef *hi2c, HAL_I2C_CallbackIDTypeDef CallbackID, pI2C_CallbackTypeDef pCallback) +{ + HAL_StatusTypeDef status = HAL_OK; + + if (pCallback == NULL) + { + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + return HAL_ERROR; + } + /* Process locked */ + __HAL_LOCK(hi2c); + + if (HAL_I2C_STATE_READY == hi2c->State) + { + switch (CallbackID) + { + case HAL_I2C_MASTER_TX_COMPLETE_CB_ID : + hi2c->MasterTxCpltCallback = pCallback; + break; + + case HAL_I2C_MASTER_RX_COMPLETE_CB_ID : + hi2c->MasterRxCpltCallback = pCallback; + break; + + case HAL_I2C_SLAVE_TX_COMPLETE_CB_ID : + hi2c->SlaveTxCpltCallback = pCallback; + break; + + case HAL_I2C_SLAVE_RX_COMPLETE_CB_ID : + hi2c->SlaveRxCpltCallback = pCallback; + break; + + case HAL_I2C_LISTEN_COMPLETE_CB_ID : + hi2c->ListenCpltCallback = pCallback; + break; + + case HAL_I2C_MEM_TX_COMPLETE_CB_ID : + hi2c->MemTxCpltCallback = pCallback; + break; + + case HAL_I2C_MEM_RX_COMPLETE_CB_ID : + hi2c->MemRxCpltCallback = pCallback; + break; + + case HAL_I2C_ERROR_CB_ID : + hi2c->ErrorCallback = pCallback; + break; + + case HAL_I2C_ABORT_CB_ID : + hi2c->AbortCpltCallback = pCallback; + break; + + case HAL_I2C_MSPINIT_CB_ID : + hi2c->MspInitCallback = pCallback; + break; + + case HAL_I2C_MSPDEINIT_CB_ID : + hi2c->MspDeInitCallback = pCallback; + break; + + default : + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else if (HAL_I2C_STATE_RESET == hi2c->State) + { + switch (CallbackID) + { + case HAL_I2C_MSPINIT_CB_ID : + hi2c->MspInitCallback = pCallback; + break; + + case HAL_I2C_MSPDEINIT_CB_ID : + hi2c->MspDeInitCallback = pCallback; + break; + + default : + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else + { + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hi2c); + return status; +} + +/** + * @brief Unregister an I2C Callback + * I2C callback is redirected to the weak predefined callback + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param CallbackID ID of the callback to be unregistered + * This parameter can be one of the following values: + * This parameter can be one of the following values: + * @arg @ref HAL_I2C_MASTER_TX_COMPLETE_CB_ID Master Tx Transfer completed callback ID + * @arg @ref HAL_I2C_MASTER_RX_COMPLETE_CB_ID Master Rx Transfer completed callback ID + * @arg @ref HAL_I2C_SLAVE_TX_COMPLETE_CB_ID Slave Tx Transfer completed callback ID + * @arg @ref HAL_I2C_SLAVE_RX_COMPLETE_CB_ID Slave Rx Transfer completed callback ID + * @arg @ref HAL_I2C_LISTEN_COMPLETE_CB_ID Listen Complete callback ID + * @arg @ref HAL_I2C_MEM_TX_COMPLETE_CB_ID Memory Tx Transfer callback ID + * @arg @ref HAL_I2C_MEM_RX_COMPLETE_CB_ID Memory Rx Transfer completed callback ID + * @arg @ref HAL_I2C_ERROR_CB_ID Error callback ID + * @arg @ref HAL_I2C_ABORT_CB_ID Abort callback ID + * @arg @ref HAL_I2C_MSPINIT_CB_ID MspInit callback ID + * @arg @ref HAL_I2C_MSPDEINIT_CB_ID MspDeInit callback ID + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_UnRegisterCallback(I2C_HandleTypeDef *hi2c, HAL_I2C_CallbackIDTypeDef CallbackID) +{ + HAL_StatusTypeDef status = HAL_OK; + + /* Process locked */ + __HAL_LOCK(hi2c); + + if (HAL_I2C_STATE_READY == hi2c->State) + { + switch (CallbackID) + { + case HAL_I2C_MASTER_TX_COMPLETE_CB_ID : + hi2c->MasterTxCpltCallback = HAL_I2C_MasterTxCpltCallback; /* Legacy weak MasterTxCpltCallback */ + break; + + case HAL_I2C_MASTER_RX_COMPLETE_CB_ID : + hi2c->MasterRxCpltCallback = HAL_I2C_MasterRxCpltCallback; /* Legacy weak MasterRxCpltCallback */ + break; + + case HAL_I2C_SLAVE_TX_COMPLETE_CB_ID : + hi2c->SlaveTxCpltCallback = HAL_I2C_SlaveTxCpltCallback; /* Legacy weak SlaveTxCpltCallback */ + break; + + case HAL_I2C_SLAVE_RX_COMPLETE_CB_ID : + hi2c->SlaveRxCpltCallback = HAL_I2C_SlaveRxCpltCallback; /* Legacy weak SlaveRxCpltCallback */ + break; + + case HAL_I2C_LISTEN_COMPLETE_CB_ID : + hi2c->ListenCpltCallback = HAL_I2C_ListenCpltCallback; /* Legacy weak ListenCpltCallback */ + break; + + case HAL_I2C_MEM_TX_COMPLETE_CB_ID : + hi2c->MemTxCpltCallback = HAL_I2C_MemTxCpltCallback; /* Legacy weak MemTxCpltCallback */ + break; + + case HAL_I2C_MEM_RX_COMPLETE_CB_ID : + hi2c->MemRxCpltCallback = HAL_I2C_MemRxCpltCallback; /* Legacy weak MemRxCpltCallback */ + break; + + case HAL_I2C_ERROR_CB_ID : + hi2c->ErrorCallback = HAL_I2C_ErrorCallback; /* Legacy weak ErrorCallback */ + break; + + case HAL_I2C_ABORT_CB_ID : + hi2c->AbortCpltCallback = HAL_I2C_AbortCpltCallback; /* Legacy weak AbortCpltCallback */ + break; + + case HAL_I2C_MSPINIT_CB_ID : + hi2c->MspInitCallback = HAL_I2C_MspInit; /* Legacy weak MspInit */ + break; + + case HAL_I2C_MSPDEINIT_CB_ID : + hi2c->MspDeInitCallback = HAL_I2C_MspDeInit; /* Legacy weak MspDeInit */ + break; + + default : + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else if (HAL_I2C_STATE_RESET == hi2c->State) + { + switch (CallbackID) + { + case HAL_I2C_MSPINIT_CB_ID : + hi2c->MspInitCallback = HAL_I2C_MspInit; /* Legacy weak MspInit */ + break; + + case HAL_I2C_MSPDEINIT_CB_ID : + hi2c->MspDeInitCallback = HAL_I2C_MspDeInit; /* Legacy weak MspDeInit */ + break; + + default : + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + break; + } + } + else + { + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hi2c); + return status; +} + +/** + * @brief Register the Slave Address Match I2C Callback + * To be used instead of the weak HAL_I2C_AddrCallback() predefined callback + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pCallback pointer to the Address Match Callback function + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_RegisterAddrCallback(I2C_HandleTypeDef *hi2c, pI2C_AddrCallbackTypeDef pCallback) +{ + HAL_StatusTypeDef status = HAL_OK; + + if (pCallback == NULL) + { + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + return HAL_ERROR; + } + /* Process locked */ + __HAL_LOCK(hi2c); + + if (HAL_I2C_STATE_READY == hi2c->State) + { + hi2c->AddrCallback = pCallback; + } + else + { + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hi2c); + return status; +} + +/** + * @brief UnRegister the Slave Address Match I2C Callback + * Info Ready I2C Callback is redirected to the weak HAL_I2C_AddrCallback() predefined callback + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_UnRegisterAddrCallback(I2C_HandleTypeDef *hi2c) +{ + HAL_StatusTypeDef status = HAL_OK; + + /* Process locked */ + __HAL_LOCK(hi2c); + + if (HAL_I2C_STATE_READY == hi2c->State) + { + hi2c->AddrCallback = HAL_I2C_AddrCallback; /* Legacy weak AddrCallback */ + } + else + { + /* Update the error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_INVALID_CALLBACK; + + /* Return error status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hi2c); + return status; +} + +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + +/** + * @brief I2C data register flush process. + * @param hi2c I2C handle. + * @retval None + */ +static void I2C_Flush_DR(I2C_HandleTypeDef *hi2c) +{ + /* Write a dummy data in DR to clear TXE flag */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) != RESET) + { + hi2c->Instance->DR = 0x00U; + } +} + +/** + * @} + */ + +/** @defgroup I2C_Exported_Functions_Group2 Input and Output operation functions + * @brief Data transfers functions + * +@verbatim + =============================================================================== + ##### IO operation functions ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to manage the I2C data + transfers. + + (#) There are two modes of transfer: + (++) Blocking mode : The communication is performed in the polling mode. + The status of all data processing is returned by the same function + after finishing transfer. + (++) No-Blocking mode : The communication is performed using Interrupts + or DMA. These functions return the status of the transfer startup. + The end of the data processing will be indicated through the + dedicated I2C IRQ when using Interrupt mode or the DMA IRQ when + using DMA mode. + + (#) Blocking mode functions are : + (++) HAL_I2C_Master_Transmit() + (++) HAL_I2C_Master_Receive() + (++) HAL_I2C_Slave_Transmit() + (++) HAL_I2C_Slave_Receive() + (++) HAL_I2C_Mem_Write() + (++) HAL_I2C_Mem_Read() + (++) HAL_I2C_IsDeviceReady() + + (#) No-Blocking mode functions with Interrupt are : + (++) HAL_I2C_Master_Transmit_IT() + (++) HAL_I2C_Master_Receive_IT() + (++) HAL_I2C_Slave_Transmit_IT() + (++) HAL_I2C_Slave_Receive_IT() + (++) HAL_I2C_Mem_Write_IT() + (++) HAL_I2C_Mem_Read_IT() + (++) HAL_I2C_Master_Seq_Transmit_IT() + (++) HAL_I2C_Master_Seq_Receive_IT() + (++) HAL_I2C_Slave_Seq_Transmit_IT() + (++) HAL_I2C_Slave_Seq_Receive_IT() + (++) HAL_I2C_EnableListen_IT() + (++) HAL_I2C_DisableListen_IT() + (++) HAL_I2C_Master_Abort_IT() + + (#) No-Blocking mode functions with DMA are : + (++) HAL_I2C_Master_Transmit_DMA() + (++) HAL_I2C_Master_Receive_DMA() + (++) HAL_I2C_Slave_Transmit_DMA() + (++) HAL_I2C_Slave_Receive_DMA() + (++) HAL_I2C_Mem_Write_DMA() + (++) HAL_I2C_Mem_Read_DMA() + (++) HAL_I2C_Master_Seq_Transmit_DMA() + (++) HAL_I2C_Master_Seq_Receive_DMA() + (++) HAL_I2C_Slave_Seq_Transmit_DMA() + (++) HAL_I2C_Slave_Seq_Receive_DMA() + + (#) A set of Transfer Complete Callbacks are provided in non Blocking mode: + (++) HAL_I2C_MasterTxCpltCallback() + (++) HAL_I2C_MasterRxCpltCallback() + (++) HAL_I2C_SlaveTxCpltCallback() + (++) HAL_I2C_SlaveRxCpltCallback() + (++) HAL_I2C_MemTxCpltCallback() + (++) HAL_I2C_MemRxCpltCallback() + (++) HAL_I2C_AddrCallback() + (++) HAL_I2C_ListenCpltCallback() + (++) HAL_I2C_ErrorCallback() + (++) HAL_I2C_AbortCpltCallback() + +@endverbatim + * @{ + */ + +/** + * @brief Transmits in master mode an amount of data in blocking mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Send Slave Address */ + if (I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + while (hi2c->XferSize > 0U) + { + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + hi2c->XferSize--; + + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + hi2c->XferSize--; + } + + /* Wait until BTF flag is set */ + if (I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + } + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receives in master mode an amount of data in blocking mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Send Slave Address */ + if (I2C_MasterRequestRead(hi2c, DevAddress, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + if (hi2c->XferSize == 0U) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + else if (hi2c->XferSize == 1U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + else if (hi2c->XferSize == 2U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Enable Pos */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + while (hi2c->XferSize > 0U) + { + if (hi2c->XferSize <= 3U) + { + /* One byte */ + if (hi2c->XferSize == 1U) + { + /* Wait until RXNE flag is set */ + if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + /* Two bytes */ + else if (hi2c->XferSize == 2U) + { + /* Wait until BTF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + /* 3 Last bytes */ + else + { + /* Wait until BTF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + /* Wait until BTF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + } + else + { + /* Wait until RXNE flag is set */ + if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) + { + + if (hi2c->XferSize == 3U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + } + } + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmits in slave mode an amount of data in blocking mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* If 10bit addressing mode is selected */ + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT) + { + /* Wait until ADDR flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + while (hi2c->XferSize > 0U) + { + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + /* Disable Address Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + return HAL_ERROR; + } + + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + hi2c->XferSize--; + + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + hi2c->XferSize--; + } + } + + /* Wait until AF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_AF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Disable Address Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in slave mode an amount of data in blocking mode + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + if ((pData == NULL) || (Size == (uint16_t)0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + while (hi2c->XferSize > 0U) + { + /* Wait until RXNE flag is set */ + if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + /* Disable Address Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + return HAL_ERROR; + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + } + + /* Wait until STOP flag is set */ + if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + /* Disable Address Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + return HAL_ERROR; + } + + /* Clear STOP flag */ + __HAL_I2C_CLEAR_STOPFLAG(hi2c); + + /* Disable Address Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in master mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in master mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in slave mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + + if (hi2c->State == HAL_I2C_STATE_READY) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in slave mode an amount of data in non-blocking mode with Interrupt + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + + if (hi2c->State == HAL_I2C_STATE_READY) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in master mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + HAL_StatusTypeDef dmaxferstatus; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + + if (hi2c->XferSize > 0U) + { + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferM1CpltCallback = NULL; + hi2c->hdmatx->XferM1HalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in master mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + HAL_StatusTypeDef dmaxferstatus; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + + if (hi2c->XferSize > 0U) + { + if (hi2c->hdmarx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferM1CpltCallback = NULL; + hi2c->hdmarx->XferM1HalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Transmit in slave mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + HAL_StatusTypeDef dmaxferstatus; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferM1CpltCallback = NULL; + hi2c->hdmatx->XferM1HalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_LISTEN; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + + return HAL_OK; + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receive in slave mode an amount of data in non-blocking mode with DMA + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size) +{ + HAL_StatusTypeDef dmaxferstatus; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + if (hi2c->hdmarx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferM1CpltCallback = NULL; + hi2c->hdmarx->XferM1HalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_LISTEN; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + return HAL_OK; + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Write an amount of data in blocking mode to a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Send Slave Address and Memory Address */ + if (I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + while (hi2c->XferSize > 0U) + { + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + } + + /* Wait until BTF flag is set */ + if (I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Read an amount of data in blocking mode from a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Send Slave Address and Memory Address */ + if (I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + if (hi2c->XferSize == 0U) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + else if (hi2c->XferSize == 1U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + else if (hi2c->XferSize == 2U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Enable Pos */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + while (hi2c->XferSize > 0U) + { + if (hi2c->XferSize <= 3U) + { + /* One byte */ + if (hi2c->XferSize == 1U) + { + /* Wait until RXNE flag is set */ + if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + /* Two bytes */ + else if (hi2c->XferSize == 2U) + { + /* Wait until BTF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + /* 3 Last bytes */ + else + { + /* Wait until BTF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + /* Wait until BTF flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + } + else + { + /* Wait until RXNE flag is set */ + if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) + { + if (hi2c->XferSize == 3U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferSize--; + hi2c->XferCount--; + } + } + } + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Write an amount of data in non-blocking mode with Interrupt to a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + hi2c->Memaddress = MemAddress; + hi2c->MemaddSize = MemAddSize; + hi2c->EventCount = 0U; + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Read an amount of data in non-blocking mode with Interrupt from a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + hi2c->Memaddress = MemAddress; + hi2c->MemaddSize = MemAddSize; + hi2c->EventCount = 0U; + + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + if (hi2c->XferSize > 0U) + { + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Write an amount of data in non-blocking mode with DMA to a specific memory address + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + __IO uint32_t count = 0U; + HAL_StatusTypeDef dmaxferstatus; + + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + hi2c->Memaddress = MemAddress; + hi2c->MemaddSize = MemAddSize; + hi2c->EventCount = 0U; + + if (hi2c->XferSize > 0U) + { + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferM1CpltCallback = NULL; + hi2c->hdmatx->XferM1HalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Send Slave Address and Memory Address */ + if (I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) + { + /* Abort the ongoing DMA */ + dmaxferstatus = HAL_DMA_Abort_IT(hi2c->hdmatx); + + /* Prevent unused argument(s) compilation and MISRA warning */ + UNUSED(dmaxferstatus); + + /* Set the unused I2C DMA transfer complete callback to NULL */ + hi2c->hdmatx->XferCpltCallback = NULL; + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + hi2c->XferSize = 0U; + hi2c->XferCount = 0U; + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR); + + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + return HAL_OK; + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_SIZE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Reads an amount of data in non-blocking mode with DMA from a specific memory address. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param pData Pointer to data buffer + * @param Size Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) +{ + /* Init tickstart for timeout management*/ + uint32_t tickstart = HAL_GetTick(); + __IO uint32_t count = 0U; + HAL_StatusTypeDef dmaxferstatus; + + /* Check the parameters */ + assert_param(IS_I2C_MEMADD_SIZE(MemAddSize)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MEM; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->Devaddress = DevAddress; + hi2c->Memaddress = MemAddress; + hi2c->MemaddSize = MemAddSize; + hi2c->EventCount = 0U; + + if (hi2c->XferSize > 0U) + { + if (hi2c->hdmarx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferM1CpltCallback = NULL; + hi2c->hdmarx->XferM1HalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Send Slave Address and Memory Address */ + if (I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) + { + /* Abort the ongoing DMA */ + dmaxferstatus = HAL_DMA_Abort_IT(hi2c->hdmarx); + + /* Prevent unused argument(s) compilation and MISRA warning */ + UNUSED(dmaxferstatus); + + /* Set the unused I2C DMA transfer complete callback to NULL */ + hi2c->hdmarx->XferCpltCallback = NULL; + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + hi2c->XferSize = 0U; + hi2c->XferCount = 0U; + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + return HAL_ERROR; + } + + if (hi2c->XferSize == 1U) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + else + { + /* Enable Last DMA bit */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + /* Send Slave Address and Memory Address */ + if (I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param Trials Number of trials + * @param Timeout Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout) +{ + /* Get tick */ + uint32_t tickstart = HAL_GetTick(); + uint32_t I2C_Trials = 0U; + FlagStatus tmp1; + FlagStatus tmp2; + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_BUSY; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + do + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + + /* Wait until ADDR or AF flag are set */ + /* Get tick */ + tickstart = HAL_GetTick(); + + tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR); + tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF); + while ((hi2c->State != HAL_I2C_STATE_TIMEOUT) && (tmp1 == RESET) && (tmp2 == RESET)) + { + if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U)) + { + hi2c->State = HAL_I2C_STATE_TIMEOUT; + } + tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR); + tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF); + } + + hi2c->State = HAL_I2C_STATE_READY; + + /* Check if the ADDR flag has been set */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Clear ADDR Flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + hi2c->State = HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_OK; + } + else + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Clear AF Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Wait until BUSY flag is reset */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK) + { + return HAL_ERROR; + } + } + + /* Increment Trials */ + I2C_Trials++; + } + while (I2C_Trials < Trials); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential transmit in master I2C mode an amount of data in non-blocking mode with Interrupt. + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + __IO uint32_t Prev_State = 0x00U; + __IO uint32_t count = 0x00U; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Check Busy Flag only if FIRST call of Master interface */ + if ((READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP) || (XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + hi2c->Devaddress = DevAddress; + + Prev_State = hi2c->PreviousState; + + /* If transfer direction not change and there is no request to start another frame, do not generate Restart Condition */ + /* Mean Previous state is same as current state */ + if ((Prev_State != I2C_STATE_MASTER_BUSY_TX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential transmit in master I2C mode an amount of data in non-blocking mode with DMA. + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + __IO uint32_t Prev_State = 0x00U; + __IO uint32_t count = 0x00U; + HAL_StatusTypeDef dmaxferstatus; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Check Busy Flag only if FIRST call of Master interface */ + if ((READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP) || (XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + hi2c->Devaddress = DevAddress; + + Prev_State = hi2c->PreviousState; + + if (hi2c->XferSize > 0U) + { + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* If transfer direction not change and there is no request to start another frame, do not generate Restart Condition */ + /* Mean Previous state is same as current state */ + if ((Prev_State != I2C_STATE_MASTER_BUSY_TX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* If XferOptions is not associated to a new frame, mean no start bit is request, enable directly the DMA request */ + /* In other cases, DMA request is enabled after Slave address treatment in IRQHandler */ + if ((XferOptions == I2C_NEXT_FRAME) || (XferOptions == I2C_LAST_FRAME) || (XferOptions == I2C_LAST_FRAME_NO_STOP)) + { + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + } + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* If transfer direction not change and there is no request to start another frame, do not generate Restart Condition */ + /* Mean Previous state is same as current state */ + if ((Prev_State != I2C_STATE_MASTER_BUSY_TX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential receive in master I2C mode an amount of data in non-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + __IO uint32_t Prev_State = 0x00U; + __IO uint32_t count = 0U; + uint32_t enableIT = (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Check Busy Flag only if FIRST call of Master interface */ + if ((READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP) || (XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + hi2c->Devaddress = DevAddress; + + Prev_State = hi2c->PreviousState; + + if ((hi2c->XferCount == 2U) && ((XferOptions == I2C_LAST_FRAME) || (XferOptions == I2C_LAST_FRAME_NO_STOP))) + { + if (Prev_State == I2C_STATE_MASTER_BUSY_RX) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Enable Pos */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + /* Remove Enabling of IT_BUF, mean RXNE treatment, treat the 2 bytes through BTF */ + enableIT &= ~I2C_IT_BUF; + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + + /* If transfer direction not change and there is no request to start another frame, do not generate Restart Condition */ + /* Mean Previous state is same as current state */ + if ((Prev_State != I2C_STATE_MASTER_BUSY_RX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable interrupts */ + __HAL_I2C_ENABLE_IT(hi2c, enableIT); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential receive in master mode an amount of data in non-blocking mode with DMA + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + __IO uint32_t Prev_State = 0x00U; + __IO uint32_t count = 0U; + uint32_t enableIT = (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + HAL_StatusTypeDef dmaxferstatus; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + /* Check Busy Flag only if FIRST call of Master interface */ + if ((READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP) || (XferOptions == I2C_FIRST_AND_LAST_FRAME) || (XferOptions == I2C_FIRST_FRAME)) + { + /* Wait until BUSY flag is reset */ + count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_BUSY; + } + } + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET); + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + /* Clear Last DMA bit */ + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + + hi2c->State = HAL_I2C_STATE_BUSY_RX; + hi2c->Mode = HAL_I2C_MODE_MASTER; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + hi2c->Devaddress = DevAddress; + + Prev_State = hi2c->PreviousState; + + if (hi2c->XferSize > 0U) + { + if ((hi2c->XferCount == 2U) && ((XferOptions == I2C_LAST_FRAME) || (XferOptions == I2C_LAST_FRAME_NO_STOP))) + { + if (Prev_State == I2C_STATE_MASTER_BUSY_RX) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Enable Pos */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + /* Enable Last DMA bit */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + if ((XferOptions == I2C_LAST_FRAME) || (XferOptions == I2C_OTHER_AND_LAST_FRAME) || (XferOptions == I2C_LAST_FRAME_NO_STOP)) + { + /* Enable Last DMA bit */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + } + } + if (hi2c->hdmarx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + if (dmaxferstatus == HAL_OK) + { + /* If transfer direction not change and there is no request to start another frame, do not generate Restart Condition */ + /* Mean Previous state is same as current state */ + if ((Prev_State != I2C_STATE_MASTER_BUSY_RX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Update interrupt for only EVT and ERR */ + enableIT = (I2C_IT_EVT | I2C_IT_ERR); + } + else + { + /* Update interrupt for only ERR */ + enableIT = I2C_IT_ERR; + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* If XferOptions is not associated to a new frame, mean no start bit is request, enable directly the DMA request */ + /* In other cases, DMA request is enabled after Slave address treatment in IRQHandler */ + if ((XferOptions == I2C_NEXT_FRAME) || (XferOptions == I2C_LAST_FRAME) || (XferOptions == I2C_LAST_FRAME_NO_STOP)) + { + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + } + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, enableIT); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* If transfer direction not change and there is no request to start another frame, do not generate Restart Condition */ + /* Mean Previous state is same as current state */ + if ((Prev_State != I2C_STATE_MASTER_BUSY_RX) || (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(XferOptions) == 1)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable interrupts */ + __HAL_I2C_ENABLE_IT(hi2c, enableIT); + } + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential transmit in slave mode an amount of data in non-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (((uint32_t)hi2c->State & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX_LISTEN; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential transmit in slave mode an amount of data in non-blocking mode with DMA + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + HAL_StatusTypeDef dmaxferstatus; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (((uint32_t)hi2c->State & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Disable Interrupts, to prevent preemption during treatment in case of multicall */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* I2C cannot manage full duplex exchange so disable previous IT enabled if any */ + /* and then toggle the HAL slave RX state to TX state */ + if (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN) + { + if ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + /* Abort DMA Xfer if any */ + if (hi2c->hdmarx != NULL) + { + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Set the I2C DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort; + + /* Abort DMA RX */ + if (HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx); + } + } + } + } + else if (hi2c->State == HAL_I2C_STATE_BUSY_TX_LISTEN) + { + if ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Abort DMA Xfer if any */ + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort; + + /* Abort DMA TX */ + if (HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx); + } + } + } + } + else + { + /* Nothing to do */ + } + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_TX_LISTEN; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmatx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmatx->XferHalfCpltCallback = NULL; + hi2c->hdmatx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_LISTEN; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Enable DMA Request */ + hi2c->Instance->CR2 |= I2C_CR2_DMAEN; + + return HAL_OK; + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential receive in slave mode an amount of data in non-blocking mode with Interrupt + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (((uint32_t)hi2c->State & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX_LISTEN; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + + /* Enable EVT, BUF and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sequential receive in slave mode an amount of data in non-blocking mode with DMA + * @note This interface allow to manage repeated start condition when a direction change during transfer + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param pData Pointer to data buffer + * @param Size Amount of data to be sent + * @param XferOptions Options of Transfer, value of @ref I2C_XferOptions_definition + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions) +{ + HAL_StatusTypeDef dmaxferstatus; + + /* Check the parameters */ + assert_param(IS_I2C_TRANSFER_OPTIONS_REQUEST(XferOptions)); + + if (((uint32_t)hi2c->State & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + if ((pData == NULL) || (Size == 0U)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(hi2c); + + /* Disable Interrupts, to prevent preemption during treatment in case of multicall */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* I2C cannot manage full duplex exchange so disable previous IT enabled if any */ + /* and then toggle the HAL slave RX state to TX state */ + if (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN) + { + if ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + /* Abort DMA Xfer if any */ + if (hi2c->hdmarx != NULL) + { + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Set the I2C DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort; + + /* Abort DMA RX */ + if (HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx); + } + } + } + } + else if (hi2c->State == HAL_I2C_STATE_BUSY_TX_LISTEN) + { + if ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Abort DMA Xfer if any */ + if (hi2c->hdmatx != NULL) + { + /* Set the I2C DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort; + + /* Abort DMA TX */ + if (HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx); + } + } + } + } + else + { + /* Nothing to do */ + } + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Disable Pos */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + + hi2c->State = HAL_I2C_STATE_BUSY_RX_LISTEN; + hi2c->Mode = HAL_I2C_MODE_SLAVE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Prepare transfer parameters */ + hi2c->pBuffPtr = pData; + hi2c->XferCount = Size; + hi2c->XferSize = hi2c->XferCount; + hi2c->XferOptions = XferOptions; + + if (hi2c->hdmarx != NULL) + { + /* Set the I2C DMA transfer complete callback */ + hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt; + + /* Set the DMA error callback */ + hi2c->hdmarx->XferErrorCallback = I2C_DMAError; + + /* Set the unused DMA callbacks to NULL */ + hi2c->hdmarx->XferHalfCpltCallback = NULL; + hi2c->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA stream */ + dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize); + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_LISTEN; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + if (dmaxferstatus == HAL_OK) + { + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Note : The I2C interrupts must be enabled after unlocking current process + to avoid the risk of I2C interrupt handle execution before current + process unlock */ + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + return HAL_OK; + } + else + { + /* Update I2C state */ + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Update I2C error code */ + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Enable the Address listen mode with Interrupt. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c) +{ + if (hi2c->State == HAL_I2C_STATE_READY) + { + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Check if the I2C is already enabled */ + if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) + { + /* Enable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + } + + /* Enable Address Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Enable EVT and ERR interrupt */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Disable the Address listen mode with Interrupt. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of tmp to prevent undefined behavior of volatile usage */ + uint32_t tmp; + + /* Disable Address listen mode only if a transfer is not ongoing */ + if (hi2c->State == HAL_I2C_STATE_LISTEN) + { + tmp = (uint32_t)(hi2c->State) & I2C_STATE_MSK; + hi2c->PreviousState = tmp | (uint32_t)(hi2c->Mode); + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Disable Address Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Disable EVT and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Abort a master or memory I2C IT or DMA process communication with Interrupt. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + + /* Prevent unused argument(s) compilation warning */ + UNUSED(DevAddress); + + /* Abort Master transfer during Receive or Transmit process */ + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET) && ((CurrentMode == HAL_I2C_MODE_MASTER) || + (CurrentMode == HAL_I2C_MODE_MEM))) + { + /* Process Locked */ + __HAL_LOCK(hi2c); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_ABORT; + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->XferCount = 0U; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Call the corresponding callback to inform upper layer of End of Transfer */ + I2C_ITError(hi2c); + + return HAL_OK; + } + else + { + /* Wrong usage of abort function */ + /* This function should be used only in case of abort monitored by master device */ + /* Or periphal is not in busy state, mean there is no active sequence to be abort */ + return HAL_ERROR; + } +} + +/** + * @} + */ + +/** @defgroup I2C_IRQ_Handler_and_Callbacks IRQ Handler and Callbacks + * @{ + */ + +/** + * @brief This function handles I2C event interrupt request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c) +{ + uint32_t sr1itflags; + uint32_t sr2itflags = 0U; + uint32_t itsources = READ_REG(hi2c->Instance->CR2); + uint32_t CurrentXferOptions = hi2c->XferOptions; + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + + /* Master or Memory mode selected */ + if ((CurrentMode == HAL_I2C_MODE_MASTER) || (CurrentMode == HAL_I2C_MODE_MEM)) + { + sr2itflags = READ_REG(hi2c->Instance->SR2); + sr1itflags = READ_REG(hi2c->Instance->SR1); + + /* Exit IRQ event until Start Bit detected in case of Other frame requested */ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_SB) == RESET) && (IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(CurrentXferOptions) == 1U)) + { + return; + } + + /* SB Set ----------------------------------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_SB) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + /* Convert OTHER_xxx XferOptions if any */ + I2C_ConvertOtherXferOptions(hi2c); + + I2C_Master_SB(hi2c); + } + /* ADD10 Set -------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ADD10) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + I2C_Master_ADD10(hi2c); + } + /* ADDR Set --------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ADDR) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + I2C_Master_ADDR(hi2c); + } + /* I2C in mode Transmitter -----------------------------------------------*/ + else if (I2C_CHECK_FLAG(sr2itflags, I2C_FLAG_TRA) != RESET) + { + /* Do not check buffer and BTF flag if a Xfer DMA is on going */ + if (READ_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN) != I2C_CR2_DMAEN) + { + /* TXE set and BTF reset -----------------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_TXE) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_BUF) != RESET) && (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) == RESET)) + { + I2C_MasterTransmit_TXE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + if (CurrentState == HAL_I2C_STATE_BUSY_TX) + { + I2C_MasterTransmit_BTF(hi2c); + } + else /* HAL_I2C_MODE_MEM */ + { + if (CurrentMode == HAL_I2C_MODE_MEM) + { + I2C_MemoryTransmit_TXE_BTF(hi2c); + } + } + } + else + { + /* Do nothing */ + } + } + } + /* I2C in mode Receiver --------------------------------------------------*/ + else + { + /* Do not check buffer and BTF flag if a Xfer DMA is on going */ + if (READ_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN) != I2C_CR2_DMAEN) + { + /* RXNE set and BTF reset -----------------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_RXNE) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_BUF) != RESET) && (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) == RESET)) + { + I2C_MasterReceive_RXNE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + I2C_MasterReceive_BTF(hi2c); + } + else + { + /* Do nothing */ + } + } + } + } + /* Slave mode selected */ + else + { + /* If an error is detected, read only SR1 register to prevent */ + /* a clear of ADDR flags by reading SR2 after reading SR1 in Error treatment */ + if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { + sr1itflags = READ_REG(hi2c->Instance->SR1); + } + else + { + sr2itflags = READ_REG(hi2c->Instance->SR2); + sr1itflags = READ_REG(hi2c->Instance->SR1); + } + + /* ADDR set --------------------------------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ADDR) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + /* Now time to read SR2, this will clear ADDR flag automatically */ + if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { + sr2itflags = READ_REG(hi2c->Instance->SR2); + } + I2C_Slave_ADDR(hi2c, sr2itflags); + } + /* STOPF set --------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_STOPF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + I2C_Slave_STOPF(hi2c); + } + /* I2C in mode Transmitter -----------------------------------------------*/ + else if ((CurrentState == HAL_I2C_STATE_BUSY_TX) || (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)) + { + /* TXE set and BTF reset -----------------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_TXE) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_BUF) != RESET) && (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) == RESET)) + { + I2C_SlaveTransmit_TXE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + I2C_SlaveTransmit_BTF(hi2c); + } + else + { + /* Do nothing */ + } + } + /* I2C in mode Receiver --------------------------------------------------*/ + else + { + /* RXNE set and BTF reset ----------------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_RXNE) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_BUF) != RESET) && (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) == RESET)) + { + I2C_SlaveReceive_RXNE(hi2c); + } + /* BTF set -------------------------------------------------------------*/ + else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) + { + I2C_SlaveReceive_BTF(hi2c); + } + else + { + /* Do nothing */ + } + } + } +} + +/** + * @brief This function handles I2C error interrupt request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c) +{ + HAL_I2C_ModeTypeDef tmp1; + uint32_t tmp2; + HAL_I2C_StateTypeDef tmp3; + uint32_t tmp4; + uint32_t sr1itflags = READ_REG(hi2c->Instance->SR1); + uint32_t itsources = READ_REG(hi2c->Instance->CR2); + uint32_t error = HAL_I2C_ERROR_NONE; + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + + /* I2C Bus error interrupt occurred ----------------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BERR) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_ERR) != RESET)) + { + error |= HAL_I2C_ERROR_BERR; + + /* Clear BERR flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); + } + + /* I2C Arbitration Lost error interrupt occurred ---------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ARLO) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_ERR) != RESET)) + { + error |= HAL_I2C_ERROR_ARLO; + + /* Clear ARLO flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); + } + + /* I2C Acknowledge failure error interrupt occurred ------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_AF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_ERR) != RESET)) + { + tmp1 = CurrentMode; + tmp2 = hi2c->XferCount; + tmp3 = hi2c->State; + tmp4 = hi2c->PreviousState; + if ((tmp1 == HAL_I2C_MODE_SLAVE) && (tmp2 == 0U) && \ + ((tmp3 == HAL_I2C_STATE_BUSY_TX) || (tmp3 == HAL_I2C_STATE_BUSY_TX_LISTEN) || \ + ((tmp3 == HAL_I2C_STATE_LISTEN) && (tmp4 == I2C_STATE_SLAVE_BUSY_TX)))) + { + I2C_Slave_AF(hi2c); + } + else + { + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + error |= HAL_I2C_ERROR_AF; + + /* Do not generate a STOP in case of Slave receive non acknowledge during transfer (mean not at the end of transfer) */ + if ((CurrentMode == HAL_I2C_MODE_MASTER) || (CurrentMode == HAL_I2C_MODE_MEM)) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + } + } + + /* I2C Over-Run/Under-Run interrupt occurred -------------------------------*/ + if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_OVR) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_ERR) != RESET)) + { + error |= HAL_I2C_ERROR_OVR; + /* Clear OVR flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); + } + + /* Call the Error Callback in case of Error detected -----------------------*/ + if (error != HAL_I2C_ERROR_NONE) + { + hi2c->ErrorCode |= error; + I2C_ITError(hi2c); + } +} + +/** + * @brief Master Tx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MasterTxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Master Rx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MasterRxCpltCallback could be implemented in the user file + */ +} + +/** @brief Slave Tx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_SlaveTxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Slave Rx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_SlaveRxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Slave Address Match callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param TransferDirection Master request Transfer Direction (Write/Read), value of @ref I2C_XferDirection_definition + * @param AddrMatchCode Address Match Code + * @retval None + */ +__weak void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + UNUSED(TransferDirection); + UNUSED(AddrMatchCode); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_AddrCallback() could be implemented in the user file + */ +} + +/** + * @brief Listen Complete callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_ListenCpltCallback() could be implemented in the user file + */ +} + +/** + * @brief Memory Tx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MemTxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Memory Rx Transfer completed callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_MemRxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief I2C error callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_ErrorCallback could be implemented in the user file + */ +} + +/** + * @brief I2C abort callback. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +__weak void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hi2c); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_I2C_AbortCpltCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup I2C_Exported_Functions_Group3 Peripheral State, Mode and Error functions + * @brief Peripheral State, Mode and Error functions + * +@verbatim + =============================================================================== + ##### Peripheral State, Mode and Error functions ##### + =============================================================================== + [..] + This subsection permit to get in run-time the status of the peripheral + and the data flow. + +@endverbatim + * @{ + */ + +/** + * @brief Return the I2C handle state. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL state + */ +HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c) +{ + /* Return I2C handle state */ + return hi2c->State; +} + +/** + * @brief Returns the I2C Master, Slave, Memory or no mode. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval HAL mode + */ +HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c) +{ + return hi2c->Mode; +} + +/** + * @brief Return the I2C error code. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval I2C Error Code + */ +uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c) +{ + return hi2c->ErrorCode; +} + +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup I2C_Private_Functions + * @{ + */ + +/** + * @brief Handle TXE flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_MasterTransmit_TXE(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if ((hi2c->XferSize == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX)) + { + /* Call TxCpltCallback() directly if no stop mode is set */ + if ((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) + { + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterTxCpltCallback(hi2c); +#else + HAL_I2C_MasterTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else /* Generate Stop condition then Call TxCpltCallback() */ + { + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MemTxCpltCallback(hi2c); +#else + HAL_I2C_MemTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterTxCpltCallback(hi2c); +#else + HAL_I2C_MasterTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + } + else if ((CurrentState == HAL_I2C_STATE_BUSY_TX) || \ + ((CurrentMode == HAL_I2C_MODE_MEM) && (CurrentState == HAL_I2C_STATE_BUSY_RX))) + { + if (hi2c->XferCount == 0U) + { + /* Disable BUF interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + } + else + { + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + I2C_MemoryTransmit_TXE_BTF(hi2c); + } + else + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + } + } + else + { + /* Do nothing */ + } +} + +/** + * @brief Handle BTF flag for Master transmitter + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if (hi2c->State == HAL_I2C_STATE_BUSY_TX) + { + if (hi2c->XferCount != 0U) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + else + { + /* Call TxCpltCallback() directly if no stop mode is set */ + if ((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) + { + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterTxCpltCallback(hi2c); +#else + HAL_I2C_MasterTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else /* Generate Stop condition then Call TxCpltCallback() */ + { + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MemTxCpltCallback(hi2c); +#else + HAL_I2C_MemTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterTxCpltCallback(hi2c); +#else + HAL_I2C_MasterTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + } + } + else + { + /* Do nothing */ + } +} + +/** + * @brief Handle TXE and BTF flag for Memory transmitter + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_MemoryTransmit_TXE_BTF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + + if (hi2c->EventCount == 0U) + { + /* If Memory address size is 8Bit */ + if (hi2c->MemaddSize == I2C_MEMADD_SIZE_8BIT) + { + /* Send Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(hi2c->Memaddress); + + hi2c->EventCount += 2U; + } + /* If Memory address size is 16Bit */ + else + { + /* Send MSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_MSB(hi2c->Memaddress); + + hi2c->EventCount++; + } + } + else if (hi2c->EventCount == 1U) + { + /* Send LSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(hi2c->Memaddress); + + hi2c->EventCount++; + } + else if (hi2c->EventCount == 2U) + { + if (CurrentState == HAL_I2C_STATE_BUSY_RX) + { + /* Generate Restart */ + hi2c->Instance->CR1 |= I2C_CR1_START; + + hi2c->EventCount++; + } + else if ((hi2c->XferCount > 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX)) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + else if ((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX)) + { + /* Generate Stop condition then Call TxCpltCallback() */ + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MemTxCpltCallback(hi2c); +#else + HAL_I2C_MemTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + /* Do nothing */ + } + } + else + { + /* Clear TXE and BTF flags */ + I2C_Flush_DR(hi2c); + } +} + +/** + * @brief Handle RXNE flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_MasterReceive_RXNE(I2C_HandleTypeDef *hi2c) +{ + if (hi2c->State == HAL_I2C_STATE_BUSY_RX) + { + uint32_t tmp; + uint32_t CurrentXferOptions; + + CurrentXferOptions = hi2c->XferOptions; + tmp = hi2c->XferCount; + if (tmp > 3U) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + if (hi2c->XferCount == (uint16_t)3) + { + /* Disable BUF interrupt, this help to treat correctly the last 4 bytes + on BTF subroutine */ + /* Disable BUF interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + } + } + else if ((hi2c->XferOptions != I2C_FIRST_AND_NEXT_FRAME) && ((tmp == 1U) || (tmp == 0U))) + { + if (I2C_WaitOnSTOPRequestThroughIT(hi2c) == HAL_OK) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + hi2c->State = HAL_I2C_STATE_READY; + + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->PreviousState = I2C_STATE_NONE; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MemRxCpltCallback(hi2c); +#else + HAL_I2C_MemRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) + { + hi2c->PreviousState = I2C_STATE_NONE; + } + else + { + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_RX; + } + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterRxCpltCallback(hi2c); +#else + HAL_I2C_MasterRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + else + { + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call user error callback */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ErrorCallback(hi2c); +#else + HAL_I2C_ErrorCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + else + { + /* Disable BUF interrupt, this help to treat correctly the last 2 bytes + on BTF subroutine if there is a reception delay between N-1 and N byte */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + } + } +} + +/** + * @brief Handle BTF flag for Master receiver + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_MasterReceive_BTF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if (hi2c->XferCount == 4U) + { + /* Disable BUF interrupt, this help to treat correctly the last 2 bytes + on BTF subroutine if there is a reception delay between N-1 and N byte */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + else if (hi2c->XferCount == 3U) + { + /* Disable BUF interrupt, this help to treat correctly the last 2 bytes + on BTF subroutine if there is a reception delay between N-1 and N byte */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + if ((CurrentXferOptions != I2C_NEXT_FRAME) && (CurrentXferOptions != I2C_FIRST_AND_NEXT_FRAME)) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + else if (hi2c->XferCount == 2U) + { + /* Prepare next transfer or stop current transfer */ + if ((CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME_NO_STOP)) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + else if ((CurrentXferOptions == I2C_NEXT_FRAME) || (CurrentXferOptions == I2C_FIRST_AND_NEXT_FRAME)) + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + else + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + /* Disable EVT and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + hi2c->State = HAL_I2C_STATE_READY; + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->PreviousState = I2C_STATE_NONE; +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MemRxCpltCallback(hi2c); +#else + HAL_I2C_MemRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) + { + hi2c->PreviousState = I2C_STATE_NONE; + } + else + { + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_RX; + } +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterRxCpltCallback(hi2c); +#else + HAL_I2C_MasterRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + else + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } +} + +/** + * @brief Handle SB flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_Master_SB(I2C_HandleTypeDef *hi2c) +{ + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + if (hi2c->EventCount == 0U) + { + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(hi2c->Devaddress); + } + else + { + hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress); + } + } + else + { + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + { + /* Send slave 7 Bits address */ + if (hi2c->State == HAL_I2C_STATE_BUSY_TX) + { + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(hi2c->Devaddress); + } + else + { + hi2c->Instance->DR = I2C_7BIT_ADD_READ(hi2c->Devaddress); + } + + if (((hi2c->hdmatx != NULL) && (hi2c->hdmatx->XferCpltCallback != NULL)) + || ((hi2c->hdmarx != NULL) && (hi2c->hdmarx->XferCpltCallback != NULL))) + { + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + } + } + else + { + if (hi2c->EventCount == 0U) + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(hi2c->Devaddress); + } + else if (hi2c->EventCount == 1U) + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_READ(hi2c->Devaddress); + } + else + { + /* Do nothing */ + } + } + } +} + +/** + * @brief Handle ADD10 flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_Master_ADD10(I2C_HandleTypeDef *hi2c) +{ + /* Send slave address */ + hi2c->Instance->DR = I2C_10BIT_ADDRESS(hi2c->Devaddress); + + if (((hi2c->hdmatx != NULL) && (hi2c->hdmatx->XferCpltCallback != NULL)) + || ((hi2c->hdmarx != NULL) && (hi2c->hdmarx->XferCpltCallback != NULL))) + { + /* Enable DMA Request */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + } +} + +/** + * @brief Handle ADDR flag for Master + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_Master_ADDR(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + uint32_t CurrentXferOptions = hi2c->XferOptions; + uint32_t Prev_State = hi2c->PreviousState; + + if (hi2c->State == HAL_I2C_STATE_BUSY_RX) + { + if ((hi2c->EventCount == 0U) && (CurrentMode == HAL_I2C_MODE_MEM)) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else if ((hi2c->EventCount == 0U) && (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_10BIT)) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Restart */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + hi2c->EventCount++; + } + else + { + if (hi2c->XferCount == 0U) + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + else if (hi2c->XferCount == 1U) + { + if (CurrentXferOptions == I2C_NO_OPTION_FRAME) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + if ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + } + /* Prepare next transfer or stop current transfer */ + else if ((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) \ + && ((Prev_State != I2C_STATE_MASTER_BUSY_RX) || (CurrentXferOptions == I2C_FIRST_FRAME))) + { + if ((CurrentXferOptions != I2C_NEXT_FRAME) && (CurrentXferOptions != I2C_FIRST_AND_NEXT_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME_NO_STOP)) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + } + else if (hi2c->XferCount == 2U) + { + if ((CurrentXferOptions != I2C_NEXT_FRAME) && (CurrentXferOptions != I2C_FIRST_AND_NEXT_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME_NO_STOP)) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Enable Pos */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_POS); + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + + if (((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) && ((CurrentXferOptions == I2C_NO_OPTION_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME_NO_STOP) || (CurrentXferOptions == I2C_LAST_FRAME))) + { + /* Enable Last DMA bit */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + else + { + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + if (((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) && ((CurrentXferOptions == I2C_NO_OPTION_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME_NO_STOP) || (CurrentXferOptions == I2C_LAST_FRAME))) + { + /* Enable Last DMA bit */ + SET_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } + + /* Reset Event counter */ + hi2c->EventCount = 0U; + } + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + } +} + +/** + * @brief Handle TXE flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + + if (hi2c->XferCount != 0U) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + if ((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)) + { + /* Last Byte is received, disable Interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveTxCpltCallback(hi2c); +#else + HAL_I2C_SlaveTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } +} + +/** + * @brief Handle BTF flag for Slave transmitter + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c) +{ + if (hi2c->XferCount != 0U) + { + /* Write data to DR */ + hi2c->Instance->DR = *hi2c->pBuffPtr; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } +} + +/** + * @brief Handle RXNE flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + + if (hi2c->XferCount != 0U) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + + if ((hi2c->XferCount == 0U) && (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)) + { + /* Last Byte is received, disable Interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF); + + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_RX; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveRxCpltCallback(hi2c); +#else + HAL_I2C_SlaveRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } +} + +/** + * @brief Handle BTF flag for Slave receiver + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c) +{ + if (hi2c->XferCount != 0U) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } +} + +/** + * @brief Handle ADD flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param IT2Flags Interrupt2 flags to handle. + * @retval None + */ +static void I2C_Slave_ADDR(I2C_HandleTypeDef *hi2c, uint32_t IT2Flags) +{ + uint8_t TransferDirection = I2C_DIRECTION_RECEIVE; + uint16_t SlaveAddrCode; + + if (((uint32_t)hi2c->State & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + /* Disable BUF interrupt, BUF enabling is manage through slave specific interface */ + __HAL_I2C_DISABLE_IT(hi2c, (I2C_IT_BUF)); + + /* Transfer Direction requested by Master */ + if (I2C_CHECK_FLAG(IT2Flags, I2C_FLAG_TRA) == RESET) + { + TransferDirection = I2C_DIRECTION_TRANSMIT; + } + + if (I2C_CHECK_FLAG(IT2Flags, I2C_FLAG_DUALF) == RESET) + { + SlaveAddrCode = (uint16_t)hi2c->Init.OwnAddress1; + } + else + { + SlaveAddrCode = (uint16_t)hi2c->Init.OwnAddress2; + } + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + /* Call Slave Addr callback */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->AddrCallback(hi2c, TransferDirection, SlaveAddrCode); +#else + HAL_I2C_AddrCallback(hi2c, TransferDirection, SlaveAddrCode); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + } +} + +/** + * @brief Handle STOPF flag for Slave + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_Slave_STOPF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Clear STOPF flag */ + __HAL_I2C_CLEAR_STOPFLAG(hi2c); + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* If a DMA is ongoing, Update handle size context */ + if ((hi2c->Instance->CR2 & I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + if ((CurrentState == HAL_I2C_STATE_BUSY_RX) || (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)) + { + hi2c->XferCount = (uint16_t)(I2C_GET_DMA_REMAIN_DATA(hi2c->hdmarx)); + + if (hi2c->XferCount != 0U) + { + /* Set ErrorCode corresponding to a Non-Acknowledge */ + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + } + + /* Disable, stop the current DMA */ + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Abort DMA Xfer if any */ + if (HAL_DMA_GetState(hi2c->hdmarx) != HAL_DMA_STATE_READY) + { + /* Set the I2C DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort; + + /* Abort DMA RX */ + if (HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx); + } + } + } + else + { + hi2c->XferCount = (uint16_t)(I2C_GET_DMA_REMAIN_DATA(hi2c->hdmatx)); + + if (hi2c->XferCount != 0U) + { + /* Set ErrorCode corresponding to a Non-Acknowledge */ + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + } + + /* Disable, stop the current DMA */ + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + /* Abort DMA Xfer if any */ + if (HAL_DMA_GetState(hi2c->hdmatx) != HAL_DMA_STATE_READY) + { + /* Set the I2C DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort; + + /* Abort DMA TX */ + if (HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx); + } + } + } + } + + /* All data are not transferred, so set error code accordingly */ + if (hi2c->XferCount != 0U) + { + /* Store Last receive data if any */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + + /* Store Last receive data if any */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + + /* Update counter */ + hi2c->XferCount--; + } + + if (hi2c->XferCount != 0U) + { + /* Set ErrorCode corresponding to a Non-Acknowledge */ + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + } + } + + if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { + /* Call the corresponding callback to inform upper layer of End of Transfer */ + I2C_ITError(hi2c); + } + else + { + if (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN) + { + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveRxCpltCallback(hi2c); +#else + HAL_I2C_SlaveRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + + if (hi2c->State == HAL_I2C_STATE_LISTEN) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ListenCpltCallback(hi2c); +#else + HAL_I2C_ListenCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + if ((hi2c->PreviousState == I2C_STATE_SLAVE_BUSY_RX) || (CurrentState == HAL_I2C_STATE_BUSY_RX)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveRxCpltCallback(hi2c); +#else + HAL_I2C_SlaveRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + } +} + +/** + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @retval None + */ +static void I2C_Slave_AF(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + uint32_t CurrentXferOptions = hi2c->XferOptions; + + if (((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) && \ + (CurrentState == HAL_I2C_STATE_LISTEN)) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ListenCpltCallback(hi2c); +#else + HAL_I2C_ListenCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else if (CurrentState == HAL_I2C_STATE_BUSY_TX) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + + /* Clear AF flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Clear TXE flag */ + I2C_Flush_DR(hi2c); + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveTxCpltCallback(hi2c); +#else + HAL_I2C_SlaveTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + /* Clear AF flag only */ + /* State Listen, but XferOptions == FIRST or NEXT */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + } +} + +/** + * @brief I2C interrupts error process + * @param hi2c I2C handle. + * @retval None + */ +static void I2C_ITError(I2C_HandleTypeDef *hi2c) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + uint32_t CurrentError; + + if (((CurrentMode == HAL_I2C_MODE_MASTER) || (CurrentMode == HAL_I2C_MODE_MEM)) && (CurrentState == HAL_I2C_STATE_BUSY_RX)) + { + /* Disable Pos bit in I2C CR1 when error occurred in Master/Mem Receive IT Process */ + hi2c->Instance->CR1 &= ~I2C_CR1_POS; + } + + if (((uint32_t)CurrentState & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + /* keep HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_LISTEN; + } + else + { + /* If state is an abort treatment on going, don't change state */ + /* This change will be do later */ + if ((READ_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN) != I2C_CR2_DMAEN) && (CurrentState != HAL_I2C_STATE_ABORT)) + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + } + hi2c->PreviousState = I2C_STATE_NONE; + } + + /* Abort DMA transfer */ + if (READ_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN) == I2C_CR2_DMAEN) + { + hi2c->Instance->CR2 &= ~I2C_CR2_DMAEN; + + if (hi2c->hdmatx->State != HAL_DMA_STATE_READY) + { + /* Set the DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmatx->XferAbortCallback = I2C_DMAAbort; + + if (HAL_DMA_Abort_IT(hi2c->hdmatx) != HAL_OK) + { + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Call Directly XferAbortCallback function in case of error */ + hi2c->hdmatx->XferAbortCallback(hi2c->hdmatx); + } + } + else + { + /* Set the DMA Abort callback : + will lead to call HAL_I2C_ErrorCallback() at end of DMA abort procedure */ + hi2c->hdmarx->XferAbortCallback = I2C_DMAAbort; + + if (HAL_DMA_Abort_IT(hi2c->hdmarx) != HAL_OK) + { + /* Store Last receive data if any */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + } + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + /* Call Directly hi2c->hdmarx->XferAbortCallback function in case of error */ + hi2c->hdmarx->XferAbortCallback(hi2c->hdmarx); + } + } + } + else if (hi2c->State == HAL_I2C_STATE_ABORT) + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Store Last receive data if any */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + } + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->AbortCpltCallback(hi2c); +#else + HAL_I2C_AbortCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + /* Store Last receive data if any */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == SET) + { + /* Read data from DR */ + *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR; + + /* Increment Buffer pointer */ + hi2c->pBuffPtr++; + } + + /* Call user error callback */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ErrorCallback(hi2c); +#else + HAL_I2C_ErrorCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + + /* STOP Flag is not set after a NACK reception, BusError, ArbitrationLost, OverRun */ + CurrentError = hi2c->ErrorCode; + + if (((CurrentError & HAL_I2C_ERROR_BERR) == HAL_I2C_ERROR_BERR) || \ + ((CurrentError & HAL_I2C_ERROR_ARLO) == HAL_I2C_ERROR_ARLO) || \ + ((CurrentError & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF) || \ + ((CurrentError & HAL_I2C_ERROR_OVR) == HAL_I2C_ERROR_OVR)) + { + /* Disable EVT, BUF and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + } + + /* So may inform upper layer that listen phase is stopped */ + /* during NACK error treatment */ + CurrentState = hi2c->State; + if (((hi2c->ErrorCode & HAL_I2C_ERROR_AF) == HAL_I2C_ERROR_AF) && (CurrentState == HAL_I2C_STATE_LISTEN)) + { + hi2c->XferOptions = I2C_NO_OPTION_FRAME; + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + /* Call the Listen Complete callback, to inform upper layer of the end of Listen usecase */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ListenCpltCallback(hi2c); +#else + HAL_I2C_ListenCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } +} + +/** + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + /* Generate Start condition if first transfer */ + if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + else if (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_RX) + { + /* Generate ReStart */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + else + { + /* Do nothing */ + } + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + { + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + } + else + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress); + + /* Wait until ADD10 flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress); + } + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +/** + * @brief Master sends target device address for read request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart) +{ + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + uint32_t CurrentXferOptions = hi2c->XferOptions; + + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start condition if first transfer */ + if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME)) + { + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + else if (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) + { + /* Generate ReStart */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + } + else + { + /* Do nothing */ + } + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT) + { + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress); + } + else + { + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress); + + /* Wait until ADD10 flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress); + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Generate Restart */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + /* Send header of slave address */ + hi2c->Instance->DR = I2C_10BIT_HEADER_READ(DevAddress); + } + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +/** + * @brief Master sends target device address followed by internal memory address for write request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart) +{ + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* If Memory address size is 8Bit */ + if (MemAddSize == I2C_MEMADD_SIZE_8BIT) + { + /* Send Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + /* If Memory address size is 16Bit */ + else + { + /* Send MSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress); + + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* Send LSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + + return HAL_OK; +} + +/** + * @brief Master sends target device address followed by internal memory address for read request. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param DevAddress Target device address: The device 7 bits address value + * in datasheet must be shifted to the left before calling the interface + * @param MemAddress Internal memory address + * @param MemAddSize Size of internal memory address + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart) +{ + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* Generate Start */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress); + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + /* Clear ADDR flag */ + __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* If Memory address size is 8Bit */ + if (MemAddSize == I2C_MEMADD_SIZE_8BIT) + { + /* Send Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + /* If Memory address size is 16Bit */ + else + { + /* Send MSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress); + + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* Send LSB of Memory Address */ + hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress); + } + + /* Wait until TXE flag is set */ + if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK) + { + if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + return HAL_ERROR; + } + + /* Generate Restart */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_START); + + /* Wait until SB flag is set */ + if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK) + { + if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START) + { + hi2c->ErrorCode = HAL_I2C_WRONG_START; + } + return HAL_TIMEOUT; + } + + /* Send slave address */ + hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress); + + /* Wait until ADDR flag is set */ + if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK) + { + return HAL_ERROR; + } + + return HAL_OK; +} + +/** + * @brief DMA I2C process complete callback. + * @param hdma DMA handle + * @retval None + */ +static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma) +{ + I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */ + + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode; + uint32_t CurrentXferOptions = hi2c->XferOptions; + + /* Disable EVT and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Clear Complete callback */ + if (hi2c->hdmatx != NULL) + { + hi2c->hdmatx->XferCpltCallback = NULL; + } + if (hi2c->hdmarx != NULL) + { + hi2c->hdmarx->XferCpltCallback = NULL; + } + + if ((((uint32_t)CurrentState & (uint32_t)HAL_I2C_STATE_BUSY_TX) == (uint32_t)HAL_I2C_STATE_BUSY_TX) || ((((uint32_t)CurrentState & (uint32_t)HAL_I2C_STATE_BUSY_RX) == (uint32_t)HAL_I2C_STATE_BUSY_RX) && (CurrentMode == HAL_I2C_MODE_SLAVE))) + { + /* Disable DMA Request */ + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + hi2c->XferCount = 0U; + + if (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN) + { + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveTxCpltCallback(hi2c); +#else + HAL_I2C_SlaveTxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else if (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN) + { + /* Set state at HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_RX; + hi2c->State = HAL_I2C_STATE_LISTEN; + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->SlaveRxCpltCallback(hi2c); +#else + HAL_I2C_SlaveRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + /* Do nothing */ + } + + /* Enable EVT and ERR interrupt to treat end of transfer in IRQ handler */ + __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + } + /* Check current Mode, in case of treatment DMA handler have been preempted by a prior interrupt */ + else if (hi2c->Mode != HAL_I2C_MODE_NONE) + { + if (hi2c->XferCount == (uint16_t)1) + { + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + } + + /* Disable EVT and ERR interrupt */ + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR); + + /* Prepare next transfer or stop current transfer */ + if ((CurrentXferOptions == I2C_NO_OPTION_FRAME) || (CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_OTHER_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + } + + /* Disable Last DMA */ + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_LAST); + + /* Disable DMA Request */ + CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN); + + hi2c->XferCount = 0U; + + /* Check if Errors has been detected during transfer */ + if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) + { +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ErrorCallback(hi2c); +#else + HAL_I2C_ErrorCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + hi2c->State = HAL_I2C_STATE_READY; + + if (hi2c->Mode == HAL_I2C_MODE_MEM) + { + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->PreviousState = I2C_STATE_NONE; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MemRxCpltCallback(hi2c); +#else + HAL_I2C_MemRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + hi2c->Mode = HAL_I2C_MODE_NONE; + if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME)) + { + hi2c->PreviousState = I2C_STATE_NONE; + } + else + { + hi2c->PreviousState = I2C_STATE_MASTER_BUSY_RX; + } + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->MasterRxCpltCallback(hi2c); +#else + HAL_I2C_MasterRxCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + } + } + else + { + /* Do nothing */ + } +} + +/** + * @brief DMA I2C communication error callback. + * @param hdma DMA handle + * @retval None + */ +static void I2C_DMAError(DMA_HandleTypeDef *hdma) +{ + I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */ + + /* Clear Complete callback */ + if (hi2c->hdmatx != NULL) + { + hi2c->hdmatx->XferCpltCallback = NULL; + } + if (hi2c->hdmarx != NULL) + { + hi2c->hdmarx->XferCpltCallback = NULL; + } + + /* Ignore DMA FIFO error */ + if (HAL_DMA_GetError(hdma) != HAL_DMA_ERROR_FE) + { + /* Disable Acknowledge */ + hi2c->Instance->CR1 &= ~I2C_CR1_ACK; + + hi2c->XferCount = 0U; + + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + + hi2c->ErrorCode |= HAL_I2C_ERROR_DMA; + +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ErrorCallback(hi2c); +#else + HAL_I2C_ErrorCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } +} + +/** + * @brief DMA I2C communication abort callback + * (To be called at end of DMA Abort procedure). + * @param hdma DMA handle. + * @retval None + */ +static void I2C_DMAAbort(DMA_HandleTypeDef *hdma) +{ + __IO uint32_t count = 0U; + I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */ + + /* Declaration of temporary variable to prevent undefined behavior of volatile usage */ + HAL_I2C_StateTypeDef CurrentState = hi2c->State; + + /* During abort treatment, check that there is no pending STOP request */ + /* Wait until STOP flag is reset */ + count = I2C_TIMEOUT_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + if (count == 0U) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + break; + } + count--; + } + while (READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP); + + /* Clear Complete callback */ + if (hi2c->hdmatx != NULL) + { + hi2c->hdmatx->XferCpltCallback = NULL; + } + if (hi2c->hdmarx != NULL) + { + hi2c->hdmarx->XferCpltCallback = NULL; + } + + /* Disable Acknowledge */ + CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + hi2c->XferCount = 0U; + + /* Reset XferAbortCallback */ + if (hi2c->hdmatx != NULL) + { + hi2c->hdmatx->XferAbortCallback = NULL; + } + if (hi2c->hdmarx != NULL) + { + hi2c->hdmarx->XferAbortCallback = NULL; + } + + /* Disable I2C peripheral to prevent dummy data in buffer */ + __HAL_I2C_DISABLE(hi2c); + + /* Check if come from abort from user */ + if (hi2c->State == HAL_I2C_STATE_ABORT) + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode = HAL_I2C_ERROR_NONE; + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->AbortCpltCallback(hi2c); +#else + HAL_I2C_AbortCpltCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } + else + { + if (((uint32_t)CurrentState & (uint32_t)HAL_I2C_STATE_LISTEN) == (uint32_t)HAL_I2C_STATE_LISTEN) + { + /* Renable I2C peripheral */ + __HAL_I2C_ENABLE(hi2c); + + /* Enable Acknowledge */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); + + /* keep HAL_I2C_STATE_LISTEN */ + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_LISTEN; + } + else + { + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + } + + /* Call the corresponding callback to inform upper layer of End of Transfer */ +#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) + hi2c->ErrorCallback(hi2c); +#else + HAL_I2C_ErrorCallback(hi2c); +#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ + } +} + +/** + * @brief This function handles I2C Communication Timeout. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param Flag specifies the I2C flag to check. + * @param Status The new Flag status (SET or RESET). + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) +{ + /* Wait until flag is set */ + while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status) + { + /* Check for the Timeout */ + if (Timeout != HAL_MAX_DELAY) + { + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + { + if ((__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for Master addressing phase. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for I2C module + * @param Flag specifies the I2C flag to check. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart) +{ + while (__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET) + { + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + { + /* Generate Stop */ + SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); + + /* Clear AF Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + /* Check for the Timeout */ + if (Timeout != HAL_MAX_DELAY) + { + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + { + if ((__HAL_I2C_GET_FLAG(hi2c, Flag) == RESET)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of TXE flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) + { + /* Check if a NACK is detected */ + if (I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) + { + return HAL_ERROR; + } + + /* Check for the Timeout */ + if (Timeout != HAL_MAX_DELAY) + { + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + { + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of BTF flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) + { + /* Check if a NACK is detected */ + if (I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) + { + return HAL_ERROR; + } + + /* Check for the Timeout */ + if (Timeout != HAL_MAX_DELAY) + { + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + { + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of STOP flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) + { + /* Check if a NACK is detected */ + if (I2C_IsAcknowledgeFailed(hi2c) != HAL_OK) + { + return HAL_ERROR; + } + + /* Check for the Timeout */ + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + { + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of STOP request through Interrupt. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnSTOPRequestThroughIT(I2C_HandleTypeDef *hi2c) +{ + __IO uint32_t count = 0U; + + /* Wait until STOP flag is reset */ + count = I2C_TIMEOUT_STOP_FLAG * (SystemCoreClock / 25U / 1000U); + do + { + count--; + if (count == 0U) + { + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + return HAL_ERROR; + } + } + while (READ_BIT(hi2c->Instance->CR1, I2C_CR1_STOP) == I2C_CR1_STOP); + + return HAL_OK; +} + +/** + * @brief This function handles I2C Communication Timeout for specific usage of RXNE flag. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @param Timeout Timeout duration + * @param Tickstart Tick start value + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) +{ + + while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) + { + /* Check if a STOPF is detected */ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) + { + /* Clear STOP Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_NONE; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + + /* Check for the Timeout */ + if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U)) + { + if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET)) + { + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + } + } + return HAL_OK; +} + +/** + * @brief This function handles Acknowledge failed detection during an I2C Communication. + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval HAL status + */ +static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) +{ + if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) + { + /* Clear NACKF Flag */ + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + + hi2c->PreviousState = I2C_STATE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + + /* Process Unlocked */ + __HAL_UNLOCK(hi2c); + + return HAL_ERROR; + } + return HAL_OK; +} + +/** + * @brief Convert I2Cx OTHER_xxx XferOptions to functional XferOptions. + * @param hi2c I2C handle. + * @retval None + */ +static void I2C_ConvertOtherXferOptions(I2C_HandleTypeDef *hi2c) +{ + /* if user set XferOptions to I2C_OTHER_FRAME */ + /* it request implicitly to generate a restart condition */ + /* set XferOptions to I2C_FIRST_FRAME */ + if (hi2c->XferOptions == I2C_OTHER_FRAME) + { + hi2c->XferOptions = I2C_FIRST_FRAME; + } + /* else if user set XferOptions to I2C_OTHER_AND_LAST_FRAME */ + /* it request implicitly to generate a restart condition */ + /* then generate a stop condition at the end of transfer */ + /* set XferOptions to I2C_FIRST_AND_LAST_FRAME */ + else if (hi2c->XferOptions == I2C_OTHER_AND_LAST_FRAME) + { + hi2c->XferOptions = I2C_FIRST_AND_LAST_FRAME; + } + else + { + /* Nothing to do */ + } +} + +/** + * @} + */ + +#endif /* HAL_I2C_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + diff --git a/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c new file mode 100644 index 0000000..64aabaa --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c @@ -0,0 +1,182 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_i2c_ex.c + * @author MCD Application Team + * @brief I2C Extension HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of I2C extension peripheral: + * + Extension features functions + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2016 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + @verbatim + ============================================================================== + ##### I2C peripheral extension features ##### + ============================================================================== + + [..] Comparing to other previous devices, the I2C interface for STM32F427xx/437xx/ + 429xx/439xx devices contains the following additional features : + + (+) Possibility to disable or enable Analog Noise Filter + (+) Use of a configured Digital Noise Filter + + ##### How to use this driver ##### + ============================================================================== + [..] This driver provides functions to configure Noise Filter + (#) Configure I2C Analog noise filter using the function HAL_I2C_AnalogFilter_Config() + (#) Configure I2C Digital noise filter using the function HAL_I2C_DigitalFilter_Config() + + @endverbatim + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup I2CEx I2CEx + * @brief I2C HAL module driver + * @{ + */ + +#ifdef HAL_I2C_MODULE_ENABLED + +#if defined(I2C_FLTR_ANOFF)&&defined(I2C_FLTR_DNF) +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ +/** @defgroup I2CEx_Exported_Functions I2C Exported Functions + * @{ + */ + + +/** @defgroup I2CEx_Exported_Functions_Group1 Extension features functions + * @brief Extension features functions + * +@verbatim + =============================================================================== + ##### Extension features functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Configure Noise Filters + +@endverbatim + * @{ + */ + +/** + * @brief Configures I2C Analog noise filter. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2Cx peripheral. + * @param AnalogFilter new state of the Analog filter. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_I2C_ANALOG_FILTER(AnalogFilter)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + __HAL_I2C_DISABLE(hi2c); + + /* Reset I2Cx ANOFF bit */ + hi2c->Instance->FLTR &= ~(I2C_FLTR_ANOFF); + + /* Disable the analog filter */ + hi2c->Instance->FLTR |= AnalogFilter; + + __HAL_I2C_ENABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Configures I2C Digital noise filter. + * @param hi2c pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2Cx peripheral. + * @param DigitalFilter Coefficient of digital noise filter between 0x00 and 0x0F. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter) +{ + uint16_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); + assert_param(IS_I2C_DIGITAL_FILTER(DigitalFilter)); + + if (hi2c->State == HAL_I2C_STATE_READY) + { + hi2c->State = HAL_I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + __HAL_I2C_DISABLE(hi2c); + + /* Get the old register value */ + tmpreg = hi2c->Instance->FLTR; + + /* Reset I2Cx DNF bit [3:0] */ + tmpreg &= ~(I2C_FLTR_DNF); + + /* Set I2Cx DNF coefficient */ + tmpreg |= DigitalFilter; + + /* Store the new register value */ + hi2c->Instance->FLTR = tmpreg; + + __HAL_I2C_ENABLE(hi2c); + + hi2c->State = HAL_I2C_STATE_READY; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @} + */ + +/** + * @} + */ +#endif + +#endif /* HAL_I2C_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + diff --git a/Inc/dma.h b/Inc/dma.h new file mode 100644 index 0000000..afad30d --- /dev/null +++ b/Inc/dma.h @@ -0,0 +1,52 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file dma.h + * @brief This file contains all the function prototypes for + * the dma.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __DMA_H__ +#define __DMA_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* DMA memory to memory transfer handles -------------------------------------*/ + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_DMA_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __DMA_H__ */ + diff --git a/Inc/i2c.h b/Inc/i2c.h new file mode 100644 index 0000000..4baa02a --- /dev/null +++ b/Inc/i2c.h @@ -0,0 +1,52 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file i2c.h + * @brief This file contains all the function prototypes for + * the i2c.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __I2C_H__ +#define __I2C_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern I2C_HandleTypeDef hi2c1; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_I2C1_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __I2C_H__ */ + diff --git a/Inc/main.h b/Inc/main.h index 24b1dbf..66ba597 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -69,6 +69,20 @@ void Error_Handler(void); #define LED5_GPIO_Port GPIOF #define LED6_Pin GPIO_PIN_12 #define LED6_GPIO_Port GPIOF +#define TP_OS0_Pin GPIO_PIN_13 +#define TP_OS0_GPIO_Port GPIOF +#define TP_OS1_Pin GPIO_PIN_14 +#define TP_OS1_GPIO_Port GPIOF +#define TP_OS2_Pin GPIO_PIN_15 +#define TP_OS2_GPIO_Port GPIOF +#define DB0_Pin GPIO_PIN_0 +#define DB0_GPIO_Port GPIOG +#define DB1_Pin GPIO_PIN_1 +#define DB1_GPIO_Port GPIOG +#define ST_TX2_Pin GPIO_PIN_10 +#define ST_TX2_GPIO_Port GPIOB +#define ST_RX2_Pin GPIO_PIN_11 +#define ST_RX2_GPIO_Port GPIOB #define CH395_SCS_Pin GPIO_PIN_12 #define CH395_SCS_GPIO_Port GPIOB #define CH395F_SCK_Pin GPIO_PIN_13 @@ -77,16 +91,67 @@ void Error_Handler(void); #define CH395F_SDO_GPIO_Port GPIOB #define CH395F_SDOB15_Pin GPIO_PIN_15 #define CH395F_SDOB15_GPIO_Port GPIOB -#define ST_TX0_Pin GPIO_PIN_9 -#define ST_TX0_GPIO_Port GPIOA -#define ST_RX0_Pin GPIO_PIN_10 -#define ST_RX0_GPIO_Port GPIOA +#define DB2_Pin GPIO_PIN_2 +#define DB2_GPIO_Port GPIOG +#define DB3_Pin GPIO_PIN_3 +#define DB3_GPIO_Port GPIOG +#define DB4_Pin GPIO_PIN_4 +#define DB4_GPIO_Port GPIOG +#define DB5_Pin GPIO_PIN_5 +#define DB5_GPIO_Port GPIOG +#define DB6_Pin GPIO_PIN_6 +#define DB6_GPIO_Port GPIOG +#define DB7_Pin GPIO_PIN_7 +#define DB7_GPIO_Port GPIOG +#define DB8_Pin GPIO_PIN_8 +#define DB8_GPIO_Port GPIOG +#define ST_TX3_Pin GPIO_PIN_10 +#define ST_TX3_GPIO_Port GPIOC +#define ST_RX3_Pin GPIO_PIN_11 +#define ST_RX3_GPIO_Port GPIOC +#define ST_TX4_Pin GPIO_PIN_12 +#define ST_TX4_GPIO_Port GPIOC +#define ST_DIR4_Pin GPIO_PIN_0 +#define ST_DIR4_GPIO_Port GPIOD +#define TP_FRSTDATA_Pin GPIO_PIN_1 +#define TP_FRSTDATA_GPIO_Port GPIOD +#define ST_RX4_Pin GPIO_PIN_2 +#define ST_RX4_GPIO_Port GPIOD +#define TP_RD_Pin GPIO_PIN_3 +#define TP_RD_GPIO_Port GPIOD +#define TP_CONVST_Pin GPIO_PIN_4 +#define TP_CONVST_GPIO_Port GPIOD +#define ST_TX1_Pin GPIO_PIN_5 +#define ST_TX1_GPIO_Port GPIOD +#define ST_RX1_Pin GPIO_PIN_6 +#define ST_RX1_GPIO_Port GPIOD +#define TP_BUSY_Pin GPIO_PIN_7 +#define TP_BUSY_GPIO_Port GPIOD +#define TP_BUSY_EXTI_IRQn EXTI9_5_IRQn +#define DB9_Pin GPIO_PIN_9 +#define DB9_GPIO_Port GPIOG +#define DB10_Pin GPIO_PIN_10 +#define DB10_GPIO_Port GPIOG +#define DB11_Pin GPIO_PIN_11 +#define DB11_GPIO_Port GPIOG +#define DB12_Pin GPIO_PIN_12 +#define DB12_GPIO_Port GPIOG +#define DB13_Pin GPIO_PIN_13 +#define DB13_GPIO_Port GPIOG +#define DB14_Pin GPIO_PIN_14 +#define DB14_GPIO_Port GPIOG +#define DB15_Pin GPIO_PIN_15 +#define DB15_GPIO_Port GPIOG #define GD_SCLK_Pin GPIO_PIN_3 #define GD_SCLK_GPIO_Port GPIOB #define GD_SO_Pin GPIO_PIN_4 #define GD_SO_GPIO_Port GPIOB #define GD_SI_Pin GPIO_PIN_5 #define GD_SI_GPIO_Port GPIOB +#define SD_SCL_Pin GPIO_PIN_6 +#define SD_SCL_GPIO_Port GPIOB +#define SD_SDA_Pin GPIO_PIN_7 +#define SD_SDA_GPIO_Port GPIOB #define GD_WP_Pin GPIO_PIN_8 #define GD_WP_GPIO_Port GPIOB #define GD_CS_Pin GPIO_PIN_0 diff --git a/Inc/stm32f4xx_hal_conf.h b/Inc/stm32f4xx_hal_conf.h index 596fa96..b73be28 100644 --- a/Inc/stm32f4xx_hal_conf.h +++ b/Inc/stm32f4xx_hal_conf.h @@ -53,7 +53,7 @@ /* #define HAL_SRAM_MODULE_ENABLED */ /* #define HAL_SDRAM_MODULE_ENABLED */ /* #define HAL_HASH_MODULE_ENABLED */ -/* #define HAL_I2C_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED /* #define HAL_I2S_MODULE_ENABLED */ /* #define HAL_IWDG_MODULE_ENABLED */ /* #define HAL_LTDC_MODULE_ENABLED */ diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index ed32f27..7e5f406 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -55,6 +55,14 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); +void EXTI9_5_IRQHandler(void); +void USART1_IRQHandler(void); +void USART2_IRQHandler(void); +void USART3_IRQHandler(void); +void UART4_IRQHandler(void); +void UART5_IRQHandler(void); +void DMA2_Stream2_IRQHandler(void); +void DMA2_Stream7_IRQHandler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ diff --git a/Inc/usart.h b/Inc/usart.h index 6512dcb..f2b8e20 100644 --- a/Inc/usart.h +++ b/Inc/usart.h @@ -32,13 +32,25 @@ extern "C" { /* USER CODE END Includes */ +extern UART_HandleTypeDef huart4; + +extern UART_HandleTypeDef huart5; + extern UART_HandleTypeDef huart1; +extern UART_HandleTypeDef huart2; + +extern UART_HandleTypeDef huart3; + /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ +void MX_UART4_Init(void); +void MX_UART5_Init(void); void MX_USART1_UART_Init(void); +void MX_USART2_UART_Init(void); +void MX_USART3_UART_Init(void); /* USER CODE BEGIN Prototypes */ diff --git a/Lib/fal b/Lib/fal deleted file mode 160000 index aa02112..0000000 --- a/Lib/fal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit aa0211218634a613d3638425a830854bd07a0b76 diff --git a/MDK-ARM/STM32F407-Demo.uvprojx b/MDK-ARM/STM32F407-Demo.uvprojx index 58efc69..ac39bd6 100644 --- a/MDK-ARM/STM32F407-Demo.uvprojx +++ b/MDK-ARM/STM32F407-Demo.uvprojx @@ -1,10 +1,7 @@ - - - + + 2.1 -
### uVision Project, (C) Keil Software
- STM32F407-Demo @@ -19,28 +16,28 @@ Keil.STM32F4xx_DFP.3.1.1 https://www.keil.com/pack/ IRAM(0x20000000-0x2001BFFF) IRAM2(0x2001C000-0x2001FFFF) IROM(0x8000000-0x80FFFFF) CLOCK(25000000) FPU2 CPUTYPE("Cortex-M4") TZ - - - + + + 0 - - - - - - - - - - + + + + + + + + + + $$Device:STM32F407ZGTx$CMSIS\SVD\STM32F407.svd 0 0 - - - - - + + + + + 0 0 @@ -55,15 +52,15 @@ 1 1 1 - + 1 0 0 0 0 - - + + 0 0 0 @@ -72,8 +69,8 @@ 0 0 - - + + 0 0 0 @@ -82,15 +79,15 @@ 0 1 - - + + 0 0 0 0 1 - + 0 @@ -104,8 +101,8 @@ 0 0 3 - - + + 0 @@ -139,10 +136,10 @@ 1 BIN\UL2CM3.DLL "" () - - - - + + + + 0 @@ -175,7 +172,7 @@ 0 0 "Cortex-M4" - + 0 0 0 @@ -310,7 +307,7 @@ 0x4000 - + 1 @@ -337,10 +334,10 @@ 0 0 - + USE_HAL_DRIVER,STM32F407xx - - ../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc + + ../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485 @@ -355,10 +352,10 @@ 0 1 - - - - + + + + @@ -368,15 +365,15 @@ 0 1 0 - - - - - - - - - + + + + + + + + + @@ -405,8 +402,116 @@ ../Src/gpio.c - spi.c + dma.c 1 + ../Src/dma.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 1 + + + + + + i2c.c + 1 + ../Src/i2c.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + spi.c + 1 ../Src/spi.c @@ -421,8 +526,6 @@ 2 2 11 - - 1 @@ -450,12 +553,6 @@ 2 2 2 - - - - - - @@ -477,8 +574,6 @@ 2 2 11 - - 1 @@ -506,12 +601,6 @@ 2 2 2 - - - - - - @@ -532,9 +621,57 @@ Drivers/STM32F4xx_HAL_Driver - stm32f4xx_hal_spi.c + stm32f4xx_hal_i2c.c 1 - ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c + ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + stm32f4xx_hal_i2c_ex.c + 1 + ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c 2 @@ -548,8 +685,6 @@ 2 2 11 - - 1 @@ -577,12 +712,6 @@ 2 2 2 - - - - - - @@ -653,8 +782,56 @@ ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c - stm32f4xx_hal_uart.c + stm32f4xx_hal_spi.c 1 + ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c + + + 2 + 0 + 0 + 0 + 0 + 1 + 2 + 2 + 2 + 2 + 11 + 1 + + + + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 0 + 2 + 2 + 2 + 2 + 2 + 0 + 0 + 2 + 2 + 2 + 2 + 2 + + + + + + stm32f4xx_hal_uart.c + 1 ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c @@ -669,8 +846,6 @@ 2 2 11 - - 1 @@ -698,12 +873,6 @@ 2 2 2 - - - - - - @@ -738,6 +907,21 @@ 1 ..\Drivers\BSP\GD5F2GQ5UE\gd5f2gq5ue.c + + tpafe5160.c + 1 + ..\Drivers\BSP\TPAFE5160\tpafe5160.c + + + sd2506.c + 1 + ..\Drivers\BSP\SD2506\sd2506.c + + + rs485.c + 1 + ..\Drivers\BSP\RS485\rs485.c + @@ -786,20 +970,18 @@ - - + - + - + - + - @@ -808,5 +990,5 @@ -
+ diff --git a/STM32F407-Demo.ioc b/STM32F407-Demo.ioc index dff3b07..b388d77 100644 --- a/STM32F407-Demo.ioc +++ b/STM32F407-Demo.ioc @@ -2,51 +2,117 @@ CAD.formats= CAD.pinconfig= CAD.provider= +Dma.Request0=USART1_TX +Dma.Request1=USART1_RX +Dma.RequestsNb=2 +Dma.USART1_RX.1.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART1_RX.1.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART1_RX.1.Instance=DMA2_Stream2 +Dma.USART1_RX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_RX.1.MemInc=DMA_MINC_ENABLE +Dma.USART1_RX.1.Mode=DMA_CIRCULAR +Dma.USART1_RX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_RX.1.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_RX.1.Priority=DMA_PRIORITY_LOW +Dma.USART1_RX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART1_TX.0.Direction=DMA_MEMORY_TO_PERIPH +Dma.USART1_TX.0.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART1_TX.0.Instance=DMA2_Stream7 +Dma.USART1_TX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_TX.0.MemInc=DMA_MINC_ENABLE +Dma.USART1_TX.0.Mode=DMA_NORMAL +Dma.USART1_TX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_TX.0.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_TX.0.Priority=DMA_PRIORITY_LOW +Dma.USART1_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode File.Version=6 GPIO.groupedBy=Group By Peripherals KeepUserPlacement=false Mcu.CPN=STM32F407ZGT6 Mcu.Family=STM32F4 -Mcu.IP0=NVIC -Mcu.IP1=RCC -Mcu.IP2=SPI1 -Mcu.IP3=SPI2 -Mcu.IP4=SYS -Mcu.IP5=USART1 -Mcu.IPNb=6 +Mcu.IP0=DMA +Mcu.IP1=I2C1 +Mcu.IP10=USART2 +Mcu.IP11=USART3 +Mcu.IP2=NVIC +Mcu.IP3=RCC +Mcu.IP4=SPI1 +Mcu.IP5=SPI2 +Mcu.IP6=SYS +Mcu.IP7=UART4 +Mcu.IP8=UART5 +Mcu.IP9=USART1 +Mcu.IPNb=12 Mcu.Name=STM32F407Z(E-G)Tx Mcu.Package=LQFP144 Mcu.Pin0=PH0-OSC_IN Mcu.Pin1=PH1-OSC_OUT -Mcu.Pin10=PB14 -Mcu.Pin11=PB15 -Mcu.Pin12=PA9 -Mcu.Pin13=PA10 -Mcu.Pin14=PA13 -Mcu.Pin15=PA14 -Mcu.Pin16=PB3 -Mcu.Pin17=PB4 -Mcu.Pin18=PB5 -Mcu.Pin19=PB8 +Mcu.Pin10=PF15 +Mcu.Pin11=PG0 +Mcu.Pin12=PG1 +Mcu.Pin13=PB10 +Mcu.Pin14=PB11 +Mcu.Pin15=PB12 +Mcu.Pin16=PB13 +Mcu.Pin17=PB14 +Mcu.Pin18=PB15 +Mcu.Pin19=PG2 Mcu.Pin2=PC4 -Mcu.Pin20=PE0 -Mcu.Pin21=PE1 -Mcu.Pin22=VP_SYS_VS_Systick +Mcu.Pin20=PG3 +Mcu.Pin21=PG4 +Mcu.Pin22=PG5 +Mcu.Pin23=PG6 +Mcu.Pin24=PG7 +Mcu.Pin25=PG8 +Mcu.Pin26=PA9 +Mcu.Pin27=PA10 +Mcu.Pin28=PA13 +Mcu.Pin29=PA14 Mcu.Pin3=PC5 +Mcu.Pin30=PC10 +Mcu.Pin31=PC11 +Mcu.Pin32=PC12 +Mcu.Pin33=PD0 +Mcu.Pin34=PD1 +Mcu.Pin35=PD2 +Mcu.Pin36=PD3 +Mcu.Pin37=PD4 +Mcu.Pin38=PD5 +Mcu.Pin39=PD6 Mcu.Pin4=PB1 +Mcu.Pin40=PD7 +Mcu.Pin41=PG9 +Mcu.Pin42=PG10 +Mcu.Pin43=PG11 +Mcu.Pin44=PG12 +Mcu.Pin45=PG13 +Mcu.Pin46=PG14 +Mcu.Pin47=PG15 +Mcu.Pin48=PB3 +Mcu.Pin49=PB4 Mcu.Pin5=PB2 +Mcu.Pin50=PB5 +Mcu.Pin51=PB6 +Mcu.Pin52=PB7 +Mcu.Pin53=PB8 +Mcu.Pin54=PE0 +Mcu.Pin55=PE1 +Mcu.Pin56=VP_SYS_VS_Systick Mcu.Pin6=PF11 Mcu.Pin7=PF12 -Mcu.Pin8=PB12 -Mcu.Pin9=PB13 -Mcu.PinsNb=23 +Mcu.Pin8=PF13 +Mcu.Pin9=PF14 +Mcu.PinsNb=57 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F407ZGTx MxCube.Version=6.17.0 MxDb.Version=DB.6.0.170 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.DMA2_Stream2_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream7_IRQn=true\:3\:0\:true\:false\:true\:false\:true\:true NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.EXTI9_5_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false @@ -55,18 +121,26 @@ NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.UART4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true +NVIC.UART5_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true +NVIC.USART1_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true +NVIC.USART2_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true +NVIC.USART3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -PA10.GPIOParameters=GPIO_PuPd,GPIO_Label -PA10.GPIO_Label=ST_RX0 -PA10.GPIO_PuPd=GPIO_PULLUP +PA10.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd +PA10.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP +PA10.GPIO_PuPd=GPIO_NOPULL +PA10.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH PA10.Mode=Asynchronous PA10.Signal=USART1_RX PA13.Mode=Serial_Wire PA13.Signal=SYS_JTMS-SWDIO PA14.Mode=Serial_Wire PA14.Signal=SYS_JTCK-SWCLK -PA9.GPIOParameters=GPIO_Label -PA9.GPIO_Label=ST_TX0 +PA9.GPIOParameters=GPIO_ModeDefaultPP,GPIO_Speed,GPIO_PuPd +PA9.GPIO_ModeDefaultPP=GPIO_MODE_AF_PP +PA9.GPIO_PuPd=GPIO_NOPULL +PA9.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH PA9.Mode=Asynchronous PA9.Signal=USART1_TX PB1.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label @@ -76,6 +150,16 @@ PB1.GPIO_Speed=GPIO_SPEED_FREQ_HIGH PB1.Locked=true PB1.PinState=GPIO_PIN_SET PB1.Signal=GPIO_Output +PB10.GPIOParameters=GPIO_Label +PB10.GPIO_Label=ST_TX2 +PB10.Locked=true +PB10.Mode=Asynchronous +PB10.Signal=USART3_TX +PB11.GPIOParameters=GPIO_Label +PB11.GPIO_Label=ST_RX2 +PB11.Locked=true +PB11.Mode=Asynchronous +PB11.Signal=USART3_RX PB12.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label PB12.GPIO_Label=CH395_SCS PB12.GPIO_PuPd=GPIO_NOPULL @@ -124,6 +208,16 @@ PB5.GPIO_PuPd=GPIO_PULLUP PB5.Locked=true PB5.Mode=Full_Duplex_Master PB5.Signal=SPI1_MOSI +PB6.GPIOParameters=GPIO_Label +PB6.GPIO_Label=SD_SCL +PB6.Locked=true +PB6.Mode=I2C +PB6.Signal=I2C1_SCL +PB7.GPIOParameters=GPIO_Label +PB7.GPIO_Label=SD_SDA +PB7.Locked=true +PB7.Mode=I2C +PB7.Signal=I2C1_SDA PB8.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label PB8.GPIO_Label=GD_WP PB8.GPIO_PuPd=GPIO_PULLUP @@ -131,6 +225,21 @@ PB8.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH PB8.Locked=true PB8.PinState=GPIO_PIN_SET PB8.Signal=GPIO_Output +PC10.GPIOParameters=GPIO_Label +PC10.GPIO_Label=ST_TX3 +PC10.Locked=true +PC10.Mode=Asynchronous +PC10.Signal=UART4_TX +PC11.GPIOParameters=GPIO_Label +PC11.GPIO_Label=ST_RX3 +PC11.Locked=true +PC11.Mode=Asynchronous +PC11.Signal=UART4_RX +PC12.GPIOParameters=GPIO_Label +PC12.GPIO_Label=ST_TX4 +PC12.Locked=true +PC12.Mode=Asynchronous +PC12.Signal=UART5_TX PC4.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label PC4.GPIO_Label=LED1 PC4.GPIO_PuPd=GPIO_PULLUP @@ -153,6 +262,45 @@ PCC.PartNumber=STM32F407ZGTx PCC.Series=STM32F4 PCC.Temperature=25 PCC.Vdd=3.3 +PD0.GPIOParameters=GPIO_PuPd,GPIO_Label +PD0.GPIO_Label=ST_DIR4 +PD0.GPIO_PuPd=GPIO_NOPULL +PD0.Locked=true +PD0.Signal=GPIO_Output +PD1.GPIOParameters=GPIO_Label +PD1.GPIO_Label=TP_FRSTDATA +PD1.Locked=true +PD1.Signal=GPIO_Input +PD2.GPIOParameters=GPIO_Label +PD2.GPIO_Label=ST_RX4 +PD2.Mode=Asynchronous +PD2.Signal=UART5_RX +PD3.GPIOParameters=GPIO_Speed,PinState,GPIO_Label +PD3.GPIO_Label=TP_RD +PD3.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PD3.Locked=true +PD3.PinState=GPIO_PIN_SET +PD3.Signal=GPIO_Output +PD4.GPIOParameters=GPIO_Speed,GPIO_Label +PD4.GPIO_Label=TP_CONVST +PD4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PD4.Locked=true +PD4.Signal=GPIO_Output +PD5.GPIOParameters=GPIO_Label +PD5.GPIO_Label=ST_TX1 +PD5.Locked=true +PD5.Mode=Asynchronous +PD5.Signal=USART2_TX +PD6.GPIOParameters=GPIO_Label +PD6.GPIO_Label=ST_RX1 +PD6.Locked=true +PD6.Mode=Asynchronous +PD6.Signal=USART2_RX +PD7.GPIOParameters=GPIO_Label,GPIO_ModeDefaultEXTI +PD7.GPIO_Label=TP_BUSY +PD7.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PD7.Locked=true +PD7.Signal=GPXTI7 PE0.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label PE0.GPIO_Label=GD_CS PE0.GPIO_PuPd=GPIO_PULLUP @@ -181,6 +329,85 @@ PF12.GPIO_Speed=GPIO_SPEED_FREQ_HIGH PF12.Locked=true PF12.PinState=GPIO_PIN_SET PF12.Signal=GPIO_Output +PF13.GPIOParameters=GPIO_Speed,GPIO_Label +PF13.GPIO_Label=TP_OS0 +PF13.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PF13.Locked=true +PF13.Signal=GPIO_Output +PF14.GPIOParameters=GPIO_Speed,GPIO_Label +PF14.GPIO_Label=TP_OS1 +PF14.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PF14.Locked=true +PF14.Signal=GPIO_Output +PF15.GPIOParameters=GPIO_Speed,GPIO_Label +PF15.GPIO_Label=TP_OS2 +PF15.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PF15.Locked=true +PF15.Signal=GPIO_Output +PG0.GPIOParameters=GPIO_Label +PG0.GPIO_Label=DB0 +PG0.Locked=true +PG0.Signal=GPIO_Input +PG1.GPIOParameters=GPIO_Label +PG1.GPIO_Label=DB1 +PG1.Locked=true +PG1.Signal=GPIO_Input +PG10.GPIOParameters=GPIO_Label +PG10.GPIO_Label=DB10 +PG10.Locked=true +PG10.Signal=GPIO_Input +PG11.GPIOParameters=GPIO_Label +PG11.GPIO_Label=DB11 +PG11.Locked=true +PG11.Signal=GPIO_Input +PG12.GPIOParameters=GPIO_Label +PG12.GPIO_Label=DB12 +PG12.Locked=true +PG12.Signal=GPIO_Input +PG13.GPIOParameters=GPIO_Label +PG13.GPIO_Label=DB13 +PG13.Locked=true +PG13.Signal=GPIO_Input +PG14.GPIOParameters=GPIO_Label +PG14.GPIO_Label=DB14 +PG14.Locked=true +PG14.Signal=GPIO_Input +PG15.GPIOParameters=GPIO_Label +PG15.GPIO_Label=DB15 +PG15.Locked=true +PG15.Signal=GPIO_Input +PG2.GPIOParameters=GPIO_Label +PG2.GPIO_Label=DB2 +PG2.Locked=true +PG2.Signal=GPIO_Input +PG3.GPIOParameters=GPIO_Label +PG3.GPIO_Label=DB3 +PG3.Locked=true +PG3.Signal=GPIO_Input +PG4.GPIOParameters=GPIO_Label +PG4.GPIO_Label=DB4 +PG4.Locked=true +PG4.Signal=GPIO_Input +PG5.GPIOParameters=GPIO_Label +PG5.GPIO_Label=DB5 +PG5.Locked=true +PG5.Signal=GPIO_Input +PG6.GPIOParameters=GPIO_Label +PG6.GPIO_Label=DB6 +PG6.Locked=true +PG6.Signal=GPIO_Input +PG7.GPIOParameters=GPIO_Label +PG7.GPIO_Label=DB7 +PG7.Locked=true +PG7.Signal=GPIO_Input +PG8.GPIOParameters=GPIO_Label +PG8.GPIO_Label=DB8 +PG8.Locked=true +PG8.Signal=GPIO_Input +PG9.GPIOParameters=GPIO_Label +PG9.GPIO_Label=DB9 +PG9.Locked=true +PG9.Signal=GPIO_Input PH0-OSC_IN.Mode=HSE-External-Oscillator PH0-OSC_IN.Signal=RCC_OSC_IN PH1-OSC_OUT.Mode=HSE-External-Oscillator @@ -218,7 +445,7 @@ ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_USART1_UART_Init-USART1-false-HAL-true,4-MX_SPI2_Init-SPI2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART1_UART_Init-USART1-false-HAL-true,5-MX_SPI2_Init-SPI2-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_I2C1_Init-I2C1-false-HAL-true,8-MX_UART4_Init-UART4-false-HAL-true,9-MX_UART5_Init-UART5-false-HAL-true,10-MX_USART2_UART_Init-USART2-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true RCC.48MHZClocksFreq_Value=84000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 @@ -252,6 +479,8 @@ RCC.VCOI2SOutputFreq_Value=384000000 RCC.VCOInputFreq_Value=2000000 RCC.VCOOutputFreq_Value=336000000 RCC.VcooutputI2S=192000000 +SH.GPXTI7.0=GPIO_EXTI7 +SH.GPXTI7.ConfNb=1 SPI1.CalculateBaudRate=42.0 MBits/s SPI1.Direction=SPI_DIRECTION_2LINES SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate @@ -262,8 +491,16 @@ SPI2.Direction=SPI_DIRECTION_2LINES SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate SPI2.Mode=SPI_MODE_MASTER SPI2.VirtualType=VM_MASTER +UART4.IPParameters=VirtualMode +UART4.VirtualMode=Asynchronous +UART5.IPParameters=VirtualMode +UART5.VirtualMode=Asynchronous USART1.IPParameters=VirtualMode USART1.VirtualMode=VM_ASYNC +USART2.IPParameters=VirtualMode +USART2.VirtualMode=VM_ASYNC +USART3.IPParameters=VirtualMode +USART3.VirtualMode=VM_ASYNC VP_SYS_VS_Systick.Mode=SysTick VP_SYS_VS_Systick.Signal=SYS_VS_Systick board=custom diff --git a/Src/dma.c b/Src/dma.c new file mode 100644 index 0000000..67a3016 --- /dev/null +++ b/Src/dma.c @@ -0,0 +1,58 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file dma.c + * @brief This file provides code for the configuration + * of all the requested memory to memory DMA transfers. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "dma.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/*----------------------------------------------------------------------------*/ +/* Configure DMA */ +/*----------------------------------------------------------------------------*/ + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** + * Enable DMA controller clock + */ +void MX_DMA_Init(void) +{ + + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA2_Stream2_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); + /* DMA2_Stream7_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn); + +} + +/* USER CODE BEGIN 2 */ + +/* USER CODE END 2 */ + diff --git a/Src/gpio.c b/Src/gpio.c index d443ff3..2ba48eb 100644 --- a/Src/gpio.c +++ b/Src/gpio.c @@ -49,7 +49,9 @@ void MX_GPIO_Init(void) __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); /*Configure GPIO pin Output Level */ @@ -61,6 +63,15 @@ void MX_GPIO_Init(void) /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOF, LED5_Pin|LED6_Pin, GPIO_PIN_SET); + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOF, TP_OS0_Pin|TP_OS1_Pin|TP_OS2_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOD, ST_DIR4_Pin|TP_CONVST_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_SET); + /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOE, GD_CS_Pin|GD_HOLD_Pin, GPIO_PIN_SET); @@ -85,6 +96,25 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); + /*Configure GPIO pins : TP_OS0_Pin TP_OS1_Pin TP_OS2_Pin */ + GPIO_InitStruct.Pin = TP_OS0_Pin|TP_OS1_Pin|TP_OS2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + /*Configure GPIO pins : DB0_Pin DB1_Pin DB2_Pin DB3_Pin + DB4_Pin DB5_Pin DB6_Pin DB7_Pin + DB8_Pin DB9_Pin DB10_Pin DB11_Pin + DB12_Pin DB13_Pin DB14_Pin DB15_Pin */ + GPIO_InitStruct.Pin = DB0_Pin|DB1_Pin|DB2_Pin|DB3_Pin + |DB4_Pin|DB5_Pin|DB6_Pin|DB7_Pin + |DB8_Pin|DB9_Pin|DB10_Pin|DB11_Pin + |DB12_Pin|DB13_Pin|DB14_Pin|DB15_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + /*Configure GPIO pin : CH395_SCS_Pin */ GPIO_InitStruct.Pin = CH395_SCS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; @@ -92,6 +122,32 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(CH395_SCS_GPIO_Port, &GPIO_InitStruct); + /*Configure GPIO pin : ST_DIR4_Pin */ + GPIO_InitStruct.Pin = ST_DIR4_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(ST_DIR4_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : TP_FRSTDATA_Pin */ + GPIO_InitStruct.Pin = TP_FRSTDATA_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(TP_FRSTDATA_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : TP_RD_Pin TP_CONVST_Pin */ + GPIO_InitStruct.Pin = TP_RD_Pin|TP_CONVST_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /*Configure GPIO pin : TP_BUSY_Pin */ + GPIO_InitStruct.Pin = TP_BUSY_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(TP_BUSY_GPIO_Port, &GPIO_InitStruct); + /*Configure GPIO pin : GD_WP_Pin */ GPIO_InitStruct.Pin = GD_WP_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; @@ -106,6 +162,10 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); + /* EXTI interrupt init*/ + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2, 0); + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); + } /* USER CODE BEGIN 2 */ diff --git a/Src/i2c.c b/Src/i2c.c new file mode 100644 index 0000000..15e409b --- /dev/null +++ b/Src/i2c.c @@ -0,0 +1,117 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file i2c.c + * @brief This file provides code for the configuration + * of the I2C instances. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "i2c.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +I2C_HandleTypeDef hi2c1; + +/* I2C1 init function */ +void MX_I2C1_Init(void) +{ + + /* USER CODE BEGIN I2C1_Init 0 */ + + /* USER CODE END I2C1_Init 0 */ + + /* USER CODE BEGIN I2C1_Init 1 */ + + /* USER CODE END I2C1_Init 1 */ + hi2c1.Instance = I2C1; + hi2c1.Init.ClockSpeed = 100000; + hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; + hi2c1.Init.OwnAddress1 = 0; + hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c1.Init.OwnAddress2 = 0; + hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + if (HAL_I2C_Init(&hi2c1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN I2C1_Init 2 */ + + /* USER CODE END I2C1_Init 2 */ + +} + +void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(i2cHandle->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspInit 0 */ + + /* USER CODE END I2C1_MspInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**I2C1 GPIO Configuration + PB6 ------> I2C1_SCL + PB7 ------> I2C1_SDA + */ + GPIO_InitStruct.Pin = SD_SCL_Pin|SD_SDA_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* I2C1 clock enable */ + __HAL_RCC_I2C1_CLK_ENABLE(); + /* USER CODE BEGIN I2C1_MspInit 1 */ + + /* USER CODE END I2C1_MspInit 1 */ + } +} + +void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle) +{ + + if(i2cHandle->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspDeInit 0 */ + + /* USER CODE END I2C1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_I2C1_CLK_DISABLE(); + + /**I2C1 GPIO Configuration + PB6 ------> I2C1_SCL + PB7 ------> I2C1_SDA + */ + HAL_GPIO_DeInit(SD_SCL_GPIO_Port, SD_SCL_Pin); + + HAL_GPIO_DeInit(SD_SDA_GPIO_Port, SD_SDA_Pin); + + /* USER CODE BEGIN I2C1_MspDeInit 1 */ + + /* USER CODE END I2C1_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + diff --git a/Src/main.c b/Src/main.c index 7d36aea..07c8d5e 100644 --- a/Src/main.c +++ b/Src/main.c @@ -18,6 +18,8 @@ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" +#include "dma.h" +#include "i2c.h" #include "spi.h" #include "usart.h" #include "gpio.h" @@ -28,7 +30,9 @@ #include #include "ch395f.h" #include "gd5f2gq5ue.h" -#include "flashdb.h" +#include "tpafe5160.h" +#include "sd2506.h" +#include "rs485.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -49,7 +53,10 @@ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ - +/* RS-485 通信实例(UART5: PC12=TX, PD2=RX, PD0=DE) */ +rs485_handle_t g_rs485; +#define RS485_RX_BUF_SIZE 256 +uint8_t g_rs485_rx_buf[RS485_RX_BUF_SIZE]; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ @@ -71,7 +78,6 @@ int main(void) { /* USER CODE BEGIN 1 */ - uint8_t str[] = "Hello World\n"; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ @@ -92,95 +98,123 @@ int main(void) /* Initialize all configured peripherals */ MX_GPIO_Init(); + MX_DMA_Init(); MX_USART1_UART_Init(); MX_SPI2_Init(); MX_SPI1_Init(); + MX_I2C1_Init(); + MX_UART4_Init(); + MX_UART5_Init(); + MX_USART2_UART_Init(); + MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ - char dbg[64]; - uint8_t mac[6]; + HAL_Delay(100); - ch395f_reset(); + /* CH395F 硬件检测 */ + ch395f_status_t ch395f_ret = ch395f_check_exist(); + printf("[CH395F] SPI: %s\r\n", + (ch395f_ret == CH395F_STATUS_OK) ? "OK" : "FAIL"); - /* [1/5] SPI 通信检测 */ - sprintf(dbg, "[1/5] CH395F %s\r\n", - (ch395f_check_exist() == CH395F_STATUS_OK) ? "detected" : "ERROR: not detected"); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); + printf("[CH395F] version: 0x%02X\r\n", ch395f_get_version()); - /* [2/5] 芯片版本 */ - sprintf(dbg, "[2/5] CH395F version: 0x%02X\r\n", ch395f_get_version()); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); + if (ch395f_ret == CH395F_STATUS_OK) { + /* 1. 复位 */ + ch395f_reset(); - /* 配置 IP/网关/掩码 */ - { + /* 2. 配置网络参数(必须在 INIT 之前,INIT 会锁定协议栈参数) */ uint8_t ip[4] = {192, 168, 1, 100}; uint8_t gw[4] = {192, 168, 1, 1}; uint8_t mask[4] = {255, 255, 255, 0}; ch395f_set_ip_addr(ip); ch395f_set_gwip_addr(gw); ch395f_set_mask_addr(mask); - } - /* [3/5] 协议栈初始化 */ - sprintf(dbg, "[3/5] Protocol stack init %s\r\n", - (ch395f_init() == CH395F_STATUS_OK) ? "OK" : "ERROR"); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); + /* 3. 初始化协议栈(锁定 IP/GW/MASK 等参数) */ + printf("[CH395F] init: %s\r\n", + (ch395f_init() == CH395F_STATUS_OK) ? "OK" : "FAIL"); - /* [4/5] MAC 地址 */ - ch395f_get_mac_addr(mac); - sprintf(dbg, "[4/5] MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); + /* 4. 读取 MAC */ + uint8_t mac[6]; + ch395f_get_mac_addr(mac); + printf("[CH395F] MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - /* [5/5] 强制 100M 全双工后检测 PHY */ - ch395f_set_phy(CH395F_PHY_100M_FULL); - HAL_Delay(3000); - { - uint8_t s = ch395f_get_phy_status(); - const char *desc = (s == CH395F_PHY_DISCONN) ? "DISCONNECTED" : - (s == CH395F_PHY_100M_FULL) ? "100M FULL" : - (s == CH395F_PHY_100M_HALF) ? "100M HALF" : - (s == CH395F_PHY_10M_FULL) ? "10M FULL" : - (s == CH395F_PHY_10M_HALF) ? "10M HALF" : "RESERVED"; - sprintf(dbg, "[5/5] PHY: 0x%02X (%s)\r\n", s, desc); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); - } - - /* ===================== FlashDB KVDB 测试 ===================== */ - { - uint8_t gd_mid, gd_did; - int ret; - - /* 检测 GD5F2GQ5UE */ - ret = gd5f2gq5ue_read_id(&gd_mid, &gd_did); - sprintf(dbg, "[GD5F] ID: MID=0x%02X DID=0x%02X %s\r\n", - gd_mid, gd_did, - (ret == GD5F_OK && gd_mid == 0xC8 && gd_did == 0x52) ? "OK" : "FAIL"); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); - - /* 初始化 FlashDB KVDB */ - { - static struct fdb_kvdb kvdb; - ret = fdb_kvdb_init(&kvdb, "db", "fdb_kvdb1", NULL, NULL); - sprintf(dbg, "[FlashDB] KVDB init: %s\r\n", - (ret == FDB_NO_ERR) ? "OK" : "FAIL"); - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); - - if (ret == FDB_NO_ERR) { - /* 写入测试 KV */ - fdb_kv_set(&kvdb, "test_key", "hello_flashdb"); - HAL_UART_Transmit(&huart1, (uint8_t*)"[FlashDB] KV set OK\r\n", 21, 1000); - - /* 读取测试 KV */ - char *val = fdb_kv_get(&kvdb, "test_key"); - if (val) { - sprintf(dbg, "[FlashDB] KV get: %s\r\n", val); - } else { - sprintf(dbg, "[FlashDB] KV get: NULL\r\n"); - } - HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000); - } + /* 5. 强制 100M 全双工,建立 PHY 链路 */ + ch395f_set_phy(CH395F_PHY_100M_FULL); + HAL_Delay(3000); + uint8_t phy = ch395f_get_phy_status(); + const char *phy_str = "UNKNOWN"; + switch (phy) { + case CH395F_PHY_DISCONN: phy_str = "DISCONNECT"; break; + case CH395F_PHY_10M_FULL: phy_str = "10M FULL"; break; + case CH395F_PHY_10M_HALF: phy_str = "10M HALF"; break; + case CH395F_PHY_100M_FULL: phy_str = "100M FULL"; break; + case CH395F_PHY_100M_HALF: phy_str = "100M HALF"; break; } + printf("[CH395F] PHY: %s\r\n", phy_str); } + + /* GD5F 初始化测试 */ + int ret = gd5f2gq5ue_init(); + const char *gd5f_str = "UNKNOWN"; + switch (ret) { + case GD5F_OK: gd5f_str = "OK"; break; + case GD5F_ERROR: gd5f_str = "ERROR"; break; + case GD5F_BUSY_TIMEOUT: gd5f_str = "BUSY TIMEOUT"; break; + case GD5F_ECC_ERROR: gd5f_str = "ECC ERROR"; break; + case GD5F_PROGRAM_FAIL: gd5f_str = "PROGRAM FAIL"; break; + case GD5F_ERASE_FAIL: gd5f_str = "ERASE FAIL"; break; + case GD5F_ID_MISMATCH: gd5f_str = "ID MISMATCH"; break; + } + printf("[GD5F] init: %s\r\n", gd5f_str); + + /* TPAFE5160 ADC 测试 */ + int tp_ret = tpafe5160_init(); + printf("[TPAFE5160] init: %s\r\n", + (tp_ret == TPAFE5160_OK) ? "OK" : "TIMEOUT"); + + /* SD2506 RTC 初始化测试 */ + int sd_ret = sd2506_init(); + printf("[SD2506] init: %s\r\n", + (sd_ret == SD2506_OK) ? "OK" : "I2C ERROR"); + + if (sd_ret == SD2506_OK) { + /* 读取 ID */ + uint8_t sd_id[8]; + sd2506_get_id(sd_id); + printf("[SD2506] ID: %02X%02X%02X%02X%02X%02X%02X%02X\r\n", + sd_id[0], sd_id[1], sd_id[2], sd_id[3], + sd_id[4], sd_id[5], sd_id[6], sd_id[7]); + + /* 读取当前时间 */ + sd2506_time_t sd_time; + sd2506_get_time(&sd_time); + printf("[SD2506] time: %04d-%02d-%02d %02d:%02d:%02d (week %d)\r\n", + sd_time.year, sd_time.month, sd_time.day, + sd_time.hour, sd_time.minute, sd_time.second, + sd_time.week); + + /* 读取温度 */ + int8_t sd_temp; + sd2506_get_temperature(&sd_temp); + printf("[SD2506] temp: %d C\r\n", sd_temp); + + /* 读取电池电压 */ + uint16_t sd_vbat; + sd2506_get_battery_voltage(&sd_vbat); + printf("[SD2506] battery: %d.%02d V\r\n", + sd_vbat / 1000, (sd_vbat % 1000) / 10); + } + + /* RS-485 初始化(UART5 + PD0 方向控制) */ + rs485_init(&g_rs485, &huart5, ST_DIR4_GPIO_Port, ST_DIR4_Pin); + printf("[RS485] init: OK (UART5, DE=PD0)\r\n"); + + /* 启动第一次 RS-485 接收 */ + rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE); + + /* 启动第一次转换(CubeMX 已配置 BUSY EXTI 中断) */ + tpafe5160_start_conv_irq(); /* USER CODE END 2 */ /* Infinite loop */ @@ -190,13 +224,21 @@ int main(void) /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ + /* TPAFE5160 中断模式读取 */ + if (tpafe5160_data_ready()) { + const int16_t *buf = tpafe5160_get_buf(); + printf("[TPAFE5160] CH:"); + for (int i = 0; i < 8; i++) { + printf(" %d", buf[i]); + } + printf("\r\n"); + tpafe5160_clear_ready(); + /* 启动下一次转换 */ + tpafe5160_start_conv_irq(); + } + + /* 其他任务 */ HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); - HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin); - HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin); - HAL_GPIO_TogglePin(LED4_GPIO_Port, LED4_Pin); - HAL_GPIO_TogglePin(LED5_GPIO_Port, LED5_Pin); - HAL_GPIO_TogglePin(LED6_GPIO_Port, LED6_Pin); - //HAL_UART_Transmit(&huart1, str, strlen((char*)str), 1000); HAL_Delay(500); } /* USER CODE END 3 */ @@ -248,7 +290,38 @@ void SystemClock_Config(void) } /* USER CODE BEGIN 4 */ +/* + * HAL UART 扩展接收回调(IDLE 空闲帧中断触发) + * 当 RS-485 总线空闲超过 1 个字符时间后触发 + */ +void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) +{ + if (huart->Instance == UART5) { + rs485_rx_set_size(&g_rs485, Size); + /* TODO: 在此处处理接收到的 RS-485 数据 + * g_rs485_rx_buf[0 .. Size-1] 为有效数据 + * 例如:rs485_transmit(&g_rs485, g_rs485_rx_buf, Size, 0); + */ + + /* 重新开启接收 */ + rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE); + } +} + +/* + * HAL UART 错误回调 + */ +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == UART5) { + /* STM32F4 通过读 SR + DR 清除 ORE/NE/FE/PE 错误标志 */ + (void)huart->Instance->SR; + (void)huart->Instance->DR; + /* 重新开启接收 */ + rs485_receive_start(&g_rs485, g_rs485_rx_buf, RS485_RX_BUF_SIZE); + } +} /* USER CODE END 4 */ /** diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index 6a1bd00..a61978f 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -55,7 +55,13 @@ /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ - +extern DMA_HandleTypeDef hdma_usart1_tx; +extern DMA_HandleTypeDef hdma_usart1_rx; +extern UART_HandleTypeDef huart4; +extern UART_HandleTypeDef huart5; +extern UART_HandleTypeDef huart1; +extern UART_HandleTypeDef huart2; +extern UART_HandleTypeDef huart3; /* USER CODE BEGIN EV */ /* USER CODE END EV */ @@ -198,6 +204,118 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32f4xx.s). */ /******************************************************************************/ +/** + * @brief This function handles EXTI line[9:5] interrupts. + */ +void EXTI9_5_IRQHandler(void) +{ + /* USER CODE BEGIN EXTI9_5_IRQn 0 */ + + /* USER CODE END EXTI9_5_IRQn 0 */ + HAL_GPIO_EXTI_IRQHandler(TP_BUSY_Pin); + /* USER CODE BEGIN EXTI9_5_IRQn 1 */ + + /* USER CODE END EXTI9_5_IRQn 1 */ +} + +/** + * @brief This function handles USART1 global interrupt. + */ +void USART1_IRQHandler(void) +{ + /* USER CODE BEGIN USART1_IRQn 0 */ + + /* USER CODE END USART1_IRQn 0 */ + HAL_UART_IRQHandler(&huart1); + /* USER CODE BEGIN USART1_IRQn 1 */ + + /* USER CODE END USART1_IRQn 1 */ +} + +/** + * @brief This function handles USART2 global interrupt. + */ +void USART2_IRQHandler(void) +{ + /* USER CODE BEGIN USART2_IRQn 0 */ + + /* USER CODE END USART2_IRQn 0 */ + HAL_UART_IRQHandler(&huart2); + /* USER CODE BEGIN USART2_IRQn 1 */ + + /* USER CODE END USART2_IRQn 1 */ +} + +/** + * @brief This function handles USART3 global interrupt. + */ +void USART3_IRQHandler(void) +{ + /* USER CODE BEGIN USART3_IRQn 0 */ + + /* USER CODE END USART3_IRQn 0 */ + HAL_UART_IRQHandler(&huart3); + /* USER CODE BEGIN USART3_IRQn 1 */ + + /* USER CODE END USART3_IRQn 1 */ +} + +/** + * @brief This function handles UART4 global interrupt. + */ +void UART4_IRQHandler(void) +{ + /* USER CODE BEGIN UART4_IRQn 0 */ + + /* USER CODE END UART4_IRQn 0 */ + HAL_UART_IRQHandler(&huart4); + /* USER CODE BEGIN UART4_IRQn 1 */ + + /* USER CODE END UART4_IRQn 1 */ +} + +/** + * @brief This function handles UART5 global interrupt. + */ +void UART5_IRQHandler(void) +{ + /* USER CODE BEGIN UART5_IRQn 0 */ + + /* USER CODE END UART5_IRQn 0 */ + HAL_UART_IRQHandler(&huart5); + /* USER CODE BEGIN UART5_IRQn 1 */ + + /* USER CODE END UART5_IRQn 1 */ +} + +/** + * @brief This function handles DMA2 stream2 global interrupt. + */ +void DMA2_Stream2_IRQHandler(void) +{ + /* USER CODE BEGIN DMA2_Stream2_IRQn 0 */ + + /* USER CODE END DMA2_Stream2_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_usart1_rx); + /* USER CODE BEGIN DMA2_Stream2_IRQn 1 */ + + /* USER CODE END DMA2_Stream2_IRQn 1 */ +} + +/** + * @brief This function handles DMA2 stream7 global interrupt. + */ +void DMA2_Stream7_IRQHandler(void) +{ + /* USER CODE BEGIN DMA2_Stream7_IRQn 0 */ + + /* USER CODE END DMA2_Stream7_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_usart1_tx); + /* USER CODE BEGIN DMA2_Stream7_IRQn 1 */ + + /* USER CODE END DMA2_Stream7_IRQn 1 */ +} + /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ diff --git a/Src/usart.c b/Src/usart.c index 8f39ae7..38b3f8b 100644 --- a/Src/usart.c +++ b/Src/usart.c @@ -24,8 +24,70 @@ /* USER CODE END 0 */ +UART_HandleTypeDef huart4; +UART_HandleTypeDef huart5; UART_HandleTypeDef huart1; +UART_HandleTypeDef huart2; +UART_HandleTypeDef huart3; +DMA_HandleTypeDef hdma_usart1_tx; +DMA_HandleTypeDef hdma_usart1_rx; +/* UART4 init function */ +void MX_UART4_Init(void) +{ + + /* USER CODE BEGIN UART4_Init 0 */ + + /* USER CODE END UART4_Init 0 */ + + /* USER CODE BEGIN UART4_Init 1 */ + + /* USER CODE END UART4_Init 1 */ + huart4.Instance = UART4; + huart4.Init.BaudRate = 115200; + huart4.Init.WordLength = UART_WORDLENGTH_8B; + huart4.Init.StopBits = UART_STOPBITS_1; + huart4.Init.Parity = UART_PARITY_NONE; + huart4.Init.Mode = UART_MODE_TX_RX; + huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart4.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart4) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN UART4_Init 2 */ + + /* USER CODE END UART4_Init 2 */ + +} +/* UART5 init function */ +void MX_UART5_Init(void) +{ + + /* USER CODE BEGIN UART5_Init 0 */ + + /* USER CODE END UART5_Init 0 */ + + /* USER CODE BEGIN UART5_Init 1 */ + + /* USER CODE END UART5_Init 1 */ + huart5.Instance = UART5; + huart5.Init.BaudRate = 115200; + huart5.Init.WordLength = UART_WORDLENGTH_8B; + huart5.Init.StopBits = UART_STOPBITS_1; + huart5.Init.Parity = UART_PARITY_NONE; + huart5.Init.Mode = UART_MODE_TX_RX; + huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart5.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart5) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN UART5_Init 2 */ + + /* USER CODE END UART5_Init 2 */ + +} /* USART1 init function */ void MX_USART1_UART_Init(void) @@ -54,13 +116,133 @@ void MX_USART1_UART_Init(void) /* USER CODE END USART1_Init 2 */ +} +/* USART2 init function */ + +void MX_USART2_UART_Init(void) +{ + + /* USER CODE BEGIN USART2_Init 0 */ + + /* USER CODE END USART2_Init 0 */ + + /* USER CODE BEGIN USART2_Init 1 */ + + /* USER CODE END USART2_Init 1 */ + huart2.Instance = USART2; + huart2.Init.BaudRate = 115200; + huart2.Init.WordLength = UART_WORDLENGTH_8B; + huart2.Init.StopBits = UART_STOPBITS_1; + huart2.Init.Parity = UART_PARITY_NONE; + huart2.Init.Mode = UART_MODE_TX_RX; + huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart2.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USART2_Init 2 */ + + /* USER CODE END USART2_Init 2 */ + +} +/* USART3 init function */ + +void MX_USART3_UART_Init(void) +{ + + /* USER CODE BEGIN USART3_Init 0 */ + + /* USER CODE END USART3_Init 0 */ + + /* USER CODE BEGIN USART3_Init 1 */ + + /* USER CODE END USART3_Init 1 */ + huart3.Instance = USART3; + huart3.Init.BaudRate = 115200; + huart3.Init.WordLength = UART_WORDLENGTH_8B; + huart3.Init.StopBits = UART_STOPBITS_1; + huart3.Init.Parity = UART_PARITY_NONE; + huart3.Init.Mode = UART_MODE_TX_RX; + huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart3.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart3) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USART3_Init 2 */ + + /* USER CODE END USART3_Init 2 */ + } void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(uartHandle->Instance==USART1) + if(uartHandle->Instance==UART4) + { + /* USER CODE BEGIN UART4_MspInit 0 */ + + /* USER CODE END UART4_MspInit 0 */ + /* UART4 clock enable */ + __HAL_RCC_UART4_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**UART4 GPIO Configuration + PC10 ------> UART4_TX + PC11 ------> UART4_RX + */ + GPIO_InitStruct.Pin = ST_TX3_Pin|ST_RX3_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /* UART4 interrupt Init */ + HAL_NVIC_SetPriority(UART4_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(UART4_IRQn); + /* USER CODE BEGIN UART4_MspInit 1 */ + + /* USER CODE END UART4_MspInit 1 */ + } + else if(uartHandle->Instance==UART5) + { + /* USER CODE BEGIN UART5_MspInit 0 */ + + /* USER CODE END UART5_MspInit 0 */ + /* UART5 clock enable */ + __HAL_RCC_UART5_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + /**UART5 GPIO Configuration + PC12 ------> UART5_TX + PD2 ------> UART5_RX + */ + GPIO_InitStruct.Pin = ST_TX4_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART5; + HAL_GPIO_Init(ST_TX4_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ST_RX4_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART5; + HAL_GPIO_Init(ST_RX4_GPIO_Port, &GPIO_InitStruct); + + /* UART5 interrupt Init */ + HAL_NVIC_SetPriority(UART5_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(UART5_IRQn); + /* USER CODE BEGIN UART5_MspInit 1 */ + + /* USER CODE END UART5_MspInit 1 */ + } + else if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ @@ -73,30 +255,159 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) PA9 ------> USART1_TX PA10 ------> USART1_RX */ - GPIO_InitStruct.Pin = ST_TX0_Pin; + GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; - HAL_GPIO_Init(ST_TX0_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - GPIO_InitStruct.Pin = ST_RX0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF7_USART1; - HAL_GPIO_Init(ST_RX0_GPIO_Port, &GPIO_InitStruct); + /* USART1 DMA Init */ + /* USART1_TX Init */ + hdma_usart1_tx.Instance = DMA2_Stream7; + hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4; + hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart1_tx.Init.Mode = DMA_NORMAL; + hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) + { + Error_Handler(); + } + __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx); + + /* USART1_RX Init */ + hdma_usart1_rx.Instance = DMA2_Stream2; + hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4; + hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; + hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) + { + Error_Handler(); + } + + __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx); + + /* USART1 interrupt Init */ + HAL_NVIC_SetPriority(USART1_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } + else if(uartHandle->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspInit 0 */ + + /* USER CODE END USART2_MspInit 0 */ + /* USART2 clock enable */ + __HAL_RCC_USART2_CLK_ENABLE(); + + __HAL_RCC_GPIOD_CLK_ENABLE(); + /**USART2 GPIO Configuration + PD5 ------> USART2_TX + PD6 ------> USART2_RX + */ + GPIO_InitStruct.Pin = ST_TX1_Pin|ST_RX1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF7_USART2; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* USART2 interrupt Init */ + HAL_NVIC_SetPriority(USART2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(USART2_IRQn); + /* USER CODE BEGIN USART2_MspInit 1 */ + + /* USER CODE END USART2_MspInit 1 */ + } + else if(uartHandle->Instance==USART3) + { + /* USER CODE BEGIN USART3_MspInit 0 */ + + /* USER CODE END USART3_MspInit 0 */ + /* USART3 clock enable */ + __HAL_RCC_USART3_CLK_ENABLE(); + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**USART3 GPIO Configuration + PB10 ------> USART3_TX + PB11 ------> USART3_RX + */ + GPIO_InitStruct.Pin = ST_TX2_Pin|ST_RX2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF7_USART3; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USART3 interrupt Init */ + HAL_NVIC_SetPriority(USART3_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(USART3_IRQn); + /* USER CODE BEGIN USART3_MspInit 1 */ + + /* USER CODE END USART3_MspInit 1 */ + } } void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) { - if(uartHandle->Instance==USART1) + if(uartHandle->Instance==UART4) + { + /* USER CODE BEGIN UART4_MspDeInit 0 */ + + /* USER CODE END UART4_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_UART4_CLK_DISABLE(); + + /**UART4 GPIO Configuration + PC10 ------> UART4_TX + PC11 ------> UART4_RX + */ + HAL_GPIO_DeInit(GPIOC, ST_TX3_Pin|ST_RX3_Pin); + + /* UART4 interrupt Deinit */ + HAL_NVIC_DisableIRQ(UART4_IRQn); + /* USER CODE BEGIN UART4_MspDeInit 1 */ + + /* USER CODE END UART4_MspDeInit 1 */ + } + else if(uartHandle->Instance==UART5) + { + /* USER CODE BEGIN UART5_MspDeInit 0 */ + + /* USER CODE END UART5_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_UART5_CLK_DISABLE(); + + /**UART5 GPIO Configuration + PC12 ------> UART5_TX + PD2 ------> UART5_RX + */ + HAL_GPIO_DeInit(ST_TX4_GPIO_Port, ST_TX4_Pin); + + HAL_GPIO_DeInit(ST_RX4_GPIO_Port, ST_RX4_Pin); + + /* UART5 interrupt Deinit */ + HAL_NVIC_DisableIRQ(UART5_IRQn); + /* USER CODE BEGIN UART5_MspDeInit 1 */ + + /* USER CODE END UART5_MspDeInit 1 */ + } + else if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspDeInit 0 */ @@ -108,12 +419,58 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) PA9 ------> USART1_TX PA10 ------> USART1_RX */ - HAL_GPIO_DeInit(GPIOA, ST_TX0_Pin|ST_RX0_Pin); + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); + /* USART1 DMA DeInit */ + HAL_DMA_DeInit(uartHandle->hdmatx); + HAL_DMA_DeInit(uartHandle->hdmarx); + + /* USART1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspDeInit 1 */ /* USER CODE END USART1_MspDeInit 1 */ } + else if(uartHandle->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspDeInit 0 */ + + /* USER CODE END USART2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USART2_CLK_DISABLE(); + + /**USART2 GPIO Configuration + PD5 ------> USART2_TX + PD6 ------> USART2_RX + */ + HAL_GPIO_DeInit(GPIOD, ST_TX1_Pin|ST_RX1_Pin); + + /* USART2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(USART2_IRQn); + /* USER CODE BEGIN USART2_MspDeInit 1 */ + + /* USER CODE END USART2_MspDeInit 1 */ + } + else if(uartHandle->Instance==USART3) + { + /* USER CODE BEGIN USART3_MspDeInit 0 */ + + /* USER CODE END USART3_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USART3_CLK_DISABLE(); + + /**USART3 GPIO Configuration + PB10 ------> USART3_TX + PB11 ------> USART3_RX + */ + HAL_GPIO_DeInit(GPIOB, ST_TX2_Pin|ST_RX2_Pin); + + /* USART3 interrupt Deinit */ + HAL_NVIC_DisableIRQ(USART3_IRQn); + /* USER CODE BEGIN USART3_MspDeInit 1 */ + + /* USER CODE END USART3_MspDeInit 1 */ + } } /* USER CODE BEGIN 1 */ diff --git a/CH395F.md b/docs/CH395F.md similarity index 100% rename from CH395F.md rename to docs/CH395F.md diff --git a/docs/FlashDB使用说明.md b/docs/FlashDB使用说明.md new file mode 100644 index 0000000..989c6c8 --- /dev/null +++ b/docs/FlashDB使用说明.md @@ -0,0 +1,400 @@ +# FlashDB 使用说明 + +## 1. 概述 + +本项目使用 [FlashDB](https://github.com/armink/FlashDB) 嵌入式数据库,提供两种数据库: + +- **KVDB**(键值数据库):存储键值对,类似 Redis 简化版 +- **TSDB**(时序数据库):存储带时间戳的日志记录,支持按时间范围查询 + +底层存储介质为 GD5F2GQ5UE SPI NAND Flash(256MB),通过 FAL(Flash Abstraction Layer)抽象层访问。 + +## 2. 软件架构 + +``` +┌─────────────────────────────────────────┐ +│ 用户应用(main.c) │ +├──────────────┬──────────────────────────┤ +│ fdb_kvdb │ fdb_tsdb │ +│ (键值数据库) │ (时序数据库) │ +├──────────────┴──────────────────────────┤ +│ FlashDB 核心 │ +│ Lib/FlashDB/src/ │ +├─────────────────────────────────────────┤ +│ FAL 抽象层 │ +│ Lib/FlashDB/port/fal/src/ │ +├─────────────────────────────────────────┤ +│ FAL 设备适配层 │ +│ fal_flash_gd5f2gq5ue.c │ +├─────────────────────────────────────────┤ +│ GD5F2GQ5UE SPI NAND 驱动 │ +│ gd5f2gq5ue.c │ +├─────────────────────────────────────────┤ +│ SPI1 硬件外设 + HAL 驱动 │ +└─────────────────────────────────────────┘ +``` + +## 3. 文件清单 + +| 文件 | 说明 | 是否自编 | +|------|------|----------| +| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h` | NAND 驱动头文件 | 是 | +| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c` | NAND 驱动实现 | 是 | +| `Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c` | FAL 设备适配 | 是 | +| `Drivers/BSP/GD5F2GQ5UE/fal_cfg.h` | FAL 设备表 + 分区表 | 是 | +| `Drivers/BSP/GD5F2GQ5UE/fdb_cfg.h` | FlashDB 功能配置 | 是 | +| `Lib/FlashDB/src/` | FlashDB 核心源码 | 否 | +| `Lib/FlashDB/port/fal/src/` | FAL 硬件抽象框架源码 | 否 | + +## 4. 硬件配置 + +### 4.1 Flash 芯片参数 + +| 参数 | 值 | +|------|-----| +| 型号 | GD5F2GQ5UE(GigaDevice) | +| 总容量 | 2Gbit = 256MB | +| 页大小 | 2048 字节 | +| Spare 区 | 64 字节 | +| 每块页数 | 64 页 | +| 块大小 | 128KB(64 × 2048) | +| 总块数 | 2048 | +| SPI 模式 | Mode 0(CPOL=0, CPHA=0) | +| SPI 时钟 | 42MHz(APB2=84MHz, 分频=2) | +| MID | 0xC8 | +| DID | 0x52 | + +### 4.2 引脚连接 + +| 信号 | STM32 引脚 | 方向 | 说明 | +|------|-----------|------|------| +| CS# | PE0 | OUT | 片选,低有效 | +| SCLK | PB3 | OUT | SPI1 时钟 | +| MOSI | PB5 | OUT | SPI1 主出从入 | +| MISO | PB4 | IN | SPI1 主入从出 | +| WP# | PB8 | OUT | 写保护,低有效(拉高禁用) | +| HOLD# | PE1 | OUT | 保持,低有效(拉高禁用) | + +### 4.3 GPIO 初始化 + +CubeMX 中需确保以下 GPIO 上电默认电平: + +- **CS#** (PE0):上电输出 **高电平**(未选中) +- **HOLD#** (PE1):上电输出 **高电平**(不保持) +- **WP#** (PB8):上电输出 **高电平**(不禁用写保护) + +> 若 GPIO 初始电平错误,SPI 通信将完全无响应。 + +## 5. 分区规划 + +| 分区名 | 设备 | 偏移 | 大小 | 用途 | +|--------|------|------|------|------| +| fdb_kvdb1 | gd5f2gq5ue | 0 | 64MB | KVDB 键值数据库 | +| fdb_tsdb1 | gd5f2gq5ue | 64MB | 64MB | TSDB 时序数据库 | +| (未分配) | - | 128MB | 128MB | 剩余空间 | + +共使用 128MB / 256MB,剩余 128MB 可扩展。 + +## 6. 初始化流程 + +``` +1. HAL_Init() +2. SystemClock_Config() +3. MX_GPIO_Init() ← CS#/HOLD#/WP# 初始电平 +4. MX_USART1_UART_Init() ← 调试串口 +5. MX_SPI2_Init() ← CH395F 以太网 +6. MX_SPI1_Init() ← GD5F2GQ5UE NAND +7. gd5f2gq5ue_init() ← NAND 初始化 +8. fdb_kvdb_init() ← FlashDB KVDB 初始化 +``` + +### 6.1 gd5f2gq5ue_init() 内部步骤 + +``` +1. CS#/WP#/HOLD# 拉高 +2. 发送复位命令(FFh),等待 5ms +3. 读取芯片 ID(9Fh),校验 MID=0xC8, DID=0x52 +4. 使能内部 ECC:SET_FEATURE(B0h, 10h) +5. 解除块保护:SET_FEATURE(A0h, 00h) +``` + +> **关键点**:SET_FEATURE 命令前必须先发写使能(06h),否则设置不生效。 + +## 7. KVDB 使用方法 + +### 7.1 初始化 + +```c +#include "flashdb.h" + +static struct fdb_kvdb kvdb; + +/* path 参数对应分区表中的分区名 "fdb_kvdb1" */ +/* default_kv 传 NULL 表示不使用默认键值 */ +int ret = fdb_kvdb_init(&kvdb, "db", "fdb_kvdb1", NULL, NULL); +if (ret != FDB_NO_ERR) { + /* 初始化失败处理 */ +} +``` + +### 7.2 字符串读写 + +```c +/* 写入字符串 */ +fdb_kv_set(&kvdb, "device_name", "STM32F407-DTU"); + +/* 读取字符串(返回内部缓存指针,下次写入同一 key 后失效) */ +char *val = fdb_kv_get(&kvdb, "device_name"); +if (val) { + printf("device_name = %s\n", val); +} +``` + +### 7.3 二进制数据读写(Blob) + +```c +#include + +/* 写入二进制数据 */ +uint32_t temp = 2560; +fdb_kv_set_blob(&kvdb, "temperature", + fdb_blob_make(NULL, &temp, sizeof(temp))); + +/* 读取二进制数据 */ +uint32_t read_temp = 0; +fdb_kv_get_blob(&kvdb, "temperature", + fdb_blob_make(NULL, &read_temp, sizeof(read_temp))); +printf("temperature = %u\n", read_temp); +``` + +### 7.4 删除键 + +```c +fdb_kv_del(&kvdb, "device_name"); +``` + +### 7.5 遍历所有键 + +```c +struct fdb_kv kv; +struct fdb_kv_iterator itr; + +fdb_kv_iterator_init(&kvdb, &itr); +while (fdb_kv_iterate(&kvdb, &itr)) { + kv = itr.curr; + printf("key: %s\n", kv.name); +} +``` + +### 7.6 打印所有键值 + +```c +fdb_kv_print(&kvdb); +``` + +## 8. TSDB 使用方法 + +### 8.1 获取时间戳 + +FlashDB 需要用户提供时间戳获取函数。本项目使用 HAL_GetTick()(毫秒): + +```c +static fdb_time_t get_time(void) +{ + return (fdb_time_t)HAL_GetTick(); +} +``` + +### 8.2 初始化 + +```c +static struct fdb_tsdb tsdb; + +/* max_len 参数限制单条记录最大长度 */ +int ret = fdb_tsdb_init(&tsdb, "tsdb", "fdb_tsdb1", + get_time, 256, NULL); +``` + +### 8.3 追加记录 + +```c +/* 写入二进制数据,自动附加当前时间戳 */ +uint32_t sensor_val = 3200; +fdb_tsl_append(&tsdb, + fdb_blob_make(NULL, &sensor_val, sizeof(sensor_val))); +``` + +### 8.4 遍历记录 + +```c +/* 正序遍历 */ +fdb_tsl_iter(&tsdb, tsl_cb_func, NULL); + +/* 逆序遍历 */ +fdb_tsl_iter_reverse(&tsdb, tsl_cb_func, NULL); + +/* 按时间范围遍历 */ +fdb_tsl_iter_by_time(&tsdb, from_time, to_time, tsl_cb_func, NULL); +``` + +回调函数原型: + +```c +static void tsl_cb_func(struct fdb_tsl *tsl, void *arg) +{ + struct fdb_blob blob; + uint32_t val; + + /* 读取数据 */ + fdb_blob_read((fdb_db_t)&tsl, + fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &val, sizeof(val)))); + printf("ts=%lu, val=%lu\n", tsl->time, val); +} +``` + +### 8.5 查询记录数量 + +```c +size_t count = fdb_tsl_query_count(&tsdb, from_time, to_time, + FDB_TSL_STATUS_APPEND); +``` + +### 8.6 清理所有记录 + +```c +fdb_tsl_clean(&tsdb); +``` + +## 9. 配置文件说明 + +### 9.1 fdb_cfg.h + +| 宏 | 说明 | +|----|------| +| `FDB_USING_KVDB` | 启用 KVDB | +| `FDB_USING_TSDB` | 启用 TSDB | +| `FDB_USING_FAL_MODE` | 使用 FAL 模式(非文件系统) | +| `FDB_WRITE_GRAN` | 写入粒度 8(字节可编程) | +| `FDB_DEBUG_ENABLE` | 启用调试输出 | +| `FDB_KV_AUTO_UPDATE` | KVDB 版本变化时自动更新(默认关闭) | + +### 9.2 fal_cfg.h + +分区表定义,修改分区大小需同时调整偏移和大小: + +```c +#define FAL_PART_TABLE \ +{ \ + {FAL_PART_MAGIC_WORD, "fdb_kvdb1", "gd5f2gq5ue", 0, 64*1024*1024, 0}, \ + {FAL_PART_MAGIC_WORD, "fdb_tsdb1", "gd5f2gq5ue", 64*1024*1024, 64*1024*1024, 0}, \ +} +``` + +字段顺序:`{魔数, 分区名, 设备名, 偏移, 大小, 标志}` + +## 10. Keil 工程配置 + +### 10.1 头文件搜索路径 + +在 Keil 工程 Options → C/C++ → Include Paths 中添加: + +``` +../Drivers/BSP/GD5F2GQ5UE +../Lib/FlashDB/inc +../Lib/FlashDB/port/fal/inc +``` + +### 10.2 编译的源文件 + +需在 Keil 工程中添加以下源文件: + +``` +Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c +Drivers/BSP/GD5F2GQ5UE/fal_flash_gd5f2gq5ue.c +Lib/FlashDB/src/fdb.c +Lib/FlashDB/src/fdb_kvdb.c +Lib/FlashDB/src/fdb_tsdb.c +Lib/FlashDB/src/fdb_utils.c +Lib/FlashDB/port/fal/src/fal.c +Lib/FlashDB/port/fal/src/fal_flash.c +Lib/FlashDB/port/fal/src/fal_partition.c +``` + +### 10.3 全局宏定义 + +确保工程中定义了: + +``` +USE_HAL_DRIVER, STM32F407xx +``` + +## 11. 注意事项 + +### 11.1 NAND Flash 特性 + +1. **写前必须擦除**:NAND 只能将 1→0,不能 0→1。写入前目标块必须先擦除(全部变为 0xFF) +2. **擦除单位是块**:最小擦除单位 128KB,不能按页擦除 +3. **写入单位是页**:单次写入不超过一页(2048 字节),跨页需驱动层拆分 +4. **Spare 区不可直接访问**:驱动已使能内部 ECC,Spare 区由芯片硬件管理 + +### 11.2 驱动层注意事项 + +1. **每次 SPI 事务前**:必须 `CS_LOW()` 拉低片选 +2. **每次 SPI 事务后**:必须 `CS_HIGH()` 拉高片选 +3. **SET_FEATURE 前必须写使能**:先发 06h,再发 1Fh + 地址 + 数据 +4. **块擦除地址是字节地址**:D8h 命令的参数 = 块编号 × 128KB(不是块编号本身) +5. **读取 ID 需跳过 dummy 字节**:9Fh 返回 3 字节,第 0 字节无意义,第 1 字节 MID,第 2 字节 DID + +### 11.3 FlashDB 使用注意事项 + +1. **fdb_kv_get 返回值是内部缓存**:下次对同一 key 写入后,之前返回的指针失效 +2. **TSDB 需要用户提供时间戳**:通过 `get_time` 回调,本项目使用 `HAL_GetTick()` +3. **fdb_kvdb_init 的 path 参数**:对应分区表中的分区名 `"fdb_kvdb1"` +4. **FlashDB 开启 FDB_DEBUG_ENABLE 后**:会通过 `fdb_print()` 输出调试信息,需确保有可用的输出(如 printf 重定向到串口) +5. **分区大小修改后**:需同步更新 `fal_cfg.h` 中的偏移和大小 + +### 11.4 常见问题 + +| 现象 | 可能原因 | 解决方法 | +|------|----------|----------| +| init 返回 -6 (ID_MISMATCH) | SPI 通信失败或芯片未上电 | 检查接线、GPIO 初始电平、虚焊 | +| KVDB init 失败 | 分区名不匹配 | 确认 `fdb_kvdb_init` 的 path 与 `fal_cfg.h` 一致 | +| 写入后读取为空 | 未擦除或写入失败 | 检查写入返回值,确认目标块已擦除 | +| 读取数据异常 | ECC 错误 | 检查 `gd5f2gq5ue_init` 是否成功使能 ECC | +| SET_FEATURE 未生效 | 缺少写使能命令 | 确认 `gd5f_set_feature` 中先调用 `gd5f_write_enable()` | + +## 12. 调试方法 + +### 12.1 串口调试输出 + +FlashDB 调试输出通过 `fdb_print` 宏实现。在 `fdb_cfg.h` 中定义 `FDB_DEBUG_ENABLE` 后,FlashDB 内部操作会自动输出到标准输出。 + +确保 Keil 工程中 `printf` 已重定向到 USART1(PA9/PA10, 115200bps)。 + +### 12.2 NAND 驱动调试 + +可通过串口输出以下信息验证驱动工作正常: + +```c +/* 读取芯片 ID */ +uint8_t mid, did; +gd5f2gq5ue_read_id(&mid, &did); +printf("MID=0x%02X DID=0x%02X\n", mid, did); +/* 预期输出:MID=0xC8 DID=0x52 */ + +/* 初始化测试 */ +int ret = gd5f2gq5ue_init(); +printf("init ret=%d\n", ret); +/* 预期输出:init ret=0 */ +``` + +### 12.3 FAL 设备注册验证 + +```c +#include "fal.h" + +/* 检查 FAL 是否初始化成功 */ +int ret = fal_init(); +printf("fal_init ret=%d\n", ret); +/* 预期输出:fal_init ret=0 */ +``` diff --git a/GD5F2GQ5UExxG.md b/docs/GD5F2GQ5UExxG.md similarity index 100% rename from GD5F2GQ5UExxG.md rename to docs/GD5F2GQ5UExxG.md diff --git a/RTL8305NBI-CG.md b/docs/RTL8305NBI-CG.md similarity index 100% rename from RTL8305NBI-CG.md rename to docs/RTL8305NBI-CG.md diff --git a/docs/SD2506API-G.md b/docs/SD2506API-G.md new file mode 100644 index 0000000..44b1388 --- /dev/null +++ b/docs/SD2506API-G.md @@ -0,0 +1,850 @@ +## 内置晶振、充电电池、温度补偿的高精度实时时钟 + +## SD2506API-G + +## 1.概述 + +SD2506API是一种内置晶振、充电电池、温度补偿及标准 IIC 接口的实时时钟模块,CPU可使用该接口通过 7位地址来寻址读写片内 122字节的数据(包括时间寄存器、报警寄存器、控制寄存器、温度寄存器、电池电量寄存器、70字节的用户 SRAM寄存器及 8 字节的 ID 码寄存器)。 + +SD2506API内置晶振及数字温度补偿, 用户可以不用顾虑因外接晶振、谐振电容等所带来的元件匹配误差问题、晶振温度特性问题及可靠性问题,实现在常温及宽温范围内(-30℃~+80℃)不需用户干预、全自动、高可靠温度补偿计时功能;SD2506 可保证时钟精度为±3.8ppm(在 25℃左右),即年误差小于 2 分钟。 + +SD2506API内置充电电池及充电电路,在电池满充的常温情况下内部时钟走时在 8个月时间左右,累计电池电量超过 550mAh,电池使用寿命为 5~8 年时间;内部具备电源切换电路,当模块检测到主电源 VDD掉到充电电池电压以下,模块会自动转为由充电电池供电。 + +SD2506API内置 8 字节的 ID,每一颗模块具备唯一的身份识别码。 + +SD2506API内置单路定时/报警中断输出,报警中断时间可最长设至 100年;该系列模块可满足对实时时钟模块的各种需要,且管脚与以前的 SD2405兼容,软件部分绝大部分兼容(重要区别在:强烈建议用户的程序在每一次上电时重置 18H 寄存器的值为 82H,用于确保开启充电功能),是在选用高精度实时时钟时的理想选择。 + +## 2.特性 + +低功耗: 0.8μA 典型值(内部电池供电,Ta=25℃)。 +工作电压:2.7V~5.5V,工作温度:-30℃~+80℃。 +标准IIC总线接口方式,最高速度400KHZ(4.5V~5.5V)。 + 年、月、日、星期、时、分、秒的BCD码输入/输出,并可通过独立的地址访问各时间寄存器。 +闰年自动调整功能(从2000年~2099年)。 +可选择12/24小时制式. +. 内置年、月、日、星期、时、分、秒共7字节的报警数据寄存器及1字节的报警允许寄存器。 +内置70字节通用SRAM寄存器可用于存储用户的一般数据。 +三种中断均可选择从INT脚输出,并具有两个中断标志位。 + 内置年、月、日、星期、时、分、秒共7字节的报警数据寄存器及1字节的报警允许寄存器,共有96种组合报警方式,并有单事件报警和周期性报警两种中断输出模式,报警时间最长可设至100年。 +周期性频率中断输出:从4096Hz~1/16Hz……1秒共十四种方波脉冲. + +自动重置的三字节共24位的倒计时定时器,可选的2种时钟源(4096Hz、1024Hz)。 + 内置8bit转换结果的数字温度传感器,为了节省电池电量消耗,设为VDD模式下60S间隔测温一次,电池模式600S间隔测温一次。 + 内置记录历史高、低温发生时刻及相关温度值的功能;可设置高、低温报警值并从INT脚输出中断。 + 内置晶振和谐振电容,模块内部通过高精度补偿方法,实现在宽温范围内高精度的计时功能,其中25℃精度<±3.8ppm,即时钟年误差小于2分钟(在25±1℃下)。 + 内置充电电池及充电电路,累计电池电量超过550mAH,在电池满充的常温情况下内部时钟走时时间在8个月左右,电池使用寿命为5~8年时间。 + 内置电池电压检测功能,可读取当前电池电压值(三位有效数),设置高低电池报警电压值并从INT脚输出中断。 +模块依据不同的电压自动从VDD切换到VBAT或从VBAT切换到VDD。当模块检测到主电源VDD掉到2.4V电压以下且VDD小于VBAT,模块会转为由接在VBAT的后备电池供电;当VDD大于VBAT或VDD大于2.4V,则模块会转为由VDD供电。(内置电源模式指示位PMF,VDD模式时PMF=0,VBAT模式时PMF=1)。 + 内置总线0.5秒自动复位功能(从Start命令开始计时),保证时钟数据的有效性及可靠性,避免IIC总线挂死问题。 + 内置三个时钟数据写保护位, 避免对数据的误写操作,可更好地保护数据。 + 内置软件可控VBAT模式IIC总线通信禁止功能(BATIIC=0,VBAT模式下禁止IIC通信;BATIIC=1,VBAT模式下允许IIC通信.上电默认值BATIIC=0),从而避免在电池供电时CPU对时钟操作所消耗的电池电量,也可避免在VDD上、下电的过程中因CPU的I/O端口所输出的不受控的杂波信号对时钟模块的误写操作,进一步提高时钟模块的可靠性。 + 在VBAT模式下,模块具有中断输出允许或禁止的功能,可满足在备用电池供电时输出中断的需要。 + 内置上电复位电路及指示位RTCF,当包括电池在内的所有电源第一次上电时该位置1。 +内置电源稳压,内部计时电压可低至2.0V。 +内置8字节的ID码,模块出厂之前设定的、全球唯一的身份识别码。 +模块在兴威帆的评估板上可通过4KV的群脉冲(EFT)干扰 +CMOS工艺。 +封装形式:8脚的DIP封装。 + +## 3.原理框图和管脚定义 + +![](images/232802d20b9421a02d9d02b17c8f6a991fb908d9c88b558d1187f9bb4857dca5.jpg) + +
+flowchart + +```mermaid +graph LR + SDA["SDA"] --> Buffer1["SDA BUFFER"] + SCL["SCL"] --> Buffer2["SCL BUFFER"] + Buffer1 --> Interface["IIC INTERFACE"] + Buffer2 --> Interface + Interface --> ControlLogic["RTC CONTROL LOGIC"] + GND["GND"] --> Crystals["CRYSTAL OSCILLATOR"] + Crystals --> Dividers["RTC DIVIDER"] + Dividers --> FreqOut["FREQUENCY OUT"] + FreqOut --> Alarm["ALARM"] + FreqOut --> CountDown["COUNT DOWN"] + Alarm --> CountDown + CountDown --> Switch["POWER SWITCH"] + Switch --> Battery["RECHARGE CIRCUIT"] + Battery --> Battery + Switch --> Test["TEST"] + Test --> Recharge["RECHARGE CIRCUIT"] + Recharge --> Battery + GND --> CT["CT"] + CT --> Crystals + GND --> C["C"] + C --> Crystals + C --> 32768Hz["32768Hz"] + C --> GND + GND --> FreqOut + FreqOut --> INT["INT"] + INT --> Second["Second"] + INT --> Minute["Minute"] + INT --> Hour["Hour"] + INT --> Week["Week"] + INT --> Date["Date"] + INT --> Month["Month"] + INT --> Year["Year"] + INT --> Alarm/Control["ALARM/CONT - ROL REGISTERS"] + INT --> SRAM["USER SRAM"] +``` +
+ +![](images/ea8b0d8c8950659a161f87903e26bcf255e7f32ebc66d4bb73b61bbe30f9fbbe.jpg) + +
+text_image + +TEST 1 SD2506AP +8 VDD +7 INT +6 SCL +5 SDA +4 +GND +
+ +封装形式:DIP-8(引脚宽度 300mil) + +表 1 SD2506API 管脚功能表 + +
脚号名称功能特征
1TEST内部电池电压测试脚,该电池通过510K电阻输出到该脚。悬空(不可与其它脚相连,仅用于测试)。
4GND负电源(GND)N沟道开路输出;CMOS输入
5SDA串行数据输入/输出脚,此管脚通常用一电阻上拉至VDD,并与其它漏极开路或集电器开路输出的器件通过线与方式连接。N沟道开路输出,CMOS输入;当模块由内部后备充电电池供电时,该引脚功能被禁止。
6SCL串行时钟输入脚,由于在SCL上升/下降沿处理信号,要特别注意SCL信号的上升/下降升降时间,应严格遵守说明书。与SCL相连的MCU端口最好设置为CMOS输出。CMOS输入,当模块由内部后备充电电池供电时,该引脚功能被禁止。
7INT报警中断输出脚,根据控制寄存器来设置其工作的模式,它可通过重写控制寄存器来禁止。N-沟道开路输出
8VDD正电源2.7V~5.5V
+ +## 4. 基本功能定义 + +4.1寄存器列表 + +
地址寄存器段寄存器名称BIT数值范围(十进制)复位值(二进制)
D7D6D5D4D3D2D1D0
00H实时时钟寄存器0S40S20S10S8S4S2S10-59XXXX-XXXX
01H分钟0MN40MN20MN10MN8MN4MN2MN10-59XXXX-XXXX
02H小时12_/240H20P/A_H10H8H4H2H10-23XXXX-XXXX
03H星期00000W4W2W10-6XXXX-XXXX
04H00D20D10D8D4D2D11-31XXXX-XXXX
05H000M010M08M04M02M011-12XXXX-XXXX
06HY80Y40Y20Y10Y8Y4Y2Y10-99XXXX-XXXX
07H时间报警寄存器秒报警0AS40AS20AS10AS8AS4AS2AS10-590000-0000
08H分钟报警0AMN40AMN20AMN10AMN8AMN4AMN2AMN10-590000-0000
09H小时报警00AH20AP/A_AH10AH8AH4AH2AH10-230000-0000
0AH星期报警0AW6AW5AW4AW3AW2AW1AW0N/A0000-0000
0BH日报警00AD20AD10AD8AD4AD2AD11-310000-0000
0CH月报警000AM010AM08AM04AM02AM011-120000-0000
0DH年报警AY7AY6AY5AY4AY3AY2AY1AY00-990000-0000
0EH报警允许0EAYEAM0EADEAWEAHEAMNEASN/A0000-0000
0FH控制寄存器CTR1WRTC3OSFINTAFINTDFBLFWRTC2PMFRTCFN/A0000-0000
10HCTR2WRTC1IMINTS1INTS0FOBATINTDEINTAEINTFEN/A0000-0000
11HCTR3ARSTF32KTDS1TDS0FS3FS2FS1FS0N/A0000-0000
12H25°C TTF(只读RAM)1ppm/3ppmF6F5F4F3F2F1F0N/A0000-0000
13H倒计时定时器TD7TD6TD5TD4TD3TD2TD1TD00-2550000-0000
14HTD15TD14TD13TD12TD11TD10TD9TD80-2550000-0000
15HTD23TD22TD21TD20TD19TD18TD17TD160-2550000-0000
16H温度寄存器TEMPTM7TM6TM5TM4TM3TM2TM1TMO0-255XXXX-XXXX
17HIIC控制寄存器AGTCBATIIC0------0-2550000-0000
18H充电寄存器CHARGEENCH-----Charge1Charge20-255CHARGE
19H扩展控制寄存器CTR4INTS_E2INTS_E1INTS_E0CONT_BATINTTHEINTTLEINTBHEINTBLE0-2550000_0000
1AHCTR5BAT8_VALSYSOSC_RDYBHFBLF0-2550000_0000
1BH电池电量BAT_VALBAT7_VALBAT6_VALBAT5_VALBAT4_VALBAT3_VALBAT2_VALBAT1_VALBATO_VAL0-2550000_0000
1CH低温报警值TEMP_ALTEMP7_ALTEMP6_ALTEMP5_ALTEMP4_ALTEMP3_ALTEMP2_ALTEMP1_ALTEMPO_AL0-2550000_0000
1DH高温报警值TEMP_AHTEMP7_AHTEMP6_AHTEMP5_AHTEMP4_AHTEMP3_AHTEMP2_AHTEMP1_AHTEMPO_AH0-2550000_0000
1EH历史最低温度TEMP_HIS_LTEMP_L7TEMP_L6TEMP_L5TEMP_L4TEMP_L3TEMP_L2TEMP_L1TEMP_L00-2550111_1111
1FH历史最高温度TEMP_HIS_HTEMP_H7TEMP_H6TEMP_H5TEMP_H4TEMP_H3TEMP_H2TEMP_H1TEMP_H00-2551000_0000
20H历史最低温度发生的时间分钟0-590000_0000
21H小时0-230000_0000
22H星期0-60000_0000
23H1-310000_0000
24H1-120000_0000
25H0-990000_0000
26H历史最高温度发生的时间分钟0-590000_0000
27H小时0-230000_0000
28H星期0-60000_0000
29H1-310000_0000
2AH1-120000_0000
2BH0-990000_0000
2CH~71H用户RAM(70Bytes)BIT7BIT6BIT5BIT4BIT3BIT2BIT1BIT00-255XXXX-XXXX
72H~79HID(只读)(8Bytes)BIT7BIT6BIT5BIT4BIT3BIT2BIT1BIT0N/AXXXX-XXXX
+ +注: $" \mathbb { X } ^ { 3 1 }$ 表示随机值,可以为 0或者 1。 + +## 4.2 实时时钟数据寄存器 $( 0 0 mathsf { H } \widetilde { \mathsf { \Omega } } 0 6 \mathsf { H } )$ + +实时时钟数据寄存器是 7字节的存储器,它以 BCD码方式存贮包括年、月、日、星期、时、分、秒的数据。 + +年数据[06H 地址] $\left( 0 0 ^ { \sim } 9 9 \right)$ ):设置千年(20XX)的后两位数字 $\left( 0 0 ^ { \sim } 9 9 \right)$ ),通过自动日历功能计至 2099年。(注意: 2000年为闰年) + +月数据[05H地址 $\left( 0 1 ^ { \sim } 1 2 \right)$ ): 每月包含的天数通过自动日历功能来更改。 + +1,3,5,7,8,10,12: 1\~31 + +4,6,9,11: 1\~30 + +2(闰年): $1 ^ { \sim } 2 9$ + +2(普通): $1 ^ { \sim } 2 8$ + +日数据[04H 地址] $\left( 0 1 ^ { \sim } 3 1 \right)$ + +星期数据[03H地址] $\left( 0 0 ^ { \sim } 0 6 \right)$ :七进制计数器,00 对应星期天,01 对应星期一,依次类推。 + +小时数据[02H地址] $\left( 0 0 ^ { \sim } 2 3 \right.$ 或 $0 1 ^ { \sim } 1 2 )$ ):小时的最高位 12\_/24是 12或 24 小时制选择位。 + +当 12\_/24=1 时,24 小时制; 当 12\_/24=0 时, 12 小时制。 + +12 小时制时,H20 为 AM/PM 指示位,H20=0 为 AM,H20=1 为 PM, + +见下表:(位 H20H10H8H4H2H1) + +
24小时显示系统12小时显示系统24小时显示系统12小时显示系统
0012(AM12)1232(PM12)
0101(AM1)1321(PM1)
0202(AM2)1422(PM2)
0303(AM3)1523(PM3)
0404(AM4)1624(PM4)
0505(AM5)1725(PM5)
0606(AM6)1826(PM6)
0707(AM7)1927(PM7)
0808(AM8)2028(PM8)
0909(AM9)2129(PM9)
1010(AM10)2230(PM10)
1111(AM11)2331(PM11)
+ +注意: 当读取小时数据时,要屏蔽掉小时的最高位12\_/24,否则在24小时制时会因为12\_/24=1而显示不对。 + +分数据[01H 地址] $( 0 0 ^ { \sim } 5 9 )$ + +秒数据[00H 地址] $( 0 0 ^ { \sim } 5 9 )$ + +例如: 设置时间为2014年12月20日星期三18点19分20秒(24小时制),则寄存器00~07H的赋值应分别为 20h、19h、98h、03h、20h、12h、14h。要特别注意此处小时位的赋值,因为是 24 小时制式,小时的 12\_/24 位=1,所以小时的赋值为 98h(1001 1000B)。 + +也请注意在24小时制时,当小时数据读出后,其最高位为1,所以要将读到的数据最高位置 0,否则小时数据不对。 + +注: + +1.在上电复位时,芯片内部不对实时时钟数据寄存器作清零或置位处理。 +2.当写实时时间数据时 $\mathrm { ( 0 0 H \widetilde { \Omega } 0 6 H ) }$ ,不可以单独对 7 个时间数据中的某一位进行写操作,否则可能会引起时间数据的错误进位,所以要修改其中某一个数据, 应一次性写入全部 7 个实时时钟数据。 +3. 当芯片收到读实时时钟数据命令,则所有实时时钟数据被锁存(时钟走时并不受影 + +响),此功能可以避免时间数据的错读现象。 + +## 4.3 时间中断(07H\~15H 地址) + +SD2506API 有 3 种不同时间报警中断,它们由控制寄存器 CTR2(10H)中的位 INTAE、INTFE、INTDE 位来使能: + +$\$ 123,456$ + +
序号中断允许位(1=允许, 0=禁止)中断名中断标志位(1=有中断, 0=无中断)
1INTAE报警中断INTAF
2INTFE频率中断
3INTDE倒计时中断INTDF
+ +当报警中断产生时,置中断标志位 INTAF 为 1;当倒计时中断产生时, 置中断标志位INTDF为 1;频率中断没有标志位,标志位被置 1后,需要手动清除。 + +三种中断都是以 INT脚为输出脚, 通过控制寄存器 2中的 INTS1、INTS0 位来选择确定INT脚输出何种中断: + +INT脚中断输出选通表 + +
序号INTS1INTS0描述
000电量报警(见4.4)
101报警中断输出
210频率中断输出
311倒计时中断输出
+ +## (1)报警中断 + +当 INTAE=1时报警中断被允许,报警中断何时发生由时间报警寄存器(07H\~0EH)来确定。这其中 07H\~0DH依次用于存放报警时间的秒、分钟、小时、星期、日、月、年数据,除小时报警数据寄存器的最高位始终为”0” 、星期位的定义不同以外,其它的格式与实时时钟寄存器相同。 + +0EH为时间报警允许寄存器,如下: + +
BITD7D6D5D4D3D2D1D0
位名(值)0EAYEAMOEADEAWEAHEAMNEAS
报警允许-年(ODH)月(OCH)日(OBH)星期(OAH)小时(09H)分钟(08H)秒(07H)
+ +注:1=允许,0=禁止。 + +时间报警允许寄存器的使能位是用于确定哪些时间报警寄存器(秒、分钟等)需要与实时时钟寄存器之间作比较。当实时时钟运行时,一旦被允许的报警寄存器均与对应的实时时钟寄存器相匹配,就会触发一次报警中断,同时报警中断标志位 INTAF 位被置”1”。 + +特别: + +1.当日报警与星期报警均被允许即 EAD=EAW=1时,只有日报警有效,而星期报警无效,所以时间报警中断共有 96种组合方式。 +2.星期报警寄存器的数据格式与实时时钟数据星期的格式不同,星期报警寄存器的位AW6、AW5、AW4、AW3、AW2、AW1、AW0分别对应星期六、星期五、星期四、星期三、星期二、 + +星期一、星期日,并可多位置 1,例如 AW6,AW1=1,其它位为 0,则对应在星期六,星期一会有报警。 + +每一次对时间报警允许寄存器的写入都会清 INTAF 为"0",当设置 INTS1=0、INTS0=1时,即允许报警中断从 INT脚输出。该报警中断有两种模式,即单事件报警和周期性报警, 模式的选定由控制寄存器 2中的报警中断模式位 IM的值来定: + +
IM位报警中断模式INT脚
0单事件报警输出低电平直至INTAF位清零
1周期性报警输出低电平有效、宽度为250ms的周期性脉冲直至中断允许位清零
+ +为清除报警中断,可通过写操作将控制寄存器 1 的 INTAF 位置”0”,但当 ARST位置为”1”,则在控制寄存器 1 被读取时,INTAF位会自动清零。 + +举例: + +1.设寄存器 0EH=00000001B,秒报警寄存器 07H=20h,位 INTAE=1、IM=1、INTS1=0、INTS0=1 ,则每当时间秒数据进位到 20h的时候,INT 脚都会输出宽度为 250ms 的低电平,即频率为 1 分钟的方波。如下图: + +![](images/01d8a7840304f8197d7f2dd4e019d19915bf7d3ad1e7d5bda932029f1b74ff58.jpg) + +
+text_image + +INT +60s +250ms +
+ +2.设寄存器 0EH=00001111B,星期报警寄存器 0AH=0010 0110B,小时报警寄存器 09H=08h,分钟报警寄存器 08H=30h,秒报警寄存器 07H=00h,位 INTAE=1、IM=1、INTS1=0、INTS0=1 , 则每到星期一、星期二、星期五的 8 点 30 分 0 秒的时候,INT 脚都会输出宽度为 250ms 的低电平。 + +3.设寄存器 0EH=00010111B,日报警寄存器 0BH=01h,小时报警寄存器 09H=08h,分钟报警寄存器 08H=30h,秒报警寄存器 07H=00h,位 INTAE=1、IM=1、INTS1=0、INTS0=1 , 则到每个月 1 号的 8点 30分 0 秒的时候,INT脚都会输出宽度为 250ms的低电平。 + +4.设寄存器 0EH=0111 0100B, 年报警寄存器 0DH=08h,月报警寄存器 0CH=08h,日报警寄存器 0BH=08h,小时报警寄存器 09H=20h,位 INTAE=1、IM=0、INTS1=0、INTS0=1、12\_/24=1 ,则到 2008 年 8 月 8 日 20 点 0 分 0 秒时,INT 脚会输出低电平。此后如清零 INTAF,则 INT脚从低电平变成高电平。 + +(2)频率中断 + +当 INTFE=1时频率中断被允许, INTFE=0 时频率中断被禁止。 + +当设置 INTS1=1、INTS0=0时,即允许频率中断从 INT脚输出,频率中断没有标志位。 + +INT脚输出频率中断由控制寄存器 3 中的 FS3、FS2、FS1、FS0位来选择确定: + +
频率(Hz)FS3FS2FS1FS0
00000
40960010
10240011
640100
320101
160110
80111
41000
21001
11010
1/21011
1/41100
1/81101
1/161110
1秒1111
+ +注:除了 1 秒外,INT 脚输出的频率中断均是由 32768Hz 晶体振荡电路整形及分频得到的;1 秒频率中断是指输出 500ms 低电平、500ms 高电平的方波,其低电平的下降沿与秒进位同步; 在温度补偿时内部数字调整寄存器起作用时,1秒和 1Hz的时长是不相同的。 + +例如:需要 INT 脚输出 1Hz 信号时,可以通过设置位 INTS1=1、INTS0=0、INTFE=1、FS3-FS2-FS1-FS0=1010 得到。 + +## (1)倒计时中断 + +与倒计时中断相关的寄存器是三字节 24bit 的倒数定时器 13H、14H 和 15H, 当控制寄存器 CTR2 中的位 INTDE=1时倒计时中断被允许。 + +倒数定时器的频率源由控制寄存器 CTR2中的位 TDS1、TDS0来选定; + +
TDS1TDS0定时器频率源
004096Hz
011024Hz
+ +当 INTDE=1 且倒数定时器写入一个 24 位自动重置的二进制数后, 倒数定时器会按照TDS1、TDS0选定的频率时间来减一。每次当三字节倒数定时器全为零时,会置倒计时中断的标志位(控制寄存器 1 中的位 INTDF)为 1。 + +当设置 INTS1=1、INTS0=1、IM=0 时,即允许倒计时中断的低电平从 INT 脚输出. 置INTDF=0 时 INT 脚输出变为高电平直到下一次倒计时中断 INT 脚再次变为低电平;当设置INTS1=1、INTS0=1、IM=1 且倒数定时周期大于 250ms 时,则从 INT 脚输出低电平时间为 250ms连续脉冲。 + +当设置 INTDE=0时倒计时中断被禁止或复位。 + +特别的:当重新配置倒计时中断时,需要复位倒计时计数器,即置 INTDE=0,然后再置INTDE=1,才可以启用新的倒计时中断。 + +## 4.4 电池控制寄存器 + +## 4.4.1 IIC 控制寄存器 AGTC(17H) + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
AGTCBATIIC0------0-255
+ +BATIIC: BATIIC=0,VBAT 模式下禁止 IIC 通信;BATIIC=1,VBAT 模式下允许 IIC 通信,该寄存器位上电默认值为 0;其它位赋值均须为 0. + +## 4.4.2 扩展控制寄存器 CRT4(19H): + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
CTR4INTS_E2INTS_E1INTS_E0CONT_BATINTTHEINTTLEINTBHEINTBLE0000_0000
+ +当寄存器 10H 中的{INTS1,INTS0}=00 时,INT 引脚输出扩展以下功能: + +
INTS_E2INTS_E1INTS_E0功能描述
000禁止输出,高阻态
001-
010-
011电池低压报警
100电池高压报警
其他禁止输出,高阻态
+ +VDD模式下,芯片电池电量测量周期为 60S,从每分钟的 3S 开始测量; VBAT模式下,芯片电池电量测量周期为 600S,从分钟的个位为 0 的 3S 时开始测量。 电池电压测量结果存放在寄存器 1AH[7]和 VBAT\_VAL 中。(下同) 例如:1AH=80H,1BH(VBAT\_VAL)=30H,则芯片 Vbat 脚外接电池的电压=130H=304D=3.04V。 + +INTTHE: 固定设置为 0 + +INTTLE: 固定设置为 0 + +INTBHE:电池高压报警使能位 (报警电压值电压值为 3.30V,精度±0.10V),当若INTBHE=1 且检测到的 VBAT 脚电压大于等于 3.3V 时置 BHF 位为 1。 + +INTBLE:电池低压报警使能位(电池报警电压值为 2.20V,精度±0.10V),当若 INTBLE=1且检测到的 VBAT脚电压小于等于 2.2V时置 BLF位为 1。 + +注: + +1.以上两种报警中断均只支持单周期报警中断,不支持周期性报警中断。 + +2. Bit4位默认值为 0;该位赋值均须为 0。 + +## 4.4.3 寄存器 CTR5(1AH) + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
CTR5BAT8_VAL---THFTLFBHFBLF0000_0000
+ +BAT8\_VAL:电池测量结果的最高位 + +BHF:电池电压高压标志位 + +BLF:电池电压欠压标志位(与 0FH寄存器的 BLF 位完全相同,为方便读电池状态而设置)。 + +BHF、BLF 不能通过软件来设置或清除;当 INT 选择为BHF、BLF 输出时, 中断脚 INT的状态和BHF、BLF 状态一致。 + +## 4.4.4 电池电量低八位寄存器(1BH) + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
BAT_VLBAT7_VLBAT6_VLBAT5_VLBAT4_VLBAT3_VLBAT2_VLBAT1_VLBATO_VL0000_0000
+ +电池测量值,若禁止电池测量,则读出的数据为 0,该寄存器只读。 + +1AH[7]即 BAT8\_VAL 与 1BH合起来的 9 位数据的表示电池电量的电压值。 + +如 1AH[7]=1,VBAT\_VAL=35H,则当前所测的电池电量=135H=309(十进制)=3.09V。 + +## 4.5 温度控制寄存器 + +## 4.5.1 温度寄存器 TEMP(16H) + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
TEMPTM7TM6TM5TM4TM3TM2TM1TMO0-255
+ +最高位 TM7 为符号位,举例:TEMP=10H,温度为 16℃,TEMP=FEH,温度为-2℃。 + +在 VDD模式下 60S间隔自动测温一次,电池模式 600S 间隔测温一次,温度值在 0S 时自动更新。 + +## 寄存器(19H)和寄存器 CTR5(1AH)的温度相关位:INTTHE、INTTLE、THF、TLF。 + +INTTLE: 低温报警使能位。INTTLE=1并且芯片测量的温度低于或等于 TEMP\_AL寄存器设定的值时,芯片发出低温报警,置低温报警位 CTR5 中的 TLF 为 1;直到下次测量的温度值高于 TEMP\_AL 寄存器设定的值,TLF 变为 0。若 INTTLE=0,禁止低温报警,TEMP\_AL 所设定的值没有意义,可以作为通用的 SRAM来使用,在这种情况下 TLF一直为 0。 + +INTTHE: 高温报警使能位。INTTHE=1并且芯片测量的温度高于或等于 TEMP\_AH寄存器设定的值时,芯片发出高温报警,置高温报警位 CTR5 中的 THF为 1;直到下次测量的温度值低于 TEMP\_AH 寄存器设定的值,THF 变为 0。若 INTTHE=0,禁止高温报警,TEMP\_AH 所设定的值没有意义,可以作为通用的 SRAM来使用,在这种情况下 THF一直为 0。 + +THF : 高 温 报 警 标 志 位 , 当 寄 存 器 10H 中 的 {INTS1,INTS0}=00 且 19H 中 的{INTS\_E2,INTS\_E1,INTS\_E0}=010 时,INT 脚输出高温报警中断。 + +TLF : 低 温 报 警 标 志 位 , 当 寄 存 器 10H 中 的 {INTS1,INTS0}=00 且 19H 中 的{INTS\_E2,INTS\_E1,INTS\_E0}=001 时,INT 脚输出低温报警中断。 + +## 4.5.2 寄存器 1CH + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
TEMP_ALTEMP7_ALTEMP6_ALTEMP5_ALTEMP4_ALTEMP3_ALTEMP2_ALTEMP1_ALTEMP0_AL0000_0000
+ +低温报警的温度值,低于或等于此温度开始报警。 + +## 4.5.3 寄存器 1DH + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
TEMP_AHTEMP7_AHTEMP6_AHTEMP5_AHTEMP4_AHTEMP3_AHTEMP2_AHTEMP1_AHTEMPO_AH0000_0000
+ +高温报警的温度值,高于或等于此温度开始报警。 + +## 4.5.4 寄存器 1EH + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
TEMP_HIS_LTEMP_L7TEMP_L6TEMP_L5TEMP_L4TEMP_L3TEMP_L2TEMP_L1TEMP_L00111_1111
+ +历史低温数据值,Bit7 为符号位。 + +## 4.5.5 寄存器 1FH + +
名称Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0复位值
TEMP_HIS_HTEMP_H7TEMP_H6TEMP_H5TEMP_H4TEMP_H3TEMP_H2TEMP_H1TEMP_H01000_0000
+ +历史高温数据值,Bit7 为符号位。 + +## 4.5.6 寄存器 20H~25H + +分别记录发生最低温的历史时间:年、月、日、星期、小时、分钟。 + +## 4.5.7 寄存器 26H~2BH + +分别记录发生最高温的历史时间:年、月、日、星期、小时、分钟。 + +## 4.6 用户 RAM(2CH\~71H):70 字节的用户数据 RAM + +## 4.7 ID码(72H\~79H):8 字节的模块身份识别码,包含生产日期、内部批号、内部序号等 + +
ID码地址72H73H74H75H76H77H78H79H
说明生产年份:00~99生产月份:1~12生产日份:1~31生产机台编号四位生产工单号:如A394.工单内序号:0000~9999
+ +## 4.8 充电选择寄存器(18H): + +
Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
EN_ChargeCharge1Charge0
0-----11
+ +EN\_Charge:0 禁止充电功能;1允许充电功能;复位值为 0,即禁止充电功能。 + +Charge1 Charge0 描述 + +0 10k + +1 5k + +0 2k + +1 1 无穷大,断开 + +对于该寄存器,SD2506API出厂均配置成 82H.为了避免在停电时间过长导致电池电量耗光、18H的值被改变,强烈建议用户的程序在每一次上电时重置 18H寄存器的值为 82H。(充电功能开启后,模块会增加大约 80uA 左右的 VDD工作电流。) + +WRTC1、WRTC2、WRTC3 位: 寄存器(00H\~71H)写允许位。即 WRTC1=1、WRTC2=1、WRTC3=1时写允许.注意置位有先后顺序,先置 WRTC1 为 1,后置 WRTC2、WRTC3 为 1;当 WRTC1=0、 + +WRTC2=0、WRTC3=0 时则写禁止,同样置位有先后顺序,先置 WRTC2、WRTC3 为 0,后置WRTC1为 0。当写禁止时,除了以上三位可以写以外,从 00H 到 79H所有的寄存器均不可以写。写禁止并不影响读操作。 + +特别的:当写允许时,如需要赋值与写保护位相关的寄存器 0FH、10H,则要注意对应的位WRTC1、WRTC2、WRTC3 的赋值,这三个位只能为 1 而不可为 0,否则会造成写禁止而数据写不进相应的寄存器.又因为 0F 的寄存器其它位均为标志位,所以建议写允许时赋值 0F 寄存器的值可以定为 FFH,写禁止时赋值 0F 寄存器的值可以定为 7BH。 + +ARST位: 自动复位使能位.对控制寄存器 1的 INTAF、INTDF、BAT位的自动复位进行使能/禁止. 当 ARST=1 时,对控制寄存器 1 进行一次有效的读操作后,以上三个状态位均复位为”0”.若 ARST=0,则需要对 INTAF、INTDF、BAT 位进行手动复位方可清零。 + +FOBAT 位:FOBAT=0 时,当处于 VBAT 模式下,INT 脚输出禁止;FOBAT=1 时,当处于 VBAT 模式下,INT脚输出允许.该位在 VDD模式下不起作用。(要注意在 VBAT 模式下 INT脚输出会引起电池的消耗) + +RTCF位:上电位,全部电源失效后再上电则该位置”1”,为只读位.上电后的第一次有效写(只要写一个字节即可)就可以将 RTCF位清为”0”。 + +SYS位:RTC 芯片上电配置完成标志位(只读位)。系统上电 80ms 后,SYS置 1,在 SYS置 1 之前,芯片输出禁止,IIC不可操作。 + +OSC\_RDY位:RTC 芯片内部起振标志位(只读位),该位在内部振荡器起振 0.5 秒后该位置为 1。 + +OSF:停振标志位,OSF=1,表示之前有过停振发生。默认值为 0。 + +BLF:电池电压欠压标志位,当电池电压低于 2.2V 时此位置"1"(不论是 VDD 模式还是VBAT 模式)。 + +PMF:电源模式标志位,当电源模式为 VDD 模式时 PMF=0; 当电源模式为 VBAT 模式时PMF=1。 + +F32K:32K 输出控制位---32K=0,允许输出;32K=1,禁止输出;默认值为 0。 + +## 5.串行 IIC 接口 + +## 5.1 SD2506API 通过两线式 IIC串行接口方式接收各种命令并读写数据。两线式串行 IIC接口方式描述如下: + +两线式串行 IIC接口方式描述如下: + +## (1)开始条件 + +当 SCL处于高电平时,SDA 由高电平变成低电平构成一个开始条件,对 SD2506API 的所有操作均必须由开始条件开始。 + +## (2)停止条件 + +当 SCL处于高电平时,SDA 由低电平变成高电平构成一个停止条件,对 SD2506API 的所有操作均停止,系统进入待机状态。 + +![](images/a09f66458c45ec02deccf90c15d3a688911fd27ed77b4a962be9ba203892c53f.jpg) + +
+text_image + +tsu:sta thd:sta +t:su:sto +SCL +SDA +start +stop +
+ +实时时钟串行接口 + +## (3)数据传输 + +当 SCL为低电平,且 SDA线电平变化时,则数据由 CPU传输给 SD2506API(高位在前、低位在后,下同);当 SCL为高电平,且 SDA电平保持不变时,则 CPU读取 SD2506API 发送来的数据:当 SCL为高电平,且 SDA电平变化时,SD2506API收到一个开始或停止条件。 + +![](images/08aede159d16d33946dec4ebdee8cc93a410f3d1a988a634080f893f17a0e2e5.jpg) + +
+text_image + +tsu:dat +thd:dat +SCL +SDA +
+ +实时时钟数据传输时序 + +## (4)确认 + +数据传输以 8 位序列进行。SD2506API 在第九个时钟周期时将 SDA置位为低电平,即送出一个确认信号(Acknowledge bit,以下简称“ACK”),表明数据已经被其收到。 + +![](images/28b585ec7bf8f89e0d12012308181ff36087e3cfd5e90264ae13acaf82710cb4.jpg) + +
+text_image + +SCL (CPU) +1 +8 +9 +SDA (CPU) +SDA (SD2507A) +start +tpd +tdh +
+ +实时时钟确认信号 + +## 5.2 数据/指令传输格式 + +当 CPU 发出开始条件与实时时钟建立连接后, CPU 首先通过 SDA 总线连续输出 7 位器件地址和 1位读/写指令来唤醒 SD2506API。 + +## (1) 器件代码: + +
Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
0110010R/W
+ +其中高 7 位 BIT7\~BIT1 称“器件代码”,它代表实时时钟的器件地址,固定为“0110010”;BIT0 为读/写位,”1”为读操作,”0”为写操作。 + +## (2) 数据传输格式 + +在数据发送/接收时停止信号到来时,将结束其数据传输,同时内部 5 位地址归零(注:内部 5 位地址的缺省值为 00000B)。如果只有开始信号,而没有结束信号,接着重新产生起始信号,则还要重新设置器件代码(在传输方向需要改变时,就用这种传输方式,如下面的读数据方式 1)。 + +主设备向从设备写入数据过程如下图: + +
S01100100A数据A数据AP
寻址字节
+ +主设备向从设备直接读取数据过程如下图: + +
S01100101A数据A数据A_P
寻址字节
+ +数据传输时改变其传输方向过程图: + +![](images/2c2b3daaace1b174f3eae6b385726f94471c56654d71420ac50f9bee10eae478.jpg) + +
+text_image + +S 0 1 1 0 0 1 0 0 A 数据 A Sr 0 1 1 0 0 1 0 1 A +寻址字节 写 寻址字节 读 +数据 A 数据 A_ P +CPU到时钟 时钟到CPU A A A_ 响应信号 +S 起始信号 P 停止信号 Sr 重新起始信号 +通知从设备以结束读数据 +
+ +(3)SD2506API 数据传输的写模式 + +先送 7 位器件地址(0110010),第 8 位送入写命令(“0”), 第 9 位是 SD2506API 的响应位(ACK),SD2506API 进入写状态。 + +接下来一个字节的前 8 位确定 SD2506API 的内部地址(00H\~79H), , 第 9 位是 SD2506API的响应位。 + +开始写数据,每写完1个字节的数据之后,都经过1位的响应信号才能写下1字节的数据;如果要结束写数据过程,则在 ACK 后送出停止命令即可。 + +SD2506API 写数据示例(向 14H,15H 地址写数据): + +
S01100100A00010100A数据A数据AP
寻址字节设置14H内部地址14H15H
+ +![](images/0f33608a662c2eb50849d4282cd88c7b2d68111caefee4430b8d17f282499e46.jpg) + +特别注意: + +1.除了 WRTC1、WRTC2、WRTC3 三个写允许位,对寄存器(00H\~71H)的写操作必须确认模块处于写允状态,否则写无效。 +2.写时间同步:每次对实时时间秒寄存器的写操作时,当秒数据的 8个 bit完全写入并收到 ACK信号后,就会对秒以下的内部计数器清零,使时间同步。 +3. 从当前地址开始,每次读写完一个字节地址自动加 1。 +4.如果写入的时间数据不存在,则不改写相对应的时间寄存器的值。 +5.为了提高数据的可靠性,当写完成后,应将模块置于写禁止状态。(参见 5.7) + +(4)SD2506API 数据传输的读模式 + +SD2506API 有两种读数据方法: + +I)读方法 1:从指定的内部地址中读取数据。 + +. 与写模式的前两步一样。 + +. 重新发出开始命令以改变两线接口数据传输方向。 + +. 再送 7 位器件地址(0110010),第 8 位送入读命令(“1”), 第 9 位是 SD2506API 的响应位(ACK),SD2506API 进入读状态。 + +. 开始读数据,每读完1个字节的数据之后,CPU都要送出1位的响应信号(ACK,低电平)才能读下1字节的数据;如果想要结束读数据过程,则CPU要送出1位的响应信号(ACK\_,高电平), ACK\_后送出停止命令即可。 + +SD2506API 读数据方法 1 示例(从 7H\~9H 地址读取数据): + +![](images/7bf6b3c945980e17b4e2859485f424d2cc287acc86a7967499ad56b0c4eb16ce.jpg) + +
+text_image + +S 0 1 1 0 0 1 0 0 A 0 0 0 0 0 1 1 1 A +寻址字节 写 设置7H内部地址 +Sr 0 1 1 0 0 1 0 1 A 数据 A 数据 A 数据 A_ P +寻址字节 读 7H 8H 9H +CPU到时钟 时钟到CPU A A A_ +通知时钟以结束读数据 +S 起始信号 P 停止信号 Sr 重新起始信号 +
+ +II)读方法 2:直接读取数据(从内部地址 00H开始) + +. 开始信号后,先送 7 位器件地址(0110010),第 8 位送入读命令(“1”), 第 9 位是SD2506API 的响应位(ACK),SD2506API 进入读状态。 + +. 每读完 1 个字节的数据之后,CPU 都要送出 1 位的响应信号(ACK,低电平)才能读下 1字节的数据;如果想要结束读数据过程,则CPU要送出1位的响应信号(ACK\_,高电平), ACK\_后送出停止命令即可。 + +SD2506API 读数据方法 2 示例(从 00H 地址开始读取数据): + +![](images/3648bb8b1603ba26ab34070418559365f9df547a1dc36cf7879a3f4d489d46d1.jpg) + +(5)SD2506API在特殊条件下的数据传输 + +为了保证读写数据的有效性,SD2506API 的两线通信开始到结束仅在此 0.5S 秒之内,如此可避免总线挂死的现象。 + +因此在 SD2506API 中,IIC 通信方式会在第一个开始信号(START)到来之后的 0.5 秒之内自动终止本次通信。所以,要注意: 从开始信号进行读/写数据,直到停止信号, 读/写操作 + +过程必须在 0.5秒之内完成。 + +特别:在进入 VBAT 模式后 IC会禁止 IIC总线的通信。 + +## 6.备用电源切换电路 + +SD2506API具有后备电池自动切换功能:当模块检测到主电源 VDD掉到后备电池电压以下且 VDD小于 2.4V时自动转为由内部的后备电池供电,模块进入后备电池 VBAT 供电模式;当 VDD大于内部电池电压或 VDD大于 2.4V,则模块会转为由 VDD供电,模块进入 VDD供电模式。(内置电源模式指示位 PMF,VDD 模式时 PMF=0,VBAT 模式时 PMF=1)。 + +电源失效检测: + +SD2506API 有一个实时时钟失效位(RTCF),用于检测总电源失效。它在器件丢失所有电源(VDD 和后备电池)之后使用户可以确定器件是否已上电。 + +## 7.内部电池充电电路 + +SD2506API 内置电池充电电路,当 VDD 电压正常时,内部充电自动进行直至电池充满。(内部充电过程不需要用户干预,会自动完成)。 + +内部充电电池一次充满时的电量为 5.5mAh,在外电源掉电的常温情况下时钟走时时间在 8 个月左右。电池可以满充 100 次(注:满充的定义是指将电池从 0V 充到 3.0V),常温下等效总电量为 550mAh;如果从电池电量的 90%开始充电,则电池的充电此数为 1000次。 + +## 特别提示: + +1.为了保证充电功能的正常运行,用户的程序须在每一次上电时重置 18H 寄存器的值为 82H。 +2.对内置充电电池的时钟模块不上电充电时间不能超过 8 个月,不要等电池的电耗光后再去充电,否则会减少电池的使用寿命。 + +## 8.上电复位 + +模块内部具有上电复位电路,当所有电源包括内部电池完全掉电再上电时会复位内部寄存器,复位操作对内部部分寄存器进行置初值但不包括实时时钟数据寄存器、通用 RAM。 + +## 9.使用说明 + +1.为了防止电路噪声问题,请在此模块的旁边放置两个旁路电容,分别是 0.1uF 电容和10uF 电容。 +2.为了防止干扰,在 PCB 制作时请保证模块底部无大电流信号通过,最好能铺地。 + +## 10. 应用参考电路 + +![](images/81a2cbd724548c83235e88d8d54c5e2a059b50485d5b0307744c505079c856a4.jpg) + +
+text_image + +VDD +C2 10uF ++ +C1 100nF +U1 +TEST VDD +NC INT +NC SCL +GND SDA +1 8 R1 +2 7 6 R2 +3 5 10K 10K +
+ +## 11.极限参数 + +VDD 、VBAT 、SCL、SDA 和 INT 引脚上的电压(相对于地)……… -0.5V 至 7.0V引线温度(焊接,5秒)…… 350℃ + +注: + +1.因模块内置电池本体的表面温度不能超过 85℃,本产品不可以采用回流焊或波峰焊方式,最好采用烙铁焊接方式。 +2.强度超出所列的极限参数可能导致器件的永久性损坏。这些仅仅是极限参数,并不意味着在极限条件下或在任何其它超出推荐工作条件所示参数的情况下器件能有效地工作。延长在极限参数条件上的工作时间会影响器件的可靠性。 + +## 12.直流特性 + +
符号参数条件最小值典型值最大值单位备注
$V_{DD}$ 主电源2.75.5V
$I_{DD1}$ 电源电流 $V_{DD}=5V$ 80uA2mA1
$V_{DD}=3.3V$ 80uA2mA
$I_{BAT}$ 电池供电电流 $V_{BAT}=3V$ 800nA
$I_{L1}$ SCL的输入漏电流100nA
$I_{LO}$ SDA上的I/O泄漏电流100nA
$V_{BATHYS}$ VBAT和VDD之间切换的迟滞电压300mV
INT/SDAVOLINT/SDA低电平输出电压 $V_{DD}=5V$ $I_{OL}=0.5mA$ 0.10.20.3V
+ +Note1:此时最大电流 2mA主要是充电电流.当内部电池电压为 0V时,充电电流最大。当充电功能打开时,会增加 80uA的功耗。 + +## 13.掉电时序(温度:-30℃至+80℃) + +
符号参数条件最小值典型值最大值单位注意
$V_{DD\ br}$ $V_{DD}$ 下电速率10V/ms
+ +## 14.交流特性 + +
符号参数条件标准模式(fSCL=100kHz)快速模式(fSCL I=400kHz)单位
最小值典型值最大值最小值典型值最大值
fSCLSCL 频率100400kHz
VILSDA 和 SCL 低电平输入电压-0.30.3×VDD-0.30.3×VDDV
VIHSDA 和 SCL 高电平输入电压0.7×VDDVDD+0.30.7×VDDVDD+0.3V
VhysSDA 和 SCL 施密特触发输入滞后0.05×VDD0.05×VDDV
VOL低电平输出电压SDA 输出低电平状态下,吸收 2mA 电流时的电压0.40.4V
CpinSDA 和 SCL引脚电容TA=25°C f=1MHzVDD=5V VIN=0V VOUT=0V1010pF
tINSDA 和 SCL 输入端的脉冲宽度抑制时间10050ns
tAASCL 下降沿到 SDA 输出数据有效SCL 下降到 0.3×VDD,直到 SDA 不在 0.3×VDD至 0.7×VDD区间。900900ns
tBUF总线在 STOP 和 START之间的空闲时间SDA 在 STOP 条件下上升到 0.7×VDD,在开始条件下下降到 0.7×VDD。47001300ns
tLOW时钟低电平时间在 0.3×VDD处测量47001300ns
tHIGH时钟高电平时间在 0.7×VDD处测量4000600ns
tSU:STAIIC 启动信号的建立时间SCL 上升到 0.7×VDD至 SDA 下降沿到 0.7×VDD4700600ns
tHD:STAIIC 停止信号的保持时间在 SDA 下降沿到 0.3×VDD, SCL 下降沿到 0.7×VDD4000600ns
tSU:DAT输入数据的建立时间从 SDA 不在 0.3×VDD至 0.7×VDD范围,到 SCL 上升沿的 0.3×VDD250100ns
tHD:DAT输入数据保持时间SCL 下降沿的 0.3×VDD,到 SDA 在 0.3×VDD至 0.7×VDD区间00ns
tSU:STO停止条件的建立时间从 SCL 上升沿经过 0.7×VDD,到 SDA上升沿 0.3×VDD4000600ns
tDH数据输出的保持时间从 SCL 下降沿 0.7×VDD,到 SDA 0.3×VDD至 0.7×VDD区间00ns
$t_{R}$ SDA 和 SCL 的上升时间 $0.3 \times V_{DD}$ 至 $0.7 \times V_{DD}$ 区间1000300ns
$t_{F}$ SDA 和 SCL 的下降时间 $0.3 \times V_{DD}$ 至 $0.7 \times V_{DD}$ 区间300300ns
+ +IIC Timing Chart +![](images/28e2f0df5c853c92033967c174cdd1cf7055764c95077034acfde0e7e1c3edae.jpg) + +
+text_image + +tSU:STA +tHD:STA +tR +tF +tHIGH +tLOW +tSU:DAT +tHD:DAT +1/fscL +tSU:STO +tBUF +SDAIN +SDAOUT +tAA +tDH +
+ +15.频率误差&温度关系曲线(与没有温补功能的时钟模块进行对比): + +![](images/465951ede3196713718e34db1b6885a5627c50aa0ed981246efb5dedca30d8e9.jpg) + +
+funnel + +| 温度 \(({}^{\circ}C)\) | 具温补的SD2506AP温度-精度特性 \(( \times 10^{-6})\) | 没有温补的RTC温度-精度特性 \(( \times 10^{-6})\) | +| --- | --- | --- | +| -40 | ~18 | -140 | +| -30 | ~10 | ~-100 | +| -20 | ~5 | ~-80 | +| -10 | ~2 | ~-60 | +| 0 | 0 | ~-40 | +| 10 | ~-2 | ~-20 | +| 20 | ~-5 | 0 | +| 30 | ~-8 | ~-20 | +| 40 | ~-10 | ~-60 | +| 50 | ~-12 | ~-80 | +| 60 | ~-14 | ~-100 | +| 70 | ~-16 | ~-120 | +| 80 | ~-18 | -140 | +
+ +16.SD2506API充放电曲线(图中电压均是指内部电池电压) + +![](images/c8865d0318313374ef1721bb3a1bb64adf2fd418e65c8db9bd35ca5b6dc6a2ca.jpg) + +
+line + +| 充电时间 (h) | 充电电流 (mA) | 充电电压 (V) | +| --- | --- | --- | +| 0 | ~0.9 | ~2.0 | +| 05 | ~0.15 | ~2.8 | +| 15 | ~0.1 | ~2.9 | +| 25 | ~0.08 | ~2.95 | +| 35 | ~0.06 | ~2.98 | +| 45 | ~0.05 | ~3.0 | +| 55 | ~0.04 | ~3.02 | +| 65 | ~0.03 | ~3.03 | +| 75 | ~0.02 | ~3.04 | +
+ +![](images/ee72a8996b2a00d57ebe49c8479cdb0c9f9569d24dbf984d662c8c7258869417.jpg) + +
+line + +| 放电时间 (weeks) | 电压 (V) | +| --- | --- | +| 0 | 3.2 | +| 0.3 | ~2.75 | +| 06 | ~2.65 | +| 09 | ~2.62 | +| 12 | ~2.6 | +| 15 | ~2.58 | +| 18 | ~2.52 | +| 21 | ~2.4 | +| 24 | ~2.2 | +| 27 | 2.0 | +
+ +SD2506API 放电曲线 + +## 17.模块顶部字符说明 + +![](images/3669a9ab2b6d709e7e4d35a4ae9188009fa344f4b60844441ff055efa7eccf1c.jpg) + +## 18.封装尺寸(DIP8,单位:mm;尺寸误差±0.2mm,特别说明除外。) + +![](images/41580fc9cac8fc2a6b4cfef8dad118f1b596f5326d67ff0ef958611e4b3b1ae0.jpg) + +
+text_image + +11.2 +6.5 +2.54 +0.5 +4.5 +11.2 +7.6 +0.3 +11.2 +
+ +SD2506 封装尺寸(管脚尺寸:0.5\*0.3mm,管脚公差±0.05mm) + +##  编后语 + +感谢您阅读本资料。由于经验和水平的欠缺,本文难免有错误和遗漏。如果您在使用过程中发现错误或不恰当的地方,请拨打电话:0755-83246178 或请 E-mail:support@whwave.com.cn,我们将尽快予以答复。 + +谢谢您的支持与合作! + +注: + +本资料中的内容如有变化,恕不另行通知。 + +本资料提供的应用线路及程序仅供参考,本公司不承担由此而引起的任何损失。 + +由于本公司的产品不断更新和提高,希望您经常与本公司联系,以索取最新资料。 + +本公司不承担在任何使用过程中引起的侵犯第三方专利和其它权利的责任。 + +注:本文档受中国版权法保护,非授权禁止拷贝、复制、引用或传播 + +(SD 及 WAVE 均为我公司注册商标) + +深圳市兴威帆电子技术有限公司 + +
版本号修改时间修改记录修改人
V2.02025.08.29修改倒计时部分CHENMY
V2.12026.02.03修改封装尺寸部分CHENMY
+ +附录: + +## 一. SD2506系列应用中硬件注意事项: + +(1) 对 SD2506 及 MCU 的电源\~地之间加 104 电容去高频。 +(2) 对SD2506及MCU所在的板数字电源\~地的输入端加220uF以上的电解及104电容去除电源扰动. +(3) 为了防止干扰,在 PCB 制作时请保证模块底部无大电流信号通过,最好能铺地. +(4) 对MCU的复位端尽量采用可靠的复位方式,而摒弃阻容复位或直接连到VDD的方式.以下推荐廉价的三极管复位方式,当然用电压检测器或专用复位电路就更好啦. + +![](images/4a911065bebf54af10afdb0752802a3b875abcff3cc81619e5b9403ea2fcc977.jpg) +图中 R2,R3 为分压电阻,其选值可用以下公式: + +Vbe/Vrst=R2/(R2+R3) + +其中:Vbe为三极管 b极和 e 极之间导通电压 + +Vrst为单片机的复位电压 + +C1为延时电容 + +D1为延时电容的放电二极管,可选用. + +## 二. SD2506系列应用中软件注意事项 + +1) 软件上电开始做一个几百毫秒的延时,等 MCU端口稳定后再去进行读写操作。 +2) 时钟最多半秒才读一次:这样做主要目的是考虑到时间数据的改变需要 1S,频繁去读的话是在做无用功,不但会加大电源功耗,而且会引入干扰。 +3) IIC 总线”START”里:在置 SDA 为高后要再判断 SDA 是否为高,即 SDA 是否被箝位为低,否则等 SDA 线 +置高。在写命令字时:要判断ACK 是否正常,否则退出 + +4)IIC 总线”STOP”里:在置 SDA 为高后要再判断 SDA 是否为高,即 SDA 是否被箝位为低,否则多置 SCL 脉 + +冲让 SDA 线释放为高.在写命令字时:要判断ACK 是否正常,否则退出,不要再进行下面的操 + +作。 + +## 三. 有关 SD2506 的一些问题回答 + +## (1) 时钟精度: + +SD2506 的精度指标为常温 25 度下±3.8ppm,即年误差少于 2 分钟. + +出厂之前对每一只 SD2506 都用超高精度的仪器和严格的程序做了校准,所以能保证精度.有人说他拿到 SD2506 的精度好像不准,一般问题出在参考时钟上,通常可用电信 12117台作基准来验证,但如用电脑那就差远了,因为电脑的时钟精度一般都不高,通常大于 30ppm.最好用网络校时软件. + +手机安卓版网络/GPS校时软件: + +https://www.whwave.com.cn/filedownload/420894 + +## (2) 温度对精度的影响: + +SD2506时钟具有温度补偿功能。 \ No newline at end of file diff --git a/docs/TPAFE5160.md b/docs/TPAFE5160.md new file mode 100644 index 0000000..ea6d09c --- /dev/null +++ b/docs/TPAFE5160.md @@ -0,0 +1,777 @@ +# 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Features + +• 8 Simultaneously Sampled Inputs +- Single 5-V Analog Supply and 1.71-V to 5-V $V_{DRIVE}$ +• 16-Bit ADC with 350 kSPS on All Channels +• Bipolar Inputs Ranges: ±10 V, ±5 V +- Analog Input Clamp Protection +• 1-MΩ Analog Input Impedance +- On-Chip Reference and Buffer +• On-Chip Oversampling Digital Filter +- SPI Compatible Interface +• Temperature Range: -40°C to 125°C +• Package: LQFP10×10-64 + +## Applications + +- Power Line Monitor +• Power Line Protection Relays +- Motor Control +• Data Acquisition System (DAS) +• Industrial Automation and Controls + +## Description + +The TPAFE5160 is a 16-bit, 8-channel simultaneous sampling, successive approximation (SAR) ADC. Each channel has a complete analog front end, as well as an ADC operating at 350 kSPS per channel. The analog front end features the input clamp, a programmable gain amplifier (PGA) with a high input impedance of 1 MΩ, a low pass filter, and an ADC input driver. + +The device features an internal precision reference with buffer to drive the ADC. A digital interface supports serial, parallel and parallel byte communication, which can be used with various host controllers. + +The TPAFE5160 can accept ±10-V or ± 5-V true bipolar inputs with a single 5-V supply. Also, the high input impedance allows direct connection to transformers or other sensors without external driver circuits. + +The zero-latency conversion with high performance also makes the device suitable for industrial automation and control applications. + +Typical Application Circuit +![](images/2762ffa4db2bc51143440506cde64b960997e1a64f0903688628d389c1dc0a9d.jpg) + +
+flowchart + +This diagram illustrates the architecture and signal flow of an electronic circuit, specifically detailing the signal processing flow from input AIN to digital interface, including amplification, ADC driver, and feedback loops. +
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Table of Contents + +Features....1 + +Applications....1 + +Description....1 + +Typical Application Circuit....1 + +Product Family Table....3 + +Revision History....4 + +Pin Configuration and Functions....5 + +Specifications....8 + +Absolute Maximum Ratings (1)....8 + +ESD, Electrostatic Discharge Protection....8 + +Recommended Operating Conditions....8 + +Thermal Information....9 + +Electrical Characteristics....10 + +Timing Specifications....13 + +Timing Diagrams....16 + +Detailed Description....18 + +Overview....18 + +Feature Description....18 + +Device Functional Modes....19 + +Device Modes of Operation....21 + +Application and Implementation....24 + +Tape and Reel Information....25 + +Package Outline Dimensions....26 + +LQFP10x10-64....26 + +Order Information....27 + +IMPORTANT NOTICE AND DISCLAIMER....28 + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +Product Family Table + +
Order NumberInput Range (V)Package
TPAFE5160SI08-QP7R±10, ±5LQFP10×10-64
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +Revision History + +
DateRevisionNotes
2021-11-15Rev.Pre.0Pre-release version.
2022-03-01Rev.Pre.1Updated the diagram and the EC table.
2022-05-10Rev.Pre.2Updated the EC table.
2022-05-22Rev.Pre.3Updated the tape and reel parameters.
2022-06-20Rev.Pre.4Updated the EC table.
2022-11-21Rev.Pre.5Updated Timing Specifications and Timing Diagrams.
2023-07-10Rev.A.0Initial released version.
2024-11-26Rev.A.1Updated to a new datasheet format.Updated Timing Specifications.
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Pin Configuration and Functions + +![](images/2aeac05f6d00f0027a9c2e6424449079d7a39a39f2bd6ffad63e39265066bdef.jpg) + +
+text_image + +AIN_8GND +AIN_8P +AIN_7GND +AIN_7P +AIN_6GND +AIN_6P +AIN_5GND +AIN_5P +AIN_4GND +AIN_4P +AIN_3GND +AIN_3P +AIN_2GND +AIN_2P +AIN_1GND +AIN_1P +64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 +AVDD 1 +AGND 2 +OS0 3 +OS1 4 +OS2 5 +PAR/SER/BYTE SEL 6 +STBY 7 +RANGE 8 +CONVSTA 9 +CONVSTB 10 +RESET 11 +RD/SCLK 12 +OS 13 +BUSY 14 +FRSTDATA 15 +DB0 16 +48 AVDD +47 AGND +46 REF/GND +45 REF/CAPB +44 REF/CAPA +43 REF/GND +42 REF/IN/REFOUT +41 AGND +40 AGND +39 REGCAP2 +38 AVDD +37 AVDD +36 REGCAP1 +35 AGND +34 REF/SEL +33 DB15/BYTE SEL +17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 +DB1 DB2 DB3 DB4 DB5 DB6 DB7 DB8 DB9 DB10 DB11 DB12 DB13 DB14/HBEN +
+ +Table 1. Pin Functions + +
PinI/ODescription
No.Name
1AVDDPAnalog supply pin.
2AGNDPAnalog ground pin.
3OS0DIOversampling control pin.
4OS1DIOversampling control pin.
5OS2DIOversampling control pin.
6 $\overline{PAR/SER/BYTE SEL}$ DIControl pin to select the serial, parallel, or parallel byte interface mode.
7 $\overline{STBY}$ DIControl pin to select the standby or shutdown mode, active low.
8RANGEDIMulti-function logic input pin:When STBY is low, this pin selects between the standby and shutdown modes.When STBY is high, this pin selects an input range of ±10 V or ±5 V.
9CONVSTADIActive high logic input to control the start of the conversion for the first half count of the input channels of the device.
10CONVSTBDIActive high logic input to control the start of the conversion for the second half count of the input channels of the device.
11RESETDIActive high logic input to reset the digital logic of the device.
12 $\overline{RD/SCLK}$ DIMulti-function logic input pin:This pin is active-low ready input pin in the parallel and parallel byte interface.This pin is the clock input pin in the serial interface mode.
13 $\overline{CS}$ DIActive low logic input chip-select signal.
14BUSYDOActive high digital output indicating ongoing conversion.
15FRSTDATADOActive high digital output indicating data read back from channel 1 of the device.
16DB0DOData output DB0 (LSB) in the parallel interface mode.
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
PinI/ODescription
No.Name
17DB1DOData output DB1 in the parallel interface mode.
18DB2DOData output DB2 in the parallel interface mode.
19DB3DOData output DB3 in the parallel interface mode.
20DB4DOData output DB4 in the parallel interface mode.
21DB5DOData output DB5 in the parallel interface mode.
22DB6DOData output DB6 in the parallel interface mode.
23DVDDPDigital supply pin; decouple with AGND on pin 26.
24DB7/ DOUTADOMulti-function logic output pin:This pin is data output DB7 in the parallel and parallel byte interface mode.This pin is a data output pin in serial interface mode.
25DB8/ DOUTBDOMulti-function logic output pin:This pin is data output DB8 in the parallel and parallel byte interface mode.This pin is a data output pin in the serial interface mode.
26AGNDPAnalog ground pin.
27DB9DOData output DB9 in the parallel interface mode.
28DB10DOData output DB10 in the parallel interface mode.
29DB11DOData output DB11 in the parallel interface mode.
30DB12DOData output DB12 in the parallel interface mode.
31DB13DOData output DB13 in the parallel interface mode.
32DB14/ HBENDOMulti-function logic input or output pin:This pin is data output DB14 in the parallel interface mode.This pin is a control input pin for byte selection (high or low) in the parallel byte interface mode.
33DB15/ BYTE SELDOMulti-function logic input or output pin:This pin is data output DB15 (MSB) in parallel interface mode.This pin is an active high-control input pin to enable the parallel byte interface mode.
34REFSELDIActive high logic input to enable the internal reference.
35AGNDPAnalog ground pin.
36REGCAP1AOOutput pin 1 for the internal voltage regulator; decouple separately to AGND using a 1-μF capacitor. Typical 4 V.
37AVDDPAnalog supply pin.
38AVDDPAnalog supply pin.
39REGCAP2AOOutput pin 2 for the internal voltage regulator; decouple separately to AGND using a 1-μF capacitor. Typical 4 V.
40AGNDPAnalog ground pin.
41AGNDPAnalog ground pin.
42REFIN/ REFOUTAIOThis pin acts as an internal 2.5 V reference output when REFSEL is high.This pin functions as an input pin for the external reference when REFSEL is low; decouple with REFGND on pin 43 using a 10-μF capacitor.
+ +16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
PinI/ODescription
No.Name
43REFGNDPReference GND pin. This pin must be shorted to the analog GND plane and decoupled with REFIN/REFOUT on pin 42 using a 10-μF capacitor.
44REFCAPAAOReference amplifier output pins. This pin must be shorted to REFCAPB and decoupled to AGND using a low ESR, 10-μF ceramic capacitor. Typical 4 V.
45REFCAPBAOReference amplifier output pins. This pin must be shorted to REFCAPA and decoupled to AGND using a low ESR, 10-μF ceramic capacitor. Typical 4 V.
46REFGNDPReference GND pin. This pin must be shorted to the analog GND plane and decoupled with REFIN/REFOUT on pin 42 using a 10-μF capacitor.
47AGNDPAnalog ground pin.
48AVDDPAnalog supply pin.
49AIN_1PAIOAnalog input channel 1: positive input.
50AIN_1GNDAIOAnalog input channel 1: negative input.
51AIN_2PAIOAnalog input channel 2: positive input.
52AIN_2GNDAIOAnalog input channel 2: negative input.
53AIN_3PAIOAnalog input channel 3: positive input.
54AIN_3GNDAIOAnalog input channel 3: negative input.
55AIN_4PAIOAnalog input channel 4: positive input.
56AIN_4GNDAIOAnalog input channel 4: negative input.
57AIN_5PAIOAnalog input channel 5: positive input.
58AIN_5GNDAIOAnalog input channel 5: negative input.
59AIN_6PAIOAnalog input channel 6: positive input.
60AIN_6GNDAIOAnalog input channel 6: negative input.
61AIN_7PAIOAnalog input channel 7: positive input.
62AIN_7GNDAIOAnalog input channel 7: negative input.
63AIN_8PAIOAnalog input channel 8: positive input.
64AIN_8GNDAIOAnalog input channel 8: negative input.
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Specifications + +## Absolute Maximum Ratings (1) + +All test conditions: $T_{A} = 25^{\circ}C$ , unless otherwise noted. + +
ParameterMinMaxUnit
AVDD to AGND-0.37V
DVDD to DGND-0.37V
AGND to DGND-0.30.3V
Analog Input Voltage to AGND-1515V
Digital Input to DGND-0.3DVDD + 0.3V
REFIN to AGND-0.3AVDD + 0.3V
Input Current to Any Pin Except Supplies-1010mA
$T_J$ Maximum Junction Temperature-40150°C
$T_A$ Operating Temperature Range-40125°C
$T_{STG}$ Storage Temperature Range-65150°C
$T_L$ Lead Temperature (Soldering, 10 sec)260°C
+ +(1) Stresses beyond those listed under Absolute Maximum Ratings may cause permanent damage to the device. Exposure to any Absolute Maximum Rating condition for extended periods may affect device reliability and lifetime. +(2) This data was taken with the JEDEC low effective thermal conductivity test board. +(3) This data was taken with the JEDEC standard multilayer test boards. + +ESD, Electrostatic Discharge Protection + +
SymbolParameterConditionMinimum LevelUnit
HBMHuman Body Model ESD for all pins except analog input pinsANSI/ESDA/JEDEC JS-001 (1)±5000V
HBMHuman Body Model ESD for analog input pins onlyANSI/ESDA/JEDEC JS-001 (1)±7000V
CDMCharged Device Model ESDANSI/ESDA/JEDEC JS-002 (2)±1500V
+ +(1) JEDEC document JEP155 states that 500-V HBM allows safe manufacturing with a standard ESD control process. +(2) JEDEC document JEP157 states that 250-V CDM allows safe manufacturing with a standard ESD control process. + +Recommended Operating Conditions + +
ParameterMinTypMaxUnit
AVDDAnalog Supply Voltage4.7555.25V
DVDDDigital Supply Voltage1.713.3AVDDV
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +Thermal Information + +
Package Type $\theta_{JA}$ $\theta_{JC}$ Unit
LQFP10×10-64467.8°C/W
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Electrical Characteristics + +All test conditions: $V_{REF} = 2.5$ V external/internal, AVDD = 4.75 V to 5.25 V, $V_{DRIVE} = 1.71$ V to AVDD, $f_{SAMPLE} = 350$ kSPS, $T_{A} = -40^{\circ}C$ to $125^{\circ}C$ , Low Bandwidth Mode, unless otherwise noted. + +
SymbolParameterTest conditionMinTypMaxUnit
Dynamic Performance
SNRSignal-to-Noise Ratiofin = 1 kHz sine wave, unless otherwise noted±10 V No oversampling8689.7dB
±5 V No oversampling85.589.5dB
fin = 130 HzOversampling by 16, ±10-V Range9195.2dB
fin = 130 HzOversampling by 16, ±5-V Range9194.7dB
SINADSignal to Noise + Distortion Ratiofin = 1 kHz sine wave, unless otherwise noted±10 V No oversampling89.5dB
±5 V No oversampling89.4dB
THDTotal Harmonic DistortionAll input range, fin =1 kHz-106dB
SFDRSpurious Free Dynamic Rangefin = 1 kHz-106dB
Analog Input Filter
BW (-3 dB)Small Signal BandwidthLow Bandwidth Mode-3 dB, ±10 V20.0kHz
Low Bandwidth Mode-3 dB, ±5 V12.7kHz
High Bandwidth Mode-3 dB, ±10 V26.5kHz
High Bandwidth Mode-3 dB, ±5 V16.4kHz
BW (-0.1 dB)Small Signal BandwidthLow Bandwidth Mode-0.1 dB, ±10 V3.3kHz
Low Bandwidth Mode-0.1 dB, ±5 V2.2kHz
High Bandwidth Mode-0.1 dB, ±10 V4.3kHz
High Bandwidth Mode-0.1 dB, ±5 V2.6kHz
Tgroup_delayGroup DelayLow Bandwidth Mode±10 V10μs
Low Bandwidth Mode±5 V16μs
High Bandwidth Mode±10 V8μs
High Bandwidth Mode±5 V12μs
DC Accuracy
ResolutionNO missing code16bit
DNLDifferential Nonlinearity $f_{SAMPLE}$ = 200 kSPS, -40~85°C-0.99±0.51.5LSB
INLIntegral Nonlinearity $f_{SAMPLE}$ = 200 kSPS, -40~85°C±0.7±2LSB
$f_{SAMPLE}$ = 350 kSPS, -40~85°C±1±2.5LSB
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
Positive and Negative Full-Scale ErrorExt reference±4±50LSB
Int reference±15LSB
Positive Full-Scale Error DriftExt reference±2ppm/C
Int reference±10ppm/C
Negative Full-Scale Error DriftExt reference±2ppm/C
Int reference±10ppm/C
Bipolar Zero Code Error±10 V±1±15LSB
±5 V
Bipolar Zero Code Error Drift±10 V±10μV/C
±5 V±5μV/C
Bipolar Full-Scale Error Matching±6±22LSB
Bipolar Zero Code Error matching±5 V±10 V±3±20LSB
Analog Input
Input RangeVx - VxGNDRANGE = 1, ±10-V range-1010V
RANGE = 0, ±5-V range-55
Analog Input Current10-V range(VIN - 2) / RINμA
5-V rangeμA
CINInput Capacitance5pF
RINInput Resistance1Mohm
Input Impedance Drift±20ppm/C
Reference Input/Output
Reference Input VoltageREF SELECT = 0, select Ext Ref, force voltage on REFIN/REFOUT2.4752.52.525V
Reference Output VoltageREF_SELECT = 1, REFIN/REFOUT output voltage TA = 25°C2.4952.52.505V
Reference Voltage TC±10ppm/C
V (REFCAPA/B)Voltage on REFCAPA and REFCAPB, also used for ADC4V
Logic Input
VIHInput High VoltageInput logic high voltage0.7 × VDRIVEV
VILInput Low VoltageInput logic low voltage0.3 × VDRIVEV
CIInput CapacitanceInput capacitance5pF
I1Input CurrentInput current±2μA
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
Logic Output
$V_{OH}$ Output High VoltageCurrent source = 100 μA $V_{DRIVE}$ - 0.2V
$V_{OL}$ Output Low VoltageCurrent sink = 100 μA0.2V
Float State Leakage Current±1±20μA
$C_O$ Output Capacitance5pF
Conversion Rate
Conversion Time1.65μs
Acquisition Time1.2μs
Throughput RatePer channel350kSPS
Timing specifications
SCLKFrequency of Serial Interface $V_{DRIVE}$ > 2.7 V23.5MHz
$V_{DRIVE}$ > 1.7 V15MHz
AVCC Normal4151mA
AVCC Standby59mA
AVCC Shutdown1125μA
+ +(1) 100% tested at $T_{A} = 25^{\circ}C$ . + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Timing Specifications + +All test conditions: $AV_{CC} = 5 V$ , $V_{DRIVE} = 1.7 V$ to 5.5 V, $V_{REF} = 2.5 V$ , $T_{A} = T_{MIN}$ to $T_{MAX}$ , unless otherwise noted. + +
ParameterLimit at TMIN, TMAX (0.1 × VDRIVE and 0.9 × VDRIVE Logic Input Levels)UnitDescription
MinTypMax
Parallel/Serial/Byte Mode
tCYCLE1/throughput rate
2.85μsParallel mode, reading during or after conversion; or serial mode: VDRIVE = 2.7 V to 5.5 V, reading during conversion using DOUTA and DOUTB lines
4.5μsSerial mode: VDRIVE = 2.7 V, reading after a conversion using DOUTA and DOUTB lines
6μsSerial mode: VDRIVE = 1.7 V, reading after a conversion using DOUTA and DOUTB lines
tCONVConversion time
1.74μsOversampling off
4.4μsOversampling by 2
9.6μsOversampling by 4
20μsOversampling by 8
41μsOversampling by 16
83μsOversampling by 32
167μsOversampling by 64
tWAKE-UP STANDBY100μsSTBY rising edge to CONVST × rising edge; power-up time from standby mode
tWAKE-UP SHUTDOWN Internal Reference180msSTBY rising edge to CONVST × rising edge; power-up time from shutdown mode
tWAKE-UP SHUTDOWN External Reference13msSTBY rising edge to CONVST × rising edge; power-up time from shutdown mode
tRESET100nsRESET high pulse width
t140nsCONVST × high to BUSY high
t225nsMinimum CONVST × low pulse
t325nsMinimum CONVST × high pulse
t445nsBUSY falling edge to CS falling edge setup time
t50.5msMaximum delay allowed between CONVST A, CONVST B rising edges
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
t6110nsMinimum time between last $\overline{CS}$ rising edge and BUSY falling edge
t7200nsMinimum delay between RESET low to CONVST × high
Parallel/Byte Read Operation
t80ns $\overline{CS}$ to $\overline{RD}$ setup time
t90ns $\overline{CS}$ to $\overline{RD}$ hold time
t10 $\overline{RD}$ low pulse width
22ns $V_{DRIVE}$ above 2.7 V
32ns $V_{DRIVE}$ above 1.7 V
t1110ns $\overline{RD}$ high pulse width
t1210ns $\overline{CS}$ high pulse width; $\overline{CS}$ and $\overline{RD}$ linked
t13Delay from $\overline{CS}$ until DB [15:0] three-state disabled
21ns $V_{DRIVE}$ above 2.7 V
30ns $V_{DRIVE}$ above 1.7 V
t14Data access time after $\overline{RD}$ falling edge
21ns $V_{DRIVE}$ above 2.7 V
30ns $V_{DRIVE}$ above 1.7 V
t156nsData hold time after $\overline{RD}$ falling edge
t166ns $\overline{CS}$ to DB [15:0] hold time
t1720nsDelay from $\overline{CS}$ rising edge to DB [15:0] three-state enabled
Serial Read Operation
fSCLKFrequency of serial read clock
23.5MHz $V_{DRIVE}$ above 2.7 V
15MHz $V_{DRIVE}$ above 1.7 V
t18Delay from CS until $D_{OUTA}/D_{OUTB}$ three-state disabled/delay from $\overline{CS}$ until MSB valid
10ns $V_{DRIVE}$ above 2.7 V
15ns $V_{DRIVE}$ above 1.7 V
t19Data access time after SCLK rising edge
21ns $V_{DRIVE}$ above 2.7 V
30ns $V_{DRIVE}$ above 1.7 V
t200.4tSCLKnsSCLK low pulse width
t210.4tSCLKnsSCLK high pulse width
t226nsSCLK rising edge to $D_{OUTA}/D_{OUTB}$ valid hold time
t2315ns $\overline{CS}$ rising edge to $D_{OUTA}/D_{OUTB}$ three-state enabled
FRATDATA Operation
t24Delay from $\overline{CS}$ falling edge until FRSTDATA three-state disabled
+ +16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
t2411nsVDRIVE above 2.7 V
20nsVDRIVE above 1.7 V
t25Delay from CS falling edge until FRSTDATA high, serial mode
11nsVDRIVE above 2.7 V
20nsVDRIVE above 1.7 V
t26Delay from RD falling edge to FRSTDATA high
22nsVDRIVE above 2.7 V
32nsVDRIVE above 1.7 V
t27Delay from RD falling edge to FRSTDATA low
22nsVDRIVE above 2.7 V
32nsVDRIVE above 1.7 V
t28Delay from the 16th SCLK falling edge to FRSTDATA low
22nsVDRIVE above 2.7 V
32nsVDRIVE above 1.7 V
t2920nsDelay from CS rising edge until FRSTDATA three-state enabled
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +Timing Diagrams +![](images/ab9ed3131120172d9148c4c79d2214382249a502455cbe52ed18950d9dacc404.jpg) + +
+flowchart + +```mermaid +graph LR + CONVST_A["CONVST A, CONVST B"] -->|t5| CONVST_B["CONVST A, CONVST B"] + CONVST_B -->|tCYCLE| CONVST_B + CONVST_B -->|t2| CONVST_B + CONVST_B -->|t3| BUSY["BUSY"] + BUSY -->|t1| CS["CS"] + CS -->|t4| CS + CONVST_B -->|tCONV| CS + CONVST_B -->|tRESET| RESET["RESET"] +``` +
+ +Figure 1. CONVST Timing-Reading After a Conversion + +![](images/1d86c3b520eb44528610b7cc420279851cd5fd4d70a7789894d9ae21c278099c.jpg) + +
+flowchart + +This diagram illustrates the timing relationships and signal flow between a system, including convolutional and busy states, reset, and synchronization intervals. +
+ +Figure 2. CONVST Timing-Reading During a Conversion + +![](images/973d1c32a5a7d76853d3c30b0982a2f07c6b64dd6e97b492c94ff8a0ef94c0de.jpg) + +
+text_image + +CS +RD +DATA: +DB[15:0] +FRSTDATA +t8 +t10 +t11 +t13 +t14 +t15 +t16 +t17 +t24 +t26 +t27 +t29 +t8 +t10 +t11 +t14 +t15 +t16 +t17 +V1 +V2 +V3 +V4 +V7 +V8 +
+ +Figure 3. Parallel Mode, Separate CS and RD Pulses +![](images/e4c998e58453c5f862866d953ac1e8da6de4b497a7140586ea5abc631c5e785d.jpg) + +
+text_image + +CS AND RD +DATA: +DB[15:0] +V1 V2 V3 V4 V5 V6 V7 V8 +t12 +t13 +t16 +t17 +FRSTDATA +
+ +Figure 4. CS and RD, Linked Parallel Mode + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +![](images/684073195c572cb351c311f748a53c26dd1d8ea558bb372c334e20836006ada3.jpg) + +
+text_image + +CS +SCLK +DOUTA, +DOUTB +FRSTDATA +t18 +t19 +t21 +t20 +t22 +t23 +t25 +DB15 +DB14 +DB13 +DB1 +DB0 +t28 +t29 +
+ +Figure 5. Serial Read Operation (Channel 1) + +![](images/e05c428f982b37656361ac07897016ea34d2e2eb7abe8c40ecde80503a89558c.jpg) + +
+text_image + +CS +RD +DATA: +DB[7:0] +FRSTDATA +t8 +t10 +t11 +t9 +t13 +t14 +t15 +t16 +t17 +t24 +t26 +t27 +t29 +INVALID +HIGH BYTE V1 +LOW BYTE V1 +HIGH BYTE V8 +LOW BYTE V8 +
+ +Figure 6. BYTE Mode Read Operation + +# 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Detailed Description + +## Overview + +The TPAFE5160 is a 16-bit, 8-channel simultaneous sampling, successive approximation (SAR) ADC. Each channel has a complete analog front end, as well as an ADC operating at 350 kSPS per channel. The analog front end features the input clamp, a programmable gain amplifier (PGA) with a high input impedance of 1 MΩ, a low pass filter, and an ADC input driver. + +The device features an internal precision reference with a buffer to drive the ADC. A digital interface supports serial, parallel, and parallel byte communication, which can be used with various host controllers. + +The TPAFE5160 can accept ±10-V or ±5-V true bipolar inputs with a single 5-V supply. Also, the high input impedance allows direct connection to transformers or other sensors without external driver circuits. + +## Feature Description + +## Analog Inputs + +The TPAFE5160 has 8 analog input channels, and positive inputs AIN\_nP (n = 1 to 8) are the single-ended analog inputs. The negative inputs AIN\_nGND should be tied to GND. + +The input voltage range can be configured to bipolar ±10 V or ±5 V by the RANGE pin. + +The device allows a ±0.3-V range on the AIN\_nGND. + +## Analog Input Impedance + +Each analog input channel in the device presents a constant resistive impedance of 1 MΩ. + +Matching the external source impedance on the AIN\_nP input pin with an equivalent resistance on the AIN\_nGND pin is recommended to cancel any additional offset error contributed by the external resistance. + +## Input Clamp Protection Circuit + +The input clamp protection circuit allows the analog input to swing up to ±30 V (typical). The input clamp circuit turns on beyond the clamp voltage. + +For input voltages above the clamp threshold, make sure that the input current never exceeds the absolute maximum rating to prevent any damage to the device. + +Don't keep the device in a state such that the clamp circuit is activated for extended periods of time, because this fault condition can degrade the performance and reliability of the device. + +## Programmable Gain Amplifier (PGA) + +The device has a programmable gain amplifier (PGA) at each individual input channel. The PGA converts the single-ended input signal into a fully-differential signal to drive internal ADC. The PGA also adjusts the common-mode voltage feeding into the ADC to ensure maximum usage of the ADC input dynamic range. The PGA gain is adjusted by configuring the RANGE pin of the ADC accordingly. + +## Low Pass Filter + +Each channel of the TPAFE5160 features a second-order antialiasing low pass filter (LPF) at the output of the PGA, to remove the noise of the front-end amplifiers and gain resistors of the PGA. + +## ADC Driver + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +There is an integrated ADC input driver before each ADC channel. This integrated ADC driver eliminates the need of any external amplifier, helping inputs of the ADC to settle to better than 16-bit accuracy before any sampled analog voltage gets converted. And thus, the signal chain design for the user is simplified. + +## Digital Filter + +The TPAFE5160 has an optional digital averaging filter that can be used in slower throughput applications requiring lower noise and higher dynamic range. The oversampling ratio of the digital filter is determined by the configuration of the OS[2:0] pins. + +In oversampling mode, the samples are averaged to reduce the noise of the signal chain as well as to improve the SNR of the ADC. The final output is also decimated to provide data for each channel. + +
OS [2:0]OS RATIOMAX THROUGHPUT PER CHANNEL (kSPS)
000NO OS350
0012175
010487.5
011843.75
1001621.875
1013210.94
110645.47
111NA350
+ +## Reference + +The TPAFE5160 can operate with either an internal voltage reference or an external voltage reference. The internal or external reference selection is determined by an external REFSEL pin, + +The REFIN/REFOUT pin outputs the internal band-gap voltage (in the internal reference mode) or functions as the input pin to the external reference voltage (in the external reference mode). The on-chip amplifier is enabled in both modes to drive the actual reference input of the internal ADC core. The REFCAPA and REFCAPB pins must be shorted together externally and a ceramic capacitor of a minimum 10 μF should be connected between this node and REFGND to ensure that the internal reference buffer is operating as a closed loop. + +## ADC Transfer Function + +The TPAFE5160 outputs 16-bit data in binary twos complement format for both bipolar input ranges. The format for the output codes is the same across all analog channels. + +
Input Range (V)Full-Scale Range (V)LSB (μV)
±1020305.18
±510152.59
+ +## Device Functional Modes + +Device Interface: Pin Description + +REFSEL (Input) + +The REFSEL pin selects between the internal and external reference modes of the device. + +If the REFSEL pin is set to logic high, then the internal reference is enabled and selected. + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +If the REFSEL pin is set to logic low, then the internal reference circuit is disabled and powered down. In this mode, an external reference voltage must be provided to the REFIN/REFOUT pin. + +The internal reference buffer is always enabled under both conditions. + +The reference mode after power-up depends on the state of the REFSEL input pin. + +## RANGE (Input) + +The RANGE pin selects the input range for all analog input channels. + +If this pin is set to logic high, the device is configured to operate in the ±10-V input range. + +If this pin is set to logic low, the device is configured to operate in the ±5-V input range. + +The RANGE pin is also used to put the device in standby or shutdown mode depending on the state of the STBY input pin, as explained in the Power Down Modes. + +## STBY (Input) + +The STBY pin puts the device into one of the two power-down modes: standby and power down. + +If this pin is set to logic high, the device is in normal operation mode. + +If this pin is set to logic low, the device is in the standby or power down mode, depending on the state of the RANGE pin. + +In the shutdown mode, all internal circuitry is powered down, + +In the standby mode, the internal reference remains powered up to enable a relatively quicker recovery to normal operation mode. + +## PAR/SER/BYTE SEL (Input) + +The PAR/SER/BYTE SEL pin selects between the parallel, serial, and parallel byte interface modes for reading data from the device. + +If this pin is set to logic high, then the serial or parallel byte interface mode is selected depending on the state of the DB15/BYTE SEL pin. If the DB15/BYTE SEL pin is high, the parallel byte interface is selected, and if the DB15/BYTE SEL is low, then the serial mode is selected. + +## CONVSTA, CONVSTB (Input) + +CONVSTA, and CONVSTB (Input) are conversion control input pins. + +CONVSTA can be used to simultaneously sample and initiate the conversion process for the first half count of the input channels (channels 1-4), and CONVSTB can be used to simultaneously sample and initiate the conversion process for the latter half count of the input channels (channels 5-8). + +On the rising edge of the CONVSTA, CONVSTB signals, the internal track-and-hold circuits for each analog input channel are placed into the hold mode and the sampled input signal is converted. + +The CONVSTA, and CONVSTB signals can be pulled low when the internal conversion is over, as indicated by the BUSY signal. At this point, the front-end circuit for all analog input channels acquires the respective input signals and the internal ADC is not converting. + +The output data can be read from the device irrespective of the status of the CONVSTA and CONVSTB pins. + +## RESET (Input) + +The RESET pin can be used to reset the device at any time in an asynchronous manner. When the RESET pin is set to logic high, the device is in the reset mode and remains in the state until the pin returns low. + +The device should be reset after power-up or recovery from the shut down mode when all the supplies and references have settled to the required accuracy. + +## RD/SCLK (Input) + +RD/SCLK (Input) is a dual-function pin to be used in different interface modes. + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +
Device Operating ConditionFunctionality of RD/SCLK(Input)
Parallel InterfacePAR/SER/BYTR SEL = 0DB15/BYTE = 0The active-low digital input pin to read the output data from the device.In the parallel or parallel byte interface mode, the output bus is enabled when both the CS and RD inputs are tied to a logic-low input.
Parallel Byte InterfacePAR/SER/BYTR SEL = 1DB15/BYTE = 1
Serial InterfacePAR/SER/BYTR SEL = 1DB15/BYTE = 0The external clock input for the serial data interface. In the serial mode, all synchronous accesses to the device are timed with respect to the rising edge of the SCLK signal.
+ +## $\overline{CS}$ (Input) + +The $\overline{CS}$ pin is an active-low, chip-select signal. + +A rising edge on the $\overline{CS}$ signal outputs all the data lines in tri-state mode. + +A falling edge of the $\overline{CS}$ signal marks the beginning of the output data transfer frame in any interface mode of operation for the device. + +## OS [2:0] + +The OS [2:0] pins are active-high digital input pins used to configure the oversampling ratio for the internal digital filter on the device. + +When OS [2:0] = 111, a higher filter bandwidth of $\sim$ 30 kHz is selected. + +## Device Modes of Operation + +## Power Down Modes + +The device supports two power-down modes: standby mode and shutdown mode. The device can enter either power-down mode by pulling the STBY pin to a logic level. Additionally, the selection between these two power-down modes is done by the state of the RANGE pin. + +
Power Down Mode $\overline{STBY}$ Range
Standby01
Shutdown00
+ +## Standby Mode + +In the standby mode, only the internal reference of the circuit is powered up, and the analog front-end, signal-conditioning circuit for each channel remains powered down. + +## Shutdown Mode + +In the shutdown mode, the entire internal circuitry is powered down. + +## Conversion Control + +The device offers precise control of simultaneously sampling all analog input channels. + +## Simultaneous Sampling on All Input Channels + +All the analog input channels are to be simultaneously sampled by connecting CONVSTA and CONVSTB signals together, and a single CONVST signal should be used to control the sampling of all analog input channels of the device. + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Simultaneous Sampling Two Sets of Input Channels + +Two sets of analog input channels can be simultaneously sampled by separating CONVSTA and CONVSTB signals. And the device could not operate in oversampling mode in this state. + +## Data read operation + +The device updates the internal data registers with the conversion data for all analog channels at the end of every conversion phase (when BUSY goes low). + +If the output data are read after BUSY goes low, then the device outputs the conversion results for the current sample. + +If the output data are read when BUSY is high, then the device outputs conversion results for the previous sample. + +There are three interface modes: + +
Interface mode $\overline{PAR}/SER/BYTE SEL$ DB15/BYTE SEL
Parallel Interface00
Parallel Byte Interface11
Serial Interface10
+ +## Parallel Data Read + +The device supports a parallel interface mode for reading the output data of the device using the control inputs ( $\overline{CS}$ and $\overline{RD}$ ), the parallel output bus (DB [15:0]), and the BUSY indicator. + +For applications that use only one device in the system and do not share the parallel output bus with any other devices, the CS and RD input signals can be tied together, or the CS signal can be permanently tied low. At the first falling edge of the CS and RD signal, the output data of channel 1 becomes available on the parallel bus to be read by the digital host. At this instant, the FRSTDATA output also goes high, indicating channel 1 data is ready to be read back. The output data for the remaining channels are clocked out on the parallel bus on subsequent falling edges of the CS and RD signal in a sequential manner. + +For applications that use multiple devices in the system, the CS and RD input signals must be driven separately. + +## Parallel Byte Data Read + +The parallel byte interface mode is very similar to the parallel interface mode, except that the output data for each channel is read in two data transfers of 8-bit byte sizes. + +In the parallel byte mode, the DB14/HBEN pin decides the order of the most significant byte (MSB byte) and the least significant byte (LSB byte). When the DB14/HBEN pin is tied high, the MSB byte of the conversion results is output first followed by the LSB byte. This order is reversed when DB14/HBEN is tied to logic low. + +At the first falling edge of the $\overline{RD}$ signal, the first byte of the channel 1 conversion result becomes available on DB [7:0]. This byte is followed by the second byte of conversion data on the next falling edge of the RD signal. + +## Serial Data Read + +This interface mode uses a CS control input, a communication clock input (SCLK), BUSY and FRSTDATA output indicators, and serial data output lines DOUTA and DOUTB. + +A total of 16 SCLK cycles are required to clock out 16 bits of conversion result for each channel and the same process can be repeated for the remaining channels in an ascending order. + +The conversion results from the first set of channels appear first on DOUTA, followed by the second set of channels if only DOUTA is used for reading data. This order is reversed for DOUTB, in which the second set of channels appear first followed by the first set of channels. The use of both data output lines reduces the time needed for data retrieval and a higher throughput can therefore be achieved in this mode. + +## Data Read During Conversion + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +The device allows data read when the ADC is converting and the BUSY output is high status. In this case, the ADC outputs conversion results for previous samples. + +The data read back during conversion mode allows faster throughput to be achieved from the device. + +## Data Read During Conversion + +The device can be configured in the oversampling mode by the OS [2:0] pins. The input on the OS pins is latched on the falling edge of the BUSY signal to configure the oversampling rate for the next conversion. + +In this mode, the CONVST A and CONVST B signals should be tied or driven together. + +The BUSY signal duration varies with the OSR setting because the conversion time increases with the OSR setting. + +Oversampling the input signal reduces noise during the conversion process, thus reducing the histogram code spread for a DC input signal to the ADC. + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Application and Implementation + +Note + +Information in the following application sections is not part of the 3PEAK's component specification and 3PEAK does not warrant its accuracy or completeness. 3PEAK's customers are responsible for determining suitability of components for their purposes. Customers should validate and test their design implementation to confirm system functionality. + +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +Tape and Reel Information +![](images/4749eae1dd6c621d0dbd7c811bca00b8cf3bd13593146bd28dc8bb4182d566ea.jpg) + +
+natural_image + +Technical line drawing of a wheel with four spokes and a central hub, no text or symbols present +
+ +D1:Reel Diameter + +![](images/c36041b46def9706b380365e508554455f46e4e3d89ee675b091679e9df03c06.jpg) + +
+natural_image + +Pure diagram of a vertical structure with horizontal lines and a central horizontal bar, labeled W1 at the bottom (no text or symbols beyond label) +
+ +![](images/2cdaafaa6a256fbc8cd6edba7b762af379531acb481fc31a71fd939ac81b38d1.jpg) + +
+text_image + +Direction of Feed +W0 +P0 +A0 +B0 +K0 +
+ +
Order NumberPackageD1 (mm)W1 (mm)A0 (mm)B0 (mm)K0 (mm)P0 (mm)W0 (mm)Pin1 Quadrant
TPAFE5160SI08-QP7RLQFP10×10-6433028.412.08512.0852.11624Q2
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## Package Outline Dimensions + +LQFP10x10-64 + +Package Outline Dimensions +QP5(LQFP10X10-64-A) +![](images/9ce7a4caaa2788c2c2561d9e7d69c3d74fccea3315ea0ee307ae562847d01c1b.jpg) + +
+text_image + +D +D1 +64 +1 +PIN 1 +E1 +E +
+ +![](images/a1b45902cfbba60871cce6181733e1b136e588a028df9303c8f8c6fd40b237f3.jpg) + +
+text_image + +WITH PLATING +b +c +BASE +METAL +
+ +SECTION N-N + +![](images/f69b0c5e472b09735358baad95d78c77abc6caffba1dec62b7946792623e25af.jpg) + +
+natural_image + +Pure electrical circuit lines without any symbols +
+ +![](images/c42cbf274e4b9daea53dd9192a21043b96bfd4820fc19d1793a23e96be4851ce.jpg) + +![](images/8b28c815d6a32e3c1f1c7ced71fb8ccb1eb0e1794ad7a8529b5c410ecb696b53.jpg) + +
+text_image + +A +A2 +SEATING +PLANE +A1 +C +e +b +θ +L +N +
+ +DETAIL Y + +## NOTES + +1. Do not include mold flash or protrusion. +2. This drawing is subject to change without notice. + +
SymbolDimensions In MillimetersDimensions In Inches
MINMAXMINMAX
A1.4001.6000.0550.063
A10.0500.1500.0020.006
A21.3501.4500.0530.057
b0.1700.2700.0070.011
c0.0900.2000.0040.008
D11.80012.2000.4650.480
D19.90010.1000.3900.398
E11.80012.2000.4650.480
E19.90010.1000.3900.398
e0.500 BSC0.020 BSC
L0.4500.7500.0180.030
θ00
+ +## 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +Order Information + +
Order NumberOperating Temperature RangePackageMarking InformationMSLTransport Media, QuantityEco Plan
TPAFE5160SI08-QP7R-40 to 125°CLQFP10×10-64AFE51603Tape and Reel, 1000Green
+ +Green: 3PEAK defines "Green" to mean RoHS compatible and free of halogen substances. + +# 16-Bit, 8-Channel, Simultaneous Sampling ADC with Bipolar Inputs + +## IMPORTANT NOTICE AND DISCLAIMER + +Copyright© 3PEAK 2012-2024. All rights reserved. + +Trademarks. Any of the 思瑞浦 or 3PEAK trade names, trademarks, graphic marks, and domain names contained in this document /material are the property of 3PEAK. You may NOT reproduce, modify, publish, transmit or distribute any Trademark without the prior written consent of 3PEAK. + +Performance Information. Performance tests or performance range contained in this document/material are either results of design simulation or actual tests conducted under designated testing environment. Any variation in testing environment or simulation environment, including but not limited to testing method, testing process or testing temperature, may affect actual performance of the product. + +Disclaimer. 3PEAK provides technical and reliability data (including data sheets), design resources (including reference designs), application or other design recommendations, networking tools, security information and other resources "As Is". 3PEAK makes no warranty as to the absence of defects, and makes no warranties of any kind, express or implied, including without limitation, implied warranties as to merchantability, fitness for a particular purpose or non-infringement of any third-party's intellectual property rights. Unless otherwise specified in writing, products supplied by 3PEAK are not designed to be used in any life-threatening scenarios, including critical medical applications, automotive safety-critical systems, aviation, aerospace, or any situations where failure could result in bodily harm, loss of life, or significant property damage. 3PEAK disclaims all liability for any such unauthorized use. \ No newline at end of file diff --git a/嵌入式C语言代码规范(V1.0).md b/docs/嵌入式C语言代码规范(V1.0).md similarity index 100% rename from 嵌入式C语言代码规范(V1.0).md rename to docs/嵌入式C语言代码规范(V1.0).md