Skip to content

Expose NINA command handlers for Digital Read and Analog Read #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 23, 2019
Merged

Expose NINA command handlers for Digital Read and Analog Read #80

merged 8 commits into from
Oct 23, 2019

Conversation

anecdata
Copy link
Member

@anecdata anecdata commented Oct 17, 2019

This PR adds two command handlers to ESP32SPI, changing files in the ESP32SPI CircuitPython library corresponding to a PR for adding the two handlers in the NINA firmware. Addresses #76

set_digital_read(pin) is easy: pin in, boolean return.

set_analog_read(pin, atten) takes two parameters, pin and an attenuation constant, and returns a 12-bit-resolution value (0-4095) as an integer in the range 0-65535 (to be consistent with CircuitPython analogio).

Only ADC1 pins are allowed since ADC2 can't be used when Wi-Fi is running. Not all eight of the ADC1 pins can be used. 37 & 38 aren't exposed on Adafruit boards. 36 and 39 may be dedicated to the Hall Effect sensor (needs further investigation whether they can be used independently for arbitrary ADC). 33 is used for ESP32SPI Busy/!Rdy in our NINA builds. That leaves 32 and 34 (A2) for user connections. Also, 35 (A13) is connected to the battery via a voltage divider and will give half the battery voltage.

The ESP32 ADC is 12 bits by default (can potentially be adjusted to 11, 10, or 9). This PR sticks to the 12-bit default.

Test environment

• Adafruit Feather M4 Express with samd51j19
• CircuitPython 5.0.0-alpha.4 on 2019-09-15
• CircuitPython Library Bundle 20191012
• ESP32 Feather, NINA firmware 1.4.0 as base
• ESP32 digital out (21) connected to digital in (12)
• ESP32 pin 32 connected to trim pot to 3.3v
• ESP32 pin 35 internally connected to the battery via a voltage divider
• M4 & ESP32 connected to host via their respective USBs for output

In testing I saw roughly ±5% or so measurement variation between ESP32 analog read values vs. my meter. Possible sources identified: noise from breadboard, jumpers, SPI, etc.; chosen attenuation value; and ADC calibration (or lack thereof), damaged ESP32, bad meter. I tried delays, and also capacitors on the inputs and multi-sampling per Espressif suggestion, to little effect. It does not seem to work well to connect an ESP32 analog output to an ESP32 analog input, so at times I used the M4 to generate test voltages.

The voltage regulator on the ESP32 Feather is the AP2112-3.3, and the Diodes Inc datasheet says the regulator Output Voltage Accuracy is ±1.5% @ 25°C (±100 ppm/°C).

Sample test code

import board
import busio
import time
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogIn, AnalogOut
from adafruit_esp32spi import adafruit_esp32spi

spi = board.SPI()

# Airlift FeatherWing compatible
esp32_cs = DigitalInOut(board.D13)  # M4 Red LED
esp32_ready = DigitalInOut(board.D11)
esp32_reset = DigitalInOut(board.D12)
# esp32_gpio0 = DigitalInOut(board.D10)  # optional
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, debug=False)

esp.set_esp_debug(True)  # ESP32 serial debug
# esp._debug = 1  # CircuitPython debug

# ESP32 Digital
esp.set_pin_mode(21, 0x1)  # OUTPUT
esp.set_pin_mode(12, 0x0)  # INPUT

# ESP32 Analog
# esp.set_pin_mode(36, 0x0)  # INPUT ?? Hall Effect Sensor
# esp.set_pin_mode(37, 0x0)  # INPUT NO Not Exposed
# esp.set_pin_mode(38, 0x0)  # INPUT NO Not Exposed
# esp.set_pin_mode(39, 0x0)  # INPUT ?? Hall Effect Sensor
esp.set_pin_mode(32, 0x0)    # INPUT OK
# esp.set_pin_mode(33, 0x0)  # INPUT NO ESP32SPI Busy/!Rdy
# esp.set_pin_mode(34, 0x0)    # INPUT OK (A2)
esp.set_pin_mode(35, 0x0)    # INPUT 1/2 of Battery

# initial digital write value
d_w_val = False

print()
espfw = ''
for _ in esp.firmware_version:
    espfw += "{:c}".format(_)
print("ESP Firmware:", espfw)
print()

while True:

    print('ESP32 DIGITAL:', d_w_val, end=' ? ')
    try:
        esp.set_digital_write(21, d_w_val)
        d_r_val = esp.set_digital_read(12)
        print(d_r_val)
    except RuntimeError as e:
        print('ESP32 RuntimeError', e)
    time.sleep(.1)

    print()

    print('ESP32 ANALOG:')

    try:
        r32 = esp.set_analog_read(32)
        print(' ESP 32 READ: {:5d} {} {:1.2f}v'.format(r32, hex(r32), (r32+0.5)*3.3/65536))
    except RuntimeError as e:
        print('ESP32 RuntimeError', e)
    time.sleep(.1)

    try:
        r35 = esp.set_analog_read(35)
        print(' ESP 35 READ: {:5d} {} {:1.2f}v  BAT'.format(r35, hex(r35), 2*(r35+0.5)*3.3/65536))
    except RuntimeError as e:
        print('ESP32 RuntimeError', e)
    time.sleep(.1)

    print()

    # new digital value
    d_w_val = not d_w_val

    time.sleep(5)

