Skip to content
Browse files

Lots of changes for migrating from 1-Wire® over to Fox-Bus™.

These changes are not complete, but in light of some recent
developments I felt it was necessary to update the documentation
of this project as soon as possible.

It turns out that MAXIM is unable or unwilling to offer any
license for the 1-Wire® slave protocol on a non-MAXIM IC.
As a result of this revelation, a suitable alternative
to the 1-Wire protocol must be found and used instead.

For now, I have settled on Fox-Bus™, which has been developed
by Chris Fox. This protocol is a free single-wire alternative
to 1-Wire, and Chris is generously allowing this project
to take advantage of his research to use his protocol.

Chris has indicated that he intends to make more information
available at <http://fox-bus.com/> in the near future.

For historical purposes, below is the email exchange between
MAXIM and myself. Note that MAXIM is simply asserting their
right to not license their patent. While I may find patents
like this one to be rather dubious, I respect the fact that
this is their right---and you should too. Do not harass MAXIM
about this subject, as doing so would be counter-productive.
Besides, there are alternatives that are better than the
1-wire protocol for this application.

Begin forwarded message:

> From: Hal Kurkowski <Hal.Kurkowski@maxim-ic.com>
> Date: August 10, 2011 12:34:12 PM PDT
> To: Robert Quattlebaum <darco@deepdarc.com>
> Cc: Scott Jones <Scott.Jones@maxim-ic.com>
> Subject: RE: 1-wire license agreement
> 
> Robert,
> 
> Thanks for your email.
> 
> In response to your questions:
>
>> 1) Will you require that I license the 1-wire protocol from you for
>> devices which I build for my own personal use? (limited to 25 devices,
>> max)
>
> Any non-Maxim slave device that incorporates the 1-Wire protocol
> would be considered to be in violation of Maxim's applicable 1-Wire IP.
>
>> 2) Would the incorporation of a DS2401 into the design implicitly
>> license the 1-wire patent for the device in the eyes of your legal team?
>
> Incorporating a 1-Wire slave device within a system does not allow
> unlimited use of the protocol by other, non-Maxim parts.
>
>> 3) Would Maxim be willing to license the 1-wire patent for devices which
>> include no Maxim parts?
>
> We currently are not able to license you or your company for this
> application.
> 
> Hal Kurkowski
> Managing Director
> Maxim Integrated Products
> 
> 
> -----Original Message-----
> From: Robert Quattlebaum [mailto:darco@deepdarc.com]
> Sent: Thursday, July 21, 2011 3:46 PM
> To: Hal Kurkowski
> Subject: Fwd: 1-wire license agreement
> 
> Hello Hal! I was referred to you by Chris Fox, in the email quoted
> below.
> 
> As a hobby project, I have been developing a capacitive soil moisture
> sensor which utilizes a ATtiny25 microcontroller and a few passive
> components. I intend to release this project as an "open-source
> hardware" project, licensed under the CC-BY-SA-3.0 and GPL-2.0
> licenses. The project is generally documented in the following
> links:
> 
> http://www.deepdarc.com/2010/11/01/soil-moisture-sensor/
> http://www.deepdarc.com/2011/01/08/soil-moisture-sensor-update/
> http://www.deepdarc.com/2011/07/20/sensor-panel/
> https://github.com/darconeous/soil-moisture-sensor/
> 
> The use of the 1-wire protocol for communicating with the sensor
> seemed like a natural fit, as it would allow the sensors to be
> chained together easily. I was able to implement a 1-wire slave
> interface in software on the ATtiny25, and it is working great. The
> only issue is one of the 1-wire patent, which MAXIM owns.
> 
> I figured that as long as the device contained at least one official
> 1-wire component (such as the DS2401) that this may be sufficient
> (via "patent exhaustion") to cover the entire device, so I adjusted
> the design of the sensor to include a DS2401. However, I have
> absolutely no resources to consider an option which might possibly
> lead to litigation, so I wanted to clarify the issue with you
> directly.
> 
> At this time I am developing these devices for my own personal use,
> but if there is enough interest I may make a production run of a
> few thousand, perhaps sold via kickstarter.com. As such I wanted
> to reach out to you directly to get a feel for what your views are
> on this subject and to possibly discuss patent licensing options.
> 
> Alternatively, I could abandon the 1-wire protocol entirely and use
> a different non-patented protocol---but I think that using the
> 1-wire protocol in this case adds significant value to the utility
> of this product.
> 
> So, my questions are as follows:
> 
> 1) Will you require that I license the 1-wire protocol from you for
> devices which I build for my own personal use? (limited to 25
> devices, max)
> 2) Would the incorporation of a DS2401 into the design
> implicitly license the 1-wire patent for the device in the eyes of
> your legal team?
> 3) Would Maxim be willing to license the 1-wire
> patent for devices which include no Maxim parts?
> 
> If there are any additional points which come to mind which are not
> addressed by these questions which you think are relevant to this
> project, please let me know.
> 
> Again, at this point these devices are for my own personal use---I'm
> just trying to get a feel for what my liabilities are with respect
> to this project.
> 
> Thanks for your time!
  • Loading branch information...
1 parent 7adde2b commit c50a22f17eadae9c7f51c39b34a7caf4c9cc97d5 @darconeous committed Aug 16, 2011
Showing with 356 additions and 211 deletions.
  1. +4 −30 bom.txt
  2. +315 −167 main.c
  3. +37 −14 protocol.txt
