URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
[/] [neorv32/] [trunk/] [docs/] [datasheet/] [soc_twi.adoc] - Rev 74
Go to most recent revision | Compare with Previous | Blame | View Log
<<<
: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`) - despite of the number of connected devices - it allows easy interconnections of
several peripheral nodes.
The NEORV32 TWI implements a **TWI controller**. It supports "clock so a slow peripheral can halt
the transmission by pulling the SCL line low. Currently, **no multi-controller
support** is available. Also, the NEORV32 TWI unit cannot operate in peripheral mode.
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 send by writing a byte to the `DATA` register. Received data can also be read from this
register. The TWI controller is busy (transmitting data or performing a START or STOP condition) as long as the
_TWI_CTRL_BUSY_ bit in the control register is set.
An accessed 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 it is cleared after a
transmission, the peripheral has send a not-acknowledge (NACK). The NEORV32 TWI controller can also
send an ACK by itself ("controller acknowledge _MACK_") after a transmission by pulling SDA low during the
ACK time slot. Set the _TWI_CTRL_MACK_ bit to activate this feature. If this bit is cleared, the ACK/NACK of the
peripheral is sampled in this time slot instead (normal mode).
In summary, the following independent TWI operations can be triggered by the application program:
* send START condition (also as REPEATED START condition)
* send STOP condition
* send (at least) one byte while also sampling one byte from the bus
[TIP]
A transmission can be terminated at any time by disabling the TWI module
by clearing the _TWI_CTRL_EN_ control register bit.
[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.
The TWI clock frequency is defined via the 3-bit _TWI_CTRL_PRSCx_ clock prescaler. The following prescalers
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_ configuration, the actual TWI clock frequency f~SCL~ is derived from the processor main clock f~main~ and is determined by:
_**f~SCL~**_ = _f~main~[Hz]_ / (4 * `clock_prescaler`)
**TWI Interrupt**
The SPI module provides a single interrupt to signal "operation done" to the CPU. Whenever the TWI
module completes the current operation (generate stop condition, generate start conditions or transfer byte),
the interrupt is triggered. Once triggered, the interrupt has to be explicitly cleared again by
writing zero to the according <<_mip>> CSR bit.
.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
.9+<| `0xffffffb0` .9+<| `NEORV32_TWI.CTRL` <|`0` _TWI_CTRL_EN_ ^| r/w <| TWI enable
<|`1` _TWI_CTRL_START_ ^| r/w <| generate START condition
<|`2` _TWI_CTRL_STOP_ ^| r/w <| generate STOP condition
<|`3` _TWI_CTRL_PRSC0_ ^| r/w .3+<| 3-bit clock prescaler select
<|`4` _TWI_CTRL_PRSC1_ ^| r/w
<|`5` _TWI_CTRL_PRSC2_ ^| r/w
<|`6` _TWI_CTRL_MACK_ ^| r/w <| generate controller ACK for each transmission ("MACK")
<|`30` _TWI_CTRL_ACK_ ^| r/- <| ACK received when set
<|`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
|=======================
Go to most recent revision | Compare with Previous | Blame | View Log