2 * Copyright © 2011 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 #include <avr/interrupt.h>
22 #define F_CPU 16000000UL // 16 MHz
24 #define F_CPU 8000000UL // 8 MHz
26 #include <util/delay.h>
36 ISR(TIMER1_COMPA_vect)
44 TCCR1A = ((0 << WGM11) | /* CTC mode, OCR1A */
45 (0 << WGM10)); /* CTC mode, OCR1A */
46 TCCR1B = ((0 << ICNC1) | /* no input capture noise canceler */
47 (0 << ICES1) | /* input capture on falling edge (don't care) */
48 (0 << WGM13) | /* CTC mode, OCR1A */
49 (1 << WGM12) | /* CTC mode, OCR1A */
50 (3 << CS10)); /* clk/64 from prescaler */
53 OCR1A = 2500; /* 16MHz clock */
55 OCR1A = 1250; /* 8MHz clock */
58 TIMSK1 = (1 << OCIE1A); /* Interrupt on compare match */
64 /* disable RC clock */
65 CLKSEL0 &= ~(1 << RCE);
68 PLLCSR &= ~(1 << PLLE);
70 /* Enable external clock */
71 CLKSEL0 |= (1 << EXTE);
73 /* wait for external clock to be ready */
74 while ((CLKSTA & (1 << EXTON)) == 0)
77 /* select external clock */
78 CLKSEL0 |= (1 << CLKS);
80 /* Disable the clock prescaler */
82 CLKPR = (1 << CLKPCE);
86 /* Set up the PLL to use the crystal */
88 /* Use primary system clock as PLL source */
89 PLLFRQ = ((0 << PINMUX) | /* Use primary clock */
90 (0 << PLLUSB) | /* No divide by 2 for USB */
91 (0 << PLLTM0) | /* Disable high speed timer */
92 (0x4 << PDIV0)); /* 48MHz PLL clock */
94 /* Set the frequency of the crystal */
96 PLLCSR |= (1 << PINDIV); /* For 16MHz crystal on Teensy board */
98 PLLCSR &= ~(1 << PINDIV); /* For 8MHz crystal on TeleScience board */
102 PLLCSR |= (1 << PLLE);
103 while (!(PLLCSR & (1 << PLOCK)))
110 TCCR0A = ((1 << COM0A1) |
119 TCCR0B = ((0 << WGM02) |
128 #define ADC_CHANNEL 0x25 /* Channel ADC13 */
129 #define ADC_CHANNEL_LOW(c) (((c) & 0x1f) << MUX0)
130 #define ADC_CHANNEL_HIGH(c) ((((c) & 0x20) >> 5) << MUX5)
132 #define ADCSRA_INIT ((1 << ADEN) | /* Enable ADC */ \
133 (0 << ADATE) | /* No auto ADC trigger */ \
134 (1 << ADIE) | /* Enable interrupt */ \
135 (6 << ADPS0)) /* Prescale clock by 64 */
137 #define ADCSRB_INIT ((0 << ADHSM) | /* No high-speed mode */ \
138 (0 << ACME) | /* Some comparitor thing */ \
139 (0 << ADTS0)) /* Free running mode (don't care) */
144 ADMUX = ((0 << REFS1) | /* AVcc reference */
145 (1 << REFS0) | /* AVcc reference */
146 (1 << ADLAR) | /* Left-shift results */
147 (ADC_CHANNEL_LOW(ADC_CHANNEL))); /* Select channel */
149 ADCSRB = ADCSRB_INIT | ADC_CHANNEL_HIGH(ADC_CHANNEL);
151 ADCSRA = ADCSRA_INIT | (1 << ADSC); /* Start conversion */
157 ADCSRA = ADCSRA_INIT;
158 ADCSRB = ADCSRB_INIT;
162 #define AO_STACK_SIZE 128
164 uint8_t new_stack[512];
167 #define PUSH8(stack, val) (*--(stack) = (val))
169 #define PUSH16(stack, val) PUSH8(stack, ((uint16_t) (val))); PUSH8(stack, ((uint16_t) (val)) >> 8)
181 LEDPORT ^= (1 << LEDOUT);
193 init_stack(void (*f) (void))
195 uint8_t *stack = new_stack + AO_STACK_SIZE;
202 /* Clear register values */
207 /* SREG with interrupts enabled */
210 stack_count = stack - new_stack;
214 switch_stack(void) __attribute__((naked));
223 a = (uint16_t) function;
226 asm("push %0" : : "r" (l));
227 asm("push %0" : : "r" (h));
231 asm("push r31; push r30");
232 asm("push r29; push r28; push r27; push r26; push r25");
233 asm("push r24; push r23; push r22; push r21; push r20");
234 asm("push r19; push r18; push r17; push r16; push r15");
235 asm("push r14; push r13; push r12; push r11; push r10");
236 asm("push r9; push r8; push r7; push r6; push r5");
237 asm("push r4; push r3; push r2; push r1; push r0");
238 asm("in r0, __SREG__" "\n\t"
241 uint8_t *sp = (new_stack + stack_count);
244 sp_l = (uint16_t) sp;
245 sp_h = ((uint16_t) sp) >> 8;
246 asm("out __SP_H__,%0" : : "r" (sp_h) );
247 asm("out __SP_L__,%0" : : "r" (sp_l) );
252 asm("pop r0; pop r1; pop r2; pop r3; pop r4");
253 asm("pop r5; pop r6; pop r7; pop r8; pop r9");
254 asm("pop r10; pop r11; pop r12; pop r13; pop r14");
255 asm("pop r15; pop r16; pop r17; pop r18; pop r19");
256 asm("pop r20; pop r21; pop r22; pop r23; pop r24");
257 asm("pop r25; pop r26; pop r27; pop r28; pop r29");
258 asm("pop r30; pop r31");
278 LEDDDR |= (1 << LEDDDRPIN);