Projet_SETI_RISC-V/neorv32/docs/datasheet/soc_twi.adoc

147 lines
7.8 KiB
Text
Raw Normal View History

2023-03-06 14:48:14 +01:00
<<<
: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
|=======================