Sample test results (annotated)

The CircuitPython decimal and hex values displayed will be 16 times the values shown on the ESP32 debug output due to the 16-bit value range (0-65535) vs. 12-bit value range (0-4095) difference.

DIGITAL

Digital write pin 21 = False (0)

.8COMMAND: e0 51 02 01 15 01 00 ee
RESPONSE: e0 d1 01 01 01 ee

Digital read pin 12 = False (0)

.8COMMAND: e0 53 01 01 0c ee 00 ee
RESPONSE: e0 d3 01 01 00 ee

ANALOG

Analog read pin 32 = 
[bytearray(b'\xae\x06\x00\x00')] (1710,) 1710 27360
 ESP 32 READ:   27360 0x6ae0 1.38v (vs. meter: 1.49v)

.8COMMAND: e0 54 02 01 20 01 03 ee
RESPONSE: e0 d4 01 04 ae 06 00 00 ee

Analog read pin 35 = 
[bytearray(b'\x83\t\x00\x00')] (2435,) 2435 38960
 ESP 35 READ:   38960 0x9830 3.92v  BAT (vs. meter: 4.17v)

.8COMMAND: e0 54 02 01 23 01 03 ee
RESPONSE: e0 d4 01 04 83 09 00 00 ee

Attenuation

The attenuation constant is one of four, from 0dB (Espressif default) to 11dB (our default). 11dB was chosen as CircuitPython default since it will allow the fullest range of analog read voltage inputs (I tested also at 0dB and it didn't seem to make a difference in measurement variation):
"11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V"*

*At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage.

Espressif also notes, "For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges: ...11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV"

Calibration

Automatically measuring Vref requires Wi-Fi to be off (uses ADC2), so this isn't practical in our application, and trying to pass in a user-supplied Vref will not work (I tried) on chips newer than start of 2018 due to built-in values in eFuse taking precedence. I've added the basic characterization code, which will use eFuse values or 1100mV default if no eFuse. Adding the characterization code didn't seem to make a difference in measurement variation.

Reference
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html#

cc: @brentru

@anecdata anecdata mentioned this pull request Oct 17, 2019
@brentru brentru requested review from brentru and a team October 17, 2019 13:04
Copy link
Member

@brentru brentru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

req'ing some small modifications

@brentru brentru requested a review from a team October 17, 2019 13:52
@brentru
Copy link
Member

brentru commented Oct 17, 2019

@anecdata Those pins aren't exposed on the ESP32 AirLift FeatherWing, did you solder directly to the pads? Could you attach a pic. of your test setup.

@anecdata
Copy link
Member Author

anecdata commented Oct 17, 2019

These features will not work on Airlift FeatherWing, Airlift Breakout, Bitsy Airlift add-on, or all-in-ones without surgery. They're easiest on a standalone full-pinout ESP32 like the ESP32 Feather (see photo below) or the ESP32 Huzzah Breakout (or probably the TinyPICO too).

ESP32SPI pins now available for input and output: https://gist.github.com/anecdata/80aa1b95933c0d37828c0c177f229d73

Main test rig:
Screen Shot 2019-10-17 at 11 36 24 AM
( there are 15 CP & Arduino devices plugged in right now, USB gets confusing ;-) )

@brentru
Copy link
Member

brentru commented Oct 23, 2019

Released nina-fw 1.5.0 (https://github.com/adafruit/nina-fw/releases/tag/1.5.0), merging this PR in so CircuitPythonistas can start readin'!

Thanks for the work on this @anecdata.

@brentru brentru merged commit c68c642 into adafruit:master Oct 23, 2019
@anecdata anecdata deleted the Kraken_II branch October 23, 2019 18:07
adafruit-adabot added a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Oct 23, 2019
Updating https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI to 3.1.0 from 3.0.2:
  > Merge pull request adafruit/Adafruit_CircuitPython_ESP32SPI#80 from anecdata/Kraken_II
  > Merge pull request adafruit/Adafruit_CircuitPython_ESP32SPI#82 from adafruit/dherrada-patch-1
  > Merge pull request adafruit/Adafruit_CircuitPython_ESP32SPI#81 from adafruit/dherrada-patch-1

Updating https://github.com/adafruit/Adafruit_CircuitPython_ST7789 to 1.2.0 from 1.1.3:
  > Merge pull request adafruit/Adafruit_CircuitPython_ST7789#12 from makermelissa/master
  > Merge pull request adafruit/Adafruit_CircuitPython_ST7789#11 from adafruit/dherrada-patch-1
@anecdata
Copy link
Member Author

anecdata commented Oct 31, 2019

Tested digital & analog Read on TinyPICO + ItsyBitsy M4, and updated available GPIO pins for TinyPICO at https://gist.github.com/anecdata/80aa1b95933c0d37828c0c177f229d73
esp32spi ib+tp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants