1-wire: add option to use interrupt redirection
This commit is contained in:
parent
b8fcf17af9
commit
62cc65d954
|
@ -12,8 +12,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/** library for 1-wire protocol as master (code)
|
||||
* @file onewire_master.c
|
||||
/** library for 1-wire protocol as master
|
||||
* @file
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @date 2017-2018
|
||||
* @note peripherals used: timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio
|
||||
|
@ -35,14 +35,20 @@
|
|||
|
||||
/* own libraries */
|
||||
#include "global.h" // help macros
|
||||
#include "interrupt.h" // runtime interrupt table
|
||||
#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 */
|
||||
#define ONEWIRE_MASTER_TIMER 5 /**< timer ID */
|
||||
/** @} */
|
||||
|
||||
/** 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
|
||||
|
||||
/** state of 1-Wire communication */
|
||||
volatile enum {
|
||||
ONEWIRE_STATE_IDLE, /**< no current communication */
|
||||
|
@ -59,6 +65,106 @@ 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 */
|
||||
#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
|
||||
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)
|
||||
{
|
||||
|
@ -86,6 +192,11 @@ void onewire_master_setup(void)
|
|||
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
|
||||
|
@ -101,6 +212,16 @@ void onewire_master_release(void)
|
|||
|
||||
// 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)
|
||||
|
@ -390,94 +511,3 @@ bool onewire_master_rom_match(uint64_t code)
|
|||
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_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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/** library for 1-wire protocol as master (API)
|
||||
* @file onewire_master.h
|
||||
/** library for 1-wire protocol as master
|
||||
* @file
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @date 2017-2018
|
||||
* @note peripherals used: timer @ref onewire_master_timer, GPIO @ref onewire_master_gpio
|
||||
|
|
Loading…
Reference in New Issue