drivers/ds18: Add Maxim Integrated 1-Wire temperature sensor driver#10011
drivers/ds18: Add Maxim Integrated 1-Wire temperature sensor driver#10011danpetry merged 1 commit intoRIOT-OS:masterfrom
Conversation
|
@aabadie Do you still have access to the hardware to test this? |
Normally yes but I have to find it in my mess :) |
|
@leandrolanzieri, I found it but I still can't make the sensor to give a valid temperature (tested with different DS18_PARAM_PULL values PU/PD) but it always display the following (with debug enabled): 2018-09-25 11:08:08,323 - INFO # [DS18] Reset and read scratchpad
2018-09-25 11:08:08,325 - INFO # [DS18] Received byte: 0xff
2018-09-25 11:08:08,326 - INFO # [DS18] Received byte: 0xff
2018-09-25 11:08:08,326 - INFO # Temperature [ºC]: 163.77I tested with an Arduino Zero and a Nucleo L073. I setup the pin correctly for both boards. Maybe my sensor is broken ? I only have this one so I cannot test with another one to check this. |
|
@aabadie thanks a lot for testing! |
|
Partial ACK: on the fundamentals. |
haukepetersen
left a comment
There was a problem hiding this comment.
Nice one, have been waiting for this driver a long time :-). Found some issues that I see, I think all of them should be quite easy to fix.
The reason I had some concrete code snippets at hand is, that I also implemented this driver some time (~2 years) ago, but never got to quite finish it. But maybe there is more useful stuff for you in my branch: https://github.com/haukepetersen/RIOT/tree/add_driver_ds18b20
But for now, I'd say lets go with the driver as is (only the small fixes left), and once its merged we could think about things like factoring out the 1wire driver etc...
drivers/ds18/Makefile
Outdated
| @@ -0,0 +1,2 @@ | |||
| MODULE = ds18 | |||
There was a problem hiding this comment.
no need for this line
drivers/ds18/ds18.c
Outdated
|
|
||
| static void ds18_release(ds18_t *dev) | ||
| { | ||
| /* Init pin as input and enable pull-up */ |
There was a problem hiding this comment.
comment doesnt fit to code anymore, 'pull-up' is not always ture, depending on dev->in_mode...
drivers/ds18/ds18_saul.c
Outdated
| ds18_t *d = (ds18_t *)dev; | ||
|
|
||
| ds18_get_temperature(d, &temperature); | ||
| res->val[0] = temperature; |
There was a problem hiding this comment.
how about:
ds18_get_temperature((ds18_t *)dev, &res->val[0]);
would reduce the code above into a single line.
But aside from that: it would be good to also check the return value of read_temperature and return a -ECANCELED in case of an error.
There was a problem hiding this comment.
You are right, much better.
|
|
||
| /* Measure time low of device pin, timeout after slot time*/ | ||
| start = xtimer_now_usec(); | ||
| while (!gpio_read(dev->pin) && measurement < DS18_DELAY_SLOT) { |
There was a problem hiding this comment.
this seems to be wasting resources by by reading the pin in a loop. As the pulse widths are specified, it would be more efficient to sample the pin state once in the middle of the corresponding pulse. The code I wrote for this (a long time ago) did something like this:
gpio_clear(owi->pin);
xtimer_usleep(T_RW_PULSE);
gpio_init(owi->pin, owi->imode);
xtimer_usleep(T_R_SAMPLE);
in = gpio_read(owi->pin);
xtimer_usleep(T_R_RECOVER);
gpio_init(owi->pin, owi->omode);
gpio_set(owi->pin);with
#define T_RW_PULSE (3)
#define T_W_HOLD (57)
#define T_W_RECOVER (10)
#define T_R_SAMPLE (7)
#define T_R_RECOVER (55)There was a problem hiding this comment.
also this way, all this timeout stuff is not needed anymore...
There was a problem hiding this comment.
I am having trouble with this one. There seems to be a problem with the xtimer on the board I am using (which has the sensor). I also did some tests on some nucleo boards and raised an issue here #10073.
I am not getting the needed time accuracy so I did not change the reading function just yet, as I am not able to test it right now. I already ordered a sensor so I can test it with different boards.
Any ideas to approach this problem?
There was a problem hiding this comment.
True, more-or-less precise timings are quite mandatory for using my proposed code block...
So until we get the timer imprecision sorted out, how about we go with a dual approach? We could include both code blocks in the code, #if - #elseing them based on a sub(pseudo)module, making my variant optional. This way people can use the more efficient code once they made sure their platform is handle the needed timings...
Of course we would need to document this in the module description :-)
| } | ||
|
|
||
| DEBUG("[DS18] Convert T\n"); | ||
| ds18_write_byte(dev, DS18_CMD_SKIPROM); |
There was a problem hiding this comment.
maybe put a comment in that this command triggers a conversion on all devices connected to the bus...
drivers/ds18/ds18.c
Outdated
|
|
||
| /* Fixed point value to uint16_t */ | ||
| uint16_t degrees = (b2 << 4) + (b1 >> 4); | ||
| uint16_t mdegrees = (b1 & 0xF) * 6.25; |
There was a problem hiding this comment.
Seeing a floating point number (6.25) in the code makes my head hurt :-) In the worst case, this pulls in ~5K of ROM or soft floating point library into the code - I guess this is not wanted here, right?
My proposal for the conversion:
int32_t res = ((int32_t)(b2 << 8 | b1) * 625);
*temperature = (int16_t)(res / 10);The trick is to use a larger type for intermediate conversion by basically shifting the position of the decimal point temporarily.
There was a problem hiding this comment.
Thanks, changed this.
| @@ -0,0 +1,64 @@ | |||
| /* | |||
There was a problem hiding this comment.
I would move this file to drivers/ds18/ds18_internal.h. This way it is only accessible from this driver and pulled out of the global include path...
drivers/include/ds18.h
Outdated
| */ | ||
| typedef struct { | ||
| gpio_t pin; /**< Pin the sensor is connected to */ | ||
| gpio_mode_t in_mode; /**< Pin output mode */ |
There was a problem hiding this comment.
What about the output mode?! I think it makes much sense to specify it as well. Or maybe even only specify the output mode in the configuration, and deduct the input mode from it:
// in the _init() function:
dev->in_mode = (params->out_mode == GPIO_OD_PU) ? GPIO_IN_PU : GPIO_IN;rationale behind this is, that CPUs that allow for GPIO_OD_PU have pull-up resistors implemented. These are then also usable for input mode...
There was a problem hiding this comment.
Makes sense, changed the param struct to have out_mode
| * @return 0 on success | ||
| * @return -1 on error | ||
| */ | ||
| int ds18_get_temperature(ds18_t *dev, int16_t *temperature); |
There was a problem hiding this comment.
I would prefer to split this function into 3 separate ones, something like:
int ds18_trigger(dev); // trigger a new conversion
int ds18_read(dev, temp); // read the results of the last conversion
int ds18_get_temp(dev, temp); // convenience function for trigger->wait->readThere was a problem hiding this comment.
Splitted the function
| * @ingroup drivers_saul | ||
| * @brief Driver interface for the DS18 temperature sensors | ||
| * | ||
| * This driver provides @ref drivers_saul capabilities. |
There was a problem hiding this comment.
Would you please also add some more documentation about the supported (or not supported) features and limitations of this driver?!
E.g.
- does not allow for addressing devices -> only supports a single device on the bus
- hardcodes the 1wire bus functionality into the driver
- does not allow for configuration of the sampling width
0ac1887 to
f8f3b1a
Compare
17bac9b to
a612d6d
Compare
|
I added a submodule |
haukepetersen
left a comment
There was a problem hiding this comment.
few more findings, once fixed I am happy :-)
drivers/ds18/ds18.c
Outdated
| { | ||
| int res; | ||
|
|
||
| res = ds18_reset(dev); |
There was a problem hiding this comment.
please remove this here, it is done already in ds18_trigger()
drivers/ds18/ds18.c
Outdated
|
|
||
| #if defined(MODULE_DS18_OPTIMIZED) | ||
| DEBUG("[DS18] Using optimized read function"); | ||
| #endif |
There was a problem hiding this comment.
please remove this block, I think it is rather for internal debugging...
drivers/ds18/ds18_internal.h
Outdated
| #define DS18_DELAY_R_RECOVER (DS18_DELAY_SLOT - DS18_SAMPLE_TIME) | ||
| /** @} */ | ||
|
|
||
|
|
| /** | ||
| * @brief convenience fuction for triggering a conversion and reading the | ||
| * value | ||
| * |
There was a problem hiding this comment.
here should also be a note or description that this function will block for an amount of time (don't remember the value...).
There was a problem hiding this comment.
I added a note on that.
sys/auto_init/auto_init.c
Outdated
| extern void auto_init_veml6070(void); | ||
| auto_init_veml6070(); | ||
| #endif | ||
| #ifdef MODULE_DS18 |
There was a problem hiding this comment.
seems like something went wrong when you rebased, most of these entries are unrelated to this PR, right?!
There was a problem hiding this comment.
Oops, I screwed up yep :(
91840bd to
f185003
Compare
haukepetersen
left a comment
There was a problem hiding this comment.
ACK from my side for concept, code, and documentation.
I did however NOT test the code nor did I check for coding style... So @danpetry would you mind?!
|
Yes I'll do that tomorrow. |
danpetry
left a comment
There was a problem hiding this comment.
A few small nits, just putting them down now in case I forget on monday :)
drivers/ds18/ds18.c
Outdated
|
|
||
| int ds18_get_temperature(ds18_t *dev, int16_t *temperature) | ||
| { | ||
| int res; |
There was a problem hiding this comment.
unused variable. Weren't you getting compile errors?
| @@ -0,0 +1,64 @@ | |||
| /* | |||
There was a problem hiding this comment.
This file should go in the /internal folder in the driver
There was a problem hiding this comment.
I haven't seen an internal folder in the common drivers structure
There was a problem hiding this comment.
Here #10011 (comment) @haukepetersen asked to move it out of the folder so it is not in the global path.
drivers/ds18/ds18.c
Outdated
| start = xtimer_now_usec(); | ||
| while (!gpio_read(dev->pin) && measurement < DS18_DELAY_SLOT) { | ||
| measurement = xtimer_now_usec() - start; | ||
| }; |
|
After @danpetry reported failures in readings with I found that the delayed introduced by the call to EDIT: |
tests/driver_ds18: Add test application for DS18B20 sensor. tests/driver_ds18: Add whitelist of boards
4608e54 to
8b8790c
Compare
|
Tested on all three whitelisted boards |
Contribution description
This PR is based on #6512. It adds the driver for the 1-Wire temperature sensors DS18 and SAUL interface.
What this PR adds:
ds18_read_bitfunction.Testing procedure
DS18_PARAM_PINandDS18_PARAM_PULLaccordingly to your board.BOARD=sensebox_samd21 make flash term -C tests/driver_ds18.Issues/PRs references
Based on #6512.
EDIT
Some measurements were performed on different platforms. Due to the need of timing accuracy for the implementation of the 1-wire protocol a whitelist of boards has been added to the test application. These boards have been tested and are known to work with the current implementation of the driver.
Measurements and captures can be found here: time_measurements_2.zip
@danpetry Reported the following time measurements (he took 3 samples of '1' and 3 of '0'):
Sensebox
Samr21-xpro
Nucleo L152RE