146 lines
7.8 KiB
Text
146 lines
7.8 KiB
Text
<<<
|
|
: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_io` | 1-bit bi-directional serial data
|
|
| | `twi_scl_io` | 1-bit bi-directional serial clock
|
|
| Configuration generics: | _IO_TWI_EN_ | implement TWI controller when _true_
|
|
| CPU interrupts: | fast IRQ channel 7 | transmission done interrupt (see <<_processor_interrupts>>)
|
|
|=======================
|
|
|
|
|
|
**Theory of Operation**
|
|
|
|
The two wire interface - also called "I²C" - is a quite famous interface for connecting several on-board
|
|
components. Since this interface only needs two signals (the serial data line `twi_sda_io` and the serial
|
|
clock line `twi_scl_io`) for an arbitrarily number of devices it allows easy interconnections of
|
|
several peripheral nodes.
|
|
|
|
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.
|
|
|
|
|
|
**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.
|
|
|
|
The following pre-scalers (_TWI_CTRL_PRSCx_) are available:
|
|
|
|
.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 _TWI_CTRL_PRSCx_ and _TWI_CTRL_CDIVx_ 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.
|
|
|
|
|
|
**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_. 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_CLAIMED_ of the control register will be set if the bus
|
|
is currently claimed.
|
|
|
|
|
|
**Summary**
|
|
|
|
In summary, a complete TWI transfer is based on the following elementary operation:
|
|
|
|
[start=1]
|
|
. generate START condition by setting _TWI_CTRL_START_
|
|
. wait until _TWI_CTRL_BUSY_ has cleared (start condition completed)
|
|
. transfer one byte while also sampling one byte from the bus (this also samples ACK/NACK or generates a
|
|
controller ACK "MACK" if _TWI_CTRL_MACK_ is set) by writing data to `NEORV32_TWI.DATA`; this step can be repeated to
|
|
send/receive an arbitrary number of bytes
|
|
. wait until _TWI_CTRL_BUSY_ has cleared (data transfer completed)
|
|
. optionally generate another START condition (as REPEATED-START condition) by setting _TWI_CTRL_START_ again
|
|
. wait until _TWI_CTRL_BUSY_ has cleared (repeated-start condition completed)
|
|
. generate STOP condition by setting _TWI_CTRL_STOP_
|
|
. wait until _TWI_CTRL_BUSY_ has cleared (stop condition completed)
|
|
|
|
[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 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,<2,<4,^1,<7"]
|
|
[options="header",grid="all"]
|
|
|=======================
|
|
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
|
|
.10+<| `0xffffffb0` .10+<| `NEORV32_TWI.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
|
|
| `0xffffffb4` | `NEORV32_TWI.DATA` |`7:0` _TWI_DATA_MSB_ : _TWI_DATA_LSB_ | r/w | receive/transmit data
|
|
|=======================
|