[SOLVED] Polling pin at 13_us rate ?

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
pidou46
Posts: 80
Joined: Sat May 28, 2016 7:01 pm

[SOLVED] Polling pin at 13_us rate ?

Post by pidou46 » Tue Jul 28, 2020 3:24 pm

Hi,

I'm willing to read data from Chinese digital dial gauge.

This have been successfully been done with arduino microcontroller.

Here are some references:
https://www.davidpilling.com/wiki/index.php/DialGauge
http://www.shumatech.com/support/chinese_scales.htm
https://web.archive.org/web/20180730194 ... n-arduino/

On my side I would like to do it with esp32 and micropython.

The communication protocol is based on:
- a clock line : ticking at 77Hz to 90Hz depending on exact device used
- a data line : bits are read synchronically with clock line

Is there a way to poll a pin at this rate (13_us) ?

Either pcnt or rmt devices from esp32 would be a good way to do it but they are not supported yet.
Last edited by pidou46 on Wed Jul 29, 2020 1:56 pm, edited 1 time in total.
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

User avatar
jimmo
Posts: 2215
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Polling pin at 13_us rate ?

Post by jimmo » Tue Jul 28, 2020 11:54 pm

Is it 77 Hz or kHz -- if it's only Hz then its 13ms, which might be fine to just poll.

Sounds like what you want is SPI peripheral mode, but unfortunately I don't think that's supported on ESP32 MicroPython? RMT receive would also be useful.

User avatar
pythoncoder
Posts: 4914
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Polling pin at 13_us rate ?

Post by pythoncoder » Wed Jul 29, 2020 5:28 am

The rates on those web references vary. The dial gauge ref shows 5 clocks in a 2ms period i.e. 400μs interval which should be manageable. For the faster devices I'd recommend a Pyboard (V1.1 or any D series).
Peter Hinch

pidou46
Posts: 80
Joined: Sat May 28, 2016 7:01 pm

Re: Polling pin at 13_us rate ?

Post by pidou46 » Wed Jul 29, 2020 6:47 am

Thanks for your answers,

I've made a typo, the clock is rated at 13_us (77_kHz)

But it's quite different from one device to another.

I've made some test to check if I would be able to manage the dial gauge case (400_us)

Code: Select all

from machine import Pin
import time

pin=Pin(12)

while True:
    pin.value()
    print(time.ticks_us())
result:

Code: Select all

92386809
92387675
92388534
92389400
92390259
92391125
92391984
92392857
92393709
92394575
So about 860_us, quite disappointing...
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

pidou46
Posts: 80
Joined: Sat May 28, 2016 7:01 pm

Re: Polling pin at 13_us rate ?

Post by pidou46 » Wed Jul 29, 2020 7:15 am

pcnt support would help a lot in this case.

There have been some attempt to implement it, but what I have understand is that it's not wanted to add it to the firmware like it have been done with RMT to avoid bloating it.
https://github.com/micropython/micropython/pull/5496

On an other hand, it have been some effort to find a mechanism to call platform-dependent functions but it stall (the PR is closed)
https://github.com/micropython/micropython/pull/5653

Does I understand it well ? maybe I could rise an issue on github, but I don't want to beat a dead horse.
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

Online
User avatar
Roberthh
Posts: 2438
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Polling pin at 13_us rate ?

Post by Roberthh » Wed Jul 29, 2020 7:20 am

In your example printing 8 digits + CR + NL at 115200 baud takes about 860 µs (100 bits / 115200 bits/s).

pidou46
Posts: 80
Joined: Sat May 28, 2016 7:01 pm

Re: Polling pin at 13_us rate ?

Post by pidou46 » Wed Jul 29, 2020 9:13 am

good point Robethh !

With a modified version of the test script:

Code: Select all

from machine import Pin
import time

data=[]
pin=Pin(12)

for _ in range(10):
    #time.sleep_us(1500)
    pin.value()
    data.append(time.ticks_us())
    
print(data)
I get:

Code: Select all

[code][395274683, 395274763, 395274800, 395274837, 395274873, 395275040, 395275077, 395275113, 395275150, 395275232]
[/code]

This gives between 36 and 167_us

So as pythoncoder have stated I may be able to manage 400us signal ?

Disabling IRQ would help to get more stable result ?

Now I've to order a dial gauge and try.

Still, PCNT would be a nice addition and would allow to read from several devices...
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

pidou46
Posts: 80
Joined: Sat May 28, 2016 7:01 pm

Re: Polling pin at 13_us rate ?

Post by pidou46 » Wed Jul 29, 2020 9:29 am

I've tried to disable IRQ:

Code: Select all

from machine import Pin
import machine
import time

data=[]
pin=Pin(12)

state=machine.disable_irq()
for _ in range(10):
    #time.sleep_us(1500)
    pin.value()
    data.append(time.ticks_us())
machine.enable_irq(state)
print(data)
It doesn't really help, I get result from 29 to 158_us

I have tried to disable the garbage collector, but it doesn't help much neither

Is there some tricks to get a better result ?
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

Online
User avatar
Roberthh
Posts: 2438
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Polling pin at 13_us rate ?

Post by Roberthh » Wed Jul 29, 2020 10:19 am

- data.append() is slow. Better add to a pre-defined array.
- you might try native or viper code.

Online
User avatar
Roberthh
Posts: 2438
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Polling pin at 13_us rate ?

Post by Roberthh » Wed Jul 29, 2020 10:43 am

So I have a version is is slightly faster, at least from the second sample on. Sampling times are 119µs(first pair) and 7 µs (following pairs) on a non-spiram board and 161 / 20µs on a SPIRAM board.

Edit: Code improved to 138/5µs on spiram board and 119/5 on a non-spiram board.

Code: Select all

from machine import Pin
import machine
import time
from array import array

data=array("l", 10*[0])
pin=Pin(12)

@micropython.viper
def sample(data, p, t):
    state=machine.disable_irq()
    for _ in range(10):
        p()
        data[_]=t()
    machine.enable_irq(state)

def run():
    sample(data, pin,  time.ticks_us)
    for _ in range(9):
        print(data[_ + 1] - data[_])

Post Reply