add 1-Wire master software implementation library from thermo-regulator project
This commit is contained in:
parent
610d366754
commit
48ac76bc02
|
@ -0,0 +1,492 @@
|
|||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
/** library for 1-wire protocol as master (code)
|
||||
* @file onewire_master.c
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @date 2017
|
||||
* @note peripherals used: timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio
|
||||
* @warning this library does not support parasite power mode
|
||||
*/
|
||||
|
||||
/* standard libraries */
|
||||
#include <stdint.h> // standard integer types
|
||||
#include <stdbool.h> // boolean type
|
||||
#include <stdlib.h> // memory utilities
|
||||
|
||||
/* 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 "onewire_master.h" // own definitions
|
||||
|
||||
/** @defgroup onewire_master_timer timer used to measure 1-wire signal timing
|
||||
* @{
|
||||
*/
|
||||
#define ONEWIRE_MASTER_TIMER 2 /**< timer ID */
|
||||
/** @} */
|
||||
|
||||
/** @defgroup onewire_master_gpio GPIO used for 1-wire signal
|
||||
* @note use external pull-up resistor on pin
|
||||
* @{
|
||||
*/
|
||||
#define ONEWIRE_MASTER_PORT A /**< GPIO port */
|
||||
#define ONEWIRE_MASTER_PIN 4 /**< GPIO pin */
|
||||
/** @} */
|
||||
|
||||
/** state of 1-Wire communication */
|
||||
volatile enum {
|
||||
ONEWIRE_STATE_IDLE, /**< no current communication */
|
||||
ONEWIRE_STATE_DONE, /**< communication complete */
|
||||
ONEWIRE_STATE_ERROR, /**< communication error */
|
||||
ONEWIRE_STATE_MASTER_RESET, /**< reset pulse started */
|
||||
ONEWIRE_STATE_SLAVE_PRESENCE, /**< waiting for slave response to reset pulse */
|
||||
ONEWIRE_STATE_MASTER_WRITE, /**< master is writing bits */
|
||||
ONEWIRE_STATE_MASTER_READ, /**< master is reading bits */
|
||||
ONEWIRE_MAX /** to count the number of possible states */
|
||||
} onewire_master_state = ONEWIRE_STATE_IDLE;
|
||||
|
||||
volatile bool slave_presence = false; /**< if slaves have been detected */
|
||||
uint8_t* buffer = NULL; /**< input/output buffer for read/write commands/functions */
|
||||
size_t buffer_size = 0; /**< size of buffer in bits */
|
||||
volatile size_t buffer_bit = 0; /**< number of bits read/written */
|
||||
|
||||
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_mode(GPIO(ONEWIRE_MASTER_PORT), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(ONEWIRE_MASTER_PIN)); // setup GPIO pin as output (master starts communication before slave replies)
|
||||
gpio_set(GPIO(ONEWIRE_MASTER_PORT),GPIO(ONEWIRE_MASTER_PIN)); // idle is high (using 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_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_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC1, 1*(rcc_ahb_frequency/1000000)); // use compare function to time master pulling low (1 < Tlowr < 15)
|
||||
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC2, 7*(rcc_ahb_frequency/1000000)); // use compare function to read of write (1 < Trw < 15)
|
||||
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC3, 62*(rcc_ahb_frequency/1000000)); // use compare function to end time slot (60 < Tslot < 120), this will be followed by a recovery time (end of timer)
|
||||
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC4, 120*(rcc_ahb_frequency/1000000)); // use compare function to detect slave presence (60 < Tpdl < 240)
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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)); // set timeout to > 480 us (490)
|
||||
|
||||
slave_presence = false; // reset state
|
||||
onewire_master_state = ONEWIRE_STATE_MASTER_RESET; // set new state
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/** write bits on 1-Wire bus
|
||||
* @warning buffer_size must be set to the number of bits to write and buffer must contain the data to write
|
||||
* @return if write succeeded
|
||||
*/
|
||||
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))+5*(rcc_ahb_frequency/1000000)); // set time for new time slot (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_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 reset procedure completed
|
||||
__WFI(); // go to sleep
|
||||
}
|
||||
if (ONEWIRE_STATE_ERROR==onewire_master_state) { // an error occurred
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** read bits on 1-Wire bus
|
||||
* @warning buffer_size must be set to the number of bits to read
|
||||
* @return if read succeeded
|
||||
*/
|
||||
static bool onewire_master_read(void)
|
||||
{
|
||||
if (0==buffer_size) { // check input
|
||||
return false;
|
||||
}
|
||||
if (!(buffer=realloc(buffer, (buffer_size-1)/8+1))) { // allocate memory
|
||||
return false; // error in memory allocation
|
||||
}
|
||||
buffer_bit = 0; // reset bit index
|
||||
onewire_master_state = ONEWIRE_STATE_MASTER_READ; // set new state
|
||||
|
||||
// prepare timer
|
||||
timer_set_counter(TIM(ONEWIRE_MASTER_TIMER),0); // reset counter
|
||||
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_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 reset 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, size_t size)
|
||||
{
|
||||
if (NULL==data || 0==size) { // check input
|
||||
return 0; // wrong input
|
||||
}
|
||||
|
||||
uint8_t crc = 0x00; // initial value
|
||||
for (uint8_t i=0; i<size; 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_function_read(uint8_t function, uint8_t* data, size_t bits)
|
||||
{
|
||||
// send function command
|
||||
buffer_size = 8; // function command is only one byte
|
||||
if (!(buffer=realloc(buffer, (buffer_size-1)/8+1))) { // allocate memory
|
||||
return false; // error in memory allocation
|
||||
}
|
||||
buffer[0] = function; // set function command
|
||||
if (!onewire_master_write()) { // send command
|
||||
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
|
||||
if (!onewire_master_read()) { // read bits from slave
|
||||
return false; // an error occurred
|
||||
}
|
||||
|
||||
// copy data to user buffer
|
||||
for (uint8_t i=0; i<bits/8; i++) { // copy bytes
|
||||
data[i] = buffer[i]; // copy data
|
||||
}
|
||||
// copy remaining bits
|
||||
switch (bits%8) {
|
||||
case 1:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x01;
|
||||
break;
|
||||
case 2:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x03;
|
||||
break;
|
||||
case 3:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x07;
|
||||
break;
|
||||
case 4:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x0f;
|
||||
break;
|
||||
case 5:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x1f;
|
||||
break;
|
||||
case 6:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x3f;
|
||||
break;
|
||||
case 7:
|
||||
data[(bits-1)/8] = data[(bits-1)/8]&0x7f;
|
||||
break;
|
||||
case 0: // no bits remaining
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onewire_master_function_write(uint8_t function, uint8_t* data, size_t bits)
|
||||
{
|
||||
// send function command
|
||||
buffer_size = 8; // function command is only one byte
|
||||
if (!(buffer=realloc(buffer, (buffer_size-1)/8+1))) { // allocate memory
|
||||
return false; // error in memory allocation
|
||||
}
|
||||
buffer[0] = function; // set function command
|
||||
if (!onewire_master_write()) { // send command
|
||||
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
|
||||
if (!(buffer=realloc(buffer, (buffer_size-1)/8+1))) { // allocate memory
|
||||
return false; // error in memory allocation
|
||||
}
|
||||
for (uint8_t i=0; i<(buffer_size-1)/8+1; i++) { // copy bytes
|
||||
buffer[i] = data[i]; // copy data
|
||||
}
|
||||
// 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 (size_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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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
|
||||
goto end; // an error has occurred
|
||||
}
|
||||
buffer_size = 1; // to send next bit
|
||||
if (!(buffer=realloc(buffer, 1))) { // allocate memory
|
||||
goto end; // an error has occurred
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/** interrupt service routine called for timer */
|
||||
void TIM_ISR(ONEWIRE_MASTER_TIMER)(void)
|
||||
{
|
||||
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_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
|
||||
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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
/** library for 1-wire protocol as master (API)
|
||||
* @file onewire_master.c
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @date 2017
|
||||
* @note peripherals used: timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio
|
||||
* @warning this library does not support parasite power mode
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/** setup 1-wire peripheral */
|
||||
void onewire_master_setup(void);
|
||||
/** send reset pulse
|
||||
* @return if slaves have indicated their presence
|
||||
*/
|
||||
bool onewire_master_reset(void);
|
||||
/** compute CRC for 1-Wire
|
||||
* @note this CRC-8 uses normal polynomial 0x31, reverse polynomial 0x8C, start value 0x00
|
||||
* @param[in] data bytes on which to calculate CRC checksum on
|
||||
* @param[in] size number of bytes in data
|
||||
* @return computed CRC checksum
|
||||
*/
|
||||
uint8_t onewire_master_crc(uint8_t* data, size_t size);
|
||||
/** send READ ROM command
|
||||
* @note user needs to send reset pulse before
|
||||
* @return ROM code read
|
||||
*/
|
||||
uint64_t onewire_master_rom_read(void);
|
||||
/** send SEARCH ROM command
|
||||
* @note user needs to send reset pulse before
|
||||
* @warning undefined behaviour if a ROM code different than the last found is provided
|
||||
* @param[in,out] code use 0 to start search ROM code from scratch, or last know value to search next; writes back next ROM code found, or 0 if error occurred
|
||||
* @param[in] alarm search only for ROM codes for slaves with an alarm flag set
|
||||
* @return if an additional slave has been detected
|
||||
*/
|
||||
bool onewire_master_rom_search(uint64_t* code, bool alarm);
|
||||
/** send SKIP ROM command (all slaves on the bus will be selected)
|
||||
* @note user needs to send reset pulse before
|
||||
* @return if operation succeeded
|
||||
*/
|
||||
bool onewire_master_rom_skip(void);
|
||||
/** send MATCH ROM command to select a specific slave
|
||||
* @note user needs to send reset pulse before
|
||||
* @param[in] code ROM code of slave to select
|
||||
* @return if operation succeeded
|
||||
*/
|
||||
bool onewire_master_rom_match(uint64_t code);
|
||||
/** issue function and read data
|
||||
* @note user needs to send a ROM command before
|
||||
* @param[in] function function command to send
|
||||
* @param[out] data buffer to save read bits (NULL if only the function command should be sent)
|
||||
* @param[in] bits number of bits to read (0 if only the function command should be sent)
|
||||
* @return if operation succeeded
|
||||
*/
|
||||
bool onewire_master_function_read(uint8_t function, uint8_t* data, size_t bits);
|
||||
/** issue function and write data
|
||||
* @note user needs to send a ROM command before
|
||||
* @param[in] function function command to send
|
||||
* @param[out] data data to write (NULL if only the function command should be sent)
|
||||
* @param[in] bits number of bits to write (0 if only the function command should be sent)
|
||||
* @return if operation succeeded
|
||||
*/
|
||||
bool onewire_master_function_write(uint8_t function, uint8_t* data, size_t bits);
|
Loading…
Reference in New Issue