Author: ian
Date: Sun Dec  8 20:42:58 2019
New Revision: 355533
URL: https://svnweb.freebsd.org/changeset/base/355533

Log:
  Add support for more chips to the gpioths driver.
  
  Previously the driver supported the DHT11 sensor.  Now it supports
  
   DHT11, DHT12, DHT21, DHT22, AM3201, AM3202.
  
  All these chips are similar, differing primarily in supported temperature
  and humidity ranges and accuracy (and, presumably, cost).  There are two
  basic data formats reported by the various chips, and it is possible to
  figure out at runtime which format to use for decoding the data based on
  the range of values in a single byte of the humidity measurement. (which
  is detailed in a comment block, so I won't recapitulate it here).

Modified:
  head/sys/dev/gpio/gpioths.c

Modified: head/sys/dev/gpio/gpioths.c
==============================================================================
--- head/sys/dev/gpio/gpioths.c Sun Dec  8 20:36:13 2019        (r355532)
+++ head/sys/dev/gpio/gpioths.c Sun Dec  8 20:42:58 2019        (r355533)
@@ -47,6 +47,14 @@ __FBSDID("$FreeBSD$");
  * This is driver for Temperature & Humidity sensor which provides digital
  * output over single-wire protocol from embedded 8-bit microcontroller.
  * 
+ * This driver supports the following chips:
+ *   DHT11:  Temp   0c to 50c +-2.0c, Humidity 20% to  90% +-5%
+ *   DHT12:  Temp -20c to 60c +-0.5c, Humidity 20% to  95% +-5%
+ *   DHT21:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-3%
+ *   DHT22:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-2%
+ *   AM2301: Same as DHT21, but also supports i2c interface.
+ *   AM2302: Same as DHT22, but also supports i2c interface.
+ *
  * Temp/Humidity sensor can't be discovered automatically, please specify hints
  * as part of loader or kernel configuration:
  *     hint.gpioths.0.at="gpiobus0"
@@ -59,8 +67,6 @@ __FBSDID("$FreeBSD$");
 #define        GPIOTHS_DHT_TIMEOUT     1000    /* 1ms = 1000us */
 #define        GPIOTHS_DHT_CYCLES      41
 #define        GPIOTHS_DHT_ONEBYTEMASK 0xFF
-#define        GPIOTHS_DHT_TEMP_SHIFT  8
-#define        GPIOTHS_DHT_HUM_SHIFT   24
 
 struct gpioths_softc {
        device_t                 dev;
@@ -160,7 +166,7 @@ gpioths_dht_readbytes(device_t bus, device_t dev)
        uint32_t                 intervals[GPIOTHS_DHT_CYCLES];
        uint32_t                 err, avglen, value;
        uint8_t                  crc, calc;
-       int                      i, offset, size;
+       int                      i, negmul, offset, size, tmphi, tmplo;
 
        sc = device_get_softc(dev);
 
@@ -246,9 +252,46 @@ gpioths_dht_readbytes(device_t bus, device_t dev)
                goto error;
        }
 
+       /*
+        * For DHT11/12, the values are split into 8 bits of integer and 8 bits
+        * of fractional tenths.  On DHT11 the fraction bytes are always zero.
+        * On DHT12 the sign bit is in the high bit of the fraction byte.
+        *  - DHT11: 0HHHHHHH 00000000 00TTTTTT 00000000
+        *  - DHT12: 0HHHHHHH 0000hhhh 00TTTTTT s000tttt
+        *
+        * For DHT21/21, the values are are encoded in 16 bits each, with the
+        * temperature sign bit in the high bit.  The values are tenths of a
+        * degree C and tenths of a percent RH.
+        *  - DHT21: 000000HH HHHHHHHH s00000TT TTTTTTTT
+        *  - DHT22: 000000HH HHHHHHHH s00000TT TTTTTTTT
+        *
+        * For all devices, some bits are always zero because of the range of
+        * values supported by the device.
+        *
+        * We figure out how to decode things based on the high byte of the
+        * humidity.  A DHT21/22 cannot report a value greater than 3 in
+        * the upper bits of its 16-bit humidity.  A DHT11/12 should not report
+        * a value lower than 20.  To allow for the possibility that a device
+        * could report a value slightly out of its sensitivity range, we split
+        * the difference and say if the value is greater than 10 it cannot be a
+        * DHT22 (that would be a humidity over 256%).
+        */
+#define        DK_OFFSET 2731 /* Offset between K and C, in decikelvins. */
+       if ((value >> 24) > 10) {
+               /* DHT11 or DHT12 */
+               tmphi = (value >> 8) & 0x3f;
+               tmplo = value & 0x0f;
+               negmul = (value & 0x80) ? -1 : 1;
+               sc->temp = DK_OFFSET + (negmul * (tmphi * 10 + tmplo));
+               sc->hum = (value >> 24) & 0x7f;
+       } else {
+                /* DHT21 or DHT22 */
+               negmul = (value & 0x8000) ? -1 : 1;
+               sc->temp = DK_OFFSET + (negmul * (value & 0x03ff));
+               sc->hum = ((value >> 16) & 0x03ff) / 10;
+       }
+
        sc->fails = 0;
-       sc->temp = (value >> GPIOTHS_DHT_TEMP_SHIFT) & GPIOTHS_DHT_ONEBYTEMASK;
-       sc->hum = (value >> GPIOTHS_DHT_HUM_SHIFT) & GPIOTHS_DHT_ONEBYTEMASK;
 
 #ifdef GPIOTHS_DEBUG
        /* Debug bits */
@@ -296,7 +339,7 @@ gpioths_attach(device_t dev)
 
        sysctl_add_oid(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "temperature",     
                        \
            CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
-           &sc->temp, 0, sysctl_handle_int, "I", "temperature", NULL);
+           &sc->temp, 0, sysctl_handle_int, "IK", "temperature", NULL);
 
        SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "humidity",
            CTLFLAG_RD, &sc->hum, 0, "relative humidity(%)");
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to