I did some work back in 2021 (5 years ago!) on a NanoPi board which uses the Allwinner H3. A quick look at dallas.c from this effort shows me that I didn't get too far and I am just going to start over.
A central concern is the nature of the GPIO. A place to start is the H5 TRM. On page 291 a section starts entitle "Port Controller (CPUx-PORT). This is the GPIO. A configure register supplies 3 bits per port bit. We can select Input or Output here, or special functions. We have a data register where we can read the pin state when the port is configured as an input. We have a "multi-driving" register where we can pick level 0,1,2, or 3 ad the drive level, whatever the heck that does. Finally we have a "pull" control register where we can enable pullup, pulldown, both, or neither.
What API do I provide in my gpio.c?
gpio_config ( bit, val) sets the config register field (static) gpio_out_init ( bit ) - configures as output gpio_dir_out ( bit ) - same as above gpio_in_init ( bit ) - configures as input gpio_dir_in ( bit ) - same as above gpio_output ( gpio, pin, val ) - write to data register (static) gpio_clear_bit ( bit ) - clear a bit gpio_set_bit ( bit ) - set a bit gpio_input ( gpio, pin ) - read from data register (static) gpio_read_bit ( bit ) - read a bit gpio_pull ( bit, val ) - set pullup configuration (static)I provide no ability to change the "drive" register.
I just added this routine:
void
gpio_one_wire ( int bit )
{
gpio_config ( bit, GPIO_INPUT );
gpio_clear_bit ( bit );
gpio_pull ( bit, GPIO_PULL_DISABLE );
}
What I plan to do to "emulate" an open drain drive is to leave the port
in input mode when I want to write a 1. This way the driver is high
impedance, and the external pullup will provide a "1".
The write a 0, I will put the port into output mode, which will enable
the driver and the "0" lurking in the data register will drive the
bus low.
This gets me started coding up dallas.c -- to start I just set up a scope loop like this:
for ( ;; ) {
gpio_dir_out ( dallas_pin );
delay_us ( 10 );
gpio_dir_in ( dallas_pin );
delay_us ( 10 );
}
The main point of this is to check the timing in delay_us(),
but this turns up some surprises, which is the topic of the
next section.
Tom's software pages / tom@mmto.org