From f650211f9e99e1d3d0ae13ae559dd1c082f71545 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 12 Dec 2016 16:44:47 -0800 Subject: altos/stm: Make ao_usb_set_address static. Saves a bunch of text space I'm sure this makes the function end up in-lined, which saves enough text space to fit the flash loader in ROM again. Signed-off-by: Keith Packard --- src/stm/ao_usb_stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/stm') diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 0de501ab..f2b8ea94 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -174,7 +174,7 @@ static inline uint32_t ao_usb_epr_dtog_tx(uint32_t epr) { * Set current device address and mark the * interface as active */ -void +static void ao_usb_set_address(uint8_t address) { debug("ao_usb_set_address %02x\n", address); -- 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/stm') 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 088ddbb177efc8be2fc467524dc1668553080d3b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 20:54:10 -0800 Subject: altos/stm: Interrupt priority is in the upper bits of the priority mask Because the STM32L only offers 16 priority levels, the bottom four bits of each priority mask are not used. All of the interrupt priority settings in the system were using values < 16, making them all effectively the same. Fix that by moving them into the upper 4 bits and using symbolic constants everywhere. Signed-off-by: Keith Packard --- src/stm/ao_arch.h | 10 ++++++---- src/stm/ao_dma_stm.c | 3 ++- src/stm/ao_exti_stm.c | 2 +- src/stm/ao_serial_stm.c | 6 +++--- src/stm/ao_timer.c | 1 + src/stm/ao_usb_stm.c | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/stm') diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 0cc29376..3d09af3c 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -122,10 +122,12 @@ extern const uint32_t ao_radio_cal; #define AO_TIM91011_CLK (2 * AO_PCLK2) #endif -#define AO_STM_NVIC_HIGH_PRIORITY 4 -#define AO_STM_NVIC_CLOCK_PRIORITY 6 -#define AO_STM_NVIC_MED_PRIORITY 8 -#define AO_STM_NVIC_LOW_PRIORITY 10 +/* The stm32l implements only 4 bits of the priority fields */ + +#define AO_STM_NVIC_HIGH_PRIORITY 0x40 +#define AO_STM_NVIC_MED_PRIORITY 0x80 +#define AO_STM_NVIC_LOW_PRIORITY 0xC0 +#define AO_STM_NVIC_CLOCK_PRIORITY 0xf0 void ao_lcd_stm_init(void); diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 6d779660..63d6688a 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -155,7 +155,8 @@ ao_dma_init(void) for (index = 0; index < STM_NUM_DMA; index++) { stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index); - stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, 4); + stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, + AO_STM_NVIC_MED_PRIORITY); ao_dma_allocated[index] = 0; ao_dma_mutex[index] = 0; } diff --git a/src/stm/ao_exti_stm.c b/src/stm/ao_exti_stm.c index 3e0b3e5c..2491b609 100644 --- a/src/stm/ao_exti_stm.c +++ b/src/stm/ao_exti_stm.c @@ -123,7 +123,7 @@ ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) { (void) gpio; uint32_t mask = 1 << pin; - + if (mode & AO_EXTI_MODE_RISING) stm_exti.rtsr |= mask; else diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index db0be992..c625471e 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -444,7 +444,7 @@ ao_serial_init(void) ao_usart_init(&ao_stm_usart1); stm_nvic_set_enable(STM_ISR_USART1_POS); - stm_nvic_set_priority(STM_ISR_USART1_POS, 4); + stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN ao_add_stdio(_ao_serial1_pollchar, ao_serial1_putchar, @@ -500,7 +500,7 @@ ao_serial_init(void) #endif stm_nvic_set_enable(STM_ISR_USART2_POS); - stm_nvic_set_priority(STM_ISR_USART2_POS, 4); + stm_nvic_set_priority(STM_ISR_USART2_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN ao_add_stdio(_ao_serial2_pollchar, ao_serial2_putchar, @@ -544,7 +544,7 @@ ao_serial_init(void) ao_usart_init(&ao_stm_usart3); stm_nvic_set_enable(STM_ISR_USART3_POS); - stm_nvic_set_priority(STM_ISR_USART3_POS, 4); + stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN ao_add_stdio(_ao_serial3_pollchar, ao_serial3_putchar, diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index f86a5116..1576a6c9 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -90,6 +90,7 @@ ao_timer_init(void) stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) | (1 << STM_SYSTICK_CSR_TICKINT) | (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE)); + stm_nvic.shpr15_12 |= AO_STM_NVIC_CLOCK_PRIORITY << 24; } #endif diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 9d72844e..2abaf10f 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -1015,7 +1015,7 @@ ao_usb_enable(void) ao_arch_block_interrupts(); /* Route interrupts */ - stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3); + stm_nvic_set_priority(STM_ISR_USB_LP_POS, AO_STM_NVIC_LOW_PRIORITY); stm_nvic_set_enable(STM_ISR_USB_LP_POS); ao_usb_configuration = 0; -- cgit v1.2.3 From 839eadbc8e5694842eb498c6e47cfbf08ba8fbf4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 02:59:40 -0800 Subject: altos/stm: Allow use basepri instead of primask for masking interrupts This allows for high priority interrupts (priority 0) to run, even when other interrupts are blocked. Code executing in such interrupt handlers must not attempt to control task execution as that will race with the scheduler. Select this by defining AO_NONMASK_INTERRUPT in ao_pins.h. non-maskable interrupt priority is AO_STM_NVIC_NONMASK_PRIORITY Signed-off-by: Keith Packard --- src/stm/ao_arch.h | 13 +++++--- src/stm/ao_arch_funcs.h | 84 ++++++++++++++++++++++++++++++++++++++++--------- src/stm/ao_usb_stm.c | 16 ++++++---- 3 files changed, 89 insertions(+), 24 deletions(-) (limited to 'src/stm') diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 3d09af3c..5f033b66 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -85,10 +85,6 @@ extern const uint32_t ao_radio_cal; #define ao_arch_task_members\ uint32_t *sp; /* saved stack pointer */ -#define ao_arch_block_interrupts() asm("cpsid i") -#define ao_arch_release_interrupts() asm("cpsie i") - - /* * For now, we're running at a weird frequency */ @@ -124,6 +120,15 @@ extern const uint32_t ao_radio_cal; /* The stm32l implements only 4 bits of the priority fields */ +#if AO_NONMASK_INTERRUPT +#define AO_STM_NVIC_NONMASK_PRIORITY 0x00 + +/* Set the basepri register to this value to mask all + * non-maskable priorities + */ +#define AO_STM_NVIC_BASEPRI_MASK 0x10 +#endif + #define AO_STM_NVIC_HIGH_PRIORITY 0x40 #define AO_STM_NVIC_MED_PRIORITY 0x80 #define AO_STM_NVIC_LOW_PRIORITY 0xC0 diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index a9d0fa34..88097406 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -345,17 +345,43 @@ extern struct ao_stm_usart ao_stm_usart3; typedef uint32_t ao_arch_irq_t; +static inline void +ao_arch_block_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else + asm("cpsid i"); +#endif +} + +static inline void +ao_arch_release_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (0x0)); +#else + asm("cpsie i"); +#endif +} + static inline uint32_t ao_arch_irqsave(void) { - uint32_t primask; - asm("mrs %0,primask" : "=&r" (primask)); + uint32_t val; +#ifdef AO_NONMASK_INTERRUPTS + asm("mrs %0,basepri" : "=r" (val)); +#else + asm("mrs %0,primask" : "=r" (val)); +#endif ao_arch_block_interrupts(); - return primask; + return val; } static inline void -ao_arch_irqrestore(uint32_t primask) { - asm("msr primask,%0" : : "r" (primask)); +ao_arch_irqrestore(uint32_t basepri) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (basepri)); +#else + asm("msr primask,%0" : : "r" (basepri)); +#endif } static inline void @@ -365,10 +391,17 @@ ao_arch_memory_barrier() { static inline void ao_arch_irq_check(void) { +#ifdef AO_NONMASK_INTERRUPTS + uint32_t basepri; + asm("mrs %0,basepri" : "=r" (basepri)); + if (basepri == 0) + ao_panic(AO_PANIC_IRQ); +#else uint32_t primask; - asm("mrs %0,primask" : "=&r" (primask)); + asm("mrs %0,primask" : "=r" (primask)); if ((primask & 1) == 0) ao_panic(AO_PANIC_IRQ); +#endif } #if HAS_TASK @@ -390,7 +423,7 @@ ao_arch_init_stack(struct ao_task *task, void *start) /* APSR */ ARM_PUSH32(sp, 0); - /* PRIMASK with interrupts enabled */ + /* BASEPRI with interrupts enabled */ ARM_PUSH32(sp, 0); task->sp = sp; @@ -404,8 +437,13 @@ static inline void ao_arch_save_regs(void) { asm("mrs r0,apsr"); asm("push {r0}"); +#ifdef AO_NONMASK_INTERRUPTS + /* Save BASEPRI */ + asm("mrs r0,basepri"); +#else /* Save PRIMASK */ asm("mrs r0,primask"); +#endif asm("push {r0}"); } @@ -419,9 +457,15 @@ static inline void ao_arch_restore_stack(void) { /* Switch stacks */ asm("mov sp, %0" : : "r" (ao_cur_task->sp) ); +#ifdef AO_NONMASK_INTERRUPTS + /* Restore BASEPRI */ + asm("pop {r0}"); + asm("msr basepri,r0"); +#else /* Restore PRIMASK */ asm("pop {r0}"); asm("msr primask,r0"); +#endif /* Restore APSR */ asm("pop {r0}"); @@ -463,7 +507,7 @@ static inline void ao_arch_start_scheduler(void) { asm("mrs %0,msp" : "=&r" (sp)); asm("msr psp,%0" : : "r" (sp)); - asm("mrs %0,control" : "=&r" (control)); + asm("mrs %0,control" : "=r" (control)); control |= (1 << 1); asm("msr control,%0" : : "r" (control)); asm("isb"); @@ -474,12 +518,24 @@ static inline void ao_arch_start_scheduler(void) { #endif -#define ao_arch_wait_interrupt() do { \ - asm("\twfi\n"); \ - ao_arch_release_interrupts(); \ - asm(".global ao_idle_loc\nao_idle_loc:"); \ - ao_arch_block_interrupts(); \ - } while (0) +static inline void +ao_arch_wait_interrupt(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm( + "dsb\n" /* Serialize data */ + "isb\n" /* Serialize instructions */ + "cpsid i\n" /* Block all interrupts */ + "msr basepri,%0\n" /* Allow all interrupts through basepri */ + "wfi\n" /* Wait for an interrupt */ + "cpsie i\n" /* Allow all interrupts */ + "msr basepri,%1\n" /* Block interrupts through basepri */ + : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else + asm("\twfi\n"); + ao_arch_release_interrupts(); + ao_arch_block_interrupts(); +#endif +} #define ao_arch_critical(b) do { \ uint32_t __mask = ao_arch_irqsave(); \ diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 2abaf10f..33e0617c 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -1109,7 +1109,7 @@ struct ao_usb_dbg { int line; char *msg; uint32_t value; - uint32_t primask; + uint32_t prival; #if TX_DBG uint16_t in_count; uint32_t in_epr; @@ -1125,19 +1125,23 @@ struct ao_usb_dbg { #endif }; -#define NUM_USB_DBG 128 +#define NUM_USB_DBG 16 -static struct ao_usb_dbg dbg[128]; +static struct ao_usb_dbg dbg[NUM_USB_DBG]; static int dbg_i; static void _dbg(int line, char *msg, uint32_t value) { - uint32_t primask; + uint32_t prival; dbg[dbg_i].line = line; dbg[dbg_i].msg = msg; dbg[dbg_i].value = value; - asm("mrs %0,primask" : "=&r" (primask)); - dbg[dbg_i].primask = primask; +#if AO_NONMASK_INTERRUPT + asm("mrs %0,basepri" : "=&r" (prival)); +#else + asm("mrs %0,primask" : "=&r" (prival)); +#endif + dbg[dbg_i].prival = prival; #if TX_DBG dbg[dbg_i].in_count = in_count; dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; -- cgit v1.2.3 From 72ea90d28817549c4343d2fea03a4c951f849cbe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:12:43 -0800 Subject: altos/stm: Allow DMA channels to be hijacked by other code This lets code which needs finer control over DMA to use the channel without interference, and leaves the DMA engine running so that it can. Signed-off-by: Keith Packard --- src/stm/ao_dma_stm.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'src/stm') diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 63d6688a..962b3acc 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -29,7 +29,6 @@ uint8_t ao_dma_done[NUM_DMA]; static struct ao_dma_config ao_dma_config[NUM_DMA]; static uint8_t ao_dma_allocated[NUM_DMA]; static uint8_t ao_dma_mutex[NUM_DMA]; -static uint8_t ao_dma_active; static void ao_dma_isr(uint8_t index) { @@ -49,12 +48,24 @@ ao_dma_isr(uint8_t index) { void stm_dma1_channel1_isr(void) { ao_dma_isr(STM_DMA_INDEX(1)); } void stm_dma1_channel2_isr(void) { ao_dma_isr(STM_DMA_INDEX(2)); } +#ifdef STM_DMA1_3_STOLEN +#define LEAVE_DMA_ON +#else void stm_dma1_channel3_isr(void) { ao_dma_isr(STM_DMA_INDEX(3)); } +#endif void stm_dma1_channel4_isr(void) { ao_dma_isr(STM_DMA_INDEX(4)); } +#ifdef STM_DMA1_5_STOLEN +#define LEAVE_DMA_ON +#else void stm_dma1_channel5_isr(void) { ao_dma_isr(STM_DMA_INDEX(5)); } +#endif void stm_dma1_channel6_isr(void) { ao_dma_isr(STM_DMA_INDEX(6)); } void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); } +#ifndef LEAVE_DMA_ON +static uint8_t ao_dma_active; +#endif + void ao_dma_set_transfer(uint8_t index, volatile void *peripheral, @@ -68,10 +79,12 @@ ao_dma_set_transfer(uint8_t index, ao_dma_mutex[index] = 0xff; } else ao_mutex_get(&ao_dma_mutex[index]); +#ifndef LEAVE_DMA_ON ao_arch_critical( if (ao_dma_active++ == 0) stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); ); +#endif stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE); stm_dma.channel[index].cndtr = count; stm_dma.channel[index].cpar = peripheral; @@ -96,10 +109,12 @@ void ao_dma_done_transfer(uint8_t index) { stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN); +#ifndef LEAVE_DMA_ON ao_arch_critical( if (--ao_dma_active == 0) stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN); ); +#endif if (ao_dma_allocated[index]) ao_dma_mutex[index] = 0; else @@ -120,10 +135,12 @@ ao_dma_dump_cmd(void) { int i; +#ifndef LEAVE_DMA_ON ao_arch_critical( if (ao_dma_active++ == 0) stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); ); +#endif printf ("isr %08x ifcr%08x\n", stm_dma.isr, stm_dma.ifcr); for (i = 0; i < NUM_DMA; i++) printf("%d: done %d allocated %d mutex %2d ccr %04x cndtr %04x cpar %08x cmar %08x isr %08x\n", @@ -136,10 +153,12 @@ ao_dma_dump_cmd(void) stm_dma.channel[i].cpar, stm_dma.channel[i].cmar, ao_dma_config[i].isr); +#ifndef LEAVE_DMA_ON ao_arch_critical( if (--ao_dma_active == 0) stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN); ); +#endif } static const struct ao_cmds ao_dma_cmds[] = { @@ -153,7 +172,24 @@ ao_dma_init(void) { int index; +#ifdef LEAVE_DMA_ON + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); +#endif for (index = 0; index < STM_NUM_DMA; index++) { +#if STM_DMA1_5_STOLEN + if (index == STM_DMA_INDEX(5)) { + ao_dma_allocated[index] = 1; + ao_dma_mutex[index] = 0xff; + continue; + } +#endif +#if STM_DMA1_3_STOLEN + if (index == STM_DMA_INDEX(3)) { + ao_dma_allocated[index] = 1; + ao_dma_mutex[index] = 0xff; + continue; + } +#endif stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index); stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, AO_STM_NVIC_MED_PRIORITY); -- cgit v1.2.3 From 80fd7f7bef5320ce86048d74dc4a72e1ec361120 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:14:10 -0800 Subject: altos/stm: Make i2c code handle PCLK1 of 24MHz Just adds the necessary defines to the code. Signed-off-by: Keith Packard --- src/stm/ao_i2c_stm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/stm') diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 29a8f173..59cad495 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -75,6 +75,9 @@ uint8_t ao_i2c_mutex[STM_NUM_I2C]; #if AO_PCLK1 == 16000000 # define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_16_MHZ #endif +#if AO_PCLK1 == 24000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_24_MHZ +#endif #if AO_PCLK1 == 32000000 # define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_32_MHZ #endif -- cgit v1.2.3 From a487d2fcba57141f6b083d5612c76bac5ad1ac7c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:15:45 -0800 Subject: altos/stm: Add nvic priority register fields. Add more TIM234 defines. Signed-off-by: Keith Packard --- src/stm/stm32l.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'src/stm') diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index be1e1d65..a20efa8a 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -518,7 +518,7 @@ extern struct stm_rcc stm_rcc; #define STM_RCC_CFGR_MCOPRE_DIV_4 2 #define STM_RCC_CFGR_MCOPRE_DIV_8 3 #define STM_RCC_CFGR_MCOPRE_DIV_16 4 -#define STM_RCC_CFGR_MCOPRE_DIV_MASK 7 +#define STM_RCC_CFGR_MCOPRE_MASK 7 #define STM_RCC_CFGR_MCOSEL (24) #define STM_RCC_CFGR_MCOSEL_DISABLE 0 @@ -897,7 +897,11 @@ struct stm_nvic { vuint32_t sc; /* 0xc10 0xe000ed10 System Control Register */ vuint32_t cc; /* 0xc14 0xe000ed14 Configuration Control Register */ - uint8_t _unusedc18[0xe00 - 0xc18]; + vuint32_t shpr7_4; /* 0xc18 0xe000ed18 System Hander Priority Registers */ + vuint32_t shpr11_8; /* 0xc1c */ + vuint32_t shpr15_12; /* 0xc20 */ + + uint8_t _unusedc18[0xe00 - 0xc24]; vuint32_t stir; /* 0xe00 */ }; @@ -1594,6 +1598,7 @@ extern struct stm_i2c stm_i2c1, stm_i2c2; #define STM_I2C_CR2_FREQ_4_MHZ 4 #define STM_I2C_CR2_FREQ_8_MHZ 8 #define STM_I2C_CR2_FREQ_16_MHZ 16 +#define STM_I2C_CR2_FREQ_24_MHZ 24 #define STM_I2C_CR2_FREQ_32_MHZ 32 #define STM_I2C_CR2_FREQ_MASK 0x3f @@ -1740,6 +1745,12 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4; #define STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK 7 #define STM_TIM234_SMCR_SMS_MASK 7 +#define STM_TIM234_DIER_CC4IE 4 +#define STM_TIM234_DIER_CC3IE 3 +#define STM_TIM234_DIER_CC2IE 2 +#define STM_TIM234_DIER_CC1IE 1 +#define STM_TIM234_DIER_UIE 0 + #define STM_TIM234_SR_CC4OF 12 #define STM_TIM234_SR_CC3OF 11 #define STM_TIM234_SR_CC2OF 10 @@ -1840,15 +1851,23 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4; #define STM_TIM234_CCER_CC4NP 15 #define STM_TIM234_CCER_CC4P 13 +#define STM_TIM234_CCER_CC4P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC4P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC4E 12 #define STM_TIM234_CCER_CC3NP 11 #define STM_TIM234_CCER_CC3P 9 +#define STM_TIM234_CCER_CC3P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC3P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC3E 8 #define STM_TIM234_CCER_CC2NP 7 #define STM_TIM234_CCER_CC2P 5 +#define STM_TIM234_CCER_CC2P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC2P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC2E 4 #define STM_TIM234_CCER_CC1NP 3 #define STM_TIM234_CCER_CC1P 1 +#define STM_TIM234_CCER_CC1P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC1P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC1E 0 struct stm_usb { -- cgit v1.2.3 From 0eadc2d50417408beebd50e4a0e7e12430ed67ef Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:16:27 -0800 Subject: altos/stm: Add draw and lisp to make search paths. Signed-off-by: Keith Packard --- src/stm/Makefile.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/stm') diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index 0ba86f5a..66ed4be8 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -1,4 +1,4 @@ -vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:.. +vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../lisp:.. vpath make-altitude ../util vpath make-kalman ../util vpath kalman.5c ../kalman @@ -26,7 +26,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) +AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I../draw -I../lisp -I.. $(PDCLIB_INCLUDES) STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) -- cgit v1.2.3 From 54c76d48924fecc2aeabbc352c553822a87f9d19 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:40:03 -0700 Subject: cortexelf-v1: Use new memory map to access all flash and ram. Add fat. Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 5 ++- src/cortexelf-v1/ao_cortexelf.c | 2 + src/stm/altos-512.ld | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/stm/altos-512.ld (limited to 'src/stm') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index c74b0cce..02ef817e 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -4,6 +4,7 @@ # include ../stm/Makefile.defs +LDFLAGS=-L../stm -Wl,-Taltos-512.ld INC = \ ao.h \ @@ -61,6 +62,8 @@ ALTOS_SRC = \ ao_ps2.c \ ao_console.c \ ao_sdcard.c \ + ao_bufio.c \ + ao_fat.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ $(STACK_GUARD) @@ -80,7 +83,7 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -$(PROG): Makefile $(OBJ) altos.ld +$(PROG): Makefile $(OBJ) altos-512.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) ../altitude-pa.h: make-altitude-pa diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 67062c85..0c6852d9 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -26,6 +26,7 @@ #include #include #include +#include struct ao_task ball_task; @@ -207,6 +208,7 @@ main(void) ao_exti_init(); ao_sdcard_init(); + ao_fat_init(); ao_ps2_init(); ao_vga_init(); diff --git a/src/stm/altos-512.ld b/src/stm/altos-512.ld new file mode 100644 index 00000000..78c41685 --- /dev/null +++ b/src/stm/altos-512.ld @@ -0,0 +1,98 @@ +/* + * 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. + * + * 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 = 508K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 81408 + stack (!w) : ORIGIN = 0x20013e00, LENGTH = 512 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .text ORIGIN(rom) : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + + . = 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 */ + *(.rodata*) /* Constants */ + + } > rom + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > 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 + + /* 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); + + -- cgit v1.2.3 From 3ce663875d69739cc2d43fcd88b22820cd9d6500 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:56:17 -0700 Subject: stm: Use common flash wait loop instead of inlining Signed-off-by: Keith Packard --- src/stm/ao_flash_stm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/stm') diff --git a/src/stm/ao_flash_stm.c b/src/stm/ao_flash_stm.c index c1648421..38618bbe 100644 --- a/src/stm/ao_flash_stm.c +++ b/src/stm/ao_flash_stm.c @@ -74,11 +74,10 @@ static void __attribute__ ((section(".ramtext"),noinline)) _ao_flash_erase_page(uint32_t *page) { stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG); - + *page = 0x00000000; - while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) - ; + ao_flash_wait_bsy(); } void @@ -101,9 +100,8 @@ _ao_flash_half_page(uint32_t *dst, uint32_t *src) stm_flash.pecr |= (1 << STM_FLASH_PECR_FPRG); stm_flash.pecr |= (1 << STM_FLASH_PECR_PROG); - - while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) - ; + + ao_flash_wait_bsy(); for (i = 0; i < 32; i++) { *dst++ = *src++; -- 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/stm') 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 0197157a295d848bac65cf7f4457dd5a99af24e3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 3 Apr 2017 11:37:21 -0700 Subject: stm: Add a few more GPIO functions to make dealing with the 1802 easier ao_gpio_set_mask and ao_gpio_get_all Signed-off-by: Keith Packard --- src/stm/ao_arch_funcs.h | 3 +++ src/stm/stm32l.h | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'src/stm') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index b294c379..15741505 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -202,8 +202,11 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s #define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits) +#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask) + #define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits); +#define ao_gpio_get_all(port) stm_gpio_get_all(port) #define ao_enable_output(port,bit,pin,v) do { \ ao_enable_port(port); \ diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index a20efa8a..4f966e3e 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -167,6 +167,12 @@ stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) { gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin); } +static inline void +stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) { + /* Use the bit set/reset register to do this atomically */ + gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask)); +} + static inline void stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) { gpio->bsrr = bits; -- cgit v1.2.3 From 301b724d2169f4ac46d921f518455c783e1dd894 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:04:25 -0700 Subject: stm: Add more mask-based GPIO controls Lets cortexelf do more things with groups of pins, rather than one pin at a time. Signed-off-by: Keith Packard --- src/stm/ao_arch_funcs.h | 79 ++++++++++++++++++++++++++++++++++++++----------- src/stm/stm32l.h | 53 +++++++++++++++++++++++++++++---- 2 files changed, 109 insertions(+), 23 deletions(-) (limited to 'src/stm') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 15741505..522059bc 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -214,6 +214,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_enable_output_mask(port,bits,mask) do { \ + ao_enable_port(port); \ + ao_gpio_set_mask(port, bits, mask); \ + ao_set_output_mask(port, mask); \ + } while (0) + #define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL #define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN @@ -229,35 +235,72 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s stm_pupdr_set(port, bit, STM_PUPDR_NONE); \ } while (0) +#define ao_gpio_set_mode_mask(port,mask,mode) do { \ + if (mode == AO_EXTI_MODE_PULL_UP) \ + stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_UP); \ + else if (mode == AO_EXTI_MODE_PULL_DOWN) \ + stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_DOWN); \ + else \ + stm_pupdr_set_mask(port, mask, STM_PUPDR_NONE); \ + } while (0) + +#define ao_set_input(port, bit) do { \ + stm_moder_set(port, bit, STM_MODER_INPUT); \ + } while (0) + +#define ao_set_output(port, bit, pin, v) do { \ + ao_gpio_set(port, bit, pin, v); \ + stm_moder_set(port, bit, STM_MODER_OUTPUT); \ + } while (0) + +#define ao_set_output_mask(port, mask) do { \ + stm_moder_set_mask(port, mask, STM_MODER_OUTPUT); \ + } while (0) + +#define ao_set_input_mask(port, mask) do { \ + stm_moder_set_mask(port, mask, STM_MODER_INPUT); \ + } while (0) + #define ao_enable_input(port,bit,mode) do { \ ao_enable_port(port); \ - stm_moder_set(port, bit, STM_MODER_INPUT); \ + ao_set_input(port, bit); \ ao_gpio_set_mode(port, bit, mode); \ } while (0) -#define ao_enable_cs(port,bit) do { \ +#define ao_enable_input_mask(port,mask,mode) do { \ + ao_enable_port(port); \ + ao_gpio_set_mode_mask(port, mask, mode); \ + ao_set_input_mask(port, mask); \ + } while (0) + +#define _ao_enable_cs(port, bit) do { \ stm_gpio_set((port), bit, 1); \ stm_moder_set((port), bit, STM_MODER_OUTPUT); \ } while (0) +#define ao_enable_cs(port,bit) do { \ + ao_enable_port(port); \ + _ao_enable_cs(port, bit); \ + } while (0) + #define ao_spi_init_cs(port, mask) do { \ ao_enable_port(port); \ - if ((mask) & 0x0001) ao_enable_cs(port, 0); \ - if ((mask) & 0x0002) ao_enable_cs(port, 1); \ - if ((mask) & 0x0004) ao_enable_cs(port, 2); \ - if ((mask) & 0x0008) ao_enable_cs(port, 3); \ - if ((mask) & 0x0010) ao_enable_cs(port, 4); \ - if ((mask) & 0x0020) ao_enable_cs(port, 5); \ - if ((mask) & 0x0040) ao_enable_cs(port, 6); \ - if ((mask) & 0x0080) ao_enable_cs(port, 7); \ - if ((mask) & 0x0100) ao_enable_cs(port, 8); \ - if ((mask) & 0x0200) ao_enable_cs(port, 9); \ - if ((mask) & 0x0400) ao_enable_cs(port, 10);\ - if ((mask) & 0x0800) ao_enable_cs(port, 11);\ - if ((mask) & 0x1000) ao_enable_cs(port, 12);\ - if ((mask) & 0x2000) ao_enable_cs(port, 13);\ - if ((mask) & 0x4000) ao_enable_cs(port, 14);\ - if ((mask) & 0x8000) ao_enable_cs(port, 15);\ + if ((mask) & 0x0001) _ao_enable_cs(port, 0); \ + if ((mask) & 0x0002) _ao_enable_cs(port, 1); \ + if ((mask) & 0x0004) _ao_enable_cs(port, 2); \ + if ((mask) & 0x0008) _ao_enable_cs(port, 3); \ + if ((mask) & 0x0010) _ao_enable_cs(port, 4); \ + if ((mask) & 0x0020) _ao_enable_cs(port, 5); \ + if ((mask) & 0x0040) _ao_enable_cs(port, 6); \ + if ((mask) & 0x0080) _ao_enable_cs(port, 7); \ + if ((mask) & 0x0100) _ao_enable_cs(port, 8); \ + if ((mask) & 0x0200) _ao_enable_cs(port, 9); \ + if ((mask) & 0x0400) _ao_enable_cs(port, 10);\ + if ((mask) & 0x0800) _ao_enable_cs(port, 11);\ + if ((mask) & 0x1000) _ao_enable_cs(port, 12);\ + if ((mask) & 0x2000) _ao_enable_cs(port, 13);\ + if ((mask) & 0x4000) _ao_enable_cs(port, 14);\ + if ((mask) & 0x8000) _ao_enable_cs(port, 15);\ } while (0) /* ao_dma_stm.c diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 4f966e3e..201f4f36 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -52,7 +52,32 @@ stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) { ~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) | value << STM_MODER_SHIFT(pin)); } - + +static inline uint32_t +stm_spread_mask(uint16_t mask) { + uint32_t m = mask; + + /* 0000000000000000mmmmmmmmmmmmmmmm */ + m = (m & 0xff) | ((m & 0xff00) << 8); + /* 00000000mmmmmmmm00000000mmmmmmmm */ + m = (m & 0x000f000f) | ((m & 0x00f000f0) << 4); + /* 0000mmmm0000mmmm0000mmmm0000mmmm */ + m = (m & 0x03030303) | ((m & 0x0c0c0c0c) << 2); + /* 00mm00mm00mm00mm00mm00mm00mm00mm */ + m = (m & 0x11111111) | ((m & 0x22222222) << 2); + /* 0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m */ + return m; +} + +static inline void +stm_moder_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { + uint32_t bits32 = stm_spread_mask(mask); + uint32_t mask32 = 3 * bits32; + uint32_t value32 = (value & 3) * bits32; + + gpio->moder = ((gpio->moder & ~mask32) | value32); +} + static inline uint32_t stm_moder_get(struct stm_gpio *gpio, int pin) { return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK; @@ -69,7 +94,7 @@ stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) { ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) | value << STM_OTYPER_SHIFT(pin)); } - + static inline uint32_t stm_otyper_get(struct stm_gpio *gpio, int pin) { return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK; @@ -83,12 +108,21 @@ stm_otyper_get(struct stm_gpio *gpio, int pin) { #define STM_OSPEEDR_40MHz 3 static inline void -stm_ospeedr_set(struct stm_gpio *gpio, int pin, vuint32_t value) { +stm_ospeedr_set(struct stm_gpio *gpio, int pin, uint32_t value) { gpio->ospeedr = ((gpio->ospeedr & ~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) | value << STM_OSPEEDR_SHIFT(pin)); } - + +static inline void +stm_ospeedr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { + uint32_t bits32 = stm_spread_mask(mask); + uint32_t mask32 = 3 * bits32; + uint32_t value32 = (value & 3) * bits32; + + gpio->ospeedr = ((gpio->ospeedr & ~mask32) | value32); +} + static inline uint32_t stm_ospeedr_get(struct stm_gpio *gpio, int pin) { return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK; @@ -107,7 +141,16 @@ stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) { ~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) | value << STM_PUPDR_SHIFT(pin)); } - + +static inline void +stm_pupdr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { + uint32_t bits32 = stm_spread_mask(mask); + uint32_t mask32 = 3 * bits32; + uint32_t value32 = (value & 3) * bits32; + + gpio->pupdr = (gpio->pupdr & ~mask32) | value32; +} + static inline uint32_t stm_pupdr_get(struct stm_gpio *gpio, int pin) { return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK; -- cgit v1.2.3