|
19 | 19 | #define LOG_TAG "drv.i2c.hw"
|
20 | 20 | #include <drv_log.h>
|
21 | 21 |
|
| 22 | +// 添加I2C速度设置命令定义 |
| 23 | +#define I2C_CTRL_SET_SPEED 0x01 |
| 24 | +#define I2C_CTRL_SET_DUTY 0x02 |
| 25 | + |
22 | 26 | enum
|
23 | 27 | {
|
24 | 28 | #ifdef BSP_USING_HARD_I2C1
|
@@ -47,6 +51,157 @@ static struct stm32_i2c_config i2c_config[] =
|
47 | 51 |
|
48 | 52 | static struct stm32_i2c i2c_objs[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};
|
49 | 53 |
|
| 54 | +// 添加I2C速度设置函数 |
| 55 | +static rt_err_t stm32_i2c_set_speed(struct rt_i2c_bus_device *bus, uint32_t speed) |
| 56 | +{ |
| 57 | + struct stm32_i2c *i2c_drv = rt_container_of(bus, struct stm32_i2c, i2c_bus); |
| 58 | + I2C_HandleTypeDef *i2c_handle = &i2c_drv->handle; |
| 59 | + rt_err_t ret = RT_EOK; |
| 60 | + |
| 61 | + RT_ASSERT(bus != RT_NULL); |
| 62 | + RT_ASSERT(speed > 0); |
| 63 | + |
| 64 | + LOG_D("Setting I2C speed to %d Hz", speed); |
| 65 | + |
| 66 | + if (HAL_I2C_DeInit(i2c_handle) != HAL_OK) |
| 67 | + { |
| 68 | + LOG_E("Failed to deinit I2C for speed change"); |
| 69 | + return -RT_ERROR; |
| 70 | + } |
| 71 | + |
| 72 | + rt_memset(i2c_handle, 0, sizeof(I2C_HandleTypeDef)); |
| 73 | + i2c_handle->Instance = i2c_drv->config->Instance; |
| 74 | + |
| 75 | +#if defined(SOC_SERIES_STM32H7) |
| 76 | + i2c_handle->Init.Timing = i2c_drv->config->timing; |
| 77 | +#elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F4) |
| 78 | + i2c_handle->Init.ClockSpeed = speed; |
| 79 | + i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2; |
| 80 | +#endif |
| 81 | + |
| 82 | + i2c_handle->Init.OwnAddress1 = 0; |
| 83 | + i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; |
| 84 | + i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; |
| 85 | + i2c_handle->Init.OwnAddress2 = 0; |
| 86 | + i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; |
| 87 | + i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; |
| 88 | + |
| 89 | + if (HAL_I2C_Init(i2c_handle) != HAL_OK) |
| 90 | + { |
| 91 | + LOG_E("Failed to reinit I2C with new speed"); |
| 92 | + return -RT_ERROR; |
| 93 | + } |
| 94 | + |
| 95 | +#if defined(SOC_SERIES_STM32H7) |
| 96 | + if (HAL_I2CEx_ConfigAnalogFilter(i2c_handle, I2C_ANALOGFILTER_ENABLE) != HAL_OK) |
| 97 | + { |
| 98 | + LOG_E("Failed to configure analog filter"); |
| 99 | + ret = -RT_ERROR; |
| 100 | + } |
| 101 | + |
| 102 | + if (HAL_I2CEx_ConfigDigitalFilter(i2c_handle, 0) != HAL_OK) |
| 103 | + { |
| 104 | + LOG_E("Failed to configure digital filter"); |
| 105 | + ret = -RT_ERROR; |
| 106 | + } |
| 107 | +#endif |
| 108 | + |
| 109 | + /* 参考启动流程,若开启了 DMA,需要重新配置 DMA 和 NVIC,避免重新初始化后句柄失效 */ |
| 110 | + if (i2c_drv->i2c_dma_flag & I2C_USING_RX_DMA_FLAG) |
| 111 | + { |
| 112 | + /* 重新设置 DMA RX 基本参数并初始化 */ |
| 113 | + i2c_drv->dma.handle_rx.Instance = i2c_drv->config->dma_rx->Instance; |
| 114 | +#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) |
| 115 | + i2c_drv->dma.handle_rx.Init.Channel = i2c_drv->config->dma_rx->channel; |
| 116 | +#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) |
| 117 | + i2c_drv->dma.handle_rx.Init.Request = i2c_drv->config->dma_rx->request; |
| 118 | +#endif |
| 119 | +#ifndef SOC_SERIES_STM32U5 |
| 120 | + i2c_drv->dma.handle_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; |
| 121 | + i2c_drv->dma.handle_rx.Init.PeriphInc = DMA_PINC_DISABLE; |
| 122 | + i2c_drv->dma.handle_rx.Init.MemInc = DMA_MINC_ENABLE; |
| 123 | + i2c_drv->dma.handle_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; |
| 124 | + i2c_drv->dma.handle_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; |
| 125 | + i2c_drv->dma.handle_rx.Init.Mode = DMA_NORMAL; |
| 126 | + i2c_drv->dma.handle_rx.Init.Priority = DMA_PRIORITY_LOW; |
| 127 | +#endif |
| 128 | +#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) |
| 129 | + i2c_drv->dma.handle_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; |
| 130 | +#endif |
| 131 | + HAL_DMA_DeInit(&i2c_drv->dma.handle_rx); |
| 132 | + HAL_DMA_Init(&i2c_drv->dma.handle_rx); |
| 133 | + __HAL_LINKDMA(&i2c_drv->handle, hdmarx, i2c_drv->dma.handle_rx); |
| 134 | + /* NVIC 配置 */ |
| 135 | + HAL_NVIC_SetPriority(i2c_drv->config->dma_rx->dma_irq, 0, 0); |
| 136 | + HAL_NVIC_EnableIRQ(i2c_drv->config->dma_rx->dma_irq); |
| 137 | + } |
| 138 | + |
| 139 | + if (i2c_drv->i2c_dma_flag & I2C_USING_TX_DMA_FLAG) |
| 140 | + { |
| 141 | + /* 重新设置 DMA TX 基本参数并初始化 */ |
| 142 | + i2c_drv->dma.handle_tx.Instance = i2c_drv->config->dma_tx->Instance; |
| 143 | +#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) |
| 144 | + i2c_drv->dma.handle_tx.Init.Channel = i2c_drv->config->dma_tx->channel; |
| 145 | +#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7) |
| 146 | + i2c_drv->dma.handle_tx.Init.Request = i2c_drv->config->dma_tx->request; |
| 147 | +#endif |
| 148 | +#ifndef SOC_SERIES_STM32U5 |
| 149 | + i2c_drv->dma.handle_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; |
| 150 | + i2c_drv->dma.handle_tx.Init.PeriphInc = DMA_PINC_DISABLE; |
| 151 | + i2c_drv->dma.handle_tx.Init.MemInc = DMA_MINC_ENABLE; |
| 152 | + i2c_drv->dma.handle_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; |
| 153 | + i2c_drv->dma.handle_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; |
| 154 | + i2c_drv->dma.handle_tx.Init.Mode = DMA_NORMAL; |
| 155 | + i2c_drv->dma.handle_tx.Init.Priority = DMA_PRIORITY_LOW; |
| 156 | +#endif |
| 157 | +#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) |
| 158 | + i2c_drv->dma.handle_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; |
| 159 | + i2c_drv->dma.handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; |
| 160 | + i2c_drv->dma.handle_tx.Init.MemBurst = DMA_MBURST_INC4; |
| 161 | + i2c_drv->dma.handle_tx.Init.PeriphBurst = DMA_PBURST_INC4; |
| 162 | +#endif |
| 163 | + HAL_DMA_DeInit(&i2c_drv->dma.handle_tx); |
| 164 | + HAL_DMA_Init(&i2c_drv->dma.handle_tx); |
| 165 | + __HAL_LINKDMA(&i2c_drv->handle, hdmatx, i2c_drv->dma.handle_tx); |
| 166 | + /* NVIC 配置 */ |
| 167 | + HAL_NVIC_SetPriority(i2c_drv->config->dma_tx->dma_irq, 1, 0); |
| 168 | + HAL_NVIC_EnableIRQ(i2c_drv->config->dma_tx->dma_irq); |
| 169 | + } |
| 170 | + |
| 171 | + /* 事件中断 NVIC 重新配置(IT 模式也需要) */ |
| 172 | + HAL_NVIC_SetPriority(i2c_drv->config->evirq_type, 2, 0); |
| 173 | + HAL_NVIC_EnableIRQ(i2c_drv->config->evirq_type); |
| 174 | + |
| 175 | + if (ret == RT_EOK) |
| 176 | + { |
| 177 | + LOG_D("I2C speed changed to %d Hz successfully (DMA/IRQ reconfigured)", speed); |
| 178 | + } |
| 179 | + |
| 180 | + return ret; |
| 181 | +} |
| 182 | + |
| 183 | +// 添加I2C控制函数 |
| 184 | +static rt_err_t stm32_i2c_control(struct rt_i2c_bus_device *bus, int cmd, void *args) { |
| 185 | + RT_ASSERT(bus != RT_NULL); |
| 186 | + |
| 187 | + switch (cmd) { |
| 188 | + case I2C_CTRL_SET_SPEED: |
| 189 | + if (args != RT_NULL) { |
| 190 | + uint32_t speed = *(uint32_t *)args; |
| 191 | + return stm32_i2c_set_speed(bus, speed); |
| 192 | + } |
| 193 | + return -RT_EINVAL; |
| 194 | + |
| 195 | + case I2C_CTRL_SET_DUTY: |
| 196 | + // 占空比设置暂时不实现,因为需要重新计算时钟分频 |
| 197 | + LOG_W("Duty cycle setting not implemented yet"); |
| 198 | + return RT_EOK; |
| 199 | + |
| 200 | + default: |
| 201 | + return -RT_ENOSYS; |
| 202 | + } |
| 203 | +} |
| 204 | + |
50 | 205 | static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
|
51 | 206 | {
|
52 | 207 | RT_ASSERT(i2c_drv != RT_NULL);
|
@@ -326,12 +481,8 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
|
326 | 481 | return ret;
|
327 | 482 | }
|
328 | 483 |
|
329 |
| -static const struct rt_i2c_bus_device_ops stm32_i2c_ops = |
330 |
| -{ |
331 |
| - .master_xfer = stm32_i2c_master_xfer, |
332 |
| - RT_NULL, |
333 |
| - RT_NULL |
334 |
| -}; |
| 484 | +static const struct rt_i2c_bus_device_ops stm32_i2c_ops = { |
| 485 | + .master_xfer = stm32_i2c_master_xfer, .slave_xfer = RT_NULL, .i2c_bus_control = stm32_i2c_control}; |
335 | 486 |
|
336 | 487 | int RT_hw_i2c_bus_init(void)
|
337 | 488 | {
|
|
0 commit comments