|
11 | 11 | #include <rtthread.h> |
12 | 12 | #include <rthw.h> |
13 | 13 | #include <board.h> |
| 14 | + |
| 15 | +/* The driver owns the peripheral registers, so it pulls in the peripheral |
| 16 | + * header itself instead of relying on board.h to have declared it. Only the |
| 17 | + * H49x board happens to include it today. |
| 18 | + */ |
| 19 | +#if defined(SOC_SERIES_N32H7xx) |
| 20 | +#include <n32h7xx_i2c.h> |
| 21 | +#elif defined(SOC_SERIES_N32H49x) |
| 22 | +#include <n32h49x_i2c.h> |
| 23 | +#elif defined(SOC_SERIES_N32H47x_48x) |
| 24 | +#include <n32h47x_48x_i2c.h> |
| 25 | +#endif |
| 26 | + |
14 | 27 | #include "drv_hard_i2c.h" |
15 | 28 | #include "drv_config.h" |
16 | 29 | #include <string.h> |
@@ -187,11 +200,106 @@ static rt_err_t n32_i2c_master_start_addr(struct n32_i2c *i2c, uint8_t DevAddres |
187 | 200 | } |
188 | 201 | #endif /* defined(SOC_SERIES_N32H49x) */ |
189 | 202 |
|
190 | | -#if defined(SOC_SERIES_N32H49x) || defined(SOC_SERIES_N32H47x_48x) |
| 203 | +#if defined(SOC_SERIES_N32H7xx) |
| 204 | +/* Wait for the bus to fall idle before asserting a new STOP or START. |
| 205 | + * |
| 206 | + * Asserting either while a previous STOP is still on the wire wedges the state |
| 207 | + * machine: BUSY stays set, the address never goes out and the transfer stalls. |
| 208 | + */ |
| 209 | +static rt_err_t n32_i2c_wait_bus_idle(I2C_Module *Instance) |
| 210 | +{ |
| 211 | + rt_uint32_t timeout = 1000000U; |
| 212 | + |
| 213 | + while ((I2C_GetFlag(Instance, I2C_FLAG_BUSY) != RESET) && (--timeout > 0U)) |
| 214 | + { |
| 215 | + } |
| 216 | + |
| 217 | + return (timeout != 0U) ? RT_EOK : -RT_ETIMEOUT; |
| 218 | +} |
| 219 | + |
| 220 | +/* Clear residue left by an aborted transfer before the next one starts. |
| 221 | + * |
| 222 | + * A STOPGEN that was latched with no frame to terminate stays pending and would |
| 223 | + * tear down the transfer we are about to set up. Stale status flags would |
| 224 | + * likewise fire the moment the new transfer re-enables the error interrupt. |
| 225 | + * |
| 226 | + * I2C_ClrFlag() is a plain "INTCLR |= flag" write, so only flags that actually |
| 227 | + * have a matching INTCLR bit may be passed. TFC (0x40) and BUSY (0x8000) have |
| 228 | + * none - passing them lands in reserved bits and clears nothing. |
| 229 | + */ |
| 230 | +static void n32_i2c_prepare_start(I2C_Module *Instance) |
| 231 | +{ |
| 232 | + I2C_GenerateStop(Instance, DISABLE); |
| 233 | + |
| 234 | + I2C_ClrFlag(Instance, I2C_FLAG_NAKF | I2C_FLAG_BSER | I2C_FLAG_ABLO | |
| 235 | + I2C_FLAG_OVF | I2C_FLAG_TMOUT | I2C_FLAG_ALRT | |
| 236 | + I2C_FLAG_STOPF | I2C_FLAG_ADR | I2C_FLAG_CRCERR); |
| 237 | +} |
| 238 | + |
| 239 | +/* Tear down a transfer that the waiting thread has given up on. |
| 240 | + * |
| 241 | + * Must disarm the ISR before returning: master_xfer's callers pass stack |
| 242 | + * buffers, so a late read writing through transfer.pBuffPtr would corrupt a |
| 243 | + * stack frame that no longer exists once the caller unwinds. The DMA channel |
| 244 | + * targets that same buffer, so it is disabled here as well - dropping the |
| 245 | + * request enable alone leaves the channel armed. |
| 246 | + */ |
| 247 | +static void n32_i2c_abort_transfer(struct n32_i2c *i2c_obj) |
| 248 | +{ |
| 249 | + I2C_Module *Instance = i2c_obj->config->Instance; |
| 250 | + I2C_StateTypeDef was_state = i2c_obj->transfer.state; |
| 251 | + |
| 252 | + /* Disable interrupts and DMA first - stop the ISR touching pBuffPtr */ |
| 253 | + Instance->CTRL1 &= ~(I2C_CTRL1_TFCIE | I2C_CTRL1_WDRIE | I2C_CTRL1_RDRIE | |
| 254 | + I2C_CTRL1_STOPIE | I2C_CTRL1_NAKIE | I2C_CTRL1_ERRIE); |
| 255 | + |
| 256 | + if ((was_state == I2C_BUSY_TX) && |
| 257 | + ((i2c_obj->i2c_dma_flag & I2C_USING_TX_DMA_FLAG) == I2C_USING_TX_DMA_FLAG)) |
| 258 | + { |
| 259 | + Instance->CTRL1 &= ~I2C_CTRL1_DMAWREN; |
| 260 | + |
| 261 | + DMA_ChannelCmd(i2c_obj->config->dma_tx->Instance, |
| 262 | + i2c_obj->config->dma_tx->dma_channel, DISABLE); |
| 263 | + DMA_ChannelEventCmd(i2c_obj->config->dma_tx->Instance, |
| 264 | + i2c_obj->config->dma_tx->dma_channel, |
| 265 | + DMA_CH_EVENT_BLOCK_TRANSFER_COMPLETE, DISABLE); |
| 266 | + DMA_ClearChannelEventStatus(i2c_obj->config->dma_tx->Instance, |
| 267 | + i2c_obj->config->dma_tx->dma_channel, |
| 268 | + DMA_CH_EVENT_BLOCK_TRANSFER_COMPLETE); |
| 269 | + } |
| 270 | + else if ((was_state == I2C_BUSY_RX) && |
| 271 | + ((i2c_obj->i2c_dma_flag & I2C_USING_RX_DMA_FLAG) == I2C_USING_RX_DMA_FLAG)) |
| 272 | + { |
| 273 | + Instance->CTRL1 &= ~I2C_CTRL1_DMARDEN; |
| 274 | + |
| 275 | + DMA_ChannelCmd(i2c_obj->config->dma_rx->Instance, |
| 276 | + i2c_obj->config->dma_rx->dma_channel, DISABLE); |
| 277 | + DMA_ChannelEventCmd(i2c_obj->config->dma_rx->Instance, |
| 278 | + i2c_obj->config->dma_rx->dma_channel, |
| 279 | + DMA_CH_EVENT_BLOCK_TRANSFER_COMPLETE, DISABLE); |
| 280 | + DMA_ClearChannelEventStatus(i2c_obj->config->dma_rx->Instance, |
| 281 | + i2c_obj->config->dma_rx->dma_channel, |
| 282 | + DMA_CH_EVENT_BLOCK_TRANSFER_COMPLETE); |
| 283 | + } |
| 284 | + |
| 285 | + i2c_obj->i2c_isr_callback = RT_NULL; |
| 286 | + i2c_obj->transfer.pBuffPtr = RT_NULL; |
| 287 | + i2c_obj->transfer.XferCount = 0; |
| 288 | + i2c_obj->transfer.XferSize = 0; |
| 289 | + i2c_obj->transfer.state = I2C_READY; |
| 290 | + |
| 291 | + /* Release the bus only if we still own it, then clear residue */ |
| 292 | + if (I2C_GetFlag(Instance, I2C_FLAG_BUSY) != RESET) |
| 293 | + { |
| 294 | + I2C_GenerateStop(Instance, ENABLE); |
| 295 | + (void)n32_i2c_wait_bus_idle(Instance); |
| 296 | + } |
| 297 | + |
| 298 | + n32_i2c_prepare_start(Instance); |
| 299 | +} |
| 300 | +#endif /* defined(SOC_SERIES_N32H7xx) */ |
| 301 | + |
191 | 302 | #define I2C_ABORT_ON_TIMEOUT(obj) n32_i2c_abort_transfer(obj) |
192 | | -#else |
193 | | -#define I2C_ABORT_ON_TIMEOUT(obj) ((obj)->transfer.state = I2C_READY) |
194 | | -#endif |
195 | 303 |
|
196 | 304 | enum |
197 | 305 | { |
@@ -487,8 +595,6 @@ static rt_err_t n32_i2c_init(struct n32_i2c *i2c_drv) |
487 | 595 | #if defined(SOC_SERIES_N32H7xx) |
488 | 596 | I2C_InitType I2C_InitStructure; |
489 | 597 | uint32_t BusTim_Reg; |
490 | | - /* Call I2C_Configuration() from an external file */ |
491 | | - I2C_Configuration(); |
492 | 598 | /* Disable IIC */ |
493 | 599 | I2C_Enable(cfg->Instance, DISABLE); |
494 | 600 | /* Get IIC BUSTM Register value */ |
|
0 commit comments