This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
projects:arduino_with_dragon_attiny13 [2020/09/21 13:10] – [Getting started] admin | projects:arduino_with_dragon_attiny13 [2020/10/11 19:20] (current) – admin | ||
---|---|---|---|
Line 88: | Line 88: | ||
void loop() { | void loop() { | ||
for (int i=0; i <= 255; i++) { | for (int i=0; i <= 255; i++) { | ||
- | digitalWrite(P2_PB3, | + | digitalWrite(P2_PB3, |
- | digitalWrite(P5_PB0, | + | digitalWrite(P5_PB0, |
- | digitalWrite(P6_PB1, | + | digitalWrite(P6_PB1, |
- | digitalWrite(P7_PB2, | + | digitalWrite(P7_PB2, |
delay(500); | delay(500); | ||
} | } | ||
Line 97: | Line 97: | ||
</ | </ | ||
- | Now you can easy verify if all pins are correctly controlled: Pin 2 should show every 0.5 second a change, Pin 5 should show every second, | + | Now you can easy verify if all pins are correctly controlled: Pin 2 should show every 0.5 second a change, Pin 5 should show every second, |
+ | |||
+ | ===== Burst Controller ===== | ||
+ | <code c> | ||
+ | /** | ||
+ | * ESD burst control | ||
+ | * Controllersoftware for switching output pins in a sequence | ||
+ | * based on a trigger from one input pin. | ||
+ | * | ||
+ | * The output pins control 3 high voltage relays and one | ||
+ | * trigger output for measurement purposes. | ||
+ | * | ||
+ | * Input pin uses gpio and timer based interrupt to handle | ||
+ | * debouncing and signal edge processing. This simplifies | ||
+ | * processing a great deal. | ||
+ | * | ||
+ | * Hardware is based on the ATTINY13 8-bit microcontroller. | ||
+ | * Development was done with Arduino IDE, extended with the | ||
+ | * MicroCore, installed via: | ||
+ | * Arduino Preferences -> Additional Boards Manager URLs | ||
+ | | ||
+ | * And then selected via Tools -> Board -> MicroCore -> ATtiny13 | ||
+ | * The device is programmed using ISP programming with the AVR Dragon. | ||
+ | * From within Arduino the ATtiny13 can then be programmed with the Upload | ||
+ | * button. The selected programmer is the DragonISP. | ||
+ | * | ||
+ | * You need to edit the programmers.txt file in Arduino: | ||
+ | | ||
+ | * | ||
+ | * See here for details: | ||
+ | | ||
+ | * | ||
+ | * For pinout, see following page: | ||
+ | * https:// | ||
+ | * | ||
+ | * License: MIT | ||
+ | * Author: Marc Nijdam 10-10-2020 | ||
+ | */ | ||
+ | |||
+ | |||
+ | #define ARRAY_SIZE(x) | ||
+ | |||
+ | #define P1_PB5_NC 5 | ||
+ | #define P2_PB3_TRIGOUT 3 | ||
+ | #define P3_PB4_TOGGLESW 4 | ||
+ | #define P5_PB0_CHARGE 0 | ||
+ | #define P6_PB1_DSCHRG 1 | ||
+ | #define P7_PB2_ALLOFF 2 | ||
+ | |||
+ | #define STOP 255 | ||
+ | |||
+ | /** | ||
+ | * pin name and active state | ||
+ | */ | ||
+ | const struct { | ||
+ | const uint8_t pin; // pin name | ||
+ | const uint8_t das; // default active state | ||
+ | } io[] = { | ||
+ | [0] = {P7_PB2_ALLOFF ,1}, // bit 0, active high | ||
+ | [1] = {P2_PB3_TRIGOUT, | ||
+ | [2] = {P6_PB1_DSCHRG ,0}, // bit 2, active low | ||
+ | [3] = {P5_PB0_CHARGE ,0}, // bit 3, active low | ||
+ | [4] = {P1_PB5_NC ,1} // reset pin | ||
+ | |||
+ | }; | ||
+ | |||
+ | /** | ||
+ | | ||
+ | * | ___> discharge ----------> | ||
+ | * || __> trigout + pulldown -> (i.e. on high, trigger goes up.) | ||
+ | * ||| _> all off ------------> | ||
+ | * |||| | ||
+ | * 0000 | ||
+ | * | ||
+ | * 0: not active | ||
+ | * 1: active | ||
+ | */ | ||
+ | const struct { | ||
+ | const uint8_t bits; // bitpattern for gpio output pins | ||
+ | const uint16_t dur; // duration in ms | ||
+ | } patterns[] = { | ||
+ | {0b0000, | ||
+ | {0b0000, | ||
+ | {0b1000, | ||
+ | {STOP, 0}, /* | ||
+ | {0b0101, | ||
+ | {0b0110, 5000}, /* / \ */ | ||
+ | {0b0010, | ||
+ | {0b0000, | ||
+ | {0b0000, | ||
+ | }; | ||
+ | |||
+ | /* counter which points to index of array */ | ||
+ | volatile uint8_t processing; | ||
+ | volatile uint8_t pat_idx; | ||
+ | volatile uint8_t mode; // 0: charge, 1: discharge | ||
+ | |||
+ | void setup() { | ||
+ | /* initialize digital in- and output pins */ | ||
+ | pinMode(P3_PB4_TOGGLESW, | ||
+ | for (uint8_t i=0; i < ARRAY_SIZE(io); | ||
+ | pinMode(io[i].pin, | ||
+ | } | ||
+ | |||
+ | mode = digitalRead(P3_PB4_TOGGLESW); | ||
+ | |||
+ | /* initialize flag, 0: processing not initiated, 1: processing */ | ||
+ | processing = 0; | ||
+ | |||
+ | /* enable interrupt from PB4 */ | ||
+ | setup_gpio_interrupt(P3_PB4_TOGGLESW); | ||
+ | enable_pcint_interrupt(); | ||
+ | |||
+ | /* enable interrupt from timer for semi-automatic with 1x 0.12ms debounce */ | ||
+ | setup_timer_interrupt(1); | ||
+ | |||
+ | /* enable all interrupts */ | ||
+ | sei(); | ||
+ | } | ||
+ | |||
+ | // the loop function runs over and over again forever | ||
+ | void loop() { | ||
+ | if (!processing) { | ||
+ | processing = 1; | ||
+ | process_sequence(mode); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void process_sequence(uint8_t md) { | ||
+ | pat_idx = md ? ARRAY_SIZE(patterns) - 1 : 0; | ||
+ | for (;;) { | ||
+ | set_bits(patterns[pat_idx].bits); | ||
+ | /* wait ms duration, unless interrupted by switch */ | ||
+ | if (wait_ms(patterns[pat_idx].dur)) return; | ||
+ | pat_idx += 1 - 2*md; | ||
+ | if (patterns[pat_idx].bits == STOP) return; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Set bit pattern onto gpio output | ||
+ | * take into account active state | ||
+ | */ | ||
+ | void set_bits(uint8_t bits) { | ||
+ | for (uint8_t i=0; i < ARRAY_SIZE(io); | ||
+ | digitalWrite(io[i].pin, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | uint8_t wait_ms(uint16_t d) { | ||
+ | unsigned long ts = millis() + d; | ||
+ | for (;;) { | ||
+ | if (millis() >= ts) return 0; | ||
+ | if (!processing) return 1; | ||
+ | delay(1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void setup_gpio_interrupt(uint8_t port) { | ||
+ | pinMode(port, | ||
+ | MCUCR |= (1<< | ||
+ | MCUCR &= ~(1<< | ||
+ | PCMSK |= (1<< | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * enable PCINT interrupt | ||
+ | */ | ||
+ | void enable_pcint_interrupt(void) { | ||
+ | GIMSK |= (1<< | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * disable PCINT interrupt | ||
+ | */ | ||
+ | void disable_pcint_interrupt(void) { | ||
+ | GIMSK &= ~(1<< | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @brief setup timer interrupt | ||
+ | * @param duration in unit of +/- 0.125ms | ||
+ | */ | ||
+ | void setup_timer_interrupt(uint8_t d) { | ||
+ | TCCR0A |= _BV(WGM01); // set timer counter mode to CTC | ||
+ | TCCR0B |= _BV(CS02)|_BV(CS00); | ||
+ | OCR0A = d; // set Timer' | ||
+ | } | ||
+ | |||
+ | void enable_timer_interrupt(void) { | ||
+ | TIMSK0 |= _BV(OCIE0A); | ||
+ | } | ||
+ | |||
+ | void disable_timer_interrupt(void) { | ||
+ | TIMSK0 &= ~_BV(OCIE0A); | ||
+ | } | ||
+ | |||
+ | ISR(PCINT0_vect) // Interrupt on Int0 vector | ||
+ | { | ||
+ | disable_pcint_interrupt(); | ||
+ | /* prevent false interrupt from switch, only allow toggle */ | ||
+ | if (mode != digitalRead(P3_PB4_TOGGLESW)) { | ||
+ | mode = digitalRead(P3_PB4_TOGGLESW); | ||
+ | processing = 0; | ||
+ | } | ||
+ | /* use timer interrupt for debouncing */ | ||
+ | enable_timer_interrupt(); | ||
+ | } | ||
+ | |||
+ | ISR(TIM0_COMPA_vect) // Interrupt on Timer0 vector | ||
+ | { | ||
+ | disable_timer_interrupt(); | ||
+ | enable_pcint_interrupt(); | ||
+ | } | ||
+ | </ |