View
34 bom.txt
@@ -1,4 +1,4 @@
-## Bill of Materials
+## Bill of Materials ##
Desc: 4.5"^2 Circuit Board
Count: 1
@@ -42,32 +42,15 @@ Cost@25x: USD$1.40 (PN 102617-1)
Cost@Mass: USD$1.07 (PN 102617-1)
Source: http://search.digikey.com/scripts/DkSearch/dksus.dll?keywords=A26757-ND
-** FUNCTIONALLY-OPTIONAL-PART
-** The following part is needed for legal reasons, due to USPAT#6,108,751.
-** It may be possible to negotiate a simple licence agreement with
-** Maxim that could avoid adding this extra part, for a per-device
-** license fee, but this remains to be seen.
-Desc: DS2401X1 Silicon Serial Number (Flip-Chip)
-PartNames: IC2
-Count: 1
-Cost@1x: USD$1.40
-Cost@25x: USD$0.97
-Cost@Mass: USD$0.59
-Source: http://search.digikey.com/scripts/DkSearch/dksus.dll?keywords=DS2401X1
-Source: http://www.mouser.com/Search/Refine.aspx?Keyword=DS2401X1
-
-## Approximate Unit Part Cost Breakdown
+## Approximate Unit Part Cost Breakdown ##
Unit Cost @1x: USD$24.99 ~USD$124.95 for 5 Units
- w/DS2401X1: USD$26.39 ~USD$131.95 for 5 Units
Unit Cost @25x: USD$7.70 ~USD$192.50 for 25 Units
- w/DS2401X1: USD$8.67 ~USD$216.75 for 25 Units
Unit Cost @Mass: USD$2.82 ~USD$11,280.00 for ~4,000 Units
- w/DS2401X1: USD$3.41 ~USD$13,640.00 for ~4,000 Units
-## Parts for Mating Connector
+## Parts for Mating Connector ##
Additionally, you may want some connectors to plug into that shrouded header:
@@ -84,16 +67,7 @@ Housing:
Crimp-pins for housing:
http://search.digikey.com/scripts/DkSearch/dksus.dll?keywords=A25959
-## Additional Finishing Materials
+## Additional Finishing Materials ##
* Plasti-Dip, to water-deal the sensing section. <http://www.plastidip.com/>
* Epoxy or Silicone, for potting the electronics above the sensing section.
-
-## Patent References
-
-USPAT#5,210,846
-USPAT#6,108,751
-http://patimg1.uspto.gov/.piw?Docid=05210846&idkey=NONE
-http://patimg1.uspto.gov/.piw?Docid=06108751&idkey=NONE
-http://www.buoy.com/pipermail/1-wire-software-development/2004-November/000163.html
-http://dics.voicecontrol.ro/process_mails/arata_discutia/129197/Implementing_1-wire_slaves.html
View
482 main.c
@@ -36,16 +36,32 @@
// ----------------------------------------------------------------------------
#pragma mark Build Settings
+// TEMPORARY DEVELOPMENT OVERRIDE OF PHYSICAL BUS PROTOCOL.
+// THIS MUST BE REMOVED BEFORE THE PROJECT IS OFFICIALLY RELEASED.
+#define COMM_PHY_PROTO COMM_PHY_1WIRE
+
#ifndef FIRMWARE_VERSION
-#define FIRMWARE_VERSION (0)
+#define FIRMWARE_VERSION (0)
#endif
#ifndef CALIBRATED_BITS
-#define CALIBRATED_BITS (10)
+#define CALIBRATED_BITS (10)
+#endif
+
+#ifndef COMM_SDA
+#define COMM_SDA (0) //!< PB0, MOSI
#endif
-#ifndef OWSLAVE_IOPIN
-#define OWSLAVE_IOPIN (0) //!< PB0
+#ifndef COMM_SCK
+#define COMM_SCK (2) //!< PB2
+#endif
+
+#define COMM_PHY_FxB (1) //!< Fox-Bus™
+#define COMM_PHY_1WIRE (2) //!< 1-Wire® Compatible (DO NOT USE)
+#define COMM_PHY_2WIRE (3) //!< 2-Wire (SCK/SDA)
+
+#ifndef COMM_PHY_PROTO
+#define COMM_PHY_PROTO COMM_PHY_FxB //!< Default is Fox-Bus™.
#endif
#ifndef MOIST_DRIVE_PIN
@@ -64,12 +80,12 @@
#define SUPPORT_DEVICE_NAMING (0) //!< Not yet implemented.
#endif
-#ifndef TEMP_VOLTAGE_COMP_NUMERATOR
-#define TEMP_VOLTAGE_COMP_NUMERATOR ((uint32_t)7250*16)
+#ifndef TEMP_VOLT_COMP_NUMERATOR
+#define TEMP_VOLT_COMP_NUMERATOR ((uint32_t)7250*16)
#endif
-#ifndef TEMP_VOLTAGE_COMP_OFFSET
-#define TEMP_VOLTAGE_COMP_OFFSET (337)
+#ifndef TEMP_VOLT_COMP_OFFSET
+#define TEMP_VOLT_COMP_OFFSET (337)
#endif
#ifndef DEVICE_IS_SPACE_CONSTRAINED
@@ -135,52 +151,49 @@
#define CFG_FLAG_ALARM (1<<7)
#define CFG_FLAG_ERROR (1<<6)
-// ----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark owslave types
-
typedef uint8_t bool;
#define true (bool)(1)
#define false (bool)(0)
-#define OWSLAVE_T_X (30) //!< General one-wire delay period
+// ----------------------------------------------------------------------------
+#pragma mark -
+#pragma mark Misc.
-enum {
- OWSLAVE_TYPE_CUSTOMFLAG = 0x80,
+#if COMM_PHY_PROTO == COMM_PHY_1WIRE
+#define OWSLAVE_T_X (30) //!< General 1-Wire® delay period
+#endif
- OWSLAVE_TYPE_DS2401 = 0x01, // Serial-number only
- OWSLAVE_TYPE_DS1920 = 0x10,
- OWSLAVE_TYPE_DS18B20 = 0x28, // Temperature Sensor
- OWSLAVE_TYPE_DS2450 = 0x20, // 4-channel ADC
+#define COMM_FxB_READ_THRESHOLD (10)
- OWSLAVE_TYPE_MOIST = OWSLAVE_TYPE_DS2450|OWSLAVE_TYPE_CUSTOMFLAG
+//! Device Type Codes
+enum {
+ COMM_TYPE_CUSTOMFLAG = 0x80,
+ COMM_TYPE_MOIST = 0x20|COMM_TYPE_CUSTOMFLAG
+};
+
+//! ROM Commands
+enum {
+ COMM_ROMCMD_READ=0x33, // 00110011b
+ COMM_ROMCMD_MATCH=0x55, // 01010101b
+ COMM_ROMCMD_SKIP=0xCC, // 11001100b
+ COMM_ROMCMD_SEARCH=0xF0, // 11110000b
+ COMM_ROMCMD_ALARM_SEARCH=0xEC, // 11101100b
};
+//! Function Commands
enum {
- OWSLAVE_ROMCMD_READ=0x33, // 00110011b
- OWSLAVE_ROMCMD_MATCH=0x55, // 01010101b
- OWSLAVE_ROMCMD_SKIP=0xCC, // 11001100b
- OWSLAVE_ROMCMD_SEARCH=0xF0, // 11110000b
- OWSLAVE_ROMCMD_ALARM_SEARCH=0xEC, // 11101100b
-
- // DS2450, Quad ADC
- OWSLAVE_FUNCCMD_RD_MEM=0xAA,
- OWSLAVE_FUNCCMD_WR_MEM=0x55,
- OWSLAVE_FUNCCMD_CONVERT=0x3C,
-
- OWSLAVE_FUNCCMD_COMMIT_MEM=0x48,
- OWSLAVE_FUNCCMD_RECALL_MEM=0xB8,
-
- // DS18B20, 1-Wire Thermometer
- OWSLAVE_FUNCCMD_CONVERT_T=0x44,
- OWSLAVE_FUNCCMD_WR_SCRATCH=0x4E,
- OWSLAVE_FUNCCMD_RD_SCRATCH=0xBE,
- OWSLAVE_FUNCCMD_CP_SCRATCH=0x48,
- OWSLAVE_FUNCCMD_RECALL_E2=0xB8,
-
- // Custom
- OWSLAVE_FUNCCMD_RD_NAME=0xF1,
- OWSLAVE_FUNCCMD_WR_NAME=0xFE,
+ COMM_FUNCCMD_RD_MEM=0xAA,
+ COMM_FUNCCMD_WR_MEM=0x55,
+ COMM_FUNCCMD_CONVERT=0x3C,
+ COMM_FUNCCMD_COMMIT_MEM=0x48,
+ COMM_FUNCCMD_RECALL_MEM=0xB8,
+ COMM_FUNCCMD_CONVERT_T=0x44,
+ COMM_FUNCCMD_RD_SCRATCH=0xBE,
+
+#if SUPPORT_DEVICE_NAMING
+ COMM_FUNCCMD_RD_NAME=0xF1,
+ COMM_FUNCCMD_WR_NAME=0xFE,
+#endif
};
typedef union {
@@ -190,7 +203,7 @@ typedef union {
uint8_t crc;
} s;
uint8_t d[8];
-} owslave_addr_t;
+} comm_addr_t;
// ----------------------------------------------------------------------------
#pragma mark -
@@ -212,7 +225,6 @@ struct cfg_t {
uint8_t flags;
uint8_t reserved[4];
-
uint8_t firmware_version;
} cfg ATTR_NO_INIT;
@@ -231,20 +243,22 @@ struct calib_t {
register uint8_t was_interrupted __asm__("r3");
#endif
+bool convert_error_occured ATTR_NO_INIT;
+
// ----------------------------------------------------------------------------
#pragma mark -
#pragma mark EEPROM Layout
-owslave_addr_t owslave_addr EEMEM = {
- .s.type = OWSLAVE_TYPE_MOIST,
+comm_addr_t comm_addr EEMEM = {
+ .s.type = COMM_TYPE_MOIST,
.s.serial = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
.s.crc = 0x4D
};
struct cfg_t cfg_eeprom EEMEM = {
.alarm_low = 0x00,
.alarm_high = 0xFF,
- .flags = 0x00 | (7&TEMP_RESOLUTION_MASK),
+ .flags = 0x00 | (4&TEMP_RESOLUTION_MASK),
};
struct calib_t calib_eeprom EEMEM = {
@@ -258,8 +272,6 @@ struct calib_t calib_eeprom EEMEM = {
char device_name[16] EEMEM = "";
#endif
-bool convert_error_occured ATTR_NO_INIT;
-
// ----------------------------------------------------------------------------
#pragma mark -
#pragma mark Misc. Helper Functions
@@ -290,22 +302,22 @@ median_uint16(
#if SUPPORT_CONVERT_INDICATOR
static void
-owslave_begin_busy() {
+comm_begin_busy() {
sbi(TIMSK0, OCIE0A);
}
static void
-owslave_end_busy() {
- cbi(DDRB, OWSLAVE_IOPIN);
+comm_end_busy() {
+ cbi(DDRB, COMM_SDA);
cbi(TIMSK0, OCIE0A);
}
#else
-#define owslave_begin_busy() do {} while(0)
-#define owslave_end_busy() do {} while(0)
+#define comm_begin_busy() do {} while(0)
+#define comm_end_busy() do {} while(0)
#endif
static uint8_t
-owslave_cb_alarm_condition() {
+get_alarm_condition() {
return (cfg.flags&(CFG_FLAG_ALARM|CFG_FLAG_ERROR))!=0;
}
@@ -341,15 +353,24 @@ moist_calc() {
bit_is_clear(PINB, MOIST_COLLECTOR_PIN);
v++
) {
+ // Change the pin state to HIGH.
sbi(PORTB, MOIST_DRIVE_PIN);
-#if MOIST_FULLY_DRIVE_PULSES
+
+ // Change the output direction to output.
sbi(DDRB, MOIST_DRIVE_PIN);
+
+ // Change the output direction back to input (Hi-Z).
cbi(DDRB, MOIST_DRIVE_PIN);
-#endif
+
+ // Change the pin state back to LOW.
+ // If we don't do this, then the built-in pull-up will
+ // still be enabled and throw off our readings.
cbi(PORTB, MOIST_DRIVE_PIN);
+
#if SUPPORT_CONVERT_INDICATOR
if(was_interrupted)
goto again;
+
_NOP();
#else
_delay_us(1);
@@ -410,14 +431,17 @@ convert_temp() {
loop_until_bit_is_clear(ADCSRA, ADSC);
temp += ADC - 270;
}
+
temp >>= (cfg.flags&TEMP_RESOLUTION_MASK);
- value.temp = temp + calib.temp_offset*2;
+ temp += calib.temp_offset*2;
#if SUPPORT_VOLT_READING
// Adjust for changes in voltage.
- value.temp += TEMP_VOLTAGE_COMP_NUMERATOR/value.voltage - TEMP_VOLTAGE_COMP_OFFSET;
+ temp += TEMP_VOLT_COMP_NUMERATOR/value.voltage - TEMP_VOLT_COMP_OFFSET;
#endif
+
+ value.temp = temp;
}
#endif
@@ -493,8 +517,8 @@ convert_moisture() {
}
static void
-owslave_cb_convert() {
- owslave_begin_busy();
+do_convert() {
+ comm_begin_busy();
// Clear status flags
cfg.flags &= ~(CFG_FLAG_ALARM|CFG_FLAG_ERROR);
@@ -504,9 +528,7 @@ owslave_cb_convert() {
#if !DEVICE_IS_SPACE_CONSTRAINED
// Set all values to OxFFFF
uint8_t i = 7;
- do {
- ((uint8_t*)&value)[i]=0xFF;
- } while(i--);
+ do { ((uint8_t*)&value)[i]=0xFF; } while(i--);
#endif
#if SUPPORT_VOLT_READING
@@ -526,14 +548,14 @@ owslave_cb_convert() {
cfg.flags |= CFG_FLAG_ALARM;
}
- if(!convert_error_occured);
+ if(!convert_error_occured)
cfg.flags &= ~CFG_FLAG_ERROR;
- owslave_end_busy();
+ comm_end_busy();
}
static void
-owslave_cb_recall() {
+do_recall() {
eeprom_busy_wait();
eeprom_read_block(
&cfg,
@@ -544,7 +566,7 @@ owslave_cb_recall() {
}
static void
-owslave_cb_commit() {
+do_commit() {
#if USE_WATCHDOG
wdt_reset();
#endif
@@ -558,91 +580,191 @@ owslave_cb_commit() {
// ----------------------------------------------------------------------------
#pragma mark -
-#pragma mark OWSlave Functions
+#pragma mark Bus Communications Functions
static uint8_t
-owslave_read_bit() {
+comm_read_bit() {
+#if COMM_PHY_PROTO == COMM_PHY_1WIRE
// Wait for the bus to go idle if it is already low.
- if(bit_is_clear(PINB, OWSLAVE_IOPIN))
- loop_until_bit_is_set(PINB, OWSLAVE_IOPIN);
+ if(bit_is_clear(PINB, COMM_SDA))
+ loop_until_bit_is_set(PINB, COMM_SDA);
// Wait for the slot to open.
- loop_until_bit_is_clear(PINB, OWSLAVE_IOPIN);
+ loop_until_bit_is_clear(PINB, COMM_SDA);
// Wait until we should sample.
_delay_us(OWSLAVE_T_X);
// Return the value of the bit.
- return bit_is_set(PINB, OWSLAVE_IOPIN);
+ return bit_is_set(PINB, COMM_SDA);
+#elif COMM_PHY_PROTO == COMM_PHY_FxB
+ uint8_t sum=0;
+
+ // Wait for the bus to go idle if it is already low.
+ if(bit_is_clear(PINB, COMM_SDA))
+ loop_until_bit_is_set(PINB, COMM_SDA);
+
+ // Wait for the slot to open.
+ loop_until_bit_is_clear(PINB, COMM_SDA);
+
+ // Disable interrupts, so we can make sure we get the timing right.
+ cli();
+
+ while(1) {
+ if(bit_is_set(PINB, COMM_SDA)) {
+ _delay_us(2);
+ if(bit_is_set(PINB, COMM_SDA))
+ break;
+ }
+ }
+
+ _delay_us(3);
+
+ for(uint8_t i=0;i<255;i++) {
+ if(bit_is_clear(PINB,COMM_SDA)) {
+ if(sum++>COMM_FxB_READ_THRESHOLD) {
+ // Turn interrupts back on.
+ sei();
+ return true;
+ }
+ } else {
+ sum = 0;
+ }
+ }
+
+ // Turn interrupts back on.
+ sei();
+ return 0;
+#else
+#error COMM_PHY_PROTO not set properly!
+#endif
}
static void
-owslave_write_bit(uint8_t v) {
+comm_write_bit(uint8_t v) {
+#if COMM_PHY_PROTO == COMM_PHY_1WIRE
// Wait for the bus to go idle.
- if(bit_is_clear(PINB, OWSLAVE_IOPIN))
- loop_until_bit_is_set(PINB, OWSLAVE_IOPIN);
+ if(bit_is_clear(PINB, COMM_SDA))
+ loop_until_bit_is_set(PINB, COMM_SDA);
if(v == 0) {
#if SUPPORT_CONVERT_INDICATOR
- owslave_begin_busy();
- loop_until_bit_is_clear(PINB, OWSLAVE_IOPIN);
- loop_until_bit_is_set(PINB, OWSLAVE_IOPIN);
- owslave_end_busy();
+ comm_begin_busy();
+ loop_until_bit_is_clear(PINB, COMM_SDA);
+ loop_until_bit_is_set(PINB, COMM_SDA);
+ comm_end_busy();
#else
// Disable interrupts, so we can make sure we get the timing right.
cli();
// Wait for the slot to open.
- loop_until_bit_is_clear(PINB, OWSLAVE_IOPIN);
+ loop_until_bit_is_clear(PINB, COMM_SDA);
// Assert our zero bit.
- sbi(DDRB, OWSLAVE_IOPIN);
+ sbi(DDRB, COMM_SDA);
// Wait for the master to sample us.
_delay_us(OWSLAVE_T_X);
// Return the bus back to idle.
- cbi(DDRB, OWSLAVE_IOPIN);
+ cbi(DDRB, COMM_SDA);
// Turn interrupts back on.
sei();
#endif
} else {
// Wait for the slot to open.
- loop_until_bit_is_clear(PINB, OWSLAVE_IOPIN);
+ loop_until_bit_is_clear(PINB, COMM_SDA);
}
+#elif COMM_PHY_PROTO == COMM_PHY_FxB
+ // Wait for the bus to go idle.
+ if(bit_is_clear(PINB, COMM_SDA))
+ loop_until_bit_is_set(PINB, COMM_SDA);
+
+ if(v == 0) {
+ // Disable interrupts, so we can make sure we get the timing right.
+ cli();
+
+ // Wait for the slot to open.
+ loop_until_bit_is_clear(PINB, COMM_SDA);
+
+ loop_until_bit_is_set(PINB, COMM_SDA);
+
+ _delay_us(5);
+
+ // Assert our zero bit.
+ sbi(DDRB, COMM_SDA);
+
+ _delay_us(5);
+
+ // Return the bus back to idle.
+ cbi(DDRB, COMM_SDA);
+
+ // Turn interrupts back on.
+ sei();
+ } else {
+ loop_until_bit_is_clear(PINB, COMM_SDA);
+ loop_until_bit_is_set(PINB, COMM_SDA);
+ }
+#else
+#error COMM_PHY_PROTO not set properly!
+#endif
+}
+
+static inline void
+comm_send_presence() {
+#if COMM_PHY_PROTO == COMM_PHY_1WIRE
+ // Wait for reset pulse to end.
+ while(bit_is_clear(PINB, COMM_SDA)) sleep_cpu();
+
+ // Let the bus idle for 20µSec after the end of the reset pulse.
+ _delay_us(20);
+
+ // Send the 80µSec presence pulse.
+ sbi(DDRB, COMM_SDA);
+ _delay_us(80);
+ cbi(DDRB, COMM_SDA);
+#elif COMM_PHY_PROTO == COMM_PHY_FxB
+ // Wait for reset pulse to end.
+ while(bit_is_clear(PINB, COMM_SDA)) sleep_cpu();
+
+ // Send a '0' bit for our presence.
+ comm_write_bit(0);
+#else
+#error COMM_PHY_PROTO not set properly!
+#endif
}
static uint8_t
-owslave_read_byte() {
+comm_read_byte() {
// We really DON'T need to initialize this. Honest.
uint8_t ret;
for(uint8_t i = 0; i != 8; i++) {
ret >>= 1;
- if(owslave_read_bit())
+ if(comm_read_bit())
sbi(ret, 7);
}
return ret;
}
static void
-owslave_write_byte(uint8_t byte) {
+comm_write_byte(uint8_t byte) {
for(uint8_t i = 0; i != 8; i++) {
- owslave_write_bit(byte & 1);
+ comm_write_bit(byte & 1);
byte >>= 1;
}
}
static inline uint16_t
-owslave_read_word() {
- return owslave_read_byte() + (owslave_read_byte() << 8);
+comm_read_word() {
+ return comm_read_byte() + (comm_read_byte() << 8);
}
static inline void
-owslave_write_word(uint16_t x) {
- owslave_write_byte(x);
- owslave_write_byte(x >> 8);
+comm_write_word(uint16_t x) {
+ comm_write_byte(x);
+ comm_write_byte(x >> 8);
}
// These next three lines help clean out some,
@@ -660,30 +782,46 @@ main(void) {
// Stop the timer, if it happens to be running.
TCCR0B = 0;
- // Initialize the IOPin
- cbi(PORTB, OWSLAVE_IOPIN);
- cbi(DDRB, OWSLAVE_IOPIN);
+ // Only set MOIST_COLLECTOR_PIN and MOIST_DRIVE_PIN to be outputs.
+ DDRB = _BV(MOIST_COLLECTOR_PIN) | _BV(MOIST_DRIVE_PIN);
+
+ // All pins other than COMM_SDA, MOIST_COLLECTOR_PIN,
+ // and MOIST_DRIVE_PIN are set to HIGH, which turns on
+ // the pull-up resistors.
+ PORTB = ~(
+ _BV(COMM_SDA) | _BV(MOIST_COLLECTOR_PIN) | _BV(MOIST_DRIVE_PIN)
+#if COMM_PHY_PROTO == COMM_PHY_2WIRE
+ | _BV(COMM_SCK)
+#endif
+ );
// Enable overflow interrupt, which is how we detect reset pulses.
// The interrupt handler for the overflow interrupt isn't actually
// defined, which means that __bad_interrupt gets called instead.
// This causes a soft-reset of the device by jumping to address 0x0000.
- TIMSK0 = 0;
- sbi(TIMSK0, TOIE0);
+ TIMSK0 = _BV(TOIE0);
-#if SUPPORT_CONVERT_INDICATOR
- OCR0A = (uint8_t)((uint32_t)OWSLAVE_T_X * F_CPU / 8l / 1000000l);
+#if SUPPORT_CONVERT_INDICATOR && (COMM_PHY_PROTO==COMM_PHY_1WIRE)
+ OCR0A = (uint8_t)((uint32_t)OWSLAVE_T_X * F_CPU / (8l * 1000000l) );
#endif
-#if SUPPORT_VOLT_READING || EMULATE_DS18B20
+#if SUPPORT_VOLT_READING || SUPPORT_TEMP_READING
ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
#endif
- // Allow the 1wire pin to generate interrupts.
- sbi(PCMSK, OWSLAVE_IOPIN);
+#if COMM_PHY_PROTO == COMM_PHY_2WIRE
+ USICR =
+ _BV(USIWM1) | _BV(USIWM0) // 2-Wire Mode.
+ | _BV(USISIE) // Start-Condition Interrupt Enable.
+ | _BV(USICS0) | _BV(USICS1) // External clock, negative edge.
+ ;
+#else
+ // Allow the bus pin to generate interrupts.
+ sbi(PCMSK, COMM_SDA);
// Turn on the pin-change interrupt.
sbi(GIMSK, PCIE);
+#endif
#if USE_WATCHDOG
// Turn on the watchdog with a maximum watchdog timeout period.
@@ -695,67 +833,65 @@ main(void) {
// Check to see if this was a hard or soft reset.
if(MCUSR) {
- // Hard reset. No presence pulse.
+ // Hard reset. This happens at initial power-up,
+ // when a brown-out condition occurs, and when the
+ // watchdog timer expires.
+ // We don't send a presense-pulse in this case.
+ // Reset the MCU status register.
MCUSR = 0;
#if !USE_WATCHDOG
+ // We should always attempt to disable the watchdog if we
+ // are not configured to use one. (Advice from the datasheet)
wdt_disable();
#endif
- owslave_cb_recall();
+ // Load our initial settings from EEPROM.
+ do_recall();
goto wait_for_reset;
}
// Reset the MCU status register.
MCUSR = 0;
- // Wait for reset pulse to end.
- while(bit_is_clear(PINB, OWSLAVE_IOPIN)) sleep_cpu();
+ comm_send_presence();
#if USE_WATCHDOG
wdt_reset();
#endif
- // Let the bus idle for 20µSec after the end of the reset pulse.
- _delay_us(20);
-
- // Send the 80µSec presence pulse.
- sbi(DDRB, OWSLAVE_IOPIN);
- _delay_us(80);
- cbi(DDRB, OWSLAVE_IOPIN);
-
// Read ROM command
- cmd = owslave_read_byte();
+ cmd = comm_read_byte();
flags = 0;
// Interpret what the ROM command means.
- if(cmd == OWSLAVE_ROMCMD_MATCH)
+ if(cmd == COMM_ROMCMD_MATCH)
flags = _BV(2);
- else if(cmd == OWSLAVE_ROMCMD_READ)
+ else if(cmd == COMM_ROMCMD_READ)
flags = _BV(0);
- else if((cmd == OWSLAVE_ROMCMD_SEARCH)
- || ((cmd == OWSLAVE_ROMCMD_ALARM_SEARCH)
- && owslave_cb_alarm_condition()
+ else if((cmd == COMM_ROMCMD_SEARCH)
+ || ((cmd == COMM_ROMCMD_ALARM_SEARCH)
+ && get_alarm_condition()
)
)
flags = _BV(0) | _BV(1) | _BV(2);
- else if(cmd != OWSLAVE_ROMCMD_SKIP)
+ else if(cmd != COMM_ROMCMD_SKIP)
goto wait_for_reset;
// Perfom the ROM command.
if(flags) {
for(uint8_t i = 0; i != 8; i++) {
- uint8_t byte = eeprom_read_byte(&owslave_addr.d[i]);
+ uint8_t byte = eeprom_read_byte(&comm_addr.d[i]);
uint8_t j = 8;
do {
if(flags & _BV(0))
- owslave_write_bit(byte & 1);
+ comm_write_bit(byte & 1);
if(flags & _BV(1))
- owslave_write_bit((~byte) & 1);
+ comm_write_bit((~byte) & 1);
if(flags & _BV(2))
- if((byte & 1) ^ owslave_read_bit())
+ if((byte & 1) ^ comm_read_bit())
goto wait_for_reset;
byte >>= 1;
} while(--j);
@@ -767,38 +903,38 @@ main(void) {
#endif
// Read function command
- cmd = owslave_read_byte();
+ cmd = comm_read_byte();
#if SUPPORT_DEVICE_NAMING
- if(cmd == OWSLAVE_FUNCCMD_RD_NAME) {
+ if(cmd == COMM_FUNCCMD_RD_NAME) {
for(uint8_t i = 0; i != (uint8_t)sizeof(device_name); i++) {
- owslave_write_byte(eeprom_read_byte(&device_name[i]));
+ comm_write_byte(eeprom_read_byte(&device_name[i]));
}
- owslave_write_byte(0x00);
+ comm_write_byte(0x00);
} else
#endif
- if((cmd == OWSLAVE_FUNCCMD_RD_MEM)
- || (cmd == OWSLAVE_FUNCCMD_WR_MEM)
+ if((cmd == COMM_FUNCCMD_RD_MEM)
+ || (cmd == COMM_FUNCCMD_WR_MEM)
) {
// Initialize the CRC by shifting in the command.
uint16_t crc = _crc16_update(0, cmd);
// Read in the requested byte address and update the CRC.
- uint8_t i = owslave_read_byte();
+ uint8_t i = comm_read_byte();
crc = _crc16_update(crc, i);
- owslave_read_byte();
+ comm_read_byte();
crc = _crc16_update(crc, 0);
while(i < 23) {
uint8_t byte;
- if(cmd == OWSLAVE_FUNCCMD_RD_MEM) {
+ if(cmd == COMM_FUNCCMD_RD_MEM) {
// Send the byte to the OW master.
byte = ((uint8_t*)&value)[i++];
- owslave_write_byte(byte);
+ comm_write_byte(byte);
} else {
// receive the byte from the OW master.
- byte = owslave_read_byte();
+ byte = comm_read_byte();
((uint8_t*)&value)[i++] = byte;
}
@@ -807,44 +943,44 @@ main(void) {
// Write out the CRC at every 8-byte page boundry.
if((i & 7) == 0) {
- owslave_write_word(crc);
+ comm_write_word(crc);
crc = 0;
}
}
- } else if(cmd == OWSLAVE_FUNCCMD_CONVERT) {
- owslave_read_byte(); // Ignore input select mask
- owslave_read_byte(); // Ignore read-out control
- owslave_cb_convert();
- } else if(cmd == OWSLAVE_FUNCCMD_COMMIT_MEM) {
- owslave_begin_busy();
- owslave_cb_commit();
- owslave_end_busy();
- } else if(cmd == OWSLAVE_FUNCCMD_RECALL_MEM) {
- owslave_begin_busy();
- owslave_cb_recall();
- owslave_end_busy();
- } else if(cmd == OWSLAVE_FUNCCMD_CONVERT_T) {
- owslave_cb_convert();
+ } else if(cmd == COMM_FUNCCMD_CONVERT) {
+ comm_read_byte(); // Ignore input select mask
+ comm_read_byte(); // Ignore read-out control
+ do_convert();
+ } else if(cmd == COMM_FUNCCMD_COMMIT_MEM) {
+ comm_begin_busy();
+ do_commit();
+ comm_end_busy();
+ } else if(cmd == COMM_FUNCCMD_RECALL_MEM) {
+ comm_begin_busy();
+ do_recall();
+ comm_end_busy();
+ } else if(cmd == COMM_FUNCCMD_CONVERT_T) {
+ do_convert();
}
#if EMULATE_DS18B20
- else if(cmd == OWSLAVE_FUNCCMD_RD_SCRATCH) {
+ else if(cmd == COMM_FUNCCMD_RD_SCRATCH) {
uint8_t crc = 0;
crc = _crc_ibutton_update(crc, ((uint8_t*)&value.temp)[0]);
- owslave_write_byte(((uint8_t*)&value.temp)[0]);
+ comm_write_byte(((uint8_t*)&value.temp)[0]);
crc = _crc_ibutton_update(crc, ((uint8_t*)&value.temp)[1]);
- owslave_write_byte(((uint8_t*)&value.temp)[1]);
+ comm_write_byte(((uint8_t*)&value.temp)[1]);
for(uint8_t i = 0; i < 6; i++) {
crc = _crc_ibutton_update(crc, 0);
- owslave_write_byte(0);
+ comm_write_byte(0);
}
- owslave_write_byte(crc);
+ comm_write_byte(crc);
}
#endif
wait_for_reset:
for(;;) {
- // Allow the 1wire pin to generate interrupts.
- sbi(PCMSK, OWSLAVE_IOPIN);
+ // Allow the bus pin to generate interrupts.
+ sbi(PCMSK, COMM_SDA);
// Turn on the pin-change interrupt.
sbi(GIMSK, PCIE);
@@ -858,10 +994,16 @@ main(void) {
}
}
+#if (COMM_PHY_PROTO == COMM_PHY_1WIRE) || (COMM_PHY_PROTO == COMM_PHY_FxB)
+
#if SUPPORT_CONVERT_INDICATOR
ISR(TIM0_COMPA_vect) {
- cbi(DDRB, OWSLAVE_IOPIN);
+#if COMM_PHY_PROTO == COMM_PHY_1WIRE
+ cbi(DDRB, COMM_SDA);
was_interrupted++;
+#elif COMM_PHY_PROTO == COMM_PHY_FxB
+ // TODO: Writeme!
+#endif
}
#endif
@@ -874,18 +1016,24 @@ ISR(PCINT0_vect) {
#endif
// Is this a high-to-low transition?
- if(bit_is_clear(PINB, OWSLAVE_IOPIN)) {
+ if(bit_is_clear(PINB, COMM_SDA)) {
#if SUPPORT_CONVERT_INDICATOR
+#if COMM_PHY_PROTO == COMM_PHY_1WIRE
if(bit_is_set(TIMSK0, OCIE0A))
- sbi(DDRB, OWSLAVE_IOPIN);
+ sbi(DDRB, COMM_SDA);
+#elif COMM_PHY_PROTO == COMM_PHY_FxB
+ // TODO: Writeme!
+#endif
#endif
TCNT0 = 0; // Reset counter.
// Start timer with prescaler of 1/8.
- // @9.6MHz: ~.8333µSecconds per tick, 214µSecond reset pulse
- // @8.0MHz: ~1µSecond per tick, 256µSecond reset pulse
+ // @9.6MHz: ~.8333µSecconds per tick, 214µSecond reset pulse
+ // @8.0MHz: ~1µSecond per tick, 256µSecond reset pulse
TCCR0B = (1 << 1);
}
}
+#endif
+
View
51 protocol.txt
@@ -4,17 +4,39 @@ NOTE: THIS IS ALL CURRENTLY IN FLUX. THIS DOCUMENTATION MAY NOT REFLECT THE
ACTUAL PROTOCOL IMPLEMENTED IN THE SOURCE CODE. THIS WILL BE FIXED BEFORE THE
OFFICIAL RELEASE.
-This sensor uses the 1-wire slave protocol. This protocol is widely documented.
-See the 1-Wire/iButton Standard (referenced at the end of this document) for
-more information.
+# Physical-layer Bus Protocol #
-## Patent Notice ##
+The firmware on this sensor can be compiled to use any number of physical
+protocols for communication. These protocols define how individual bits are
+sent and received from the bus. These include:
-The 1-wire protocol is patented: USPAT#6,108,751
+ * 1-Wire® Compatible: DO NOT USE. SEE PATENT NOTICE BELOW.
+ * Fox-Bus™: Similar to 1-Wire®, but not patented and with better
+ noise resistance. <http://fox-bus.org/>
+ * 2-Wire: Uses two wires, SCL(clock) and SDA(data).
-You will need to obtain a license for the 1-wire protocol if you plan to
-construct any significant number of these devices, otherwise MAXIM will come
-knocking at your door with angry lawyers.
+The recommended and default physical bus protocol is Fox-Bus™.
+
+## IMPORTANT PATENT NOTICE ##
+
+THE PHYSICAL LAYER OF THE 1-WIRE® PROTOCOL IS PATENTED: USPAT#6,108,751
+
+MAXIM-IC, THE OWNER OF THIS PATENT, HAS EXPLICITLY STATED THAT THEY ARE
+UNABLE/UNWILLING TO GRANT ANY LICENSE FOR THE USE OF THE 1-WIRE PROTOCOL
+ON NON-MAXIM SLAVE DEVICES. AS SUCH, IF YOU CHOOSE TO USE OF THE 1-WIRE
+PHYSICAL PROTOCOL FOR THIS PROJECT, IT COULD EXPOSE YOU TO SUBSTANTIAL AND
+DEVISTATING CIVIL LIABILITY---EVEN FOR PERSONAL USE.
+
+USE FOX-BUS™ INSTEAD. YOU HAVE BEEN WARNED.
+
+# Link-layer Bus Protocol #
+
+The link-layer of the 1-Wire® protocol appears to *NOT* be patented. As such,
+the link-layer bus protocol used for this project is similar to that of
+1-Wire®. See any documentation of the 1-Wire® protocol for more details.
+
+Alternative link-layer bus protocols (Like I²C) may be implemented in the future
+if the need arrises.
## ROM Commands ##
@@ -26,7 +48,7 @@ This device supports the following ROM funcitons:
* `0xF0` SEARCH
* `0xEC` ALARMSEARCH
-Overdrive commands are not (yet?) supported.
+Overdrive commands are not supported.
## Function Commands ##
@@ -42,8 +64,8 @@ This device supports the following funciton commands:
### READMEM and WRITEMEM ###
-READMEM and WRITEMEM work similar to how they work on other 1-wire or
-iButton devices: each takes a two-byte start address and then either
+READMEM and WRITEMEM work similar to how they work on other 1-Wire® or
+iButton® devices: each takes a two-byte start address and then either
reads out or reads in bytes to be read or written respectively. At each
eight-byte page boundary, a 16-bit CRC is returned from the device.
@@ -130,7 +152,7 @@ following formula:
VCC = 1024.0*1.1/(VOLTAGE_L+(VOLTAGE_H<<8))
-### Page 1 - Device Configuration ###
+### Page 1 - Device Configuration and Status ###
* `0x08` ALARM_LOW
* `0x09` ALARM_HIGH
@@ -156,8 +178,9 @@ See notes.txt for more information on calibration values.
## References ##
- * [1-Wire Wikipedia Page](http://en.wikipedia.org/wiki/1-Wire)
- * [1-Wire/iButton Standard](http://www.maxim-ic.com/products/ibutton/ibuttons/standard.pdf)
+ * [1-Wire® Wikipedia Page](http://en.wikipedia.org/wiki/1-Wire)
+ * [1-Wire®/iButton® Standard](http://www.maxim-ic.com/products/ibutton/ibuttons/standard.pdf)
* [DS18B20 Datasheet](http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf)
* [DS2450 Datasheet](http://datasheets.maxim-ic.com/en/ds/DS2450.pdf)
* [USPAT#6,108,751](http://patimg1.uspto.gov/.piw?Docid=06108751&idkey=NONE)
+ * [Fox-Bus™](http://fox-bus.org/)

0 comments on commit c50a22f

Please sign in to comment.
Something went wrong with that request. Please try again.