Root/atusb/fw/board_app.c

1/*
2 * fw/board_app.c - Board-specific functions (for the application)
3 *
4 * Written 2011, 2013 by Werner Almesberger
5 * Copyright 2011, 2013 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stddef.h>
15#include <stdbool.h>
16#include <stdint.h>
17
18#include <avr/io.h>
19#include <avr/interrupt.h>
20
21#define F_CPU 8000000UL
22#include <util/delay.h>
23
24#include "usb.h"
25#include "at86rf230.h"
26#include "spi.h"
27#include "mac.h"
28#include "board.h"
29
30
31static volatile uint32_t timer_h = 0; /* 2^(16+32) / 8 MHz = ~1.1 years */
32
33
34void reset_cpu(void)
35{
36    WDTCSR = 1 << WDE;
37}
38
39
40uint8_t read_irq(void)
41{
42    return PIN(IRQ_RF);
43}
44
45
46void slp_tr(void)
47{
48    SET(SLP_TR);
49    CLR(SLP_TR);
50}
51
52
53ISR(TIMER1_OVF_vect)
54{
55    timer_h++;
56}
57
58
59uint64_t timer_read(void)
60{
61    uint32_t high;
62    uint8_t low, mid;
63
64    do {
65        if (TIFR1 & (1 << TOV1)) {
66            TIFR1 = 1 << TOV1;
67            timer_h++;
68        }
69        high = timer_h;
70        low = TCNT1L;
71        mid = TCNT1H;
72    }
73    while (TIFR1 & (1 << TOV1));
74
75    /*
76     * We need all these casts because the intermediate results are handled
77     * as if they were signed and thus get sign-expanded. Sounds wrong-ish.
78     */
79    return (uint64_t) high << 16 | (uint64_t) mid << 8 | (uint64_t) low;
80}
81
82
83void timer_init(void)
84{
85    /* configure timer 1 as a free-running CLK counter */
86
87    TCCR1A = 0;
88    TCCR1B = 1 << CS10;
89
90    /* enable timer overflow interrupt */
91
92    TIMSK1 = 1 << TOIE1;
93}
94
95
96bool gpio(uint8_t port, uint8_t data, uint8_t dir, uint8_t mask, uint8_t *res)
97{
98    EIMSK = 0; /* recover INT_RF to ATUSB_GPIO_CLEANUP or an MCU reset */
99
100    switch (port) {
101    case 1:
102        DDRB = (DDRB & ~mask) | dir;
103        PORTB = (PORTB & ~mask) | data;
104        break;
105    case 2:
106        DDRC = (DDRC & ~mask) | dir;
107        PORTC = (PORTC & ~mask) | data;
108        break;
109    case 3:
110        DDRD = (DDRD & ~mask) | dir;
111        PORTD = (PORTD & ~mask) | data;
112        break;
113    default:
114        return 0;
115    }
116
117    /* disable the UART so that we can meddle with these pins as well. */
118    spi_off();
119    _delay_ms(1);
120
121    switch (port) {
122    case 1:
123        res[0] = PINB;
124        res[1] = PORTB;
125        res[2] = DDRB;
126        break;
127    case 2:
128        res[0] = PINC;
129        res[1] = PORTC;
130        res[2] = DDRC;
131        break;
132    case 3:
133        res[0] = PIND;
134        res[1] = PORTD;
135        res[2] = DDRD;
136        break;
137    }
138
139    return 1;
140}
141
142
143void gpio_cleanup(void)
144{
145    EIMSK = 1 << 0;
146}
147
148
149static void done(void *user)
150{
151    led(0);
152}
153
154
155uint8_t irq_serial;
156
157#if defined(ATUSB) || defined(HULUSB)
158ISR(INT0_vect)
159#endif
160#ifdef RZUSB
161ISR(TIMER1_CAPT_vect)
162#endif
163{
164    if (mac_irq) {
165        if (mac_irq())
166            return;
167    }
168    if (eps[1].state == EP_IDLE) {
169        led(1);
170        irq_serial = (irq_serial+1) | 0x80;
171        usb_send(&eps[1], &irq_serial, 1, done, NULL);
172    }
173}
174

Archive Download this file



interactive