2018-07-11 08:10:25 +02:00
/** library for 1-wire protocol as master
* @ file
2017-03-28 12:38:43 +02:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2020-06-06 14:35:55 +02:00
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
2020-02-17 14:44:12 +01:00
* @ date 2017 - 2020
2017-03-28 12:38:43 +02:00
* @ note peripherals used : timer @ ref onewire_master_timer , GPIO @ ref onewire_master_gpio
2017-08-02 13:44:49 +02:00
* @ note overdrive mode is not provided
* @ implements 1 - Wire protocol description from Book of iButton Standards
2017-03-28 12:38:43 +02:00
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdbool.h> // boolean type
2017-08-01 19:17:22 +02:00
# include <stddef.h> // NULL definition
2017-03-28 12:38:43 +02:00
/* 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
2018-07-11 08:10:25 +02:00
# include "interrupt.h" // runtime interrupt table
2017-03-28 12:38:43 +02:00
# include "onewire_master.h" // own definitions
2020-02-17 14:44:12 +01:00
/** @defgroup onewire_master_gpio GPIO used for 1-wire signal
* @ note external pull - up resistor on pin is required ( < 5 kOhm )
* @ {
*/
# define ONEWIRE_MASTER_PIN PC9 /**< GPIO pin */
/** @} */
2017-03-28 12:38:43 +02:00
/** @defgroup onewire_master_timer timer used to measure 1-wire signal timing
* @ {
*/
2018-07-11 08:10:25 +02:00
# define ONEWIRE_MASTER_TIMER 5 /**< timer ID */
2017-03-28 12:38:43 +02:00
/** @} */
2018-07-11 08:10:25 +02:00
/** set if the timer ISR should be set in the interrupt table instead of the vector table
* @ note the vector table is faster , but doesn ' t allow to change the ISR
*/
# define ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE false
2017-03-28 12:38:43 +02:00
/** 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 */
2019-03-26 19:27:40 +01:00
ONEWIRE_STATE_MASTER_READ , /**< master is reading bits */
2017-03-28 12:38:43 +02:00
ONEWIRE_MAX /** to count the number of possible states */
} onewire_master_state = ONEWIRE_STATE_IDLE ;
2017-08-02 13:44:49 +02:00
static volatile bool slave_presence = false ; /**< if slaves have been detected */
static uint8_t * buffer = NULL ; /**< input/output buffer for read/write commands/functions */
static uint32_t buffer_size = 0 ; /**< size of buffer in bits */
static volatile uint32_t buffer_bit = 0 ; /**< number of bits read/written */
2018-07-11 08:10:25 +02:00
# if defined(ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE) && ONEWIRE_MASTER_TIMER_USE_INTERRUPT_TABLE
static void ( * isr_backup ) ( void ) = NULL ; /**< backup for the existing timer ISR */
static bool irq_backup = false ; /**< backup for the existing timer IRQ */
# endif
/** interrupt service routine called for timer */
# 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
2020-02-17 14:44:12 +01:00
gpio_set ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // set signal high again for slaves to respond
2018-07-11 08:10:25 +02:00
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
2020-02-17 14:44:12 +01:00
if ( buffer_bit < buffer_size ) { // check if byte to read/write are remaining
gpio_clear ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // pull signal low to start next slot
2018-07-11 08:10:25 +02:00
} 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
2020-02-17 14:44:12 +01:00
gpio_set ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // pull signal high (idle state)
2018-07-11 08:10:25 +02:00
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
2020-02-17 14:44:12 +01:00
gpio_set ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // pull signal high to end time slot
2018-07-11 08:10:25 +02:00
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
2020-02-17 14:44:12 +01:00
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_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // set signal high again to write "1"
2018-07-11 08:10:25 +02:00
}
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 ;
2019-03-26 19:27:40 +01:00
case ONEWIRE_STATE_MASTER_READ : // master has to read a bit set by slave
2018-07-11 08:10:25 +02:00
if ( buffer_bit < buffer_size ) { // check if byte to send are remaining
2020-02-17 14:44:12 +01:00
if ( gpio_get ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ) { // check if the slave kept it low
buffer [ buffer_bit / 8 ] | = ( 1 < < ( buffer_bit % 8 ) ) ; // save bit "1"
2018-07-11 08:10:25 +02:00
} else {
2020-02-17 14:45:12 +01:00
buffer [ buffer_bit / 8 ] & = ~ ( 1 < < ( buffer_bit % 8 ) ) ; // save bit "0"
2018-07-11 08:10:25 +02:00
}
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
2020-02-17 14:44:12 +01:00
gpio_set ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // pull signal high to end time slot
2018-07-11 08:10:25 +02:00
} 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
2020-02-17 14:44:12 +01:00
if ( gpio_get ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ) { // check is a slave let its presence know by pulling low
2018-07-11 08:10:25 +02:00
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
}
}
2017-03-28 12:38:43 +02:00
2018-05-09 21:27:00 +02:00
void onewire_master_setup ( void )
2017-03-28 12:38:43 +02:00
{
// setup GPIO with external interrupt
2020-02-17 14:45:12 +01:00
rcc_periph_clock_enable ( GPIO_RCC ( ONEWIRE_MASTER_PIN ) ) ; // enable clock for GPIO peripheral
gpio_set ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // idle is high (using pull-up resistor)
gpio_set_mode ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // normal 1-Wire communication (only using external pull-up resistor)
2019-03-26 19:27:40 +01:00
2017-03-28 12:38:43 +02:00
// setup timer to generate/measure signal timing
rcc_periph_clock_enable ( RCC_TIM ( ONEWIRE_MASTER_TIMER ) ) ; // enable clock for timer peripheral
2020-02-17 13:59:49 +01:00
rcc_periph_reset_pulse ( RST_TIM ( ONEWIRE_MASTER_TIMER ) ) ; // reset timer state
2018-05-09 21:27:00 +02:00
timer_disable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // disable timer to configure it
2017-03-28 12:38:43 +02:00
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
2020-02-17 14:45:12 +01:00
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 )
2017-03-28 12:38:43 +02:00
// use comparator to time signal (without using the output), starting at slot start
2018-05-09 21:27:00 +02:00
timer_clear_flag ( TIM ( ONEWIRE_MASTER_TIMER ) , TIM_SR_CC1IF ) ; // clear flag
2020-02-17 14:45:12 +01:00
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)
2018-05-09 21:27:00 +02:00
timer_clear_flag ( TIM ( ONEWIRE_MASTER_TIMER ) , TIM_SR_CC2IF ) ; // clear flag
2020-02-17 14:45:12 +01:00
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)
2018-05-09 21:27:00 +02:00
timer_clear_flag ( TIM ( ONEWIRE_MASTER_TIMER ) , TIM_SR_CC3IF ) ; // clear flag
2020-02-17 14:45:12 +01:00
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)
2018-05-09 21:27:00 +02:00
timer_clear_flag ( TIM ( ONEWIRE_MASTER_TIMER ) , TIM_SR_CC4IF ) ; // clear flag
2020-02-17 14:45:12 +01:00
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
2017-03-28 12:38:43 +02:00
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
2018-07-11 08:10:25 +02:00
# 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
2017-03-28 12:38:43 +02:00
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
}
2018-05-09 21:27:00 +02:00
void onewire_master_release ( void )
{
// release timer
timer_disable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // disable timer
2020-02-17 13:59:49 +01:00
rcc_periph_reset_pulse ( RST_TIM ( ONEWIRE_MASTER_TIMER ) ) ; // reset timer state
2018-05-09 21:27:00 +02:00
rcc_periph_clock_disable ( RCC_TIM ( ONEWIRE_MASTER_TIMER ) ) ; // disable clock for timer peripheral
// release GPIO
2020-02-17 14:44:12 +01:00
gpio_set_mode ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // put back to input floating
2018-07-11 08:10:25 +02:00
// 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
2018-05-09 21:27:00 +02:00
}
2017-03-28 12:38:43 +02:00
bool onewire_master_reset ( void )
{
// prepare timer
timer_disable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // disable timer to reconfigure it
2020-02-17 14:45:12 +01:00
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)
2017-03-28 12:38:43 +02:00
slave_presence = false ; // reset state
onewire_master_state = ONEWIRE_STATE_MASTER_RESET ; // set new state
2020-02-17 14:44:12 +01:00
gpio_set_mode ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // normal 1-Wire communication (only using external pull-up resistor)
gpio_clear ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( 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)
2017-03-28 12:38:43 +02:00
timer_enable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // start timer
2020-02-17 14:45:12 +01:00
while ( onewire_master_state ! = ONEWIRE_STATE_DONE & & onewire_master_state ! = ONEWIRE_STATE_ERROR ) { // wait until reset procedure completed
2017-03-28 12:38:43 +02:00
__WFI ( ) ; // go to sleep
}
2020-02-17 14:45:12 +01:00
if ( ONEWIRE_STATE_ERROR = = onewire_master_state ) { // an error occurred
2017-03-28 12:38:43 +02:00
return false ;
}
return slave_presence ;
}
/** write bits on 1-Wire bus
2017-08-01 19:17:22 +02:00
* @ warning buffer_size must be set to the number of bits to writen and buffer must contain the data to write
2017-03-28 12:38:43 +02:00
* @ 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
2018-05-09 21:27:00 +02:00
timer_set_counter ( TIM ( ONEWIRE_MASTER_TIMER ) , 0 ) ; // reset counter
2020-02-17 14:45:12 +01:00
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 )
2017-03-28 12:38:43 +02:00
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
2020-02-17 14:44:12 +01:00
gpio_set_mode ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // normal 1-Wire communication (only using external pull-up resistor)
gpio_clear ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // pull signal low to start slot
2017-03-28 12:38:43 +02:00
timer_enable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // start timer
2020-02-17 14:45:12 +01:00
while ( onewire_master_state ! = ONEWIRE_STATE_DONE & & onewire_master_state ! = ONEWIRE_STATE_ERROR ) { // wait until write procedure completed
2017-03-28 12:38:43 +02:00
__WFI ( ) ; // go to sleep
}
2020-02-17 14:45:12 +01:00
if ( ONEWIRE_STATE_ERROR = = onewire_master_state ) { // an error occurred
2017-03-28 12:38:43 +02:00
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 )
{
2020-02-17 14:45:12 +01:00
if ( 0 = = buffer_size ) { // check input
2017-03-28 12:38:43 +02:00
return false ;
}
buffer_bit = 0 ; // reset bit index
onewire_master_state = ONEWIRE_STATE_MASTER_READ ; // set new state
// prepare timer
2017-08-02 13:44:49 +02:00
timer_disable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // disable timer to reconfigure it
2018-05-09 21:27:00 +02:00
timer_set_counter ( TIM ( ONEWIRE_MASTER_TIMER ) , 0 ) ; // reset counter
2020-02-17 14:45:12 +01:00
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 )
2017-03-28 12:38:43 +02:00
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
2020-02-17 14:44:12 +01:00
gpio_set_mode ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // normal 1-Wire communication (only using external pull-up resistor)
gpio_clear ( GPIO_PORT ( ONEWIRE_MASTER_PIN ) , GPIO_PIN ( ONEWIRE_MASTER_PIN ) ) ; // pull signal low to start slot
2017-03-28 12:38:43 +02:00
timer_enable_counter ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // start timer
2020-02-17 14:45:12 +01:00
while ( onewire_master_state ! = ONEWIRE_STATE_DONE & & onewire_master_state ! = ONEWIRE_STATE_ERROR ) { // wait until read procedure completed
2017-03-28 12:38:43 +02:00
__WFI ( ) ; // go to sleep
}
2020-02-17 14:45:12 +01:00
if ( ONEWIRE_STATE_ERROR = = onewire_master_state ) { // an error occurred
2017-03-28 12:38:43 +02:00
return false ;
}
return true ;
}
2017-08-01 19:17:22 +02:00
uint8_t onewire_master_crc ( uint8_t * data , uint32_t length )
2017-03-28 12:38:43 +02:00
{
2020-02-17 14:45:12 +01:00
if ( NULL = = data | | 0 = = length ) { // check input
2017-03-28 12:38:43 +02:00
return 0 ; // wrong input
}
2018-05-09 21:27:00 +02:00
2017-03-28 12:38:43 +02:00
uint8_t crc = 0x00 ; // initial value
2020-02-17 14:45:12 +01:00
for ( uint8_t i = 0 ; i < length ; i + + ) { // go through every byte
2017-03-28 12:38:43 +02:00
crc ^ = data [ i ] ; // XOR byte
2020-02-17 14:45:12 +01:00
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
2017-03-28 12:38:43 +02:00
} else {
crc > > = 1 ; // just shift right (for the next bit)
}
}
}
return crc ;
}
2018-05-09 21:27:00 +02:00
bool onewire_master_read_byte ( uint8_t * data )
2017-03-28 12:38:43 +02:00
{
2020-02-17 14:45:12 +01:00
if ( NULL = = data ) { // check input
2018-05-09 21:27:00 +02:00
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
2017-03-28 12:38:43 +02:00
buffer_size = 8 ; // function command is only one byte
2018-05-09 21:27:00 +02:00
buffer = & data ; // set the buffer to the function code
2017-03-28 12:38:43 +02:00
if ( ! onewire_master_write ( ) ) { // send command
return false ; // an error occurred
}
2018-05-09 21:27:00 +02:00
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
}
2017-03-28 12:38:43 +02:00
2020-02-17 14:45:12 +01:00
if ( NULL = = data | | 0 = = bits ) { // there is no data to read
2017-03-28 12:38:43 +02:00
return true ; // operation completed
}
// read data
buffer_size = bits ; // save number of bits to read
2017-08-01 19:17:22 +02:00
buffer = data ; // set the buffer to the data to write
2017-03-28 12:38:43 +02:00
if ( ! onewire_master_read ( ) ) { // read bits from slave
return false ; // an error occurred
}
return true ;
}
2017-08-01 19:17:22 +02:00
bool onewire_master_function_write ( uint8_t function , uint8_t * data , uint32_t bits )
2017-03-28 12:38:43 +02:00
{
// send function command
2018-05-09 21:27:00 +02:00
if ( ! onewire_master_write_byte ( function ) ) {
2017-03-28 12:38:43 +02:00
return false ; // an error occurred
}
2020-02-17 14:45:12 +01:00
if ( NULL = = data | | 0 = = bits ) { // there is no data to read
2017-03-28 12:38:43 +02:00
return true ; // operation completed
}
// copy data from user buffer
buffer_size = bits ; // save number of bits to write
2017-08-01 19:17:22 +02:00
buffer = data ; // set the buffer to the data to write
2017-03-28 12:38:43 +02:00
// 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)
}
2019-03-26 19:27:40 +01:00
2017-03-28 12:38:43 +02:00
// return ROM code
uint64_t code = 0 ;
2020-02-17 14:45:12 +01:00
for ( uint32_t i = 0 ; i < 8 ; i + + ) {
code + = ( uint64_t ) rom_code [ i ] < < ( 8 * i ) ; // add byte
2017-03-28 12:38:43 +02:00
}
2019-03-26 19:27:40 +01:00
2017-03-28 12:38:43 +02:00
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
2017-08-02 15:20:01 +02:00
uint8_t bits [ 1 ] = { 0 } ; // small buffer to store the bits used to search the ROM codes
2017-03-28 12:38:43 +02:00
// 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
}
2020-02-17 14:45:12 +01:00
if ( conflict_last > = 64 ) { // no previous conflict has been detected
2017-03-28 12:38:43 +02:00
* code = 0 ; // restart search codes
}
2017-08-02 15:20:01 +02:00
buffer = bits ; // buffer to read up to two bits
2020-02-17 14:45:12 +01:00
for ( uint8_t bit = 0 ; bit < 64 ; bit + + ) { // go through all 64 bits ROM code
2017-03-28 12:38:43 +02:00
buffer_size = 2 ; // read two first bits to detect conflict
if ( ! onewire_master_read ( ) ) { // read ROM ID from slave
goto end ; // an error occurred
}
2020-02-17 14:45:12 +01:00
switch ( buffer [ 0 ] & 0x03 ) { // check 2 bits received
2017-03-28 12:38:43 +02:00
case 0 : // collision detected
2020-02-17 14:45:12 +01:00
if ( bit = = conflict_last ) { // this conflict is known
* code | = ( ( ( uint64_t ) 1 ) < < bit ) ; // use 0 as next bit
2017-03-28 12:38:43 +02:00
} else { // unknown conflict
conflict_current = bit ; // remember conflict
2020-02-17 14:45:12 +01:00
* code & = ~ ( ( ( uint64_t ) 1 ) < < bit ) ; // use 1 as next bit
2017-03-28 12:38:43 +02:00
}
break ;
case 1 : // no conflict, valid bit is 1
2020-02-17 14:45:12 +01:00
* code | = ( ( ( uint64_t ) 1 ) < < bit ) ; // remember valid bit 1
2017-03-28 12:38:43 +02:00
break ;
case 2 : // no conflict, valid bit is 0
2020-02-17 14:45:12 +01:00
* code & = ~ ( ( ( uint64_t ) 1 ) < < bit ) ; // remember valid bit 0
2017-03-28 12:38:43 +02:00
break ;
default : // two 1's indicate there is no slave
2018-06-16 11:05:12 +02:00
conflict_current = 64 ; // remember there was no conflict because there is no slave
2017-03-28 12:38:43 +02:00
goto end ; // an error has occurred
}
buffer_size = 1 ; // to send next bit
2020-02-17 14:45:12 +01:00
buffer [ 0 ] = ( ( * code ) > > bit ) ; // set bit to send
2017-03-28 12:38:43 +02:00
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
2020-02-17 14:45:12 +01:00
for ( uint8_t i = 0 ; i < LENGTH ( rom_code ) ; i + + ) {
rom_code [ i ] = ( * code ) > > ( 8 * i ) ; // split and save last code in ROM code
2017-03-28 12:38:43 +02:00
}
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
2020-02-17 14:45:12 +01:00
if ( conflict_current < 64 ) { // we have seen an unknown conflict
2017-03-28 12:38:43 +02:00
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
2020-02-17 14:45:12 +01:00
for ( uint8_t i = 0 ; i < LENGTH ( rom_code ) ; i + + ) {
rom_code [ i ] = code > > ( 8 * i ) ; // split and save code in ROM code
2017-03-28 12:38:43 +02:00
}
if ( ! onewire_master_function_write ( 0x55 , rom_code , 64 ) ) { // send MATCH ROM command with ROM code
return false ; // an error occurred
}
return true ;
}