<<< :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) |=======================