adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.02k stars 1.19k forks source link

OneWire not working in CP 3.0.0 rc0 #964

Closed caternuson closed 6 years ago

caternuson commented 6 years ago

REF: https://forums.adafruit.com/viewtopic.php?f=60&t=137405

D5 is a special pin on the Itsy, but even using D7 for testing indicates something is not working:

CP 2.3.1

Adafruit CircuitPython 2.3.1 on 2018-05-07; Adafruit Itsy Bitsy M0 Express with samd21g18
>>> import board, busio
>>> ow = busio.OneWire(board.D7)
>>> ow.write_bit(1)

cp2 3 1_write_bit

CP 3.0.0 rc0

Adafruit CircuitPython 3.0.0-rc.0 on 2018-06-18; Adafruit ItsyBitsy M0 Express with samd21g18
>>> import board, busio
>>> ow = busio.OneWire(board.D7)
>>> ow.write_bit(1)

cp3 0 0rc0_write_bit

sommersoft commented 6 years ago

I think it is beyond OneWire. I ran this test for DigitalInOut, since that is all that shared-modules/bitbangio/OneWire is doing:

Adafruit CircuitPython 3.0.0-alpha.1-737-gd1b3c3c-dirty on 2018-06-22; Metro M4 Express with samd51j19
>>> import board, digitalio
>>> d = digitalio.DigitalInOut(board.D11)
>>> d.switch_to_output(True, digitalio.DriveMode.PUSH_PULL)
>>> d.switch_to_input()
>>>

Same flatline result: digitalinou_switch_to_input_failure

The 3.x change in DigitalInOut that I have a hunch is causing this, is a switch to using hri_port_set_PINCFG_DRVSTR_bit to set the pin config in switch_to_output. Then for whatever reason, gpio_set_function in switch_to_input isn't overriding the pin config.

I'm going to dip into the ASF4/datasheet to see if any documentation supports this.

NOTE: while i'm on a dirty, oldish 3.x, I verified it includes the same digitalio code as RC0. also, for whatever reason, my tags never update anyway. this is post 3.alpha-6 firmware. 🤷‍♂️

dhalbert commented 6 years ago

The DRVSTR bit setting thing was added about eight months ago, but the code was wrong for PBxx pins initially. It worked OK for PAxx pins. That was fixed 2 months ago.

btw if you want to update your tags, you can do git pull --tags or git fetch --tags.

dhalbert commented 6 years ago

@sommersoft How did you decide to do digitalio.DriveMode.PUSH_PULL and give no args to switch_to_input()?

shared-module/bitbangio/OneWire.c` does this:

void shared_module_bitbangio_onewire_write_bit(bitbangio_onewire_obj_t* self,
        bool bit) {
    common_hal_mcu_disable_interrupts();
    common_hal_digitalio_digitalinout_switch_to_output(&self->pin, false, DRIVE_MODE_OPEN_DRAIN);
    common_hal_mcu_delay_us(bit? 6 : 60);
    common_hal_digitalio_digitalinout_switch_to_input(&self->pin, PULL_NONE);
    common_hal_mcu_delay_us(bit? 64 : 10);
    common_hal_mcu_enable_interrupts();
}

which is more like


d = digitalio.DigitalInOut(board.D11)
d.switch_to_output(False, digitalio.DriveMode.OPEN_DRAIN)
# sleep 6 or 60 usecs
d.switch_to_input(digitalio.Pull.NONE)
# sleep 64 or 10 usecs
sommersoft commented 6 years ago

My initial test with OPEN_DRAIN didn't pull the pin high, since I'm using the pin directly. If I were using a OW device, the slave would be pulling it high; at least that is my understanding. So, I forced it with PUSH_PULL.

The no arg switch_to_input is because it defaults to PULL_NONE anyway.

I was really just trying to force the behavior of switching between modes, and being able to capture it with the Saleae.

sommersoft commented 6 years ago

Yep! That was my bad. Using switch_to_input(pull=Pull.DOWN) fixes my test. Disregard my rambling... 😄

dhalbert commented 6 years ago

I spent time on this and have OneWire working, if a bit erratically, with a DS18B20 temp sensor. Two issues:

  1. common_hal_digitalinout_set_pull() worked differently in 2.x vs. 3.0. In 2.x it always sets the port direction to input. In 3.0 it just set the pull-up/down/none bits, without forcing the direction to input. common_hal_digitalio_digitalinout_switch_to_input() was depending on the direction change, because it wasn't doing it itself explicitly. (Thanks to @sommersoft for looking around here, which caused me to look at it all carefully.)
  2. The timing is flaky, because it depends on short microsecond waits. In shared_module_bitbangio_onewire_read_bit() there is a delay of 6us. There was already a comment that it should be 9 but 9 didn't work. I just commented out the delay completely and reads of the sensor work most of the time, though sometimes I get a CRC error.

Given the strict timing, perhaps using pulseio would be better, if possible.

tannewt commented 6 years ago

Thanks everyone!

caternuson commented 6 years ago

Yep. Looks good:

Adafruit CircuitPython 3.0.0-rc.0-13-gf1248dc on 2018-06-29; Adafruit ItsyBitsy M0 Express with samd21g18
>>> import board, busio
>>> ow = busio.OneWire(board.D7)
>>> ow.write_bit(1)

screenshot

DS18B20 checks out:

Adafruit CircuitPython 3.0.0-rc.0-13-gf1248dc on 2018-06-29; Adafruit ItsyBitsy M0 Express with samd21g18
>>> import board
>>> from adafruit_onewire.bus import OneWireBus
>>> import adafruit_ds18x20
>>> ow_bus = OneWireBus(board.D7)
>>> devices = ow_bus.scan()
>>> ds18b20 = adafruit_ds18x20.DS18X20(ow_bus, devices[0])
>>> ds18b20.temperature
24.5

DS2413 checks out:

Adafruit CircuitPython 3.0.0-rc.0-13-gf1248dc on 2018-06-29; Adafruit ItsyBitsy M0 Express with samd21g18
>>> import board
>>> from adafruit_onewire.bus import OneWireBus
>>> import adafruit_ds2413
>>> ow_bus = OneWireBus(board.D7)
>>> ds = adafruit_ds2413.DS2413(ow_bus, ow_bus.scan()[0])
>>> ds.IOA.direction = adafruit_ds2413.INPUT
>>> ds.IOA.value
True
>>> ds.IOA.value
False