Skip to content

Fix GPIO16 Board Reset; Updated Usage#780

Merged
tannewt merged 5 commits intoadafruit:masterfrom
sommersoft:esp8266_gpio16
Apr 30, 2018
Merged

Fix GPIO16 Board Reset; Updated Usage#780
tannewt merged 5 commits intoadafruit:masterfrom
sommersoft:esp8266_gpio16

Conversation

@sommersoft
Copy link

See Issue #753.

No longer causes a reset when creating the digitalio object. Also updated some of the usage, since a few functions only included normal gpio functions (gpio16 is controlled through RTC register, not GPIO register). Tested both simple output and input usage; both work as expected.

Note to Reviewer(s): PLEASE pay extra attention to common_hal_digitalio_digitalinout_set_value. I'm not totally sure I implemented the conditionals correct with respect to open_drain and else.

@jerryneedell
Copy link
Collaborator

jerryneedell commented Apr 26, 2018

FYI - tested with OLED Featherwing on Feather Huzzah ESP8266 and button B works!

>>> import board
>>> import digitalio
>>> button = digitalio.DigitalInOut(board.GPIO16)
True
>>> button.value    PRESSED BUTTON HERE
False
>>> 

@tannewt tannewt added this to the 3.0 milestone Apr 26, 2018
Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

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

Awesome work on this! Just a few sanity checks

WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); // mux configuration for XPD_DCDC and rtc_gpio0 connection
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE, READ_PERI_REG(RTC_GPIO_ENABLE) & ~1); //out disable
gpio16_in_use = true;
Copy link
Member

Choose a reason for hiding this comment

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

Mind factoring gpio16_in_use related code into claim_pin and reset_pin like the SAMD port does? https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/common-hal/microcontroller/Pin.c#L99

Copy link
Author

Choose a reason for hiding this comment

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

I can certainly try...

Copy link
Author

Choose a reason for hiding this comment

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

Should I also roll adc_in_use into this? Hardly takes any additional effort.

