From 64500ab11ab76d2309608f8e02a1dd9658963b3e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Oct 2012 14:04:57 -0700 Subject: [PATCH] altos: Add attiny architecture files These are designed to work with the ATtiny85 processor, but can presuambly be easily adapted to others in that series Signed-off-by: Keith Packard --- src/attiny/ao_arch.h | 82 +++++++++++++ src/attiny/ao_arch_funcs.h | 125 +++++++++++++++++++ src/attiny/ao_clock.c | 114 +++++++++++++++++ src/attiny/ao_eeprom_tiny.c | 71 +++++++++++ src/attiny/ao_exti.c | 37 ++++++ src/attiny/ao_exti.h | 34 ++++++ src/attiny/ao_i2c_attiny.c | 238 ++++++++++++++++++++++++++++++++++++ src/attiny/ao_led.c | 63 ++++++++++ src/attiny/ao_spi_attiny.c | 123 +++++++++++++++++++ 9 files changed, 887 insertions(+) create mode 100644 src/attiny/ao_arch.h create mode 100644 src/attiny/ao_arch_funcs.h create mode 100644 src/attiny/ao_clock.c create mode 100644 src/attiny/ao_eeprom_tiny.c create mode 100644 src/attiny/ao_exti.c create mode 100644 src/attiny/ao_exti.h create mode 100644 src/attiny/ao_i2c_attiny.c create mode 100644 src/attiny/ao_led.c create mode 100644 src/attiny/ao_spi_attiny.c diff --git a/src/attiny/ao_arch.h b/src/attiny/ao_arch.h new file mode 100644 index 00000000..c34206e6 --- /dev/null +++ b/src/attiny/ao_arch.h @@ -0,0 +1,82 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ARCH_H_ +#define _AO_ARCH_H_ + +#include +#include +#include +#include + +#define F_CPU 8000000UL // 8 MHz + +/* + * AVR definitions and code fragments for AltOS + */ + +#define AO_STACK_SIZE 116 + +/* Various definitions to make GCC look more like SDCC */ + +#define ao_arch_naked_declare __attribute__((naked)) +#define ao_arch_naked_define +#define __pdata +#define __data +#define __xdata +#define __code const +#define __reentrant +#define __critical +#define __interrupt(n) +#define __at(n) + +#define ao_arch_reboot() /* XXX */ + +#define ao_arch_nop() asm("nop") + +#define ao_arch_interrupt(n) /* nothing */ + +#undef putchar +#undef getchar +#define putchar(c) ao_putchar(c) +#define getchar ao_getchar + +#define ao_arch_cpu_idle() do { \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + } while (0) + +#define ao_arch_critical(b) do { cli(); do { b } while (0); sei(); } while (0) + +#define ao_mutex_get(m) +#define ao_mutex_put(m) + +void +ao_delay_until(uint16_t target); + +/* We can't hit 100 Hz, but we can hit 125 */ +#define AO_HERTZ 125 + +void +ao_eeprom_read(uint16_t addr, void *buf, uint16_t len); + +void +ao_eeprom_write(uint16_t addr, void *buf, uint16_t len); + +#endif /* _AO_ARCH_H_ */ diff --git a/src/attiny/ao_arch_funcs.h b/src/attiny/ao_arch_funcs.h new file mode 100644 index 00000000..8c9d1ae6 --- /dev/null +++ b/src/attiny/ao_arch_funcs.h @@ -0,0 +1,125 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* + * ao_spi.c + */ + +#define ao_spi_get_mask(reg,mask,bus,speed) do { \ + (reg) &= ~(mask); \ + } while (0) + +#define ao_spi_put_mask(reg,mask,bus) do { \ + (reg) |= (mask); \ + } while (0) + +#define ao_spi_get_bit(reg,bit,pin,bus,speed) do { \ + (pin) = 0; \ + } while (0) + +#define ao_spi_put_bit(reg,bit,pin,bus) do { \ + (pin) = 1; \ + } while (0) + + +#define ao_gpio_token_paster(x,y) x ## y +#define ao_gpio_token_evaluator(x,y) ao_gpio_token_paster(x,y) + +#define ao_gpio_set(port, bit, pin, v) do { \ + if (v) \ + PORTB |= (1 << bit); \ + else \ + PORTB &= ~(1 << bit); \ + } while (0) + +/* + * The SPI mutex must be held to call either of these + * functions -- this mutex covers the entire SPI operation, + * from chip select low to chip select high + */ + +#define ao_enable_output(port, bit, pin, v) do { \ + ao_gpio_set(port, bit, pin, v); \ + ao_gpio_token_evaluator(DDR,port) |= (1 << bit); \ + } while (0) + + +void +ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant; + +void +ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant; + +#define ao_spi_send(block, len, bus) ao_spi_send_bus(block, len) +#define ao_spi_recv(block, len, bus) ao_spi_recv_bus(block, len) + +void +ao_spi_init(void); + +#define ao_spi_get(bus, speed) +#define ao_spi_put(bus) + +#define ao_spi_init_cs(port, mask) do { \ + PORTB |= (mask); \ + DDRB |= (mask); \ + } while (0) + +/* I2C */ + +void +ao_i2c_get(uint8_t i2c_index); + +uint8_t +ao_i2c_start_bus(uint8_t address); + +#define ao_i2c_start(i,a) ao_i2c_start_bus(a) + +void +ao_i2c_put(uint8_t i2c_index); + +uint8_t +ao_i2c_send_bus(void *block, uint16_t len, uint8_t stop); + +#define ao_i2c_send(b,l,i,s) ao_i2c_send_bus(b,l.s) + +uint8_t +ao_i2c_send_fixed_bus(uint8_t value, uint16_t len, uint8_t stop); + +#define ao_i2c_send_fixed(v,l,i,s) ao_i2c_send_fixed_bus(v,l.s) + +uint8_t +ao_i2c_recv_bus(void *block, uint16_t len, uint8_t stop); + +#define ao_i2c_recv(b,l,i,s) ao_i2c_recv_bus(b,l.s) + +void +ao_i2c_init(void); + +/* notask.c */ + +uint8_t +ao_sleep(__xdata void *wchan); + +void +ao_wakeup(__xdata void *wchan); + +extern alt_t ao_max_height; + +extern void ao_report_altitude(void); + +void ao_delay_us(uint16_t us); + diff --git a/src/attiny/ao_clock.c b/src/attiny/ao_clock.c new file mode 100644 index 00000000..a381b47f --- /dev/null +++ b/src/attiny/ao_clock.c @@ -0,0 +1,114 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +volatile AO_TICK_TYPE ao_tick_count; +static volatile AO_TICK_TYPE ao_wakeup_count; + +ISR(TIMER1_COMPA_vect) +{ + PORTB ^= 2; + ++ao_tick_count; + if ((int16_t) (ao_tick_count - ao_wakeup_count) >= 0) + ao_wakeup((void *) &ao_tick_count); +} + +uint16_t +ao_time(void) +{ + uint16_t r; + + cli(); + r = ao_tick_count; + sei(); + return r; +} + +void +ao_timer_init(void) +{ + cli(); + CLKPR = (1 << CLKPCE); + CLKPR = 0; + sei(); + + /* Overall division ratio is 512 * 125, + * so our 8MHz base clock ends up as a 125Hz + * clock + */ + TCCR1 = ((1 << CTC1) | /* Clear timer on match */ + (0 << PWM1A) | /* Not PWM mode */ + (0 << COM1A0) | /* Don't change output pins */ + (0 << COM1A1) | /* ... */ + (1 << CS13) | /* Prescale by 512 */ + (0 << CS12) | /* ... */ + (1 << CS11) | /* ... */ + (0 << CS10)); /* ... */ + GTCCR = ((0 << PWM1B) | /* Not PWM mode */ + (0 << COM1B1) | /* Don't change output pins */ + (0 << COM1B0) | /* ... */ + (0 << FOC1B) | /* Don't force output compare */ + (0 << FOC1A) | /* ... */ + (0 << PSR1)); /* Don't bother to reset scaler */ + + OCR1A = 0; + OCR1B = 0; + OCR1C = 124; /* Divide by as many 5s as we can (5^3 = 125) */ + + TIMSK = ((1 << OCIE1A) | /* Enable TIMER1_COMPA interrupt */ + (0 << OCIE1B) | /* Disable TIMER1_COMPB interrupt */ + (0 << TOIE1)); /* Disable TIMER1_OVF interrupt */ + DDRB |= 2; +} + +#define PER_LOOP 8 +#define US_LOOPS ((AVR_CLOCK / 1000000) / PER_LOOP) + +void ao_delay_us(uint16_t us) +{ +#if US_LOOPS > 1 + us *= US_LOOPS; +#endif + for (;;) { + ao_arch_nop(); + ao_arch_nop(); + ao_arch_nop(); + --us; + /* A bit funky to keep the optimizer + * from short-circuiting the test */ + if (!((uint8_t) (us | (us >> 8)))) + break; + } +} + +void +ao_delay_until(uint16_t target) +{ + cli(); + ao_wakeup_count = target; + while ((int16_t) (target - ao_tick_count) > 0) + ao_sleep((void *) &ao_tick_count); + sei(); +} + +void +ao_delay(uint16_t ticks) +{ + ao_delay_until(ao_time() + ticks); +} + diff --git a/src/attiny/ao_eeprom_tiny.c b/src/attiny/ao_eeprom_tiny.c new file mode 100644 index 00000000..83014183 --- /dev/null +++ b/src/attiny/ao_eeprom_tiny.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +static void +ao_eeprom_wait(void) +{ + /* Wait for previous write to complete */ + while (EECR & (1 << EEPE)) + ; +} + +static uint8_t +ao_eeprom_read_byte(uint16_t addr) +{ + uint8_t v; + + ao_eeprom_wait(); + EEAR = addr; + cli(); + EECR |= (1 << EERE); + v = EEDR; + sei(); + return v; +} + +static void +ao_eeprom_write_byte(uint16_t addr, uint8_t v) +{ + ao_eeprom_wait(); + EECR = (0 << EEPM1) | (0 << EEPM0); + EEAR = addr; + EEDR = v; + cli(); + EECR |= (1 << EEMPE); + EECR |= (1 << EEPE); + sei(); +} + +void +ao_eeprom_read(uint16_t addr, void *buf, uint16_t len) +{ + uint8_t *b = buf; + + while (len--) + *b++ = ao_eeprom_read_byte(addr++); +} + +void +ao_eeprom_write(uint16_t addr, void *buf, uint16_t len) +{ + uint8_t *b = buf; + + while (len--) + ao_eeprom_write_byte(addr++, *b++); +} diff --git a/src/attiny/ao_exti.c b/src/attiny/ao_exti.c new file mode 100644 index 00000000..0ca10ca4 --- /dev/null +++ b/src/attiny/ao_exti.c @@ -0,0 +1,37 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +static void (*pcint_callback)(void); +static uint8_t pcint_mask; + +ISR(PCINT0_vect) +{ + if (PINB & pcint_mask) + (*pcint_callback)(); +} + +void +ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void)) +{ + pcint_callback = callback; + pcint_mask = (1 << pin); + ao_exti_disable(PORTB, pin); + GIMSK |= (1 << PCIE); +} diff --git a/src/attiny/ao_exti.h b/src/attiny/ao_exti.h new file mode 100644 index 00000000..2ea4f47d --- /dev/null +++ b/src/attiny/ao_exti.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_EXTI_H_ +#define _AO_EXTI_H_ + +void +ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void)); + +#define ao_exti_setup(port, pin, mode, callback) ao_exti_setup_port(pin, mode, callback) + +#define ao_exti_enable(gpio, pin) (PCMSK |= (1 << (pin))) + +#define ao_exti_disable(gpio, pin) (PCMSK &= ~(1 << (pin))) + +#define ao_exti_init() + +#define AO_EXTI_MODE_RISING 1 + +#endif /* _AO_EXTI_H_ */ diff --git a/src/attiny/ao_i2c_attiny.c b/src/attiny/ao_i2c_attiny.c new file mode 100644 index 00000000..2ee44fd2 --- /dev/null +++ b/src/attiny/ao_i2c_attiny.c @@ -0,0 +1,238 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +/* + * ATtiny USI as an I2C interface + */ + +#define I2C_USICR ((0 << USISIE) | /* No start condition interrupt */ \ + (0 << USIOIE) | /* No counter overflow interrupt */ \ + (1 << USIWM1) | /* Two-wire mode */ \ + (0 << USIWM0) | /* ... */ \ + (1 << USICS1) | /* Software clock strobe */ \ + (0 << USICS0) | /* ... */ \ + (1 << USICLK)) /* ... */ \ + +#define I2C_USICR_TICK (I2C_USICR | (1 << USITC)) /* Toggle the clock on every write */ + +#define I2C_USISR_1BIT ((1<4.7μs */ +#define T4_TWI 4 /* >4.0μs */ + +static inline void ao_i2c_transfer(uint8_t sr) +{ + USISR = sr; + for (;;) { + ao_delay_us(T2_TWI); + + /* Clock high */ + USICR = I2C_USICR_TICK; + + /* Wait for clock high (clock stretching) */ + ao_delay_us(T4_TWI); + while(!(I2C_PIN & (1< + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +__pdata uint8_t ao_led_enable; + +#define LED_PORT PORTB +#define LED_DDR DDRB + +void +ao_led_on(uint8_t colors) +{ + LED_PORT |= (colors & ao_led_enable); +} + +void +ao_led_off(uint8_t colors) +{ + LED_PORT &= ~(colors & ao_led_enable); +} + +void +ao_led_set(uint8_t colors) +{ + LED_PORT = (LED_PORT & ~(ao_led_enable)) | (colors & ao_led_enable); +} + +void +ao_led_toggle(uint8_t colors) +{ + LED_PORT ^= (colors & ao_led_enable); +} + +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant +{ + ao_led_on(colors); + ao_delay(ticks); + ao_led_off(colors); +} + +void +ao_led_init(uint8_t enable) +{ + ao_led_enable = enable; + LED_PORT &= ~enable; + LED_DDR |= enable; +} diff --git a/src/attiny/ao_spi_attiny.c b/src/attiny/ao_spi_attiny.c new file mode 100644 index 00000000..064876d7 --- /dev/null +++ b/src/attiny/ao_spi_attiny.c @@ -0,0 +1,123 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +/* + * ATtiny USI as a SPI interface + */ + +/* + * Transfer one byte in/out of the USI interface + */ + +/* Three wire mode */ +#define SPI_USICR_WM ((0 << USIWM1) | (1 << USIWM0)) +#define SPI_USICR_CS ((1 << USICS1) | (0 << USICS0) | (1 << USICLK)) + +#define SPI_USICR_FAST_2 ((1 << USIWM0) | (1 << USITC)) +#define SPI_USICR_FAST_1 ((1 << USIWM0) | (1 << USITC) | (1 << USICLK)) + + +static uint8_t +ao_spi_transfer(uint8_t i) +{ + /* Load data register */ + USIDR = i; + +#if 1 + USISR = (1 << USIOIF); + do { + USICR = SPI_USICR_WM | SPI_USICR_CS | (1 << USITC); + } while ((USISR & (1 << USIOIF)) == 0); +#else + /* 8 clocks */ + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; + + USICR = SPI_USICR_FAST_1; + USICR = SPI_USICR_FAST_2; +#endif + + /* Pull data from the port */ + return USIDR; +} + +/* Send bytes over SPI. + * + * This just polls; the SPI is set to go as fast as possible, + * so using interrupts would take way too long + */ +void +ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant +{ + uint8_t *d = block; + + while (len--) + ao_spi_transfer (*d++); +} + +/* Receive bytes over SPI. + * + * Poll, sending zeros and reading data back + */ +void +ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant +{ + uint8_t *d = block; + + while (len--) + *d++ = ao_spi_transfer (0xff); +} + +/* + * Initialize USI + * + * Chip select is the responsibility of the caller + */ + +void +ao_spi_init(void) +{ +#if 1 + USICR = (1 << USIWM0) | (1 << USICS1) | (1 << USICLK); +#else + USICR = SPI_USICR_FAST_2; +#endif + SPI_DIR &= ~(1 << DDB0); /* DI */ + SPI_DIR |= (1 << DDB1); /* DO */ + SPI_DIR |= (1 << DDB2); /* SCLK */ + SPI_DIR |= (1 << DDB3); /* CS */ +} -- 2.30.2