2017-03-28 12:38:43 +02:00
/* 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
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
# 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
2017-08-02 13:44:49 +02:00
* @ note external pull - up resistor on pin is required ( < 5 kOhm )
2017-03-28 12:38:43 +02:00
* @ {
*/
# 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 ;
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 */
static bool onewire_master_parasite = false ; /**< if parasite power should be provided whenever the is no communication */
static uint16_t onewire_master_recovery = 0 ; /**< the recovery time in us (1 < Trec) */
2017-03-28 12:38:43 +02:00
2017-08-02 13:44:49 +02:00
void onewire_master_setup ( bool parasite , uint16_t recovery )
2017-03-28 12:38:43 +02:00
{
// 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)
2017-08-02 13:44:49 +02:00
onewire_master_parasite = parasite ; // save if we should provide parasite power
// setup GPIO pin as output (master starts communication before slave replies)
if ( onewire_master_parasite ) {
gpio_set_mode ( GPIO ( ONEWIRE_MASTER_PORT ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_PUSHPULL , GPIO ( ONEWIRE_MASTER_PIN ) ) ; // provide parasite power (external pull-up resistor is still require for communication)
} else {
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)
}
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
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
2017-08-02 13:44:49 +02: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)
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)
2017-08-01 19:17:22 +02: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)
2017-08-02 13:44:49 +02: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 tunig
onewire_master_recovery = 5 ; // set minimum recovery time
if ( recovery > onewire_master_recovery ) {
onewire_master_recovery = recovery ; // save desired recovery time
}
if ( UINT16_MAX / onewire_master_recovery < ( rcc_ahb_frequency / 1000000 ) ) { // catch integer overflow
onewire_master_recovery = UINT16_MAX ; // save maximum value
} else {
onewire_master_recovery * = ( rcc_ahb_frequency / 1000000 ) ; // save actual recovery time value
}
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
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
2017-08-02 13:44:49 +02:00
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
2017-08-02 13:44:49 +02:00
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)
2017-03-28 12:38:43 +02:00
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
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
timer_set_counter ( TIM ( ONEWIRE_MASTER_TIMER ) , 0 ) ; // reset counter
2017-08-02 13:44:49 +02:00
uint16_t timeout = TIM_CCR3 ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // time until new slot (= end of slot+recovery)
if ( UINT16_MAX - timeout < onewire_master_recovery ) { // catch integer overflow
timeout = UINT16_MAX ; // set maximum value
} else {
timeout + = onewire_master_recovery ; // add recovery time to end of slot
}
timer_set_period ( TIM ( ONEWIRE_MASTER_TIMER ) , timeout - 1 ) ; // set time for new time slot (Trec>1, after time slot end and recovery time)
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
2017-08-02 13:44:49 +02:00
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)
2017-03-28 12:38:43 +02:00
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
2017-08-01 19:17:22 +02: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
}
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 ;
}
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
2017-03-28 12:38:43 +02:00
timer_set_counter ( TIM ( ONEWIRE_MASTER_TIMER ) , 0 ) ; // reset counter
2017-08-02 13:44:49 +02:00
uint16_t timeout = TIM_CCR3 ( TIM ( ONEWIRE_MASTER_TIMER ) ) ; // time until new slot (= end of slot+recovery)
if ( UINT16_MAX - timeout < onewire_master_recovery ) { // catch integer overflow
timeout = UINT16_MAX ; // set maximum value
} else {
timeout + = onewire_master_recovery ; // add recovery time to end of slot
}
timer_set_period ( TIM ( ONEWIRE_MASTER_TIMER ) , timeout - 1 ) ; // set time for new time slot (Trec>1, after time slot end and recovery time)
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
2017-08-02 13:44:49 +02:00
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)
2017-03-28 12:38:43 +02:00
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
2017-08-01 19:17:22 +02: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
}
if ( ONEWIRE_STATE_ERROR = = onewire_master_state ) { // an error occurred
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
{
2017-08-01 19:17:22 +02:00
if ( NULL = = data | | 0 = = length ) { // check input
2017-03-28 12:38:43 +02:00
return 0 ; // wrong input
}
uint8_t crc = 0x00 ; // initial value
2017-08-01 19:17:22 +02: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
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 ;
}
2017-08-01 19:17:22 +02:00
bool onewire_master_function_read ( uint8_t function , uint8_t * data , uint32_t bits )
2017-03-28 12:38:43 +02:00
{
// send function command
buffer_size = 8 ; // function command is only one byte
2017-08-01 19:17:22 +02:00
buffer = & function ; // 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
}
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
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
buffer_size = 8 ; // function command is only one byte
2017-08-01 19:17:22 +02:00
buffer = & function ; // 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
}
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
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)
}
// return ROM code
uint64_t code = 0 ;
2017-08-01 19:17:22 +02:00
for ( uint32_t i = 0 ; i < 8 ; i + + ) {
2017-03-28 12:38:43 +02:00
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
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
}
if ( conflict_last > = 64 ) { // no previous conflict has been detected
* code = 0 ; // restart search codes
}
2017-08-02 15:20:01 +02:00
buffer = bits ; // buffer to read up to two bits
2017-03-28 12:38:43 +02:00
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
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
2017-08-02 13:44:49 +02:00
timer_disable_irq ( TIM ( ONEWIRE_MASTER_TIMER ) , TIM_DIER_CC1IE ) ; // disable all compare interrupt
2017-03-28 12:38:43 +02:00
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
}
2017-08-02 13:44:49 +02:00
if ( onewire_master_parasite & & ( ONEWIRE_STATE_ERROR = = onewire_master_state | | ONEWIRE_STATE_DONE = = onewire_master_state ) ) {
gpio_set_mode ( GPIO ( ONEWIRE_MASTER_PORT ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_PUSHPULL , GPIO ( ONEWIRE_MASTER_PIN ) ) ; // provide parasite power
} else {
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)
}
} else if ( timer_get_flag ( TIM ( ONEWIRE_MASTER_TIMER ) , TIM_SR_CC1IF ) ) { // compare event happened for master pull low end for read
2017-03-28 12:38:43 +02:00
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
2017-08-02 13:44:49 +02:00
gpio_set ( GPIO ( ONEWIRE_MASTER_PORT ) , GPIO ( ONEWIRE_MASTER_PIN ) ) ; // pull signal high to end time slot
if ( onewire_master_parasite ) { // provide power during recovery time
gpio_set_mode ( GPIO ( ONEWIRE_MASTER_PORT ) , GPIO_MODE_OUTPUT_50_MHZ , GPIO_CNF_OUTPUT_PUSHPULL , GPIO ( ONEWIRE_MASTER_PIN ) ) ; // provide parasite power
}
2017-03-28 12:38:43 +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
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
}
}