summaryrefslogtreecommitdiff
path: root/src/avr
diff options
context:
space:
mode:
Diffstat (limited to 'src/avr')
-rw-r--r--src/avr/ao_adc_avr.c7
-rw-r--r--src/avr/ao_arch.h24
-rw-r--r--src/avr/ao_avr_stdio.c11
-rw-r--r--src/avr/ao_pins.h9
-rw-r--r--src/avr/ao_pwmin.c90
-rw-r--r--src/avr/ao_pwmin.h20
-rw-r--r--src/avr/ao_serial_avr.c43
-rw-r--r--src/avr/ao_spi_slave.c14
-rw-r--r--src/avr/ao_usb_avr.c46
9 files changed, 192 insertions, 72 deletions
diff --git a/src/avr/ao_adc_avr.c b/src/avr/ao_adc_avr.c
index 3a262977..231512b2 100644
--- a/src/avr/ao_adc_avr.c
+++ b/src/avr/ao_adc_avr.c
@@ -16,6 +16,7 @@
*/
#include "ao.h"
+#include "ao_pwmin.h"
volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
volatile __data uint8_t ao_data_head;
@@ -93,9 +94,13 @@ ISR(ADC_vect)
value = ADCL;
value |= (ADCH << 8);
ao_data_ring[ao_data_head].adc.adc[ao_adc_channel] = value;
- if (++ao_adc_channel < NUM_ADC)
+ if (++ao_adc_channel < NUM_ADC - HAS_ICP3_COUNT)
ao_adc_start();
else {
+#if HAS_ICP3_COUNT
+ /* steal last adc channel for pwm input */
+ ao_data_ring[ao_data_head].adc.adc[ao_adc_channel] = ao_icp3_count;
+#endif
ADCSRA = ADCSRA_INIT;
ao_data_ring[ao_data_head].tick = ao_time();
ao_data_head = ao_data_ring_next(ao_data_head);
diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h
index a14d0ade..d626e830 100644
--- a/src/avr/ao_arch.h
+++ b/src/avr/ao_arch.h
@@ -37,7 +37,9 @@
* AVR definitions and code fragments for AltOS
*/
+#ifndef AO_STACK_SIZE
#define AO_STACK_SIZE 116
+#endif
/* Various definitions to make GCC look more like SDCC */
@@ -110,7 +112,6 @@ extern uint8_t ao_cpu_sleep_disable;
asm("push r9" "\n\t" "push r8" "\n\t" "push r7" "\n\t" "push r6" "\n\t" "push r5"); \
asm("push r4" "\n\t" "push r3" "\n\t" "push r2" "\n\t" "push r1" "\n\t" "push r0"); \
asm("in r0, __SREG__" "\n\t" "push r0"); \
- sei(); \
} while (0)
#define ao_arch_save_stack() do { \
@@ -122,16 +123,28 @@ extern uint8_t ao_cpu_sleep_disable;
#define ao_arch_isr_stack() /* nothing */
-#define ao_arch_cpu_idle() do { \
- if (!ao_cpu_sleep_disable) \
+/* Idle the CPU (if possible) waiting for an interrupt. Enabling
+ * interrupts and sleeping the CPU must be adjacent to eliminate race
+ * conditions. In all cases, we execute a single nop with interrupts
+ * enabled
+ */
+#define ao_arch_wait_interrupt() do { \
+ if (!ao_cpu_sleep_disable) { \
+ sleep_enable(); \
+ sei(); \
sleep_cpu(); \
+ sleep_disable(); \
+ } else { \
+ sei(); \
+ } \
+ ao_arch_nop(); \
+ cli(); \
} while (0)
#define ao_arch_restore_stack() do { \
uint8_t sp_l, sp_h; \
sp_l = (uint16_t) ao_cur_task->sp; \
sp_h = ((uint16_t) ao_cur_task->sp) >> 8; \
- cli(); \
asm("out __SP_H__,%0" : : "r" (sp_h) ); \
asm("out __SP_L__,%0" : : "r" (sp_l) ); \
asm("pop r0" "\n\t" \
@@ -148,6 +161,9 @@ extern uint8_t ao_cpu_sleep_disable;
#define ao_arch_critical(b) do { cli(); do { b } while (0); sei(); } while (0)
+#define ao_arch_block_interrupts() cli()
+#define ao_arch_release_interrupts() sei()
+
#define AO_TELESCIENCE_NUM_ADC 12
#endif /* _AO_ARCH_H_ */
diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c
index 2765853a..f9c0f88c 100644
--- a/src/avr/ao_avr_stdio.c
+++ b/src/avr/ao_avr_stdio.c
@@ -20,16 +20,7 @@
int
stdio_put(char c, FILE *stream)
{
- if (ao_cur_task && ao_num_stdios)
- putchar(c);
- else
- {
- if (c == '\n')
- stdio_put('\r', stream);
- loop_until_bit_is_set(UCSR1A, UDRE1);
- UDR1 = c;
- }
-
+ putchar(c);
return 0;
}
diff --git a/src/avr/ao_pins.h b/src/avr/ao_pins.h
index bc423ff7..a08e87fa 100644
--- a/src/avr/ao_pins.h
+++ b/src/avr/ao_pins.h
@@ -32,7 +32,7 @@
#define HAS_BEEP 0
#endif
-#ifdef TELESCIENCE
+#if defined(TELESCIENCE) || defined(TELESCIENCE_PWM)
#define LEDS_AVAILABLE 0
#define HAS_USB 1
#define HAS_LOG 1
@@ -47,6 +47,11 @@
#define AVR_VCC_5V 0
#define AVR_VCC_3V3 1
#define AVR_CLOCK 8000000UL
+#ifdef TELESCIENCE_PWM
+ #define HAS_ICP3_COUNT 1
+#else
+ #define HAS_ICP3_COUNT 0
+#endif
#define SPI_CS_PORT PORTE
#define SPI_CS_DIR DDRE
@@ -64,6 +69,7 @@
#endif
#ifdef TELEPYRO
+ #define AO_STACK_SIZE 104
#define LEDS_AVAILABLE 0
#define HAS_USB 1
#define HAS_LOG 0
@@ -81,6 +87,7 @@
#define IS_COMPANION 1
#define HAS_ORIENT 0
#define ao_storage_pos_t uint16_t
+ #define HAS_ICP3_COUNT 0
#define AVR_VCC_5V 0
#define AVR_VCC_3V3 1
diff --git a/src/avr/ao_pwmin.c b/src/avr/ao_pwmin.c
new file mode 100644
index 00000000..84397357
--- /dev/null
+++ b/src/avr/ao_pwmin.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2012 Robert D. Garbee <robert@gag.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_pwmin.h"
+
+/*
+ * This code implements a PWM input using ICP3.
+ *
+ * The initial use is to measure wind speed in the ULA/Ball summer intern
+ * project payload developed at Challenger Middle School.
+ */
+
+volatile __data uint16_t ao_icp3_count = 0;
+volatile __data uint16_t ao_icp3_last = 0;
+
+uint16_t ao_icp3(void)
+{
+ uint16_t v;
+ ao_arch_critical(
+ v = ao_icp3_count;
+ );
+ return v;
+}
+
+static void
+ao_pwmin_display(void) __reentrant
+{
+ /* display the most recent value */
+ printf("icp 3: %5u\n", ao_icp3());
+
+}
+
+
+ISR(TIMER3_CAPT_vect)
+{
+
+ uint8_t lo = ICR3L;
+ uint8_t hi = ICR3H;
+ uint16_t ao_icp3_this = (hi <<8) | lo;
+
+ /* handling counter rollovers */
+ if (ao_icp3_this >= ao_icp3_last)
+ ao_icp3_count = ao_icp3_this - ao_icp3_last;
+ else
+ ao_icp3_count = ao_icp3_this + (65536 - ao_icp3_last);
+ ao_icp3_last = ao_icp3_this;
+}
+
+__code struct ao_cmds ao_pwmin_cmds[] = {
+ { ao_pwmin_display, "p\0PWM input" },
+ { 0, NULL },
+};
+
+void
+ao_pwmin_init(void)
+{
+ /* do hardware setup here */
+ TCCR3A = ((0 << WGM31) | /* normal mode, OCR3A */
+ (0 << WGM30)); /* normal mode, OCR3A */
+ TCCR3B = ((1 << ICNC3) | /* input capture noise canceler on */
+ (0 << ICES3) | /* input capture on falling edge (don't care) */
+ (0 << WGM33) | /* normal mode, OCR3A */
+ (0 << WGM32) | /* normal mode, OCR3A */
+ (3 << CS30)); /* clk/64 from prescaler */
+
+
+
+ TIMSK3 = (1 << ICIE3); /* Interrupt on input compare */
+
+ /* set the spike filter bit in the TCCR3B register */
+
+ ao_cmd_register(&ao_pwmin_cmds[0]);
+}
+
+
diff --git a/src/avr/ao_pwmin.h b/src/avr/ao_pwmin.h
new file mode 100644
index 00000000..8097d399
--- /dev/null
+++ b/src/avr/ao_pwmin.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2012 Robert D. Garbee <robert@gag.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.
+ */
+
+void ao_pwmin_init(void);
+
+extern volatile __data uint16_t ao_icp3_count;
diff --git a/src/avr/ao_serial_avr.c b/src/avr/ao_serial_avr.c
index dcee246c..e0f813d5 100644
--- a/src/avr/ao_serial_avr.c
+++ b/src/avr/ao_serial_avr.c
@@ -59,52 +59,51 @@ ISR(USART1_UDRE_vect)
ao_wakeup(&ao_serial1_tx_fifo);
}
-char
-ao_serial1_getchar(void) __critical
-{
- char c;
- cli();
- while (ao_fifo_empty(ao_serial1_rx_fifo))
- ao_sleep(&ao_serial1_rx_fifo);
- ao_fifo_remove(ao_serial1_rx_fifo, c);
- sei();
- return c;
-}
-
#if USE_SERIAL_1_STDIN
-char
-ao_serial1_pollchar(void) __critical
+int
+_ao_serial1_pollchar(void)
{
char c;
- cli();
if (ao_fifo_empty(ao_serial1_rx_fifo)) {
sei();
return AO_READ_AGAIN;
}
ao_fifo_remove(ao_serial1_rx_fifo,c);
- sei();
return c;
}
#endif
+char
+ao_serial1_getchar(void) __critical
+{
+ char c;
+
+ ao_arch_block_interrupts();
+ while (ao_fifo_empty(ao_serial1_rx_fifo))
+ ao_sleep(&ao_serial1_rx_fifo);
+ ao_fifo_remove(ao_serial1_rx_fifo, c);
+ ao_arch_release_interrupts();
+ return c;
+}
+
void
-ao_serial1_putchar(char c) __critical
+ao_serial1_putchar(char c)
{
- cli();
+ ao_arch_block_interrupts();
while (ao_fifo_full(ao_serial1_tx_fifo))
ao_sleep(&ao_serial1_tx_fifo);
ao_fifo_insert(ao_serial1_tx_fifo, c);
ao_serial_tx1_start();
- sei();
+ ao_arch_release_interrupts();
}
void
ao_serial1_drain(void) __critical
{
- cli();
+ ao_arch_block_interrupts();
while (!ao_fifo_empty(ao_serial1_tx_fifo))
ao_sleep(&ao_serial1_tx_fifo);
- sei();
+ ao_arch_release_interrupts();
}
static const struct {
@@ -155,7 +154,7 @@ ao_serial_init(void)
(1 << RXCIE1) | /* Enable receive interrupts */
(1 << UDRIE1)); /* Enable transmit empty interrupts */
#if USE_SERIAL_1_STDIN
- ao_add_stdio(ao_serial1_pollchar,
+ ao_add_stdio(_ao_serial1_pollchar,
ao_serial1_putchar,
NULL);
#endif
diff --git a/src/avr/ao_spi_slave.c b/src/avr/ao_spi_slave.c
index b742d29a..15e9924d 100644
--- a/src/avr/ao_spi_slave.c
+++ b/src/avr/ao_spi_slave.c
@@ -18,22 +18,24 @@
#include "ao.h"
uint8_t
-ao_spi_slave_recv(uint8_t *buf, uint8_t len)
+ao_spi_slave_recv(void *buf, uint16_t len)
{
+ uint8_t *b = buf;
while (len--) {
while (!(SPSR & (1 << SPIF)))
if ((PINB & (1 << PINB0)))
return 0;
- *buf++ = SPDR;
+ *b++ = SPDR;
}
return 1;
}
void
-ao_spi_slave_send(uint8_t *buf, uint8_t len)
+ao_spi_slave_send(void *buf, uint16_t len)
{
+ uint8_t *b = buf;
while (len--) {
- SPDR = *buf++;
+ SPDR = *b++;
while (!(SPSR & (1 << SPIF)))
if ((PINB & (1 << PINB0)))
return;
@@ -44,9 +46,8 @@ ao_spi_slave_send(uint8_t *buf, uint8_t len)
static uint8_t ao_spi_slave_running;
-ISR(PCINT0_vect)
+ISR(PCINT0_vect, ISR_BLOCK)
{
- cli();
#if SPI_SLAVE_PIN_0_3
if ((PINB & (1 << PORTB0)) == 0)
#endif
@@ -61,7 +62,6 @@ ISR(PCINT0_vect)
} else {
ao_spi_slave_running = 0;
}
- sei();
}
void
diff --git a/src/avr/ao_usb_avr.c b/src/avr/ao_usb_avr.c
index 9ba407af..bd75b17d 100644
--- a/src/avr/ao_usb_avr.c
+++ b/src/avr/ao_usb_avr.c
@@ -411,7 +411,7 @@ ao_usb_ep0(void)
/* Wait for a free IN buffer */
static void
-ao_usb_in_wait(void)
+_ao_usb_in_wait(void)
{
for (;;) {
/* Check if the current buffer is writable */
@@ -419,7 +419,6 @@ ao_usb_in_wait(void)
if (UEINTX & (1 << RWAL))
break;
- cli();
/* Wait for an IN buffer to be ready */
for (;;) {
UENUM = AO_USB_IN_EP;
@@ -430,24 +429,24 @@ ao_usb_in_wait(void)
}
/* Ack the interrupt */
UEINTX &= ~(1 << TXINI);
- sei();
}
}
/* Queue the current IN buffer for transmission */
static void
-ao_usb_in_send(void)
+_ao_usb_in_send(void)
{
UENUM = AO_USB_IN_EP;
UEINTX &= ~(1 << FIFOCON);
}
void
-ao_usb_flush(void) __critical
+ao_usb_flush(void)
{
if (!ao_usb_running)
return;
+ ao_arch_block_interrupts();
/* Anytime we've sent a character since
* the last time we flushed, we'll need
* to send a packet -- the only other time
@@ -457,18 +456,20 @@ ao_usb_flush(void) __critical
*/
if (!ao_usb_in_flushed) {
ao_usb_in_flushed = 1;
- ao_usb_in_wait();
- ao_usb_in_send();
+ _ao_usb_in_wait();
+ _ao_usb_in_send();
}
+ ao_arch_release_interrupts();
}
void
-ao_usb_putchar(char c) __critical __reentrant
+ao_usb_putchar(char c)
{
if (!ao_usb_running)
return;
- ao_usb_in_wait();
+ ao_arch_block_interrupts();
+ _ao_usb_in_wait();
/* Queue a byte */
UENUM = AO_USB_IN_EP;
@@ -476,14 +477,15 @@ ao_usb_putchar(char c) __critical __reentrant
/* Send the packet when full */
if ((UEINTX & (1 << RWAL)) == 0)
- ao_usb_in_send();
+ _ao_usb_in_send();
ao_usb_in_flushed = 0;
+ ao_arch_release_interrupts();
}
-static char
+int
_ao_usb_pollchar(void)
{
- char c;
+ uint8_t c;
uint8_t intx;
if (!ao_usb_running)
@@ -518,24 +520,14 @@ _ao_usb_pollchar(void)
}
char
-ao_usb_pollchar(void)
+ao_usb_getchar(void)
{
- char c;
- cli();
- c = _ao_usb_pollchar();
- sei();
- return c;
-}
+ int c;
-char
-ao_usb_getchar(void) __critical
-{
- char c;
-
- cli();
+ ao_arch_block_interrupts();
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
- sei();
+ ao_arch_release_interrupts();
return c;
}
@@ -668,5 +660,5 @@ ao_usb_init(void)
#if USB_DEBUG
ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
#endif
- ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+ ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
}