Skip to content

✨ Add 1-Wire Interface Controller #402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mimpid = 0x01040312 => 01.04.03.12 => Version 01.04.03.12 => v1.4.3.12

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 02.09.2022 | 1.7.6.1 | :sparkles: add new processor module: **1-Wire Interface Controller** (ONEWIRE); [#402](https://github.com/stnolting/neorv32/pull/402) |
| 28.08.2022 | [**:rocket:1.7.6**](https://github.com/stnolting/neorv32/releases/tag/v1.7.6) | **New release** |
| 27.08.2022 | 1.7.5.9 | fix minor core rtl issues that were found while experimenting with a low-level netlist of the processor; [#398](https://github.com/stnolting/neorv32/pull/398) |
| 26.08.2022 | 1.7.5.8 | cleanup **crt0** start-up code: remove setup of `mcountern` and `mcountinhibit` CSRs; [#397](https://github.com/stnolting/neorv32/pull/397) |
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ allows booting application code via UART or from external SPI flash
* standard serial interfaces
([UART](https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0),
[SPI](https://stnolting.github.io/neorv32/#_serial_peripheral_interface_controller_spi),
[TWI](https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi))
[TWI/I2C](https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi)),
[ONEWIRE/1-Wire](https://stnolting.github.io/neorv32/#_one_wire_serial_interface_controller_onewire))
* general purpose IOs ([GPIO](https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio)) and
[PWM](https://stnolting.github.io/neorv32/#_pulse_width_modulation_controller_pwm)
* smart LED interface ([NEOLED](https://stnolting.github.io/neorv32/#_smart_led_interface_neoled)) to directly control NeoPixel(TM) LEDs
Expand Down
6 changes: 4 additions & 2 deletions docs/datasheet/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ include::rationale.adoc[]
** official https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md[RISC-V open source architecture ID]
* **NEORV32 Processor (SoC)**: highly-configurable full-scale microcontroller-like processor system
** based on the NEORV32 CPU
** optional serial interfaces (UARTs, TWI, SPI)
** optional serial interfaces (UARTs, TWI, SPI, 1-Wire)
** optional timers and counters (watchdog, system timer)
** optional general purpose IO and PWM; a native NeoPixel(c)-compatible smart LED interface
** optional embedded memories / caches for data, instructions and bootloader
Expand Down Expand Up @@ -198,6 +198,7 @@ neorv32_top.vhd - NEORV32 Processor top entity
│└neor32_application_image.vhd - IMEM application initialization image
├neorv32_mtime.vhd - Machine system timer
├neorv32_neoled.vhd - NeoPixel (TM) compatible smart LED interface
├neorv32_onewire.vhd - One-Wire serial interface controller
├neorv32_pwm.vhd - Pulse-width modulation controller
├neorv32_slink.vhd - Stream link controller
├neorv32_spi.vhd - Serial peripheral interface controller
Expand Down Expand Up @@ -288,7 +289,7 @@ https://stnolting.github.io/neorv32/ug/#_application_specific_processor_configur
[cols="<2,<8"]
[grid="topbot"]
|=======================
| HW version: | `1.6.8.3`
| HW version: | `1.6.8.3++`
| Top entity: | `rtl/core/neorv32_top.vhd`
| FPGA: | Intel Cyclone IV E `EP4CE22F17C6`
| Toolchain: | Quartus Prime Lite 21.1
Expand All @@ -313,6 +314,7 @@ https://stnolting.github.io/neorv32/ug/#_application_specific_processor_configur
| IMEM | Processor-internal instruction memory (16kB) | 12 | 2 | 131072 | 0
| MTIME | Machine system timer | 345 | 166 | 0 | 0
| NEOLED | Smart LED Interface (NeoPixel/WS28128) (FIFO_depth=1) | 227 | 184 | 0 | 0
| ONEWIRE | 1-wire interface | 107 | 77 | 0 | 0
| PWM | Pulse_width modulation controller (8 channels) | 128 | 117 | 0 | 0
| SLINK | Stream link interface (2xRX, 2xTX, FIFO_depth=1) | 136 | 116 | 0 | 0
| SPI | Serial peripheral interface | 114 | 94 | 0 | 0
Expand Down
21 changes: 19 additions & 2 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ image::neorv32_processor.png[align=center]
* _optional_ external interrupt controller with up to 32 channels (<<_external_interrupt_controller_xirq,**XIRQ**>>)
* _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>)
* _optional_ execute in place module (<<_execute_in_place_module_xip,**XIP**>>)
* _optional_ 1-wire serial interface controller (<<_one_wire_serial_interface_controller_onewire,**ONEWIRE**>>), compatible to the 1-wire standard
* _optional_ on-chip debugger with JTAG TAP (<<_on_chip_debugger_ocd,**OCD**>>)
* bus keeper to monitor processor-internal bus transactions (<<_internal_bus_monitor_buskeeper,**BUSKEEPER**>>)
* system configuration information memory to check HW configuration via software (<<_system_configuration_information_memory_sysinfo,**SYSINFO**>>)
Expand All @@ -46,7 +47,7 @@ image::neorv32_processor.png[align=center]
=== Processor Top Entity - Signals

The following table shows all interface signals of the processor top entity (`rtl/core/neorv32_top.vhd`).
The type of all signals is `std_ulogic` or `std_ulogic_vector` (or arrays of those) - only the TWI signals are of type
The type of all signals is `std_ulogic` or `std_ulogic_vector` (or arrays of those) - the bi-directional signals are of type
`std_logic`.

.Default Values of Inputs
Expand Down Expand Up @@ -126,6 +127,8 @@ bits/channels are hardwired to zero.
4+^| **Two-Wire Interface Controller (<<_two_wire_serial_interface_controller_twi,TWI>>)**
| `twi_sda_io` | 1 | inout | serial data line
| `twi_scl_io` | 1 | inout | serial clock line
4+^| **1-Wire Interface Controller (<<_one_wire_serial_interface_controller_twi,ONEWIRE>>)**
| `onewire_io` | 1 | inout | serial data line
4+^| **Pulse-Width Modulation Channels (<<_pulse_width_modulation_controller_pwm,PWM>>)**
| `pwm_o` | 60 | out | pulse-width modulated channels
4+^| **Custom Functions Subsystem (<<_custom_functions_subsystem_cfs,CFS>>)**
Expand Down Expand Up @@ -1065,6 +1068,17 @@ functions subsystem entity.
|======


:sectnums!:
===== _IO_ONEWIRE_EN_

[cols="4,4,2"]
[frame="all",grid="none"]
|======
| **IO_ONE_EN** | _boolean_ | false
3+| Implement the <<_one_wire_serial_interface_controller_onewire>> module when true.
|======



<<<
// ####################################################################################################################
Expand Down Expand Up @@ -1215,7 +1229,8 @@ table (the channel number also corresponds to the according FIRQ priority: 0 = h
| 10 | <<_stream_link_interface_slink,SLINK>> | RX data buffer interrupt
| 11 | <<_stream_link_interface_slink,SLINK>> | TX data buffer interrupt
| 12 | <<_general_purpose_timer_gptmr,GPTMR>> | General purpose timer interrupt
| 13:15 | - | _reserved_, will never fire
| 13 | <<_one_wire_serial_interface_controller_onewire,ONEWIRE>> | 1-wire operation done interrupt
| 14:15 | - | _reserved_, will never fire
|=======================

.Trigger Type
Expand Down Expand Up @@ -1601,6 +1616,8 @@ include::soc_spi.adoc[]

include::soc_twi.adoc[]

include::soc_onewire.adoc[]

include::soc_pwm.adoc[]

include::soc_trng.adoc[]
Expand Down
182 changes: 182 additions & 0 deletions docs/datasheet/soc_onewire.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<<<
: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_io` | 1-bit bi-directional serial data
| 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 1-Wire protocol allows an (nearly) arbitrary number of devices but only a single controller that initiates all transfers.

The bus is based on a single tristate 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 `onewire_io` bus line.

[TIP]
For more information regarding the 1-Wire bus and the device access mechanism
see the Application Notes provided by Maxim Integrated.


**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-impedance (tristate) state.
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.

The following clock prescalers are available:

.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="<2,<2,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.10+<| `0xffffff70` .10+<| `NEORV32_ONEWIRE.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
| `0xffffff74` | `NEORV32_ONEWIRE.DATA` |`7:0` _ONEWIRE_DATA_MSB_ : _ONEWIRE_DATA_LSB_ | r/w | receive/transmit data (8-bit)
|=======================
1 change: 1 addition & 0 deletions docs/datasheet/soc_sysinfo.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ will signal a "DEVICE ERROR" in this case.
| `28` | _SYSINFO_SOC_IO_XIRQ_ | set if the XIRQ is implemented (via top's <<_xirq_num_ch>> generic)
| `29` | _SYSINFO_SOC_IO_GPTMR_ | set if the GPTMR is implemented (via top's <<_io_gptmr_en>> generic)
| `30` | _SYSINFO_SOC_IO_XIP_ | set if the XIP module is implemented (via top's <<_io_xip_en>> generic)
| `31` | _SYSINFO_SOC_IO_ONEWIRE_ | set if the ONEWIRE interface is implemented (via top's <<_io_onewire_en>> generic)
|=======================


Expand Down
1 change: 1 addition & 0 deletions docs/datasheet/software.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ footnote:[This driver file only represents a stub, since the real CFS drivers ar
| - | `neorv32_intrinsics.h` | macros for intrinsics & custom instructions
| `neorv32_mtime.c` | `neorv32_mtime.h` | HW driver functions for the **MTIME**
| `neorv32_neoled.c` | `neorv32_neoled.h` | HW driver functions for the **NEOLED**
| `neorv32_onewire.c` | `neorv32_onewire.h` | HW driver functions for the **ONEWIRE**
| `neorv32_pwm.c` | `neorv32_pwm.h` | HW driver functions for the **PWM**
| `neorv32_rte.c` | `neorv32_rte.h` | NEORV32 **runtime environment** and helper functions
| `neorv32_slink.c` | `neorv32_slink.h` | HW driver functions for the **SLINK**
Expand Down
Binary file modified docs/figures/neorv32_processor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/figures/onewire_data.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/figures/onewire_reset.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading