Skip to content

Draft: Add 1-Wire driver #19848

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft

Conversation

Enoch247
Copy link
Contributor

@Enoch247 Enoch247 commented Jul 26, 2023

Contribution description

This patch adds a 1-Wire driver which can handle multiple driver implementations. Included in the patch is a soft 1-Wire driver implementation.

Testing procedure

TODO

Issues/PRs references

@github-actions github-actions bot added Area: tests Area: tests and testing framework Area: build system Area: Build system Area: drivers Area: Device drivers labels Jul 26, 2023
@Enoch247 Enoch247 changed the title Add 1-Wire driver Draft: Add 1-Wire driver Jul 26, 2023
@Enoch247 Enoch247 force-pushed the add-driver-onewire branch from 9b16584 to cd75a9b Compare July 26, 2023 20:17
@dylad
Copy link
Member

dylad commented Jul 27, 2023

Nice PR !
I don't think we need to define a test for the high-level API. IMO, it will be good enough to glue it to some low level driver and ensure the hardware works as expected.
Can I test this PR with a DS18B20 probe ?

@Enoch247
Copy link
Contributor Author

I don't think we need to define a test for the high-level API. IMO, it will be good enough to glue it to some low level driver and ensure the hardware works as expected.

Ok. I don't know much about RIOT's test system yet. I will work on getting up to speed and write some tests for this PR.

Can I test this PR with a DS18B20 probe ?

The onewire_search() and onewire_read_rom() should work on a ds18b20 device. I plan to convert the ds18 driver over to use this new API, but haven't yet (that will be a different PR probably). Once that's done then you'll be able to read the device's temperature using the ds18 driver via this new onewire API.

The way I've been testing this API and driver so far is with a ds2433 and driver. The ds2433 driver is functional, but still needs work before I submit it for PR.

/**
* @brief Search for devices on the given 1-Wire bus
*
* @see https://pdfserv.maximintegrated.com/en/an/AN937.pdf page 51+52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

/* Start search. Refer to e.g. to
* https://pdfserv.maximintegrated.com/en/an/AN937.pdf, page 51 and 52 for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, the URL redirects to a new page now.

//TODO: use bitfield.h for tx/rx buffers?

/* bus timings as given in
* https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 17 to 50
//TODO: better names?
#define T_RESET_HOLD_US (480U)
#define T_RESET_SAMPLE_US (70U)
#define T_RESET_RECOVERY_US (410U)
#define T_RW_START_US (6U)
#define T_W_0_HOLD_US (60U)
#define T_W_0_END_US (10U)
#define T_W_1_DELAY_US (64U)
#define T_R_WAIT_US (9U)
#define T_R_END_US (55U)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like "ONEWIRE_RESET_HOLD_US"? With the "US" it should be quite clear that it's a time.

@crasbe crasbe added the Type: new feature The issue requests / The PR implemements a new feature for RIOT label Apr 5, 2025
@Enoch247 Enoch247 marked this pull request as draft April 10, 2025 00:02
@Enoch247 Enoch247 force-pushed the add-driver-onewire branch from d92b70d to 39a6876 Compare April 10, 2025 01:40
@Enoch247 Enoch247 force-pushed the add-driver-onewire branch from 39a6876 to a8dd266 Compare April 19, 2025 11:23
@crasbe
Copy link
Contributor

crasbe commented Apr 23, 2025

I think the test would need some more instructions, in a README.md file or so. I wasn't really sure how to get it working three weeks ago and wasn't successful in doing so 😅

@Enoch247
Copy link
Contributor Author

Yeah, the test is not really complete as is. After writing the test, I realized what a pain it is to define a bus and its params. So I'm reworking that now. I also went ahead and ported the ds18 driver to use the onewire API (coming in a separate PR). I've re-worked the API to use less RAM and ROM when only one back-end is enabled too. You should see some changes in this PR once I am finished. Pretty close...

@Enoch247 Enoch247 force-pushed the add-driver-onewire branch from a8dd266 to 42e088c Compare April 28, 2025 01:37
@github-actions github-actions bot added Area: doc Area: Documentation and removed Area: build system Area: Build system labels Apr 28, 2025
@Enoch247 Enoch247 added State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Area: build system Area: Build system and removed Area: doc Area: Documentation labels Apr 28, 2025
@Enoch247
Copy link
Contributor Author

At this point. I don't expect to make any more big changes to the driver code. The test code still needs some work and doc. I'm also scratching my head on how the test could be made to be common as it really could be used to test any onewire backend. I hate the thought of each new backend just copying the test and have a bunch of near duplicates.

@Enoch247
Copy link
Contributor Author

Can I test this PR with a DS18B20 probe ?

@dylad : a few years later, yes. See my WIP branch for that.

static inline uint_fast8_t onewire_crc8(uint_fast16_t seed, const void *data,
size_t len)
{
return crc8(data, len, 0x80, seed);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I am not calculating the CRC properly here. Still working on figuring out the right polynomial and how to handle reflecting the input.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing up front: the polynomial is wrong. CRC8 for 1-Wire uses 0x8C and not 0x80. Actually 0x80 won't generate good CRC checksums anyways.


So it depends on if you really want to use the built-in CRC8 function or not.

For the built-in function to work, you have to reflect all the input bytes, the polynomial and the output byte. That is a lot of computation.

I wrote a smöl test program to demonstrate:

#include <checksum/crc8.h>
#include <stdio.h>

// from: https://github.com/nickandrew/avr-onewire/blob/master/maxim-crc8.c
uint8_t crc8_update(uint8_t crc, uint8_t data) {
        uint8_t i;

        crc = crc ^ data;

        for (i = 0; i < 8; ++i) {
                if (crc & 0x01) {
                        crc = (crc >> 1) ^ 0x8c;
                } else {
                        crc >>= 1;
                }
        }
        return crc;
}

uint8_t reflect_byte(uint8_t b) {
    b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
    b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
    b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
    return b;
}

int main(void) {
    for(uint32_t i = 0; i < 256; i++) {
        uint8_t i_refl = reflect_byte(i);
        uint8_t riot_CRC8 = reflect_byte(crc8((uint8_t*) &i_refl, 1, 0x31, 0x00));

        uint8_t onewire_CRC8 = crc8_update(0, (uint8_t) i);
        uint8_t xor_CRC8 = riot_CRC8 ^ onewire_CRC8;
        printf("i: %03d, CRC8: %02X, Onewire CRC8: %02X, XOR: %02X\n",i, riot_CRC8, onewire_CRC8, xor_CRC8);
    }

    return 0;
}

And the output is the following:

2025-06-06 15:34:59,666 # RIOT native hardware initialization complete.
2025-06-06 15:34:59,667 #
2025-06-06 15:34:59,668 # main(): This is RIOT! (Version: 2025.04-devel-500-g42e08-add-driver-onewire)
2025-06-06 15:34:59,668 # i: 000, CRC8: 00, Onewire CRC8: 00, XOR: 00
2025-06-06 15:34:59,669 # i: 001, CRC8: 5E, Onewire CRC8: 5E, XOR: 00
2025-06-06 15:34:59,669 # i: 002, CRC8: BC, Onewire CRC8: BC, XOR: 00
2025-06-06 15:34:59,669 # i: 003, CRC8: E2, Onewire CRC8: E2, XOR: 00
2025-06-06 15:34:59,670 # i: 004, CRC8: 61, Onewire CRC8: 61, XOR: 00
2025-06-06 15:34:59,671 # i: 005, CRC8: 3F, Onewire CRC8: 3F, XOR: 00
2025-06-06 15:34:59,671 # i: 006, CRC8: DD, Onewire CRC8: DD, XOR: 00
2025-06-06 15:34:59,671 # i: 007, CRC8: 83, Onewire CRC8: 83, XOR: 00
2025-06-06 15:34:59,672 # i: 008, CRC8: C2, Onewire CRC8: C2, XOR: 00
2025-06-06 15:34:59,672 # i: 009, CRC8: 9C, Onewire CRC8: 9C, XOR: 00
2025-06-06 15:34:59,673 # i: 010, CRC8: 7E, Onewire CRC8: 7E, XOR: 00
2025-06-06 15:34:59,673 # i: 011, CRC8: 20, Onewire CRC8: 20, XOR: 00
2025-06-06 15:34:59,674 # i: 012, CRC8: A3, Onewire CRC8: A3, XOR: 00
2025-06-06 15:34:59,675 # i: 013, CRC8: FD, Onewire CRC8: FD, XOR: 00
2025-06-06 15:34:59,675 # i: 014, CRC8: 1F, Onewire CRC8: 1F, XOR: 00
2025-06-06 15:34:59,676 # i: 015, CRC8: 41, Onewire CRC8: 41, XOR: 00
2025-06-06 15:34:59,676 # i: 016, CRC8: 9D, Onewire CRC8: 9D, XOR: 00
2025-06-06 15:34:59,677 # i: 017, CRC8: C3, Onewire CRC8: C3, XOR: 00
2025-06-06 15:34:59,678 # i: 018, CRC8: 21, Onewire CRC8: 21, XOR: 00
2025-06-06 15:34:59,679 # i: 019, CRC8: 7F, Onewire CRC8: 7F, XOR: 00
2025-06-06 15:34:59,679 # i: 020, CRC8: FC, Onewire CRC8: FC, XOR: 00
2025-06-06 15:34:59,680 # i: 021, CRC8: A2, Onewire CRC8: A2, XOR: 00
...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it would be best to just add a crc8r or crc8_refl or crc8_reflected function to sys/checksum/crc8 and extend the unittest for it.
Perhaps in a separate PR.

Maybe I got some time to look at that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return crc8(data, len, 0x80, seed);
return crc8_lsb(data, len, 0x8C, seed);

Once #21543 is merged, you can change it to this. Remember to also change the CRC polynomial.

@crasbe
Copy link
Contributor

crasbe commented May 7, 2025

Unfortunately I don't have the Discovery at hand, but I tried with an nRF52840DK and a Nucleo-L152RE and L073RZ.

The nRF52840DK just doesn't work, it does not recognize the DS18B20. Neither with the tests/drivers/onewire test (after I added an unconditional .pin = GPIO_PIN(0,3), to the struct) nor with the tests/drivers/ds18 (same modification).

This is the log (with ENABLE_DEBUG = 1 in the drivers/onewire/onewire.c):

2025-05-07 14:37:29,551 # main(): This is RIOT! (Version: 2025.04-devel-500-g42e08-add-driver-onewire)
2025-05-07 14:37:29,552 # _onewire_init
2025-05-07 14:37:29,555 # onewire_write: f0
2025-05-07 14:37:29,578 # found device: 0000000000000000
2025-05-07 14:37:29,581 # onewire_write: f0
2025-05-07 14:37:29,605 # failure to enumerate device: EBADMSG

The same happens on other GPIO pins as well and also with an external 4.7k Pull Up.

It appears like some data is exchanged on the bus, but idk enough about OneWire to tell what might be the fault here.
Without external Pullup:
image

With Pullup:
image

For good measure I tried with an 1k Pullup, but that leads to the same result.

The sensor is a fake, but it does work. I checked it with an Arduino Uno and this tool: https://github.com/cpetrich/counterfeit_DS18B20

Sensor ROM and Current Scratchpad Content:
   1. 28-54-DE-15-C0-21-08-3D, 28-0821C015DE54: 50/05/4B/46/7F/FF/0C/10/1C 85.00 oC
  Number of Sensors: 1.

The Nucleos crash with a failed assertion:

2025-05-07 14:33:03,551 # main(): This is RIOT! (Version: 2025.04-devel-500-g42e08-add-driver-onewire)
2025-05-07 14:33:03,554 # 0x8001537 => FAILED ASSERTION.

cbuec@W11nMate:~/RIOTstuff/riot-onewire/RIOT/tests/drivers/onewire$ arm-none-eabi-objdump -d --start-address 0x8001520 --stop-address 0x8001564 bin/nucleo-l073rz/tests_onewire.elf

bin/nucleo-l073rz/tests_onewire.elf:     file format elf32-littlearm


Disassembly of section .text:

08001520 <_onewire_write_bits+0x44>:
 8001520:       08001341        .word   0x08001341
 8001524:       0800135d        .word   0x0800135d

08001528 <soft_onewire_init>:
 8001528:       b570            push    {r4, r5, r6, lr}
 800152a:       0004            movs    r4, r0
 800152c:       000d            movs    r5, r1
 800152e:       2800            cmp     r0, #0
 8001530:       d101            bne.n   8001536 <soft_onewire_init+0xe>
 8001532:       f7ff f83d       bl      80005b0 <_assert_panic>
 8001536:       2900            cmp     r1, #0
 8001538:       d0fb            beq.n   8001532 <soft_onewire_init+0xa>
 800153a:       f7ff fbe1       bl      8000d00 <_onewire_init>
 800153e:       2301            movs    r3, #1
 8001540:       425b            negs    r3, r3
 8001542:       60a3            str     r3, [r4, #8]
 8001544:       4a05            ldr     r2, [pc, #20]   ; (800155c <soft_onewire_init+0x34>)
 8001546:       0023            movs    r3, r4
 8001548:       4905            ldr     r1, [pc, #20]   ; (8001560 <soft_onewire_init+0x38>)
 800154a:       68a8            ldr     r0, [r5, #8]
 800154c:       f7ff fd2a       bl      8000fa4 <timer_init>
 8001550:       2800            cmp     r0, #0
 8001552:       d1ee            bne.n   8001532 <soft_onewire_init+0xa>
 8001554:       6820            ldr     r0, [r4, #0]
 8001556:       f7ff fe89       bl      800126c <_bus_release.isra.0>
 800155a:       bd70            pop     {r4, r5, r6, pc}
 800155c:       08001265        .word   0x08001265
 8001560:       000f4240        .word   0x000f4240

So it seems like it is the first assertion in the soft_onewire_init function.

@crasbe crasbe added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jun 6, 2025
@riot-ci
Copy link

riot-ci commented Jun 6, 2025

Murdock results

FAILED

42e088c WIP: drivers/soft_onewire: add tests

Success Failures Total Runtime
4569 0 9811 05m:30s

Artifacts

Copy link
Contributor

@crasbe crasbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some static errors about the documentation.

* When called, the bus driver should perform a bus reset and detect the slave
* device present pulse.
*
* @param[in] bus 1-Wire bus descriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param[in] bus 1-Wire bus descriptor
* @param[in] super 1-Wire bus descriptor

/**
* @brief Callback to transfer bytes from the bus
*
* @param[in] bus 1-Wire bus descriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param[in] bus 1-Wire bus descriptor
* @param[in] super 1-Wire bus descriptor

/**
* @brief Callback to transfer bytes to the bus
*
* @param[in] bus 1-Wire bus descriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param[in] bus 1-Wire bus descriptor
* @param[in] super 1-Wire bus descriptor

/**
* @brief Initialize soft 1-Wire bus
*
* @param[in] bus bus descriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param[in] bus bus descriptor
* @param[in] super bus descriptor

@defgroup drivers_onewire_devs 1-Wire Device Drivers
@ingroup drivers_onewire
@brief 1-Wire Slave Device Drivers

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: drivers Area: Device drivers Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants