<<< :sectnums: ==== Two-Wire Serial Interface Controller (TWI) [cols="<3,<3,<4"] [frame="topbot",grid="none"] |======================= | Hardware source file(s): | neorv32_twi.vhd | | Software driver file(s): | neorv32_twi.c | | | neorv32_twi.h | | Top entity port: | `twi_sda_i` | 1-bit serial data line sense input | | `twi_sda_o` | 1-bit serial data line output (pull low only) | | `twi_scl_i` | 1-bit serial clock line sense input | | `twi_scl_o` | 1-bit serial clock line output (pull low only) | Configuration generics: | `IO_TWI_EN` | implement TWI controller when `true` | CPU interrupts: | fast IRQ channel 7 | transmission done interrupt (see <<_processor_interrupts>>) |======================= **Overview** The NEORV32 TWI implements a **TWI controller**. Currently, **no multi-controller support** is available. Furthermore, the NEORV32 TWI unit cannot operate in peripheral mode. [IMPORTANT] The serial clock (SCL) and the serial data (SDA) lines can only be actively driven low by the controller. Hence, external pull-up resistors are required for these lines. **Tri-State Drivers** The TWI module requires two tri-state drivers (actually: open-drain) for the SDA and SCL lines, which have to be implemented in the top module of the setup. A generic VHDL example is given below (`sda` and `scl` are the actual TWI bus signal, which are of type `std_logic`). .TWI VHDL tri-state driver example [source,VHDL] ---- sda <= '0' when (twi_sda_o = '0') else 'Z'; -- drive scl <= '0' when (twi_scl_o = '0') else 'Z'; -- drive twi_sda_i <= std_ulogic(sda); -- sense twi_scl_i <= std_ulogic(scl); -- sense ---- **TWI Clock Speed** The TWI clock frequency is programmed by the 3-bit `TWI_CTRL_PRSCx` clock prescaler for a coarse selection and a 4-bit clock divider `TWI_CTRL_CDIVx` for a fine selection. .TWI prescaler configuration [cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"] [options="header",grid="rows"] |======================= | **`TWI_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111` | Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096 |======================= Based on the the clock configuration, the actual TWI clock frequency f~SCL~ is derived from the processor's main clock f~main~ according to the following equation: _**f~SCL~**_ = _f~main~[Hz]_ / (4 * `clock_prescaler` * (1 + TWI_CTRL_CDIV)) Hence, the maximum TWI clock is f~main~ / 8 and the lowest TWI clock is f~main~ / 262144. The generated TWI clock is always symmetric having a duty cycle of exactly 50%. However, an accessed peripheral can "slow down" the bus clock by using **clock stretching** (= actively driving the SCL line low). The controller will pause operation in this case if clock stretching is enabled via the `TWI_CTRL_CSEN` bit of the unit's control register `CTRL` **TWI Transfers** The TWI is enabled via the `TWI_CTRL_EN` bit in the `CTRL` control register. The user program can start / stop a transmission by issuing a START or STOP condition. These conditions are generated by setting the according bits (`TWI_CTRL_START` or `TWI_CTRL_STOP`) in the control register. Data is transferred via the TWI bus by writing a byte to the `DATA` register. The written byte is send via the TWI bus and the received byte from the bus is also available in this register after the transmission is completed. The TWI operation (transmitting data or performing a START or STOP condition) is in progress as long as the control register's `TWI_CTRL_BUSY` bit is set. [TIP] A transmission can be terminated at any time by disabling the TWI module by clearing the _TWI_CTRL_EN_ control register bit. This will also reset the whole module. [NOTE] When reading data from a device, an all-one byte (`0xFF`) has to be written to TWI data register `NEORV32_TWI.DATA` so the accessed device can actively pull-down SDA when required. **TWI ACK/NACK and MACK** An accessed TWI peripheral has to acknowledge each transferred byte. When the `TWI_CTRL_ACK` bit is set after a completed transmission the accessed peripheral has send an ACKNOWLEDGE (ACK). If this bit is cleared after a completed transmission, the peripheral has send a_NOT-ACKNOWLEDGE (NACK). The NEORV32 TWI controller can also send an ACK generated by itself ("controller acknowledge / MACK") right after transmitting a byte by driving SDA low during the ACK time slot. Some TWI modules require this MACK to acknowledge certain data movement operations. The control register's `TWI_CTRL_MACK` bit has to be set to make the TWI module automatically generate a MACK after the byte transmission has been completed. If this bit is cleared, the ACK/NACK generated by the peripheral is sampled in this time slot instead (normal mode). **TWI Bus Status** The TWI controller can check if the TWI bus is currently claimed (SCL and SDA both low). The bus can be claimed by the NEORV32 TWI itself or by any other controller. Bit `TWI_CTRL_CLAIME` of the control register will be set if the bus is currently claimed. **TWI Interrupt** The TWI module provides a single interrupt to signal "transmission done" to the CPU. Whenever the TWI module completes the current transmission of one byte the interrupt is triggered. Note the the interrupt is **not** triggered when completing a START or STOP condition. Once triggered, the interrupt has to be explicitly cleared again by writing zero to the according <<_mip>> CSR bit. **Register Map** .TWI register map (`struct NEORV32_TWI`) [cols="<2,<1,<4,^1,<7"] [options="header",grid="all"] |======================= | Address | Name [C] | Bit(s), Name [C] | R/W | Function .10+<| `0xfffff900` .10+<| `CTRL` <|`0` `TWI_CTRL_EN` ^| r/w <| TWI enable, reset if cleared <|`1` `TWI_CTRL_START` ^| -/w <| generate START condition, auto-clears <|`2` `TWI_CTRL_STOP` ^| -/w <| generate STOP condition, auto-clears <|`3` `TWI_CTRL_MACK` ^| r/w <| generate controller-ACK for each transmission ("MACK") <|`4` `TWI_CTRL_CSEN` ^| r/w <| allow clock stretching when set <|`7:5` `TWI_CTRL_PRSC2 : TWI_CTRL_PRSC0` ^| r/w <| 3-bit clock prescaler select <|`11:8` `TWI_CTRL_CDIV3 : TWI_CTRL_CDIV0` ^| r/w <| 4-bit clock divider <|`28:12` - ^| r/- <| _reserved_, read as zero <|`29` `TWI_CTRL_CLAIMED` ^| r/- <| set if the TWI bus is claimed by any controller <|`30` `TWI_CTRL_ACK` ^| r/- <| ACK received when set, NACK received when cleared <|`31` `TWI_CTRL_BUSY` ^| r/- <| transfer/START/STOP in progress when set | `0xfffff904` | `DATA` |`7:0` | r/w | receive/transmit data |=======================