Skip to content

Commit

Permalink
Port failsafe watching code to raw avr-gcc
Browse files Browse the repository at this point in the history
More interrupty now
  • Loading branch information
dustin committed Apr 19, 2016
1 parent be2a068 commit fa4f41f
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
18 changes: 18 additions & 0 deletions c/avr/failsafe/Makefile
@@ -0,0 +1,18 @@
CC=avr-gcc
OBJCOPY=avr-objcopy
MICRONUCLEUS=/Users/dsal/Library/Arduino15/packages/digistump/tools/micronucleus/2.0a4/micronucleus
CFLAGS=-Wall -Os -DF_CPU=16000000L -mmcu=attiny85
LDFLAGS=-mmcu=attiny85

failsafe.hex: failsafe.elf
avr-objcopy -j .text -j .data -O ihex failsafe.elf failsafe.hex
avr-size --format=avr --mcu=attiny85 failsafe.elf

failsafe.elf: failsafe.o
${CC} $(LDFLAGS) -o failsafe.elf failsafe.o

clean:
rm failsafe.{elf,hex,o}

install: failsafe.hex
$(MICRONUCLEUS) --run failsafe.hex
110 changes: 110 additions & 0 deletions c/avr/failsafe/failsafe.c
@@ -0,0 +1,110 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <stdbool.h>

#define PPM_PIN PB0
#define OUT_PIN PB1
#define BUTTON_PIN PB2
#define SHUTDOWN_PIN PB3

// a bit under a second
#define BUTTON_OVERFLOWS 30

volatile bool disabling = false;
volatile bool failed = false;
volatile uint8_t prevb = 0xFF;
volatile int overflows = 0;
volatile bool watching_button = false;


void isr_svc_button() {
if (watching_button) {
watching_button = false;
TIMSK &= ~_BV(TOIE0); // disable timer overflow
} else {
watching_button = true;
TIMSK |= _BV(TOIE0); // enable overflow interupt
TCNT0 = 0;
overflows = 0;
}
}

ISR(PCINT0_vect) {
wdt_reset();

uint8_t vals = PINB ^ prevb;
if (vals & _BV(PPM_PIN)) {
failed = false;
}

if (vals & _BV(BUTTON_PIN)) {
isr_svc_button();
}
}

ISR(WDT_vect) {
wdt_reset();
failed = true;
}

ISR(TIM0_OVF_vect) {
if (++overflows >= BUTTON_OVERFLOWS) {
disabling = true;
TIMSK &= ~_BV(TOIE0);
watching_button = false;
}
}

void writeOut(bool failed) {
if (failed) {
DDRB |= _BV(OUT_PIN);
} else {
DDRB &= ~_BV(OUT_PIN);
}
}

void disable() {
// Maybe like, a beep or something?
PORTB |= _BV(OUT_PIN);
_delay_ms(250);
PORTB &= ~_BV(OUT_PIN);

DDRB |= _BV(SHUTDOWN_PIN);
DDRB &= ~_BV(OUT_PIN);
cli();
// No more watchdog
_WD_CONTROL_REG = 0;
// Stop watching inputs
PCMSK &= ~(_BV(PCINT0) | _BV(PCINT2));
sei();
}

int main() {
DDRB = _BV(OUT_PIN) | _BV(SHUTDOWN_PIN);
PORTB |= _BV(BUTTON_PIN);

cli();
GIMSK |= _BV(PCIE);
PCMSK |= _BV(PCINT0);

// I use the timer later. Set up 1024 prescaler.
TCCR0B |= _BV(CS02) | _BV(CS00); // 1024 prescaler

// The watchdog timer is used for detecting failsafe state.
wdt_reset();
_WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE);
// Enable WDT Interrupt, and Set Timeout to ~1 seconds,
_WD_CONTROL_REG = _BV(WDIE) | _BV(WDP2) | _BV(WDP1);
sei();

for (;;) {
// just process interrupts
asm("sleep");
if (disabling) {
disable();
disabling = false;
}
}
}

0 comments on commit fa4f41f

Please sign in to comment.