built in pull up resistor, DHT11, DHT22

Post here first, or if you can't find a relevant section!
Post Reply
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

built in pull up resistor, DHT11, DHT22

Post by ag123 »

this isn't really specific to the core more than it is a 'hardware' query
i'm thinking about interfacing DHT11 or DHT22 (AM2302)
https://www.mouser.com/datasheet/2/758/ ... 143054.pdf
https://www.sparkfun.com/datasheets/Sen ... /DHT22.pdf

a thing i noted about both of them requires a pull up resistor at the data line similar to i2c.
then in my google searches i noted this app note
AN4899 STM32 GPIO configuration for hardware settings and low-power consumption
https://www.st.com/resource/en/applicat ... ronics.pdf
mentions 3.3.1
  • The pull-up or pull-down resistors are activated depending on the value in the GPIOx_PUPDR register
but in rm0008 stm32f10x ref manual
https://www.st.com/resource/en/referenc ... ronics.pdf
9.1 gpio functional descr figure 13, table 20
the pullup / pulldown resistor is specifically shown in the figure but the register mentioned in table 20 is given as PxODR
and GPIOx_PUPDR isn't present there.
hence i'd assume that this functionality is achieved in stm32f103 using
9.2.4 Port output data register (GPIOx_ODR) (x=A..G) mentioned in rm0008 ?

it is a little surprising as 9.2.4 GPIOx_ODR is deemed an output register to set the gpio output and in addition it isn't literally clear if in the case of output
if the pin is set as output open drain, would the internal pull up automatically be effective?
having to solder a resistor between 2 pins is slightly bothersome but it can probably be done using an smd resistor on the sensor pin itself.
but i'd prefer a direct interface if the internal pull up or pull down can be used

playing with dht-11, dht-22 is a little tricky as i've to flip the pin between output open drain and input pull up

posted this across in st's forums
https://community.st.com/s/question/0D5 ... p-resistor
Last edited by ag123 on Wed Jul 01, 2020 10:29 pm, edited 1 time in total.
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: built in pull up resistor

Post by ag123 »

ODR controls the pullup/pulldown but only when in input mode.
See "Table 20. Port bit configuration table" in the reference manual or:
https://electronics.stackexchange.com/q ... -stm32f103
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: built in pull up resistor

Post by ag123 »

it sounds like when it is set as output open drain, the pull up won't be there and a resistor is needed after all.
i may try a different 'trick', when i'm setting output and triggering the dht11, dht22, i'd use normal push-pull instead. assuming that dht11, dht22 does 'open drain' it would then read that as a '1' (high). a slight risk is that the dht11, dht22 short that to ground instead, it would be somewhat a surprise as normally inputs is high impedance
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: built in pull up resistor

Post by fpiSTM »

Right, Pull config is not easy and rely on Input mode only as mentionned in the LL GPIO header:
* @note I/O mode can be Analog, Floating input, Input with pull-up/pull-down, General purpose Output,
* Alternate function Output.
Here how it is done in the STM32 core:

https://github.com/stm32duino/Arduino_C ... map.c#L163

here the detail of pin_PullConfig

https://github.com/stm32duino/Arduino_C ... .h#L50-L90

and here for LL_GPIO_SetPinPull which rely on ODR and LL_GPIO_SetPinMode

https://github.com/stm32duino/Arduino_C ... #L565-L568

https://github.com/stm32duino/Arduino_C ... #L342-L346
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: built in pull up resistor

Post by ag123 »

thanks ! it is cool that's supported in STM core :D

i'd probably try some experiments first. adafruit has a library for it kind of
https://github.com/adafruit/DHT-sensor-library
but i'd probably work something more 'stm32 based', preferably using the internal pull ups.
soldering resistors on bare wires is kind of messy. if it works pin to pin without resistors, that'd be ideal ;)
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: built in pull up resistor, DHT11, DHT22

Post by ag123 »

i ventured an implementation for DHT22 (AM2302) with a maple mini clone on libmaple core
no external pull-up resistors used

Code: Select all

#include <Arduino.h>

uint16_t pulse[80];
uint8_t data[5];

bool debug=false;
const uint8_t dht_data_pin = PB7;
uint8_t tog = 0;
bool timeout = false;

uint16_t expectPulse(uint8_t val);
void prtemp();
void timer_handler();
void dht_read();
float get_humidity();
float get_temp();
bool check_parity();
void sleep(uint16_t ms);

void setup() {
	pinMode(LED_BUILTIN, OUTPUT);
	Serial.begin();
	// vrefint
	adc_reg_map *regs = ADC1->regs;
	regs->CR2 |= ADC_CR2_TSVREFE;    // enable VREFINT and temp sensor
	regs->SMPR1 = ADC_SMPR1_SMP17;  // sample rate for VREFINT ADC channel

	//initialise microsecond timer
	Timer1.init();
	Timer1.pause();
	Timer1.setPrescaleFactor(72-1); // 1 us
	Timer1.setOverflow(0xffff); //timeout 65.535 ms
	Timer1.attachInterrupt(0, timer_handler);
	Timer1.refresh();

	pinMode(dht_data_pin, INPUT_PULLUP);
}

void timer_handler() {
	timeout = true;
	Timer1.pause();
}

void loop() {
	digitalWrite(LED_BUILTIN, HIGH);
	sleep(100);
	digitalWrite(LED_BUILTIN, LOW);

	prtemp();
	dht_read();
	float hum = get_humidity();
	float temp = get_temp();
	Serial.print("dht humidity (RH%):");
	Serial.println(hum);
	Serial.print("dht temp (C):");
	Serial.println(temp);
	sleep(10000);

}

void sleep(uint16_t ms) {
	for(int i=0; i<ms; i++)
		asm("wfi");
}

float get_humidity() {
	uint16_t hum = data[0] << 8 | data[1];
	return hum / 10.0;
}

float get_temp() {
	int temp = (data[2] & 0x7f) << 8 | data[3];
	if(data[2] >> 7 == 1)
		temp *= -1;
	return temp / 10.0;
}

bool check_parity() {
	uint8_t sum = data[0] + data[1] + data[2] + data[3];
	return sum == data[4];
}

/* note the timings used here is based on DHT22 AM2302
 */
void dht_read() {
	pinMode(dht_data_pin, OUTPUT_OPEN_DRAIN);
	digitalWrite(dht_data_pin, LOW);
	delay(1); //start conversion 1ms low pulse
	digitalWrite(dht_data_pin, HIGH);
	pinMode(dht_data_pin, INPUT_PULLUP);
	expectPulse(HIGH); //30us
	if(timeout) {
		Serial.println("timeout waiting for response low");
		return;
	}
	expectPulse(LOW); //80us
	if(timeout) {
		Serial.println("timeout waiting for response high");
		return;
	}
	expectPulse(HIGH); //80us
	if(timeout) {
		Serial.println("timeout waiting for data");
		return;
	}
	/* next data pulses
	 * low pulse 50 us
	 * '0' high pulse 26 us
	 * '1' high pulse 70 us
	 */
	for(uint16_t i=0; i<80; i+=2) {
		pulse[i] = expectPulse(LOW);
		if(timeout) {
			Serial.print("timeout reading data ");
			Serial.print(i/2);
			Serial.println("low");
			return;
		}
		pulse[i+1] = expectPulse(HIGH);
		if(timeout) {
			Serial.print("timeout reading data ");
			Serial.print(i/2);
			Serial.println("high");
			return;
		}
	}
	//decode pulses
	for(uint16_t i=0; i<40; i++) {
		uint16_t lowcount = pulse[2*i];
		uint16_t highcount = pulse[2*i + 1];
		if(debug) {
			Serial.print(i);
			Serial.print(":");
			Serial.print(lowcount);
			Serial.print(",");
			Serial.println(highcount);
		}
		data[i / 8] <<= 1;
		if (highcount > lowcount) {
		   // High cycles are greater than 50us low cycle count, must be a 1.
		   data[i / 8] |= 1;
		}
	}
}

uint16_t expectPulse(uint8_t val) {
	//start the counter
	Timer1.refresh();
	timeout = false;
	Timer1.resume();
	while(digitalRead(dht_data_pin) == val && !timeout);
	Timer1.pause();
	return Timer1.getCount();
}

void prtemp() {
	uint16_t vrefint = adc_read((adc_dev *)ADC1, 17);
	Serial.print(F("Vref int (1.2v):"));
	Serial.print(vrefint);
	Serial.println();

	uint16_t vtemp = adc_read((adc_dev *)ADC1, 16);
	Serial.print(F("temp sensor:"));
	Serial.print(vtemp);
	Serial.println();

	uint16_t mv = (1200 * vtemp) / vrefint;
	Serial.print(F("mvolt:"));
	Serial.print(mv);
	Serial.println();

	// specs 5.3.19 temp sensor characteristics
	// V 25 deg ~ 1.43v
	// slope 4.3 mv/C
	float temp = (mv - 1430) * 1.0 / 4.3 + 25.0;
	Serial.print(F("temp:"));
	Serial.print(temp);
	Serial.println();
}
results looks like such

Code: Select all

Vref int (1.2v):1496
temp sensor:1831
mvolt:1468
temp:33.84
dht humidity (RH%):81.60
dht temp (C):30.40
Vref int (1.2v):1504
temp sensor:1835
mvolt:1464
temp:32.91
dht humidity (RH%):81.70
dht temp (C):30.40
Vref int (1.2v):1495
temp sensor:1830
mvolt:1468
temp:33.84
dht humidity (RH%):81.70
dht temp (C):30.40
Vref int (1.2v):1494
temp sensor:1830
mvolt:1469
temp:34.07
dht humidity (RH%):81.70
dht temp (C):30.30
i added some codes to read the temperature off the stm32 internal temperature sensor for comparison. they looked quite well ;)
the difference between this vs adafruit's code is that i used a hardware timer TIM1 as my microsecond timer.
i did not use a library here, it is self contained in the sketch.
This is quite possibly portable to STM core as well. the main things used are

Code: Select all

pinMode(dht_data_pin, OUTPUT_OPEN_DRAIN);
pinMode(dht_data_pin, INPUT_PULLUP);
digitalRead();
digitalWrite();
using digitalRead() and digitalWrite() APIs possibly lose several microseconds in terms of the pulse timing measurements.
but fortunately it works quite well.
and the hardware timer declaration and interrupt (which is used to check timeout), the declarations would likely look a little different.
i'd likely try doing a STM core based sketch at a different sitting.
note that adafruit's library is more complete and has more features e.g. F / C conversion and heat index computation.
i've a feeling Adafruit's library probably works just as well except that Adafruit used a variable counting loop instead as hardware timer is mcu dependent.
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: built in pull up resistor, DHT11, DHT22

Post by fpiSTM »

Fine!
FYI internal ADC channel are available thanks analogRead:
https://github.com/stm32duino/wiki/wiki ... l-channels
Post Reply

Return to “General discussion”