From 77e5359087edb374cf6806401afc438d4e77e4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Str=C3=B6m?= Date: Wed, 8 Sep 2021 22:34:43 +0200 Subject: [PATCH] ow: add alarm scans and timing tweaking (#3461) --- app/driver/onewire.c | 38 +++++++++++++++-------- app/include/driver/onewire.h | 21 ++++++++++++- app/modules/ow.c | 37 +++++++++++++++++++++- docs/modules/ow.md | 60 +++++++++++++++++++++++++++++++----- 4 files changed, 134 insertions(+), 22 deletions(-) diff --git a/app/driver/onewire.c b/app/driver/onewire.c index 7a45b51a..d84765a5 100644 --- a/app/driver/onewire.c +++ b/app/driver/onewire.c @@ -75,6 +75,20 @@ static uint8_t LastFamilyDiscrepancy[NUM_OW]; static uint8_t LastDeviceFlag[NUM_OW]; #endif +struct onewire_timings_s onewire_timings = { + .reset_tx = 480, + .reset_wait = 70, + .reset_rx = 410, + .w_1_low = 5, + .w_1_high = 52, + .w_0_low = 65, + .w_0_high = 5, + .r_low = 5, + .r_wait = 8, + .r_delay = 52 +}; + + void onewire_init(uint8_t pin) { // pinMode(pin, INPUT); @@ -108,13 +122,13 @@ uint8_t onewire_reset(uint8_t pin) noInterrupts(); DIRECT_WRITE_LOW(pin); interrupts(); - delayMicroseconds(480); + delayMicroseconds(onewire_timings.reset_tx); noInterrupts(); DIRECT_MODE_INPUT(pin); // allow it to float - delayMicroseconds(70); + delayMicroseconds(onewire_timings.reset_wait); r = !DIRECT_READ(pin); interrupts(); - delayMicroseconds(410); + delayMicroseconds(onewire_timings.reset_rx); return r; } @@ -127,7 +141,7 @@ static void onewire_write_bit(uint8_t pin, uint8_t v, uint8_t power) if (v & 1) { noInterrupts(); DIRECT_WRITE_LOW(pin); - delayMicroseconds(5); + delayMicroseconds(onewire_timings.w_1_low); if (power) { DIRECT_WRITE_HIGH(pin); } else { @@ -135,18 +149,18 @@ static void onewire_write_bit(uint8_t pin, uint8_t v, uint8_t power) } delayMicroseconds(8); interrupts(); - delayMicroseconds(52); + delayMicroseconds(onewire_timings.w_1_high); } else { noInterrupts(); DIRECT_WRITE_LOW(pin); - delayMicroseconds(65); + delayMicroseconds(onewire_timings.w_0_low); if (power) { DIRECT_WRITE_HIGH(pin); } else { DIRECT_MODE_INPUT(pin); // drive output high by the pull-up } interrupts(); - delayMicroseconds(5); + delayMicroseconds(onewire_timings.w_0_high); } } @@ -161,12 +175,12 @@ static uint8_t onewire_read_bit(uint8_t pin) noInterrupts(); DIRECT_WRITE_LOW(pin); - delayMicroseconds(5); + delayMicroseconds(onewire_timings.r_low); DIRECT_MODE_INPUT(pin); // let pin float, pull up will raise - delayMicroseconds(8); + delayMicroseconds(onewire_timings.r_wait); r = DIRECT_READ(pin); interrupts(); - delayMicroseconds(52); + delayMicroseconds(onewire_timings.r_delay); return r; } @@ -289,7 +303,7 @@ void onewire_target_search(uint8_t pin, uint8_t family_code) // Return TRUE : device found, ROM number in ROM_NO buffer // FALSE : device not found, end of search // -uint8_t onewire_search(uint8_t pin, uint8_t *newAddr) +uint8_t onewire_search(uint8_t pin, uint8_t *newAddr, uint8_t alarm_search) { uint8_t id_bit_number; uint8_t last_zero, rom_byte_number, search_result; @@ -318,7 +332,7 @@ uint8_t onewire_search(uint8_t pin, uint8_t *newAddr) } // issue the search command - onewire_write(pin, 0xF0, owDefaultPower); + onewire_write(pin, alarm_search ? 0xEC : 0xF0, owDefaultPower); // loop to do the search do diff --git a/app/include/driver/onewire.h b/app/include/driver/onewire.h index f8088252..525c0bcc 100644 --- a/app/include/driver/onewire.h +++ b/app/include/driver/onewire.h @@ -47,6 +47,24 @@ #define DIRECT_WRITE_LOW(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 0)) #define DIRECT_WRITE_HIGH(pin) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 1)) +// This allows tweaking of individual timings when doing onewire operations +struct onewire_timings_s { + uint16_t reset_tx; + uint16_t reset_wait; + uint16_t reset_rx; + + uint8_t w_1_low; + uint8_t w_1_high; + uint8_t w_0_low; + uint8_t w_0_high; + + uint8_t r_low; + uint8_t r_wait; + uint8_t r_delay; +}; + +extern struct onewire_timings_s onewire_timings; + void onewire_init(uint8_t pin); // Perform a 1-Wire reset cycle. Returns 1 if a device responds @@ -101,7 +119,8 @@ void onewire_target_search(uint8_t pin, uint8_t family_code); // might be a good idea to check the CRC to make sure you didn't // get garbage. The order is deterministic. You will always get // the same devices in the same order. -uint8_t onewire_search(uint8_t pin, uint8_t *newAddr); +// If alarm_search is non-zero, it only looks for devices with the Alarm Flag set (if supported) +uint8_t onewire_search(uint8_t pin, uint8_t *newAddr, uint8_t alarm_search); #endif #if ONEWIRE_CRC diff --git a/app/modules/ow.c b/app/modules/ow.c index 2ff41923..80531e1b 100644 --- a/app/modules/ow.c +++ b/app/modules/ow.c @@ -201,8 +201,15 @@ static int ow_search( lua_State *L ) luaL_Buffer b; luaL_buffinit( L, &b ); char *p = luaL_prepbuffer(&b); + uint8_t alarm_search = 0; - if(onewire_search(id, (uint8_t *)p)){ + if(lua_isnumber(L, 2)) + alarm_search = lua_tointeger(L, 2); + if(alarm_search != 0) + alarm_search = 1; + + + if(onewire_search(id, (uint8_t *)p, alarm_search)){ luaL_addsize(&b, 8); luaL_pushresult( &b ); } else { @@ -281,6 +288,33 @@ static int ow_crc16( lua_State *L ) #endif #endif +// Lua: r = ow.set_timings( reset_tx, reset_wait, reset_rx, w1_low, w1_high, w0_low, w0_high, r_low, r_wait, r_delay ) +static int ow_set_timings( lua_State *L ) +{ + if(lua_isnumber(L, 1)) + onewire_timings.reset_tx = lua_tointeger(L, 1); + if(lua_isnumber(L, 2)) + onewire_timings.reset_wait = lua_tointeger(L, 2); + if(lua_isnumber(L, 3)) + onewire_timings.reset_rx = lua_tointeger(L, 3); + if(lua_isnumber(L, 4)) + onewire_timings.w_1_low = lua_tointeger(L, 4); + if(lua_isnumber(L, 5)) + onewire_timings.w_1_high = lua_tointeger(L, 5); + if(lua_isnumber(L, 6)) + onewire_timings.w_0_low = lua_tointeger(L, 6); + if(lua_isnumber(L, 7)) + onewire_timings.w_0_high = lua_tointeger(L, 7); + if(lua_isnumber(L, 8)) + onewire_timings.r_low = lua_tointeger(L, 8); + if(lua_isnumber(L, 9)) + onewire_timings.r_wait = lua_tointeger(L, 9); + if(lua_isnumber(L, 10)) + onewire_timings.r_delay = lua_tointeger(L, 10); + + return 0; +} + // Module function map LROT_BEGIN(ow, NULL, 0) LROT_FUNCENTRY( setup, ow_setup ) @@ -304,6 +338,7 @@ LROT_BEGIN(ow, NULL, 0) LROT_FUNCENTRY( crc16, ow_crc16 ) #endif #endif + LROT_FUNCENTRY( set_timings, ow_set_timings ) LROT_END(ow, NULL, 0) diff --git a/docs/modules/ow.md b/docs/modules/ow.md index e09819cb..d124458f 100644 --- a/docs/modules/ow.md +++ b/docs/modules/ow.md @@ -60,14 +60,14 @@ Stops forcing power onto the bus. You only need to do this if you used the 'powe #### Returns `nil` -####See also +#### See also - [ow.write()](#owwrite) - [ow.write_bytes()](#owwrite_bytes) ## ow.read() Reads a byte. -####Syntax +#### Syntax `ow.read(pin)` #### Parameters @@ -118,10 +118,11 @@ Clears the search state so that it will start from the beginning again. Looks for the next device. #### Syntax -`ow.search(pin)` +`ow.search(pin, [alarm_search])` #### Parameters -`pin` 1~12, I/O index +- `pin` 1~12, I/O index +- `alarm_search` 1 / 0, if 0 a regular 0xF0 search is performed (default if parameter is absent), if 1 a 0xEC ALARM SEARCH is performed. #### Returns `rom_code` string with length of 8 upon success. It contains the rom code of slave device. Returns `nil` if search was unsuccessful. @@ -190,7 +191,7 @@ else end ``` -####See also +#### See also [ow.reset()](#owreset) ## ow.setup() @@ -230,7 +231,7 @@ Sets up the search to find the device type `family_code`. The search itself has #### Returns `nil` -####See also +#### See also [ow.search()](#owsearch) ## ow.write() @@ -247,7 +248,7 @@ Writes a byte. If `power` is 1 then the wire is held high at the end for parasit #### Returns `nil` -####See also +#### See also [ow.depower()](#owdepower) ## ow.write_bytes() @@ -264,5 +265,48 @@ Writes multi bytes. If `power` is 1 then the wire is held high at the end for pa #### Returns `nil` -####See also +#### See also [ow.depower()](#owdepower) + +## ow.set_timings() +Tweak different bit timing parameters. Some slow custom devices might not work perfectly well with NodeMCU as 1-wire master. Since NodeMCU ow module is bit-banging the 1-wire protocol, it is possible to adjust the timings a bit. + +Note that you can break the protocol totally if you tweak some numbers too much. This should never be needed with normal devices. + +#### Syntax +`ow.set_timings(reset_tx, reset_wait, reset_rx, w1_low, w1_high, w0_low, w0_high, r_low, r_wait, r_delay)` + +#### Parameters +Each parameter specifies number of microseconds to delay at different stages in the 1-wire bit-banging process. +A nil value will leave the value unmodified. + +- `reset_tx` pull bus low during reset (default 480) +- `reset_wait` wait for presence pulse after reset (default 70) +- `reset_rx` delay after presence pulse have been checked (default 410) +- `w1_low` pull bus low during write 1 slot (default 5) +- `w1_high` leave bus high during write 1 slot (default 52) +- `w0_low` pull bus low during write 1 slot (default 65) +- `w0_high` leave bus high during write 1 slot (default 5) +- `r_low` pull bus low during read slot (default 5) +- `r_wait` wait before reading bus level during read slot (default 8) +- `r_delay` delay after reading bus level (default 52) + +#### Returns +`nil` + +#### Example +```lua +-- Give 300uS longer read/write slots for slow MCU based 1-wire slave +ow.set_timings( + nil, -- reset_tx + nil, -- reset_wait + nil, -- reset_rx + nil, -- w1_low + 352, -- w1_high + nil, -- w0_low + 305, -- w0_high + nil, -- r_low + nil, -- r_wait + 352 -- r_delay +) +```