onewire_master.c
Go to the documentation of this file.
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdbool.h> // boolean type
#include <stddef.h> // NULL definition
/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/cm3/nvic.h> // interrupt handler
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/timer.h> // timer library
/* own libraries */
#include "global.h" // help macros
#include "interrupt.h" // runtime interrupt table
#include "onewire_master.h" // own definitions
#define ONEWIRE_MASTER_TIMER 5
#define ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE false
volatile enum {
ONEWIRE_STATE_IDLE,
ONEWIRE_STATE_DONE,
ONEWIRE_STATE_ERROR,
ONEWIRE_STATE_MASTER_RESET,
ONEWIRE_STATE_SLAVE_PRESENCE,
ONEWIRE_STATE_MASTER_WRITE,
ONEWIRE_STATE_MASTER_READ,
ONEWIRE_MAX
} onewire_master_state = ONEWIRE_STATE_IDLE;
static volatile bool slave_presence = false;
static uint8_t* buffer = NULL;
static uint32_t buffer_size = 0;
static volatile uint32_t buffer_bit = 0;
#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
static void (*isr_backup)(void) = NULL;
static bool irq_backup = false;
#endif
#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
static void onewire_master_timer_isr(void)
#else
void TIM_ISR(ONEWIRE_MASTER_TIMER)(void)
#endif
{
if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF)) { // overflow update event happened
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF); // clear flag
switch (onewire_master_state) {
case ONEWIRE_STATE_MASTER_RESET: // reset pulse has been started
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear output compare flag
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC4IE); // enable compare interrupt for presence detection
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // set signal high again for slaves to respond
onewire_master_state = ONEWIRE_STATE_SLAVE_PRESENCE; // set new state
break;
case ONEWIRE_STATE_SLAVE_PRESENCE: // waiting for slave presence but none received
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC4IE); // disable compare interrupt for presence detection
onewire_master_state = ONEWIRE_STATE_DONE; // go to next state
break;
case ONEWIRE_STATE_MASTER_READ: // end of time slot and recovery time for reading bit
case ONEWIRE_STATE_MASTER_WRITE: // end of time slot and recovery time for writing bit
if (buffer_bit<buffer_size) { // check if byte to read/write are remaining
gpio_clear(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal low to start next slot
} else { // all bytes read/written
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC1IE); // disable compare interrupt for master pull low
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable compare interrupt for read/write bit
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // disable compare interrupt for end of slot
onewire_master_state = ONEWIRE_STATE_DONE; // set end state
}
break;
default: // unknown state for this stage
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC1IE); // disable all compare interrupt
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable all compare interrupt
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // disable all compare interrupt
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC4IE); // disable all compare interrupt
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal high (idle state)
onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
}
} else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF)) { // compare event happened for master pull low end for read
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear flag
switch (onewire_master_state) {
case ONEWIRE_STATE_MASTER_READ: // master has to read a bit
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal high to end time slot
break;
default: // unknown state for this stage
break; // let the overflow handle the error if any
}
} else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF)) { // compare event happened for bit sampling/setting
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear flag
switch (onewire_master_state) {
case ONEWIRE_STATE_MASTER_WRITE: // master has to write a bit
if (buffer_bit<buffer_size) { // check if byte to send are remaining
if (buffer[buffer_bit/8]&(1<<(buffer_bit%8))) { // check bit (LSb first)
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // set signal high again to write "1"
}
buffer_bit++; // got to next bit
} else {
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable compare interrupt
onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
}
break;
case ONEWIRE_STATE_MASTER_READ: // master has to read a bit set by slave
if (buffer_bit<buffer_size) { // check if byte to send are remaining
if (gpio_get(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN))) { // check if the slave kept it low
buffer[buffer_bit/8] |= (1<<(buffer_bit%8)); // save bit "1"
} else {
buffer[buffer_bit/8] &= ~(1<<(buffer_bit%8)); // save bit "0"
}
buffer_bit++; // got to next bit
} else {
timer_disable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // disable compare interrupt
onewire_master_state = ONEWIRE_STATE_ERROR; // indicate error
}
break;
default: // unknown state for this stage
break; // let the overflow handle the error if any
}
} else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF)) { // compare event happened for end to time slot
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear flag
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal high to end time slot
} else if (timer_get_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF)) { // compare event happened for slave presence detection
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear flag
if (gpio_get(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN))) { // check is a slave let its presence know by pulling low
slave_presence = false; // remember no slave(s) responded
} else {
slave_presence = true; // remember slave(s) responded
}
} else { // no other interrupt should occur
while (true); // unhandled exception: wait for the watchdog to bite
}
}
void onewire_master_setup(void)
{
// setup GPIO with external interrupt
rcc_periph_clock_enable(RCC_GPIO(ONEWIRE_MASTER_PORT)); // enable clock for GPIO peripheral
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // idle is high (using pull-up resistor)
gpio_set_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_MASTER_PIN)); // normal 1-Wire communication (only using external pull-up resistor)
// setup timer to generate/measure signal timing
rcc_periph_clock_enable(RCC_TIM(ONEWIRE_MASTER_TIMER)); // enable clock for timer peripheral
timer_reset(TIM(ONEWIRE_MASTER_TIMER)); // reset timer state
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to configure it
timer_set_mode(TIM(ONEWIRE_MASTER_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(ONEWIRE_MASTER_TIMER), 1-1); // don't use prescale since this 16 bits timer allows to wait > 480 us used for the reset pulse ( 1/(72E6/1/(2**16))=910us )
// use comparator to time signal (without using the output), starting at slot start
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC1, 1*(rcc_ahb_frequency/1000000)-1); // use compare function to time master pulling low when reading (1 < Tlowr < 15)
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC2, 7*(rcc_ahb_frequency/1000000)-1); // use compare function to read or write 0 or 1 (1 < Trw < 15)
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC3, 62*(rcc_ahb_frequency/1000000)-1); // use compare function to end time slot (60 < Tslot < 120), this will be followed by a recovery time (end of timer)
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC4, (70-10)*(rcc_ahb_frequency/1000000)-1); // use compare function to detect slave presence (15 < Tpdh < 60 + 60 < Tpdl < 240), with hand tuning
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF); // clear update (overflow) flag
timer_update_on_overflow(TIM(ONEWIRE_MASTER_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_UIE); // enable update interrupt for overflow
#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
isr_backup = interrupt_table[NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)]; // backup timer ISR
interrupt_table[NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)] = &onewire_master_timer_isr; // set the 1-wire timer ISR
irq_backup = nvic_get_irq_enabled(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // backup timer IRQ setting
#endif
nvic_enable_irq(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // catch interrupt in service routine
slave_presence = false; // reset state
onewire_master_state = ONEWIRE_STATE_IDLE; // reset state
}
void onewire_master_release(void)
{
// release timer
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer
timer_reset(TIM(ONEWIRE_MASTER_TIMER)); // reset timer state
rcc_periph_clock_disable(RCC_TIM(ONEWIRE_MASTER_TIMER)); // disable clock for timer peripheral
// release GPIO
gpio_set_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(ONEWIRE_MASTER_PIN)); // put back to input floating
// disable timer ISR
#if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
if (!irq_backup) { // don't disable the IRQ if there was already enabled
nvic_disable_irq(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // stop timer IRQ
}
interrupt_table[NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)] = isr_backup; // set back original timer ISR
#else
nvic_disable_irq(NVIC_TIM_IRQ(ONEWIRE_MASTER_TIMER)); // stop timer IRQ
#endif
}
bool onewire_master_reset(void)
{
// prepare timer
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to reconfigure it
timer_set_counter(TIM(ONEWIRE_MASTER_TIMER),0); // reset counter
timer_set_period(TIM(ONEWIRE_MASTER_TIMER), 490*(rcc_ahb_frequency/1000000)-1); // set timeout to > 480 us (480 < Trst)
slave_presence = false; // reset state
onewire_master_state = ONEWIRE_STATE_MASTER_RESET; // set new state
gpio_set_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_MASTER_PIN)); // normal 1-Wire communication (only using external pull-up resistor)
gpio_clear(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal low to start reset (it's not important if it was low in the first place since the reset pulse has no maximum time)
timer_enable_counter(TIM(ONEWIRE_MASTER_TIMER)); // start timer
while (onewire_master_state!=ONEWIRE_STATE_DONE && onewire_master_state!=ONEWIRE_STATE_ERROR) { // wait until reset procedure completed
__WFI(); // go to sleep
}
if (ONEWIRE_STATE_ERROR==onewire_master_state) { // an error occurred
return false;
}
return slave_presence;
}
static bool onewire_master_write(void)
{
buffer_bit = 0; // reset bit index
onewire_master_state = ONEWIRE_STATE_MASTER_WRITE; // set new state
// prepare timer
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to reconfigure it
timer_set_counter(TIM(ONEWIRE_MASTER_TIMER), 0); // reset counter
timer_set_period(TIM(ONEWIRE_MASTER_TIMER), TIM_CCR3(TIM(ONEWIRE_MASTER_TIMER))+2*(rcc_ahb_frequency/1000000)); // set time for new time slot (recovery timer Trec>1, after time slot end )
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear output compare flag
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // enable compare interrupt for bit setting
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear output compare flag
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // enable compare interrupt for end of time slow
// start writing
gpio_set_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_MASTER_PIN)); // normal 1-Wire communication (only using external pull-up resistor)
gpio_clear(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal low to start slot
timer_enable_counter(TIM(ONEWIRE_MASTER_TIMER)); // start timer
while (onewire_master_state!=ONEWIRE_STATE_DONE && onewire_master_state!=ONEWIRE_STATE_ERROR) { // wait until write procedure completed
__WFI(); // go to sleep
}
if (ONEWIRE_STATE_ERROR==onewire_master_state) { // an error occurred
return false;
}
return true;
}
static bool onewire_master_read(void)
{
if (0==buffer_size) { // check input
return false;
}
buffer_bit = 0; // reset bit index
onewire_master_state = ONEWIRE_STATE_MASTER_READ; // set new state
// prepare timer
timer_disable_counter(TIM(ONEWIRE_MASTER_TIMER)); // disable timer to reconfigure it
timer_set_counter(TIM(ONEWIRE_MASTER_TIMER), 0); // reset counter
timer_set_period(TIM(ONEWIRE_MASTER_TIMER), TIM_CCR3(TIM(ONEWIRE_MASTER_TIMER))+2*(rcc_ahb_frequency/1000000)); // set time for new time slot (recovery timer Trec>1, after time slot end )
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear output compare flag
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC1IE); // enable compare interrupt for stop pulling low
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear output compare flag
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC2IE); // enable compare interrupt for bit setting
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear output compare flag
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_CC3IE); // enable compare interrupt for end of time slow
// start reading
gpio_set_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_MASTER_PIN)); // normal 1-Wire communication (only using external pull-up resistor)
gpio_clear(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // pull signal low to start slot
timer_enable_counter(TIM(ONEWIRE_MASTER_TIMER)); // start timer
while (onewire_master_state!=ONEWIRE_STATE_DONE && onewire_master_state!=ONEWIRE_STATE_ERROR) { // wait until read procedure completed
__WFI(); // go to sleep
}
if (ONEWIRE_STATE_ERROR==onewire_master_state) { // an error occurred
return false;
}
return true;
}
uint8_t onewire_master_crc(uint8_t* data, uint32_t length)
{
if (NULL==data || 0==length) { // check input
return 0; // wrong input
}
uint8_t crc = 0x00; // initial value
for (uint8_t i=0; i<length; i++) { // go through every byte
crc ^= data[i]; // XOR byte
for (uint8_t b=0; b<8; b++) { // go through every bit
if (crc&0x01) { // least significant bit is set (we are using the reverse way)
crc = (crc>>1)^0x8C; // // shift to the right (for the next bit) and XOR with (reverse) polynomial
} else {
crc >>= 1; // just shift right (for the next bit)
}
}
}
return crc;
}
bool onewire_master_read_byte(uint8_t* data)
{
if (NULL==data) { // check input
return false; // wrong input
}
// read data
buffer_size = 8; // save number of bits to read (1 byte)
buffer = data; // set the buffer to the data to write
if (!onewire_master_read()) { // read bits from slave
return false; // an error occurred
}
return true;
}
bool onewire_master_write_byte(uint8_t data)
{
// send data byte
buffer_size = 8; // function command is only one byte
buffer = &data; // set the buffer to the function code
if (!onewire_master_write()) { // send command
return false; // an error occurred
}
return true;
}
bool onewire_master_function_read(uint8_t function, uint8_t* data, uint32_t bits)
{
// send function command
if (!onewire_master_write_byte(function)) {
return false; // an error occurred
}
if (NULL==data || 0==bits) { // there is no data to read
return true; // operation completed
}
// read data
buffer_size = bits; // save number of bits to read
buffer = data; // set the buffer to the data to write
if (!onewire_master_read()) { // read bits from slave
return false; // an error occurred
}
return true;
}
bool onewire_master_function_write(uint8_t function, uint8_t* data, uint32_t bits)
{
// send function command
if (!onewire_master_write_byte(function)) {
return false; // an error occurred
}
if (NULL==data || 0==bits) { // there is no data to read
return true; // operation completed
}
// copy data from user buffer
buffer_size = bits; // save number of bits to write
buffer = data; // set the buffer to the data to write
// write data
if (!onewire_master_write()) { // read bits from slave
return false; // an error occurred
}
return true;
}
uint64_t onewire_master_rom_read(void)
{
uint8_t rom_code[8] = {0}; // to store 64 bits ROM code
if (!onewire_master_function_read(0x33, rom_code, 64)) { // read ROM code (I'm cheating because the ROM command isn't a function command, but it works the same way in the end)
return 0; // an error occurred
}
if (onewire_master_crc(rom_code, LENGTH(rom_code))) { // verify checksum
return 0; // checksum is wrong (not 0)
}
// return ROM code
uint64_t code = 0;
for (uint32_t i=0; i<8; i++) {
code += (uint64_t)rom_code[i]<<(8*i); // add byte
}
return code;
}
bool onewire_master_rom_search(uint64_t* code, bool alarm)
{
static uint8_t conflict_last = 64; // on which bit has the conflict been detected (64 means there hasn't been)
uint8_t conflict_current = 64; // to remember on which bit the last unknown conflict has been detected
uint8_t bits[1] = {0}; // small buffer to store the bits used to search the ROM codes
// send SEARCH ROM command
uint8_t command = 0xf0; // SEARCH ROM command
if (alarm) { // looking only for ROM codes for slaves in alarm state
command = 0xec; // use ALARM SEARCH ROM command instead
}
if (!onewire_master_function_read(command, NULL, 0)) { // send SEARCH ROM command
goto end; // an error occurred
}
if (conflict_last>=64) { // no previous conflict has been detected
*code = 0; // restart search codes
}
buffer = bits; // buffer to read up to two bits
for (uint8_t bit=0; bit<64; bit++) { // go through all 64 bits ROM code
buffer_size = 2; // read two first bits to detect conflict
if (!onewire_master_read()) { // read ROM ID from slave
goto end; // an error occurred
}
switch (buffer[0]&0x03) { // check 2 bits received
case 0: // collision detected
if (bit==conflict_last) { // this conflict is known
*code |= (((uint64_t)1)<<bit); // use 0 as next bit
} else { // unknown conflict
conflict_current = bit; // remember conflict
*code &= ~(((uint64_t)1)<<bit); // use 1 as next bit
}
break;
case 1: // no conflict, valid bit is 1
*code |= (((uint64_t)1)<<bit); // remember valid bit 1
break;
case 2: // no conflict, valid bit is 0
*code &= ~(((uint64_t)1)<<bit); // remember valid bit 0
break;
default: // two 1's indicate there is no slave
conflict_current = 64; // remember there was no conflict because there is no slave
goto end; // an error has occurred
}
buffer_size = 1; // to send next bit
buffer[0] = ((*code)>>bit); // set bit to send
if (!onewire_master_write()) { // send bit
goto end; // an error has occurred
}
}
// verify ROM code
uint8_t rom_code[8] = {0}; // to store ROM code
for (uint8_t i=0; i<LENGTH(rom_code); i++) {
rom_code[i] = (*code)>>(8*i); // split and save last code in ROM code
}
if (onewire_master_crc(rom_code, LENGTH(rom_code))) { // verify checksum
*code = 0; // return the last code found since it's valid
}
end:
conflict_last = conflict_current; // update the last seen and unknown conflict
if (conflict_current<64) { // we have seen an unknown conflict
return true; // tell there are more slaves
} else { // no conflict seen
return false; // no more slaves
}
}
bool onewire_master_rom_skip(void)
{
if (!onewire_master_function_write(0xcc, NULL, 0)) { // send SKIP ROM command
return false; // an error occurred
}
return true;
}
bool onewire_master_rom_match(uint64_t code)
{
uint8_t rom_code[8] = {0}; // to store ROM code
for (uint8_t i=0; i<LENGTH(rom_code); i++) {
rom_code[i] = code>>(8*i); // split and save code in ROM code
}
if (!onewire_master_function_write(0x55, rom_code, 64)) { // send MATCH ROM command with ROM code
return false; // an error occurred
}
return true;
}
buffer_bit
static volatile uint32_t buffer_bit
number of bits read/written
Definition: onewire_master.c:67
ONEWIRE_MASTER_PORT
#define ONEWIRE_MASTER_PORT
GPIO port.
Definition: onewire_master.h:28
RCC_GPIO
#define RCC_GPIO(x)
get RCC for GPIO based on GPIO identifier
Definition: global.h:105
ONEWIRE_STATE_MASTER_RESET
reset pulse started
Definition: onewire_master.c:57
onewire_master_rom_read
uint64_t onewire_master_rom_read(void)
send READ ROM command and read ROM code response
Definition: onewire_master.c:407
onewire_master_rom_search
bool onewire_master_rom_search(uint64_t *code, bool alarm)
send SEARCH ROM command
Definition: onewire_master.c:426
NVIC_TIM_IRQ
#define NVIC_TIM_IRQ(x)
get NVIC IRQ for timer base on TIM identifier
Definition: global.h:111
onewire_master_function_write
bool onewire_master_function_write(uint8_t function, uint8_t *data, uint32_t bits)
issue function and write data
Definition: onewire_master.c:385
ONEWIRE_MASTER_PIN
#define ONEWIRE_MASTER_PIN
GPIO pin.
Definition: onewire_master.h:29
ONEWIRE_STATE_ERROR
communication error
Definition: onewire_master.c:56
ONEWIRE_STATE_SLAVE_PRESENCE
waiting for slave response to reset pulse
Definition: onewire_master.c:58
onewire_master_setup
void onewire_master_setup(void)
setup 1-wire peripheral
Definition: onewire_master.c:169
global.h
global definitions and methods (API)
GPIO
#define GPIO(x)
get GPIO based on GPIO identifier
Definition: global.h:103
onewire_master_read
static bool onewire_master_read(void)
read bits on 1-Wire bus
Definition: onewire_master.c:286
RCC_TIM
#define RCC_TIM(x)
get RCC for timer based on TIM identifier
Definition: global.h:109
TIM_ISR
void TIM_ISR(2)
timer ISR to measure edge timing
Definition: busvoodoo_uart_generic.c:698
onewire_master.h
library for 1-wire protocol as master
onewire_master_write_byte
bool onewire_master_write_byte(uint8_t data)
write data byte
Definition: onewire_master.c:353
onewire_master_function_read
bool onewire_master_function_read(uint8_t function, uint8_t *data, uint32_t bits)
issue function and read data
Definition: onewire_master.c:364
onewire_master_rom_skip
bool onewire_master_rom_skip(void)
send SKIP ROM command (all slaves on the bus will be selected)
Definition: onewire_master.c:494
ONEWIRE_STATE_MASTER_WRITE
master is writing bits
Definition: onewire_master.c:59
onewire_master_write
static bool onewire_master_write(void)
write bits on 1-Wire bus
Definition: onewire_master.c:255
interrupt_table
vector_table_entry_t interrupt_table[NVIC_IRQ_COUNT]
table of interrupts which can set to user functions
Definition: interrupt.c:21
ONEWIRE_MAX
to count the number of possible states
Definition: onewire_master.c:61
interrupt.h
BusVoodoo runtime interrupt table.
buffer
static uint8_t * buffer
input/output buffer for read/write commands/functions
Definition: onewire_master.c:65
onewire_master_read_byte
bool onewire_master_read_byte(uint8_t *data)
read data byte
Definition: onewire_master.c:338
buffer_size
static uint32_t buffer_size
size of buffer in bits
Definition: onewire_master.c:66
ONEWIRE_STATE_DONE
communication complete
Definition: onewire_master.c:55
LENGTH
#define LENGTH(x)
get the length of an array
Definition: global.h:26
onewire_master_rom_match
bool onewire_master_rom_match(uint64_t code)
send MATCH ROM command to select a specific slave
Definition: onewire_master.c:502
TIM
#define TIM(x)
get TIM based on TIM identifier
Definition: global.h:107
onewire_master_release
void onewire_master_release(void)
release 1-wire peripheral
Definition: onewire_master.c:206
slave_presence
static volatile bool slave_presence
if slaves have been detected
Definition: onewire_master.c:64
onewire_master_crc
uint8_t onewire_master_crc(uint8_t *data, uint32_t length)
compute CRC for 1-Wire
Definition: onewire_master.c:318
ONEWIRE_STATE_IDLE
no current communication
Definition: onewire_master.c:54
ONEWIRE_STATE_MASTER_READ
master is reading bits
Definition: onewire_master.c:60
onewire_master_reset
bool onewire_master_reset(void)
send reset pulse
Definition: onewire_master.c:227
onewire_master_state
enum @0 onewire_master_state
state of 1-Wire communication
ONEWIRE_MASTER_TIMER
#define ONEWIRE_MASTER_TIMER
timer ID
Definition: onewire_master.c:44