diff options
Diffstat (limited to 'src/attiny')
| -rw-r--r-- | src/attiny/ao_arch.h | 82 | ||||
| -rw-r--r-- | src/attiny/ao_arch_funcs.h | 125 | ||||
| -rw-r--r-- | src/attiny/ao_clock.c | 114 | ||||
| -rw-r--r-- | src/attiny/ao_eeprom_tiny.c | 71 | ||||
| -rw-r--r-- | src/attiny/ao_exti.c | 37 | ||||
| -rw-r--r-- | src/attiny/ao_exti.h | 34 | ||||
| -rw-r--r-- | src/attiny/ao_i2c_attiny.c | 238 | ||||
| -rw-r--r-- | src/attiny/ao_led.c | 63 | ||||
| -rw-r--r-- | src/attiny/ao_spi_attiny.c | 123 | 
9 files changed, 887 insertions, 0 deletions
| 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 <keithp@keithp.com> + * + * 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 <stdio.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/sleep.h> + +#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 <keithp@keithp.com> + * + * 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 <keithp@keithp.com> + * + * 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> + +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 <keithp@keithp.com> + * + * 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> + +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 <keithp@keithp.com> + * + * 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> +#include <ao_exti.h> + +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 <keithp@keithp.com> + * + * 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 <keithp@keithp.com> + * + * 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> + +/* + * 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<<USISIF)|	/* Clear start condition flag */ \ +			 (1<<USIOIF)|	/* Clear overflow flag */	\ +			 (1<<USIPF)|	/* Clear stop condition flag */	\ +			 (1<<USIDC)|	/* Clear data collision flag */	\ +			 (0xE<<USICNT0)) /* Set counter value to 0xe */ + +#define I2C_USISR_8BIT	((1<<USISIF)|	/* Clear start condition flag */ \ +			 (1<<USIOIF)|	/* Clear overflow flag */	\ +			 (1<<USIPF)|	/* Clear stop condition flag */	\ +			 (1<<USIDC)|	/* Clear data collision flag */	\ +			 (0x0<<USICNT0)) /* Set counter value to 0 */ + +#define T2_TWI    5 		/* >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<<I2C_PIN_SCL))) +			; + +		/* Clock low */ +		USICR = I2C_USICR_TICK; + +		/* Check for transfer complete */ +		if (USISR & (1 << USIOIF)) +			break; +	} +	ao_delay_us(T2_TWI); +} + +static inline uint8_t ao_i2c_get_byte(uint8_t sr) +{ +	uint8_t	ret; + +	/* Set SDA to input */ +	I2C_DIR &= ~(1<<I2C_PIN_SDA); + +	ao_i2c_transfer(sr); + +	ret = USIDR; +	USIDR = 0xff; + +	/* Set SDA to output */ +	I2C_DIR |= (1<<I2C_PIN_SDA); + +	return ret; +} + +static uint8_t +ao_i2c_write_byte(uint8_t byte) +{ +	/* Pull SCL low */ +	I2C_PORT &= ~(1<<I2C_PIN_SCL); + +	/* Write the byte */ +	USIDR = byte; +       +	/* Clock and verify (N)ACK from slave */ + +	ao_i2c_transfer(I2C_USISR_8BIT); + +	if (ao_i2c_get_byte(I2C_USISR_1BIT) & 0x80) +		return 0; + +	return 1; +} + +static uint8_t +ao_i2c_read_byte(uint8_t ack) +{ +	uint8_t	ret; + +	/* Read the data */ +	ret = ao_i2c_get_byte(I2C_USISR_8BIT); + +	/* Ack it */ +	USIDR = ack; +	ao_i2c_transfer(I2C_USISR_8BIT); + +	return ret; +} + +uint8_t +ao_i2c_start_bus(uint8_t address) +{ +	/* Release SCL to ensure that (repeated) Start can be performed */ + +	I2C_PORT |= (1<<I2C_PIN_SCL); + +	while( !(I2C_PORT & (1<<I2C_PIN_SCL)) ) +		; +	ao_delay_us(T2_TWI); + +	/* Generate Start Condition */ + +	/* Pull SDA low */ +	I2C_PORT &= ~(1<<I2C_PIN_SDA); +	ao_delay_us(T4_TWI);                          + +	/* Pull SCL low */ +	I2C_PORT &= ~(1<<I2C_PIN_SCL); + +	/* Raise SDA */ +	I2C_PORT |= (1<<I2C_PIN_SDA); + +	return ao_i2c_write_byte(address); +} + +static void +ao_i2c_stop_bus(void) +{ +	/* Pull SDA low. */ +	I2C_PORT &= ~(1<<I2C_PIN_SDA); + +	/* Release SCL. */ +	I2C_PORT |= (1<<I2C_PIN_SCL); + +	/* Wait for SCL to go high */ +	while( !(I2C_PIN & (1<<I2C_PIN_SCL)) ); +	ao_delay_us(T4_TWI); + +	/* Raise SDA */ +	I2C_PORT |= (1<<I2C_PIN_SDA); +	ao_delay_us(T2_TWI); +} + +/* 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 + */ +uint8_t +ao_i2c_send_bus(void __xdata *block, uint16_t len, uint8_t stop) +{ +	uint8_t	*d = block; + +	while (len--) +		if (!ao_i2c_write_byte (*d++)) +			return 0; +	if (stop) +		ao_i2c_stop_bus(); +	return 1; +} + +/* 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 + */ +uint8_t +ao_i2c_send_fixed_bus(uint8_t d, uint16_t len, uint8_t stop) +{ +	while (len--) +		if (!ao_i2c_write_byte (d)) +			return 0; +	if (stop) +		ao_i2c_stop_bus(); +	return 1; +} + +/* Receive bytes over SPI. + * + * Poll, sending zeros and reading data back + */ +uint8_t +ao_i2c_recv_bus(void __xdata *block, uint16_t len, uint8_t stop) +{ +	uint8_t	*d = block; + +	while (len--) +		*d++ = ao_i2c_read_byte (len ? 0x00 : 0xff); +	if (stop) +		ao_i2c_stop_bus(); +	return 1; +} + +/* + * Initialize USI + * + * Chip select is the responsibility of the caller + */ + +void +ao_i2c_init(void) +{ +	/* Pull-ups on SDA and SCL */ +	I2C_PORT |= (1<<I2C_PIN_SDA); +	I2C_PORT |= (1<<I2C_PIN_SCL); +   +	/* SCL and SDA are outputs */ +	I2C_DIR  |= (1<<I2C_PIN_SCL); +	I2C_DIR  |= (1<<I2C_PIN_SDA); +   +	USIDR =  0xFF; +	USICR =  I2C_USICR; +} diff --git a/src/attiny/ao_led.c b/src/attiny/ao_led.c new file mode 100644 index 00000000..27bbea69 --- /dev/null +++ b/src/attiny/ao_led.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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 <keithp@keithp.com> + * + * 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> + +/* + * 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 */ +} | 
