135 lines
5.0 KiB
C
135 lines
5.0 KiB
C
/**
|
|
* Copyright (c) 2023 mjcross
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/gpio.h"
|
|
#include "hardware/pio.h"
|
|
|
|
#include "onewire_library.h"
|
|
|
|
|
|
// Create a driver instance and populate the provided OW structure.
|
|
// Returns: True on success.
|
|
// ow: A pointer to a blank OW structure to hold the driver parameters.
|
|
// pio: The PIO hardware instance to use.
|
|
// offset: The location of the onewire program in the PIO shared address space.
|
|
// gpio: The pin to use for the bus (NB: see the README).
|
|
bool ow_init (OW *ow, PIO pio, uint offset, uint gpio) {
|
|
int sm = pio_claim_unused_sm (pio, false);
|
|
if (sm == -1) {
|
|
return false;
|
|
}
|
|
gpio_init (gpio); // enable the gpio and clear any output value
|
|
pio_gpio_init (pio, gpio); // set the function to PIO output
|
|
ow->gpio = gpio;
|
|
ow->pio = pio;
|
|
ow->offset = offset;
|
|
ow->sm = (uint)sm;
|
|
ow->jmp_reset = onewire_reset_instr (ow->offset); // assemble the bus reset instruction
|
|
onewire_sm_init (ow->pio, ow->sm, ow->offset, ow->gpio, 8); // set 8 bits per word
|
|
return true;
|
|
}
|
|
|
|
|
|
// Send a binary word on the bus (LSB first).
|
|
// ow: A pointer to an OW driver struct.
|
|
// data: The word to be sent.
|
|
void ow_send (OW *ow, uint data) {
|
|
pio_sm_put_blocking (ow->pio, ow->sm, (uint32_t)data);
|
|
pio_sm_get_blocking (ow->pio, ow->sm); // discard the response
|
|
}
|
|
|
|
|
|
// Read a binary word from the bus.
|
|
// Returns: the word read (LSB first).
|
|
// ow: pointer to an OW driver struct
|
|
uint8_t ow_read (OW *ow) {
|
|
pio_sm_put_blocking (ow->pio, ow->sm, 0xff); // generate read slots
|
|
return (uint8_t)(pio_sm_get_blocking (ow->pio, ow->sm) >> 24); // shift response into bits 0..7
|
|
}
|
|
|
|
|
|
// Reset the bus and detect any connected slaves.
|
|
// Returns: true if any slaves responded.
|
|
// ow: pointer to an OW driver struct
|
|
bool ow_reset (OW *ow) {
|
|
pio_sm_exec_wait_blocking (ow->pio, ow->sm, ow->jmp_reset);
|
|
if ((pio_sm_get_blocking (ow->pio, ow->sm) & 1) == 0) { // apply pin mask (see pio program)
|
|
return true; // a slave pulled the bus low
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// Find ROM codes (64-bit hardware addresses) of all connected devices.
|
|
// See https://www.analog.com/en/app-notes/1wire-search-algorithm.html
|
|
// Returns: the number of devices found (up to maxdevs) or -1 if an error occurrred.
|
|
// ow: pointer to an OW driver struct
|
|
// romcodes: location at which store the addresses (NULL means don't store)
|
|
// maxdevs: maximum number of devices to find (0 means no limit)
|
|
// command: 1-Wire search command (e.g. OW_SEARCHROM or OW_ALARM_SEARCH)
|
|
int ow_romsearch (OW *ow, uint64_t *romcodes, int maxdevs, uint command) {
|
|
int index;
|
|
uint64_t romcode = 0ull;
|
|
int branch_point;
|
|
int next_branch_point = -1;
|
|
int num_found = 0;
|
|
bool finished = false;
|
|
|
|
onewire_sm_init (ow->pio, ow->sm, ow->offset, ow->gpio, 1); // set driver to 1-bit mode
|
|
|
|
while (finished == false && (maxdevs == 0 || num_found < maxdevs )) {
|
|
finished = true;
|
|
branch_point = next_branch_point;
|
|
if (ow_reset (ow) == false) {
|
|
num_found = 0; // no slaves present
|
|
finished = true;
|
|
break;
|
|
}
|
|
for (int i = 0; i < 8; i += 1) { // send search command as single bits
|
|
ow_send (ow, command >> i);
|
|
}
|
|
for (index = 0; index < 64; index += 1) { // determine romcode bits 0..63 (see ref)
|
|
uint a = ow_read (ow);
|
|
uint b = ow_read (ow);
|
|
if (a == 0 && b == 0) { // (a, b) = (0, 0)
|
|
if (index == branch_point) {
|
|
ow_send (ow, 1);
|
|
romcode |= (1ull << index);
|
|
} else {
|
|
if (index > branch_point || (romcode & (1ull << index)) == 0) {
|
|
ow_send(ow, 0);
|
|
finished = false;
|
|
romcode &= ~(1ull << index);
|
|
next_branch_point = index;
|
|
} else { // index < branch_point or romcode[index] = 1
|
|
ow_send (ow, 1);
|
|
}
|
|
}
|
|
} else if (a != 0 && b != 0) { // (a, b) = (1, 1) error (e.g. device disconnected)
|
|
num_found = -2; // function will return -1
|
|
finished = true;
|
|
break; // terminate for loop
|
|
} else {
|
|
if (a == 0) { // (a, b) = (0, 1) or (1, 0)
|
|
ow_send (ow, 0);
|
|
romcode &= ~(1ull << index);
|
|
} else {
|
|
ow_send (ow, 1);
|
|
romcode |= (1ull << index);
|
|
}
|
|
}
|
|
} // end of for loop
|
|
|
|
if (romcodes != NULL) {
|
|
romcodes[num_found] = romcode; // store the romcode
|
|
}
|
|
num_found += 1;
|
|
} // end of while loop
|
|
|
|
onewire_sm_init (ow->pio, ow->sm, ow->offset, ow->gpio, 8); // restore 8-bit mode
|
|
return num_found;
|
|
} |