Austin Schuh | 208337d | 2022-01-01 14:29:11 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include "hardware/i2c.h" |
| 8 | #include "hardware/resets.h" |
| 9 | #include "hardware/clocks.h" |
| 10 | #include "pico/timeout_helper.h" |
| 11 | |
| 12 | check_hw_layout(i2c_hw_t, enable, I2C_IC_ENABLE_OFFSET); |
| 13 | check_hw_layout(i2c_hw_t, clr_restart_det, I2C_IC_CLR_RESTART_DET_OFFSET); |
| 14 | |
| 15 | i2c_inst_t i2c0_inst = {i2c0_hw, false}; |
| 16 | i2c_inst_t i2c1_inst = {i2c1_hw, false}; |
| 17 | |
| 18 | static inline void i2c_reset(i2c_inst_t *i2c) { |
| 19 | invalid_params_if(I2C, i2c != i2c0 && i2c != i2c1); |
| 20 | reset_block(i2c == i2c0 ? RESETS_RESET_I2C0_BITS : RESETS_RESET_I2C1_BITS); |
| 21 | } |
| 22 | |
| 23 | static inline void i2c_unreset(i2c_inst_t *i2c) { |
| 24 | invalid_params_if(I2C, i2c != i2c0 && i2c != i2c1); |
| 25 | unreset_block_wait(i2c == i2c0 ? RESETS_RESET_I2C0_BITS : RESETS_RESET_I2C1_BITS); |
| 26 | } |
| 27 | |
| 28 | // Addresses of the form 000 0xxx or 111 1xxx are reserved. No slave should |
| 29 | // have these addresses. |
| 30 | static inline bool i2c_reserved_addr(uint8_t addr) { |
| 31 | return (addr & 0x78) == 0 || (addr & 0x78) == 0x78; |
| 32 | } |
| 33 | |
| 34 | uint i2c_init(i2c_inst_t *i2c, uint baudrate) { |
| 35 | i2c_reset(i2c); |
| 36 | i2c_unreset(i2c); |
| 37 | i2c->restart_on_next = false; |
| 38 | |
| 39 | i2c->hw->enable = 0; |
| 40 | |
| 41 | // Configure as a fast-mode master with RepStart support, 7-bit addresses |
| 42 | i2c->hw->con = |
| 43 | I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB | |
| 44 | I2C_IC_CON_MASTER_MODE_BITS | |
| 45 | I2C_IC_CON_IC_SLAVE_DISABLE_BITS | |
| 46 | I2C_IC_CON_IC_RESTART_EN_BITS | |
| 47 | I2C_IC_CON_TX_EMPTY_CTRL_BITS; |
| 48 | |
| 49 | // Set FIFO watermarks to 1 to make things simpler. This is encoded by a register value of 0. |
| 50 | i2c->hw->tx_tl = 0; |
| 51 | i2c->hw->rx_tl = 0; |
| 52 | |
| 53 | // Always enable the DREQ signalling -- harmless if DMA isn't listening |
| 54 | i2c->hw->dma_cr = I2C_IC_DMA_CR_TDMAE_BITS | I2C_IC_DMA_CR_RDMAE_BITS; |
| 55 | |
| 56 | // Re-sets i2c->hw->enable upon returning: |
| 57 | return i2c_set_baudrate(i2c, baudrate); |
| 58 | } |
| 59 | |
| 60 | void i2c_deinit(i2c_inst_t *i2c) { |
| 61 | i2c_reset(i2c); |
| 62 | } |
| 63 | |
| 64 | uint i2c_set_baudrate(i2c_inst_t *i2c, uint baudrate) { |
| 65 | invalid_params_if(I2C, baudrate == 0); |
| 66 | // I2C is synchronous design that runs from clk_sys |
| 67 | uint freq_in = clock_get_hz(clk_sys); |
| 68 | |
| 69 | // TODO there are some subtleties to I2C timing which we are completely ignoring here |
| 70 | uint period = (freq_in + baudrate / 2) / baudrate; |
| 71 | uint lcnt = period * 3 / 5; // oof this one hurts |
| 72 | uint hcnt = period - lcnt; |
| 73 | // Check for out-of-range divisors: |
| 74 | invalid_params_if(I2C, hcnt > I2C_IC_FS_SCL_HCNT_IC_FS_SCL_HCNT_BITS); |
| 75 | invalid_params_if(I2C, lcnt > I2C_IC_FS_SCL_LCNT_IC_FS_SCL_LCNT_BITS); |
| 76 | invalid_params_if(I2C, hcnt < 8); |
| 77 | invalid_params_if(I2C, lcnt < 8); |
| 78 | |
| 79 | // Per I2C-bus specification a device in standard or fast mode must |
| 80 | // internally provide a hold time of at least 300ns for the SDA signal to |
| 81 | // bridge the undefined region of the falling edge of SCL. A smaller hold |
| 82 | // time of 120ns is used for fast mode plus. |
| 83 | uint sda_tx_hold_count; |
| 84 | if (baudrate < 1000000) { |
| 85 | // sda_tx_hold_count = freq_in [cycles/s] * 300ns * (1s / 1e9ns) |
| 86 | // Reduce 300/1e9 to 3/1e7 to avoid numbers that don't fit in uint. |
| 87 | // Add 1 to avoid division truncation. |
| 88 | sda_tx_hold_count = ((freq_in * 3) / 10000000) + 1; |
| 89 | } else { |
| 90 | // sda_tx_hold_count = freq_in [cycles/s] * 120ns * (1s / 1e9ns) |
| 91 | // Reduce 120/1e9 to 3/25e6 to avoid numbers that don't fit in uint. |
| 92 | // Add 1 to avoid division truncation. |
| 93 | sda_tx_hold_count = ((freq_in * 3) / 25000000) + 1; |
| 94 | } |
| 95 | assert(sda_tx_hold_count <= lcnt - 2); |
| 96 | |
| 97 | i2c->hw->enable = 0; |
| 98 | // Always use "fast" mode (<= 400 kHz, works fine for standard mode too) |
| 99 | hw_write_masked(&i2c->hw->con, |
| 100 | I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB, |
| 101 | I2C_IC_CON_SPEED_BITS |
| 102 | ); |
| 103 | i2c->hw->fs_scl_hcnt = hcnt; |
| 104 | i2c->hw->fs_scl_lcnt = lcnt; |
| 105 | i2c->hw->fs_spklen = lcnt < 16 ? 1 : lcnt / 16; |
| 106 | hw_write_masked(&i2c->hw->sda_hold, |
| 107 | sda_tx_hold_count << I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_LSB, |
| 108 | I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_BITS); |
| 109 | |
| 110 | i2c->hw->enable = 1; |
| 111 | return freq_in / period; |
| 112 | } |
| 113 | |
| 114 | void i2c_set_slave_mode(i2c_inst_t *i2c, bool slave, uint8_t addr) { |
| 115 | invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses |
| 116 | invalid_params_if(I2C, i2c_reserved_addr(addr)); |
| 117 | i2c->hw->enable = 0; |
| 118 | uint32_t ctrl_set_if_master = I2C_IC_CON_MASTER_MODE_BITS | I2C_IC_CON_IC_SLAVE_DISABLE_BITS; |
| 119 | uint32_t ctrl_set_if_slave = I2C_IC_CON_RX_FIFO_FULL_HLD_CTRL_BITS; |
| 120 | if (slave) { |
| 121 | hw_write_masked(&i2c->hw->con, |
| 122 | ctrl_set_if_slave, |
| 123 | ctrl_set_if_master | ctrl_set_if_slave |
| 124 | ); |
| 125 | i2c->hw->sar = addr; |
| 126 | } else { |
| 127 | hw_write_masked(&i2c->hw->con, |
| 128 | ctrl_set_if_master, |
| 129 | ctrl_set_if_master | ctrl_set_if_slave |
| 130 | ); |
| 131 | } |
| 132 | i2c->hw->enable = 1; |
| 133 | } |
| 134 | |
| 135 | static int i2c_write_blocking_internal(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop, |
| 136 | check_timeout_fn timeout_check, struct timeout_state *ts) { |
| 137 | invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses |
| 138 | invalid_params_if(I2C, i2c_reserved_addr(addr)); |
| 139 | // Synopsys hw accepts start/stop flags alongside data items in the same |
| 140 | // FIFO word, so no 0 byte transfers. |
| 141 | invalid_params_if(I2C, len == 0); |
| 142 | invalid_params_if(I2C, ((int)len) < 0); |
| 143 | |
| 144 | i2c->hw->enable = 0; |
| 145 | i2c->hw->tar = addr; |
| 146 | i2c->hw->enable = 1; |
| 147 | |
| 148 | bool abort = false; |
| 149 | bool timeout = false; |
| 150 | |
| 151 | uint32_t abort_reason = 0; |
| 152 | int byte_ctr; |
| 153 | |
| 154 | int ilen = (int)len; |
| 155 | for (byte_ctr = 0; byte_ctr < ilen; ++byte_ctr) { |
| 156 | bool first = byte_ctr == 0; |
| 157 | bool last = byte_ctr == ilen - 1; |
| 158 | |
| 159 | i2c->hw->data_cmd = |
| 160 | bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | |
| 161 | bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | |
| 162 | *src++; |
| 163 | |
| 164 | // Wait until the transmission of the address/data from the internal |
| 165 | // shift register has completed. For this to function correctly, the |
| 166 | // TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag |
| 167 | // was set in i2c_init. |
| 168 | do { |
| 169 | if (timeout_check) { |
| 170 | timeout = timeout_check(ts); |
| 171 | abort |= timeout; |
| 172 | } |
| 173 | tight_loop_contents(); |
| 174 | } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS)); |
| 175 | |
| 176 | // If there was a timeout, don't attempt to do anything else. |
| 177 | if (!timeout) { |
| 178 | abort_reason = i2c->hw->tx_abrt_source; |
| 179 | if (abort_reason) { |
| 180 | // Note clearing the abort flag also clears the reason, and |
| 181 | // this instance of flag is clear-on-read! Note also the |
| 182 | // IC_CLR_TX_ABRT register always reads as 0. |
| 183 | i2c->hw->clr_tx_abrt; |
| 184 | abort = true; |
| 185 | } |
| 186 | |
| 187 | if (abort || (last && !nostop)) { |
| 188 | // If the transaction was aborted or if it completed |
| 189 | // successfully wait until the STOP condition has occured. |
| 190 | |
| 191 | // TODO Could there be an abort while waiting for the STOP |
| 192 | // condition here? If so, additional code would be needed here |
| 193 | // to take care of the abort. |
| 194 | do { |
| 195 | if (timeout_check) { |
| 196 | timeout = timeout_check(ts); |
| 197 | abort |= timeout; |
| 198 | } |
| 199 | tight_loop_contents(); |
| 200 | } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS)); |
| 201 | |
| 202 | // If there was a timeout, don't attempt to do anything else. |
| 203 | if (!timeout) { |
| 204 | i2c->hw->clr_stop_det; |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | // Note the hardware issues a STOP automatically on an abort condition. |
| 210 | // Note also the hardware clears RX FIFO as well as TX on abort, |
| 211 | // because we set hwparam IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. |
| 212 | if (abort) |
| 213 | break; |
| 214 | } |
| 215 | |
| 216 | int rval; |
| 217 | |
| 218 | // A lot of things could have just happened due to the ingenious and |
| 219 | // creative design of I2C. Try to figure things out. |
| 220 | if (abort) { |
| 221 | if (timeout) |
| 222 | rval = PICO_ERROR_TIMEOUT; |
| 223 | else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) { |
| 224 | // No reported errors - seems to happen if there is nothing connected to the bus. |
| 225 | // Address byte not acknowledged |
| 226 | rval = PICO_ERROR_GENERIC; |
| 227 | } else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) { |
| 228 | // Address acknowledged, some data not acknowledged |
| 229 | rval = byte_ctr; |
| 230 | } else { |
| 231 | //panic("Unknown abort from I2C instance @%08x: %08x\n", (uint32_t) i2c->hw, abort_reason); |
| 232 | rval = PICO_ERROR_GENERIC; |
| 233 | } |
| 234 | } else { |
| 235 | rval = byte_ctr; |
| 236 | } |
| 237 | |
| 238 | // nostop means we are now at the end of a *message* but not the end of a *transfer* |
| 239 | i2c->restart_on_next = nostop; |
| 240 | return rval; |
| 241 | } |
| 242 | |
| 243 | int i2c_write_blocking(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop) { |
| 244 | return i2c_write_blocking_internal(i2c, addr, src, len, nostop, NULL, NULL); |
| 245 | } |
| 246 | |
| 247 | int i2c_write_blocking_until(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop, |
| 248 | absolute_time_t until) { |
| 249 | timeout_state_t ts; |
| 250 | return i2c_write_blocking_internal(i2c, addr, src, len, nostop, init_single_timeout_until(&ts, until), &ts); |
| 251 | } |
| 252 | |
| 253 | int i2c_write_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop, |
| 254 | uint timeout_per_char_us) { |
| 255 | timeout_state_t ts; |
| 256 | return i2c_write_blocking_internal(i2c, addr, src, len, nostop, |
| 257 | init_per_iteration_timeout_us(&ts, timeout_per_char_us), &ts); |
| 258 | } |
| 259 | |
| 260 | static int i2c_read_blocking_internal(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, |
| 261 | check_timeout_fn timeout_check, timeout_state_t *ts) { |
| 262 | invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses |
| 263 | invalid_params_if(I2C, i2c_reserved_addr(addr)); |
| 264 | invalid_params_if(I2C, len == 0); |
| 265 | invalid_params_if(I2C, ((int)len) < 0); |
| 266 | |
| 267 | i2c->hw->enable = 0; |
| 268 | i2c->hw->tar = addr; |
| 269 | i2c->hw->enable = 1; |
| 270 | |
| 271 | bool abort = false; |
| 272 | bool timeout = false; |
| 273 | uint32_t abort_reason; |
| 274 | int byte_ctr; |
| 275 | int ilen = (int)len; |
| 276 | for (byte_ctr = 0; byte_ctr < ilen; ++byte_ctr) { |
| 277 | bool first = byte_ctr == 0; |
| 278 | bool last = byte_ctr == ilen - 1; |
| 279 | while (!i2c_get_write_available(i2c)) |
| 280 | tight_loop_contents(); |
| 281 | |
| 282 | i2c->hw->data_cmd = |
| 283 | bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | |
| 284 | bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | |
| 285 | I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read |
| 286 | |
| 287 | do { |
| 288 | abort_reason = i2c->hw->tx_abrt_source; |
| 289 | abort = (bool) i2c->hw->clr_tx_abrt; |
| 290 | if (timeout_check) { |
| 291 | timeout = timeout_check(ts); |
| 292 | abort |= timeout; |
| 293 | } |
| 294 | } while (!abort && !i2c_get_read_available(i2c)); |
| 295 | |
| 296 | if (abort) |
| 297 | break; |
| 298 | |
| 299 | *dst++ = (uint8_t) i2c->hw->data_cmd; |
| 300 | } |
| 301 | |
| 302 | int rval; |
| 303 | |
| 304 | if (abort) { |
| 305 | if (timeout) |
| 306 | rval = PICO_ERROR_TIMEOUT; |
| 307 | else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) { |
| 308 | // No reported errors - seems to happen if there is nothing connected to the bus. |
| 309 | // Address byte not acknowledged |
| 310 | rval = PICO_ERROR_GENERIC; |
| 311 | } else { |
| 312 | // panic("Unknown abort from I2C instance @%08x: %08x\n", (uint32_t) i2c->hw, abort_reason); |
| 313 | rval = PICO_ERROR_GENERIC; |
| 314 | } |
| 315 | } else { |
| 316 | rval = byte_ctr; |
| 317 | } |
| 318 | |
| 319 | i2c->restart_on_next = nostop; |
| 320 | return rval; |
| 321 | } |
| 322 | |
| 323 | int i2c_read_blocking(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop) { |
| 324 | return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, NULL, NULL); |
| 325 | } |
| 326 | |
| 327 | int i2c_read_blocking_until(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, absolute_time_t until) { |
| 328 | timeout_state_t ts; |
| 329 | return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, init_single_timeout_until(&ts, until), &ts); |
| 330 | } |
| 331 | |
| 332 | int i2c_read_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, |
| 333 | uint timeout_per_char_us) { |
| 334 | timeout_state_t ts; |
| 335 | return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, |
| 336 | init_per_iteration_timeout_us(&ts, timeout_per_char_us), &ts); |
| 337 | } |