From 148f6e0a107d9e88509958700351794f2f971312 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 30 Oct 2016 19:06:20 -0700 Subject: altos/stmf0: Add USART support The STM32F0 usart can be operated much like the STM32L usart, but the registers are all moved around. Signed-off-by: Keith Packard --- src/stmf0/ao_arch_funcs.h | 13 +- src/stmf0/ao_serial_stm.c | 500 ++++++++++++++++++++++++++++++++++++++++++++++ src/stmf0/stm32f0.h | 125 ++++++++++++ 3 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 src/stmf0/ao_serial_stm.c (limited to 'src/stmf0') diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index 8b6234c4..d35bafbd 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -314,7 +314,18 @@ 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/stmf0/ao_serial_stm.c b/src/stmf0/ao_serial_stm.c new file mode 100644 index 00000000..30b0dbd2 --- /dev/null +++ b/src/stmf0/ao_serial_stm.c @@ -0,0 +1,500 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include +#include + +void +ao_debug_out(char c) +{ + if (c == '\n') + ao_debug_out('\r'); + while (!(stm_usart1.isr & (1 << STM_USART_ISR_TXE))); + stm_usart1.tdr = c; +} + +static int +_ao_usart_tx_start(struct ao_stm_usart *usart) +{ + 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->isr & (1 << STM_USART_ISR_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->tdr); + 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->isr & (1 << STM_USART_ISR_RXNE)) { + usart->reg->icr = (1 << STM_USART_ICR_ORECF); + if (!ao_fifo_full(usart->rx_fifo)) { + ao_fifo_insert(usart->rx_fifo, usart->reg->rdr); + 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) +{ + _ao_usart_rx(usart, stdin); + + if (!_ao_usart_tx_start(usart)) + usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); + + if (usart->reg->isr & (1 << STM_USART_ISR_TC)) { + usart->tx_running = 0; + usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE); + if (usart->draining) { + usart->draining = 0; + ao_wakeup(&usart->tx_fifo); + } + } +} + +static int +_ao_usart_pollchar(struct ao_stm_usart *usart) +{ + int c; + + if (ao_fifo_empty(usart->rx_fifo)) + c = AO_READ_AGAIN; + 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; + } + return c; +} + +static char +ao_usart_getchar(struct ao_stm_usart *usart) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) + ao_sleep(&usart->rx_fifo); + ao_arch_release_interrupts(); + return (char) c; +} + +static inline uint8_t +_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) +{ + return ao_sleep_for(&usart->rx_fifo, timeout); +} + +static void +ao_usart_putchar(struct ao_stm_usart *usart, char c) +{ + ao_arch_block_interrupts(); + while (ao_fifo_full(usart->tx_fifo)) + ao_sleep(&usart->tx_fifo); + ao_fifo_insert(usart->tx_fifo, c); + _ao_usart_tx_start(usart); + ao_arch_release_interrupts(); +} + +static void +ao_usart_drain(struct ao_stm_usart *usart) +{ + ao_arch_block_interrupts(); + while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) { + usart->draining = 1; + ao_sleep(&usart->tx_fifo); + } + ao_arch_release_interrupts(); +} + +static const struct { + uint32_t brr; +} ao_usart_speeds[] = { + [AO_SERIAL_SPEED_4800] = { + AO_PCLK / 4800 + }, + [AO_SERIAL_SPEED_9600] = { + AO_PCLK / 9600 + }, + [AO_SERIAL_SPEED_19200] = { + AO_PCLK / 19200 + }, + [AO_SERIAL_SPEED_57600] = { + AO_PCLK / 57600 + }, + [AO_SERIAL_SPEED_115200] = { + AO_PCLK / 115200 + }, +}; + +static void +ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) +{ + if (speed > AO_SERIAL_SPEED_115200) + return; + usart->reg->brr = ao_usart_speeds[speed].brr; +} + +static void +ao_usart_init(struct ao_stm_usart *usart) +{ + usart->reg->cr1 = ((0 << STM_USART_CR1_M1) | + (0 << STM_USART_CR1_EOBIE) | + (0 << STM_USART_CR1_RTOIE) | + (0 << STM_USART_CR1_DEAT) | + (0 << STM_USART_CR1_DEDT) | + (0 << STM_USART_CR1_OVER8) | + (0 << STM_USART_CR1_CMIE) | + (0 << STM_USART_CR1_MME) | + (0 << STM_USART_CR1_M0) | + (0 << STM_USART_CR1_WAKE) | + (0 << STM_USART_CR1_PCE) | + (0 << STM_USART_CR1_PS) | + (0 << STM_USART_CR1_PEIE) | + (0 << STM_USART_CR1_TXEIE) | + (0 << STM_USART_CR1_TCIE) | + (1 << STM_USART_CR1_RXNEIE) | + (0 << STM_USART_CR1_IDLEIE) | + (1 << STM_USART_CR1_TE) | + (1 << STM_USART_CR1_RE) | + (0 << STM_USART_CR1_UESM) | + (0 << STM_USART_CR1_UE)); + + usart->reg->cr2 = ((0 << STM_USART_CR2_ADD) | + (0 << STM_USART_CR2_RTOEN) | + (0 << STM_USART_CR2_ABRMOD) | + (0 << STM_USART_CR2_ABREN) | + (0 << STM_USART_CR2_MSBFIRST) | + (0 << STM_USART_CR2_DATAINV) | + (0 << STM_USART_CR2_TXINV) | + (0 << STM_USART_CR2_RXINV) | + (0 << STM_USART_CR2_SWAP) | + (0 << STM_USART_CR2_LINEN) | + (0 << STM_USART_CR2_STOP) | + (0 << STM_USART_CR2_CLKEN) | + (0 << STM_USART_CR2_CPOL) | + (0 << STM_USART_CR2_CHPA) | + (0 << STM_USART_CR2_LBCL) | + (0 << STM_USART_CR2_LBDIE) | + (0 << STM_USART_CR2_LBDL) | + (0 << STM_USART_CR2_ADDM7)); + + usart->reg->cr3 = ((0 << STM_USART_CR3_WUFIE) | + (0 << STM_USART_CR3_WUS) | + (0 << STM_USART_CR3_SCARCNT) | + (0 << STM_USART_CR3_DEP) | + (0 << STM_USART_CR3_DEM) | + (0 << STM_USART_CR3_DDRE) | + (0 << STM_USART_CR3_OVRDIS) | + (0 << STM_USART_CR3_ONEBIT) | + (0 << STM_USART_CR3_CTIIE) | + (0 << STM_USART_CR3_CTSE) | + (0 << STM_USART_CR3_RTSE) | + (0 << STM_USART_CR3_DMAT) | + (0 << STM_USART_CR3_DMAR) | + (0 << STM_USART_CR3_SCEN) | + (0 << STM_USART_CR3_NACK) | + (0 << STM_USART_CR3_HDSEL) | + (0 << STM_USART_CR3_IRLP) | + (0 << STM_USART_CR3_IREN) | + (0 << STM_USART_CR3_EIE)); + + + /* Pick a 9600 baud rate */ + ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); + + /* Enable the usart */ + usart->reg->cr1 |= (1 << STM_USART_CR1_UE); + +} + +#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 + +struct ao_stm_usart ao_stm_usart1; + +void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); } + +char +ao_serial1_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart1); +} + +void +ao_serial1_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart1, c); +} + +int +_ao_serial1_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart1); +} + +uint8_t +_ao_serial1_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart1, timeout); +} + +void +ao_serial1_drain(void) +{ + ao_usart_drain(&ao_stm_usart1); +} + +void +ao_serial1_set_speed(uint8_t speed) +{ + ao_usart_drain(&ao_stm_usart1); + ao_usart_set_speed(&ao_stm_usart1, speed); +} +#endif /* HAS_SERIAL_1 */ + +#if HAS_SERIAL_2 + +struct ao_stm_usart ao_stm_usart2; + +void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); } + +char +ao_serial2_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart2); +} + +void +ao_serial2_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart2, c); +} + +int +_ao_serial2_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart2); +} + +uint8_t +_ao_serial2_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart2, timeout); +} + +void +ao_serial2_drain(void) +{ + ao_usart_drain(&ao_stm_usart2); +} + +void +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_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) +{ +#if HAS_SERIAL_1 + /* + * TX RX + * PA9 PA10 + * PB6 PB7 + */ + +#if SERIAL_1_PA9_PA10 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 9, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 10, STM_AFR_AF1); +#else +#if SERIAL_1_PB6_PB7 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); + + stm_afr_set(&stm_gpiob, 6, STM_AFR_AF0); + stm_afr_set(&stm_gpiob, 7, STM_AFR_AF0); +#else +#error "No SERIAL_1 port configuration specified" +#endif +#endif + /* Enable USART */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN); + + ao_stm_usart1.reg = &stm_usart1; + ao_usart_init(&ao_stm_usart1); + + stm_nvic_set_enable(STM_ISR_USART1_POS); + stm_nvic_set_priority(STM_ISR_USART1_POS, 4); +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN + ao_add_stdio(_ao_serial1_pollchar, + ao_serial1_putchar, + NULL); +#endif +#endif + +#if HAS_SERIAL_2 + /* + * TX RX + * PA2 PA3 + * PA14 PA15 + */ + +# if SERIAL_2_PA2_PA3 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 3, STM_AFR_AF1); +# 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_AF1); + stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1); +# endif +# endif +# else +# if SERIAL_2_PA14_PA15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 14, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1); +# if USE_SERIAL_2_FLOW +# error "Don't know how to set flowcontrol for serial 2 on PA14" +# endif +# else +# if SERIAL_2_PA2_PA15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1); +# if USE_SERIAL_2_FLOW +# error "Don't know how to set flowcontrol for serial 2 on PA2_PA15" +# endif +# else +# error "No SERIAL_2 port configuration specified" +# endif +# endif +# endif + /* Enable USART */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN); + + ao_stm_usart2.reg = &stm_usart2; + ao_usart_init(&ao_stm_usart2); +# if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW + ao_usart_set_flow(&ao_stm_usart2); +# endif + + stm_nvic_set_enable(STM_ISR_USART2_POS); + stm_nvic_set_priority(STM_ISR_USART2_POS, 4); +# if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN + ao_add_stdio(_ao_serial2_pollchar, + ao_serial2_putchar, + NULL); +# endif +#endif +} diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index 054200e0..182cd963 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -2010,4 +2010,129 @@ struct stm_exti { extern struct stm_exti stm_exti; +struct stm_usart { + vuint32_t cr1; /* control register 1 */ + vuint32_t cr2; /* control register 2 */ + vuint32_t cr3; /* control register 3 */ + vuint32_t brr; /* baud rate register */ + + vuint32_t gtpr; /* guard time and prescaler */ + vuint32_t rtor; /* receiver timeout register */ + vuint32_t rqr; /* request register */ + vuint32_t isr; /* interrupt and status register */ + + vuint32_t icr; /* interrupt flag clear register */ + vuint32_t rdr; /* receive data register */ + vuint32_t tdr; /* transmit data register */ +}; + +#define STM_USART_CR1_M1 28 +#define STM_USART_CR1_EOBIE 27 +#define STM_USART_CR1_RTOIE 26 +#define STM_USART_CR1_DEAT 21 +#define STM_USART_CR1_DEDT 16 +#define STM_USART_CR1_OVER8 15 +#define STM_USART_CR1_CMIE 14 +#define STM_USART_CR1_MME 13 +#define STM_USART_CR1_M0 12 +#define STM_USART_CR1_WAKE 11 +#define STM_USART_CR1_PCE 10 +#define STM_USART_CR1_PS 9 +#define STM_USART_CR1_PEIE 8 +#define STM_USART_CR1_TXEIE 7 +#define STM_USART_CR1_TCIE 6 +#define STM_USART_CR1_RXNEIE 5 +#define STM_USART_CR1_IDLEIE 4 +#define STM_USART_CR1_TE 3 +#define STM_USART_CR1_RE 2 +#define STM_USART_CR1_UESM 1 +#define STM_USART_CR1_UE 0 + +#define STM_USART_CR2_ADD 24 +#define STM_USART_CR2_RTOEN 23 +#define STM_USART_CR2_ABRMOD 21 +#define STM_USART_CR2_ABREN 20 +#define STM_USART_CR2_MSBFIRST 19 +#define STM_USART_CR2_DATAINV 18 +#define STM_USART_CR2_TXINV 17 +#define STM_USART_CR2_RXINV 16 +#define STM_USART_CR2_SWAP 15 +#define STM_USART_CR2_LINEN 14 +#define STM_USART_CR2_STOP 12 +#define STM_USART_CR2_CLKEN 11 +#define STM_USART_CR2_CPOL 10 +#define STM_USART_CR2_CHPA 9 +#define STM_USART_CR2_LBCL 8 +#define STM_USART_CR2_LBDIE 6 +#define STM_USART_CR2_LBDL 5 +#define STM_USART_CR2_ADDM7 4 + +#define STM_USART_CR3_WUFIE 22 +#define STM_USART_CR3_WUS 20 +#define STM_USART_CR3_SCARCNT 17 +#define STM_USART_CR3_DEP 15 +#define STM_USART_CR3_DEM 14 +#define STM_USART_CR3_DDRE 13 +#define STM_USART_CR3_OVRDIS 12 +#define STM_USART_CR3_ONEBIT 11 +#define STM_USART_CR3_CTIIE 10 +#define STM_USART_CR3_CTSE 9 +#define STM_USART_CR3_RTSE 8 +#define STM_USART_CR3_DMAT 7 +#define STM_USART_CR3_DMAR 6 +#define STM_USART_CR3_SCEN 5 +#define STM_USART_CR3_NACK 4 +#define STM_USART_CR3_HDSEL 3 +#define STM_USART_CR3_IRLP 2 +#define STM_USART_CR3_IREN 1 +#define STM_USART_CR3_EIE 0 + +#define STM_USART_GTPR_GT 8 +#define STM_USART_GTPR_PSC 0 + +#define STM_USART_RQR_TXFRQ 4 +#define STM_USART_RQR_RXFRQ 3 +#define STM_USART_RQR_MMRQ 2 +#define STM_USART_RQR_SBKRQ 1 +#define STM_USART_RQR_ABRRQ 0 + +#define STM_USART_ISR_REACK 22 +#define STM_USART_ISR_TEACK 21 +#define STM_USART_ISR_WUF 20 +#define STM_USART_ISR_RWU 19 +#define STM_USART_ISR_SBKF 18 +#define STM_USART_ISR_CMF 17 +#define STM_USART_ISR_BUSY 16 +#define STM_USART_ISR_ABRF 15 +#define STM_USART_ISR_ABRE 14 +#define STM_USART_ISR_EOBF 12 +#define STM_USART_ISR_RTOF 11 +#define STM_USART_ISR_CTS 10 +#define STM_USART_ISR_CTSIF 9 +#define STM_USART_ISR_LBDF 8 +#define STM_USART_ISR_TXE 7 +#define STM_USART_ISR_TC 6 +#define STM_USART_ISR_RXNE 5 +#define STM_USART_ISR_IDLE 4 +#define STM_USART_ISR_ORE 3 +#define STM_USART_ISR_NF 2 +#define STM_USART_ISR_FE 1 +#define STM_USART_ISR_PE 0 + +#define STM_USART_ICR_WUCF 20 +#define STM_USART_ICR_CMCF 17 +#define STM_USART_ICR_EOBCF 12 +#define STM_USART_ICR_RTOCF 11 +#define STM_USART_ICR_CTSCF 9 +#define STM_USART_ICR_LBDCF 8 +#define STM_USART_ICR_TCCF 6 +#define STM_USART_ICR_IDLECF 4 +#define STM_USART_ICR_ORECF 3 +#define STM_USART_ICR_NCF 2 +#define STM_USART_ICR_FECF 1 +#define STM_USART_ICR_PECF 0 + +extern struct stm_usart stm_usart1; +extern struct stm_usart stm_usart2; + #endif /* _STM32F0_H_ */ -- cgit v1.2.3 From 89ecc32b90565ace078c4a84d4406a4d1f86821a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 17 Dec 2016 20:58:36 -0800 Subject: altos/arm: Align data so that gcc 5.4 doesn't do byte-accesses. Add -Wcast-align Gcc 5.4.1 tracks alignment of data through assignments, so that a uint32_t pointer which comes from byte-aligned uint8_t data: extern uint8_t foo[]; uint32_t *q = (void *) foo; Fetches and stores through this pointer are done bytewise. This is slow (meh), but if q references a device register, things to bad very quickly. This patch works around this bug in the compiler by adding __attribute__((aligned(4))) tags to some variables, or changing them from uint8_t to uint32_t. Places doing this will now be caught as I've added -Wcast-align to the compiler flags. That required adding (void *) casts, after the relevant code was checked to make sure the compiler could tell that the addresses were aligned. Signed-off-by: Keith Packard --- src/aes/ao_aes.c | 9 +++++---- src/drivers/ao_gps_ublox.c | 4 ++-- src/drivers/ao_trng_send.c | 2 +- src/kernel/ao_list.h | 2 +- src/kernel/ao_pyro.c | 4 ++-- src/kernel/ao_task.h | 13 ++++++++++++- src/stm/Makefile.defs | 2 +- src/stm/ao_arch_funcs.h | 9 ++------- src/stm/ao_eeprom_stm.c | 4 ++-- src/stm/ao_usb_stm.c | 2 +- src/stm/stm32l.h | 2 +- src/stmf0/Makefile-stmf0.defs | 2 +- src/stmf0/ao_adc_fast.h | 2 +- src/stmf0/ao_arch_funcs.h | 2 +- src/stmf0/ao_usb_stm.c | 2 +- src/stmf0/stm32f0.h | 2 +- 16 files changed, 35 insertions(+), 28 deletions(-) (limited to 'src/stmf0') diff --git a/src/aes/ao_aes.c b/src/aes/ao_aes.c index a04174c6..fd90c5bf 100644 --- a/src/aes/ao_aes.c +++ b/src/aes/ao_aes.c @@ -359,10 +359,10 @@ void xrijndaelDecrypt(word32 block[], roundkey *rkk) #endif uint8_t ao_aes_mutex; -static uint8_t key[16]; +static word32 key[16/4]; static roundkey rkk; -static uint8_t iv[16]; +static word32 iv[16/4]; void ao_aes_set_mode(enum ao_aes_mode mode) @@ -389,10 +389,11 @@ ao_aes_run(__xdata uint8_t *in, __xdata uint8_t *out) { uint8_t i; + uint8_t *_iv = (uint8_t *) iv; for (i = 0; i < 16; i++) - iv[i] ^= in[i]; - xrijndaelEncrypt((word32 *) iv, &rkk); + _iv[i] ^= in[i]; + xrijndaelEncrypt(iv, &rkk); if (out) memcpy(out, iv, 16); } diff --git a/src/drivers/ao_gps_ublox.c b/src/drivers/ao_gps_ublox.c index 22af413a..c720f802 100644 --- a/src/drivers/ao_gps_ublox.c +++ b/src/drivers/ao_gps_ublox.c @@ -156,7 +156,7 @@ static char __xdata *ublox_target; static void ublox_u16(uint8_t offset) { - uint16_t __xdata *ptr = (uint16_t __xdata *) (ublox_target + offset); + uint16_t __xdata *ptr = (uint16_t __xdata *) (void __xdata *) (ublox_target + offset); uint16_t val; val = data_byte(); @@ -175,7 +175,7 @@ static void ublox_u8(uint8_t offset) static void ublox_u32(uint8_t offset) __reentrant { - uint32_t __xdata *ptr = (uint32_t __xdata *) (ublox_target + offset); + uint32_t __xdata *ptr = (uint32_t __xdata *) (void __xdata *) (ublox_target + offset); uint32_t val; val = ((uint32_t) data_byte ()); diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index 85034efd..b1227aaa 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -104,7 +104,7 @@ ao_trng_get_cooked(uint16_t *buf) { uint16_t i; uint16_t t; - uint32_t *rnd = (uint32_t *) ao_adc_ring; + uint32_t *rnd = (uint32_t *) (void *) ao_adc_ring; uint8_t mismatch = 0; t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ diff --git a/src/kernel/ao_list.h b/src/kernel/ao_list.h index e2df6885..45a3df5b 100644 --- a/src/kernel/ao_list.h +++ b/src/kernel/ao_list.h @@ -138,7 +138,7 @@ ao_list_is_empty(struct ao_list *head) * @return A pointer to the data struct containing the list head. */ #define ao_container_of(ptr, type, member) \ - ((type *)((char *)(ptr) - offsetof(type, member))) + ((type *)((void *) ((char *)(ptr) - offsetof(type, member)))) /** * Alias of ao_container_of diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index b11d1080..a0881f9e 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -438,7 +438,7 @@ ao_pyro_show(void) if (ao_pyro_values[v].flag & AO_PYRO_8_BIT_VALUE) value = *((uint8_t *) ((char *) pyro + ao_pyro_values[v].offset)); else - value = *((int16_t *) ((char *) pyro + ao_pyro_values[v].offset)); + value = *((int16_t *) (void *) ((char *) pyro + ao_pyro_values[v].offset)); printf ("%6d ", value); } else { printf (" "); @@ -517,7 +517,7 @@ ao_pyro_set(void) } else { if (negative) ao_cmd_lex_i = -ao_cmd_lex_i; - *((int16_t *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i; + *((int16_t *) (void *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i; } } } diff --git a/src/kernel/ao_task.h b/src/kernel/ao_task.h index f1dbd654..30b018ff 100644 --- a/src/kernel/ao_task.h +++ b/src/kernel/ao_task.h @@ -26,6 +26,17 @@ #define HAS_TASK_INFO 1 #endif +/* arm stacks must be 32-bit aligned */ +#ifdef __arm__ +#define AO_STACK_ALIGNMENT __attribute__ ((aligned(4))) +#endif +#ifdef SDCC +#define AO_STACK_ALIGNMENT +#endif +#ifdef __AVR__ +#define AO_STACK_ALIGNMENT +#endif + /* An AltOS task */ struct ao_task { __xdata void *wchan; /* current wait channel (NULL if running) */ @@ -37,7 +48,7 @@ struct ao_task { struct ao_list queue; struct ao_list alarm_queue; #endif - uint8_t stack[AO_STACK_SIZE]; /* saved stack */ + uint8_t stack[AO_STACK_SIZE] AO_STACK_ALIGNMENT; /* saved stack */ #if HAS_SAMPLE_PROFILE uint32_t ticks; uint32_t yields; diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index c3d2707f..0ba86f5a 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -27,7 +27,7 @@ LIBS=$(PDCLIB_LIBS_M3) -lgcc WARN_FLAGS=-Wall -Wextra -Werror AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I.. $(PDCLIB_INCLUDES) -STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb \ +STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) LDFLAGS=-L../stm -Wl,-Taltos.ld diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 18ca20da..a9d0fa34 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -375,7 +375,7 @@ ao_arch_irq_check(void) { static inline void ao_arch_init_stack(struct ao_task *task, void *start) { - uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); + uint32_t *sp = (uint32_t *) ((void*) task->stack + AO_STACK_SIZE); uint32_t a = (uint32_t) start; int i; @@ -413,16 +413,11 @@ static inline void ao_arch_save_stack(void) { uint32_t *sp; asm("mov %0,sp" : "=&r" (sp) ); ao_cur_task->sp = (sp); - if ((uint8_t *) sp < &ao_cur_task->stack[0]) - ao_panic (AO_PANIC_STACK); } static inline void ao_arch_restore_stack(void) { - uint32_t sp; - sp = (uint32_t) ao_cur_task->sp; - /* Switch stacks */ - asm("mov sp, %0" : : "r" (sp) ); + asm("mov sp, %0" : : "r" (ao_cur_task->sp) ); /* Restore PRIMASK */ asm("pop {r0}"); diff --git a/src/stm/ao_eeprom_stm.c b/src/stm/ao_eeprom_stm.c index 05f880b8..4f477122 100644 --- a/src/stm/ao_eeprom_stm.c +++ b/src/stm/ao_eeprom_stm.c @@ -83,7 +83,7 @@ ao_intflash_write32(uint16_t pos, uint32_t w) { volatile uint32_t *addr; - addr = (uint32_t *) (stm_eeprom + pos); + addr = (uint32_t *) (void *) (stm_eeprom + pos); /* Write a word to a valid address in the data EEPROM */ *addr = w; @@ -96,7 +96,7 @@ ao_intflash_write8(uint16_t pos, uint8_t d) uint32_t w, *addr, mask; uint8_t shift; - addr = (uint32_t *) (stm_eeprom + (pos & ~3)); + addr = (uint32_t *) (void *) (stm_eeprom + (pos & ~3)); /* Compute word to be written */ shift = (pos & 3) << 3; diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index f2b8ea94..9d72844e 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -139,7 +139,7 @@ static inline uint32_t set_toggle(uint32_t current_value, static inline uint32_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) { - return (uint32_t *) (stm_usb_sram + 2 * sram_addr); + return (uint32_t *) (((void *) ((uint8_t *) stm_usb_sram + 2 * sram_addr))); } static inline uint32_t ao_usb_epr_stat_rx(uint32_t epr) { diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 463125e2..be1e1d65 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -1961,7 +1961,7 @@ union stm_usb_bdt { #define STM_USB_BDT_SIZE 8 -extern uint8_t stm_usb_sram[]; +extern uint8_t stm_usb_sram[] __attribute__ ((aligned(4))); struct stm_exti { vuint32_t imr; diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index 4862f46e..f3296b69 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -25,7 +25,7 @@ endif ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex CC=$(ARM_CC) -WARN_FLAGS=-Wall -Wextra -Werror +WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES) STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\ diff --git a/src/stmf0/ao_adc_fast.h b/src/stmf0/ao_adc_fast.h index b8b5e003..3f0b0547 100644 --- a/src/stmf0/ao_adc_fast.h +++ b/src/stmf0/ao_adc_fast.h @@ -28,7 +28,7 @@ ao_adc_init(void); /* Total ring size in samples */ #define AO_ADC_RING_SIZE 256 -extern uint16_t ao_adc_ring[AO_ADC_RING_SIZE]; +extern uint16_t ao_adc_ring[AO_ADC_RING_SIZE] __attribute__((aligned(4))); #define ao_adc_ring_step(pos,inc) (((pos) + (inc)) & (AO_ADC_RING_SIZE - 1)) diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index d35bafbd..c38ce41a 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -366,7 +366,7 @@ ao_arch_memory_barrier() { static inline void ao_arch_init_stack(struct ao_task *task, void *start) { - uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); + uint32_t *sp = (uint32_t *) ((void *) task->stack + AO_STACK_SIZE); uint32_t a = (uint32_t) start; int i; diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c index cbedb996..652b3b6c 100644 --- a/src/stmf0/ao_usb_stm.c +++ b/src/stmf0/ao_usb_stm.c @@ -185,7 +185,7 @@ static inline uint32_t set_toggle(uint32_t current_value, static inline uint16_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) { - return (uint16_t *) (stm_usb_sram + sram_addr); + return (uint16_t *) (void *) (stm_usb_sram + sram_addr); } static inline uint16_t ao_usb_packet_buffer_offset(uint16_t *addr) diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index 182cd963..1c33f020 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -1996,7 +1996,7 @@ union stm_usb_bdt { #define STM_USB_BDT_SIZE 8 -extern uint8_t stm_usb_sram[]; +extern uint8_t stm_usb_sram[] __attribute__((aligned(4))); struct stm_exti { vuint32_t imr; -- cgit v1.2.3 From 56d46ceaa1413415f25e47e81036426132f99924 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 31 Oct 2016 16:43:44 -0700 Subject: Add first lisp bits Signed-off-by: Keith Packard --- src/lisp/ao_lisp_atom.c | 107 ++++++++++++++++++ src/lisp/ao_lisp_builtin.c | 21 ++++ src/lisp/ao_lisp_cons.c | 84 +++++++++++++++ src/lisp/ao_lisp_eval.c | 152 ++++++++++++++++++++++++++ src/lisp/ao_lisp_int.c | 21 ++++ src/lisp/ao_lisp_lex.c | 146 +++++++++++++++++++++++++ src/lisp/ao_lisp_mem.c | 246 ++++++++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_poly.c | 132 +++++++++++++++++++++++ src/lisp/ao_lisp_prim.c | 71 ++++++++++++ src/lisp/ao_lisp_string.c | 87 +++++++++++++++ src/stmf0/Makefile-stmf0.defs | 2 +- src/test/Makefile | 13 ++- src/test/ao_lisp_test.c | 58 ++++++++++ 13 files changed, 1136 insertions(+), 4 deletions(-) create mode 100644 src/lisp/ao_lisp_atom.c create mode 100644 src/lisp/ao_lisp_builtin.c create mode 100644 src/lisp/ao_lisp_cons.c create mode 100644 src/lisp/ao_lisp_eval.c create mode 100644 src/lisp/ao_lisp_int.c create mode 100644 src/lisp/ao_lisp_lex.c create mode 100644 src/lisp/ao_lisp_mem.c create mode 100644 src/lisp/ao_lisp_poly.c create mode 100644 src/lisp/ao_lisp_prim.c create mode 100644 src/lisp/ao_lisp_string.c create mode 100644 src/test/ao_lisp_test.c (limited to 'src/stmf0') diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c new file mode 100644 index 00000000..65282142 --- /dev/null +++ b/src/lisp/ao_lisp_atom.c @@ -0,0 +1,107 @@ +/* + * 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 "ao_lisp.h" + +static int name_size(char *name) +{ + return sizeof(struct ao_lisp_atom) + strlen(name) + 1; +} + +static int atom_size(void *addr) +{ + struct ao_lisp_atom *atom = addr; + if (!atom) + return 0; + return name_size(atom->name); +} + +static void atom_mark(void *addr) +{ + struct ao_lisp_atom *atom = addr; + + if (atom->next == AO_LISP_ATOM_CONST) + return; + + for (;;) { + ao_lisp_poly_mark(atom->val); + atom = atom->next; + if (!atom) + break; + if (ao_lisp_mark_memory(atom, atom_size(atom))) + break; + } +} + +static void atom_move(void *addr) +{ + struct ao_lisp_atom *atom = addr; + + if (atom->next == AO_LISP_ATOM_CONST) + return; + + for (;;) { + struct ao_lisp_atom *next; + + atom->val = ao_lisp_poly_move(atom->val); + next = ao_lisp_move_memory(atom->next, atom_size(atom->next)); + if (!next) + break; + atom->next = next; + atom = next; + } +} + +const struct ao_lisp_mem_type ao_lisp_atom_type = { + .mark = atom_mark, + .size = atom_size, + .move = atom_move, +}; + +struct ao_lisp_atom *atoms; + +struct ao_lisp_atom * +ao_lisp_atom_intern(char *name) +{ + struct ao_lisp_atom *atom; + int b; + + for (atom = atoms; atom; atom = atom->next) { + if (!strcmp(atom->name, name)) + return atom; + } + for (b = 0; ao_lisp_builtins[b]; b++) + if (!strcmp(ao_lisp_builtins[b]->name, name)) + return (struct ao_lisp_atom *) ao_lisp_builtins[b]; + if (!atoms) + ao_lisp_root_add(&ao_lisp_atom_type, (void **) &atoms); + atom = ao_lisp_alloc(name_size(name)); + if (atom) { + atom->type = AO_LISP_ATOM; + atom->next = atoms; + atoms = atom; + strcpy(atom->name, name); + atom->val = AO_LISP_NIL; + } + return atom; +} + +void +ao_lisp_atom_print(struct ao_lisp_atom *a) +{ + fputs(a->name, stdout); +} diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c new file mode 100644 index 00000000..3752a2c8 --- /dev/null +++ b/src/lisp/ao_lisp_builtin.c @@ -0,0 +1,21 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +void +ao_lisp_builtin_print(struct ao_lisp_builtin *b) +{ + printf("[builtin %s]", b->name); +} diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c new file mode 100644 index 00000000..60cbb2f3 --- /dev/null +++ b/src/lisp/ao_lisp_cons.c @@ -0,0 +1,84 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +static void cons_mark(void *addr) +{ + struct ao_lisp_cons *cons = addr; + + for (;;) { + ao_lisp_poly_mark(cons->car); + cons = cons->cdr; + if (!cons) + break; + if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) + break; + } +} + +static int cons_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_cons); +} + +static void cons_move(void *addr) +{ + struct ao_lisp_cons *cons = addr; + + for (;;) { + struct ao_lisp_cons *cdr; + + cons->car = ao_lisp_poly_move(cons->car); + cdr = ao_lisp_move_memory(cons->cdr, sizeof (struct ao_lisp_cons)); + if (!cdr) + break; + cons->cdr = cdr; + cons = cdr; + } +} + +const struct ao_lisp_mem_type ao_lisp_cons_type = { + .mark = cons_mark, + .size = cons_size, + .move = cons_move, +}; + +struct ao_lisp_cons * +ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr) +{ + struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + if (!cons) + return NULL; + cons->car = car; + cons->cdr = cdr; + return cons; +} + +void +ao_lisp_cons_print(struct ao_lisp_cons *cons) +{ + int first = 1; + printf("("); + while (cons) { + if (!first) + printf(" "); + fflush(stdout); + ao_lisp_poly_print(cons->car); + cons = cons->cdr; + first = 0; + } + printf(")"); +} diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c new file mode 100644 index 00000000..531e3b72 --- /dev/null +++ b/src/lisp/ao_lisp_eval.c @@ -0,0 +1,152 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +/* + * Non-recursive eval + * + * Plan: walk actuals, construct formals + * + * stack > save > actuals > actual_1 + * v v + * formals . > actual_2 + */ + +static struct ao_lisp_cons *stack; +static struct ao_lisp_cons *actuals; +static struct ao_lisp_cons *formals; +static struct ao_lisp_cons *formals_tail; +static uint8_t been_here; + +ao_lisp_poly +ao_lisp_eval(ao_lisp_poly v) +{ + struct ao_lisp_cons *formal; + int cons = 0; + + if (!been_here) { + been_here = 1; + ao_lisp_root_add(&ao_lisp_cons_type, &stack); + ao_lisp_root_add(&ao_lisp_cons_type, &actuals); + ao_lisp_root_add(&ao_lisp_cons_type, &formals); + ao_lisp_root_add(&ao_lisp_cons_type, &formals_tail); + } + stack = 0; + actuals = 0; + formals = 0; + formals_tail = 0; + for (;;) { + + /* Build stack frames for each list */ + while (ao_lisp_poly_type(v) == AO_LISP_CONS) { + if (v == AO_LISP_NIL) + break; + + /* Push existing frame on the stack */ + if (cons++) { + struct ao_lisp_cons *frame; + + frame = ao_lisp_cons(ao_lisp_cons_poly(actuals), formals); + stack = ao_lisp_cons(ao_lisp_cons_poly(frame), stack); + } + actuals = ao_lisp_poly_cons(v); + formals = NULL; + formals_tail = NULL; + v = actuals->car; + + printf("start: stack"); ao_lisp_cons_print(stack); printf("\n"); + printf("start: actuals"); ao_lisp_cons_print(actuals); printf("\n"); + printf("start: formals"); ao_lisp_cons_print(formals); printf("\n"); + } + + /* Evaluate primitive types */ + + switch (ao_lisp_poly_type(v)) { + case AO_LISP_INT: + case AO_LISP_STRING: + break; + case AO_LISP_ATOM: + v = ao_lisp_poly_atom(v)->val; + break; + } + + for (;;) { + printf("add formal: "); ao_lisp_poly_print(v); printf("\n"); + + formal = ao_lisp_cons(v, NULL); + if (formals_tail) + formals_tail->cdr = formal; + else + formals = formal; + formals_tail = formal; + actuals = actuals->cdr; + + printf("formals: "); + ao_lisp_cons_print(formals); + printf("\n"); + printf("actuals: "); + ao_lisp_cons_print(actuals); + printf("\n"); + + /* Process all of the arguments */ + if (actuals) { + v = actuals->car; + printf ("actual: "); ao_lisp_poly_print(v); printf("\n"); + break; + } + + v = formals->car; + + /* Evaluate the resulting list */ + if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + + v = b->func(formals->cdr); + + printf ("eval: "); + ao_lisp_cons_print(formals); + printf(" -> "); + ao_lisp_poly_print(v); + printf ("\n"); + } else { + printf ("invalid eval\n"); + } + + if (--cons) { + struct ao_lisp_cons *frame; + + /* Pop the previous frame off the stack */ + frame = ao_lisp_poly_cons(stack->car); + actuals = ao_lisp_poly_cons(frame->car); + formals = frame->cdr; + + /* Recompute the tail of the formals list */ + for (formal = formals; formal->cdr != NULL; formal = formal->cdr); + formals_tail = formal; + + stack = stack->cdr; + printf("stack pop: stack"); ao_lisp_cons_print(stack); printf("\n"); + printf("stack pop: actuals"); ao_lisp_cons_print(actuals); printf("\n"); + printf("stack pop: formals"); ao_lisp_cons_print(formals); printf("\n"); + } else { + printf("done func\n"); + break; + } + } + if (!cons) + break; + } + return v; +} diff --git a/src/lisp/ao_lisp_int.c b/src/lisp/ao_lisp_int.c new file mode 100644 index 00000000..6ee3096d --- /dev/null +++ b/src/lisp/ao_lisp_int.c @@ -0,0 +1,21 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +void +ao_lisp_int_print(int i) +{ + printf("%d", i); +} diff --git a/src/lisp/ao_lisp_lex.c b/src/lisp/ao_lisp_lex.c new file mode 100644 index 00000000..d62db872 --- /dev/null +++ b/src/lisp/ao_lisp_lex.c @@ -0,0 +1,146 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +const uint32_t classTable[256] = { + IGNORE, /* ^@ */ + IGNORE, /* ^A */ + IGNORE, /* ^B */ + IGNORE, /* ^C */ + IGNORE, /* ^D */ + IGNORE, /* ^E */ + IGNORE, /* ^F */ + IGNORE, /* ^G */ + IGNORE, /* ^H */ + WHITE, /* ^I */ + WHITE, /* ^J */ + WHITE, /* ^K */ + WHITE, /* ^L */ + WHITE, /* ^M */ + IGNORE, /* ^N */ + IGNORE, /* ^O */ + IGNORE, /* ^P */ + IGNORE, /* ^Q */ + IGNORE, /* ^R */ + IGNORE, /* ^S */ + IGNORE, /* ^T */ + IGNORE, /* ^U */ + IGNORE, /* ^V */ + IGNORE, /* ^W */ + IGNORE, /* ^X */ + IGNORE, /* ^Y */ + IGNORE, /* ^Z */ + IGNORE, /* ^[ */ + IGNORE, /* ^\ */ + IGNORE, /* ^] */ + IGNORE, /* ^^ */ + IGNORE, /* ^_ */ + PRINTABLE|WHITE, /* */ + PRINTABLE, /* ! */ + PRINTABLE|STRINGC, /* " */ + PRINTABLE|COMMENT, /* # */ + PRINTABLE, /* $ */ + PRINTABLE, /* % */ + PRINTABLE, /* & */ + PRINTABLE|QUOTEC, /* ' */ + PRINTABLE|BRA, /* ( */ + PRINTABLE|KET, /* ) */ + PRINTABLE, /* * */ + PRINTABLE|SIGN, /* + */ + PRINTABLE, /* , */ + PRINTABLE|SIGN, /* - */ + PRINTABLE|DOT, /* . */ + PRINTABLE, /* / */ + PRINTABLE|DIGIT, /* 0 */ + PRINTABLE|DIGIT, /* 1 */ + PRINTABLE|DIGIT, /* 2 */ + PRINTABLE|DIGIT, /* 3 */ + PRINTABLE|DIGIT, /* 4 */ + PRINTABLE|DIGIT, /* 5 */ + PRINTABLE|DIGIT, /* 6 */ + PRINTABLE|DIGIT, /* 7 */ + PRINTABLE|DIGIT, /* 8 */ + PRINTABLE|DIGIT, /* 9 */ + PRINTABLE, /* : */ + PRINTABLE|COMMENT, /* ; */ + PRINTABLE, /* < */ + PRINTABLE, /* = */ + PRINTABLE, /* > */ + PRINTABLE, /* ? */ + PRINTABLE, /* @ */ + PRINTABLE, /* A */ + PRINTABLE, /* B */ + PRINTABLE, /* C */ + PRINTABLE, /* D */ + PRINTABLE|EXP, /* E */ + PRINTABLE, /* F */ + PRINTABLE, /* G */ + PRINTABLE, /* H */ + PRINTABLE, /* I */ + PRINTABLE, /* J */ + PRINTABLE, /* K */ + PRINTABLE, /* L */ + PRINTABLE, /* M */ + PRINTABLE, /* N */ + PRINTABLE, /* O */ + PRINTABLE, /* P */ + PRINTABLE, /* Q */ + PRINTABLE, /* R */ + PRINTABLE, /* S */ + PRINTABLE, /* T */ + PRINTABLE, /* U */ + PRINTABLE, /* V */ + PRINTABLE, /* W */ + PRINTABLE, /* X */ + PRINTABLE, /* Y */ + PRINTABLE, /* Z */ + PRINTABLE|BRA, /* [ */ + PRINTABLE|BACKSLASH, /* \ */ + PRINTABLE|KET, /* ] */ + PRINTABLE, /* ^ */ + PRINTABLE, /* _ */ + PRINTABLE, /* ` */ + PRINTABLE, /* a */ + PRINTABLE, /* b */ + PRINTABLE, /* c */ + PRINTABLE, /* d */ + PRINTABLE|EXP, /* e */ + PRINTABLE, /* f */ + PRINTABLE, /* g */ + PRINTABLE, /* h */ + PRINTABLE, /* i */ + PRINTABLE, /* j */ + PRINTABLE, /* k */ + PRINTABLE, /* l */ + PRINTABLE, /* m */ + PRINTABLE, /* n */ + PRINTABLE, /* o */ + PRINTABLE, /* p */ + PRINTABLE, /* q */ + PRINTABLE, /* r */ + PRINTABLE, /* s */ + PRINTABLE, /* t */ + PRINTABLE, /* u */ + PRINTABLE, /* v */ + PRINTABLE, /* w */ + PRINTABLE, /* x */ + PRINTABLE, /* y */ + PRINTABLE, /* z */ + PRINTABLE|BRA, /* { */ + PRINTABLE|VBAR, /* | */ + PRINTABLE|KET, /* } */ + PRINTABLE|TWIDDLE, /* ~ */ + IGNORE, /* ^? */ +}; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c new file mode 100644 index 00000000..f6a108e9 --- /dev/null +++ b/src/lisp/ao_lisp_mem.c @@ -0,0 +1,246 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" +#include + +uint8_t ao_lisp_pool[AO_LISP_POOL]; + +struct ao_lisp_root { + void **addr; + const struct ao_lisp_mem_type *type; +}; + +static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; + +static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; + +static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; + +static uint16_t ao_lisp_top; + +static inline void mark(uint8_t *tag, int offset) { + int byte = offset >> 5; + int bit = (offset >> 2) & 7; + tag[byte] |= (1 << bit); +} + +static inline void clear(uint8_t *tag, int offset) { + int byte = offset >> 5; + int bit = (offset >> 2) & 7; + tag[byte] &= ~(1 << bit); +} + +static inline int busy(uint8_t *tag, int offset) { + int byte = offset >> 5; + int bit = (offset >> 2) & 7; + return (tag[byte] >> bit) & 1; +} + +static inline int min(int a, int b) { return a < b ? a : b; } +static inline int max(int a, int b) { return a > b ? a : b; } + +static inline int limit(int offset) { + return min(AO_LISP_POOL, max(offset, 0)); +} + +static int +mark_object(uint8_t *tag, void *addr, int size) { + int base; + int bound; + if (!addr) + return 1; + + base = (uint8_t *) addr - ao_lisp_pool; + bound = base + size; + + base = limit(base); + bound = limit(bound); + if (busy(tag, base)) + return 1; + while (base < bound) { + mark(tag, base); + base += 4; + } + return 0; +} + +static int +clear_object(uint8_t *tag, void *addr, int size) { + int base; + int bound; + if (!addr) + return 1; + + base = (uint8_t *) addr - ao_lisp_pool; + bound = base + size; + + base = limit(base); + bound = limit(bound); + if (!busy(tag, base)) + return 1; + while (base < bound) { + clear(tag, base); + base += 4; + } + return 0; +} + +static void *move_old, *move_new; +static int move_size; + +static void +move_object(void) +{ + int i; + + memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); + for (i = 0; i < AO_LISP_ROOT; i++) + if (ao_lisp_root[i].addr) { + void *new; + new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr); + if (new) + *ao_lisp_root[i].addr = new; + } +} + +static void +collect(void) +{ + int i; + + printf("collect\n"); + /* Mark */ + memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + for (i = 0; i < AO_LISP_ROOT; i++) + if (ao_lisp_root[i].addr) + ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr); + + /* Compact */ + ao_lisp_top = 0; + for (i = 0; i < AO_LISP_POOL; i += 4) { + if (!busy(ao_lisp_busy, i)) + break; + } + ao_lisp_top = i; + while(i < AO_LISP_POOL) { + if (busy(ao_lisp_busy, i)) { + move_old = &ao_lisp_pool[i]; + move_new = &ao_lisp_pool[ao_lisp_top]; + move_size = 0; + move_object(); + clear_object(ao_lisp_busy, move_old, move_size); + i += move_size; + ao_lisp_top += move_size; + } else { + i += 4; + } + } +} + + +void +ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr) +{ + if (mark_object(ao_lisp_busy, addr, type->size(addr))) + return; + type->mark(addr); +} + +int +ao_lisp_mark_memory(void *addr, int size) +{ + return mark_object(ao_lisp_busy, addr, size); +} + +static void * +check_move(void *addr, int size) +{ + if (addr == move_old) { + memmove(move_new, move_old, size); + move_size = (size + 3) & ~3; + addr = move_new; + } + return addr; +} + +void * +ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr) +{ + int size = type->size(addr); + + if (!addr) + return NULL; + + addr = check_move(addr, size); + if (mark_object(ao_lisp_moving, addr, size)) + return addr; + type->move(addr); + return addr; +} + +void * +ao_lisp_move_memory(void *addr, int size) +{ + if (!addr) + return NULL; + + addr = check_move(addr, size); + if (mark_object(ao_lisp_moving, addr, size)) + return NULL; + return addr; +} + +void * +ao_lisp_alloc(int size) +{ + void *addr; + + size = (size + 3) & ~3; + if (ao_lisp_top + size > AO_LISP_POOL) { + collect(); + if (ao_lisp_top + size > AO_LISP_POOL) + return NULL; + } + addr = ao_lisp_pool + ao_lisp_top; + ao_lisp_top += size; + return addr; +} + +int +ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr) +{ + int i; + for (i = 0; i < AO_LISP_ROOT; i++) { + if (!ao_lisp_root[i].addr) { + ao_lisp_root[i].addr = addr; + ao_lisp_root[i].type = type; + return 1; + } + } + return 0; +} + +void +ao_lisp_root_clear(void *addr) +{ + int i; + for (i = 0; i < AO_LISP_ROOT; i++) { + if (ao_lisp_root[i].addr == addr) { + ao_lisp_root[i].addr = 0; + ao_lisp_root[i].type = 0; + break; + } + } +} diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c new file mode 100644 index 00000000..1855d945 --- /dev/null +++ b/src/lisp/ao_lisp_poly.c @@ -0,0 +1,132 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; + +ao_lisp_poly +ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) +{ + ao_lisp_poly ret = AO_LISP_NIL; + + while (cons) { + ao_lisp_poly car = cons->car; + uint8_t rt = ao_lisp_poly_type(ret); + uint8_t ct = ao_lisp_poly_type(car); + + cons = cons->cdr; + + if (rt == AO_LISP_NIL) + ret = car; + + else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { + int r = ao_lisp_poly_int(ret); + int c = ao_lisp_poly_int(car); + + switch(op) { + case math_plus: + r += c; + break; + case math_minus: + r -= c; + break; + case math_times: + r *= c; + break; + case math_divide: + if (c == 0) + return AO_LISP_NIL; + r /= c; + break; + case math_mod: + if (c == 0) + return AO_LISP_NIL; + r %= c; + break; + } + ret = ao_lisp_int_poly(r); + } + + else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) + ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), + ao_lisp_poly_string(car))); + else { + /* XXX exception */ + return AO_LISP_NIL; + } + } + return ret; +} + +ao_lisp_poly +ao_lisp_plus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_plus); +} + +ao_lisp_poly +ao_lisp_minus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_minus); +} + +ao_lisp_poly +ao_lisp_times(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_times); +} + +ao_lisp_poly +ao_lisp_divide(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_divide); +} + +ao_lisp_poly +ao_lisp_mod(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_mod); +} + +static const struct ao_lisp_builtin builtin_plus = { + .type = AO_LISP_BUILTIN, + .func = ao_lisp_plus, + .name = "+" +}; + +static const struct ao_lisp_atom atom_plus = { + .type = AO_LISP_ATOM, + .val = AO_LISP_OTHER_POLY(&builtin_plus), + .next = AO_LISP_ATOM_CONST, + .name = "plus" +}; + +/* +static const struct ao_lisp_builtin builtin_minus = { + .type = AO_LISP_BUILTIN, + .func = ao_lisp_minus +}; + +static const struct ao_lisp_builtin builtin_times = { + .type = AO_LISP_BUILTIN, + .func = ao_lisp_times +}; + +*/ + +const struct ao_lisp_atom const *ao_lisp_builtins[] = { + &atom_plus, + 0 +}; diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c new file mode 100644 index 00000000..ccfd2be4 --- /dev/null +++ b/src/lisp/ao_lisp_prim.c @@ -0,0 +1,71 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" + +ao_lisp_poly +ao_lisp_poly_print(ao_lisp_poly p) +{ + switch (ao_lisp_poly_type(p)) { + case AO_LISP_CONS: + ao_lisp_cons_print(ao_lisp_poly_cons(p)); + break; + case AO_LISP_STRING: + ao_lisp_string_print(ao_lisp_poly_string(p)); + break; + case AO_LISP_INT: + ao_lisp_int_print(ao_lisp_poly_int(p)); + break; + case AO_LISP_ATOM: + ao_lisp_atom_print(ao_lisp_poly_atom(p)); + break; + case AO_LISP_BUILTIN: + ao_lisp_builtin_print(ao_lisp_poly_builtin(p)); + break; + } + return AO_LISP_NIL; +} + +void +ao_lisp_poly_mark(ao_lisp_poly p) +{ + switch (ao_lisp_poly_type(p)) { + case AO_LISP_CONS: + ao_lisp_mark(&ao_lisp_cons_type, ao_lisp_poly_cons(p)); + break; + case AO_LISP_STRING: + ao_lisp_mark(&ao_lisp_string_type, ao_lisp_poly_string(p)); + break; + case AO_LISP_ATOM: + ao_lisp_mark(&ao_lisp_atom_type, ao_lisp_poly_atom(p)); + break; + } +} + +ao_lisp_poly +ao_lisp_poly_move(ao_lisp_poly p) +{ + switch (ao_lisp_poly_type(p)) { + case AO_LISP_CONS: + p = ao_lisp_cons_poly(ao_lisp_move(&ao_lisp_cons_type, ao_lisp_poly_cons(p))); + break; + case AO_LISP_STRING: + p = ao_lisp_string_poly(ao_lisp_move(&ao_lisp_string_type, ao_lisp_poly_string(p))); + break; + case AO_LISP_ATOM: + p = ao_lisp_atom_poly(ao_lisp_move(&ao_lisp_atom_type, ao_lisp_poly_atom(p))); + break; + } + return p; +} diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c new file mode 100644 index 00000000..87024271 --- /dev/null +++ b/src/lisp/ao_lisp_string.c @@ -0,0 +1,87 @@ +/* + * 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 "ao_lisp.h" + +static void string_mark(void *addr) +{ + (void) addr; +} + +static int string_size(void *addr) +{ + if (!addr) + return 0; + return strlen(addr) + 1; +} + +static void string_move(void *addr) +{ + (void) addr; +} + +char * +ao_lisp_string_new(int len) { + char *a = ao_lisp_alloc(len + 1); + if (!a) + return NULL; + a[len] = '\0'; + return a; +} + +char * +ao_lisp_string_cat(char *a, char *b) +{ + int alen = strlen(a); + int blen = strlen(b); + char *r = ao_lisp_alloc(alen + blen + 1); + if (!r) + return NULL; + strcpy(r, a); + strcpy(r+alen, b); + return r; +} + +const struct ao_lisp_mem_type ao_lisp_string_type = { + .mark = string_mark, + .size = string_size, + .move = string_move, +}; + +void +ao_lisp_string_print(char *s) +{ + char c; + putchar('"'); + while ((c = *s++)) { + switch (c) { + case '\n': + printf ("\\n"); + break; + case '\r': + printf ("\\r"); + break; + case '\t': + printf ("\\t"); + break; + default: + putchar(c); + break; + } + } + putchar('"'); +} diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index f3296b69..0ccfbe2a 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -4,7 +4,7 @@ endif include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math +vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp vpath make-altitude $(TOPDIR)/util vpath make-kalman $(TOPDIR)/util vpath kalman.5c $(TOPDIR)/kalman diff --git a/src/test/Makefile b/src/test/Makefile index 02e1d22b..a409ae13 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,16 +1,16 @@ -vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product +vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product:../lisp PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \ ao_flight_test_metrum \ ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \ ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \ - ao_ms5607_convert_test ao_quaternion_test + ao_ms5607_convert_test ao_quaternion_test ao_lisp_test INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h KALMAN=make-kalman -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -O0 -g -Wall +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall all: $(PROGS) ao_aprs_data.wav @@ -88,3 +88,10 @@ ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm + +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o + +ao_lisp_test: $(AO_LISP_OBJS) + cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) + +$(AO_LISP_OBJS): ao_lisp.h diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c new file mode 100644 index 00000000..bbadfa75 --- /dev/null +++ b/src/test/ao_lisp_test.c @@ -0,0 +1,58 @@ +/* + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +#include "ao_lisp.h" +#include + +static struct ao_lisp_cons *list; +static char *string; + +int +main (int argc, char **argv) +{ + int i, j; + struct ao_lisp_atom *atom; + ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); + ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); + + /* allocator test */ + for (j = 0; j < 10; j++) { + list = 0; + string = ao_lisp_string_new(0); + for (i = 0; i < 7; i++) { + string = ao_lisp_string_cat(string, "a"); + list = ao_lisp_cons(ao_lisp_string_poly(string), list); + list = ao_lisp_cons(ao_lisp_int_poly(i), list); + atom = ao_lisp_atom_intern("ant"); + atom->val = ao_lisp_cons_poly(list); + list = ao_lisp_cons(ao_lisp_atom_poly(atom), list); + } + ao_lisp_poly_print(ao_lisp_cons_poly(list)); + printf("\n"); + } + + atom = ao_lisp_atom_intern("ant"); + atom->val = ao_lisp_string_poly(ao_lisp_string_cat("hello world", "")); + + list = ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), + ao_lisp_cons(ao_lisp_cons_poly(ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), + ao_lisp_cons(ao_lisp_int_poly(3), + ao_lisp_cons(ao_lisp_int_poly(4), NULL)))), + ao_lisp_cons(ao_lisp_int_poly(2), NULL))); + printf("list: "); + ao_lisp_poly_print(ao_lisp_cons_poly(list)); + printf ("\n"); + ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); + printf ("\n"); +} -- cgit v1.2.3 From 8362393a621ea78a96e7f65f602f4bfc7bbd1158 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Nov 2016 14:18:31 -0700 Subject: altos/stmf0: Add lisp to include directories Signed-off-by: Keith Packard --- src/stmf0/Makefile-stmf0.defs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/stmf0') diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index 0ccfbe2a..2ea3d1d8 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -27,7 +27,10 @@ CC=$(ARM_CC) WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align -AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES) +AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \ + -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR)/lisp \ + $(PDCLIB_INCLUDES) + STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) -- cgit v1.2.3 From 30db58ade19ec69272a8c39c2f13d7919ca491a9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 23:36:22 -0800 Subject: altos/lambdakey: Get save/restore working Need the HSI clock running for the flash hardware to work. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 7 ++- src/lambdakey-v1.0/ao_pins.h | 6 ++- src/lambdakey-v1.0/lambda.ld | 117 +++++++++++++++++++++++++++++++++++++++++++ src/stmf0/ao_flash_stm.c | 7 +-- 4 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 src/lambdakey-v1.0/lambda.ld (limited to 'src/stmf0') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index 1ac04f24..c71e1ab5 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -34,6 +34,7 @@ ALTOS_SRC = \ ao_mutex.c \ ao_usb_stm.c \ ao_serial_stm.c \ + ao_flash_stm.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ ao_lisp_cons.c \ @@ -41,20 +42,22 @@ ALTOS_SRC = \ ao_lisp_string.c \ ao_lisp_atom.c \ ao_lisp_int.c \ - ao_lisp_prim.c \ + ao_lisp_poly.c \ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_rep.c \ ao_lisp_frame.c \ ao_lisp_error.c \ ao_lisp_lambda.c \ + ao_lisp_save.c \ + ao_lisp_os_save.c \ ao_exti_stm.c PRODUCT=LambdaKey-v1.0 PRODUCT_DEF=-DLAMBDAKEY IDPRODUCT=0x000a -CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g +CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index b8429c55..167d0857 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -25,9 +25,13 @@ #define AO_LED_RED (1 << LED_PIN_RED) #define AO_LED_PANIC AO_LED_RED #define AO_CMD_LEN 128 -#define AO_LISP_POOL 3072 +#define AO_LISP_POOL_TOTAL 3072 +#define AO_LISP_SAVE 1 #define AO_STACK_SIZE 1024 +/* need HSI active to write to flash */ +#define AO_NEED_HSI 1 + #define LEDS_AVAILABLE (AO_LED_RED) #define AO_POWER_MANAGEMENT 0 diff --git a/src/lambdakey-v1.0/lambda.ld b/src/lambdakey-v1.0/lambda.ld new file mode 100644 index 00000000..5de65eb5 --- /dev/null +++ b/src/lambdakey-v1.0/lambda.ld @@ -0,0 +1,117 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08001000, LENGTH = 25K + flash (r): ORIGIN = 0x08007400, LENGTH = 3k + ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 128 + stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) { + __interrupt_start__ = .; + __interrupt_rom__ = ORIGIN(rom); + *(.interrupt) /* Interrupt vectors */ + __interrupt_end__ = .; + } > ram + + .text ORIGIN(rom) + 0x100 : { + __text_start__ = .; + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + + *(.text*) /* Executable code */ + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.rodata*) /* Constants */ + + } > rom + __text_end__ = .; + + + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot (NOLOAD) : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + + /* Functions placed in RAM (required for flashing) + * + * Align to 8 bytes as that's what the ARM likes text + * segment alignments to be, and if we don't, then + * we end up with a mismatch between the location in + * ROM and the desired location in RAM. I don't + * entirely understand this, but at least this appears + * to work... + */ + + .textram BLOCK(8): { + __data_start__ = .; + __text_ram_start__ = .; + *(.ramtext) + __text_ram_end = .; + } >ram AT>rom + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + + __flash__ = ORIGIN(flash); +} + +ENTRY(start); diff --git a/src/stmf0/ao_flash_stm.c b/src/stmf0/ao_flash_stm.c index 2aeff388..ef2e2619 100644 --- a/src/stmf0/ao_flash_stm.c +++ b/src/stmf0/ao_flash_stm.c @@ -44,12 +44,7 @@ ao_flash_lock(void) stm_flash.cr |= (1 << STM_FLASH_CR_LOCK); } -static void -ao_flash_wait_bsy(void) -{ - while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) - ; -} +#define ao_flash_wait_bsy() do { while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)); } while (0) static void __attribute__ ((section(".ramtext"),noinline)) _ao_flash_erase_page(uint32_t *page) -- cgit v1.2.3 From affcf6ffc08313151541993ee543bfe390165e81 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 23:38:03 -0800 Subject: altos/stmf0: Add a comment about the requirements for using ao_flash_stm Need HSI clock and the flashing functions loaded in ram. Signed-off-by: Keith Packard --- src/stmf0/ao_flash_stm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_flash_stm.c b/src/stmf0/ao_flash_stm.c index ef2e2619..2d57eea7 100644 --- a/src/stmf0/ao_flash_stm.c +++ b/src/stmf0/ao_flash_stm.c @@ -19,6 +19,12 @@ #include #include +/* Note that the HSI clock must be running for this code to work. + * Also, special care must be taken with the linker to ensure that the + * functions marked 'ramtext' land in ram and not rom. An example of that + * can be found in altos-loader.ld + */ + static uint8_t ao_flash_is_locked(void) { -- cgit v1.2.3 From d96224c2fdc535d08de23aec30d62d4ada9fb8d3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 22 Jan 2017 15:29:13 -0800 Subject: altos/chaoskey: use both halves of the CRC When pulling 16 bits from the 32-bit crc, instead of just using the low bits, xor the two halves together. This appears to even out the number of zero and one bits. Signed-off-by: Keith Packard --- src/chaoskey-v1.0/Makefile | 1 + src/stmf0/ao_crc.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/stmf0') diff --git a/src/chaoskey-v1.0/Makefile b/src/chaoskey-v1.0/Makefile index f6b78d07..f2c168ba 100644 --- a/src/chaoskey-v1.0/Makefile +++ b/src/chaoskey-v1.0/Makefile @@ -14,6 +14,7 @@ INC = \ ao_task.h \ ao_adc_fast.h \ ao_power.h \ + ao_crc.h \ stm32f0.h # diff --git a/src/stmf0/ao_crc.h b/src/stmf0/ao_crc.h index 7acc6f9c..b6d91023 100644 --- a/src/stmf0/ao_crc.h +++ b/src/stmf0/ao_crc.h @@ -35,7 +35,8 @@ static inline uint16_t ao_crc_in_32_out_16(uint32_t v) { stm_crc.dr.u32 = v; - return stm_crc.dr.u16; + v = stm_crc.dr.u32; + return v ^ (v >> 16); } static inline uint16_t -- cgit v1.2.3 From f85997eb53779e637dca697d0d96da7d1235fa80 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 3 Feb 2017 06:51:11 +0100 Subject: altos/stmf0: Allow apps to leave interrupt vectors at 0 TeleMini v3.0 doesn't need a boot loader, so we'll have the app run its interrupt vector right at the bottom of the address space instead of copying it to the bottom of ram and reconfiguring the chip to use that. Signed-off-by: Keith Packard --- src/stmf0/ao_interrupt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_interrupt.c b/src/stmf0/ao_interrupt.c index 79412483..fcd330f1 100644 --- a/src/stmf0/ao_interrupt.c +++ b/src/stmf0/ao_interrupt.c @@ -26,9 +26,11 @@ #define IS_FLASH_LOADER 0 #endif +#ifndef RELOCATE_INTERRUPT #if !IS_FLASH_LOADER #define RELOCATE_INTERRUPT 1 #endif +#endif extern void main(void); extern char __stack__; -- cgit v1.2.3 From 3770a5f527cb6d519ce22fe91e0cc4078bf72661 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:53:03 -0800 Subject: altos/stmf0: Complain if the SPI configuration isn't complete If the pin usage values SPI_1_PA5_PA6_PA7 or SPI_1_PB3_PB4_PB5 aren't defined, then the speed values for the pins aren't going to get set correctly, which results in erratic SPI behaviour. Signed-off-by: Keith Packard --- src/stmf0/ao_spi_stm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c index 0448ad8c..5e76d6c3 100644 --- a/src/stmf0/ao_spi_stm.c +++ b/src/stmf0/ao_spi_stm.c @@ -536,12 +536,18 @@ void ao_spi_init(void) { #if HAS_SPI_1 +#ifndef SPI_1_PA5_PA6_PA7 +#error SPI_1_PA5_PA6_PA7 undefined +#endif # if SPI_1_PA5_PA6_PA7 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR); stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR); stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR); # endif +# ifndef SPI_1_PB3_PB4_PB5 +# error SPI_1_PB3_PB4_PB5 undefined +# endif # if SPI_1_PB3_PB4_PB5 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR); -- cgit v1.2.3 From cf10239e5485a101fcd7a12b28be927af94d577a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:54:35 -0800 Subject: altos/stmf0: Allow projects to not use the USB boot loader Let applications define HAS_BOOT_LOADER on their own if desired. Signed-off-by: Keith Packard --- src/stmf0/ao_arch.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_arch.h b/src/stmf0/ao_arch.h index a36482b6..c5f451f5 100644 --- a/src/stmf0/ao_arch.h +++ b/src/stmf0/ao_arch.h @@ -144,10 +144,15 @@ ao_adc_init(); /* ADC maximum reported value */ #define AO_ADC_MAX 4095 +#ifndef HAS_BOOT_LOADER +#define HAS_BOOT_LOADER 1 +#endif + +#if HAS_BOOT_LOADER #define AO_BOOT_APPLICATION_BASE ((uint32_t *) 0x08001000) #define AO_BOOT_APPLICATION_BOUND ((uint32_t *) (0x08000000 + stm_flash_size())) #define AO_BOOT_LOADER_BASE ((uint32_t *) 0x08000000) -#define HAS_BOOT_LOADER 1 +#endif #endif /* _AO_ARCH_H_ */ -- cgit v1.2.3 From b94fe9915b33283df6b86bcdc96ceada1fc71ce6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Feb 2017 17:42:05 -0800 Subject: altos/stmf0: Add adc and beep support for TeleMini v3.0 Note that the ADC code is running very slowly as required by the high impedance dividers on the TeleMini v3.0 pyro circuits. Signed-off-by: Keith Packard --- src/stmf0/altos-raw.ld | 85 +++++++++++ src/stmf0/ao_adc_stm.c | 340 +++++++++++++++++++++++++++++++++++++++++++ src/stmf0/ao_beep_stm.c | 185 +++++++++++++++++++++++ src/stmf0/ao_spi_stm_slave.c | 339 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 949 insertions(+) create mode 100644 src/stmf0/altos-raw.ld create mode 100644 src/stmf0/ao_adc_stm.c create mode 100644 src/stmf0/ao_beep_stm.c create mode 100644 src/stmf0/ao_spi_stm_slave.c (limited to 'src/stmf0') diff --git a/src/stmf0/altos-raw.ld b/src/stmf0/altos-raw.ld new file mode 100644 index 00000000..eb285e07 --- /dev/null +++ b/src/stmf0/altos-raw.ld @@ -0,0 +1,85 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 128 + stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .interrupt : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + } > rom + + .text ORIGIN(rom) + 0x100 : { + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + + *(.text*) /* Executable code */ + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.rodata*) /* Constants */ + + } > rom + __text_end__ = .; + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + __data_start__ = .; + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); +} + +ENTRY(start); + + diff --git a/src/stmf0/ao_adc_stm.c b/src/stmf0/ao_adc_stm.c new file mode 100644 index 00000000..2b23dc50 --- /dev/null +++ b/src/stmf0/ao_adc_stm.c @@ -0,0 +1,340 @@ +/* + * Copyright © 2015 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 + +#define AO_ADC_DEBUG 0 + +static uint8_t ao_adc_ready; + +/* + * Callback from DMA ISR + * + * Mark time in ring, shut down DMA engine + */ +static void ao_adc_done(int index) +{ + (void) index; + /* Clear ISR bits */ + stm_adc.isr = ((1 << STM_ADC_ISR_AWD) | + (1 << STM_ADC_ISR_OVR) | + (1 << STM_ADC_ISR_EOSEQ) | + (1 << STM_ADC_ISR_EOC)); + + AO_DATA_PRESENT(AO_DATA_ADC); + ao_dma_done_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + if (ao_data_present == AO_DATA_ALL) { +#if HAS_MS5607 + ao_data_ring[ao_data_head].ms5607_raw = ao_ms5607_current; +#endif +#if HAS_MMA655X + ao_data_ring[ao_data_head].mma655x = ao_mma655x_current; +#endif +#if HAS_HMC5883 + ao_data_ring[ao_data_head].hmc5883 = ao_hmc5883_current; +#endif +#if HAS_MPU6000 + ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current; +#endif + ao_data_ring[ao_data_head].tick = ao_tick_count; + ao_data_head = ao_data_ring_next(ao_data_head); + ao_wakeup((void *) &ao_data_head); + } + ao_adc_ready = 1; +} + +/* + * Start the ADC sequence using the DMA engine + */ +void +ao_adc_poll(void) +{ + if (!ao_adc_ready) + return; + ao_adc_ready = 0; + stm_adc.isr = 0; + ao_dma_set_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), + &stm_adc.dr, + (void *) (&ao_data_ring[ao_data_head].adc), + AO_NUM_ADC, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) | + (1 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | + (1 << STM_DMA_CCR_TCIE)); + ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_done); + ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + + stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); +} + +static void +ao_adc_dump(void) +{ + struct ao_data packet; + + ao_data_get(&packet); + AO_ADC_DUMP(&packet); +} + +#if AO_ADC_DEBUG +static void +ao_adc_one(void) +{ + int ch; + uint16_t value; + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + ch = ao_cmd_lex_i; + if (ch < 0 || AO_NUM_ADC <= ch) { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + + ao_timer_set_adc_interval(0); + ao_delay(1); + + printf("At top, data %u isr %04x cr %04x\n", stm_adc.dr, stm_adc.isr, stm_adc.cr); + + if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { + printf("Disabling\n"); flush(); + stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); + while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) + ; + printf("Disabled\n"); flush(); + } + + /* Turn off everything */ + stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADSTP) | + (1 << STM_ADC_CR_ADSTART) | + (1 << STM_ADC_CR_ADEN)); + + printf("After disable, ADC status %04x\n", stm_adc.cr); + + /* Configure */ + stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */ + (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */ + (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */ + (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */ + (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */ + (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */ + (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */ + (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */ + (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */ + (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */ + (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */ + (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */ + (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ + (0 << STM_ADC_CFGR1_DMAEN)); /* disable DMA */ + + stm_adc.chselr = (1 << ch); + + /* Longest sample time */ + stm_adc.smpr = STM_ADC_SMPR_SMP_41_5 << STM_ADC_SMPR_SMP; + + printf("Before enable, ADC status %04x\n", stm_adc.cr); flush(); + /* Enable */ + stm_adc.cr |= (1 << STM_ADC_CR_ADEN); + while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) + ; + + /* Start */ + stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); + + /* Wait for conversion complete */ + while (!(stm_adc.isr & (1 << STM_ADC_ISR_EOC))) + ; + + value = stm_adc.dr; + printf ("value %u, cr is %04x isr is %04x\n", + value, stm_adc.cr, stm_adc.isr); + + + /* Clear ISR bits */ + stm_adc.isr = ((1 << STM_ADC_ISR_AWD) | + (1 << STM_ADC_ISR_OVR) | + (1 << STM_ADC_ISR_EOSEQ) | + (1 << STM_ADC_ISR_EOC)); +} +#endif + +__code struct ao_cmds ao_adc_cmds[] = { + { ao_adc_dump, "a\0Display current ADC values" }, +#if AO_ADC_DEBUG + { ao_adc_one, "A ch\0Display one ADC channel" }, +#endif + { 0, NULL }, +}; + +void +ao_adc_init(void) +{ + uint32_t chselr; + + /* Reset ADC */ + stm_rcc.apb2rstr |= (1 << STM_RCC_APB2RSTR_ADCRST); + stm_rcc.apb2rstr &= ~(1 << STM_RCC_APB2RSTR_ADCRST); + + /* Turn on ADC pins */ + stm_rcc.ahbenr |= AO_ADC_RCC_AHBENR; + +#ifdef AO_ADC_PIN0_PORT + stm_moder_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN1_PORT + stm_moder_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN2_PORT + stm_moder_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN3_PORT + stm_moder_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN4_PORT + stm_moder_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN5_PORT + stm_moder_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN6_PORT + stm_moder_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN7_PORT + stm_moder_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN24_PORT + #error "Too many ADC ports" +#endif + + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN); + + chselr = 0; +#if AO_NUM_ADC > 0 + chselr |= (1 << AO_ADC_PIN0_CH); +#endif +#if AO_NUM_ADC > 1 + chselr |= (1 << AO_ADC_PIN1_CH); +#endif +#if AO_NUM_ADC > 2 + chselr |= (1 << AO_ADC_PIN2_CH); +#endif +#if AO_NUM_ADC > 3 + chselr |= (1 << AO_ADC_PIN3_CH); +#endif +#if AO_NUM_ADC > 4 + chselr |= (1 << AO_ADC_PIN4_CH); +#endif +#if AO_NUM_ADC > 5 + chselr |= (1 << AO_ADC_PIN5_CH); +#endif +#if AO_NUM_ADC > 6 + chselr |= (1 << AO_ADC_PIN6_CH); +#endif +#if AO_NUM_ADC > 7 + chselr |= (1 << AO_ADC_PIN7_CH); +#endif +#if AO_NUM_ADC > 8 +#error Need more ADC defines +#endif + + /* Wait for ADC to be idle */ + while (stm_adc.cr & ((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADDIS))) + ; + + /* Disable */ + if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { + stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); + while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) + ; + } + + /* Turn off everything */ + stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADSTP) | + (1 << STM_ADC_CR_ADSTART) | + (1 << STM_ADC_CR_ADEN)); + + /* Configure */ + stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */ + (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */ + (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */ + (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */ + (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */ + (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */ + (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */ + (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */ + (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */ + (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */ + (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */ + (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */ + (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ + (1 << STM_ADC_CFGR1_DMAEN)); /* enable DMA */ + + /* Set the clock */ + stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE; + + /* Shortest sample time */ + stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP; + + stm_adc.chselr = chselr; + + stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) | + (0 << STM_ADC_CCR_TSEN) | + (0 << STM_ADC_CCR_VREFEN)); + + /* Calibrate */ + stm_adc.cr |= (1 << STM_ADC_CR_ADCAL); + while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0) + ; + + /* Enable */ + stm_adc.cr |= (1 << STM_ADC_CR_ADEN); + while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) + ; + + /* Clear any stale status bits */ + stm_adc.isr = 0; + + /* Turn on syscfg */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + + /* Set ADC to use DMA channel 1 (option 1) */ + stm_syscfg.cfgr1 &= ~(1 << STM_SYSCFG_CFGR1_ADC_DMA_RMP); + + ao_dma_alloc(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + + ao_cmd_register(&ao_adc_cmds[0]); + + ao_adc_ready = 1; +} diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c new file mode 100644 index 00000000..fc83bb63 --- /dev/null +++ b/src/stmf0/ao_beep_stm.c @@ -0,0 +1,185 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +#ifndef BEEPER_CHANNEL +#error BEEPER_CHANNEL undefined +#endif + +void +ao_beep(uint8_t beep) +{ + if (beep == 0) { + stm_tim1.cr1 = 0; + stm_tim1.bdtr = 0; + stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); + } else { + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_TIM1EN); + + /* Master output enable */ + stm_tim1.bdtr = (1 << STM_TIM1_BDTR_MOE); + + stm_tim1.cr2 = ((0 << STM_TIM1_CR2_TI1S) | + (STM_TIM1_CR2_MMS_RESET << STM_TIM1_CR2_MMS) | + (0 << STM_TIM1_CR2_CCDS)); + + /* Set prescaler to match cc1111 clocks + */ + stm_tim1.psc = AO_TIM_CLK / 750000; + + /* 1. Select the counter clock (internal, external, prescaler). + * + * Setting SMCR to zero means use the internal clock + */ + + stm_tim1.smcr = 0; + + /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */ + stm_tim1.arr = beep; + stm_tim1.ccr1 = beep; + + /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a + * DMA request is to be generated. + */ + /* don't want this */ + + /* 4. Select the output mode. For example, you must write + * OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output + * pin when CNT matches CCRx, CCRx preload is not used, OCx + * is enabled and active high. + */ + +#if BEEPER_CHANNEL == 1 + stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | + (STM_TIM1_CCMR1_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | + (0 << STM_TIM1_CCMR1_OC2PE) | + (0 << STM_TIM1_CCMR1_OC2FE) | + (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + + (0 << STM_TIM1_CCMR1_OC1CE) | + (STM_TIM1_CCMR1_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | + (0 << STM_TIM1_CCMR1_OC1PE) | + (0 << STM_TIM1_CCMR1_OC1FE) | + (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | + (0 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3NE) | + (0 << STM_TIM1_CCER_CC3P) | + (0 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2NE) | + (0 << STM_TIM1_CCER_CC2P) | + (0 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NE) | + (0 << STM_TIM1_CCER_CC1P) | + (1 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 3 + stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | + (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR2_OC4M) | + (0 << STM_TIM1_CCMR2_OC4PE) | + (0 << STM_TIM1_CCMR2_OC4FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC4S) | + + (0 << STM_TIM1_CCMR2_OC3CE) | + (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR2_OC3M) | + (0 << STM_TIM1_CCMR2_OC3PE) | + (0 << STM_TIM1_CCMR2_OC3FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC3S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | + (0 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3NE) | + (0 << STM_TIM1_CCER_CC3P) | + (1 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2NE) | + (0 << STM_TIM1_CCER_CC2P) | + (0 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NE) | + (0 << STM_TIM1_CCER_CC1P) | + (0 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 4 + stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | + (STM_TIM1_CCMR2_OC4M_TOGGLE << STM_TIM1_CCMR2_OC4M) | + (0 << STM_TIM1_CCMR2_OC4PE) | + (0 << STM_TIM1_CCMR2_OC4FE) | + (STM_TIM1_CCMR2_CC4S_OUTPUT << STM_TIM1_CCMR2_CC4S) | + + (0 << STM_TIM1_CCMR2_OC3CE) | + (STM_TIM1_CCMR2_OC3M_FROZEN << STM_TIM1_CCMR2_OC3M) | + (0 << STM_TIM1_CCMR2_OC3PE) | + (0 << STM_TIM1_CCMR2_OC3FE) | + (STM_TIM1_CCMR2_CC3S_OUTPUT << STM_TIM1_CCMR2_CC3S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4NP) | + (0 << STM_TIM1_CCER_CC4P) | + (1 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3P) | + (0 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2P) | + (0 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NP) | + (0 << STM_TIM1_CCER_CC1P) | + (0 << STM_TIM1_CCER_CC1E)); +#endif + /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */ + + stm_tim1.cr1 = ((STM_TIM1_CR1_CKD_1 << STM_TIM1_CR1_CKD) | + (0 << STM_TIM1_CR1_ARPE) | + (STM_TIM1_CR1_CMS_EDGE << STM_TIM1_CR1_CMS) | + (0 << STM_TIM1_CR1_DIR) | + (0 << STM_TIM1_CR1_OPM) | + (0 << STM_TIM1_CR1_URS) | + (0 << STM_TIM1_CR1_UDIS) | + (1 << STM_TIM1_CR1_CEN)); + + /* Update the values */ + stm_tim1.egr = (1 << STM_TIM1_EGR_UG); + } +} + +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant +{ + ao_beep(beep); + ao_delay(ticks); + ao_beep(0); +} + +void +ao_beep_init(void) +{ +#if BEEPER_CHANNEL == 3 + /* Our beeper is on PA10, which is hooked to TIM1_CH3. + */ + ao_enable_port(&stm_gpioa); + stm_afr_set(&stm_gpioa, 10, STM_AFR_AF2); +#else +#error unknown beeper channel +#endif + /* Leave the timer off until requested */ + + stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); +} diff --git a/src/stmf0/ao_spi_stm_slave.c b/src/stmf0/ao_spi_stm_slave.c new file mode 100644 index 00000000..962ff2c6 --- /dev/null +++ b/src/stmf0/ao_spi_stm_slave.c @@ -0,0 +1,339 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +struct ao_spi_stm_slave_info { + uint8_t miso_dma_index; + uint8_t mosi_dma_index; + struct stm_spi *stm_spi; +}; + +static uint8_t ao_spi_slave_mutex[STM_NUM_SPI]; +static uint8_t ao_spi_slave_index[STM_NUM_SPI]; + +static const struct ao_spi_stm_slave_info ao_spi_stm_slave_info[STM_NUM_SPI] = { + { + .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX), + .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX), + &stm_spi1 + }, + { + .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX), + .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX), + &stm_spi2 + } +}; + +static uint8_t spi_dev_null; + +void +ao_spi_slave_send(void *block, uint16_t len) +{ + struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index; + + /* Set up the transmit DMA to deliver data */ + ao_dma_set_transfer(mosi_dma_index, + &stm_spi->dr, + block, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (1 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + + /* Clear RXNE */ + (void) stm_spi->dr; + + /* Set up the receive DMA -- when this is done, we know the SPI unit + * is idle. Without this, we'd have to poll waiting for the BSY bit to + * be cleared + */ + ao_dma_set_transfer(miso_dma_index, + &stm_spi->dr, + &spi_dev_null, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (0 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (1 << STM_SPI_CR2_TXDMAEN) | + (1 << STM_SPI_CR2_RXDMAEN)); + ao_dma_start(miso_dma_index); + ao_dma_start(mosi_dma_index); + ao_arch_critical( + while (!ao_dma_done[miso_dma_index]) + ao_sleep(&ao_dma_done[miso_dma_index]); + ); + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); +} + +uint8_t +ao_spi_slave_recv(void *block, uint16_t len) +{ + struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index; + + /* Set up transmit DMA to make the SPI hardware actually run */ + ao_dma_set_transfer(mosi_dma_index, + &stm_spi->dr, + &spi_dev_null, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (0 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + + /* Clear RXNE */ + (void) stm_spi->dr; + + /* Set up the receive DMA to capture data */ + ao_dma_set_transfer(miso_dma_index, + &stm_spi->dr, + block, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (1 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); + + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (1 << STM_SPI_CR2_TXDMAEN) | + (1 << STM_SPI_CR2_RXDMAEN)); + ao_dma_start(miso_dma_index); + ao_dma_start(mosi_dma_index); + + /* Wait until the SPI unit is done */ + ao_arch_critical( + while (!ao_dma_done[miso_dma_index]) + ao_sleep(&ao_dma_done[miso_dma_index]); + ); + + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); + return 1; +} + +static void +ao_spi_slave_disable_index(uint8_t spi_index) +{ + /* Disable current config + */ + switch (AO_SPI_INDEX(spi_index)) { + case STM_SPI_INDEX(1): + switch (spi_index) { + case AO_SPI_1_PA5_PA6_PA7: + stm_gpio_set(&stm_gpioa, 5, 1); + stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT); + stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT); + break; + case AO_SPI_1_PB3_PB4_PB5: + stm_gpio_set(&stm_gpiob, 3, 1); + stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT); + stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT); + break; + case AO_SPI_1_PE13_PE14_PE15: + stm_gpio_set(&stm_gpioe, 13, 1); + stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT); + stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT); + break; + } + break; + case STM_SPI_INDEX(2): + switch (spi_index) { + case AO_SPI_2_PB13_PB14_PB15: + stm_gpio_set(&stm_gpiob, 13, 1); + stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT); + stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT); + break; + case AO_SPI_2_PD1_PD3_PD4: + stm_gpio_set(&stm_gpiod, 1, 1); + stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT); + stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT); + break; + } + break; + } +} + +static void +ao_spi_slave_enable_index(uint8_t spi_index) +{ + switch (AO_SPI_INDEX(spi_index)) { + case STM_SPI_INDEX(1): + switch (spi_index) { + case AO_SPI_1_PA5_PA6_PA7: + stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5); + stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5); + stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5); + break; + case AO_SPI_1_PB3_PB4_PB5: + stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5); + break; + case AO_SPI_1_PE13_PE14_PE15: + stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5); + stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5); + stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5); + break; + } + break; + case STM_SPI_INDEX(2): + switch (spi_index) { + case AO_SPI_2_PB13_PB14_PB15: + stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5); + break; + case AO_SPI_2_PD1_PD3_PD4: + stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5); + stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5); + stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5); + break; + } + break; + } +} + +void +ao_spi_slave_get(uint8_t spi_index, uint32_t speed) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi; + + ao_mutex_get(&ao_spi_slave_mutex[id]); + stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */ + (0 << STM_SPI_CR1_BIDIOE) | + (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */ + (0 << STM_SPI_CR1_CRCNEXT) | + (0 << STM_SPI_CR1_DFF) | + (0 << STM_SPI_CR1_RXONLY) | + (1 << STM_SPI_CR1_SSM) | /* Software SS handling */ + (1 << STM_SPI_CR1_SSI) | /* ... */ + (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */ + (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ + (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */ + (1 << STM_SPI_CR1_MSTR) | + (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ + (0 << STM_SPI_CR1_CPHA)); + if (spi_index != ao_spi_slave_index[id]) { + + /* Disable old config + */ + ao_spi_slave_disable_index(ao_spi_slave_index[id]); + + /* Enable new config + */ + ao_spi_slave_enable_index(spi_index); + + /* Remember current config + */ + ao_spi_slave_index[id] = spi_index; + } +} + +void +ao_spi_slave_put(uint8_t spi_index) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi; + + stm_spi->cr1 = 0; + ao_mutex_put(&ao_spi_slave_mutex[id]); +} + +static void +ao_spi_channel_init(uint8_t spi_index) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi; + + ao_spi_slave_disable_index(spi_index); + + stm_spi->cr1 = 0; + (void) stm_spi->sr; + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (0 << STM_SPI_CR2_TXDMAEN) | + (0 << STM_SPI_CR2_RXDMAEN)); +} + +void +ao_spi_slave_init(void) +{ +#if HAS_SPI_SLAVE_1 +# if SPI_1_PA5_PA6_PA7 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); +# endif +# if SPI_1_PB3_PB4_PB5 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +# endif +# if SPI_1_PE13_PE14_PE15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN); +# endif + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); + ao_spi_slave_index[0] = AO_SPI_CONFIG_NONE; + ao_spi_channel_init(0); +#endif + +#if HAS_SPI_SLAVE_2 +# if SPI_2_PB13_PB14_PB15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +# endif +# if SPI_2_PD1_PD3_PD4 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); +# endif + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN); + ao_spi_slave_index[1] = AO_SPI_CONFIG_NONE; + ao_spi_channel_init(1); +#endif +} -- cgit v1.2.3 From 003e9479ad4364d9f7acf189b35f32ccdfd43be0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 16:51:09 -0800 Subject: altos/stmf0: Support tim1 beeper channel other than 3 ch1 was broken and ch2 didn't have any code at all. Signed-off-by: Keith Packard --- src/stmf0/ao_beep_stm.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c index fc83bb63..969538fd 100644 --- a/src/stmf0/ao_beep_stm.c +++ b/src/stmf0/ao_beep_stm.c @@ -66,16 +66,16 @@ ao_beep(uint8_t beep) #if BEEPER_CHANNEL == 1 stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | - (STM_TIM1_CCMR1_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | + (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | (0 << STM_TIM1_CCMR1_OC2PE) | (0 << STM_TIM1_CCMR1_OC2FE) | - (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | (0 << STM_TIM1_CCMR1_OC1CE) | - (STM_TIM1_CCMR1_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | + (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | (0 << STM_TIM1_CCMR1_OC1PE) | (0 << STM_TIM1_CCMR1_OC1FE) | - (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | (0 << STM_TIM1_CCER_CC4E) | @@ -91,6 +91,33 @@ ao_beep(uint8_t beep) (0 << STM_TIM1_CCER_CC1P) | (1 << STM_TIM1_CCER_CC1E)); #endif +#if BEEPER_CHANNEL == 2 + stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | + (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC2M) | + (0 << STM_TIM1_CCMR1_OC2PE) | + (0 << STM_TIM1_CCMR1_OC2FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + + (0 << STM_TIM1_CCMR1_OC1CE) | + (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC1M) | + (0 << STM_TIM1_CCMR1_OC1PE) | + (0 << STM_TIM1_CCMR1_OC1FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | + (0 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3NE) | + (0 << STM_TIM1_CCER_CC3P) | + (0 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2NE) | + (0 << STM_TIM1_CCER_CC2P) | + (1 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NE) | + (0 << STM_TIM1_CCER_CC1P) | + (0 << STM_TIM1_CCER_CC1E)); +#endif #if BEEPER_CHANNEL == 3 stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR2_OC4M) | @@ -177,7 +204,8 @@ ao_beep_init(void) ao_enable_port(&stm_gpioa); stm_afr_set(&stm_gpioa, 10, STM_AFR_AF2); #else -#error unknown beeper channel + ao_enable_port(BEEPER_PORT); + stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); #endif /* Leave the timer off until requested */ -- cgit v1.2.3 From 9603d737e9ea58217ff2c2dd7c350c7a29fba980 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 17:29:15 -0800 Subject: altos/stmf0: Support timer 2/3 for the beeper Tested on timer 2, all four channels. Signed-off-by: Keith Packard --- src/stmf0/ao_beep_stm.c | 197 ++++++++++++++++++++++++++++++++++++++++++++---- src/stmf0/stm32f0.h | 34 ++++----- 2 files changed, 201 insertions(+), 30 deletions(-) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c index 969538fd..84ccd93e 100644 --- a/src/stmf0/ao_beep_stm.c +++ b/src/stmf0/ao_beep_stm.c @@ -21,16 +21,51 @@ #error BEEPER_CHANNEL undefined #endif +#ifndef BEEPER_TIMER +#define BEEPER_TIMER 1 +#endif + +#if BEEPER_TIMER == 1 +#define timer stm_tim1 +#define STM_RCC_TIMER STM_RCC_APB2ENR_TIM1EN +#define stm_rcc_enr stm_rcc.apb2enr +#endif + +#if BEEPER_TIMER == 2 +#define timer stm_tim2 +#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM2EN +#define stm_rcc_enr stm_rcc.apb1enr +#endif + +#if BEEPER_TIMER == 3 +#define timer stm_tim3 +#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM3EN +#define stm_rcc_enr stm_rcc.apb1enr +#endif + +#ifndef timer +#error BEEPER_TIMER invalid +#endif + +static inline void +disable(void) +{ + timer.cr1 = 0; +#if BEEPER_TIMER == 1 + timer.bdtr = 0; +#endif + stm_rcc_enr &= ~(1 << STM_RCC_TIMER); +} + void ao_beep(uint8_t beep) { if (beep == 0) { - stm_tim1.cr1 = 0; - stm_tim1.bdtr = 0; - stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); + disable(); } else { - stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_TIM1EN); + stm_rcc_enr |= (1 << STM_RCC_TIMER); +#if BEEPER_TIMER == 1 /* Master output enable */ stm_tim1.bdtr = (1 << STM_TIM1_BDTR_MOE); @@ -184,6 +219,149 @@ ao_beep(uint8_t beep) /* Update the values */ stm_tim1.egr = (1 << STM_TIM1_EGR_UG); +#endif +#if BEEPER_TIMER == 2 || BEEPER_TIMER == 3 + + timer.cr2 = ((0 << STM_TIM23_CR2_TI1S) | + (STM_TIM23_CR2_MMS_RESET << STM_TIM23_CR2_MMS) | + (0 << STM_TIM23_CR2_CCDS)); + + /* Set prescaler to match cc1111 clocks + */ + timer.psc = AO_TIM_CLK / 750000; + + /* 1. Select the counter clock (internal, external, prescaler). + * + * Setting SMCR to zero means use the internal clock + */ + + timer.smcr = 0; + + /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */ + timer.arr = beep; + timer.ccr1 = beep; + + /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a + * DMA request is to be generated. + */ + /* don't want this */ + + /* 4. Select the output mode. For example, you must write + * OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output + * pin when CNT matches CCRx, CCRx preload is not used, OCx + * is enabled and active high. + */ + +#if BEEPER_CHANNEL == 1 + timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | + (STM_TIM23_CCMR1_OC2M_FROZEN << STM_TIM23_CCMR1_OC2M) | + (0 << STM_TIM23_CCMR1_OC2PE) | + (0 << STM_TIM23_CCMR1_OC2FE) | + (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + + (0 << STM_TIM23_CCMR1_OC1CE) | + (STM_TIM23_CCMR1_OC1M_TOGGLE << STM_TIM23_CCMR1_OC1M) | + (0 << STM_TIM23_CCMR1_OC1PE) | + (0 << STM_TIM23_CCMR1_OC1FE) | + (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (0 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (0 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (0 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (1 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 2 + timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | + (STM_TIM23_CCMR1_OC2M_TOGGLE << STM_TIM23_CCMR1_OC2M) | + (0 << STM_TIM23_CCMR1_OC2PE) | + (0 << STM_TIM23_CCMR1_OC2FE) | + (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + + (0 << STM_TIM23_CCMR1_OC1CE) | + (STM_TIM23_CCMR1_OC1M_FROZEN << STM_TIM23_CCMR1_OC1M) | + (0 << STM_TIM23_CCMR1_OC1PE) | + (0 << STM_TIM23_CCMR1_OC1FE) | + (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (0 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (0 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (1 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (0 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 3 + timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | + (STM_TIM23_CCMR2_OC4M_FROZEN << STM_TIM23_CCMR2_OC4M) | + (0 << STM_TIM23_CCMR2_OC4PE) | + (0 << STM_TIM23_CCMR2_OC4FE) | + (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + + (0 << STM_TIM23_CCMR2_OC3CE) | + (STM_TIM23_CCMR2_OC3M_TOGGLE << STM_TIM23_CCMR2_OC3M) | + (0 << STM_TIM23_CCMR2_OC3PE) | + (0 << STM_TIM23_CCMR2_OC3FE) | + (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (0 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (1 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (0 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (0 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 4 + timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | + (STM_TIM23_CCMR2_OC4M_TOGGLE << STM_TIM23_CCMR2_OC4M) | + (0 << STM_TIM23_CCMR2_OC4PE) | + (0 << STM_TIM23_CCMR2_OC4FE) | + (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + + (0 << STM_TIM23_CCMR2_OC3CE) | + (STM_TIM23_CCMR2_OC3M_FROZEN << STM_TIM23_CCMR2_OC3M) | + (0 << STM_TIM23_CCMR2_OC3PE) | + (0 << STM_TIM23_CCMR2_OC3FE) | + (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (1 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (0 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (0 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (0 << STM_TIM23_CCER_CC1E)); +#endif + /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */ + + timer.cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) | + (0 << STM_TIM23_CR1_ARPE) | + (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) | + (0 << STM_TIM23_CR1_DIR) | + (0 << STM_TIM23_CR1_OPM) | + (0 << STM_TIM23_CR1_URS) | + (0 << STM_TIM23_CR1_UDIS) | + (1 << STM_TIM23_CR1_CEN)); + + /* Update the values */ + timer.egr = (1 << STM_TIM23_EGR_UG); +#endif } } @@ -198,16 +376,9 @@ ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant void ao_beep_init(void) { -#if BEEPER_CHANNEL == 3 - /* Our beeper is on PA10, which is hooked to TIM1_CH3. - */ - ao_enable_port(&stm_gpioa); - stm_afr_set(&stm_gpioa, 10, STM_AFR_AF2); -#else ao_enable_port(BEEPER_PORT); stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); -#endif - /* Leave the timer off until requested */ - stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); + /* Leave the timer off until requested */ + stm_rcc_enr &= ~(1 << STM_RCC_TIMER); } diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index 1c33f020..e53a5dfd 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -1812,15 +1812,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3; #define STM_TIM23_CCMR2_OC4CE 15 #define STM_TIM23_CCMR2_OC4M 12 -#define STM_TIM23_CCMR2_OCM_FROZEN 0 -#define STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH 1 -#define STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH 2 -#define STM_TIM23_CCMR2_OCM_TOGGLE 3 -#define STM_TIM23_CCMR2_OCM_FORCE_LOW 4 -#define STM_TIM23_CCMR2_OCM_FORCE_HIGH 5 -#define STM_TIM23_CCMR2_OCM_PWM_MODE_1 6 -#define STM_TIM23_CCMR2_OCM_PWM_MODE_2 7 -#define STM_TIM23_CCMR2_OCM_MASK 7 +#define STM_TIM23_CCMR2_OC4M_FROZEN 0 +#define STM_TIM23_CCMR2_OC4M_SET_HIGH_ON_MATCH 1 +#define STM_TIM23_CCMR2_OC4M_SET_LOW_ON_MATCH 2 +#define STM_TIM23_CCMR2_OC4M_TOGGLE 3 +#define STM_TIM23_CCMR2_OC4M_FORCE_LOW 4 +#define STM_TIM23_CCMR2_OC4M_FORCE_HIGH 5 +#define STM_TIM23_CCMR2_OC4M_PWM_MODE_1 6 +#define STM_TIM23_CCMR2_OC4M_PWM_MODE_2 7 +#define STM_TIM23_CCMR2_OC4M_MASK 7 #define STM_TIM23_CCMR2_OC4PE 11 #define STM_TIM23_CCMR2_OC4FE 10 #define STM_TIM23_CCMR2_CC4S 8 @@ -1832,15 +1832,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3; #define STM_TIM23_CCMR2_OC3CE 7 #define STM_TIM23_CCMR2_OC3M 4 -#define STM_TIM23_CCMR2_OCM_FROZEN 0 -#define STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH 1 -#define STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH 2 -#define STM_TIM23_CCMR2_OCM_TOGGLE 3 -#define STM_TIM23_CCMR2_OCM_FORCE_LOW 4 -#define STM_TIM23_CCMR2_OCM_FORCE_HIGH 5 +#define STM_TIM23_CCMR2_OC3M_FROZEN 0 +#define STM_TIM23_CCMR2_OC3M_SET_HIGH_ON_MATCH 1 +#define STM_TIM23_CCMR2_OC3M_SET_LOW_ON_MATCH 2 +#define STM_TIM23_CCMR2_OC3M_TOGGLE 3 +#define STM_TIM23_CCMR2_OC3M_FORCE_LOW 4 +#define STM_TIM23_CCMR2_OC3M_FORCE_HIGH 5 #define STM_TIM23_CCMR2_OC3M_PWM_MODE_1 6 -#define STM_TIM23_CCMR2_OCM_PWM_MODE_2 7 -#define STM_TIM23_CCMR2_OCM_MASK 7 +#define STM_TIM23_CCMR2_OC3M_PWM_MODE_2 7 +#define STM_TIM23_CCMR2_OC3M_MASK 7 #define STM_TIM23_CCMR2_OC3PE 11 #define STM_TIM23_CCMR2_OC3FE 2 #define STM_TIM23_CCMR2_CC3S 0 -- cgit v1.2.3 From 4e561ae43a734d870470e36c41232482bd5f398f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 13 Apr 2017 21:47:14 -0600 Subject: altos/stmf0: Split up rom load in altos.ld to make linker happy The linker isn't happy when the .ld file tries to add text, the .exidx and .rodata segments in the same block. Split them up for success. Signed-off-by: Keith Packard --- src/stmf0/altos.ld | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/stmf0') diff --git a/src/stmf0/altos.ld b/src/stmf0/altos.ld index 8f8933c6..74fdf3ea 100644 --- a/src/stmf0/altos.ld +++ b/src/stmf0/altos.ld @@ -55,10 +55,16 @@ SECTIONS { ao_product.o(.romconfig*) *(.text*) /* Executable code */ + } > rom + + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) - *(.rodata*) /* Constants */ + } > rom + .rodata : { + *(.rodata*) /* Constants */ } > rom + __text_end__ = .; /* Boot data which must live at the start of ram so that -- cgit v1.2.3 From 64ac93f5495db7a8b06f1eb4fe4eb2418125d792 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 17:06:23 -0700 Subject: altos/lpc,altos/stmf0: Use -n flag to work around link editor issue Something changed in the link editor which makes it complain about 'no space for program headers' on LPC and STMF0 builds. Somehow, adding the '-n' flag to the linking step fixes it. It doesn't appear to break the build, so I guess it's ok? Signed-off-by: Keith Packard --- src/lpc/Makefile.defs | 2 +- src/stmf0/Makefile.defs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/stmf0') diff --git a/src/lpc/Makefile.defs b/src/lpc/Makefile.defs index b6d739c2..5bb8133d 100644 --- a/src/lpc/Makefile.defs +++ b/src/lpc/Makefile.defs @@ -5,7 +5,7 @@ endif include $(TOPDIR)/lpc/Makefile-lpc.defs include $(TOPDIR)/Makedefs -LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld -n ao_serial_lpc.h: $(TOPDIR)/lpc/baud_rate ao_pins.h nickle $(TOPDIR)/lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@ diff --git a/src/stmf0/Makefile.defs b/src/stmf0/Makefile.defs index a1d93eb5..3da42874 100644 --- a/src/stmf0/Makefile.defs +++ b/src/stmf0/Makefile.defs @@ -4,6 +4,6 @@ endif include $(TOPDIR)/stmf0/Makefile-stmf0.defs -LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld -n .DEFAULT_GOAL=all -- cgit v1.2.3 From 86a54146b58be86c58fb45386c7abcfa0bb11677 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 17:15:05 -0700 Subject: alots/stmf0: Fix vpath entry for AES directory Mis-placed ) Signed-off-by: Keith Packard --- src/stmf0/Makefile-stmf0.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/stmf0') diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index 2ea3d1d8..f2c53499 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -4,7 +4,7 @@ endif include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp +vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp vpath make-altitude $(TOPDIR)/util vpath make-kalman $(TOPDIR)/util vpath kalman.5c $(TOPDIR)/kalman -- cgit v1.2.3 From 4682323a4bf147b9a908f5f9104bf01ab2cf0533 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 23:02:57 -0700 Subject: altos/stmf0: Pull beeper pin low when beeper is off This avoids having the pin float and pick up noise from any adjacent signals, like TeleMini's radio. Signed-off-by: Keith Packard --- src/stmf0/ao_beep_stm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/stmf0') diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c index 84ccd93e..610f4a31 100644 --- a/src/stmf0/ao_beep_stm.c +++ b/src/stmf0/ao_beep_stm.c @@ -55,6 +55,9 @@ disable(void) timer.bdtr = 0; #endif stm_rcc_enr &= ~(1 << STM_RCC_TIMER); + + /* Disconnect the timer from the pin */ + stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_NONE); } void @@ -361,6 +364,9 @@ ao_beep(uint8_t beep) /* Update the values */ timer.egr = (1 << STM_TIM23_EGR_UG); + + /* Hook the timer up to the beeper pin */ + stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); #endif } } @@ -376,8 +382,7 @@ ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant void ao_beep_init(void) { - ao_enable_port(BEEPER_PORT); - stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); + ao_enable_output(BEEPER_PORT, BEEPER_PIN, BEEPER, 0); /* Leave the timer off until requested */ stm_rcc_enr &= ~(1 << STM_RCC_TIMER); -- cgit v1.2.3