diff options
Diffstat (limited to 'docs/drivers/i2c.md')
| -rw-r--r-- | docs/drivers/i2c.md | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/docs/drivers/i2c.md b/docs/drivers/i2c.md new file mode 100644 index 0000000000..10949ed59e --- /dev/null +++ b/docs/drivers/i2c.md | |||
| @@ -0,0 +1,290 @@ | |||
| 1 | # I2C Master Driver {#i2c-master-driver} | ||
| 2 | |||
| 3 | The I2C Master drivers used in QMK have a set of common functions to allow portability between MCUs. | ||
| 4 | |||
| 5 | ## Usage {#usage} | ||
| 6 | |||
| 7 | In most cases, the I2C Master driver code is automatically included if you are using a feature or driver which requires it, such as [OLED](../features/oled_driver). | ||
| 8 | |||
| 9 | However, if you need to use the driver standalone, add the following to your `rules.mk`: | ||
| 10 | |||
| 11 | ```make | ||
| 12 | I2C_DRIVER_REQUIRED = yes | ||
| 13 | ``` | ||
| 14 | |||
| 15 | You can then call the I2C API by including `i2c_master.h` in your code. | ||
| 16 | |||
| 17 | ## I2C Addressing {#note-on-i2c-addresses} | ||
| 18 | |||
| 19 | All of the addresses expected by this driver should be pushed to the upper 7 bits of the address byte. Setting | ||
| 20 | the lower bit (indicating read/write) will be done by the respective functions. Almost all I2C addresses listed | ||
| 21 | on datasheets and the internet will be represented as 7 bits occupying the lower 7 bits and will need to be | ||
| 22 | shifted to the left (more significant) by one bit. This is easy to do via the bitwise shift operator `<< 1`. | ||
| 23 | |||
| 24 | You can either do this on each call to the functions below, or once in your definition of the address. For example, if your device has an address of `0x18`: | ||
| 25 | |||
| 26 | ```c | ||
| 27 | #define MY_I2C_ADDRESS (0x18 << 1) | ||
| 28 | ``` | ||
| 29 | |||
| 30 | See https://www.robot-electronics.co.uk/i2c-tutorial for more information about I2C addressing and other technical details. | ||
| 31 | |||
| 32 | ## AVR Configuration {#avr-configuration} | ||
| 33 | |||
| 34 | The following defines can be used to configure the I2C master driver: | ||
| 35 | |||
| 36 | |`config.h` Override|Description |Default | | ||
| 37 | |-------------------|---------------------|--------| | ||
| 38 | |`F_SCL` |Clock frequency in Hz|`400000`| | ||
| 39 | |||
| 40 | No further setup is required - just connect the `SDA` and `SCL` pins of your I2C devices to the matching pins on the MCU: | ||
| 41 | |||
| 42 | |MCU |`SCL`|`SDA`| | ||
| 43 | |------------------|-----|-----| | ||
| 44 | |ATmega16/32U4 |`D0` |`D1` | | ||
| 45 | |AT90USB64/128 |`D0` |`D1` | | ||
| 46 | |ATmega32A |`C0` |`C1` | | ||
| 47 | |ATmega328/P |`C5` |`C4` | | ||
| 48 | |||
| 49 | ::: tip | ||
| 50 | The ATmega16/32U2 does not possess I2C functionality, and so cannot use this driver. | ||
| 51 | ::: | ||
| 52 | |||
| 53 | ## ChibiOS/ARM Configuration {#arm-configuration} | ||
| 54 | |||
| 55 | You'll need to determine which pins can be used for I2C -- a an example, STM32 parts generally have multiple I2C peripherals, labeled I2C1, I2C2, I2C3 etc. | ||
| 56 | |||
| 57 | To enable I2C, modify your board's `halconf.h` to enable I2C: | ||
| 58 | |||
| 59 | ```c | ||
| 60 | #define HAL_USE_I2C TRUE | ||
| 61 | ``` | ||
| 62 | |||
| 63 | Then, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example: | ||
| 64 | |||
| 65 | ```c | ||
| 66 | #undef STM32_I2C_USE_I2C2 | ||
| 67 | #define STM32_I2C_USE_I2C2 TRUE | ||
| 68 | ``` | ||
| 69 | |||
| 70 | |`mcuconf.h` Setting |Description |Default| | ||
| 71 | |----------------------------|----------------------------------------------------------------------------------|-------| | ||
| 72 | |`STM32_I2C_BUSY_TIMEOUT` |Time in milliseconds until the I2C command is aborted if no response is received |`50` | | ||
| 73 | |`STM32_I2C_XXX_IRQ_PRIORITY`|Interrupt priority for hardware driver XXX (THIS IS AN EXPERT SETTING) |`10` | | ||
| 74 | |`STM32_I2C_USE_DMA` |Enable/Disable the ability of the MCU to offload the data transfer to the DMA unit|`TRUE` | | ||
| 75 | |`STM32_I2C_XXX_DMA_PRIORITY`|Priority of DMA unit for hardware driver XXX (THIS IS AN EXPERT SETTING) |`1` | | ||
| 76 | |||
| 77 | Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303. | ||
| 78 | |||
| 79 | |`config.h` Overrride |Description |Default| | ||
| 80 | |------------------------|--------------------------------------------------------------|-------| | ||
| 81 | |`I2C_DRIVER` |I2C peripheral to use - I2C1 -> `I2CD1`, I2C2 -> `I2CD2` etc. |`I2CD1`| | ||
| 82 | |`I2C1_SCL_PIN` |The pin definition for SCL |`B6` | | ||
| 83 | |`I2C1_SCL_PAL_MODE` |The alternate function mode for SCL |`4` | | ||
| 84 | |`I2C1_SDA_PIN` |The pin definition for SDA |`B7` | | ||
| 85 | |`I2C1_SDA_PAL_MODE` |The alternate function mode for SDA |`4` | | ||
| 86 | |||
| 87 | The following configuration values depend on the specific MCU in use. | ||
| 88 | |||
| 89 | ### I2Cv1 {#arm-configuration-i2cv1} | ||
| 90 | |||
| 91 | * STM32F1xx | ||
| 92 | * STM32F2xx | ||
| 93 | * STM32F4xx | ||
| 94 | * STM32L0xx | ||
| 95 | * STM32L1xx | ||
| 96 | |||
| 97 | See [this page](https://www.playembedded.org/blog/stm32-i2c-chibios/#7_I2Cv1_configuration_structure) for the I2Cv1 configuration structure. | ||
| 98 | |||
| 99 | |`config.h` Override|Default | | ||
| 100 | |-------------------|----------------| | ||
| 101 | |`I2C1_OPMODE` |`OPMODE_I2C` | | ||
| 102 | |`I2C1_CLOCK_SPEED` |`100000` | | ||
| 103 | |`I2C1_DUTY_CYCLE` |`STD_DUTY_CYCLE`| | ||
| 104 | |||
| 105 | ### I2Cv2 {#arm-configuration-i2cv2} | ||
| 106 | |||
| 107 | * STM32F0xx | ||
| 108 | * STM32F3xx | ||
| 109 | * STM32F7xx | ||
| 110 | * STM32L4xx | ||
| 111 | |||
| 112 | See [this page](https://www.playembedded.org/blog/stm32-i2c-chibios/#8_I2Cv2_I2Cv3_configuration_structure) for the I2Cv2 configuration structure. | ||
| 113 | |||
| 114 | |`config.h` Override |Default| | ||
| 115 | |---------------------|-------| | ||
| 116 | |`I2C1_TIMINGR_PRESC` |`0U` | | ||
| 117 | |`I2C1_TIMINGR_SCLDEL`|`7U` | | ||
| 118 | |`I2C1_TIMINGR_SDADEL`|`0U` | | ||
| 119 | |`I2C1_TIMINGR_SCLH` |`38U` | | ||
| 120 | |`I2C1_TIMINGR_SCLL` |`129U` | | ||
| 121 | |||
| 122 | ## API {#api} | ||
| 123 | |||
| 124 | ### `void i2c_init(void)` {#api-i2c-init} | ||
| 125 | |||
| 126 | Initialize the I2C driver. This function must be called only once, before any of the below functions can be called. | ||
| 127 | |||
| 128 | This function is weakly defined, meaning it can be overridden if necessary for your particular use case: | ||
| 129 | |||
| 130 | ```c | ||
| 131 | void i2c_init(void) { | ||
| 132 | gpio_set_pin_input(B6); // Try releasing special pins for a short time | ||
| 133 | gpio_set_pin_input(B7); | ||
| 134 | wait_ms(10); // Wait for the release to happen | ||
| 135 | |||
| 136 | palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); // Set B6 to I2C function | ||
| 137 | palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); // Set B7 to I2C function | ||
| 138 | } | ||
| 139 | ``` | ||
| 140 | |||
| 141 | --- | ||
| 142 | |||
| 143 | ### `i2c_status_t i2c_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)` {#api-i2c-transmit} | ||
| 144 | |||
| 145 | Send multiple bytes to the selected I2C device. | ||
| 146 | |||
| 147 | #### Arguments {#api-i2c-transmit-arguments} | ||
| 148 | |||
| 149 | - `uint8_t address` | ||
| 150 | The 7-bit I2C address of the device. | ||
| 151 | - `uint8_t *data` | ||
| 152 | A pointer to the data to transmit. | ||
| 153 | - `uint16_t length` | ||
| 154 | The number of bytes to write. Take care not to overrun the length of `data`. | ||
| 155 | - `uint16_t timeout` | ||
| 156 | The time in milliseconds to wait for a response from the target device. | ||
| 157 | |||
| 158 | #### Return Value {#api-i2c-transmit-return} | ||
| 159 | |||
| 160 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
| 161 | |||
| 162 | --- | ||
| 163 | |||
| 164 | ### `i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-receive} | ||
| 165 | |||
| 166 | Receive multiple bytes from the selected I2C device. | ||
| 167 | |||
| 168 | #### Arguments {#api-i2c-receive-arguments} | ||
| 169 | |||
| 170 | - `uint8_t address` | ||
| 171 | The 7-bit I2C address of the device. | ||
| 172 | - `uint8_t *data` | ||
| 173 | A pointer to the buffer to read into. | ||
| 174 | - `uint16_t length` | ||
| 175 | The number of bytes to read. Take care not to overrun the length of `data`. | ||
| 176 | - `uint16_t timeout` | ||
| 177 | The time in milliseconds to wait for a response from the target device. | ||
| 178 | |||
| 179 | #### Return Value {#api-i2c-receive-return} | ||
| 180 | |||
| 181 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
| 182 | |||
| 183 | --- | ||
| 184 | |||
| 185 | ### `i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-write-register} | ||
| 186 | |||
| 187 | Writes to a register with an 8-bit address on the I2C device. | ||
| 188 | |||
| 189 | #### Arguments {#api-i2c-write-register-arguments} | ||
| 190 | |||
| 191 | - `uint8_t devaddr` | ||
| 192 | The 7-bit I2C address of the device. | ||
| 193 | - `uint8_t regaddr` | ||
| 194 | The register address to write to. | ||
| 195 | - `uint8_t *data` | ||
| 196 | A pointer to the data to transmit. | ||
| 197 | - `uint16_t length` | ||
| 198 | The number of bytes to write. Take care not to overrun the length of `data`. | ||
| 199 | - `uint16_t timeout` | ||
| 200 | The time in milliseconds to wait for a response from the target device. | ||
| 201 | |||
| 202 | #### Return Value {#api-i2c-write-register-return} | ||
| 203 | |||
| 204 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
| 205 | |||
| 206 | --- | ||
| 207 | |||
| 208 | ### `i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-write-register16} | ||
| 209 | |||
| 210 | Writes to a register with a 16-bit address (big endian) on the I2C device. | ||
| 211 | |||
| 212 | #### Arguments {#api-i2c-write-register16-arguments} | ||
| 213 | |||
| 214 | - `uint8_t devaddr` | ||
| 215 | The 7-bit I2C address of the device. | ||
| 216 | - `uint16_t regaddr` | ||
| 217 | The register address to write to. | ||
| 218 | - `uint8_t *data` | ||
| 219 | A pointer to the data to transmit. | ||
| 220 | - `uint16_t length` | ||
| 221 | The number of bytes to write. Take care not to overrun the length of `data`. | ||
| 222 | - `uint16_t timeout` | ||
| 223 | The time in milliseconds to wait for a response from the target device. | ||
| 224 | |||
| 225 | #### Return Value {#api-i2c-write-register16-return} | ||
| 226 | |||
| 227 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
| 228 | |||
| 229 | --- | ||
| 230 | |||
| 231 | ### `i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-read-register} | ||
| 232 | |||
| 233 | Reads from a register with an 8-bit address on the I2C device. | ||
| 234 | |||
| 235 | #### Arguments {#api-i2c-read-register-arguments} | ||
| 236 | |||
| 237 | - `uint8_t devaddr` | ||
| 238 | The 7-bit I2C address of the device. | ||
| 239 | - `uint8_t regaddr` | ||
| 240 | The register address to read from. | ||
| 241 | - `uint16_t length` | ||
| 242 | The number of bytes to read. Take care not to overrun the length of `data`. | ||
| 243 | - `uint16_t timeout` | ||
| 244 | The time in milliseconds to wait for a response from the target device. | ||
| 245 | |||
| 246 | #### Return Value {#api-i2c-read-register-return} | ||
| 247 | |||
| 248 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
| 249 | |||
| 250 | --- | ||
| 251 | |||
| 252 | ### `i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-read-register16} | ||
| 253 | |||
| 254 | Reads from a register with a 16-bit address (big endian) on the I2C device. | ||
| 255 | |||
| 256 | #### Arguments {#api-i2c-read-register16-arguments} | ||
| 257 | |||
| 258 | - `uint8_t devaddr` | ||
| 259 | The 7-bit I2C address of the device. | ||
| 260 | - `uint16_t regaddr` | ||
| 261 | The register address to read from. | ||
| 262 | - `uint16_t length` | ||
| 263 | The number of bytes to read. Take care not to overrun the length of `data`. | ||
| 264 | - `uint16_t timeout` | ||
| 265 | The time in milliseconds to wait for a response from the target device. | ||
| 266 | |||
| 267 | #### Return Value {#api-i2c-read-register16-return} | ||
| 268 | |||
| 269 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
| 270 | |||
| 271 | --- | ||
| 272 | |||
| 273 | ### `i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout)` {#api-i2c-ping-address} | ||
| 274 | |||
| 275 | Pings the I2C bus for a specific address. | ||
| 276 | |||
| 277 | On ChibiOS a "best effort" attempt is made by reading a single byte from register 0 at the requested address. This should generally work except for I2C devices that do not not respond to a register 0 read request, which will result in a false negative result (unsucessful response to ping attempt). | ||
| 278 | |||
| 279 | This function is weakly defined, meaning it can be overridden if necessary for your particular use case: | ||
| 280 | |||
| 281 | #### Arguments | ||
| 282 | |||
| 283 | - `uint8_t address` | ||
| 284 | The 7-bit I2C address of the device (ie. without the read/write bit - this will be set automatically). | ||
| 285 | - `uint16_t timeout` | ||
| 286 | The time in milliseconds to wait for a response from the target device. | ||
| 287 | |||
| 288 | #### Return Value | ||
| 289 | |||
| 290 | `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`. | ||