void common_hal_digitalio_digitalinout_set_value(
digitalio_digitalinout_obj_t* self, bool value) {
if (self->pin->gpio_number == 16) {
if (self->open_drain) {
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be self->open_drain && value since you want to be outputting a zero in open drain.

Copy link
Author

Choose a reason for hiding this comment

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

I originally had it that way, but I wasn't sure how/if open_drain && !value would get handled. My theoretical line of thinking was related to set_drive_mode using set_value. Does it need to throw an exception in that case?

Copy link
Author

Choose a reason for hiding this comment

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

So, belay that. I must have confused myself on that. set_drive_mode will only call set_value if the current value is true. I'll update the condition.

if (self->open_drain && ((*PIN_DIR) & pin_mask) == 0) {
return true;
if (self->pin->gpio_number == 16) {
return READ_PERI_REG(RTC_GPIO_OUT) & 1;
Copy link
Member

Choose a reason for hiding this comment

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

Does this handle open drain 1 correctly?

Copy link
Author

Choose a reason for hiding this comment

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

With fixing open_drain above, I see why you're asking. And no, it won't, since RTC_GPIO_OUT will return 0.

"Pin does not support pull."));
// PULL_DOWN is the only hardware pull direction available on GPIO16
// since we don't support pull down, just return without attempting
// to set pull (which won't work anyway).
Copy link
Member

Choose a reason for hiding this comment

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

Why not throw the exception?

Copy link
Author

Choose a reason for hiding this comment

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

I can add if (pull != PULL_NONE) and throw the exception. I just wanted to remove the confusion when swith_to_input called this, and tossed the exception out even though the pin has been switched to input by the time this is called.

@sommersoft
Copy link
Author

Open drain update: I think I have the get_value reporting correctly. Tested with a LED hooked up with external pull up:

3V -> LED+  |  LED- -> pull up -> GPIO16

gpio.value = false = LED On
gpio.value = true = LED Off

@jerryneedell
Copy link
Collaborator

jerryneedell commented Apr 27, 2018

@sommersoft I tried this on GPIO16 but I don't get any response from the LED if I use OPEN_DRAIN. with PUSH_PULL True is ON , False is OFF.

>>> led.drive_mode=digitalio.DriveMode.PUSH_PULL
>>> led.value=False     LED OFF
>>> led.value=True       LED ON
>>> led.value=False      LED OFF
>>> led.drive_mode=digitalio.DriveMode.OPEN_DRAIN
>>> led.value=False     LED OFF
>>> led.value=True       LED OFF
>>> led.drive_mode=digitalio.DriveMode.PUSH_PULL
>>> led.value=False       LED OFF
>>> 

DO I need to do something differently?

Here is the completes setup

Adafruit CircuitPython 3.0.0-alpha.6-4-g4e1f7d4-dirty on 2018-04-27; ESP module with ESP8266
>>>
>>>
>>> import board,digitalio
>>> led=digitalio.DigitalInOut(board.GPIO16)
>>> led.switch_to_output()
>>> led.drive_mode
digitalio.DriveMode.PUSH_PULL
>>> led.value=True       LED ON
>>> led.value=False      LED OFF
>>> led.drive_mode=digitalio.DriveMode.OPEN_DRAIN
>>> led.value=True        LED OFF
>>> led.value=False       LED OFF
>>> led.drive_mode=digitalio.DriveMode.PUSH_PULL
>>> led.value=True        LED ON
>>> led.value=False      LED OFF

@jerryneedell
Copy link
Collaborator

jerryneedell commented Apr 27, 2018

Doh! Nevermind -- connencting 220 ohm resistor to +3 and cathode to GPIO16 works as you described.

led.value=True LED OFF
led.value=False LED ON

for both PUSH_PULL and OPEN DRAIN

if (self->open_drain && ((*PIN_DIR) & pin_mask) == 0) {
return true;
if (self->pin->gpio_number == 16) {
if (self->open_drain && (READ_PERI_REG(RTC_GPIO_OUT) | READ_PERI_REG(RTC_GPIO_ENABLE)) == 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Mind removing the bitwise OR in favor of boolean logic? That'll make it easier to read.

WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input
WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1)); // out=0
Copy link
Member

Choose a reason for hiding this comment

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

Can OUT be 1? It'd simplify reading the value.

This block can be indented one less too.

Copy link
Author

Choose a reason for hiding this comment

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

How did that extra indenture sneak in there?... 🤷‍♂️ 😄

Can OUT be 1? It'd simplify reading the value.

I'm not sure, but I can try it. I want to check if it's used to set the pull mode for input, though. Could easily assume that it is config'd in RTC_GPIO_CONF, but assumptions ya know. I'm rolling through the Arduino esp8266 repo to see how they implemented pull down.

Copy link
Author

Choose a reason for hiding this comment

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

After reading through Arduino's handling of GPIO16, I'm confident they use one of the CONF registers. Couldn't find where the calls go from pinMode, but they are definitely shifting values in a full byte. I just tested this with setting OUT & 1 and the same LED test, and didn't get any different results. Also tested switching to 'PUSH_PULL'; 5x5. Will update get_value accordingly.

@jepler
Copy link

jepler commented Apr 30, 2018

I also tested at 3.0.0-alpha.6-5-g396e4ffc3 and "GPIO16" now works for me as an input. Thanks @sommersoft !

Besides testing as an input, I also tested this:

>>> a = digitalio.DigitalInOut(board.GPIO16)
>>> b = digitalio.DigitalInOut(board.GPIO16)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Pin XPD_DCDC in use```

This is clearly what the code intends but I have to admit that I'm not sure why.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

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

Awesome! Thank you so much!

@tannewt tannewt merged commit 6855541 into adafruit:master Apr 30, 2018
@tannewt tannewt mentioned this pull request Apr 30, 2018
@sommersoft sommersoft deleted the esp8266_gpio16 branch July 29, 2018 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants