Skip to content
This repository was archived by the owner on Nov 12, 2019. It is now read-only.

Commit a5acb6a

Browse files
committed
Update to support the Raspberry Pi 2.
1 parent dfdcbd9 commit a5acb6a

10 files changed

+519
-35
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ build
22
*.egg-info
33
*.pyc
44
setuptools-*
5+
*.so
56

Adafruit_DHT/Raspberry_Pi_2.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright (c) 2014 Adafruit Industries
2+
# Author: Tony DiCola
3+
4+
# Permission is hereby granted, free of charge, to any person obtaining a copy
5+
# of this software and associated documentation files (the "Software"), to deal
6+
# in the Software without restriction, including without limitation the rights
7+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
# copies of the Software, and to permit persons to whom the Software is
9+
# furnished to do so, subject to the following conditions:
10+
11+
# The above copyright notice and this permission notice shall be included in all
12+
# copies or substantial portions of the Software.
13+
14+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
# SOFTWARE.
21+
import common
22+
import Raspberry_Pi_2_Driver as driver
23+
24+
def read(sensor, pin):
25+
# Validate pin is a valid GPIO.
26+
if pin is None or int(pin) < 0 or int(pin) > 31:
27+
raise ValueError('Pin must be a valid GPIO number 0 to 31.')
28+
# Get a reading from C driver code.
29+
result, humidity, temp = driver.read(sensor, int(pin))
30+
if result in common.TRANSIENT_ERRORS:
31+
# Signal no result could be obtained, but the caller can retry.
32+
return (None, None)
33+
elif result == common.DHT_ERROR_GPIO:
34+
raise RuntimeError('Error accessing GPIO. Make sure program is run as root with sudo!')
35+
elif result != common.DHT_SUCCESS:
36+
# Some kind of error occured.
37+
raise RuntimeError('Error calling DHT test driver read: {0}'.format(result))
38+
return (humidity, temp)

Adafruit_DHT/common.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,16 @@ def get_platform():
4242
"""Return a DHT platform interface for the currently detected platform."""
4343
plat = platform_detect.platform_detect()
4444
if plat == platform_detect.RASPBERRY_PI:
45-
import Raspberry_Pi
46-
return Raspberry_Pi
45+
# Check for version 1 or 2 of the pi.
46+
version = platform_detect.pi_version()
47+
if version == 1:
48+
import Raspberry_Pi
49+
return Raspberry_Pi
50+
elif version == 2:
51+
import Raspberry_Pi_2
52+
return Raspberry_Pi_2
53+
else:
54+
raise RuntimeError('No driver for detected Raspberry Pi version available!')
4755
elif plat == platform_detect.BEAGLEBONE_BLACK:
4856
import Beaglebone_Black
4957
return Beaglebone_Black

Adafruit_DHT/platform_detect.py

+75-28
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,86 @@
1818
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1919
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2020
# SOFTWARE.
21+
22+
# This is a direct copy of what's in the Adafruit Python GPIO library:
23+
# https://raw.githubusercontent.com/adafruit/Adafruit_Python_GPIO/master/Adafruit_GPIO/Platform.py
24+
# TODO: Add dependency on Adafruit Python GPIO and use its platform detect
25+
# functions.
26+
2127
import platform
28+
import re
2229

2330
# Platform identification constants.
2431
UNKNOWN = 0
2532
RASPBERRY_PI = 1
2633
BEAGLEBONE_BLACK = 2
2734

2835

29-
def platform_detect(plat=platform.platform()):
30-
"""Detect if running on the Raspberry Pi or Beaglebone Black and return the
31-
platform type. Will return RASPBERRY_PI, BEAGLEBONE_BLACK, or UNKNOWN."""
32-
# Handle Raspberry Pi
33-
# Platform output on Raspbian testing/jessie ~May 2014:
34-
# Linux-3.10.25+-armv6l-with-debian-7.4
35-
if plat.lower().find('armv6l-with-debian') > -1:
36-
return RASPBERRY_PI
37-
# Handle pidora distribution.
38-
elif plat.lower().find('raspberry_pi') > -1:
39-
return RASPBERRY_PI
40-
# Handle arch distribution.
41-
elif plat.lower().find('arch-armv6l') > -1:
42-
return RASPBERRY_PI
43-
# Handle Beaglebone Black
44-
# Platform output on Debian ~May 2014:
45-
# Linux-3.8.13-bone47-armv7l-with-debian-7.4
46-
elif plat.lower().find('armv7l-with-debian') > -1:
47-
return BEAGLEBONE_BLACK
48-
# Handle Beaglebone Black
49-
# Platform output on Ubuntu ~July 2014:
50-
# Linux-3.8.13-bone56-armv7l-with-Ubuntu-14.04-trusty
51-
elif plat.lower().find('armv7l-with-ubuntu') > -1:
52-
return BEAGLEBONE_BLACK
53-
elif plat.lower().find('armv7l-with-glibc2.4') > -1:
54-
return BEAGLEBONE_BLACK
55-
else:
56-
return UNKNOWN
36+
def platform_detect():
37+
"""Detect if running on the Raspberry Pi or Beaglebone Black and return the
38+
platform type. Will return RASPBERRY_PI, BEAGLEBONE_BLACK, or UNKNOWN."""
39+
# Handle Raspberry Pi
40+
pi = pi_version()
41+
if pi is not None:
42+
return RASPBERRY_PI
43+
44+
# Handle Beaglebone Black
45+
# TODO: Check the Beaglebone Black /proc/cpuinfo value instead of reading
46+
# the platform.
47+
plat = platform.platform()
48+
if plat.lower().find('armv7l-with-debian') > -1:
49+
return BEAGLEBONE_BLACK
50+
elif plat.lower().find('armv7l-with-ubuntu') > -1:
51+
return BEAGLEBONE_BLACK
52+
elif plat.lower().find('armv7l-with-glibc2.4') > -1:
53+
return BEAGLEBONE_BLACK
54+
55+
# Couldn't figure out the platform, just return unknown.
56+
return UNKNOWN
57+
58+
59+
def pi_revision():
60+
"""Detect the revision number of a Raspberry Pi, useful for changing
61+
functionality like default I2C bus based on revision."""
62+
# Revision list available at: http://elinux.org/RPi_HardwareHistory#Board_Revision_History
63+
with open('/proc/cpuinfo', 'r') as infile:
64+
for line in infile:
65+
# Match a line of the form "Revision : 0002" while ignoring extra
66+
# info in front of the revsion (like 1000 when the Pi was over-volted).
67+
match = re.match('Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE)
68+
if match and match.group(1) in ['0000', '0002', '0003']:
69+
# Return revision 1 if revision ends with 0000, 0002 or 0003.
70+
return 1
71+
elif match:
72+
# Assume revision 2 if revision ends with any other 4 chars.
73+
return 2
74+
# Couldn't find the revision, throw an exception.
75+
raise RuntimeError('Could not determine Raspberry Pi revision.')
76+
77+
78+
def pi_version():
79+
"""Detect the version of the Raspberry Pi. Returns either 1, 2 or
80+
None depending on if it's a Raspberry Pi 1 (model A, B, A+, B+),
81+
Raspberry Pi 2 (model B+), or not a Raspberry Pi.
82+
"""
83+
# Check /proc/cpuinfo for the Hardware field value.
84+
# 2708 is pi 1
85+
# 2709 is pi 2
86+
# Anything else is not a pi.
87+
with open('/proc/cpuinfo', 'r') as infile:
88+
cpuinfo = infile.read()
89+
# Match a line like 'Hardware : BCM2709'
90+
match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo,
91+
flags=re.MULTILINE | re.IGNORECASE)
92+
if not match:
93+
# Couldn't find the hardware, assume it isn't a pi.
94+
return None
95+
if match.group(1) == 'BCM2708':
96+
# Pi 1
97+
return 1
98+
elif match.group(1) == 'BCM2709':
99+
# Pi 2
100+
return 2
101+
else:
102+
# Something else, not a pi.
103+
return None

setup.py

+23-5
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@
1010
# Kind of hacky to manipulate the argument list before calling setup, but it's
1111
# the best simple option for adding optional config to the setup.
1212
platform = platform_detect.UNKNOWN
13+
pi_version = None
1314
if '--force-pi' in sys.argv:
1415
platform = platform_detect.RASPBERRY_PI
16+
pi_version = 1
1517
sys.argv.remove('--force-pi')
18+
elif '--force-pi2' in sys.argv:
19+
platform = platform_detect.RASPBERRY_PI
20+
pi_version = 2
21+
sys.argv.remove('--force-pi2')
1622
elif '--force-bbb' in sys.argv:
1723
platform = platform_detect.BEAGLEBONE_BLACK
1824
sys.argv.remove('--force-bbb')
@@ -26,10 +32,22 @@
2632
# Pick the right extension to compile based on the platform.
2733
extensions = []
2834
if platform == platform_detect.RASPBERRY_PI:
29-
extensions.append(Extension("Adafruit_DHT.Raspberry_Pi_Driver",
30-
["source/_Raspberry_Pi_Driver.c", "source/common_dht_read.c", "source/Raspberry_Pi/pi_dht_read.c", "source/Raspberry_Pi/pi_mmio.c"],
31-
libraries=['rt'],
32-
extra_compile_args=['-std=gnu99']))
35+
# Get the Pi version (1 or 2)
36+
if pi_version is None:
37+
pi_version = platform_detect.pi_version()
38+
# Build the right extension depending on the Pi version.
39+
if pi_version == 1:
40+
extensions.append(Extension("Adafruit_DHT.Raspberry_Pi_Driver",
41+
["source/_Raspberry_Pi_Driver.c", "source/common_dht_read.c", "source/Raspberry_Pi/pi_dht_read.c", "source/Raspberry_Pi/pi_mmio.c"],
42+
libraries=['rt'],
43+
extra_compile_args=['-std=gnu99']))
44+
elif pi_version == 2:
45+
extensions.append(Extension("Adafruit_DHT.Raspberry_Pi_2_Driver",
46+
["source/_Raspberry_Pi_2_Driver.c", "source/common_dht_read.c", "source/Raspberry_Pi_2/pi_2_dht_read.c", "source/Raspberry_Pi_2/pi_2_mmio.c"],
47+
libraries=['rt'],
48+
extra_compile_args=['-std=gnu99']))
49+
else:
50+
raise RuntimeError('Detected Pi version that has no appropriate driver available.')
3351
elif platform == platform_detect.BEAGLEBONE_BLACK:
3452
extensions.append(Extension("Adafruit_DHT.Beaglebone_Black_Driver",
3553
["source/_Beaglebone_Black_Driver.c", "source/common_dht_read.c", "source/Beaglebone_Black/bbb_dht_read.c", "source/Beaglebone_Black/bbb_mmio.c"],
@@ -45,7 +63,7 @@
4563

4664
# Call setuptools setup function to install package.
4765
setup(name = 'Adafruit_DHT',
48-
version = '1.0.0',
66+
version = '1.1.0',
4967
author = 'Tony DiCola',
5068
author_email = 'tdicola@adafruit.com',
5169
description = 'Library to get readings from the DHT11, DHT22, and AM2302 humidity and temperature sensors on a Raspberry Pi or Beaglebone Black.',

source/Raspberry_Pi_2/pi_2_dht_read.c

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright (c) 2014 Adafruit Industries
2+
// Author: Tony DiCola
3+
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
11+
// The above copyright notice and this permission notice shall be included in all
12+
// copies or substantial portions of the Software.
13+
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
// SOFTWARE.
21+
#include <stdbool.h>
22+
#include <stdlib.h>
23+
24+
#include "pi_2_dht_read.h"
25+
#include "pi_2_mmio.h"
26+
27+
// This is the only processor specific magic value, the maximum amount of time to
28+
// spin in a loop before bailing out and considering the read a timeout. This should
29+
// be a high value, but if you're running on a much faster platform than a Raspberry
30+
// Pi or Beaglebone Black then it might need to be increased.
31+
#define DHT_MAXCOUNT 32000
32+
33+
// Number of bit pulses to expect from the DHT. Note that this is 41 because
34+
// the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
35+
// the data afterwards.
36+
#define DHT_PULSES 41
37+
38+
int pi_2_dht_read(int type, int pin, float* humidity, float* temperature) {
39+
// Validate humidity and temperature arguments and set them to zero.
40+
if (humidity == NULL || temperature == NULL) {
41+
return DHT_ERROR_ARGUMENT;
42+
}
43+
*temperature = 0.0f;
44+
*humidity = 0.0f;
45+
46+
// Initialize GPIO library.
47+
if (pi_2_mmio_init() < 0) {
48+
return DHT_ERROR_GPIO;
49+
}
50+
51+
// Store the count that each DHT bit pulse is low and high.
52+
// Make sure array is initialized to start at zero.
53+
int pulseCounts[DHT_PULSES*2] = {0};
54+
55+
// Set pin to output.
56+
pi_2_mmio_set_output(pin);
57+
58+
// Bump up process priority and change scheduler to try to try to make process more 'real time'.
59+
set_max_priority();
60+
61+
// Set pin high for ~500 milliseconds.
62+
pi_2_mmio_set_high(pin);
63+
sleep_milliseconds(500);
64+
65+
// The next calls are timing critical and care should be taken
66+
// to ensure no unnecssary work is done below.
67+
68+
// Set pin low for ~20 milliseconds.
69+
pi_2_mmio_set_low(pin);
70+
busy_wait_milliseconds(20);
71+
72+
// Set pin at input.
73+
pi_2_mmio_set_input(pin);
74+
// Need a very short delay before reading pins or else value is sometimes still low.
75+
for (volatile int i = 0; i < 50; ++i) {
76+
}
77+
78+
// Wait for DHT to pull pin low.
79+
uint32_t count = 0;
80+
while (pi_2_mmio_input(pin)) {
81+
if (++count >= DHT_MAXCOUNT) {
82+
// Timeout waiting for response.
83+
set_default_priority();
84+
return DHT_ERROR_TIMEOUT;
85+
}
86+
}
87+
88+
// Record pulse widths for the expected result bits.
89+
for (int i=0; i < DHT_PULSES*2; i+=2) {
90+
// Count how long pin is low and store in pulseCounts[i]
91+
while (!pi_2_mmio_input(pin)) {
92+
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
93+
// Timeout waiting for response.
94+
set_default_priority();
95+
return DHT_ERROR_TIMEOUT;
96+
}
97+
}
98+
// Count how long pin is high and store in pulseCounts[i+1]
99+
while (pi_2_mmio_input(pin)) {
100+
if (++pulseCounts[i+1] >= DHT_MAXCOUNT) {
101+
// Timeout waiting for response.
102+
set_default_priority();
103+
return DHT_ERROR_TIMEOUT;
104+
}
105+
}
106+
}
107+
108+
// Done with timing critical code, now interpret the results.
109+
110+
// Drop back to normal priority.
111+
set_default_priority();
112+
113+
// Compute the average low pulse width to use as a 50 microsecond reference threshold.
114+
// Ignore the first two readings because they are a constant 80 microsecond pulse.
115+
uint32_t threshold = 0;
116+
for (int i=2; i < DHT_PULSES*2; i+=2) {
117+
threshold += pulseCounts[i];
118+
}
119+
threshold /= DHT_PULSES-1;
120+
121+
// Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
122+
// If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
123+
// then it must be a ~70us 1 pulse.
124+
uint8_t data[5] = {0};
125+
for (int i=3; i < DHT_PULSES*2; i+=2) {
126+
int index = (i-3)/16;
127+
data[index] <<= 1;
128+
if (pulseCounts[i] >= threshold) {
129+
// One bit for long pulse.
130+
data[index] |= 1;
131+
}
132+
// Else zero bit for short pulse.
133+
}
134+
135+
// Useful debug info:
136+
//printf("Data: 0x%x 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3], data[4]);
137+
138+
// Verify checksum of received data.
139+
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
140+
if (type == DHT11) {
141+
// Get humidity and temp for DHT11 sensor.
142+
*humidity = (float)data[0];
143+
*temperature = (float)data[2];
144+
}
145+
else if (type == DHT22) {
146+
// Calculate humidity and temp for DHT22 sensor.
147+
*humidity = (data[0] * 256 + data[1]) / 10.0f;
148+
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
149+
if (data[2] & 0x80) {
150+
*temperature *= -1.0f;
151+
}
152+
}
153+
return DHT_SUCCESS;
154+
}
155+
else {
156+
return DHT_ERROR_CHECKSUM;
157+
}
158+
}

0 commit comments

Comments
 (0)