Browse Source

ow: add alarm scans and timing tweaking (#3461)

Johan Ström 2 years ago
parent
commit
21ab6eddc3
4 changed files with 134 additions and 22 deletions
  1. 26 12
      app/driver/onewire.c
  2. 20 1
      app/include/driver/onewire.h
  3. 36 1
      app/modules/ow.c
  4. 52 8
      docs/modules/ow.md

+ 26 - 12
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

+ 20 - 1
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

+ 36 - 1
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)
 
 

+ 52 - 8
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
+)
+```