190 lines
9.9 KiB
Plaintext
190 lines
9.9 KiB
Plaintext
<<<
|
|
:sectnums:
|
|
==== One-Wire Serial Interface Controller (ONEWIRE)
|
|
|
|
[cols="<3,<3,<4"]
|
|
[frame="topbot",grid="none"]
|
|
|=======================
|
|
| Hardware source file(s): | neorv32_onewire.vhd |
|
|
| Software driver file(s): | neorv32_onewire.c |
|
|
| | neorv32_onewire.h |
|
|
| Top entity port: | `onewire_i` | 1-bit 1-wire bus sense input
|
|
| | `onewire_o` | 1-bit 1-wire bus output (pull low only)
|
|
| Configuration generics: | `IO_ONEWIRE_EN` | implement ONEWIRE interface controller when `true`
|
|
| CPU interrupts: | fast IRQ channel 13 | operation done interrupt (see <<_processor_interrupts>>)
|
|
|=======================
|
|
|
|
|
|
**Overview**
|
|
|
|
The NEORV32 ONEWIRE module implements a single-wire interface controller that is compatible to the
|
|
_Dallas/Maxim 1-Wire_ protocol, which is an asynchronous half-duplex bus requiring only a single signal wire
|
|
connected to `onewire_io` (plus ground).
|
|
|
|
The bus is based on a single open-drain signal. The controller and all the devices can only pull-down the bus actively.
|
|
Hence, an external pull-up resistor is required. Recommended values are between 1kΩ and 4kΩ depending on the bus
|
|
characteristics (wire length, number of devices, etc.). Furthermore, a series resistor (~100Ω) at the controller side
|
|
is recommended to control the slew rate and to reduce signal reflections. Also, additional external ESD protection clamp diodes
|
|
should be added to the bus line.
|
|
|
|
|
|
**Tri-State Drivers**
|
|
|
|
The ONEWIRE module requires a tri-state driver (actually, open-drain) for the 1-wire bus line, which has to be implemented
|
|
in the top module of the setup. A generic VHDL example is given below (`onewire` is the actual 1-wire
|
|
bus signal, which is of type `std_logic`).
|
|
|
|
.ONEWIRE VHDL tri-state driver example
|
|
[source,VHDL]
|
|
----
|
|
onewire <= '0' when (onewire_o = '0') else 'Z'; -- drive
|
|
onewire_i <= std_ulogic(onewire); -- sense
|
|
----
|
|
|
|
|
|
**Theory of Operation**
|
|
|
|
The ONEWIRE controller provides two interface registers: `CTRL` and `DATA.` The control registers (`CTRL`)
|
|
is used to configure the module, to trigger bus transactions and to monitor the current state of the module.
|
|
The `DATA` register is used to read/write data from/to the bus.
|
|
|
|
The module is enabled by setting the `ONEWIRE_CTRL_EN` bit in the control register. If this bit is cleared, the
|
|
module is automatically reset and the bus is brought to high-level (due to the external pull-up resistor).
|
|
The basic timing configuration is programmed via the clock prescaler bits `ONEWIRE_CTRL_PRSCx` and the
|
|
clock divider bits `ONEWIRE_CTRL_CLKDIVx` (see next section).
|
|
|
|
The controller can execute three basic bus operations, which are triggered by setting one out of three specific
|
|
control register bits (the bits auto-clear):
|
|
|
|
[start=1]
|
|
. generate reset pulse and check for device presence; triggered when setting `ONEWIRE_CTRL_TRIG_RST`
|
|
. transfer a single-bit (read-while-write); triggered when setting `ONEWIRE_CTRL_TRIG_BIT`
|
|
. transfer a full-byte (read-while-write); triggered when setting `ONEWIRE_CTRL_TRIG_BYTE`
|
|
|
|
[IMPORTANT]
|
|
Only one trigger bit may be set at once, otherwise undefined behavior might occur.
|
|
|
|
When a single-bit operation has been triggered, the data previously written to `DATA[0]` will be send to the bus
|
|
and `DATA[7]` will be sampled from the bus. Accordingly, a full-byte transmission will send the previously
|
|
byte written to `DATA[7:0]` to the bus and will update `DATA[7:0]` with the data read from the bus (LSB-first).
|
|
The triggered operation has completed when the module's busy flag `ONEWIRE_CTRL_BUSY` has cleared again.
|
|
|
|
.Read from Bus
|
|
[NOTE]
|
|
In order to read a single bit from the bus `DATA[0]` has to set to `1` before triggering the bit transmission
|
|
operation to allow the accessed device to pull-down the bus. Accordingly, `DATA` has to be set to `0xFF` before
|
|
triggering the byte transmission operation when the controller shall read a byte from the bus.
|
|
|
|
The `ONEWIRE_CTRL_PRESENCE` bit gets set if at least one device has send a "presence" signal right after the
|
|
reset pulse.
|
|
|
|
|
|
**Bus Timing**
|
|
|
|
The control register provides a 2-bit clock prescaler select (`ONEWIRE_CTRL_PRSCx`) and a 8-bit clock divider
|
|
(`ONEWIRE_CTRL_CLKDIVx`) for timing configuration. Both are used to define the elementary **base time T~base~**.
|
|
All bus operations are timed using _multiples_ of this elementary base time.
|
|
|
|
.ONEWIRE Clock Prescaler Configurations
|
|
[cols="<4,^1,^1,^1,^1"]
|
|
[options="header",grid="rows"]
|
|
|=======================
|
|
| **`ONEWIRE_CTRL_PRSCx`** | `0b00` | `0b01` | `0b10` | `0b11`
|
|
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64
|
|
|=======================
|
|
|
|
Together with the clock divider value (`ONEWIRE_CTRL_PRSCx` bits = `clock_divider`) the base time is defined by the
|
|
following formula:
|
|
|
|
_**T~base~**_ = (1 / _f~main~[Hz]_) * `clock_prescaler` * (`clock_divider` + 1)
|
|
|
|
Example:
|
|
|
|
* _f~main~_ = 100MHz
|
|
* clock prescaler select = `0b01` -> `clock_prescaler` = 4
|
|
* clock divider `clock_divider` = 249
|
|
|
|
_**T~base~**_ = (1 / 100000000Hz) * 4 * (249 + 1) = 10000ns = **10µs**
|
|
|
|
The base time is used to coordinate all bus interactions. Hence, all delays, time slots and points in time are
|
|
quantized as multiples of the base time. The following images show the two basic operations of the ONEWIRE
|
|
controller: single-bit (0 or 1) transaction and reset with presence detect. The relevant points in time are
|
|
shown as _absolute_ time (in multiples of the time base) with the bus' falling edge as reference point.
|
|
|
|
[cols="^2,^2"]
|
|
[grid="none"]
|
|
|=======================
|
|
a| image::onewire_data.png[align=center]
|
|
a| image::onewire_reset.png[align=center]
|
|
| Single-bit data transmission (not to scale) | Reset pulse and presence detect (not to scale)
|
|
|=======================
|
|
|
|
.Data Transmission Timing
|
|
[cols="<2,<6,^3,^3"]
|
|
[options="header",grid="rows"]
|
|
|=======================
|
|
| Symbol | Description | Multiples of T~base~ | Time when T~base~ = 10µs
|
|
4+^| **Single-bit data transmission**
|
|
| `t0` (a->b) | Time until end of active low-phase when writing a `'1'` or when reading | 1 | 10µs
|
|
| `t1` (a->c) | Time until controller samples bus state (read operation) | 2 | 20µs
|
|
| `t2` (a->d) | Time until end of bit time slot (when writing a `'0'` or when reading) | 7 | 70µs
|
|
| `t3` (a->e) | Time until end of inter-slot pause (= total duration of one bit) | 9 | 90µs
|
|
4+^| **Reset pulse and presence detect**
|
|
| `t4` (f->g) | Time until end of active reset pulse | 48 | 480µs
|
|
| `t5` (f->h) | Time until controller samples bus presence | 55 | 550µs
|
|
| `t6` (f->i) | Time until end of presence phase | 96 | 960µs
|
|
|=======================
|
|
|
|
[NOTE]
|
|
The default values for base time multiples were chosen to for stable and reliable bus
|
|
operation (not for maximum throughput).
|
|
|
|
The absolute points in time are hardwired by the VHDL code and cannot be changed during runtime.
|
|
However, the timing parameter can be customized by editing the ONEWIRE's VHDL source file:
|
|
|
|
.Hardwired time configuration in `neorv32_onewire.vhd`
|
|
[source,VHDL]
|
|
----
|
|
-- timing configuration (absolute time in multiples of the base tick time t_base) --
|
|
constant t_write_one_c : unsigned(6 downto 0) := to_unsigned( 1, 7); -- t0
|
|
constant t_read_sample_c : unsigned(6 downto 0) := to_unsigned( 2, 7); -- t1
|
|
constant t_slot_end_c : unsigned(6 downto 0) := to_unsigned( 7, 7); -- t2
|
|
constant t_pause_end_c : unsigned(6 downto 0) := to_unsigned( 9, 7); -- t3
|
|
constant t_reset_end_c : unsigned(6 downto 0) := to_unsigned(48, 7); -- t4
|
|
constant t_presence_sample_c : unsigned(6 downto 0) := to_unsigned(55, 7); -- t5
|
|
constant t_presence_end_c : unsigned(6 downto 0) := to_unsigned(96, 7); -- t6
|
|
----
|
|
|
|
.Overdrive
|
|
[IMPORTANT]
|
|
The ONEWIRE controller does not support the _overdrive_ mode. However, it can be implemented by reducing the base
|
|
time **T~base~** (and by eventually changing the hardwired timing configuration in the VHDL source file).
|
|
|
|
|
|
**Interrupt**
|
|
|
|
A single interrupt is provided by the ONEWIRE module to signal "operation done" condition to the CPU. Whenever the
|
|
controller completes a "generate reset pulse", a "transfer single-bit" or a "transfer full-byte" operation the
|
|
interrupt is triggered. Once triggered, the interrupt has to be _explicitly_ cleared again by writing zero to the
|
|
according <<_mip>> CSR FIRQ bit.
|
|
|
|
|
|
**Register Map**
|
|
|
|
.ONEWIRE register map (`struct NEORV32_ONEWIRE`)
|
|
[cols="<4,<2,<6,^2,<6"]
|
|
[options="header",grid="all"]
|
|
|=======================
|
|
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
|
|
.10+<| `0xfffff200` .10+<| `CTRL` <|`0` `ONEWIRE_CTRL_EN` ^| r/w <| ONEWIRE enable, reset if cleared
|
|
<|`2:1` `ONEWIRE_CTRL_PRSC1 : ONEWIRE_CTRL_PRSC0` ^| r/w <| 2-bit clock prescaler select
|
|
<|`10:3` `ONEWIRE_CTRL_CLKDIV7 : ONEWIRE_CTRL_CLKDIV0` ^| r/w <| 8-bit clock divider value
|
|
<|`11` `ONEWIRE_CTRL_TRIG_RST` ^| -/w <| trigger reset pulse, auto-clears
|
|
<|`12` `ONEWIRE_CTRL_TRIG_BIT` ^| -/w <| trigger single bit transmission, auto-clears
|
|
<|`13` `ONEWIRE_CTRL_TRIG_BYTE` ^| -/w <| trigger full-byte transmission, auto-clears
|
|
<|`28:14` - ^| r/- <| _reserved_, read as zero
|
|
<|`29` `ONEWIRE_CTRL_SENSE` ^| r/- <| current state of the bus line
|
|
<|`30` `ONEWIRE_CTRL_PRESENCE` ^| r/- <| device presence detected after reset pulse
|
|
<|`31` `ONEWIRE_CTRL_BUSY` ^| r/- <| operation in progress when set
|
|
| `0xfffff204` | `DATA` |`7:0` `ONEWIRE_DATA_MSB : ONEWIRE_DATA_LSB` | r/w | receive/transmit data (8-bit)
|
|
|======================= |