LOPY HC-SR04 Adaptation
I'm trying to adapt the HC-SR04 library to Lopy but for some reason it just get stuck when reading the Echo pin like never seeing the Pulse
the code is based on micropython lib
import machine from machine import Timer # Pin configuration. class Ultrasonic: def __init__(self, tPin, ePin): self.triggerPin = tPin self.echoPin = ePin # Init trigger pin (out) self.trigger = machine.Pin(self.triggerPin) self.trigger.init(machine.Pin.OUT) self.trigger.value(False) # Init echo pin (in) self.echo = machine.Pin(self.echoPin) self.echo.init(machine.Pin.IN) def distance_in_inches(self): return (self.distance_in_cm() * 0.3937) def distance_in_cm(self): start = 0 end = 0 # Create a microseconds counter. micros = Timer.Chrono() micros.reset() # Send a 10us pulse. self.trigger.value(True) Timer.sleep_us(10) self.trigger.value(False) # Wait 'till whe pulse starts. while self.echo.value() == 0: start = micros.read_us() # Wait 'till the pulse is gone. while self.echo.value() == 1: end = micros.read_us() # Deinit the microseconds counter micros.stop() # Calc the duration of the recieved pulse, divide the result by # 2 (round-trip) and divide it by 29 (the speed of sound is # 340 m/s and that is 29 us/cm). dist_in_cm = ((end - start) / 2) / 29 return dist_in_cm
from machine import Pin import time import Ultrasonic sensor1_trigPin = "P20" sensor1_echoPin = "P19" sensor1=Ultrasonic.Ultrasonic(sensor1_trigPin, sensor1_echoPin) distance1 = sensor1.distance_in_cm()
@robert-hh Pick it apart :).
@papasmurph Yes. I looked into an older data sheet. According to this one, there are variants with embedded flash, internally connected to the SPI controller. So timingwise it behaves like external flash.
The model with the number ESP32-D2WD has 16 MBit embedded flash. D/K which one is in the pycom devices. Probably the ones w/o internal flash.
@robert-hh The datasheet at https://espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf is not very clear about how Flash is addressed, but there's some Flash.
@papasmurph There is no internal flash in the esp32. The external flash is partiallyx memory-mapped, so it looks like internal memory.
@robert-hh I thought at least internal Flash was directly addressed. I'm aware external Flash is not. Anyway, I made an implementation using this sensor that works rather well, but not with the precision/stability of the Arduino implementation. I can provide the source if anyone's interested.
@papasmurph This is a software problem, but somewhere deep buried into the esp-idf. The largest problem is caching of code in flash. The esp cannot execude code from flash. If a section of code is requested, which is not cached, this has to be tranferred into RAM. That causes a latency of typically 300 µs. And as far as I have been told, there is no mechanism to make some code areas sticky. Even if the python scipts themselves are located in RAM, the runtime engine is in flash, as well as other firmware sections. To some extend you could still determine pulse lengths. Look in the board for the DHT11 driver. That's on the level of this Arduino code.
@papasmurph The principle used in the Arduino is quite different. Can the ESP32 (via Python) support the same as pulseIn? I couldn't see any such link between ports and timers.
Somewhat truncated code:
// Port configuration pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); // Trigger distance sensor (Trig) digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Read distance pulse (Echo) duration = (float)pulseIn(echoPin, HIGH) / Million;
@robert-hh But at least it looks like a software problem (potentially solvable via a different approach to handling queueing of events?).
@papasmurph About hardware interrupt latency with this MP port, look here: https://forum.pycom.io/topic/936/pin-interrupt-latency
@slagter Late response, but anyway: A code example I found for Arduino uses a hardware triggered timer to get the time between trig and echo. Can't the ESP32 do the same thing?
@gas The other problem is reliable timing, which does not exist on the esp32 or esp8266. At and between every Python statement you may have an extra ~300µs delay due to cache misses.
Couple of things that need fixing:
- You have to start the Chrono. Insert a "micros.start()" in the Ultrasonic class, just after micros.reset()
- Define the pull mode as part of the init of the Pin In and Pin Out: self.trigger.init(machine.Pin.OUT, None)
- I would define the pins in the start as: sensor_trigPin = Pin("G16")