From 36c6d74048283d27c890054814eee2cb39b7cbb7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 6 Feb 2016 22:47:23 +1100 Subject: altos: Add power management APIs This provides sequenced suspend/resume functionality, allowing modules to register for power management at configuration time. Signed-off-by: Keith Packard --- src/kernel/ao.h | 10 +++++++ src/kernel/ao_power.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/kernel/ao_power.h | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/kernel/ao_power.c create mode 100644 src/kernel/ao_power.h (limited to 'src/kernel') diff --git a/src/kernel/ao.h b/src/kernel/ao.h index 59a469ae..a794ba71 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -124,6 +124,16 @@ ao_timer_init(void); void ao_clock_init(void); +#if AO_POWER_MANAGEMENT +/* Go to low power clock */ +void +ao_clock_suspend(void); + +/* Restart full-speed clock */ +void +ao_clock_resume(void); +#endif + /* * ao_mutex.c */ diff --git a/src/kernel/ao_power.c b/src/kernel/ao_power.c new file mode 100644 index 00000000..bead5944 --- /dev/null +++ b/src/kernel/ao_power.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2016 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 struct ao_power *head, *tail; + +void +ao_power_register(struct ao_power *power) +{ + if (power->registered) + return; + power->registered = TRUE; + if (tail) { + tail->next = power; + power->prev = tail; + tail = power; + } else { + head = tail = power; + } +#ifdef AO_LED_POWER + ao_led_on(AO_LED_POWER); +#endif +} + +void +ao_power_unregister(struct ao_power *power) +{ + if (!power->registered) + return; + power->registered = FALSE; + if (power->prev) + power->prev->next = power->next; + else + head = power->next; + if (power->next) + power->next->prev = power->prev; + else + tail = power->prev; +} + +void +ao_power_suspend(void) +{ + struct ao_power *p; + +#ifdef AO_LED_POWER + ao_led_off(AO_LED_POWER); +#endif + for (p = tail; p; p = p->prev) + p->suspend(p->arg); +} + +void +ao_power_resume(void) +{ + struct ao_power *p; + + for (p = head; p; p = p->next) + p->resume(p->arg); +#ifdef AO_LED_POWER + ao_led_on(AO_LED_POWER); +#endif +} + diff --git a/src/kernel/ao_power.h b/src/kernel/ao_power.h new file mode 100644 index 00000000..98a8c1c7 --- /dev/null +++ b/src/kernel/ao_power.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 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_POWER_H_ +#define _AO_POWER_H_ + +#if AO_POWER_MANAGEMENT + +struct ao_power { + struct ao_power *prev, *next; + + void (*suspend)(void *arg); + void (*resume)(void *arg); + void *arg; + uint8_t registered; +}; + +void +ao_power_register(struct ao_power *power); + +void +ao_power_unregister(struct ao_power *power); + +void +ao_power_suspend(void); + +void +ao_power_resume(void); + +#else /* AO_POWER_MANAGEMENT */ + +#define ao_power_register(power) +#define ao_power_unregister(power) +#define ao_power_suspend() +#define ao_power_resume() + +#endif /* else AO_POWER_MANAGEMENT */ + +#endif /* _AO_POWER_H_ */ -- cgit v1.2.3 From 2ad756bd1b63a2c8450edd7001628b92279fd1b8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 7 Feb 2016 00:10:57 +1100 Subject: altos: Allow USB drivers to skip CDC-ACM -specific descriptors For devices not providing the standard CDC-ACM interface, let them skip the various descriptors and interfaces to provide a more limited set of capabilities. Signed-off-by: Keith Packard --- src/kernel/ao_product.c | 57 ++++++++++++++++++++++++++++++++++++------------- src/kernel/ao_usb.h | 12 +++++++++++ src/stmf0/ao_usb_stm.c | 24 +++++++++++++++------ 3 files changed, 72 insertions(+), 21 deletions(-) (limited to 'src/kernel') diff --git a/src/kernel/ao_product.c b/src/kernel/ao_product.c index c711a4d2..a1a9af09 100644 --- a/src/kernel/ao_product.c +++ b/src/kernel/ao_product.c @@ -33,11 +33,32 @@ const char ao_product[] = AO_iProduct_STRING; #define AO_USB_MAX_POWER 100 #endif -#ifndef AO_USB_INTERFACE_CLASS -#define AO_USB_INTERFACE_CLASS 0x02 +#ifndef AO_USB_SELF_POWER +#define AO_USB_SELF_POWER 1 +#endif + +#define AO_USB_DEVICE_CLASS_COMMUNICATION 0x02 +#define AO_USB_INTERFACE_CLASS_CONTROL_CDC 0x02 +#define AO_USB_INTERFACE_CLASS_DATA_CDC 0x0A + +#ifndef AO_USB_DEVICE_CLASS +#define AO_USB_DEVICE_CLASS AO_USB_DEVICE_CLASS_COMMUNICATION +#endif + +#ifndef AO_USB_INTERFACE_CLASS_DATA +#define AO_USB_INTERFACE_CLASS_CONTROL AO_USB_INTERFACE_CLASS_CONTROL_CDC +#define AO_USB_INTERFACE_CLASS_DATA AO_USB_INTERFACE_CLASS_DATA_CDC #endif #include "ao_usb.h" + +#define HEADER_LEN 9 +#define CONTROL_CLASS_LEN 35 +#define DATA_LEN (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN) + +#define TOTAL_LENGTH (HEADER_LEN + AO_USB_HAS_INT * CONTROL_CLASS_LEN + DATA_LEN) +#define NUM_INTERFACES (AO_USB_HAS_INT + 1) + /* USB descriptors in one giant block of bytes */ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = { @@ -45,7 +66,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = 0x12, AO_USB_DESC_DEVICE, LE_WORD(0x0110), /* bcdUSB */ - 0x02, /* bDeviceClass */ + AO_USB_DEVICE_CLASS, /* bDeviceClass */ 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ AO_USB_CONTROL_SIZE, /* bMaxPacketSize */ @@ -60,20 +81,21 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = /* Configuration descriptor */ 0x09, AO_USB_DESC_CONFIGURATION, - LE_WORD(67), /* wTotalLength */ - 0x02, /* bNumInterfaces */ + LE_WORD(TOTAL_LENGTH), /* wTotalLength */ + NUM_INTERFACES, /* bNumInterfaces */ 0x01, /* bConfigurationValue */ 0x00, /* iConfiguration */ - 0xC0, /* bmAttributes */ + 0x80 | (AO_USB_SELF_POWER << 6), /* bmAttributes */ AO_USB_MAX_POWER >> 1, /* bMaxPower, 2mA units */ +#if AO_USB_HAS_INT /* Control class interface */ 0x09, AO_USB_DESC_INTERFACE, 0x00, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x01, /* bNumEndPoints */ - AO_USB_INTERFACE_CLASS, /* bInterfaceClass */ + AO_USB_INTERFACE_CLASS_CONTROL, /* bInterfaceClass */ 0x02, /* bInterfaceSubClass */ 0x01, /* bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */ 0x00, /* iInterface */ @@ -111,18 +133,20 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = 0x03, /* bmAttributes = intr */ LE_WORD(8), /* wMaxPacketSize */ 0xff, /* bInterval */ +#endif /* Data class interface descriptor */ 0x09, AO_USB_DESC_INTERFACE, - 0x01, /* bInterfaceNumber */ - 0x00, /* bAlternateSetting */ - 0x02, /* bNumEndPoints */ - 0x0A, /* bInterfaceClass = data */ - 0x00, /* bInterfaceSubClass */ - 0x00, /* bInterfaceProtocol */ - 0x00, /* iInterface */ - + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + AO_USB_HAS_OUT + AO_USB_HAS_IN, /* bNumEndPoints */ + AO_USB_INTERFACE_CLASS_DATA, /* bInterfaceClass = data */ + 0x00, /* bInterfaceSubClass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + +#if AO_USB_HAS_OUT /* Data EP OUT */ 0x07, AO_USB_DESC_ENDPOINT, @@ -130,7 +154,9 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = 0x02, /* bmAttributes = bulk */ LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */ 0x00, /* bInterval */ +#endif +#if AO_USB_HAS_IN /* Data EP in */ 0x07, AO_USB_DESC_ENDPOINT, @@ -138,6 +164,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = 0x02, /* bmAttributes = bulk */ LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ 0x00, /* bInterval */ +#endif /* String descriptors */ 0x04, diff --git a/src/kernel/ao_usb.h b/src/kernel/ao_usb.h index 1ce4f82f..773b5cb7 100644 --- a/src/kernel/ao_usb.h +++ b/src/kernel/ao_usb.h @@ -107,6 +107,18 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; #define AO_USB_IN_EP 5 #endif +#ifndef AO_USB_HAS_OUT +#define AO_USB_HAS_OUT 1 +#endif + +#ifndef AO_USB_HAS_IN +#define AO_USB_HAS_IN 1 +#endif + +#ifndef AO_USB_HAS_INT +#define AO_USB_HAS_INT 1 +#endif + /* * USB bulk packets can only come in 8, 16, 32 and 64 * byte sizes, so we'll use 64 for everything diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c index 691c2d56..b0f4c516 100644 --- a/src/stmf0/ao_usb_stm.c +++ b/src/stmf0/ao_usb_stm.c @@ -29,6 +29,10 @@ #error "must define AO_PA11_PA12_RMP" #endif +#ifndef AO_POWER_MANAGEMENT +#define AO_POWER_MANAGEMENT 0 +#endif + #ifndef USE_USB_STDIO #define USE_USB_STDIO 1 #endif @@ -397,6 +401,7 @@ ao_usb_set_configuration(void) { debug ("ao_usb_set_configuration\n"); +#if AO_USB_HAS_INT /* Set up the INT end point */ ao_usb_bdt[AO_USB_INT_EPR].single.addr_tx = ao_usb_int_tx_offset; ao_usb_bdt[AO_USB_INT_EPR].single.count_tx = 0; @@ -406,7 +411,9 @@ ao_usb_set_configuration(void) STM_USB_EPR_EP_TYPE_INTERRUPT, STM_USB_EPR_STAT_RX_DISABLED, STM_USB_EPR_STAT_TX_NAK); +#endif +#if AO_USB_HAS_OUT /* Set up the OUT end point */ ao_usb_bdt[AO_USB_OUT_EPR].single.addr_rx = ao_usb_out_rx_offset; ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) | @@ -417,7 +424,9 @@ ao_usb_set_configuration(void) STM_USB_EPR_EP_TYPE_BULK, STM_USB_EPR_STAT_RX_VALID, STM_USB_EPR_STAT_TX_DISABLED); +#endif +#if AO_USB_HAS_IN /* Set up the IN end point */ ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_in_tx_offset; ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = 0; @@ -427,6 +436,7 @@ ao_usb_set_configuration(void) STM_USB_EPR_EP_TYPE_BULK, STM_USB_EPR_STAT_RX_DISABLED, STM_USB_EPR_STAT_TX_NAK); +#endif ao_usb_running = 1; #if AO_USB_DIRECTIO @@ -439,7 +449,6 @@ static uint16_t int_count; static uint16_t in_count; static uint16_t out_count; static uint16_t reset_count; -static uint16_t suspend_count; /* The USB memory must be accessed in 16-bit units */ @@ -718,6 +727,7 @@ ao_usb_ep0_handle(uint8_t receive) } } +#if AO_POWER_MANAGEMENT void ao_usb_suspend(void) { @@ -734,6 +744,7 @@ ao_usb_wakeup(void) stm_usb.cntr &= ~(1 << STM_USB_CNTR_FSUSP); ao_power_resume(); } +#endif void stm_usb_isr(void) @@ -801,8 +812,8 @@ stm_usb_isr(void) debug ("\treset\n"); ao_usb_set_ep0(); } +#if AO_POWER_MANAGEMENT if (istr & (1 << STM_USB_ISTR_SUSP)) { - ++suspend_count; debug ("\tsuspend\n"); ao_usb_suspend(); } @@ -810,6 +821,7 @@ stm_usb_isr(void) debug ("\twakeup\n"); ao_usb_wakeup(); } +#endif } /* Queue the current IN buffer for transmission */ @@ -1072,8 +1084,8 @@ ao_usb_enable(void) stm_usb.cntr = ((1 << STM_USB_CNTR_CTRM) | (0 << STM_USB_CNTR_PMAOVRM) | (0 << STM_USB_CNTR_ERRM) | - (1 << STM_USB_CNTR_WKUPM) | - (1 << STM_USB_CNTR_SUSPM) | + (AO_POWER_MANAGEMENT << STM_USB_CNTR_WKUPM) | + (AO_POWER_MANAGEMENT << STM_USB_CNTR_SUSPM) | (1 << STM_USB_CNTR_RESETM) | (0 << STM_USB_CNTR_SOFM) | (0 << STM_USB_CNTR_ESOFM) | @@ -1112,8 +1124,8 @@ ao_usb_echo(void) static void ao_usb_irq(void) { - printf ("control: %d out: %d in: %d int: %d reset: %d suspend %d\n", - control_count, out_count, in_count, int_count, reset_count, suspend_count); + printf ("control: %d out: %d in: %d int: %d reset: %d\n", + control_count, out_count, in_count, int_count, reset_count); } __code struct ao_cmds ao_usb_cmds[] = { -- cgit v1.2.3 From 0bae4b25882983cd0b7950b3e80b6d93a72f0847 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Feb 2016 19:15:31 -0800 Subject: altos: Another fix for non CDC-ACM devices Need to set the bInterfaceNumber for the actual interface to zero when there isn't an INT interface before it. Signed-off-by: Keith Packard --- src/kernel/ao_product.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/kernel') diff --git a/src/kernel/ao_product.c b/src/kernel/ao_product.c index a1a9af09..4769d86e 100644 --- a/src/kernel/ao_product.c +++ b/src/kernel/ao_product.c @@ -138,7 +138,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = /* Data class interface descriptor */ 0x09, AO_USB_DESC_INTERFACE, - 0x01, /* bInterfaceNumber */ + AO_USB_HAS_INT, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ AO_USB_HAS_OUT + AO_USB_HAS_IN, /* bNumEndPoints */ AO_USB_INTERFACE_CLASS_DATA, /* bInterfaceClass = data */ -- cgit v1.2.3 From 05fcb717bfc44aba3c1cfd43281e323505a46402 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Mar 2016 13:54:58 -0800 Subject: altos/chaoskey: Add another USB endpoint to read raw data This replaces having the single output switch based on a pin value and allows us to box the device and still fetch raw data. For now, this will use a special libusb2 program, ao-chaosread, to pull bits as I haven't figure out how to make linux provide two /dev entries for one USB device. Signed-off-by: Keith Packard --- src/chaoskey-v0.1/ao_pins.h | 2 + src/drivers/ao_trng_send.c | 149 +++++++++++++++++++++++---------- src/kernel/ao_product.c | 14 +++- src/kernel/ao_usb.h | 5 ++ src/stmf0/ao_arch_funcs.h | 3 + src/stmf0/ao_usb_stm.c | 195 +++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 321 insertions(+), 47 deletions(-) (limited to 'src/kernel') diff --git a/src/chaoskey-v0.1/ao_pins.h b/src/chaoskey-v0.1/ao_pins.h index 6ec582a9..73f76307 100644 --- a/src/chaoskey-v0.1/ao_pins.h +++ b/src/chaoskey-v0.1/ao_pins.h @@ -50,7 +50,9 @@ #define AO_USB_INTERFACE_CLASS_DATA 0xff #define AO_USB_HAS_OUT 0 #define AO_USB_HAS_IN 1 +#define AO_USB_HAS_IN2 1 #define AO_USB_HAS_INT 0 +#define USE_USB_STDIO 0 #define AO_USB_SELF_POWER 0 #define AO_USB_DEVICE_ID_SERIAL 1 diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index f8222993..171a345f 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -22,54 +22,97 @@ #include #include +static struct ao_task ao_trng_send_task, ao_trng_send_raw_task; static uint8_t trng_running; static AO_TICK_TYPE trng_power_time; -/* Make sure there's at least 8 bits of variance in the samples */ -#define MIN_VARIANCE (128 * 128) - -#define DECLARE_STATS int32_t sum = 0, sum2 = 0 - -#define ADD_STATS(value) do { \ - sum += (value); \ - sum2 += (value) * (value); \ - } while(0) - -#define GOOD_STATS(i) (((sum2 - (sum * sum) / i) / i) >= MIN_VARIANCE) - #define TRNG_ENABLE_DELAY AO_MS_TO_TICKS(100) -static int -ao_trng_send_raw(uint16_t *buf) +static uint8_t random_mutex; + +static void +ao_trng_get_raw(uint16_t *buf) { uint16_t i; uint16_t t; uint16_t v; - DECLARE_STATS; - t = ao_adc_get(AO_USB_IN_SIZE>>1); /* one 16-bit value per two output bytes */ for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { v = ao_adc_ring[t]; *buf++ = v; t = (t + 1) & (AO_ADC_RING_SIZE - 1); + } + ao_adc_ack(AO_USB_IN_SIZE>>1); +} + +static void +ao_trng_send_raw(void) +{ + static uint16_t *buffer[2]; + int usb_buf_id; - ADD_STATS(v); + if (!buffer[0]) { + buffer[0] = ao_usb_alloc(); + buffer[1] = ao_usb_alloc(); + if (!buffer[0]) + ao_exit(); + } + + usb_buf_id = 0; + + for (;;) { + ao_mutex_get(&random_mutex); + if (!trng_running) { + AO_TICK_TYPE delay; + + delay = trng_power_time + TRNG_ENABLE_DELAY - ao_time(); + if (delay > TRNG_ENABLE_DELAY) + delay = TRNG_ENABLE_DELAY; + + /* Delay long enough for the HV power supply + * to stabilize so that the first bits we read + * aren't of poor quality + */ + ao_delay(delay); + trng_running = TRUE; + } +#ifdef AO_LED_TRNG_RAW + ao_led_on(AO_LED_TRNG_RAW); +#endif + ao_trng_get_raw(buffer[usb_buf_id]); +#ifdef AO_LED_TRNG_RAW + ao_led_off(AO_LED_TRNG_RAW); +#endif + ao_mutex_put(&random_mutex); + ao_usb_write2(buffer[usb_buf_id], AO_USB_IN_SIZE); + usb_buf_id = 1-usb_buf_id; } - return GOOD_STATS(AO_USB_IN_SIZE / sizeof (uint16_t)); } +/* Make sure there's at least 8 bits of variance in the samples */ +#define MIN_VARIANCE (128 * 128) + +/* Make sure the signal is spread around a bit */ +#define MAX_VARIANCE (512 * 512) + +#define ADD_STATS(value) do { \ + sum += (value); \ + sum2 += (value) * (value); \ + } while(0) + +#define VARIANCE(n) ((sum2 - (sum / (n) * sum)) / (n)) + static int -ao_trng_send_cooked(uint16_t *buf) +ao_trng_get_cooked(uint16_t *buf) { uint16_t i; uint16_t t; uint32_t *rnd = (uint32_t *) ao_adc_ring; + int32_t sum, sum2, var; - DECLARE_STATS; - + sum = sum2 = 0; t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ - for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { uint32_t v; uint16_t v1, v2; @@ -86,14 +129,13 @@ ao_trng_send_cooked(uint16_t *buf) ADD_STATS(v1); ADD_STATS(v2); } - return GOOD_STATS(2 * AO_USB_IN_SIZE / sizeof (uint16_t)); + ao_adc_ack(AO_USB_IN_SIZE); + var = VARIANCE(2 * AO_USB_IN_SIZE / sizeof (uint16_t)); + return var >= MIN_VARIANCE && var <= MAX_VARIANCE; } -static inline int -ao_send_raw(void) -{ - return !ao_gpio_get(AO_RAW_PORT, AO_RAW_BIT, AO_RAW_PIN); -} +#define AO_TRNG_START_WAIT 1024 +#define AO_TRNG_START_CHECK 32 static void ao_trng_send(void) @@ -101,13 +143,14 @@ ao_trng_send(void) static uint16_t *buffer[2]; int usb_buf_id; int good_bits; - int failed = 0; + int failed; + int s; if (!buffer[0]) { buffer[0] = ao_usb_alloc(); buffer[1] = ao_usb_alloc(); if (!buffer[0]) - return; + ao_exit(); } usb_buf_id = 0; @@ -119,7 +162,33 @@ ao_trng_send(void) ao_crc_reset(); + ao_delay(TRNG_ENABLE_DELAY); + + for (s = 0; s < AO_TRNG_START_WAIT; s++) { + if (ao_trng_get_cooked(buffer[0])) + break; + ao_delay(AO_MS_TO_TICKS(10)); + } + + /* Validate the hardware before enabling USB */ + failed = 0; + for (s = 0; s < AO_TRNG_START_CHECK; s++) { + if (!ao_trng_get_cooked(buffer[0])) { + failed++; + ao_delay(AO_MS_TO_TICKS(10)); + } + } + if (failed > AO_TRNG_START_CHECK / 4) + ao_panic(AO_PANIC_DMA); + + ao_add_task(&ao_trng_send_raw_task, ao_trng_send_raw, "trng_send_raw"); + +#ifdef AO_USB_START_DISABLED + ao_usb_enable(); +#endif + for (;;) { + ao_mutex_get(&random_mutex); if (!trng_running) { AO_TICK_TYPE delay; @@ -134,16 +203,14 @@ ao_trng_send(void) ao_delay(delay); trng_running = TRUE; } - if (ao_send_raw()) { - ao_led_on(AO_LED_TRNG_RAW); - good_bits = ao_trng_send_raw(buffer[usb_buf_id]); - ao_led_off(AO_LED_TRNG_RAW); - } else { - ao_led_on(AO_LED_TRNG_COOKED); - good_bits = ao_trng_send_cooked(buffer[usb_buf_id]); - ao_led_off(AO_LED_TRNG_COOKED); - } - ao_adc_ack(AO_USB_IN_SIZE); +#ifdef AO_LED_TRNG_COOKED + ao_led_on(AO_LED_TRNG_COOKED); +#endif + good_bits = ao_trng_get_cooked(buffer[usb_buf_id]); +#ifdef AO_LED_TRNG_COOKED + ao_led_off(AO_LED_TRNG_COOKED); +#endif + ao_mutex_put(&random_mutex); if (good_bits) { ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE); usb_buf_id = 1-usb_buf_id; @@ -159,8 +226,6 @@ ao_trng_send(void) } } -static struct ao_task ao_trng_send_task; - #if AO_POWER_MANAGEMENT static void ao_trng_suspend(void *arg) diff --git a/src/kernel/ao_product.c b/src/kernel/ao_product.c index 4769d86e..3a829b3a 100644 --- a/src/kernel/ao_product.c +++ b/src/kernel/ao_product.c @@ -54,7 +54,7 @@ const char ao_product[] = AO_iProduct_STRING; #define HEADER_LEN 9 #define CONTROL_CLASS_LEN 35 -#define DATA_LEN (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN) +#define DATA_LEN (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN + 7 * AO_USB_HAS_IN2) #define TOTAL_LENGTH (HEADER_LEN + AO_USB_HAS_INT * CONTROL_CLASS_LEN + DATA_LEN) #define NUM_INTERFACES (AO_USB_HAS_INT + 1) @@ -140,7 +140,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = AO_USB_DESC_INTERFACE, AO_USB_HAS_INT, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ - AO_USB_HAS_OUT + AO_USB_HAS_IN, /* bNumEndPoints */ + AO_USB_HAS_OUT + AO_USB_HAS_IN + AO_USB_HAS_IN2, /* bNumEndPoints */ AO_USB_INTERFACE_CLASS_DATA, /* bInterfaceClass = data */ 0x00, /* bInterfaceSubClass */ 0x00, /* bInterfaceProtocol */ @@ -166,6 +166,16 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = 0x00, /* bInterval */ #endif +#if AO_USB_HAS_IN2 + /* Data EP in 2 */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_IN2_EP|0x80, /* bEndpointAddress */ + 0x02, /* bmAttributes = bulk */ + LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ + 0x00, /* bInterval */ +#endif + /* String descriptors */ 0x04, AO_USB_DESC_STRING, diff --git a/src/kernel/ao_usb.h b/src/kernel/ao_usb.h index 773b5cb7..8f3e7813 100644 --- a/src/kernel/ao_usb.h +++ b/src/kernel/ao_usb.h @@ -105,6 +105,7 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; #ifndef AO_USB_OUT_EP #define AO_USB_OUT_EP 4 #define AO_USB_IN_EP 5 +#define AO_USB_IN2_EP 6 #endif #ifndef AO_USB_HAS_OUT @@ -119,6 +120,10 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; #define AO_USB_HAS_INT 1 #endif +#ifndef AO_USB_HAS_IN2 +#define AO_USB_HAS_IN2 0 +#endif + /* * USB bulk packets can only come in 8, 16, 32 and 64 * byte sizes, so we'll use 64 for everything diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index 8d585f80..4e3ef018 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -413,6 +413,9 @@ ao_usb_free(uint16_t *buffer); void ao_usb_write(uint16_t *buffer, uint16_t len); + +void +ao_usb_write2(uint16_t *buffer, uint16_t len); #endif /* AO_USB_DIRECTIO */ #endif /* _AO_ARCH_FUNCS_H_ */ diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c index 17e8709c..e68da8eb 100644 --- a/src/stmf0/ao_usb_stm.c +++ b/src/stmf0/ao_usb_stm.c @@ -89,23 +89,42 @@ static uint16_t ao_usb_sram_addr; static uint16_t *ao_usb_ep0_tx_buffer; static uint16_t *ao_usb_ep0_rx_buffer; +#if AO_USB_HAS_INT /* Pointer to interrupt buffer in USB memory */ static uint16_t ao_usb_int_tx_offset; +#endif /* Pointer to bulk data tx/rx buffers in USB memory */ +#if AO_USB_HAS_IN static uint16_t ao_usb_in_tx_offset; static uint16_t *ao_usb_in_tx_buffer; -static uint16_t ao_usb_out_rx_offset; -static uint16_t *ao_usb_out_rx_buffer; /* System ram shadow of USB buffer; writing individual bytes is * too much of a pain (sigh) */ static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE]; static uint8_t ao_usb_tx_count; +#endif +#if AO_USB_HAS_OUT +static uint16_t ao_usb_out_rx_offset; +static uint16_t *ao_usb_out_rx_buffer; + +/* System ram shadow of USB buffer; writing individual bytes is + * too much of a pain (sigh) */ static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE]; static uint8_t ao_usb_rx_count, ao_usb_rx_pos; +#endif +#if AO_USB_HAS_IN2 +static uint16_t ao_usb_in2_tx_offset; +static uint16_t *ao_usb_in2_tx_buffer; + +/* System ram shadow of USB buffer; writing individual bytes is + * too much of a pain (sigh) */ +static uint8_t ao_usb_tx2_buffer[AO_USB_IN_SIZE]; +static uint8_t ao_usb_tx2_count; +#endif + /* * End point register indices */ @@ -114,6 +133,7 @@ static uint8_t ao_usb_rx_count, ao_usb_rx_pos; #define AO_USB_INT_EPR 1 #define AO_USB_OUT_EPR 2 #define AO_USB_IN_EPR 3 +#define AO_USB_IN2_EPR 4 /* Marks when we don't need to send an IN packet. * This happens only when the last IN packet is not full, @@ -128,6 +148,16 @@ static uint8_t ao_usb_in_flushed; */ static uint8_t ao_usb_in_pending; +#if AO_USB_HAS_IN2 +/* Marks when we have delivered an IN packet to the hardware + * and it has not been received yet. ao_sleep on this address + * to wait for it to be delivered. + */ +static uint8_t ao_usb_in2_pending; +static uint16_t in2_count; +static uint8_t ao_usb_in2_flushed; +#endif + /* Marks when an OUT packet has been received by the hardware * but not pulled to the shadow buffer. */ @@ -343,16 +373,29 @@ ao_usb_alloc_buffers(void) ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + +#if AO_USB_HAS_INT ao_usb_int_tx_offset = ao_usb_sram_addr; ao_usb_sram_addr += AO_USB_INT_SIZE; +#endif +#if AO_USB_HAS_OUT ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); ao_usb_out_rx_offset = ao_usb_sram_addr; ao_usb_sram_addr += AO_USB_OUT_SIZE; +#endif +#if AO_USB_HAS_IN ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); ao_usb_in_tx_offset = ao_usb_sram_addr; ao_usb_sram_addr += AO_USB_IN_SIZE; +#endif + +#if AO_USB_HAS_IN2 + ao_usb_in2_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_in2_tx_offset = ao_usb_sram_addr; + ao_usb_sram_addr += AO_USB_IN_SIZE; +#endif } static void @@ -438,6 +481,18 @@ ao_usb_set_configuration(void) STM_USB_EPR_STAT_TX_NAK); #endif +#if AO_USB_HAS_IN2 + /* Set up the IN2 end point */ + ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in2_tx_offset; + ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = 0; + + ao_usb_init_ep(AO_USB_IN2_EPR, + AO_USB_IN2_EP, + STM_USB_EPR_EP_TYPE_BULK, + STM_USB_EPR_STAT_RX_DISABLED, + STM_USB_EPR_STAT_TX_NAK); +#endif + ao_usb_running = 1; #if AO_USB_DIRECTIO ao_wakeup(&ao_usb_running); @@ -581,7 +636,7 @@ hex_to_ucs2(uint32_t in, uint8_t *out) for (i = 28; i >= 0; i -= 4) { uint8_t bits = (in >> i) & 0xf; - *out++ = (bits < 10) ? ('0' + bits) : ('a' + bits); + *out++ = ((bits < 10) ? '0' : ('a' - 10)) + bits; *out++ = 0; } } @@ -835,6 +890,16 @@ stm_usb_isr(void) ao_wakeup(&ao_usb_in_pending); } break; +#if AO_USB_HAS_IN2 + case AO_USB_IN2_EPR: + ++in2_count; + _tx_dbg1("TX2 ISR", epr); + if (ao_usb_epr_ctr_tx(epr)) { + ao_usb_in2_pending = 0; + ao_wakeup(&ao_usb_in2_pending); + } + break; +#endif case AO_USB_INT_EPR: ++int_count; if (ao_usb_epr_ctr_tx(epr)) @@ -861,6 +926,7 @@ stm_usb_isr(void) #endif } +#if AO_USB_HAS_IN /* Queue the current IN buffer for transmission */ static void _ao_usb_in_send(void) @@ -939,7 +1005,90 @@ ao_usb_putchar(char c) } ao_arch_release_interrupts(); } +#endif + +#if AO_USB_HAS_IN +/* Queue the current IN buffer for transmission */ +static void +_ao_usb_in2_send(void) +{ + _tx_dbg0("in2_send start"); + debug ("send2 %d\n", ao_usb_tx_count); + while (ao_usb_in2_pending) + ao_sleep(&ao_usb_in2_pending); + ao_usb_in2_pending = 1; + if (ao_usb_tx2_count != AO_USB_IN_SIZE) + ao_usb_in2_flushed = 1; + ao_usb_copy_tx(ao_usb_tx2_buffer, ao_usb_in2_tx_buffer, ao_usb_tx2_count); + ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in_tx_offset; + ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = ao_usb_tx_count; + ao_usb_tx2_count = 0; + _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID); + _tx_dbg0("in2_send end"); +} + +/* Wait for a free IN buffer. Interrupts are blocked */ +static void +_ao_usb_in2_wait(void) +{ + for (;;) { + /* Check if the current buffer is writable */ + if (ao_usb_tx2_count < AO_USB_IN_SIZE) + break; + + _tx_dbg0("in2_wait top"); + /* Wait for an IN buffer to be ready */ + while (ao_usb_in2_pending) + ao_sleep(&ao_usb_in2_pending); + _tx_dbg0("in_wait bottom"); + } +} + +void +ao_usb_flush2(void) +{ + if (!ao_usb_running) + return; + + /* Anytime we've sent a character since + * the last time we flushed, we'll need + * to send a packet -- the only other time + * we would send a packet is when that + * packet was full, in which case we now + * want to send an empty packet + */ + ao_arch_block_interrupts(); + while (!ao_usb_in2_flushed) { + _tx_dbg0("flush2 top"); + _ao_usb_in2_send(); + _tx_dbg0("flush2 end"); + } + ao_arch_release_interrupts(); +} + +void +ao_usb_putchar2(char c) +{ + if (!ao_usb_running) + return; + + ao_arch_block_interrupts(); + _ao_usb_in2_wait(); + + ao_usb_in2_flushed = 0; + ao_usb_tx2_buffer[ao_usb_tx2_count++] = (uint8_t) c; + + /* Send the packet when full */ + if (ao_usb_tx2_count == AO_USB_IN_SIZE) { + _tx_dbg0("putchar2 full"); + _ao_usb_in2_send(); + _tx_dbg0("putchar2 flushed"); + } + ao_arch_release_interrupts(); +} +#endif +#if AO_USB_HAS_OUT static void _ao_usb_out_recv(void) { @@ -996,6 +1145,7 @@ ao_usb_getchar(void) ao_arch_release_interrupts(); return c; } +#endif #if AO_USB_DIRECTIO uint16_t * @@ -1050,6 +1200,43 @@ ao_usb_write(uint16_t *buffer, uint16_t len) _ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); ao_arch_release_interrupts(); } + +#if AO_USB_HAS_IN2 +void +ao_usb_write2(uint16_t *buffer, uint16_t len) +{ + ao_arch_block_interrupts(); + + /* Wait for everything to be ready at the same time */ + for (;;) { + /* Make sure USB is connected */ + if (!ao_usb_running) { + ao_sleep(&ao_usb_running); + continue; + } + + /* Flush any pending regular I/O */ + if (ao_usb_tx2_count) { + _ao_usb_in2_send(); + continue; + } + + /* Wait for an idle IN buffer */ + if (ao_usb_in2_pending) { + ao_sleep(&ao_usb_in2_pending); + continue; + } + break; + } + + ao_usb_in2_pending = 1; + ao_usb_in2_flushed = (len != AO_USB_IN_SIZE); + ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_packet_buffer_offset(buffer); + ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = len; + _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID); + ao_arch_release_interrupts(); +} +#endif #endif void @@ -1180,7 +1367,9 @@ ao_usb_init(void) /* Set PA11/PA12 remapping bit */ stm_syscfg.cfgr1 |= (AO_PA11_PA12_RMP << STM_SYSCFG_CFGR1_PA11_PA12_RMP); +#ifndef AO_USB_START_DISABLED ao_usb_enable(); +#endif #if AO_USB_DEVICE_ID_SERIAL ao_usb_serial_init(); -- cgit v1.2.3 From d1af180c2d2a2caf1e13f00d83f2b86ba26de27f Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Sat, 5 Mar 2016 17:38:19 -0800 Subject: altos: Fixed timing of panic display LED to be readable When we don't have a beeper, there's no way to signal a 'warble' for panic. So, elide that bit. Second, panic can't use the scheduler and timer because those may not be running (or may have failed), and so it uses a delay loop. Add a configurable scale value to the panic loop so that the LED blinks can be read. For stm32f0 devices, scale that by the sysclk value to automatically make them of reasonable length. --- src/kernel/ao_panic.c | 11 ++++++++--- src/stmf0/ao_arch.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/kernel') diff --git a/src/kernel/ao_panic.c b/src/kernel/ao_panic.c index c29cd8fe..e280f98c 100644 --- a/src/kernel/ao_panic.c +++ b/src/kernel/ao_panic.c @@ -38,10 +38,15 @@ ao_panic_delay(uint8_t n) { uint8_t i = 0, j = 0; - while (n--) + while (n--) { +#ifdef AO_PANIC_DELAY_SCALE + uint8_t s = AO_PANIC_DELAY_SCALE; + while (s--) +#endif while (--j) while (--i) ao_arch_nop(); + } } void @@ -56,16 +61,16 @@ ao_panic(uint8_t reason) ao_arch_block_interrupts(); for (;;) { ao_panic_delay(20); +#if HAS_BEEP for (n = 0; n < 5; n++) { - ao_led_on(AO_LED_PANIC); ao_beep(AO_BEEP_HIGH); ao_panic_delay(1); - ao_led_off(AO_LED_PANIC); ao_beep(AO_BEEP_LOW); ao_panic_delay(1); } ao_beep(AO_BEEP_OFF); ao_panic_delay(2); +#endif #ifdef SDCC #pragma disable_warning 126 diff --git a/src/stmf0/ao_arch.h b/src/stmf0/ao_arch.h index 45df0982..26a34c85 100644 --- a/src/stmf0/ao_arch.h +++ b/src/stmf0/ao_arch.h @@ -117,6 +117,7 @@ extern const uint32_t ao_radio_cal; #define AO_PCLK1 (AO_HCLK / AO_APB1_PRESCALER) #define AO_PCLK2 (AO_HCLK / AO_APB2_PRESCALER) #define AO_SYSTICK (AO_HCLK) +#define AO_PANIC_DELAY_SCALE (AO_SYSCLK / 12000000) #if AO_APB1_PRESCALER == 1 #define AO_TIM23467_CLK AO_PCLK1 -- cgit v1.2.3 From a7c7e10b3bbfbdf9667d071634cdd6fdf12a1f85 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Mar 2016 10:17:24 -0700 Subject: altos: Expose fast timer API from kernel/ This allows multiple SoCs to provide the same driver interface Signed-off-by: Keith Packard --- src/kernel/ao_fast_timer.h | 34 ++++++++++++++++++++++++++++++++++ src/stm/ao_fast_timer.h | 34 ---------------------------------- 2 files changed, 34 insertions(+), 34 deletions(-) create mode 100644 src/kernel/ao_fast_timer.h delete mode 100644 src/stm/ao_fast_timer.h (limited to 'src/kernel') diff --git a/src/kernel/ao_fast_timer.h b/src/kernel/ao_fast_timer.h new file mode 100644 index 00000000..90fb3930 --- /dev/null +++ b/src/kernel/ao_fast_timer.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 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_FAST_TIMER_H_ +#define _AO_FAST_TIMER_H_ + +void +ao_fast_timer_init(void); + +#ifndef AO_FAST_TIMER_MAX +#define AO_FAST_TIMER_MAX 2 +#endif + +void +ao_fast_timer_on(void (*callback)(void)); + +void +ao_fast_timer_off(void (*callback)(void)); + +#endif /* _AO_FAST_TIMER_H_ */ diff --git a/src/stm/ao_fast_timer.h b/src/stm/ao_fast_timer.h deleted file mode 100644 index 90fb3930..00000000 --- a/src/stm/ao_fast_timer.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright © 2013 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_FAST_TIMER_H_ -#define _AO_FAST_TIMER_H_ - -void -ao_fast_timer_init(void); - -#ifndef AO_FAST_TIMER_MAX -#define AO_FAST_TIMER_MAX 2 -#endif - -void -ao_fast_timer_on(void (*callback)(void)); - -void -ao_fast_timer_off(void (*callback)(void)); - -#endif /* _AO_FAST_TIMER_H_ */ -- cgit v1.2.3 From 4fa71ecf168e275b24534a5a20e3dd4e178c7bbd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 26 Mar 2016 15:54:24 -0700 Subject: altos/stm: Validate current task SP in interrupt by looking at PSP We use a separate stack pointer for task code, which means we can verify that it is in range in any interrupt handler. This adds checks for the task stack (under #ifdef DEBUG) that run in ao_wakeup as well as at every timer interrupt. Signed-off-by: Keith Packard --- src/kernel/ao_task.c | 2 +- src/kernel/ao_task.h | 4 ++++ src/stm/ao_arch_funcs.h | 16 ++++++++++++++++ src/stm/ao_timer.c | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) (limited to 'src/kernel') diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c index 55e423bb..104d1074 100644 --- a/src/kernel/ao_task.c +++ b/src/kernel/ao_task.c @@ -355,7 +355,6 @@ ao_yield(void) ao_arch_naked_define */ if (ao_cur_task->wchan == NULL) ao_task_to_run_queue(ao_cur_task); - ao_cur_task = NULL; for (;;) { ao_arch_memory_barrier(); if (!ao_list_is_empty(&run_queue)) @@ -425,6 +424,7 @@ ao_sleep(__xdata void *wchan) void ao_wakeup(__xdata void *wchan) __reentrant { + ao_validate_cur_stack(); #if HAS_TASK_QUEUE struct ao_task *sleep, *next; struct ao_list *sleep_queue; diff --git a/src/kernel/ao_task.h b/src/kernel/ao_task.h index c6bec0e3..0e353fe8 100644 --- a/src/kernel/ao_task.h +++ b/src/kernel/ao_task.h @@ -56,6 +56,10 @@ extern __data uint8_t ao_num_tasks; extern __xdata struct ao_task *__data ao_cur_task; extern __data uint8_t ao_task_minimize_latency; /* Reduce IRQ latency */ +#ifndef HAS_ARCH_VALIDATE_CUR_STACK +#define ao_validate_cur_stack() +#endif + /* ao_task.c */ diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 02b344b1..6b38032c 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -366,6 +366,22 @@ static inline void ao_arch_restore_stack(void) { #define HAS_SAMPLE_PROFILE 0 #endif +#if DEBUG +#define HAS_ARCH_VALIDATE_CUR_STACK 1 + +static inline void +ao_validate_cur_stack(void) +{ + uint8_t *psp; + + asm("mrs %0,psp" : "=&r" (psp)); + if (ao_cur_task && + psp <= ao_cur_task->stack && + psp >= ao_cur_task->stack - 256) + ao_panic(AO_PANIC_STACK); +} +#endif + #if !HAS_SAMPLE_PROFILE #define HAS_ARCH_START_SCHEDULER 1 diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 8db62e76..91ede84b 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -41,6 +41,7 @@ volatile __data uint8_t ao_data_count; void stm_systick_isr(void) { + ao_validate_cur_stack(); if (stm_systick.csr & (1 << STM_SYSTICK_CSR_COUNTFLAG)) { ++ao_tick_count; #if HAS_TASK_QUEUE -- cgit v1.2.3 From 0ee235e1126f34987522fe852ba6ab3ac92d6cfd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Apr 2016 19:39:07 -0700 Subject: altos: Allow for flight hardware without any ADC values Detherm has no ADC connections, so we don't need to disable the ADC when going to landed state. Signed-off-by: Keith Packard --- src/kernel/ao_flight.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/kernel') diff --git a/src/kernel/ao_flight.c b/src/kernel/ao_flight.c index 251dbc02..9ba02bb8 100644 --- a/src/kernel/ao_flight.c +++ b/src/kernel/ao_flight.c @@ -370,8 +370,10 @@ ao_flight(void) { ao_flight_state = ao_flight_landed; +#if HAS_ADC /* turn off the ADC capture */ ao_timer_set_adc_interval(0); +#endif ao_wakeup(DATA_TO_XDATA(&ao_flight_state)); } -- cgit v1.2.3 From 6ead4c570a264afdc4e45eed6e87bf541668be6f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Apr 2016 19:40:19 -0700 Subject: altos: Add Detherm log format (easymini without ADC) Signed-off-by: Keith Packard --- src/kernel/ao_log.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/kernel') diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h index f86fb359..fdd428c2 100644 --- a/src/kernel/ao_log.h +++ b/src/kernel/ao_log.h @@ -49,6 +49,7 @@ extern __pdata enum ao_flight_state ao_log_state; #define AO_LOG_FORMAT_TELEMINI 8 /* 16-byte MS5607 baro only, 3.3V supply */ #define AO_LOG_FORMAT_TELEGPS 9 /* 32 byte telegps records */ #define AO_LOG_FORMAT_TELEMEGA 10 /* 32 byte typed telemega records with 32 bit gyro cal */ +#define AO_LOG_FORMAT_DETHERM 11 /* 16-byte MS5607 baro only, no ADC */ #define AO_LOG_FORMAT_NONE 127 /* No log at all */ extern __code uint8_t ao_log_format; -- cgit v1.2.3 From f5e6caab78f4ca0e5c8a2d96ef53b8752d64f4b3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Apr 2016 19:41:21 -0700 Subject: altos: Use mini logging for detherm, just without ADC Signed-off-by: Keith Packard --- src/kernel/ao_log_mini.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/kernel') diff --git a/src/kernel/ao_log_mini.c b/src/kernel/ao_log_mini.c index 0ca3ed06..844f38aa 100644 --- a/src/kernel/ao_log_mini.c +++ b/src/kernel/ao_log_mini.c @@ -110,9 +110,11 @@ ao_log(void) ao_data_ring[ao_log_data_pos].ms5607_raw.pres); ao_log_pack24(log.u.sensor.temp, ao_data_ring[ao_log_data_pos].ms5607_raw.temp); +#if AO_LOG_FORMAT != AO_LOG_FORMAT_DETHERM log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a; log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m; log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt; +#endif ao_log_mini(&log); if (ao_log_state <= ao_flight_coast) next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT; -- cgit v1.2.3 From e6bad553009704af69b08b4a22fb5eb8ac6921f8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 21 Dec 2015 21:48:37 -0800 Subject: altos: Support pad/lco boxes with fixed box numbers This allows for a configuration without adjustable box numbers on either end of the link, simplifying the UI. Signed-off-by: Keith Packard --- src/Makefile | 4 +++- src/kernel/ao_config.c | 27 +++++++++++++++++++++++++++ src/kernel/ao_config.h | 3 +++ src/telefiretwo-v0.1/ao_pins.h | 1 + src/telefiretwo-v0.1/flash-loader/ao_pins.h | 6 +++++- 5 files changed, 39 insertions(+), 2 deletions(-) (limited to 'src/kernel') diff --git a/src/Makefile b/src/Makefile index 98607031..ecba2fbd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -39,7 +39,9 @@ ARMM3DIRS=\ telescience-v0.2 telescience-v0.2/flash-loader \ teledongle-v3.0 teledongle-v3.0/flash-loader \ teleballoon-v2.0 \ - telebt-v3.0 telebt-v3.0/flash-loader + telebt-v3.0 telebt-v3.0/flash-loader \ + telelcotwo-v0.1 telelcotwo-v0.1/flash-loader \ + telefiretwo-v0.1 telefiretwo-v0.1/flash-loader \ ARMM0DIRS=\ easymini-v1.0 easymini-v1.0/flash-loader \ diff --git a/src/kernel/ao_config.c b/src/kernel/ao_config.c index b0d3e541..d51fbb41 100644 --- a/src/kernel/ao_config.c +++ b/src/kernel/ao_config.c @@ -223,6 +223,10 @@ _ao_config_get(void) #if HAS_APRS if (minor < 22) ao_config.aprs_format = AO_CONFIG_DEFAULT_APRS_FORMAT; +#endif +#if HAS_FIXED_PAD_BOX + if (minor < 22) + ao_config.pad_box = 1; #endif ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; @@ -899,6 +903,25 @@ ao_config_aprs_format_show(void) } #endif /* HAS_APRS */ +#if HAS_FIXED_PAD_BOX +void +ao_config_pad_box_show(void) +{ + printf ("Pad box: %d\n", ao_config.pad_box); +} + +void +ao_config_pad_box_set(void) +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.pad_box = ao_cmd_lex_i; + _ao_config_edit_finish(); +} +#endif + struct ao_config_var { __code char *str; void (*set)(void) __reentrant; @@ -992,6 +1015,10 @@ __code struct ao_config_var ao_config_vars[] = { ao_config_aprs_ssid_set, ao_config_aprs_ssid_show }, { "C <0 compressed, 1 uncompressed>\0APRS format", ao_config_aprs_format_set, ao_config_aprs_format_show }, +#endif +#if HAS_FIXED_PAD_BOX + { "B \0Set pad box (1-99)", + ao_config_pad_box_set, ao_config_pad_box_show }, #endif { "s\0Show", ao_config_show, 0 }, diff --git a/src/kernel/ao_config.h b/src/kernel/ao_config.h index cfe8555c..f4e9af44 100644 --- a/src/kernel/ao_config.h +++ b/src/kernel/ao_config.h @@ -118,6 +118,9 @@ struct ao_config { #if HAS_APRS uint8_t aprs_format; /* minor version 22 */ #endif +#if HAS_FIXED_PAD_BOX + uint8_t pad_box; /* minor version 22 */ +#endif }; #define AO_APRS_FORMAT_COMPRESSED 0 diff --git a/src/telefiretwo-v0.1/ao_pins.h b/src/telefiretwo-v0.1/ao_pins.h index e98b7dc7..fd840f47 100644 --- a/src/telefiretwo-v0.1/ao_pins.h +++ b/src/telefiretwo-v0.1/ao_pins.h @@ -37,6 +37,7 @@ #define PACKET_HAS_MASTER 0 #define PACKET_HAS_SLAVE 0 #define AO_DATA_RING 32 +#define HAS_FIXED_PAD_BOX 1 /* 8MHz High speed external crystal */ #define AO_HSE 8000000 diff --git a/src/telefiretwo-v0.1/flash-loader/ao_pins.h b/src/telefiretwo-v0.1/flash-loader/ao_pins.h index f6311267..daa9048d 100644 --- a/src/telefiretwo-v0.1/flash-loader/ao_pins.h +++ b/src/telefiretwo-v0.1/flash-loader/ao_pins.h @@ -23,6 +23,10 @@ #include -#define AO_BOOT_PIN 0 +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpiob +#define AO_BOOT_APPLICATION_PIN 6 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 70e46100acf597014ce54cf3b642254ce1cba59b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Apr 2016 23:45:52 -0700 Subject: altos/telelcotwo: Add idle timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Puts TeleLCOTwo in a low power state (drawing about 80µA) after a timeout (default two minutes) to keep from killing the battery if the device is left turned on. Signed-off-by: Keith Packard --- src/drivers/ao_event.c | 16 +++++++++++++++ src/drivers/ao_event.h | 3 +++ src/drivers/ao_lco_two.c | 53 +++++++++++++++++++++++++++++++++++++++++++----- src/kernel/ao_config.c | 21 +++++++++++++++++++ src/kernel/ao_config.h | 3 ++- 5 files changed, 90 insertions(+), 6 deletions(-) (limited to 'src/kernel') diff --git a/src/drivers/ao_event.c b/src/drivers/ao_event.c index 5c0d2863..8f88d778 100644 --- a/src/drivers/ao_event.c +++ b/src/drivers/ao_event.c @@ -41,6 +41,22 @@ ao_event_get(struct ao_event *ev) ); } +uint8_t +ao_event_get_for(struct ao_event *ev, uint16_t timeout) +{ + uint8_t empty = 1; + ao_arch_critical( + while ((empty = ao_event_queue_empty())) + if (ao_sleep_for(&ao_event_queue, timeout)) + break; + if (!empty) { + *ev = ao_event_queue[ao_event_queue_remove]; + ao_event_queue_remove = ao_event_queue_next(ao_event_queue_remove); + } + ); + return empty; +} + /* called with interrupts disabled */ void ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value) diff --git a/src/drivers/ao_event.h b/src/drivers/ao_event.h index 584a845a..ea89da23 100644 --- a/src/drivers/ao_event.h +++ b/src/drivers/ao_event.h @@ -32,6 +32,9 @@ struct ao_event { void ao_event_get(struct ao_event *ev); +uint8_t +ao_event_get_for(struct ao_event *ev, uint16_t timeout); + void ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value); diff --git a/src/drivers/ao_lco_two.c b/src/drivers/ao_lco_two.c index 0fd8e362..f53fef7d 100644 --- a/src/drivers/ao_lco_two.c +++ b/src/drivers/ao_lco_two.c @@ -29,12 +29,13 @@ static uint8_t ao_lco_debug; #define DEBUG_STATUS 2 #define PRINTD(l, ...) do { if (!(ao_lco_debug & l)) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) #else -#define PRINTD(l,...) +#define PRINTD(l,...) #endif #define AO_LCO_VALID_LAST 1 #define AO_LCO_VALID_EVER 2 +static uint8_t ao_lco_suspended; static uint8_t ao_lco_selected; static uint8_t ao_lco_valid; static uint8_t ao_lco_channels; @@ -43,7 +44,6 @@ static uint16_t ao_lco_tick_offset; /* UI values */ static uint8_t ao_lco_armed; static uint8_t ao_lco_firing; -static uint8_t ao_lco_fire_down; #define ao_lco_box (ao_config.pad_box) @@ -70,13 +70,45 @@ ao_lco_set_armed(int pad, int armed) ao_wakeup(&ao_lco_armed); } +static void +ao_lco_suspend(void) +{ + if (!ao_lco_suspended) { + PRINTD(DEBUG_EVENT, "suspend\n"); + ao_lco_suspended = 1; + ao_lco_selected = 0; + ao_lco_armed = 0; + ao_wakeup(&ao_pad_query); + } +} + +static void +ao_lco_wakeup(void) +{ + if (ao_lco_suspended) { + ao_lco_suspended = 0; + ao_wakeup(&ao_lco_suspended); + } +} + static void ao_lco_input(void) { static struct ao_event event; + uint8_t timeout; + ao_config_get(); for (;;) { - ao_event_get(&event); + if (ao_config.pad_idle && !ao_lco_suspended) { + timeout = ao_event_get_for(&event, AO_SEC_TO_TICKS(ao_config.pad_idle)); + if (timeout) { + ao_lco_suspend(); + continue; + } + } else { + ao_event_get(&event); + } + ao_lco_wakeup(); PRINTD(DEBUG_EVENT, "event type %d unit %d value %d\n", event.type, event.unit, event.value); switch (event.type) { @@ -92,7 +124,6 @@ ao_lco_input(void) #endif case AO_BUTTON_FIRE: if (ao_lco_armed) { - ao_lco_fire_down = 0; ao_lco_firing = event.value; PRINTD(DEBUG_EVENT, "Firing %d\n", ao_lco_firing); ao_wakeup(&ao_lco_armed); @@ -155,6 +186,12 @@ ao_lco_igniter_status(void) for (;;) { ao_sleep(&ao_pad_query); + while (ao_lco_suspended) { + ao_led_off(AO_LED_GREEN|AO_LED_AMBER|AO_LED_RED|AO_LED_REMOTE_ARM); + for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) + ao_led_off(continuity_led[c]); + ao_sleep(&ao_lco_suspended); + } PRINTD(DEBUG_STATUS, "RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_valid); if (!(ao_lco_valid & AO_LCO_VALID_LAST)) { ao_led_on(AO_LED_RED); @@ -195,6 +232,8 @@ ao_lco_arm_warn(void) { int i; for (;;) { + while (ao_lco_suspended) + ao_sleep(&ao_lco_suspended); while (!ao_lco_armed) ao_sleep(&ao_lco_armed); for (i = 0; i < ao_lco_armed; i++) { @@ -220,6 +259,9 @@ ao_lco_monitor(void) ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status"); ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); for (;;) { + while (ao_lco_suspended) + ao_sleep(&ao_lco_suspended); + PRINTD(DEBUG_STATUS, "monitor armed %d firing %d\n", ao_lco_armed, ao_lco_firing); @@ -240,8 +282,9 @@ ao_lco_monitor(void) } if (ao_lco_armed && ao_lco_firing) delay = AO_MS_TO_TICKS(100); - else + else { delay = AO_SEC_TO_TICKS(1); + } ao_sleep_for(&ao_lco_armed, delay); } } diff --git a/src/kernel/ao_config.c b/src/kernel/ao_config.c index d51fbb41..f95ca893 100644 --- a/src/kernel/ao_config.c +++ b/src/kernel/ao_config.c @@ -227,6 +227,8 @@ _ao_config_get(void) #if HAS_FIXED_PAD_BOX if (minor < 22) ao_config.pad_box = 1; + if (minor < 23) + ao_config.pad_idle = 120; #endif ao_config.minor = AO_CONFIG_MINOR; ao_config_dirty = 1; @@ -920,6 +922,23 @@ ao_config_pad_box_set(void) ao_config.pad_box = ao_cmd_lex_i; _ao_config_edit_finish(); } + +void +ao_config_pad_idle_show(void) +{ + printf ("Idle timeout: %d\n", ao_config.pad_idle); +} + +void +ao_config_pad_idle_set(void) +{ + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + _ao_config_edit_start(); + ao_config.pad_idle = ao_cmd_lex_i; + _ao_config_edit_finish(); +} #endif struct ao_config_var { @@ -1019,6 +1038,8 @@ __code struct ao_config_var ao_config_vars[] = { #if HAS_FIXED_PAD_BOX { "B \0Set pad box (1-99)", ao_config_pad_box_set, ao_config_pad_box_show }, + { "i \0Set idle timeout (0 disable)", + ao_config_pad_idle_set, ao_config_pad_idle_show }, #endif { "s\0Show", ao_config_show, 0 }, diff --git a/src/kernel/ao_config.h b/src/kernel/ao_config.h index f4e9af44..3c73ea49 100644 --- a/src/kernel/ao_config.h +++ b/src/kernel/ao_config.h @@ -57,7 +57,7 @@ #endif #define AO_CONFIG_MAJOR 1 -#define AO_CONFIG_MINOR 22 +#define AO_CONFIG_MINOR 23 #define AO_AES_LEN 16 @@ -120,6 +120,7 @@ struct ao_config { #endif #if HAS_FIXED_PAD_BOX uint8_t pad_box; /* minor version 22 */ + uint8_t pad_idle; /* minor version 23 */ #endif }; -- cgit v1.2.3 From 4db6074bb15c66bd23c513e1e41b408e5408cff8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 19 Apr 2016 23:19:59 -0400 Subject: altos: avoid mixed declarations and code in ao_task.c sdcc can't handle this. Signed-off-by: Keith Packard --- src/kernel/ao_task.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/kernel') diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c index 104d1074..e430edc6 100644 --- a/src/kernel/ao_task.c +++ b/src/kernel/ao_task.c @@ -442,10 +442,12 @@ ao_wakeup(__xdata void *wchan) __reentrant } ao_arch_irqrestore(flags); #else + { uint8_t i; for (i = 0; i < ao_num_tasks; i++) if (ao_tasks[i]->wchan == wchan) ao_tasks[i]->wchan = NULL; + } #endif ao_check_stack(); } -- cgit v1.2.3 From 27319e4edbc503f193475b437fa5fe2937d47cbe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2016 18:48:47 -0400 Subject: altos/stm32l: Add support for software-driven HW flow control This allows applications to request that the flow control bits be driven from software rather than hardware, permitting more flexible pin configuration. Signed-off-by: Keith Packard --- src/kernel/ao.h | 2 + src/stm/ao_arch_funcs.h | 23 +++++++- src/stm/ao_serial_stm.c | 154 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 140 insertions(+), 39 deletions(-) (limited to 'src/kernel') diff --git a/src/kernel/ao.h b/src/kernel/ao.h index a794ba71..6ed0299e 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -820,6 +820,8 @@ struct ao_fifo { } while(0) #define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove) +#define ao_fifo_mostly(f) ((((f).insert - (f).remove) & (AO_FIFO_SIZE-1)) >= (AO_FIFO_SIZE * 3 / 4)) +#define ao_fifo_barely(f) ((((f).insert - (f).remove) & (AO_FIFO_SIZE-1)) >= (AO_FIFO_SIZE * 1 / 4)) #define ao_fifo_empty(f) ((f).insert == (f).remove) #if PACKET_HAS_MASTER || PACKET_HAS_SLAVE diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 6fcfd5f8..5a7782de 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -278,14 +278,35 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop); void ao_i2c_init(void); +#if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW +#define HAS_SERIAL_SW_FLOW 1 +#else +#define HAS_SERIAL_SW_FLOW 0 +#endif + +#if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_FLOW && !USE_SERIAL_3_SW_FLOW +#define HAS_SERIAL_HW_FLOW 1 +#else +#define HAS_SERIAL_HW_FLOW 0 +#endif + /* ao_serial_stm.c */ struct ao_stm_usart { struct ao_fifo rx_fifo; struct ao_fifo tx_fifo; struct stm_usart *reg; - uint8_t tx_started; uint8_t tx_running; uint8_t draining; +#if HAS_SERIAL_SW_FLOW + /* RTS - 0 if we have FIFO space, 1 if not + * CTS - 0 if we can send, 0 if not + */ + struct stm_gpio *gpio_rts; + struct stm_gpio *gpio_cts; + uint8_t pin_rts; + uint8_t pin_cts; + uint8_t rts; +#endif }; #if HAS_SERIAL_1 diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index e7b6ab78..bf079060 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -16,6 +16,7 @@ */ #include +#include void ao_debug_out(char c) @@ -29,40 +30,67 @@ ao_debug_out(char c) static int _ao_usart_tx_start(struct ao_stm_usart *usart) { - if (!ao_fifo_empty(usart->tx_fifo) && !usart->tx_started) - { - usart->tx_started = 1; - usart->tx_running = 1; - usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); - ao_fifo_remove(usart->tx_fifo, usart->reg->dr); - ao_wakeup(&usart->tx_fifo); - return 1; + if (!ao_fifo_empty(usart->tx_fifo)) { +#if HAS_SERIAL_SW_FLOW + if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts, foo) == 1) { + ao_exti_enable(usart->gpio_cts, usart->pin_cts); + return 0; + } +#endif + if (usart->reg->sr & (1 << STM_USART_SR_TXE)) + { + usart->tx_running = 1; + usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); + ao_fifo_remove(usart->tx_fifo, usart->reg->dr); + ao_wakeup(&usart->tx_fifo); + return 1; + } } return 0; } +#if HAS_SERIAL_SW_FLOW +static void +_ao_usart_cts(struct ao_stm_usart *usart) +{ + if (_ao_usart_tx_start(usart)) + ao_exti_disable(usart->gpio_cts, usart->pin_cts); +} +#endif + +static void +_ao_usart_rx(struct ao_stm_usart *usart, int stdin) +{ + if (usart->reg->sr & (1 << STM_USART_SR_RXNE)) { + if (!ao_fifo_full(usart->rx_fifo)) { + ao_fifo_insert(usart->rx_fifo, usart->reg->dr); + ao_wakeup(&usart->rx_fifo); + if (stdin) + ao_wakeup(&ao_stdin_ready); +#if HAS_SERIAL_SW_FLOW + /* If the fifo is nearly full, turn off RTS and wait + * for it to drain a bunch + */ + if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) { + ao_gpio_set(usart->gpio_rts, usart->pin_rts, usart->pin_rts, 1); + usart->rts = 0; + } +#endif + } else { + usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE); + } + } +} + static void ao_usart_isr(struct ao_stm_usart *usart, int stdin) { - uint32_t sr; + _ao_usart_rx(usart, stdin); - sr = usart->reg->sr; - usart->reg->sr = 0; + if (!_ao_usart_tx_start(usart)) + usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); - if (sr & (1 << STM_USART_SR_RXNE)) { - char c = usart->reg->dr; - if (!ao_fifo_full(usart->rx_fifo)) - ao_fifo_insert(usart->rx_fifo, c); - ao_wakeup(&usart->rx_fifo); - if (stdin) - ao_wakeup(&ao_stdin_ready); - } - if (sr & (1 << STM_USART_SR_TXE)) { - usart->tx_started = 0; - if (!_ao_usart_tx_start(usart)) - usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); - } - if (sr & (1 << STM_USART_SR_TC)) { + if (usart->reg->sr & (1 << STM_USART_SR_TC)) { usart->tx_running = 0; usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE); if (usart->draining) { @@ -72,7 +100,7 @@ ao_usart_isr(struct ao_stm_usart *usart, int stdin) } } -int +static int _ao_usart_pollchar(struct ao_stm_usart *usart) { int c; @@ -82,13 +110,23 @@ _ao_usart_pollchar(struct ao_stm_usart *usart) else { uint8_t u; ao_fifo_remove(usart->rx_fifo,u); + if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) { + if (ao_fifo_barely(usart->rx_fifo)) + usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE); + } +#if HAS_SERIAL_SW_FLOW + /* If we've cleared RTS, check if there's space now and turn it back on */ + if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) { + ao_gpio_set(usart->gpio_rts, usart->pin_rts, foo, 0); + usart->rts = 1; + } +#endif c = u; - ao_usb_putchar(c); ao_usb_flush(); } return c; } -char +static char ao_usart_getchar(struct ao_stm_usart *usart) { int c; @@ -96,7 +134,6 @@ ao_usart_getchar(struct ao_stm_usart *usart) while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) ao_sleep(&usart->rx_fifo); ao_arch_release_interrupts(); - ao_usb_putchar(c); ao_usb_flush(); return (char) c; } @@ -106,10 +143,9 @@ _ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) return ao_sleep_for(&usart->rx_fifo, timeout); } -void +static void ao_usart_putchar(struct ao_stm_usart *usart, char c) { - ao_usb_putchar(c); ao_usb_flush(); ao_arch_block_interrupts(); while (ao_fifo_full(usart->tx_fifo)) ao_sleep(&usart->tx_fifo); @@ -149,7 +185,7 @@ static const struct { }, }; -void +static void ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) { if (speed > AO_SERIAL_SPEED_115200) @@ -157,7 +193,7 @@ ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) usart->reg->brr = ao_usart_speeds[speed].brr; } -void +static void ao_usart_init(struct ao_stm_usart *usart) { usart->reg->cr1 = ((0 << STM_USART_CR1_OVER8) | @@ -203,12 +239,14 @@ ao_usart_init(struct ao_stm_usart *usart) ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); } -void +#if HAS_SERIAL_HW_FLOW +static void ao_usart_set_flow(struct ao_stm_usart *usart) { usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | (1 << STM_USART_CR3_RTSE)); } +#endif #if HAS_SERIAL_1 @@ -296,13 +334,22 @@ ao_serial2_set_speed(uint8_t speed) ao_usart_drain(&ao_stm_usart2); ao_usart_set_speed(&ao_stm_usart2, speed); } + +#if HAS_SERIAL_SW_FLOW +void +ao_serial2_cts(void) +{ + _ao_usart_cts(&ao_stm_usart2); +} +#endif + #endif /* HAS_SERIAL_2 */ #if HAS_SERIAL_3 struct ao_stm_usart ao_stm_usart3; -void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_2_STDIN); } +void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); } char ao_serial3_getchar(void) @@ -342,6 +389,28 @@ ao_serial3_drain(void) } #endif /* HAS_SERIAL_3 */ +#if HAS_SERIAL_SW_FLOW +static void +ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart, + void (*isr)(void), + struct stm_gpio *port_rts, + int pin_rts, + struct stm_gpio *port_cts, + int pin_cts) +{ + /* Pull RTS low to note that there's space in the FIFO + */ + ao_enable_output(port_rts, pin_rts, foo, 0); + usart->gpio_rts = port_rts; + usart->pin_rts = pin_rts; + usart->rts = 1; + + ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr); + usart->gpio_cts = port_cts; + usart->pin_cts = pin_cts; +} +#endif + void ao_serial_init(void) { @@ -394,10 +463,19 @@ ao_serial_init(void) stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7); stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7); -#if USE_SERIAL_2_FLOW +# if USE_SERIAL_2_FLOW +# if USE_SERIAL_2_SW_FLOW + ao_serial_set_sw_rts_cts(&ao_stm_usart2, + ao_serial2_cts, + SERIAL_2_PORT_RTS, + SERIAL_2_PIN_RTS, + SERIAL_2_PORT_CTS, + SERIAL_2_PIN_CTS); +# else stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7); stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7); -#endif +# endif +# endif #else #if SERIAL_2_PD5_PD6 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); @@ -416,7 +494,7 @@ ao_serial_init(void) ao_stm_usart2.reg = &stm_usart2; ao_usart_init(&ao_stm_usart2); -#if USE_SERIAL_2_FLOW +#if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW ao_usart_set_flow(&ao_stm_usart2); #endif -- cgit v1.2.3 From b540f6f5b034f33b8e1d1c3b91e2403a56479caa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 May 2016 16:19:39 -0700 Subject: altos: Make sure AO_MMA655X_INVERT is declared where needed Add #define AO_MMA655X_INVERT 0 to existing products which didn't declare it at all. This will make sure the value is set correctly for each new board. Signed-off-by: Keith Packard --- src/easymega-v1.0/ao_pins.h | 1 + src/kernel/ao_data.h | 4 ++++ src/telemega-v0.1/ao_pins.h | 1 + src/telemega-v1.0/ao_pins.h | 1 + src/telemega-v2.0/ao_pins.h | 1 + 5 files changed, 8 insertions(+) (limited to 'src/kernel') diff --git a/src/easymega-v1.0/ao_pins.h b/src/easymega-v1.0/ao_pins.h index a5e55638..773e58d9 100644 --- a/src/easymega-v1.0/ao_pins.h +++ b/src/easymega-v1.0/ao_pins.h @@ -321,6 +321,7 @@ struct ao_adc { */ #define HAS_MMA655X 1 +#define AO_MMA655X_INVERT 0 #define AO_MMA655X_SPI_INDEX AO_SPI_1_PB3_PB4_PB5 #define AO_MMA655X_CS_PORT (&stm_gpioc) #define AO_MMA655X_CS_PIN 12 diff --git a/src/kernel/ao_data.h b/src/kernel/ao_data.h index 8f75ad87..6ee0965d 100644 --- a/src/kernel/ao_data.h +++ b/src/kernel/ao_data.h @@ -269,6 +269,10 @@ typedef int16_t accel_t; #define AO_ACCEL_INVERT 4095 +#ifndef AO_MMA655X_INVERT +#error AO_MMA655X_INVERT not defined +#endif + #define ao_data_accel(packet) ((packet)->mma655x) #if AO_MMA655X_INVERT #define ao_data_accel_cook(packet) (AO_ACCEL_INVERT - (packet)->mma655x) diff --git a/src/telemega-v0.1/ao_pins.h b/src/telemega-v0.1/ao_pins.h index 7ccc6085..1815ef54 100644 --- a/src/telemega-v0.1/ao_pins.h +++ b/src/telemega-v0.1/ao_pins.h @@ -346,6 +346,7 @@ struct ao_adc { */ #define HAS_MMA655X 1 +#define AO_MMA655X_INVERT 0 #define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15 #define AO_MMA655X_CS_PORT (&stm_gpiod) #define AO_MMA655X_CS_PIN 4 diff --git a/src/telemega-v1.0/ao_pins.h b/src/telemega-v1.0/ao_pins.h index 664546c2..b81e59a9 100644 --- a/src/telemega-v1.0/ao_pins.h +++ b/src/telemega-v1.0/ao_pins.h @@ -348,6 +348,7 @@ struct ao_adc { */ #define HAS_MMA655X 1 +#define AO_MMA655X_INVERT 0 #define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15 #define AO_MMA655X_CS_PORT (&stm_gpiod) #define AO_MMA655X_CS_PIN 4 diff --git a/src/telemega-v2.0/ao_pins.h b/src/telemega-v2.0/ao_pins.h index 9095a350..242f0ab2 100644 --- a/src/telemega-v2.0/ao_pins.h +++ b/src/telemega-v2.0/ao_pins.h @@ -348,6 +348,7 @@ struct ao_adc { */ #define HAS_MMA655X 1 +#define AO_MMA655X_INVERT 0 #define AO_MMA655X_SPI_INDEX AO_SPI_1_PE13_PE14_PE15 #define AO_MMA655X_CS_PORT (&stm_gpiod) #define AO_MMA655X_CS_PIN 4 -- cgit v1.2.3