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/drivers/ao_gps_ublox.c | 4 ++-- src/drivers/ao_trng_send.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/drivers') 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 */ -- cgit v1.2.3 From 1dc31a46f1d1adfdeab444664e581a780d995bf7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:49:34 -0800 Subject: altos: Require SPI speed to be declared for cc1200 The cc1200 can't run SPI faster than 10MHz, so make sure every device picks a SPI clock slower than that. Signed-off-by: Keith Packard --- src/drivers/ao_cc1200.c | 8 ++++++-- src/telebt-v3.0/ao_pins.h | 1 + src/teledongle-v3.0/ao_pins.h | 1 + src/telefiretwo-v0.1/ao_pins.h | 1 + src/telelco-v0.3/ao_pins.h | 1 + src/telelcotwo-v0.1/ao_pins.h | 1 + src/telemega-v2.0/ao_pins.h | 1 + src/telemetrum-v3.0/ao_pins.h | 1 + 8 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_cc1200.c b/src/drivers/ao_cc1200.c index 2bc99734..de282000 100644 --- a/src/drivers/ao_cc1200.c +++ b/src/drivers/ao_cc1200.c @@ -51,7 +51,11 @@ extern const uint32_t ao_radio_cal; #define FOSC 40000000 #endif -#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_SPI_SPEED_FAST) +#ifndef AO_CC1200_SPI_SPEED +#error AO_CC1200_SPI_SPEED undefined +#endif + +#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_CC1200_SPI_SPEED) #define ao_radio_deselect() ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS) #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1200_SPI_BUS) #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1200_SPI_BUS) @@ -1323,7 +1327,7 @@ static void ao_radio_packet(void) { void ao_radio_test_recv(void) { - uint8_t bytes[34]; + static uint8_t bytes[34]; uint8_t b; if (ao_radio_recv(bytes, 34, 0)) { diff --git a/src/telebt-v3.0/ao_pins.h b/src/telebt-v3.0/ao_pins.h index 61cbe9bb..1f7af41b 100644 --- a/src/telebt-v3.0/ao_pins.h +++ b/src/telebt-v3.0/ao_pins.h @@ -197,6 +197,7 @@ struct ao_adc { #define AO_CC1200_SPI_CS_PIN 10 #define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7 #define AO_CC1200_SPI stm_spi1 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/teledongle-v3.0/ao_pins.h b/src/teledongle-v3.0/ao_pins.h index effc2322..be710aef 100644 --- a/src/teledongle-v3.0/ao_pins.h +++ b/src/teledongle-v3.0/ao_pins.h @@ -96,6 +96,7 @@ #define AO_CC1200_SPI_CS_PIN 3 #define AO_CC1200_SPI_BUS 0 #define AO_CC1200_SPI 0 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_8MHz #define AO_CC1200_INT_PORT 0 #define AO_CC1200_INT_PIN 2 diff --git a/src/telefiretwo-v0.1/ao_pins.h b/src/telefiretwo-v0.1/ao_pins.h index f56061b2..1e5c0d09 100644 --- a/src/telefiretwo-v0.1/ao_pins.h +++ b/src/telefiretwo-v0.1/ao_pins.h @@ -110,6 +110,7 @@ #define AO_CC1200_SPI_CS_PIN 7 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/telelco-v0.3/ao_pins.h b/src/telelco-v0.3/ao_pins.h index d874a19b..dd4aaafb 100644 --- a/src/telelco-v0.3/ao_pins.h +++ b/src/telelco-v0.3/ao_pins.h @@ -89,6 +89,7 @@ #define AO_CC1200_SPI_CS_PIN 0 #define AO_CC1200_SPI_BUS AO_SPI_2_PD1_PD3_PD4 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpioc) #define AO_CC1200_INT_PIN (15) diff --git a/src/telelcotwo-v0.1/ao_pins.h b/src/telelcotwo-v0.1/ao_pins.h index 714a5c3a..60e94c67 100644 --- a/src/telelcotwo-v0.1/ao_pins.h +++ b/src/telelcotwo-v0.1/ao_pins.h @@ -91,6 +91,7 @@ #define AO_CC1200_SPI_CS_PIN 7 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/telemega-v2.0/ao_pins.h b/src/telemega-v2.0/ao_pins.h index b1c472da..c7c8ad19 100644 --- a/src/telemega-v2.0/ao_pins.h +++ b/src/telemega-v2.0/ao_pins.h @@ -309,6 +309,7 @@ struct ao_adc { #define AO_CC1200_SPI_CS_PIN 5 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpioe) #define AO_CC1200_INT_PIN 1 diff --git a/src/telemetrum-v3.0/ao_pins.h b/src/telemetrum-v3.0/ao_pins.h index ccf2f18f..b937b422 100644 --- a/src/telemetrum-v3.0/ao_pins.h +++ b/src/telemetrum-v3.0/ao_pins.h @@ -259,6 +259,7 @@ struct ao_adc { #define AO_CC1200_SPI_CS_PIN 2 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpioa) #define AO_CC1200_INT_PIN (3) -- cgit v1.2.3 From 6b39d3093c3b87689717bb03988d160473c53c64 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 00:04:27 -0800 Subject: altos: Add VGA driver for STM32L processors Generates vsync/hsync using timers and pixel data using the SPI port. 320x240 video using 640x480 mode and a 24MHz "pixel" clock. Signed-off-by: Keith Packard --- src/drivers/ao_vga.c | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_vga.h | 39 ++++++ 2 files changed, 405 insertions(+) create mode 100644 src/drivers/ao_vga.c create mode 100644 src/drivers/ao_vga.h (limited to 'src/drivers') diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c new file mode 100644 index 00000000..2d05d522 --- /dev/null +++ b/src/drivers/ao_vga.c @@ -0,0 +1,366 @@ +/* + * 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.h" +#include "ao_vga.h" + +/* VGA output from the SPI port + * + * Connections: + * + * STM VGA + * GND 4,6,7,8,9,10 + * HSYNC PA5 13 + * VSYNC PB5 14 + * RGB PB4 1,2,3 + * + * pixel clock PA8 -> PB3 + * pixel enable PA1 -> PA15 + */ + +/* GRF formula for 640x480 yields a pixel clock very close to 24MHz. Pad by + * three scanlines to hit exactly that value + */ + +#define HACTIVE (640) +#define HSYNC_START (656) +#define HSYNC_END (720) +#define HTOTAL (800) + +#define VACTIVE 480 +#define VSYNC_START 481 +#define VSYNC_END 484 +#define VTOTAL 500 + +/* + * The horizontal counter is set so that the end of hsync is reached + * at the maximum counter value. That means that the hblank interval + * is offset by HSYNC_END. + */ + +#define HSYNC (HSYNC_END - HSYNC_START) +#define HBLANK_END (HTOTAL - HSYNC_END) +#define HBLANK_START (HBLANK_END + HACTIVE) + +/* + * The vertical counter is set so that the end of vsync is reached at + * the maximum counter value. That means that the vblank interval is + * offset by VSYNC_END. We send a blank line at the start of the + * frame, so each of these is off by one + */ +#define VSYNC (VSYNC_END - VSYNC_START) +#define VBLANK_END (VTOTAL - VSYNC_END) +#define VBLANK_START (VBLANK_END + VACTIVE) + +#define WIDTH_BYTES (AO_VGA_WIDTH >> 3) +#define SCANOUT ((WIDTH_BYTES+2) >> 1) + +uint32_t ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT]; + +const struct ao_bitmap ao_vga_bitmap = { + .base = ao_vga_fb, + .stride = AO_VGA_STRIDE, + .width = AO_VGA_WIDTH, + .height = AO_VGA_HEIGHT +}; + +static uint32_t *scanline; + +#define DMA_INDEX STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX) + +#define DMA_CCR(en) ((0 << STM_DMA_CCR_MEM2MEM) | \ + (STM_DMA_CCR_PL_VERY_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_MEM_TO_PER << STM_DMA_CCR_DIR) | \ + (0 << STM_DMA_CCR_TCIE) | \ + (en << STM_DMA_CCR_EN)) + + +void stm_tim2_isr(void) +{ + int16_t line = stm_tim3.cnt; + + if (VBLANK_END <= line && line < VBLANK_START) { + /* Disable */ + stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(0); + /* Reset DMA engine for the next scanline */ + stm_dma.channel[DMA_INDEX].cmar = scanline; + stm_dma.channel[DMA_INDEX].cndtr = SCANOUT; + + /* reset SPI */ + (void) stm_spi1.dr; + (void) stm_spi1.sr; + + /* Enable */ + stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(1); + if (((line - VBLANK_END) & 1)) + scanline += AO_VGA_STRIDE; + } else { + scanline = ao_vga_fb; + } + stm_tim2.sr = 0; +} + + +void +ao_vga_init(void) +{ + uint32_t cfgr; + + /* Initialize spi1 using MISO PB4 for output */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + + stm_ospeedr_set(&stm_gpiob, 4, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5); + stm_afr_set(&stm_gpioa, 15, STM_AFR_AF5); + + /* turn on SPI */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); + + stm_spi1.cr1 = ((1 << STM_SPI_CR1_BIDIMODE) | /* Two wire mode */ + (1 << STM_SPI_CR1_BIDIOE) | + (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */ + (0 << STM_SPI_CR1_CRCNEXT) | + (1 << STM_SPI_CR1_DFF) | + (0 << STM_SPI_CR1_RXONLY) | + (0 << STM_SPI_CR1_SSM) | /* Software SS handling */ + (1 << STM_SPI_CR1_SSI) | /* ... */ + (1 << STM_SPI_CR1_LSBFIRST) | /* Little endian */ + (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ + (0 << STM_SPI_CR1_BR) | /* baud rate to pclk/2 */ + (0 << STM_SPI_CR1_MSTR) | + (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ + (0 << STM_SPI_CR1_CPHA)); + stm_spi1.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) | + (0 << STM_SPI_CR2_RXDMAEN)); + + (void) stm_spi1.dr; + (void) stm_spi1.sr; + + /* Grab the DMA channel for SPI1 MOSI */ + stm_dma.channel[DMA_INDEX].cpar = &stm_spi1.dr; + stm_dma.channel[DMA_INDEX].cmar = ao_vga_fb; + + /* + * Hsync Configuration + */ + /* Turn on timer 2 */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM2EN); + + /* tim2 runs at full speed */ + stm_tim2.psc = 0; + + /* Disable channels while modifying */ + stm_tim2.ccer = 0; + + /* Channel 1 hsync PWM values */ + stm_tim2.ccr1 = HSYNC; + + /* Channel 2 trigger scanout */ + /* wait for the time to start scanout */ + stm_tim2.ccr2 = HBLANK_END; + + stm_tim2.ccr3 = 32; + + /* Configure channel 1 to output on the pin and + * channel 2 to to set the trigger for the vsync timer + */ + stm_tim2.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) | + (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M) | + (1 << STM_TIM234_CCMR1_OC2PE) | + (0 << STM_TIM234_CCMR1_OC2FE) | + (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) | + + (0 << STM_TIM234_CCMR1_OC1CE) | + (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M) | + (1 << STM_TIM234_CCMR1_OC1PE) | + (0 << STM_TIM234_CCMR1_OC1FE) | + (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S)); + + stm_tim2.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) | + (0 << STM_TIM234_CCMR2_OC4M) | + (0 << STM_TIM234_CCMR2_OC4PE) | + (0 << STM_TIM234_CCMR2_OC4FE) | + (0 << STM_TIM234_CCMR2_CC4S) | + + (0 << STM_TIM234_CCMR2_OC3CE) | + (STM_TIM234_CCMR2_OC3M_PWM_MODE_1 << STM_TIM234_CCMR2_OC3M) | + (1 << STM_TIM234_CCMR2_OC3PE) | + (0 << STM_TIM234_CCMR2_OC3FE) | + (0 << STM_TIM234_CCMR2_CC3S)); + + /* One scanline */ + stm_tim2.arr = HTOTAL; + + stm_tim2.cnt = 0; + + /* Update the register contents */ + stm_tim2.egr |= (1 << STM_TIM234_EGR_UG); + + /* Enable the timer */ + + /* Enable the output */ + stm_tim2.ccer = ((0 << STM_TIM234_CCER_CC2NP) | + (STM_TIM234_CCER_CC2P_ACTIVE_HIGH << STM_TIM234_CCER_CC2P) | + (1 << STM_TIM234_CCER_CC2E) | + (0 << STM_TIM234_CCER_CC1NP) | + (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) | + (1 << STM_TIM234_CCER_CC1E)); + + stm_tim2.cr2 = ((0 << STM_TIM234_CR2_TI1S) | + (STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) | + (0 << STM_TIM234_CR2_CCDS)); + + /* hsync is not a slave timer */ + stm_tim2.smcr = 0; + + /* Send an interrupt on channel 3 */ + stm_tim2.dier = ((1 << STM_TIM234_DIER_CC3IE)); + + stm_tim2.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | + (1 << STM_TIM234_CR1_ARPE) | + (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | + (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) | + (0 << STM_TIM234_CR1_OPM) | + (1 << STM_TIM234_CR1_URS) | + (0 << STM_TIM234_CR1_UDIS) | + (0 << STM_TIM234_CR1_CEN)); + + /* Hsync is on PA5 which is Timer 2 CH1 output */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + stm_ospeedr_set(&stm_gpioa, 5, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpioa, 5, STM_AFR_AF1); + + /* pixel transmit enable is on PA1 */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + stm_ospeedr_set(&stm_gpioa, 1, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1); + + /* + * Vsync configuration + */ + + /* Turn on timer 3, slaved to timer 1 using ITR1 (table 61) */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN); + + /* No prescale */ + stm_tim3.psc = 0; + + /* Channel 1 or 2 vsync PWM values */ + stm_tim3.ccr1 = VSYNC; + stm_tim3.ccr2 = VSYNC; + + stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) | + (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M) | + (1 << STM_TIM234_CCMR1_OC2PE) | + (0 << STM_TIM234_CCMR1_OC2FE) | + (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) | + + (0 << STM_TIM234_CCMR1_OC1CE) | + (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M) | + (1 << STM_TIM234_CCMR1_OC1PE) | + (0 << STM_TIM234_CCMR1_OC1FE) | + (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S)); + + stm_tim3.arr = VTOTAL; + stm_tim3.cnt = 0; + + /* Update the register contents */ + stm_tim3.egr |= (1 << STM_TIM234_EGR_UG); + + /* Enable the timer */ + + /* Enable the output */ + stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC1NP) | + (STM_TIM234_CCER_CC2P_ACTIVE_LOW << STM_TIM234_CCER_CC2P) | + (1 << STM_TIM234_CCER_CC2E) | + (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) | + (1 << STM_TIM234_CCER_CC1E)); + + stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) | + (STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) | + (0 << STM_TIM234_CR2_CCDS)); + + stm_tim3.smcr = 0; + stm_tim3.smcr = ((0 << STM_TIM234_SMCR_ETP) | + (0 << STM_TIM234_SMCR_ECE) | + (STM_TIM234_SMCR_ETPS_OFF << STM_TIM234_SMCR_ETPS) | + (STM_TIM234_SMCR_ETF_NONE << STM_TIM234_SMCR_ETF) | + (0 << STM_TIM234_SMCR_MSM) | + (STM_TIM234_SMCR_TS_ITR1 << STM_TIM234_SMCR_TS) | + (0 << STM_TIM234_SMCR_OCCS) | + (STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK << STM_TIM234_SMCR_SMS)); + + stm_tim3.dier = 0; + + stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | + (1 << STM_TIM234_CR1_ARPE) | + (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | + (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) | + (0 << STM_TIM234_CR1_OPM) | + (1 << STM_TIM234_CR1_URS) | + (0 << STM_TIM234_CR1_UDIS) | + (1 << STM_TIM234_CR1_CEN)); + + /* Vsync is on PB5 which is is Timer 3 CH2 output */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); + stm_ospeedr_set(&stm_gpiob, 5, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpiob, 5, STM_AFR_AF2); + + /* Use MCO for the pixel clock, that appears on PA8 */ + cfgr = stm_rcc.cfgr & ~((STM_RCC_CFGR_MCOPRE_MASK << STM_RCC_CFGR_MCOPRE) | + (STM_RCC_CFGR_MCOSEL_MASK << STM_RCC_CFGR_MCOSEL)); + + cfgr |= ((STM_RCC_CFGR_MCOPRE_DIV_2 << STM_RCC_CFGR_MCOPRE) | + (STM_RCC_CFGR_MCOSEL_SYSCLK << STM_RCC_CFGR_MCOSEL)); + + stm_rcc.cfgr = cfgr; + + stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0); + + /* Enable the scanline interrupt */ + stm_nvic_set_priority(STM_ISR_TIM2_POS, AO_STM_NVIC_NONMASK_PRIORITY); + stm_nvic_set_enable(STM_ISR_TIM2_POS); +} + +uint8_t enabled; + +void +ao_vga_enable(int enable) +{ + if (enable) { + if (!enabled) { + ++ao_task_minimize_latency; + enabled = 1; + } + stm_tim2.cr1 |= (1 << STM_TIM234_CR1_CEN); + } else { + if (enabled) { + --ao_task_minimize_latency; + enabled = 0; + } + stm_tim2.cr1 &= ~(1 << STM_TIM234_CR1_CEN); + } +} diff --git a/src/drivers/ao_vga.h b/src/drivers/ao_vga.h new file mode 100644 index 00000000..7d9d6b39 --- /dev/null +++ b/src/drivers/ao_vga.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef _AO_VGA_H_ +#define _AO_VGA_H_ + +#include "ao_draw.h" + +void +ao_vga_init(void); + +void +ao_vga_enable(int active); + +/* Active frame buffer */ +#define AO_VGA_WIDTH 320 +#define AO_VGA_HEIGHT 240 + +/* Pad on the right so that there are zeros on the output after the line */ +#define AO_VGA_HPAD 32 + +#define AO_VGA_STRIDE ((AO_VGA_WIDTH + AO_VGA_HPAD) >> AO_SHIFT) + +extern uint32_t ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT]; + +extern const struct ao_bitmap ao_vga_bitmap; + +#endif /* _AO_VGA_H_ */ -- cgit v1.2.3 From c1d52178ce63ebdc44c83d1bca5027942e2d778c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:19:42 -0800 Subject: altos: Add PS/2 keyboard driver Interrupt driven, includes standard US keymap. Signed-off-by: Keith Packard --- src/drivers/ao_ps2.c | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_ps2.h | 220 +++++++++++++++++++++++++++ 2 files changed, 639 insertions(+) create mode 100644 src/drivers/ao_ps2.c create mode 100644 src/drivers/ao_ps2.h (limited to 'src/drivers') diff --git a/src/drivers/ao_ps2.c b/src/drivers/ao_ps2.c new file mode 100644 index 00000000..29eecea8 --- /dev/null +++ b/src/drivers/ao_ps2.c @@ -0,0 +1,419 @@ +/* + * 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.h" +#include "ao_ps2.h" +#include "ao_exti.h" + +static struct ao_fifo ao_ps2_rx_fifo; + +static uint16_t ao_ps2_tx; +static uint8_t ao_ps2_tx_count; + +static AO_TICK_TYPE ao_ps2_tick; +static uint16_t ao_ps2_value; +static uint8_t ao_ps2_count; + +uint8_t ao_ps2_stdin; + +uint8_t ao_ps2_scancode_set; + +#define AO_PS2_CLOCK_MODE(pull) ((pull) | AO_EXTI_MODE_FALLING | AO_EXTI_PRIORITY_MED) + +static void +ao_ps2_isr(void); + +static uint8_t +_ao_ps2_parity(uint8_t value) +{ + uint8_t parity = 1; + uint8_t b; + + for (b = 0; b < 8; b++) { + parity ^= (value & 1); + value >>= 1; + } + return parity; +} + +static int +_ao_ps2_poll(void) +{ + uint8_t u; + if (ao_fifo_empty(ao_ps2_rx_fifo)) { + return AO_READ_AGAIN; + } + ao_fifo_remove(ao_ps2_rx_fifo, u); + + return (int) u; +} + +uint8_t +ao_ps2_get(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_ps2_poll()) == AO_READ_AGAIN) + ao_sleep(&ao_ps2_rx_fifo); + ao_arch_release_interrupts(); + return (uint8_t) c; +} + + +int +ao_ps2_poll(void) +{ + int c; + ao_arch_block_interrupts(); + c = _ao_ps2_poll(); + ao_arch_release_interrupts(); + return (uint8_t) c; +} + +void +ao_ps2_put(uint8_t c) +{ + ao_arch_block_interrupts(); + ao_ps2_tx = ((uint16_t) c) | (_ao_ps2_parity(c) << 8) | (3 << 9); + ao_ps2_tx_count = 11; + ao_exti_disable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + ao_arch_release_interrupts(); + + /* pull the clock pin down */ + ao_enable_output(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, AO_PS2_CLOCK_PIN, 0); + ao_delay(0); + + /* pull the data pin down for the start bit */ + ao_enable_output(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, 0); + ao_delay(0); + + /* switch back to input mode for the interrupt to work */ + ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, + AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP), + ao_ps2_isr); + ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + + /* wait for the bits to drain */ + while (ao_ps2_tx_count) + ao_sleep(&ao_ps2_tx_count); + +} + +static uint8_t ao_ps2_down[128 / 8]; + +static void +ao_ps2_set_down(uint8_t code, uint8_t value) +{ + uint8_t shift = (code & 0x07); + uint8_t byte = code >> 3; + + ao_ps2_down[byte] = (ao_ps2_down[byte] & ~(1 << shift)) | (value << shift); +} + +uint8_t +ao_ps2_is_down(uint8_t code) +{ + uint8_t shift = (code & 0x07); + uint8_t byte = code >> 3; + + return (ao_ps2_down[byte] >> shift) & 1; +} + +static void +_ao_ps2_set_leds(void) +{ + uint8_t led = 0; + if (ao_ps2_is_down(AO_PS2_CAPS_LOCK)) + led |= AO_PS2_SET_LEDS_CAPS; + if (ao_ps2_is_down(AO_PS2_NUM_LOCK)) + led |= AO_PS2_SET_LEDS_NUM; + if (ao_ps2_is_down(AO_PS2_SCROLL_LOCK)) + led |= AO_PS2_SET_LEDS_SCROLL; + ao_arch_release_interrupts(); + ao_ps2_put(AO_PS2_SET_LEDS); + while (ao_ps2_get() != 0xfa); + ao_ps2_put(led); + ao_arch_block_interrupts(); +} + +static uint8_t +ao_ps2_is_lock(uint8_t code) { + switch (code) { + case AO_PS2_CAPS_LOCK: + case AO_PS2_NUM_LOCK: + case AO_PS2_SCROLL_LOCK: + return 1; + } + return 0; +} + +static void +_ao_ps2_set_scancode_set(uint8_t set) +{ + ao_ps2_scancode_set = set; + ao_arch_release_interrupts(); + ao_ps2_put(AO_PS2_SET_SCAN_CODE_SET); + while (ao_ps2_get() != 0xfa); + ao_ps2_put(set); + ao_ps2_put(AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK); + while (ao_ps2_get() != 0xfa); + ao_arch_block_interrupts(); +} + +static int +_ao_ps2_poll_key(void) +{ + int c; + uint8_t set_led = 0; + static uint8_t saw_break; + + c = _ao_ps2_poll(); + if (c < 0) { + if (ao_ps2_scancode_set != 3) { + _ao_ps2_set_scancode_set(3); + } + return c; + } + + if (c == AO_PS2_BREAK) { + saw_break = 1; + return AO_READ_AGAIN; + } + if (c & 0x80) + return AO_READ_AGAIN; + + if (ao_ps2_is_lock(c)) { + if (saw_break) { + saw_break = 0; + return AO_READ_AGAIN; + } + if (ao_ps2_is_down(c)) + saw_break = 1; + set_led = 1; + } + if (saw_break) { + saw_break = 0; + ao_ps2_set_down(c, 0); + c |= 0x80; + } else + ao_ps2_set_down(c, 1); + if (set_led) + _ao_ps2_set_leds(); + + if (ao_ps2_scancode_set != 3) + _ao_ps2_set_scancode_set(3); + + return c; +} + +int +ao_ps2_poll_key(void) +{ + int c; + ao_arch_block_interrupts(); + c = _ao_ps2_poll_key(); + ao_arch_release_interrupts(); + return c; +} + +uint8_t +ao_ps2_get_key(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_ps2_poll_key()) == AO_READ_AGAIN) + ao_sleep(&ao_ps2_rx_fifo); + ao_arch_release_interrupts(); + return (uint8_t) c; +} + +static const uint8_t ao_ps2_asciimap[128][2] = { + [AO_PS2_A] = { 'a', 'A' }, + [AO_PS2_B] = { 'b', 'B' }, + [AO_PS2_C] = { 'c', 'C' }, + [AO_PS2_D] = { 'd', 'D' }, + [AO_PS2_E] = { 'e', 'E' }, + [AO_PS2_F] = { 'f', 'F' }, + [AO_PS2_G] = { 'g', 'G' }, + [AO_PS2_H] = { 'h', 'H' }, + [AO_PS2_I] = { 'i', 'I' }, + [AO_PS2_J] = { 'j', 'J' }, + [AO_PS2_K] = { 'k', 'K' }, + [AO_PS2_L] = { 'l', 'L' }, + [AO_PS2_M] = { 'm', 'M' }, + [AO_PS2_N] = { 'n', 'N' }, + [AO_PS2_O] = { 'o', 'O' }, + [AO_PS2_P] = { 'p', 'P' }, + [AO_PS2_Q] = { 'q', 'Q' }, + [AO_PS2_R] = { 'r', 'R' }, + [AO_PS2_S] = { 's', 'S' }, + [AO_PS2_T] = { 't', 'T' }, + [AO_PS2_U] = { 'u', 'U' }, + [AO_PS2_V] = { 'v', 'V' }, + [AO_PS2_W] = { 'w', 'W' }, + [AO_PS2_X] = { 'x', 'X' }, + [AO_PS2_Y] = { 'y', 'Y' }, + [AO_PS2_Z] = { 'z', 'Z' }, + + [AO_PS2_0] = { '0', ')' }, + [AO_PS2_1] = { '1', '!' }, + [AO_PS2_2] = { '2', '@' }, + [AO_PS2_3] = { '3', '#' }, + [AO_PS2_4] = { '4', '$' }, + [AO_PS2_5] = { '5', '%' }, + [AO_PS2_6] = { '6', '^' }, + [AO_PS2_7] = { '7', '&' }, + [AO_PS2_8] = { '8', '*' }, + [AO_PS2_9] = { '9', '(' }, + + [AO_PS2_GRAVE] = { '`', '~' }, + [AO_PS2_HYPHEN] = { '-', '_' }, + [AO_PS2_EQUAL] = { '=', '+' }, + [AO_PS2_BACKSLASH] = { '\\', '|' }, + [AO_PS2_BACKSPACE] = { '\010', '\010' }, + [AO_PS2_SPACE] = { ' ', ' ' }, + [AO_PS2_TAB] = { '\t', '\t' }, + + [AO_PS2_ENTER] = { '\r', '\r' }, + [AO_PS2_ESC] = { '\033', '\033' }, + + [AO_PS2_OPEN_SQ] = { '[', '{' }, + [AO_PS2_DELETE] = { '\177', '\177' }, + + [AO_PS2_KP_TIMES] = { '*', '*' }, + [AO_PS2_KP_PLUS] = { '+', '+' }, + [AO_PS2_KP_ENTER] = { '\r', '\r' }, + [AO_PS2_KP_DECIMAL] = { '.', '.' }, + [AO_PS2_KP_0] = { '0', '0' }, + [AO_PS2_KP_1] = { '1', '1' }, + [AO_PS2_KP_2] = { '2', '2' }, + [AO_PS2_KP_3] = { '3', '3' }, + [AO_PS2_KP_4] = { '4', '4' }, + [AO_PS2_KP_5] = { '5', '5' }, + [AO_PS2_KP_6] = { '6', '6' }, + [AO_PS2_KP_7] = { '7', '7' }, + [AO_PS2_KP_8] = { '8', '8' }, + [AO_PS2_KP_9] = { '9', '9' }, + [AO_PS2_CLOSE_SQ] = { ']', '}' }, + [AO_PS2_SEMICOLON] = { ';', ':' }, + [AO_PS2_ACUTE] = { '\'', '"' }, + [AO_PS2_COMMA] = { ',', '<' }, + [AO_PS2_PERIOD] = { '.', '>' }, + [AO_PS2_SLASH] = { '/', '?' }, +}; + +int +ao_ps2_ascii(uint8_t key) +{ + uint8_t col; + char a; + + /* Skip key releases */ + if (key & 0x80) + return AO_READ_AGAIN; + + col = 0; + if (ao_ps2_is_down(AO_PS2_L_SHIFT) || ao_ps2_is_down(AO_PS2_R_SHIFT)) + col = 1; + + /* caps lock */ + a = ao_ps2_asciimap[key][0]; + if (!a) + return AO_READ_AGAIN; + + if ('a' <= a && a <= 'z') + if (ao_ps2_is_down(AO_PS2_CAPS_LOCK)) + col ^= 1; + a = ao_ps2_asciimap[key][col]; + if ('@' <= a && a <= 0x7f && (ao_ps2_is_down(AO_PS2_L_CTRL) || ao_ps2_is_down(AO_PS2_R_CTRL))) + a &= 0x1f; + return a; +} + +int +_ao_ps2_pollchar(void) +{ + int key; + + key = _ao_ps2_poll_key(); + if (key < 0) + return key; + return ao_ps2_ascii(key); +} + +char +ao_ps2_getchar(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_ps2_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_ps2_rx_fifo); + ao_arch_release_interrupts(); + return (char) c; +} + +static void +ao_ps2_isr(void) +{ + uint8_t bit; + + if (ao_ps2_tx_count) { + ao_gpio_set(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, ao_ps2_tx&1); + ao_ps2_tx >>= 1; + ao_ps2_tx_count--; + if (!ao_ps2_tx_count) { + ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_EXTI_MODE_PULL_UP); + ao_wakeup(&ao_ps2_tx_count); + } + return; + } + /* reset if its been a while */ + if ((ao_tick_count - ao_ps2_tick) > AO_MS_TO_TICKS(100)) + ao_ps2_count = 0; + ao_ps2_tick = ao_tick_count; + + bit = ao_gpio_get(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN); + if (ao_ps2_count == 0) { + /* check for start bit, ignore if not zero */ + if (bit) + return; + ao_ps2_value = 0; + } else if (ao_ps2_count < 9) { + ao_ps2_value |= (bit << (ao_ps2_count - 1)); + } else if (ao_ps2_count == 10) { + ao_fifo_insert(ao_ps2_rx_fifo, ao_ps2_value); + ao_wakeup(&ao_ps2_rx_fifo); + if (ao_ps2_stdin) + ao_wakeup(&ao_stdin_ready); + ao_ps2_count = 0; + return; + } + ao_ps2_count++; +} + +void +ao_ps2_init(void) +{ + ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, + AO_EXTI_MODE_PULL_UP); + + ao_enable_port(AO_PS2_CLOCK_PORT); + + ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, + AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP), + ao_ps2_isr); + ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + + ao_ps2_scancode_set = 2; +} diff --git a/src/drivers/ao_ps2.h b/src/drivers/ao_ps2.h new file mode 100644 index 00000000..f1f05ee5 --- /dev/null +++ b/src/drivers/ao_ps2.h @@ -0,0 +1,220 @@ +/* + * 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. + */ + +#ifndef _AO_PS2_H_ +#define _AO_PS2_H_ + +extern uint8_t ao_ps2_stdin; + +int +ao_ps2_poll(void); + +uint8_t +ao_ps2_get(void); + +void +ao_ps2_put(uint8_t b); + +uint8_t +ao_ps2_is_down(uint8_t code); + +int +ao_ps2_poll_key(void); + +uint8_t +ao_ps2_get_key(void); + +int +ao_ps2_ascii(uint8_t key); + +int +_ao_ps2_pollchar(void); + +char +ao_ps2_getchar(void); + +void +ao_ps2_init(void); + +/* From http://computer-engineering.org/ps2keyboard/ */ + +/* Device responds with ACK and then resets */ +#define AO_PS2_RESET 0xff + +/* Device retransmits last byte */ +#define AO_PS2_RESEND 0xfe + +/* Setting key report only works in mode 3 */ + +/* Disable break and typematic for specified mode 3 keys. Terminate with invalid key */ +#define AO_PS2_SET_KEY_MAKE 0xfd + +/* Disable typematic for keys */ +#define AO_PS2_SET_KEY_MAKE_BREAK 0xfc + +/* Disable break code for keys */ +#define AO_PS2_SET_KEY_TYPEMATIC 0xfb + +/* Enable make, break and typematic */ +#define AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK 0xfa + +/* Disable break and typematic for all */ +#define AO_PS2_SET_ALL_MAKE 0xf9 + +/* Disable typematic for all */ +#define AO_PS2_SET_ALL_MAKE_BREAK 0xf8 + +/* Disable break for all */ +#define AO_PS2_SET_ALL_TYPEMATIC 0xf7 + +/* Set keyboard to default (repeat, report and scan code set 2) */ +#define AO_PS2_SET_DEFAULT 0xf6 + +/* Disable and reset to default */ +#define AO_PS2_DISABLE 0xf5 + +/* Enable */ +#define AO_PS2_ENABLE 0xf4 + +/* Set repeat rate. Bytes 5-6 are the start delay, bits 0-4 are the rate */ +#define AO_PS2_SET_REPEAT_RATE 0xf3 + +/* Read keyboard id. Returns two bytes */ +#define AO_PS2_GETID 0xf2 + +/* Set scan code (1, 2, or 3) */ +#define AO_PS2_SET_SCAN_CODE_SET 0xf0 + +/* Echo. Keyboard replies with Echo */ +#define AO_PS2_ECHO 0xee + +/* Set LEDs */ +#define AO_PS2_SET_LEDS 0xed +# define AO_PS2_SET_LEDS_SCROLL 0x01 +# define AO_PS2_SET_LEDS_NUM 0x02 +# define AO_PS2_SET_LEDS_CAPS 0x04 + +#define AO_PS2_BREAK 0xf0 +#define AO_PS2_ACK 0xfa +#define AO_PS2_ERROR 0xfc +#define AO_PS2_NAK 0xfe + +/* Scan code set 3 */ + +#define AO_PS2_A 0x1c +#define AO_PS2_B 0x32 +#define AO_PS2_C 0x21 +#define AO_PS2_D 0x23 +#define AO_PS2_E 0x24 +#define AO_PS2_F 0x2b +#define AO_PS2_G 0x34 +#define AO_PS2_H 0x33 +#define AO_PS2_I 0x43 +#define AO_PS2_J 0x3b +#define AO_PS2_K 0x42 +#define AO_PS2_L 0x4b +#define AO_PS2_M 0x3a +#define AO_PS2_N 0x31 +#define AO_PS2_O 0x44 +#define AO_PS2_P 0x4d +#define AO_PS2_Q 0x15 +#define AO_PS2_R 0x2d +#define AO_PS2_S 0x1b +#define AO_PS2_T 0x2c +#define AO_PS2_U 0x3c +#define AO_PS2_V 0x2a +#define AO_PS2_W 0x1d +#define AO_PS2_X 0x22 +#define AO_PS2_Y 0x35 +#define AO_PS2_Z 0x1a +#define AO_PS2_0 0x45 +#define AO_PS2_1 0x16 +#define AO_PS2_2 0x1e +#define AO_PS2_3 0x26 +#define AO_PS2_4 0x25 +#define AO_PS2_5 0x2e +#define AO_PS2_6 0x36 +#define AO_PS2_7 0x3d +#define AO_PS2_8 0x3e +#define AO_PS2_9 0x46 +#define AO_PS2_GRAVE 0x0e +#define AO_PS2_HYPHEN 0x4e +#define AO_PS2_EQUAL 0x55 +#define AO_PS2_BACKSLASH 0x5c +#define AO_PS2_BACKSPACE 0x66 +#define AO_PS2_SPACE 0x29 +#define AO_PS2_TAB 0x0d +#define AO_PS2_CAPS_LOCK 0x14 +#define AO_PS2_L_SHIFT 0x12 +#define AO_PS2_L_CTRL 0x11 +#define AO_PS2_L_WIN 0x8b +#define AO_PS2_L_ALT 0x19 +#define AO_PS2_R_SHIFT 0x59 +#define AO_PS2_R_CTRL 0x58 +#define AO_PS2_R_WIN 0x8c +#define AO_PS2_R_ALT 0x39 +#define AO_PS2_APPS 0x8d +#define AO_PS2_ENTER 0x5a +#define AO_PS2_ESC 0x08 +#define AO_PS2_F1 0x07 +#define AO_PS2_F2 0x0f +#define AO_PS2_F3 0x17 +#define AO_PS2_F4 0x1f +#define AO_PS2_F5 0x27 +#define AO_PS2_F6 0x2f +#define AO_PS2_F7 0x37 +#define AO_PS2_F8 0x3f +#define AO_PS2_F9 0x47 +#define AO_PS2_F10 0x4f +#define AO_PS2_F11 0x56 +#define AO_PS2_F12 0x5e +#define AO_PS2_PRNT_SCRN 0x57 +#define AO_PS2_SCROLL_LOCK 0x5f +#define AO_PS2_PAUSE 0x62 +#define AO_PS2_OPEN_SQ 0x54 +#define AO_PS2_INSERT 0x67 +#define AO_PS2_HOME 0x6e +#define AO_PS2_PG_UP 0x6f +#define AO_PS2_DELETE 0x64 +#define AO_PS2_END 0x65 +#define AO_PS2_PG_DN 0x6d +#define AO_PS2_UP 0x63 +#define AO_PS2_LEFT 0x61 +#define AO_PS2_DOWN 0x60 +#define AO_PS2_RIGHT 0x6a +#define AO_PS2_NUM_LOCK 0x76 +#define AO_PS2_KP_TIMES 0x7e +#define AO_PS2_KP_PLUS 0x7c +#define AO_PS2_KP_ENTER 0x79 +#define AO_PS2_KP_DECIMAL 0x71 +#define AO_PS2_KP_0 0x70 +#define AO_PS2_KP_1 0x69 +#define AO_PS2_KP_2 0x72 +#define AO_PS2_KP_3 0x7a +#define AO_PS2_KP_4 0x6b +#define AO_PS2_KP_5 0x73 +#define AO_PS2_KP_6 0x74 +#define AO_PS2_KP_7 0x6c +#define AO_PS2_KP_8 0x75 +#define AO_PS2_KP_9 0x7d +#define AO_PS2_CLOSE_SQ 0x5b +#define AO_PS2_SEMICOLON 0x4c +#define AO_PS2_ACUTE 0x52 +#define AO_PS2_COMMA 0x41 +#define AO_PS2_PERIOD 0x49 +#define AO_PS2_SLASH 0x4a + +#define AO_PS2_RELEASE_FLAG 0x80 + +#endif /* _AO_PS2_H_ */ -- cgit v1.2.3 From c296acd643698d0128e2f58f91a9cfeea63f580a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:21:39 -0800 Subject: altos: Add console driver using VGA and PS/2 Provides an interactive text console. Signed-off-by: Keith Packard --- src/drivers/ao_console.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_console.h | 24 ++++++++ 2 files changed, 175 insertions(+) create mode 100644 src/drivers/ao_console.c create mode 100644 src/drivers/ao_console.h (limited to 'src/drivers') diff --git a/src/drivers/ao_console.c b/src/drivers/ao_console.c new file mode 100644 index 00000000..cbde38c9 --- /dev/null +++ b/src/drivers/ao_console.c @@ -0,0 +1,151 @@ +/* + * 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.h" +#include "ao_console.h" +#include "ao_ps2.h" +#include "ao_vga.h" + +static uint8_t console_row, console_col; + +#define ao_console_bitmap ao_vga_bitmap + +static uint8_t console_rows, console_cols; + +static void +ao_console_scroll(void) +{ + ao_copy(&ao_console_bitmap, + 0, 0, + ao_console_bitmap.width, + ao_console_bitmap.height - ao_font.height, + &ao_console_bitmap, + 0, ao_font.height, + AO_COPY); + ao_rect(&ao_console_bitmap, + 0, + (console_rows - 1) * ao_font.height, + ao_console_bitmap.width, + ao_font.height, + 1, + AO_COPY); +} + +static void +ao_console_cursor(void) +{ + ao_rect(&ao_console_bitmap, + console_col * ao_font.width, + console_row * ao_font.height, + ao_font.width, + ao_font.height, + 1, + AO_XOR); +} + +static void +ao_console_clear(void) +{ + ao_rect(&ao_console_bitmap, + 0, 0, + ao_console_bitmap.width, + ao_console_bitmap.height, + 1, + AO_COPY); +} + +static void +ao_console_space(void) +{ + ao_rect(&ao_console_bitmap, + console_col * ao_font.width, + console_row * ao_font.height, + ao_font.width, + ao_font.height, + 1, + AO_COPY); +} + +static void +ao_console_newline(void) +{ + if (++console_row == console_rows) { + ao_console_scroll(); + console_row--; + } +} + +void +ao_console_putchar(char c) +{ + if (' ' <= c && c < 0x7f) { + char text[2]; + ao_console_space(); + text[0] = c; + text[1] = '\0'; + ao_text(&ao_console_bitmap, + console_col * ao_font.width, + console_row * ao_font.height + ao_font.ascent, + text, + 0, + AO_COPY); + if (++console_col == console_cols) { + console_col = 0; + ao_console_newline(); + } + } else { + ao_console_cursor(); + switch (c) { + case '\r': + console_col = 0; + break; + case '\t': + console_col += 8 - (console_col & 7); + if (console_col >= console_cols) { + console_col = 0; + ao_console_newline(); + } + break; + case '\n': + ao_console_newline(); + break; + case '\f': + console_col = console_row = 0; + ao_console_clear(); + break; + case '\177': + case '\010': + if (console_col) + console_col--; + break; + } + } + ao_console_cursor(); +} + +void +ao_console_init(void) +{ + console_cols = ao_console_bitmap.width / ao_font.width; + console_rows = ao_console_bitmap.height / ao_font.height; +#if CONSOLE_STDIN + ao_ps2_stdin = 1; + ao_add_stdio(_ao_ps2_pollchar, + ao_console_putchar, + NULL); +#endif + ao_console_clear(); + ao_console_cursor(); + ao_vga_enable(1); +} diff --git a/src/drivers/ao_console.h b/src/drivers/ao_console.h new file mode 100644 index 00000000..33d3658a --- /dev/null +++ b/src/drivers/ao_console.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#ifndef _AO_CONSOLE_H_ +#define _AO_CONSOLE_H_ + +void +ao_console_putchar(char c); + +void +ao_console_init(void); + +#endif /* _AO_CONSOLE_H_ */ -- cgit v1.2.3 From cc1b56faa88c75c9c86af89c77d7f1349573b7b0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 17:39:05 -0700 Subject: altos: Add AS1107 LED display driver Signed-off-by: Keith Packard --- src/drivers/ao_as1107.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_as1107.h | 59 ++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 src/drivers/ao_as1107.c create mode 100644 src/drivers/ao_as1107.h (limited to 'src/drivers') diff --git a/src/drivers/ao_as1107.c b/src/drivers/ao_as1107.c new file mode 100644 index 00000000..0b83ab2c --- /dev/null +++ b/src/drivers/ao_as1107.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2017 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 + +static uint8_t as1107_configured; +static uint8_t as1107_mutex; + +static void +ao_as1107_start(void) { + ao_spi_get_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX, AO_AS1107_SPI_SPEED); +} + +static void +ao_as1107_stop(void) { + ao_spi_put_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX); +} + +static void +_ao_as1107_cmd(uint8_t addr, uint8_t value) +{ + uint8_t packet[2] = { addr, value }; + + ao_as1107_start(); + ao_spi_send(packet, 2, AO_AS1107_SPI_INDEX); + ao_as1107_stop(); +} + +static void +_ao_as1107_setup(void) +{ + if (!as1107_configured) { + as1107_configured = 1; + _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_RESET); + _ao_as1107_cmd(AO_AS1107_DECODE_MODE, AO_AS1107_DECODE); + _ao_as1107_cmd(AO_AS1107_SCAN_LIMIT, AO_AS1107_NUM_DIGITS - 1); + _ao_as1107_cmd(AO_AS1107_FEATURE, + (0 << AO_AS1107_FEATURE_CLK_EN) | + (0 << AO_AS1107_FEATURE_REG_RES) | + (1 << AO_AS1107_FEATURE_DECODE_SEL) | + (1 << AO_AS1107_FEATURE_SPI_EN) | + (0 << AO_AS1107_FEATURE_BLINK_EN) | + (0 << AO_AS1107_FEATURE_BLINK_FREQ) | + (0 << AO_AS1107_FEATURE_SYNC) | + (0 << AO_AS1107_FEATURE_BLINK_START)); + } +} + +void +ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values) +{ + uint8_t i; + ao_mutex_get(&as1107_mutex); + _ao_as1107_setup(); + for (i = 0; i < count; i++) + { + _ao_as1107_cmd(AO_AS1107_DIGIT(start + i), + values[i]); + } + ao_mutex_put(&as1107_mutex); +} + +void +ao_as1107_write_8(uint8_t start, uint8_t value) +{ + uint8_t values[2]; + + values[0] = (value >> 4); + values[1] = value & 0xf; + ao_as1107_write(start, 2, values); +} + +void +ao_as1107_write_16(uint8_t start, uint16_t value) +{ + uint8_t values[4]; + + values[0] = (value >> 12); + values[1] = (value >> 8) & 0xf; + values[2] = (value >> 4) & 0xf; + values[3] = (value) & 0xf; + ao_as1107_write(start, 4, values); +} + +void +ao_as1107_init(void) +{ + as1107_configured = 0; + ao_spi_init_cs(AO_AS1107_CS_PORT, (1 << AO_AS1107_CS_PIN)); +} diff --git a/src/drivers/ao_as1107.h b/src/drivers/ao_as1107.h new file mode 100644 index 00000000..a22b17db --- /dev/null +++ b/src/drivers/ao_as1107.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2017 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. + */ + +#ifndef _AO_AS1107_H_ +#define _AO_AS1107_H_ + +#define AO_AS1107_NO_OP 0x00 +#define AO_AS1107_DIGIT(n) (0x01 + (n)) +#define AO_AS1107_DECODE_MODE 0x09 +#define AO_AS1107_INTENSITY 0x0a +#define AO_AS1107_SCAN_LIMIT 0x0b +#define AO_AS1107_SHUTDOWN 0x0c +#define AO_AS1107_SHUTDOWN_SHUTDOWN_RESET 0x00 +#define AO_AS1107_SHUTDOWN_SHUTDOWN_NOP 0x80 +#define AO_AS1107_SHUTDOWN_NORMAL_RESET 0x01 +#define AO_AS1107_SHUTDOWN_NORMAL_NOP 0x81 + +#define AO_AS1107_FEATURE 0x0e +#define AO_AS1107_FEATURE_CLK_EN 0 /* external clock enable */ +#define AO_AS1107_FEATURE_REG_RES 1 +#define AO_AS1107_FEATURE_DECODE_SEL 2 /* select HEX decode */ +#define AO_AS1107_FEATURE_SPI_EN 3 +#define AO_AS1107_FEATURE_BLINK_EN 4 +#define AO_AS1107_FEATURE_BLINK_FREQ 5 +#define AO_AS1107_FEATURE_SYNC 6 +#define AO_AS1107_FEATURE_BLINK_START 7 +#define AO_AS1107_DISPLAY_TEST 0x0f + +void ao_as1107_init(void); + +void +ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values); + +void +ao_as1107_write_8(uint8_t start, uint8_t value); + +void +ao_as1107_write_16(uint8_t start, uint16_t value); + +#ifndef AO_AS1107_DECODE +#error "must define AO_AS1107_DECODE" +#endif + +#ifndef AO_AS1107_NUM_DIGITS +#error "must define AO_AS1107_NUM_DIGITS" +#endif + +#endif /* _AO_AS1107_H_ */ -- cgit v1.2.3 From 09f8710eb320f37f20dda8c635497c2b505d25e2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 19:30:57 -0700 Subject: altos: add button matrix driver Scans the matrix once per clock tick queuing events for changed keys. Signed-off-by: Keith Packard --- src/drivers/ao_event.h | 1 + src/drivers/ao_matrix.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_matrix.h | 24 ++++++ src/stm/ao_arch_funcs.h | 8 +- 4 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/drivers/ao_matrix.c create mode 100644 src/drivers/ao_matrix.h (limited to 'src/drivers') diff --git a/src/drivers/ao_event.h b/src/drivers/ao_event.h index d1c69d81..d1df6eac 100644 --- a/src/drivers/ao_event.h +++ b/src/drivers/ao_event.h @@ -22,6 +22,7 @@ #define AO_EVENT_NONE 0 #define AO_EVENT_QUADRATURE 1 #define AO_EVENT_BUTTON 2 +#define AO_EVENT_KEY 3 struct ao_event { uint8_t type; diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c new file mode 100644 index 00000000..e0f8ba75 --- /dev/null +++ b/src/drivers/ao_matrix.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2017 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 +#include +#include + +#define row_port(q) AO_MATRIX_ROW_ ## q ## _PORT +#define row_bit(q) AO_MATRIX_ROW_ ## q ## _PIN +#define row_pin(q) AO_MATRIX_ROW_ ## q ## _PIN + +#define col_port(q) AO_MATRIX_COL_ ## q ## _PORT +#define col_bit(q) AO_MATRIX_COL_ ## q ## _PIN +#define col_pin(q) AO_MATRIX_COL_ ## q ## _PIN + +static void +_ao_matrix_drive_row(uint8_t row, uint8_t val) +{ + switch (row) { +#define drive(n) case n: ao_gpio_set(row_port(n), row_bit(n), row_pin(n), val); break + drive(0); +#if AO_MATRIX_ROWS > 1 + drive(1); +#endif +#if AO_MATRIX_ROWS > 2 + drive(2); +#endif +#if AO_MATRIX_ROWS > 3 + drive(3); +#endif +#if AO_MATRIX_ROWS > 4 + drive(4); +#endif +#if AO_MATRIX_ROWS > 5 + drive(5); +#endif +#if AO_MATRIX_ROWS > 6 + drive(6); +#endif +#if AO_MATRIX_ROWS > 7 + drive(7); +#endif + } +} + +static uint8_t +_ao_matrix_read_cols(void) +{ + uint8_t v = 0; +#define read(n) (v |= ao_gpio_get(col_port(n), col_bit(n), col_pin(n)) << n) + + read(0); +#if AO_MATRIX_ROWS > 1 + read(1); +#endif +#if AO_MATRIX_ROWS > 2 + read(2); +#endif +#if AO_MATRIX_ROWS > 3 + read(3); +#endif +#if AO_MATRIX_ROWS > 4 + read(4); +#endif +#if AO_MATRIX_ROWS > 5 + read(5); +#endif +#if AO_MATRIX_ROWS > 6 + read(6); +#endif +#if AO_MATRIX_ROWS > 7 + read(7); +#endif + return v; +} + +static uint8_t +_ao_matrix_read(uint8_t row) { + uint8_t state; + _ao_matrix_drive_row(row, 1); + state = _ao_matrix_read_cols(); + _ao_matrix_drive_row(row, 0); + return state; +} + +#define AO_MATRIX_DEBOUNCE_INTERVAL AO_MS_TO_TICKS(50) + +static uint8_t ao_matrix_keymap[AO_MATRIX_ROWS][AO_MATRIX_COLS] = AO_MATRIX_KEYCODES; + +static uint8_t ao_matrix_state[AO_MATRIX_ROWS]; +static AO_TICK_TYPE ao_matrix_tick[AO_MATRIX_ROWS]; + +static void +_ao_matrix_poll_one(uint8_t row) { + uint8_t state = _ao_matrix_read(row); + + if (state != ao_matrix_state[row]) { + AO_TICK_TYPE now = ao_time(); + + if ((now - ao_matrix_tick[row]) >= AO_MATRIX_DEBOUNCE_INTERVAL) { + uint8_t col; + uint8_t changes = state ^ ao_matrix_state[row]; + + for (col = 0; col < AO_MATRIX_COLS; col++) { + if (changes & (1 << col)) { + ao_event_put_isr(AO_EVENT_KEY, + ao_matrix_keymap[row][col], + ((state >> col) & 1) == 0); + } + } + ao_matrix_state[row] = state; + } + ao_matrix_tick[row] = now; + } +} + +void +ao_matrix_poll(void) +{ + uint8_t row; + + for (row = 0; row < AO_MATRIX_ROWS; row++) + _ao_matrix_poll_one(row); +} + +#define init_row(b) do { \ + ao_enable_output(row_port(b), row_bit(b), row_pin(v), 1); \ + ao_gpio_set_output_mode(row_port(b), row_bit(b), row_pin(b), AO_OUTPUT_OPEN_DRAIN); \ + } while (0) + +#define init_col(b) do { \ + ao_enable_input(col_port(b), col_bit(b), AO_EXTI_MODE_PULL_UP); \ + } while(0) + +void +ao_matrix_init(void) +{ + uint8_t row; + + init_row(0); +#if AO_MATRIX_ROWS > 1 + init_row(1); +#endif +#if AO_MATRIX_ROWS > 2 + init_row(2); +#endif +#if AO_MATRIX_ROWS > 3 + init_row(3); +#endif +#if AO_MATRIX_ROWS > 4 + init_row(4); +#endif +#if AO_MATRIX_ROWS > 5 + init_row(5); +#endif +#if AO_MATRIX_ROWS > 6 + init_row(6); +#endif +#if AO_MATRIX_ROWS > 7 + init_row(7); +#endif + + init_col(0); +#if AO_MATRIX_COLS > 1 + init_col(1); +#endif +#if AO_MATRIX_COLS > 2 + init_col(2); +#endif +#if AO_MATRIX_COLS > 3 + init_col(3); +#endif +#if AO_MATRIX_COLS > 4 + init_col(4); +#endif +#if AO_MATRIX_COLS > 5 + init_col(5); +#endif +#if AO_MATRIX_COLS > 6 + init_col(6); +#endif +#if AO_MATRIX_COLS > 7 + init_col(7); +#endif + for (row = 0; row < AO_MATRIX_ROWS; row++) { + ao_matrix_state[row] = _ao_matrix_read(row); + ao_matrix_tick[row] = ao_time(); + } +} diff --git a/src/drivers/ao_matrix.h b/src/drivers/ao_matrix.h new file mode 100644 index 00000000..ab5a1c51 --- /dev/null +++ b/src/drivers/ao_matrix.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2017 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. + */ + +#ifndef _AO_MATRIX_H_ +#define _AO_MATRIX_H_ + +void +ao_matrix_poll(void); + +void +ao_matrix_init(void); + +#endif /* _AO_MATRIX_H_ */ diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 88097406..b294c379 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -211,6 +211,12 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s stm_moder_set(port, bit, STM_MODER_OUTPUT);\ } while (0) +#define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL +#define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN + +#define ao_gpio_set_output_mode(port,bit,pin,mode) \ + stm_otyper_set(port, pin, mode) + #define ao_gpio_set_mode(port,bit,mode) do { \ if (mode == AO_EXTI_MODE_PULL_UP) \ stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP); \ @@ -219,7 +225,7 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s else \ stm_pupdr_set(port, bit, STM_PUPDR_NONE); \ } while (0) - + #define ao_enable_input(port,bit,mode) do { \ ao_enable_port(port); \ stm_moder_set(port, bit, STM_MODER_INPUT); \ -- cgit v1.2.3 From 79215de60d3e11b4abd1ecd2fa9575a323b76754 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 19:31:45 -0700 Subject: altos: Allow buttons to be high when pressed rather than low Signed-off-by: Keith Packard --- src/drivers/ao_button.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/ao_button.c b/src/drivers/ao_button.c index 725ac45a..07e92c67 100644 --- a/src/drivers/ao_button.c +++ b/src/drivers/ao_button.c @@ -39,8 +39,16 @@ static struct ao_button_state ao_button_state[AO_BUTTON_COUNT]; #define bit(q) AO_BUTTON_ ## q #define pin(q) AO_BUTTON_ ## q ## _PIN +#ifndef AO_BUTTON_INVERTED +#define AO_BUTTON_INVERTED 1 +#endif + +#if AO_BUTTON_INVERTED /* pins are inverted */ #define ao_button_value(b) !ao_gpio_get(port(b), bit(b), pin(b)) +#else +#define ao_button_value(b) ao_gpio_get(port(b), bit(b), pin(b)) +#endif static uint8_t _ao_button_get(uint8_t b) -- cgit v1.2.3 From 920b70fd5f6b78461c7ebae6b1e6490a0e050bc2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 15:59:56 -0700 Subject: altos: Define CC115L spi speed in each product Different SoCs have different SPI speeds available; have each product specify the speed to use instead of trying to use 4Mhz everywhere. Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 2 +- src/telegps-v0.1/ao_pins.h | 1 + src/telegps-v0.3/ao_pins.h | 1 + src/telegps-v1.0/ao_pins.h | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index a67071d2..c1c21e0d 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -39,7 +39,7 @@ static uint8_t ao_radio_abort; /* radio operation should abort */ #define FOSC 26000000 -#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_6MHz) +#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED) #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS) #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS) #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS) diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 96e8cfd7..0b610cac 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -148,6 +148,7 @@ #define AO_CC115L_SPI_CS_PIN 12 #define AO_CC115L_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC115L_SPI stm_spi2 +#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_4MHz #define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 #define AO_CC115L_FIFO_INT_PORT (&stm_gpioa) diff --git a/src/telegps-v0.3/ao_pins.h b/src/telegps-v0.3/ao_pins.h index 9c650cc4..28ae30a4 100644 --- a/src/telegps-v0.3/ao_pins.h +++ b/src/telegps-v0.3/ao_pins.h @@ -95,6 +95,7 @@ #define AO_CC115L_SPI_CS_PORT 0 #define AO_CC115L_SPI_CS_PIN 3 #define AO_CC115L_SPI_BUS 0 +#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_6MHz #define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 #define AO_CC115L_FIFO_INT_PORT 0 diff --git a/src/telegps-v1.0/ao_pins.h b/src/telegps-v1.0/ao_pins.h index 19774f63..9672ab03 100644 --- a/src/telegps-v1.0/ao_pins.h +++ b/src/telegps-v1.0/ao_pins.h @@ -97,6 +97,7 @@ #define AO_CC115L_SPI_CS_PORT 0 #define AO_CC115L_SPI_CS_PIN 3 #define AO_CC115L_SPI_BUS 0 +#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_6MHz #define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 #define AO_CC115L_FIFO_INT_PORT 0 -- cgit v1.2.3 From 4eced9224f40e48d7057352b3424c18025f43f25 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:02:46 -0700 Subject: altos: Disable FAT commands unless requested This are debugging commands; don't provide them unless requested Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index fb8eecff..43e7df23 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -1615,7 +1615,7 @@ ao_fat_hexdump_cmd(void) ao_cmd_status = ao_cmd_syntax_error; return; } - + fd = ao_fat_open(name, AO_FAT_OPEN_READ); if (fd < 0) { printf ("Open failed: %d\n", fd); @@ -1649,5 +1649,7 @@ void ao_fat_init(void) { ao_bufio_init(); +#if FAT_COMMANDS ao_cmd_register(&ao_fat_cmds[0]); +#endif } -- cgit v1.2.3 From 71e430bb39fc97e543778f7bc1f1bef554ba8b75 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:03:36 -0700 Subject: altos: Allow programs to enable SDCARD debugging if desired Provides for per-application control over SDCARD debugging Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 4b17c5e3..45454000 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -38,13 +38,19 @@ extern uint8_t ao_radio_mutex; #define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) /* Include SD card commands */ +#ifndef SDCARD_DEBUG #define SDCARD_DEBUG 0 +#endif /* Spew SD tracing */ +#ifndef SDCARD_TRACE #define SDCARD_TRACE 0 +#endif /* Emit error and warning messages */ +#ifndef SDCARD_WARN #define SDCARD_WARN 0 +#endif static uint8_t initialized; static uint8_t present; -- cgit v1.2.3 From a68fb412589819980759d49565a084b23eee8b8f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:51:49 -0700 Subject: altos: Place AS1107 in 'normal' mode at end of init sequence This makes sure the device is out of reset mode while initializing, and then placed in normal mode to turn on the display. Signed-off-by: Keith Packard --- src/drivers/ao_as1107.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/drivers') diff --git a/src/drivers/ao_as1107.c b/src/drivers/ao_as1107.c index 0b83ab2c..e0172d95 100644 --- a/src/drivers/ao_as1107.c +++ b/src/drivers/ao_as1107.c @@ -44,8 +44,10 @@ _ao_as1107_setup(void) if (!as1107_configured) { as1107_configured = 1; _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_RESET); + _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_NOP); _ao_as1107_cmd(AO_AS1107_DECODE_MODE, AO_AS1107_DECODE); _ao_as1107_cmd(AO_AS1107_SCAN_LIMIT, AO_AS1107_NUM_DIGITS - 1); + _ao_as1107_cmd(AO_AS1107_INTENSITY, 0x0f); _ao_as1107_cmd(AO_AS1107_FEATURE, (0 << AO_AS1107_FEATURE_CLK_EN) | (0 << AO_AS1107_FEATURE_REG_RES) | @@ -55,6 +57,7 @@ _ao_as1107_setup(void) (0 << AO_AS1107_FEATURE_BLINK_FREQ) | (0 << AO_AS1107_FEATURE_SYNC) | (0 << AO_AS1107_FEATURE_BLINK_START)); + _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_NORMAL_NOP); } } -- cgit v1.2.3 From 24cd5dd33ccf65c1b277911c460a89ec2b52e421 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:53:34 -0700 Subject: altos: Drive row low instead of high in matrix driver Driving it high won't work all that well as we're looking for zero bits. Signed-off-by: Keith Packard --- src/drivers/ao_matrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c index e0f8ba75..fa2d0c57 100644 --- a/src/drivers/ao_matrix.c +++ b/src/drivers/ao_matrix.c @@ -89,9 +89,9 @@ _ao_matrix_read_cols(void) static uint8_t _ao_matrix_read(uint8_t row) { uint8_t state; - _ao_matrix_drive_row(row, 1); - state = _ao_matrix_read_cols(); _ao_matrix_drive_row(row, 0); + state = _ao_matrix_read_cols(); + _ao_matrix_drive_row(row, 1); return state; } -- cgit v1.2.3 From 83c1e4e8ca684f555cba252efd3882f811d8e154 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:54:57 -0700 Subject: altos: Document a few more SPI mode bits in VGA driver Just comment changes Signed-off-by: Keith Packard --- src/drivers/ao_vga.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c index 2d05d522..909e3109 100644 --- a/src/drivers/ao_vga.c +++ b/src/drivers/ao_vga.c @@ -139,13 +139,13 @@ ao_vga_init(void) (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */ (0 << STM_SPI_CR1_CRCNEXT) | (1 << STM_SPI_CR1_DFF) | - (0 << STM_SPI_CR1_RXONLY) | + (0 << STM_SPI_CR1_RXONLY) | /* transmit, not receive */ (0 << STM_SPI_CR1_SSM) | /* Software SS handling */ (1 << STM_SPI_CR1_SSI) | /* ... */ (1 << STM_SPI_CR1_LSBFIRST) | /* Little endian */ (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ (0 << STM_SPI_CR1_BR) | /* baud rate to pclk/2 */ - (0 << STM_SPI_CR1_MSTR) | + (0 << STM_SPI_CR1_MSTR) | /* slave */ (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ (0 << STM_SPI_CR1_CPHA)); stm_spi1.cr2 = ((0 << STM_SPI_CR2_TXEIE) | -- cgit v1.2.3 From e3b30d4bd6faf68c885791fb87229558cc1157a6 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:01:44 -0600 Subject: add static test start and stop commands to radio protocol for telefiretwo --- src/drivers/ao_pad.c | 31 ++++++++++++++++++++++++++++--- src/drivers/ao_pad.h | 5 +++++ 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index ffa833fe..28c00fe3 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -316,7 +316,7 @@ ao_pad(void) command.tick, command.box, ao_pad_box, command.cmd, command.channels); switch (command.cmd) { - case AO_LAUNCH_ARM: + case AO_PAD_ARM: if (command.box != ao_pad_box) { PRINTD ("box number mismatch\n"); break; @@ -338,7 +338,7 @@ ao_pad(void) ao_pad_arm_time = ao_time(); break; - case AO_LAUNCH_QUERY: + case AO_PAD_QUERY: if (command.box != ao_pad_box) { PRINTD ("box number mismatch\n"); break; @@ -357,7 +357,7 @@ ao_pad(void) query.igniter_status[3]); ao_radio_cmac_send(&query, sizeof (query)); break; - case AO_LAUNCH_FIRE: + case AO_PAD_FIRE: if (!ao_pad_armed) { PRINTD ("not armed\n"); break; @@ -373,6 +373,31 @@ ao_pad(void) ao_wakeup(&ao_pad_ignite); break; } + case AO_PAD_STATIC: + if (!ao_pad_armed) { + PRINTD ("not armed\n"); + break; + } +#ifdef HAS_LOG + if (!ao_log_running) ao_log_start(); +#endif + if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) { + PRINTD ("late pad arm_time %d time %d\n", + ao_pad_arm_time, ao_time()); + break; + } + PRINTD ("ignite\n"); + ao_pad_ignite = ao_pad_armed; + ao_pad_arm_time = ao_time(); + ao_wakeup(&ao_pad_ignite); + break; + } + case AO_PAD_ENDSTATIC: +#ifdef HAS_LOG + ao_log_stop(); +#endif + break; + } } } diff --git a/src/drivers/ao_pad.h b/src/drivers/ao_pad.h index 648d3005..e4115222 100644 --- a/src/drivers/ao_pad.h +++ b/src/drivers/ao_pad.h @@ -54,6 +54,11 @@ struct ao_pad_query { */ #define AO_PAD_FIRE 3 +/* Fire current armed pads for 200ms, no report, logging test stand sensors + */ +#define AO_PAD_STATIC 4 +#define AO_PAD_ENDSTATIC 5 + #define AO_PAD_FIRE_TIME AO_MS_TO_TICKS(200) #define AO_PAD_ARM_STATUS_DISARMED 0 -- cgit v1.2.3 From 6cfd9411026d536b5b75098b8c9ec3ceb3d945aa Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:02:53 -0600 Subject: eliminate spurious close braces --- src/drivers/ao_pad.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index 28c00fe3..c18cdd8d 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -372,7 +372,6 @@ ao_pad(void) ao_pad_arm_time = ao_time(); ao_wakeup(&ao_pad_ignite); break; - } case AO_PAD_STATIC: if (!ao_pad_armed) { PRINTD ("not armed\n"); @@ -391,7 +390,6 @@ ao_pad(void) ao_pad_arm_time = ao_time(); ao_wakeup(&ao_pad_ignite); break; - } case AO_PAD_ENDSTATIC: #ifdef HAS_LOG ao_log_stop(); -- cgit v1.2.3 From d75351c5a07241bcbb951758796b4f639ace6b1f Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:42:23 -0600 Subject: implement static test start and stop protocol for telefiretwo+telebt --- src/drivers/ao_lco.c | 2 +- src/drivers/ao_lco_cmd.c | 51 +++++++++++++++++++++++++++++++++++++++++++---- src/drivers/ao_lco_func.c | 8 ++++---- src/drivers/ao_lco_func.h | 2 +- src/drivers/ao_lco_two.c | 2 +- 5 files changed, 54 insertions(+), 11 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_lco.c b/src/drivers/ao_lco.c index 00f10ecc..e1806ca3 100644 --- a/src/drivers/ao_lco.c +++ b/src/drivers/ao_lco.c @@ -661,7 +661,7 @@ ao_lco_monitor(void) ao_lco_armed, ao_lco_firing); if (ao_lco_armed && ao_lco_firing) { - ao_lco_ignite(); + ao_lco_ignite(AO_PAD_FIRE); } else { ao_lco_update(); if (ao_lco_armed) { diff --git a/src/drivers/ao_lco_cmd.c b/src/drivers/ao_lco_cmd.c index dcc0c6d0..8de21fb6 100644 --- a/src/drivers/ao_lco_cmd.c +++ b/src/drivers/ao_lco_cmd.c @@ -61,9 +61,9 @@ lco_arm(void) } static void -lco_ignite(void) +lco_ignite(uint8_t cmd) { - ao_lco_ignite(); + ao_lco_ignite(cmd); } static void @@ -145,7 +145,40 @@ lco_fire_cmd(void) __reentrant secs = 100; for (i = 0; i < secs; i++) { printf("fire %d\n", i); flush(); - lco_ignite(); + lco_ignite(AO_PAD_FIRE); + ao_delay(AO_MS_TO_TICKS(100)); + } +} + +static void +lco_static_cmd(void) __reentrant +{ + uint8_t secs; + uint8_t i; + int8_t r; + + lco_args(); + ao_cmd_decimal(); + secs = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) + return; + r = lco_query(); + if (r != AO_RADIO_CMAC_OK) { + printf("query failed %d\n", r); + return; + } + + for (i = 0; i < 4; i++) { + printf("arm %d\n", i); flush(); + lco_arm(); + } + + secs = secs * 10 - 5; + if (secs > 100) + secs = 100; + for (i = 0; i < secs; i++) { + printf("fire %d\n", i); flush(); + lco_ignite(AO_PAD_STATIC); ao_delay(AO_MS_TO_TICKS(100)); } } @@ -171,12 +204,22 @@ lco_ignite_cmd(void) __reentrant uint8_t i; lco_args(); for (i = 0; i < 4; i++) - lco_ignite(); + lco_ignite(AO_PAD_FIRE); +} + + +static void +lco_endstatic_cmd(void) __reentrant +{ + lco_ignite(AO_PAD_ENDSTATIC); } static __code struct ao_cmds ao_lco_cmds[] = { { lco_report_cmd, "l \0Get remote status" }, { lco_fire_cmd, "F \0Fire remote igniters" }, + { lco_fire_cmd, "F \0Fire remote igniters" }, + { lco_static_cmd, "S \0Initiate static test" }, + { lco_endstatic_cmd, "D\0End static test (and download someday)" }, { lco_arm_cmd, "a \0Arm remote igniter" }, { lco_ignite_cmd, "i \0Pulse remote igniter" }, { 0, NULL }, diff --git a/src/drivers/ao_lco_func.c b/src/drivers/ao_lco_func.c index 862cb1be..92b344ed 100644 --- a/src/drivers/ao_lco_func.c +++ b/src/drivers/ao_lco_func.c @@ -47,7 +47,7 @@ ao_lco_query(uint16_t box, struct ao_pad_query *query, uint16_t *tick_offset) ao_mutex_get(&ao_lco_mutex); command.tick = ao_time(); command.box = box; - command.cmd = AO_LAUNCH_QUERY; + command.cmd = AO_PAD_QUERY; command.channels = 0; ao_radio_cmac_send(&command, sizeof (command)); sent_time = ao_time(); @@ -64,19 +64,19 @@ ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset) ao_mutex_get(&ao_lco_mutex); command.tick = ao_time() - tick_offset; command.box = box; - command.cmd = AO_LAUNCH_ARM; + command.cmd = AO_PAD_ARM; command.channels = channels; ao_radio_cmac_send(&command, sizeof (command)); ao_mutex_put(&ao_lco_mutex); } void -ao_lco_ignite(void) +ao_lco_ignite(uint8_t cmd) { ao_mutex_get(&ao_lco_mutex); command.tick = 0; command.box = 0; - command.cmd = AO_LAUNCH_FIRE; + command.cmd = cmd; command.channels = 0; ao_radio_cmac_send(&command, sizeof (command)); ao_mutex_put(&ao_lco_mutex); diff --git a/src/drivers/ao_lco_func.h b/src/drivers/ao_lco_func.h index 6b06f928..9d4a27ba 100644 --- a/src/drivers/ao_lco_func.h +++ b/src/drivers/ao_lco_func.h @@ -28,6 +28,6 @@ void ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset); void -ao_lco_ignite(void); +ao_lco_ignite(uint8_t cmd); #endif /* _AO_LCO_FUNC_H_ */ diff --git a/src/drivers/ao_lco_two.c b/src/drivers/ao_lco_two.c index 1cb0546c..e2f86745 100644 --- a/src/drivers/ao_lco_two.c +++ b/src/drivers/ao_lco_two.c @@ -287,7 +287,7 @@ ao_lco_monitor(void) ao_lco_armed, ao_lco_firing); if (ao_lco_armed && ao_lco_firing) { - ao_lco_ignite(); + ao_lco_ignite(AO_PAD_FIRE); } else { ao_lco_get_channels(); if (ao_lco_armed) { -- cgit v1.2.3 From 8e5b4359050701513a807131564ae54f2e6b919b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 24 Apr 2017 16:40:46 -0700 Subject: altos/ao_pad.c: Use #if HAS_LOG instead of #ifdef HAS_LOG TeleFire v0.1 defines HAS_LOG to 0. Signed-off-by: Keith Packard --- src/drivers/ao_pad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index c18cdd8d..16b4ae60 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -377,7 +377,7 @@ ao_pad(void) PRINTD ("not armed\n"); break; } -#ifdef HAS_LOG +#if HAS_LOG if (!ao_log_running) ao_log_start(); #endif if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) { @@ -391,7 +391,7 @@ ao_pad(void) ao_wakeup(&ao_pad_ignite); break; case AO_PAD_ENDSTATIC: -#ifdef HAS_LOG +#if HAS_LOG ao_log_stop(); #endif break; -- cgit v1.2.3