From bcc65597d3d20f1d58df784100af766cee5f0f20 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 18 Apr 2013 15:54:13 -0500 Subject: [PATCH] lpc: Initial lpcxpresso bits This gets the LPC11U14 clock set to the PLL and blinks the LED. Signed-off-by: Keith Packard --- src/lpc/Makefile.defs | 42 +++ src/lpc/altos.ld | 72 ++++ src/lpc/ao_arch.h | 122 +++++++ src/lpc/ao_arch_funcs.h | 147 ++++++++ src/lpc/ao_interrupt.c | 155 +++++++++ src/lpc/ao_led_lpc.c | 65 ++++ src/lpc/ao_romconfig.c | 25 ++ src/lpc/ao_serial_lpc.c | 154 +++++++++ src/lpc/ao_timer_lpc.c | 165 +++++++++ src/lpc/baud_rate | 131 +++++++ src/lpc/figure-checksum | 39 +++ src/lpc/lpc.h | 723 +++++++++++++++++++++++++++++++++++++++ src/lpc/registers.ld | 9 + src/lpcxpresso/Makefile | 64 ++++ src/lpcxpresso/ao_pins.h | 47 +++ 15 files changed, 1960 insertions(+) create mode 100644 src/lpc/Makefile.defs create mode 100644 src/lpc/altos.ld create mode 100644 src/lpc/ao_arch.h create mode 100644 src/lpc/ao_arch_funcs.h create mode 100644 src/lpc/ao_interrupt.c create mode 100644 src/lpc/ao_led_lpc.c create mode 100644 src/lpc/ao_romconfig.c create mode 100644 src/lpc/ao_serial_lpc.c create mode 100644 src/lpc/ao_timer_lpc.c create mode 100644 src/lpc/baud_rate create mode 100755 src/lpc/figure-checksum create mode 100644 src/lpc/lpc.h create mode 100644 src/lpc/registers.ld create mode 100644 src/lpcxpresso/Makefile create mode 100644 src/lpcxpresso/ao_pins.h diff --git a/src/lpc/Makefile.defs b/src/lpc/Makefile.defs new file mode 100644 index 00000000..c18284d2 --- /dev/null +++ b/src/lpc/Makefile.defs @@ -0,0 +1,42 @@ +vpath % ../lpc:../product:../drivers:../core:../util:../kalman:../aes:.. +vpath make-altitude ../util +vpath make-kalman ../util +vpath kalman.5c ../kalman +vpath kalman_filter.5c ../kalman +vpath load_csv.5c ../kalman +vpath matrix.5c ../kalman +vpath ao-make-product.5c ../util + +CC=arm-none-eabi-gcc +SAT=/opt/cortex +SAT_CLIB=$(SAT)/lib/pdclib-cortex-m0.a +SAT_CFLAGS=-I$(SAT)/include + +ifndef VERSION +include ../Version +endif + +AO_CFLAGS=-I. -I../lpc -I../core -I../drivers -I.. +LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS) + +LDFLAGS=-L../stm -Wl,-Taltos.ld + +NICKLE=nickle + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf " $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +.c.o: + $(call quiet,CC) -c $(CFLAGS) -o $@ $< + +ao_serial_lpc.h: ../lpc/baud_rate ao_pins.h + nickle ../lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@ + +ao_serial_lpc.o: ao_serial_lpc.h + +.DEFAULT_GOAL=all diff --git a/src/lpc/altos.ld b/src/lpc/altos.ld new file mode 100644 index 00000000..7a99e66b --- /dev/null +++ b/src/lpc/altos.ld @@ -0,0 +1,72 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x00000000, LENGTH = 32K + ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K +} + +INCLUDE registers.ld + +EXTERN (lpc_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .text ORIGIN(rom) : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + + . = ORIGIN(rom) + 0x100; + + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + + *(.text*) /* Executable code */ + *(.rodata*) /* Constants */ + + } > rom + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __text_end__ = .; + } > rom + + /* Data -- relocated to RAM, but written to ROM + */ + .data ORIGIN(ram) : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) { + __data_start__ = .; + *(.data) /* initialized data */ + __data_end__ = .; + __bss_start__ = .; + } >ram + + .bss : { + *(.bss) + *(COMMON) + __bss_end__ = .; + } >ram + + PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram)); + PROVIDE(end = .); +} + +ENTRY(start); + + diff --git a/src/lpc/ao_arch.h b/src/lpc/ao_arch.h new file mode 100644 index 00000000..61182160 --- /dev/null +++ b/src/lpc/ao_arch.h @@ -0,0 +1,122 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ARCH_H_ +#define _AO_ARCH_H_ + +#include + +/* + * LPC11U14 definitions and code fragments for AltOS + */ + +#define AO_STACK_SIZE 512 + +#define AO_LED_TYPE uint16_t + +#ifndef AO_TICK_TYPE +#define AO_TICK_TYPE uint16_t +#define AO_TICK_SIGNED int16_t +#endif + +/* Various definitions to make GCC look more like SDCC */ + +#define ao_arch_naked_declare __attribute__((naked)) +#define ao_arch_naked_define +#define __pdata +#define __data +#define __xdata +#define __code const +#define __reentrant +#define __interrupt(n) +#define __at(n) + +#define ao_arch_reboot() + +#define ao_arch_nop() asm("nop") + +#define ao_arch_interrupt(n) /* nothing */ + +#undef putchar +#undef getchar +#define putchar(c) ao_putchar(c) +#define getchar ao_getchar + +extern void putchar(char c); +extern char getchar(void); + +/* + * ao_romconfig.c + */ + +#define AO_ROMCONFIG_VERSION 2 + +#define AO_ROMCONFIG_SYMBOL(a) __attribute__((section(".romconfig"))) const + +extern const uint16_t ao_romconfig_version; +extern const uint16_t ao_romconfig_check; +extern const uint16_t ao_serial_number; +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 + */ + +#if AO_HSE +#define AO_PLLSRC AO_HSE +#else +#define AO_PLLSRC STM_HSI_FREQ +#endif + +#define AO_PLLVCO (AO_PLLSRC * AO_PLLMUL) +#define AO_SYSCLK (AO_PLLVCO / AO_PLLDIV) +#define AO_HCLK (AO_SYSCLK / AO_AHB_PRESCALER) +#define AO_PCLK1 (AO_HCLK / AO_APB1_PRESCALER) +#define AO_PCLK2 (AO_HCLK / AO_APB2_PRESCALER) + +#if AO_APB1_PRESCALER == 1 +#define AO_TIM23467_CLK AO_PCLK1 +#else +#define AO_TIM23467_CLK (2 * AO_PCLK1) +#endif + +#if AO_APB2_PRESCALER == 1 +#define AO_TIM91011_CLK AO_PCLK2 +#else +#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 + +void +ao_adc_init(void); + + + +void +ao_serial_init(void); + +#endif /* _AO_ARCH_H_ */ diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h new file mode 100644 index 00000000..39222b9d --- /dev/null +++ b/src/lpc/ao_arch_funcs.h @@ -0,0 +1,147 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ARCH_FUNCS_H_ +#define _AO_ARCH_FUNCS_H_ + +#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<stack + AO_STACK_SIZE); + uint32_t a = (uint32_t) start; + int i; + + /* Return address (goes into LR) */ + ARM_PUSH32(sp, a); + + /* Clear register values r0-r7 */ + i = 8; + while (i--) + ARM_PUSH32(sp, 0); + + /* APSR */ + ARM_PUSH32(sp, 0); + + /* PRIMASK with interrupts enabled */ + ARM_PUSH32(sp, 0); + + task->sp = sp; +} + +static inline void ao_arch_save_regs(void) { + /* Save general registers */ + asm("push {r0-r7,lr}\n"); + + /* Save APSR */ + asm("mrs r0,apsr"); + asm("push {r0}"); + + /* Save PRIMASK */ + asm("mrs r0,primask"); + asm("push {r0}"); +} + +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) ); + + /* Restore PRIMASK */ + asm("pop {r0}"); + asm("msr primask,r0"); + + /* Restore APSR */ + asm("pop {r0}"); + asm("msr apsr,r0"); + + /* Restore general registers and return */ + asm("pop {r0-r7,pc}\n"); +} + +#define ao_arch_isr_stack() + +#define ao_arch_wait_interrupt() do { \ + asm(".global ao_idle_loc\n\twfi\nao_idle_loc:"); \ + ao_arch_release_interrupts(); \ + ao_arch_block_interrupts(); \ + } while (0) + +#define ao_arch_critical(b) do { \ + ao_arch_block_interrupts(); \ + do { b } while (0); \ + ao_arch_release_interrupts(); \ + } while (0) + +#endif /* _AO_ARCH_FUNCS_H_ */ diff --git a/src/lpc/ao_interrupt.c b/src/lpc/ao_interrupt.c new file mode 100644 index 00000000..b5e67007 --- /dev/null +++ b/src/lpc/ao_interrupt.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +extern void main(void); +extern char __stack__; +extern char __text_start__, __text_end__; +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; + +/* Interrupt functions */ + +void lpc_halt_isr(void) +{ + ao_panic(AO_PANIC_CRASH); +} + +void lpc_ignore_isr(void) +{ +} + +int x; + +void start(void) { + x = 0; + memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__); + memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__); + main(); +} + +#define STRINGIFY(x) #x + +#define isr(name) \ + void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \ + _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_ignore_isr)) + +#define isr_halt(name) \ + void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \ + _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_halt_isr)) + +isr(nmi) +isr_halt(hardfault) +isr_halt(memmanage) +isr_halt(busfault) +isr_halt(usagefault) +isr(svc) +isr(debugmon) +isr(pendsv) +isr(systick) + +isr(pin_int0) /* IRQ0 */ +isr(pin_int1) +isr(pin_int2) +isr(pin_int3) +isr(pin_int4) /* IRQ4 */ +isr(pin_int5) +isr(pin_int6) +isr(pin_int7) + +isr(gint0) /* IRQ8 */ +isr(gint1) +isr(ssp1) +isr(i2c) + +isr(ct16b0) /* IRQ16 */ +isr(ct16b1) +isr(ct32b0) +isr(ct32b1) +isr(ssp0) /* IRQ20 */ +isr(usart) +isr(usb_irq) +isr(usb_fiq) + +isr(adc) /* IRQ24 */ +isr(wwdt) +isr(bod) +isr(flash) + +isr(usb_wakeup) + +#define i(addr,name) [(addr)/4] = lpc_ ## name ## _isr +#define c(addr,value) [(addr)/4] = (value) + +__attribute__ ((section(".interrupt"))) +const void *lpc_interrupt_vector[] = { + [0] = &__stack__, + [1] = start, + i(0x08, nmi), + i(0x0c, hardfault), + c(0x10, 0), + c(0x14, 0), + c(0x18, 0), + c(0x1c, 0), + c(0x20, 0), + c(0x24, 0), + c(0x28, 0), + i(0x2c, svc), + i(0x30, hardfault), + i(0x34, hardfault), + i(0x38, pendsv), + i(0x3c, systick), + + i(0x40, pin_int0), /* IRQ0 */ + i(0x44, pin_int1), + i(0x48, pin_int2), + i(0x4c, pin_int3), + i(0x50, pin_int4), /* IRQ4 */ + i(0x54, pin_int5), + i(0x58, pin_int6), + i(0x5c, pin_int7), + + i(0x60, gint0), /* IRQ8 */ + i(0x64, gint1), + i(0x68, hardfault), + i(0x6c, hardfault), + i(0x70, hardfault), /* IRQ12 */ + i(0x74, hardfault), + i(0x78, ssp1), + i(0x7c, i2c), + + i(0x80, ct16b0), /* IRQ16 */ + i(0x84, ct16b1), + i(0x88, ct32b0), + i(0x8c, ct32b1), + i(0x90, ssp0), /* IRQ20 */ + i(0x94, usart), + i(0x98, usb_irq), + i(0x9c, usb_fiq), + + i(0xa0, adc), /* IRQ24 */ + i(0xa4, wwdt), + i(0xa8, bod), + i(0xac, flash), + + i(0xb0, hardfault), /* IRQ28 */ + i(0xb4, hardfault), + i(0xb8, usb_wakeup), + i(0xbc, hardfault), +}; diff --git a/src/lpc/ao_led_lpc.c b/src/lpc/ao_led_lpc.c new file mode 100644 index 00000000..098dad6b --- /dev/null +++ b/src/lpc/ao_led_lpc.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +__pdata uint16_t ao_led_enable; + +void +ao_led_on(uint16_t colors) +{ + lpc_gpio.pin[LED_PORT] = 0xffffffff; +} + +void +ao_led_off(uint16_t colors) +{ + lpc_gpio.pin[LED_PORT] = 0; +} + +void +ao_led_set(uint16_t colors) +{ + uint16_t on = colors & ao_led_enable; + uint16_t off = ~colors & ao_led_enable; + + ao_led_off(off); + ao_led_on(on); +} + +void +ao_led_toggle(uint16_t colors) +{ +} + +void +ao_led_for(uint16_t colors, uint16_t ticks) __reentrant +{ + ao_led_on(colors); + ao_delay(ticks); + ao_led_off(colors); +} + +void +ao_led_init(uint16_t enable) +{ + int bit; + + ao_led_enable = enable; + lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO); + lpc_gpio.dir[LED_PORT] |= enable; +} diff --git a/src/lpc/ao_romconfig.c b/src/lpc/ao_romconfig.c new file mode 100644 index 00000000..cbb922ec --- /dev/null +++ b/src/lpc/ao_romconfig.c @@ -0,0 +1,25 @@ +/* + * Copyright © 2011 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION; +AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION; +AO_ROMCONFIG_SYMBOL (0) uint16_t ao_serial_number = 0; +#ifdef AO_RADIO_CAL_DEFAULT +AO_ROMCONFIG_SYMBOL (0) uint32_t ao_radio_cal = AO_RADIO_CAL_DEFAULT; +#endif diff --git a/src/lpc/ao_serial_lpc.c b/src/lpc/ao_serial_lpc.c new file mode 100644 index 00000000..e47f743e --- /dev/null +++ b/src/lpc/ao_serial_lpc.c @@ -0,0 +1,154 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +struct ao_fifo ao_usart_rx_fifo; +struct ao_fifo ao_usart_tx_fifo; +uint8_t ao_usart_tx_started; + +void +ao_debug_out(char c) +{ + if (c == '\n') + ao_debug_out('\r'); +#if 0 + while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE))); + stm_usart1.dr = c; +#endif +} + +static void +_ao_serial_tx_start(void) +{ + if (!ao_fifo_empty(ao_usart_tx_fifo) & !ao_usart_tx_started) + { + ao_usart_tx_started = 1; +#if 0 + ao_fifo_remove(ao_usart_tx_fifo, usart->reg->dr); +#endif + } +} + +void +lpc_usart_isr(void) +{ +#if 0 + uint32_t sr; + + sr = usart->reg->sr; + usart->reg->sr = 0; + + if (sr & (1 << STM_USART_SR_RXNE)) { + char c = usart->reg->dr; + if (!ao_fifo_full(ao_usart_rx_fifo)) + ao_fifo_insert(ao_usart_rx_fifo, c); + ao_wakeup(ao_usart_rx_fifo); + if (stdin) + ao_wakeup(&ao_stdin_ready); + } + if (sr & (1 << STM_USART_SR_TC)) { + ao_usart_tx_started = 0; + _ao_usart_tx_start(usart); + ao_wakeup(ao_usart_tx_fifo); + } +#endif +} + +int +_ao_serial_pollchar(void) +{ + int c; + + if (ao_fifo_empty(ao_usart_rx_fifo)) + c = AO_READ_AGAIN; + else { + uint8_t u; + ao_fifo_remove(ao_usart_rx_fifo,u); + c = u; + } + return c; +} + +char +ao_serial_getchar(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_serial_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_usart_rx_fifo); + ao_arch_release_interrupts(); + return (char) c; +} + +void +ao_serial_putchar(char c) +{ + ao_arch_block_interrupts(); + while (ao_fifo_full(ao_usart_tx_fifo)) + ao_sleep(&ao_usart_tx_fifo); + ao_fifo_insert(ao_usart_tx_fifo, c); + _ao_serial_tx_start(); + ao_arch_release_interrupts(); +} + +void +ao_serial_drain(void) +{ + ao_arch_block_interrupts(); + while (!ao_fifo_empty(ao_usart_tx_fifo)) + ao_sleep(&ao_usart_tx_fifo); + ao_arch_release_interrupts(); +} + +void +ao_serial_set_speed(uint8_t speed) +{ + if (speed > AO_SERIAL_SPEED_115200) + return; +#if 0 + usart->reg->brr = ao_usart_speeds[speed].brr; +#endif +} + +#include "ao_serial_lpc.h" + +void +ao_serial_init(void) +{ + /* Turn on the USART clock */ + lpc_scb.uartclkdiv = 1; + +#if SERIAL_0_18_19 + lpc_ioconf.pio0_18 = ((LPC_IOCONF_FUNC_PIO0_18_RXD << LPC_IOCONF_FUNC) | + (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | + (0 << LPC_IOCONF_HYS) | + (0 << LPC_IOCONF_INV) | + (0 << LPC_IOCONF_OD)); + lpc_ioconf.pio0_19 = ((LPC_IOCONF_FUNC_PIO0_19_TXD << LPC_IOCONF_FUNC) | + (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | + (0 << LPC_IOCONF_HYS) | + (0 << LPC_IOCONF_INV) | + (0 << LPC_IOCONF_OD)); +#endif + + /* Turn on the USART */ + lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_USART); +} + + diff --git a/src/lpc/ao_timer_lpc.c b/src/lpc/ao_timer_lpc.c new file mode 100644 index 00000000..aa796acf --- /dev/null +++ b/src/lpc/ao_timer_lpc.c @@ -0,0 +1,165 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +volatile __data AO_TICK_TYPE ao_tick_count; + +uint16_t +ao_time(void) +{ + return ao_tick_count; +} + +#if AO_DATA_ALL +volatile __data uint8_t ao_data_interval = 1; +volatile __data uint8_t ao_data_count; +#endif + +void lpc_systick_isr(void) +{ + if (lpc_systick.csr & (1 << LPC_SYSTICK_CSR_COUNTFLAG)) { + ++ao_tick_count; +#if HAS_TASK_QUEUE + if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0) + ao_task_check_alarm((uint16_t) ao_tick_count); +#endif +#if AO_DATA_ALL + if (++ao_data_count == ao_data_interval) { + ao_data_count = 0; + ao_adc_poll(); +#if (AO_DATA_ALL & ~(AO_DATA_ADC)) + ao_wakeup((void *) &ao_data_count); +#endif + } +#endif + } +} + +#if HAS_ADC +void +ao_timer_set_adc_interval(uint8_t interval) +{ + ao_arch_critical( + ao_data_interval = interval; + ao_data_count = 0; + ); +} +#endif + +#define SYSTICK_RELOAD ((AO_LPC_CLKOUT / 2) / 100 - 1) + +/* Initialize our 100Hz clock */ +void +ao_timer_init(void) +{ + lpc_systick.rvr = SYSTICK_RELOAD; + lpc_systick.cvr = 0; + lpc_systick.csr = ((1 << LPC_SYSTICK_CSR_ENABLE) | + (1 << LPC_SYSTICK_CSR_TICKINT) | + (LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2 << LPC_SYSTICK_CSR_CLKSOURCE)); +} + +#define AO_LPC_M ((AO_LPC_CLKOUT / AO_LPC_CLKIN) - 1) + +#define AO_LPC_FCCO_MIN 156000000 + +void +ao_clock_init(void) +{ + uint8_t p; + uint32_t i; + + /* Turn off all perhipherals except for GPIO configuration */ + lpc_scb.sysahbclkctrl = ((1 << LPC_SCB_SYSAHBCLKCTRL_SYS) | + (1 << LPC_SCB_SYSAHBCLKCTRL_ROM) | + (1 << LPC_SCB_SYSAHBCLKCTRL_RAM0) | + (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY) | + (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO) | + (1 << LPC_SCB_SYSAHBCLKCTRL_IOCON)); + + /* Turn the IRC clock back on */ + lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_IRC_PD); + + /* Switch to the IRC clock */ + lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_IRC << LPC_SCB_MAINCLKSEL_SEL; + lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA); + lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA); + + /* Find a PLL post divider ratio that gets the FCCO in range */ + for (p = 0; p < 4; p++) + if (AO_LPC_CLKOUT << (1 + p) >= AO_LPC_FCCO_MIN) + break; + + if (p == 4) + ao_panic(AO_PANIC_CRASH); + + /* Power down the PLL before touching the registers */ + lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSPLL_PD); + + /* Set PLL divider values */ + lpc_scb.syspllctrl = ((AO_LPC_M << LPC_SCB_SYSPLLCTRL_MSEL) | + (p << LPC_SCB_SYSPLLCTRL_PSEL)); + + + /* Turn off the external crystal clock */ + lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSOSC_PD); + + /* Configure the crystal clock */ + lpc_scb.sysoscctrl = ((0 << LPC_SCB_SYSOSCCTRL_BYPASS) | /* using a crystal */ + ((AO_LPC_CLKIN > 15000000) << LPC_SCB_SYSOSCCTRL_FREQRANGE));/* set range */ + + /* Turn on the external crystal clock */ + lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSOSC_PD); + + /* Select crystal as PLL input */ + + lpc_scb.syspllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL); + lpc_scb.syspllclkuen = 0; + lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA); + + /* Turn on the PLL */ + lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSPLL_PD); + + /* Wait for it to lock */ + + for (i = 0; i < 20000; i++) + if (lpc_scb.syspllstat & (1 << LPC_SCB_SYSPLLSTAT_LOCK)) + break; + if (i == 20000) + ao_panic(AO_PANIC_CRASH); + + /* Switch to the PLL */ + lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT << LPC_SCB_MAINCLKSEL_SEL; + lpc_scb.mainclkuen = 0 << LPC_SCB_MAINCLKUEN_ENA; + lpc_scb.mainclkuen = 1 << LPC_SCB_MAINCLKUEN_ENA; + + /* Set system clock divider */ + lpc_scb.sysahbclkdiv = AO_LPC_CLKOUT / AO_LPC_SYSCLK; + + /* Set USB clock source */ + lpc_scb.usbclksel = (LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK << LPC_SCB_USBCLKSEL_SEL); + lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA); + lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA); + + /* Shut down perhipheral clocks (enabled as needed) */ + lpc_scb.ssp0clkdiv = 0; + lpc_scb.uartclkdiv = 0; + lpc_scb.ssp1clkdiv = 0; + lpc_scb.usbclkdiv = 0; + lpc_scb.clkoutdiv = 0; +} diff --git a/src/lpc/baud_rate b/src/lpc/baud_rate new file mode 100644 index 00000000..2bfbf309 --- /dev/null +++ b/src/lpc/baud_rate @@ -0,0 +1,131 @@ +#!/usr/bin/env nickle + +/* + * Given a main clock frequency, + * compute USART clock freq and a table + * of USART config parameters for our target baud rates + */ + +real main_clock = 0; +real usart_clock = 0; + +real[] baud_rates = { 4800, 9600, 19200, 57600, 115200 }; + +void +compute_baud_rate(real rate) { + int divaddval; + int mulval; + + real dl_est = usart_clock / (16 * rate); + + if (dl_est == floor(dl_est)) { + divaddval = 0; + mulval = 1; + } else { + if (false) { + + /* This is how the docs suggest doing it; this + * generates a rate which is reasonably close + */ + + real fr_est = 1.5; + + /* Compute fractional estimate */ + do { + dl_est = floor(usart_clock / (16 * rate * fr_est) + 0.5); + fr_est = usart_clock / (16 * rate * dl_est); + } while (fr_est <= 1.1 || 1.9 <= fr_est); + + /* Given fractional estimate, compute divaddval/mulvals that work best */ + + real best_dist = 1000; + for (int tmp_divaddval = 1; tmp_divaddval < 15; tmp_divaddval++) { + for (int tmp_mulval = 1; tmp_mulval < 16; tmp_mulval++) { + real fr = 1 + tmp_divaddval / tmp_mulval; + real dist = abs(fr - fr_est); + if (dist < best_dist) { + divaddval = tmp_divaddval; + mulval = tmp_mulval; + best_dist = dist; + } + } + } + } else { + + /* This exhaustively searches for the best match */ + + real my_best_dist = 1e20; + int my_best_dl; + int my_best_divaddval; + int my_best_mulval; + for (int my_dl = 1; my_dl < 1024; my_dl++) { + for (int my_mulval = 1; my_mulval < 16; my_mulval++) { + for (int my_divaddval = 0; my_divaddval < my_mulval; my_divaddval++) { + real my_rate = usart_clock / ((16 * my_dl) * (1 + my_divaddval/my_mulval)); + + real my_dist = abs(rate - my_rate); + + if (my_dist == 0 && my_divaddval == 0) { + my_dist = -1; + } + + if (my_dist < my_best_dist) { + my_best_dl = my_dl; + my_best_divaddval = my_divaddval; + my_best_mulval = my_mulval; + my_best_dist = my_dist; + } + } + } + } + + dl_est = my_best_dl; + divaddval = my_best_divaddval; + mulval = my_best_mulval; + } + } + + int dl = floor (dl_est); + + real actual = usart_clock / ((16 * dl) * (1 + divaddval/mulval)); + + printf("\t[AO_SERIAL_SPEED_%d] = { /* actual = %8.2f */\n", floor(rate), actual); + printf("\t\t.dl = %d,\n", dl); + printf("\t\t.divaddval = %d,\n", divaddval); + printf("\t\t.mulval = %d\n", mulval); + printf("\t},\n"); +} + +void +main() { + if (dim(argv) < 2) { + printf ("usage: %s \n", argv[0]); + exit(1); + } + main_clock = string_to_real(argv[1]); + + for (int div = 0; div < 4; div++) { + if (main_clock / (1 << div) <= 12000000) { + usart_clock = main_clock / (1 << div); + break; + } + } + + if (usart_clock == 0) { + printf ("can't get usart clock in range\n"); + exit(1); + } + + printf ("#define AO_LPC_USARTCLK %d\n\n", floor(usart_clock)); + printf("static const struct {\n"); + printf("\tuint16_t dl;\n"); + printf("\tuint8_t divaddval;\n"); + printf("\tuint8_t mulval;\n"); + printf("} ao_usart_speeds[] = {\n"); + for (int i = 0; i < dim(baud_rates); i++) { + compute_baud_rate(baud_rates[i]); + } + printf ("};\n"); +} + +main(); diff --git a/src/lpc/figure-checksum b/src/lpc/figure-checksum new file mode 100755 index 00000000..0b1de578 --- /dev/null +++ b/src/lpc/figure-checksum @@ -0,0 +1,39 @@ +#!/usr/bin/env nickle + +autoimport Process; + +int byteflip(int x) { + return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | ((x << 24) & 0xff000000); +} + +void main () { + file input = popen(popen_direction.read, true, "objdump", + "objdump", "-j", ".text", + "--start-address=0", + "--stop-address=0x20", + "-s", argv[1]); + int sum = 0; + + void add_in(int addr, int value) { + if (addr < 0x1c) { + sum += value; + } else if (addr == 0x1c) { + printf ("-DCKSUM=0x%08x\n", -sum & 0xffffffff); + exit(0); + } + } + while (!File::end(input)) { + string line = File::fgets(input); + string[] words = String::wordsplit(line, " "); + + if (dim(words) < 5) + continue; + if (words[0] == "0000" || words[0] == "0010") { + int addr = string_to_integer(words[0], 16); + for (int i = 0; i < 4; i++) + add_in(addr + i * 4, byteflip(string_to_integer(words[i+1], 16))); + } + } +} + +main(); diff --git a/src/lpc/lpc.h b/src/lpc/lpc.h new file mode 100644 index 00000000..87af494a --- /dev/null +++ b/src/lpc/lpc.h @@ -0,0 +1,723 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _LPC_H_ +#define _LPC_H_ + +#include + +typedef volatile uint32_t vuint32_t; +typedef volatile uint16_t vuint16_t; +typedef volatile uint8_t vuint8_t; +typedef volatile void * vvoid_t; + +struct lpc_ioconf { + vuint32_t pio0_0; + vuint32_t pio0_1; + vuint32_t pio0_2; + vuint32_t pio0_3; + + vuint32_t pio0_4; + vuint32_t pio0_5; + vuint32_t pio0_6; + vuint32_t pio0_7; + + vuint32_t pio0_8; + vuint32_t pio0_9; + vuint32_t pio0_10; + vuint32_t pio0_11; + + vuint32_t pio0_12; + vuint32_t pio0_13; + vuint32_t pio0_14; + vuint32_t pio0_15; + + vuint32_t pio0_16; + vuint32_t pio0_17; + vuint32_t pio0_18; + vuint32_t pio0_19; + + vuint32_t pio0_20; + vuint32_t pio0_21; + vuint32_t pio0_22; + vuint32_t pio0_23; + + vuint32_t pio1_0; /* 0x60 */ + vuint32_t pio1_1; + vuint32_t pio1_2; + vuint32_t pio1_3; + + vuint32_t pio1_4; + vuint32_t pio1_5; + vuint32_t pio1_6; + vuint32_t pio1_7; + + vuint32_t pio1_8; /* 0x80 */ + vuint32_t pio1_9; + vuint32_t pio1_10; + vuint32_t pio1_11; + + vuint32_t pio1_12; + vuint32_t pio1_13; + vuint32_t pio1_14; + vuint32_t pio1_15; + + vuint32_t pio1_16; /* 0xa0 */ + vuint32_t pio1_17; + vuint32_t pio1_18; + vuint32_t pio1_19; + + vuint32_t pio1_20; + vuint32_t pio1_21; + vuint32_t pio1_22; + vuint32_t pio1_23; + + vuint32_t pio1_24; /* 0xc0 */ + vuint32_t pio1_25; + vuint32_t pio1_26; + vuint32_t pio1_27; + + vuint32_t pio1_28; + vuint32_t pio1_29; + vuint32_t pio1_30; + vuint32_t pio1_31; +}; + +extern struct lpc_ioconf lpc_ioconf; + +#define LPC_IOCONF_FUNC 0 + +/* PIO0_0 */ +#define LPC_IOCONF_FUNC_RESET 0 +#define LPC_IOCONF_FUNC_PIO0_0 1 + +/* PIO0_1 */ +#define LPC_IOCONF_FUNC_PIO0_1 0 +#define LPC_IOCONF_FUNC_CLKOUT 1 +#define LPC_IOCONF_FUNC_CT32B0_MAT2 2 +#define LPC_IOCONF_FUNC_USB_FTOGGLE 3 + +/* PIO0_2 */ +#define LPC_IOCONF_FUNC_PIO0_2 0 +#define LPC_IOCONF_FUNC_SSEL0 1 +#define LPC_IOCONF_FUNC_CT16B0_CAP0 2 + +/* PIO0_3 +#define LPC_IOCONF_FUNC_PIO0_3 0 +#define LPC_IOCONF_FUNC_USB_VBUS 1 + +/* PIO0_4 +#define LPC_IOCONF_FUNC_PIO0_4 0 +#define LPC_IOCONF_FUNC_I2C_SCL 1 + +/* PIO0_5 */ +#define LPC_IOCONF_FUNC_PIO0_5 0 +#define LPC_IOCONF_FUNC_I2C_SDA 1 + +/* PIO0_6 */ +#define LPC_IOCONF_FUNC_PIO0_6 0 +#define LPC_IOCONF_FUNC_USB_CONNECT 1 +#define LPC_IOCONF_FUNC_SCK0 2 + +/* PIO0_7 */ +#define LPC_IOCONF_FUNC_PIO0_7 0 +#define LPC_IOCONF_FUNC_CTS 1 + +/* PIO0_8 +#define LPC_IOCONF_FUNC_PIO0_8 0 +#define LPC_IOCONF_FUNC_MISO0 1 +#define LPC_IOCONF_FUNC_CT16B0_MAT0 2 + +/* PIO0_9 */ +#define LPC_IOCONF_FUNC_PIO0_9 0 +#define LPC_IOCONF_FUNC_MOSI0 1 +#define LPC_IOCONF_FUNC_CT16B0_MAT1 2 + +/* PIO0_10 */ +#define LPC_IOCONF_FUNC_SWCLK 0 +#define LPC_IOCONF_FUNC_PIO0_10 1 +#define LPC_IOCONF_FUNC_SCK0 2 +#define LPC_IOCONF_FUNC_CT16B0_MAT2 3 + +/* PIO0_11 */ +#define LPC_IOCONF_FUNC_TDI 0 +#define LPC_IOCONF_FUNC_PIO0_11 1 +#define LPC_IOCONF_FUNC_AD0 2 +#define LPC_IOCONF_FUNC_CT32B0_MAT3 3 + +/* PIO0_12 */ +#define LPC_IOCONF_FUNC_TMS 0 +#define LPC_IOCONF_FUNC_PIO0_12 1 +#define LPC_IOCONF_FUNC_AD1 2 +#define LPC_IOCONF_FUNC_CT32B1_CAP0 3 + +/* PIO0_13 */ +#define LPC_IOCONF_FUNC_TD0 0 +#define LPC_IOCONF_FUNC_PIO0_13 1 +#define LPC_IOCONF_FUNC_AD2 2 +#define LPC_IOCONF_FUNC_CT32B1_MAT0 3 + +/* PIO0_14 */ +#define LPC_IOCONF_FUNC_TRST 0 +#define LPC_IOCONF_FUNC_PIO0_14 1 +#define LPC_IOCONF_FUNC_AD3 2 +#define LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1 3 + +/* PIO0_15 */ +#define LPC_IOCONF_FUNC_SWDIO 0 +#define LPC_IOCONF_FUNC_PIO0_15 1 +#define LPC_IOCONF_FUNC_AD4 2 +#define LPC_IOCONF_FUNC_CT32B1_MAT2 3 + +/* PIO0_16 */ +#define LPC_IOCONF_FUNC_PIO0_16 0 +#define LPC_IOCONF_FUNC_AD5 1 +#define LPC_IOCONF_FUNC_CT32B1_MAT3 2 + +/* PIO0_17 */ +#define LPC_IOCONF_FUNC_PIO0_17 0 +#define LPC_IOCONF_FUNC_RTS 1 +#define LPC_IOCONF_FUNC_CT32B0_CAP0 2 +#define LPC_IOCONF_FUNC_SCLK 3 + +/* PIO0_18 */ +#define LPC_IOCONF_FUNC_PIO0_18 0 +#define LPC_IOCONF_FUNC_PIO0_18_RXD 1 +#define LPC_IOCONF_FUNC_PIO0_18_CT32B0_MAT0 2 + +/* PIO0_19 */ +#define LPC_IOCONF_FUNC_PIO0_19 0 +#define LPC_IOCONF_FUNC_PIO0_19_TXD 1 +#define LPC_IOCONF_FUNC_PIO0_19_CT32B0_MAT1 2 + +/* PIO0_20 */ +#define LPC_IOCONF_FUNC_PIO0_20 0 +#define LPC_IOCONF_FUNC_CT16B1_CAP0 1 + +/* PIO0_21 */ +#define LPC_IOCONF_FUNC_PIO0_21 0 +#define LPC_IOCONF_FUNC_CT16B1_MAT0 1 +#define LPC_IOCONF_FUNC_MOSI1 2 + +/* PIO0_22 */ +#define LPC_IOCONF_FUNC_PIO0_22 0 +#define LPC_IOCONF_FUNC_AD6 1 +#define LPC_IOCONF_FUNC_CT16B1_MAT1 2 +#define LPC_IOCONF_FUNC_MISO1 3 + +/* PIO0_23 */ +#define LPC_IOCONF_FUNC_PIO0_23 0 +#define LPC_IOCONF_FUNC_AD7 1 + +/* PIO1_0 */ +#define LPC_IOCONF_FUNC_PIO1_0 0 +#define LPC_IOCONF_FUNC_CT32B1_MAT1 1 + +/* PIO1_1 */ +#define LPC_IOCONF_FUNC_PIO1_1 0 +#define LPC_IOCONF_FUNC_CT32B1_MAT1 1 + +/* PIO1_2 */ +#define LPC_IOCONF_FUNC_PIO1_2 0 +#define LPC_IOCONF_FUNC_PIO1_2_CT32B1_MAT2 1 + +/* PIO1_3*/ +#define LPC_IOCONF_FUNC_PIO1_3 0 +#define LPC_IOCONF_FUNC_PIO1_3_CT32B1_MAT3 1 + +/* PIO1_4 */ +#define LPC_IOCONF_FUNC_PIO1_4 0 +#define LPC_IOCONF_FUNC_PIO1_4_CT32B1_CAP0 1 + +/* PIO1_5 */ +#define LPC_IOCONF_FUNC_PIO1_5 0 +#define LPC_IOCONF_FUNC_CT32B1_CAP1 1 + +/* PIO1_6 */ +#define LPC_IOCONF_FUNC_PIO1_6 0 + +/* PIO1_7 */ +#define LPC_IOCONF_FUNC_PIO1_7 0 + +/* PIO1_8 */ +#define LPC_IOCONF_FUNC_PIO1_8 0 + +/* PIO1_9 */ +#define LPC_IOCONF_FUNC_PIO1_9 0 + +/* PIO1_10 */ +#define LPC_IOCONF_FUNC_PIO1_10 0 + +/* PIO1_11 */ +#define LPC_IOCONF_FUNC_PIO1_11 0 + +/* PIO1_12 */ +#define LPC_IOCONF_FUNC_PIO1_12 0 + +/* PIO1_13 */ +#define LPC_IOCONF_FUNC_PIO1_13 0 +#define LPC_IOCONF_FUNC_DTR 1 +#define LPC_IOCONF_FUNC_CT16B0_MAT0 2 +#define LPC_IOCONF_FUNC_PIO1_13_TXD 3 + +/* PIO1_14 */ +#define LPC_IOCONF_FUNC_PIO1_14 0 +#define LPC_IOCONF_FUNC_DSR 1 +#define LPC_IOCONF_FUNC_CT16B0_MAT1 2 +#define LPC_IOCONF_FUNC_PIO1_13_RXD 3 + +/* PIO1_15 */ +#define LPC_IOCONF_FUNC_PIO1_15 0 +#define LPC_IOCONF_FUNC_DCD 1 +#define LPC_IOCONF_FUNC_PIO1_15_CT16B0_MAT2 2 +#define LPC_IOCONF_FUNC_SCK1 3 + +/* PIO1_16 */ +#define LPC_IOCONF_FUNC_PIO1_16 0 +#define LPC_IOCONF_FUNC_RI 1 +#define LPC_IOCONF_FUNC_CT16B0_CAP0 2 + +/* PIO1_17 */ +#define LPC_IOCONF_FUNC_PIO1_17 0 +#define LPC_IOCONF_FUNC_CT16B0_CAP1 1 +#define LPC_IOCONF_FUNC_PIO1_17_RXD 2 + +/* PIO1_18 */ +#define LPC_IOCONF_FUNC_PIO1_18 0 +#define LPC_IOCONF_FUNC_CT16B1_CAP1 1 +#define LPC_IOCONF_FUNC_PIO1_18_TXD 2 + +/* PIO1_19 */ +#define LPC_IOCONF_FUNC_PIO1_19 0 +#define LPC_IOCONF_FUNC_DTR 1 +#define LPC_IOCONF_FUNC_SSEL1 2 + +/* PIO1_20 */ +#define LPC_IOCONF_FUNC_PIO1_20 0 +#define LPC_IOCONF_FUNC_DSR 1 +#define LPC_IOCONF_FUNC_PIO1_20_SCK1 2 + +/* PIO1_21 */ +#define LPC_IOCONF_FUNC_PIO1_21 0 +#define LPC_IOCONF_FUNC_DCD 1 +#define LPC_IOCONF_FUNC_PIO1_21_MISO1 2 + +/* PIO1_22 */ +#define LPC_IOCONF_FUNC_PIO1_22 0 +#define LPC_IOCONF_FUNC_RI 1 +#define LPC_IOCONF_FUNC_MOSI1 2 + +/* PIO1_23 */ +#define LPC_IOCONF_FUNC_PIO1_23 0 +#define LPC_IOCONF_FUNC_PIO1_23_CT16B1_MAT1 1 +#define LPC_IOCONF_FUNC_SSEL1 2 + +/* PIO1_24 */ +#define LPC_IOCONF_FUNC_PIO1_24 0 +#define LPC_IOCONF_FUNC_PIO1_24_CT32B0_MAT0 1 + +/* PIO1_25 */ +#define LPC_IOCONF_FUNC_PIO1_25 0 +#define LPC_IOCONF_FUNC_PIO1_25_CT32B0_MAT1 1 + +/* PIO1_26 */ +#define LPC_IOCONF_FUNC_PIO1_26 0 +#define LPC_IOCONF_FUNC_PIO1_26_CT32B0_MAT2 1 +#define LPC_IOCONF_FUNC_PIO1_26_RXD 2 + +/* PIO1_27 */ +#define LPC_IOCONF_FUNC_PIO1_27 0 +#define LPC_IOCONF_FUNC_PIO1_27_CT32B0_MAT3 1 +#define LPC_IOCONF_FUNC_PIO1_27_TXD 2 + +/* PIO1_28 */ +#define LPC_IOCONF_FUNC_PIO1_28 0 +#define LPC_IOCONF_FUNC_PIO1_28_CT32B0_CAP0 1 +#define LPC_IOCONF_FUNC_PIO1_28_SCLK 2 + +/* PIO1_29 */ +#define LPC_IOCONF_FUNC_PIO1_29 0 +#define LPC_IOCONF_FUNC_PIO1_29_SCK0 1 +#define LPC_IOCONF_FUNC_PIO1_29_CT32B0_CAP1 2 + +/* PIO1_31 */ +#define LPC_IOCONF_FUNC_PIO1_31 0 + +#define LPC_IOCONF_FUNC_MASK 0x7 + +#define LPC_IOCONF_MODE 3 +#define LPC_IOCONF_MODE_INACTIVE 0 +#define LPC_IOCONF_MODE_PULL_DOWN 1 +#define LPC_IOCONF_MODE_PULL_UP 2 +#define LPC_IOCONF_MODE_REPEATER 3 +#define LPC_IOCONF_MODE_MASK 3 + +#define LPC_IOCONF_HYS 5 + +#define LPC_IOCONF_INV 6 +#define LPC_IOCONF_OD 10 + +struct lpc_scb { + vuint32_t sysmemremap; /* 0x00 */ + vuint32_t presetctrl; + vuint32_t syspllctrl; + vuint32_t syspllstat; + + vuint32_t usbpllctrl; /* 0x10 */ + vuint32_t usbpllstat; + uint32_t r18; + uint32_t r1c; + + vuint32_t sysoscctrl; /* 0x20 */ + vuint32_t wdtoscctrl; + uint32_t r28; + uint32_t r2c; + + vuint32_t sysrststat; /* 0x30 */ + uint32_t r34; + uint32_t r38; + uint32_t r3c; + + vuint32_t syspllclksel; /* 0x40 */ + vuint32_t syspllclkuen; + vuint32_t usbpllclksel; + vuint32_t usbplllclkuen; + + uint32_t r50[8]; + + vuint32_t mainclksel; /* 0x70 */ + vuint32_t mainclkuen; + vuint32_t sysahbclkdiv; + uint32_t r7c; + + vuint32_t sysahbclkctrl; /* 0x80 */ + uint32_t r84[3]; + + uint32_t r90; /* 0x90 */ + vuint32_t ssp0clkdiv; + vuint32_t uartclkdiv; + vuint32_t ssp1clkdiv; + + uint32_t ra0[8]; + + vuint32_t usbclksel; /* 0xc0 */ + vuint32_t usbclkuen; + vuint32_t usbclkdiv; + uint32_t rcc; + + uint32_t rd0[4]; + + vuint32_t clkoutsel; /* 0xe0 */ + vuint32_t clkoutuen; + vuint32_t clkoutdiv; + uint32_t rec; + + uint32_t rf0[4]; /* 0xf0 */ + + vuint32_t pioporcap0; /* 0x100 */ + vuint32_t pioporcap1; + uint32_t r102[2]; + + uint32_t r110[4]; /* 0x110 */ + uint32_t r120[4]; /* 0x120 */ + uint32_t r130[4]; /* 0x130 */ + uint32_t r140[4]; /* 0x140 */ + + vuint32_t bodctrl; /* 0x150 */ + vuint32_t systckcal; + uint32_t r158[2]; + + uint32_t r160[4]; /* 0x160 */ + + vuint32_t irqlatency; /* 0x170 */ + vuint32_t nmisrc; + vuint32_t pintsel0; + vuint32_t pintsel1; + + vuint32_t pintsel2; /* 0x180 */ + vuint32_t pintsel3; + vuint32_t pintsel4; + vuint32_t pintsel5; + + vuint32_t pintsel6; /* 0x190 */ + vuint32_t pintsel7; + vuint32_t usbclkctrl; + vuint32_t usbclkst; + + uint32_t r1a0[6*4]; /* 0x1a0 */ + + uint32_t r200; /* 0x200 */ + vuint32_t starterp0; + uint32_t r208[2]; + + uint32_t r210; /* 0x210 */ + vuint32_t starterp1; + uint32_t r218[2]; + + uint32_t r220[4]; /* 0x220 */ + + vuint32_t pdsleepcfg; /* 0x230 */ + vuint32_t pdawakecfg; + vuint32_t pdruncfg; + uint32_t r23c; + + uint32_t r240[12 * 4]; /* 0x240 */ + + uint32_t r300[15 * 4]; /* 0x300 */ + + uint32_t r3f0; /* 0x3f0 */ + vuint32_t device_id; +}; + +extern struct lpc_scb lpc_scb; + +#define LPC_SCB_PRESETCTRL_SSP0_RST_N 0 +#define LPC_SCB_PRESETCTRL_I2C_RST_N 1 +#define LPC_SCB_PRESETCTRL_SSP1_RST_N 2 + +#define LPC_SCB_SYSPLLCTRL_MSEL 0 +#define LPC_SCB_SYSPLLCTRL_PSEL 5 +#define LPC_SCB_SYSPLLCTRL_PSEL_1 0 +#define LPC_SCB_SYSPLLCTRL_PSEL_2 1 +#define LPC_SCB_SYSPLLCTRL_PSEL_4 2 +#define LPC_SCB_SYSPLLCTRL_PSEL_8 3 +#define LPC_SCB_SYSPLLCTRL_PSEL_MASK 3 + +#define LPC_SCB_SYSPLLSTAT_LOCK 0 + +#define LPC_SCB_USBPLLCTRL_MSEL 0 +#define LPC_SCB_USBPLLCTRL_PSEL 5 +#define LPC_SCB_USBPLLCTRL_PSEL_1 0 +#define LPC_SCB_USBPLLCTRL_PSEL_2 1 +#define LPC_SCB_USBPLLCTRL_PSEL_4 2 +#define LPC_SCB_USBPLLCTRL_PSEL_8 3 +#define LPC_SCB_USBPLLCTRL_PSEL_MASK 3 + +#define LPC_SCB_USBPLLSTAT_LOCK 0 + +#define LPC_SCB_SYSOSCCTRL_BYPASS 0 +#define LPC_SCB_SYSOSCCTRL_FREQRANGE 1 +#define LPC_SCB_SYSOSCCTRL_FREQRANGE_1_20 0 +#define LPC_SCB_SYSOSCCTRL_FREQRANGE_15_25 1 + +#define LPC_SCB_WDTOSCCTRL_DIVSEL 0 +#define LPC_SCB_WDTOSCCTRL_DIVSEL_MASK 0x1f +#define LPC_SCB_WDTOSCCTRL_FREQSEL 5 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_0_6 1 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_1_05 2 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_1_4 3 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_1_75 4 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_2_1 5 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_2_4 6 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_2_7 7 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_0 8 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_25 9 +#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_5 0x0a +#define LPC_SCB_WDTOSCCTRL_FREQSEL_3_75 0x0b +#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_0 0x0c +#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_2 0x0d +#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_4 0x0e +#define LPC_SCB_WDTOSCCTRL_FREQSEL_4_6 0x0f +#define LPC_SCB_WDTOSCCTRL_FREQSEL_MASK 0x0f + +#define LPC_SCB_SYSRSTSTAT_POR 0 +#define LPC_SCB_SYSRSTSTAT_EXTRST 1 +#define LPC_SCB_SYSRSTSTAT_WDT 2 +#define LPC_SCB_SYSRSTSTAT_BOD 3 +#define LPC_SCB_SYSRSTSTAT_SYSRST 4 + +#define LPC_SCB_SYSPLLCLKSEL_SEL 0 +#define LPC_SCB_SYSPLLCLKSEL_SEL_IRC 0 +#define LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC 1 +#define LPC_SCB_SYSPLLCLKSEL_SEL_MASK 3 + +#define LPC_SCB_SYSPLLCLKUEN_ENA 0 + +#define LPC_SCB_USBPLLCLKSEL_SEL 0 +#define LPC_SCB_USBPLLCLKSEL_SEL_IRC 0 +#define LPC_SCB_USBPLLCLKSEL_SEL_SYSOSC 1 +#define LPC_SCB_USBPLLCLKSEL_SEL_MASK 3 + +#define LPC_SCB_USBPLLCLKUEN_ENA 0 + +#define LPC_SCB_MAINCLKSEL_SEL 0 +#define LPC_SCB_MAINCLKSEL_SEL_IRC 0 +#define LPC_SCB_MAINCLKSEL_SEL_PLL_INPUT 1 +#define LPC_SCB_MAINCLKSEL_SEL_WATCHDOG 2 +#define LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT 3 +#define LPC_SCB_MAINCLKSEL_SEL_MASK 3 + +#define LPC_SCB_MAINCLKUEN_ENA 0 + +#define LPC_SCB_SYSAHBCLKDIV_DIV 0 + +#define LPC_SCB_SYSAHBCLKCTRL_SYS 0 +#define LPC_SCB_SYSAHBCLKCTRL_ROM 1 +#define LPC_SCB_SYSAHBCLKCTRL_RAM0 2 +#define LPC_SCB_SYSAHBCLKCTRL_FLASHREG 3 +#define LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY 4 +#define LPC_SCB_SYSAHBCLKCTRL_I2C 5 +#define LPC_SCB_SYSAHBCLKCTRL_GPIO 6 +#define LPC_SCB_SYSAHBCLKCTRL_CT16B0 7 +#define LPC_SCB_SYSAHBCLKCTRL_CT16B1 8 +#define LPC_SCB_SYSAHBCLKCTRL_CT32B0 9 +#define LPC_SCB_SYSAHBCLKCTRL_CT32B1 10 +#define LPC_SCB_SYSAHBCLKCTRL_SSP0 11 +#define LPC_SCB_SYSAHBCLKCTRL_USART 12 +#define LPC_SCB_SYSAHBCLKCTRL_ADC 13 +#define LPC_SCB_SYSAHBCLKCTRL_USB 14 +#define LPC_SCB_SYSAHBCLKCTRL_WWDT 15 +#define LPC_SCB_SYSAHBCLKCTRL_IOCON 16 +#define LPC_SCB_SYSAHBCLKCTRL_SSP1 18 +#define LPC_SCB_SYSAHBCLKCTRL_PINT 19 +#define LPC_SCB_SYSAHBCLKCTRL_GROUP0INT 23 +#define LPC_SCB_SYSAHBCLKCTRL_GROUP1INT 24 +#define LPC_SCB_SYSAHBCLKCTRL_RAM1 26 +#define LPC_SCB_SYSAHBCLKCTRL_USBRAM 27 + +#define LPC_SCB_SSP0CLKDIV_ +#define LPC_SCB_UARTCLKDIV_ +#define LPC_SCB_SSP1CLKDIV_ + +#define LPC_SCB_USBCLKSEL_SEL 0 +#define LPC_SCB_USBCLKSEL_SEL_USB_PLL 0 +#define LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK 1 + +#define LPC_SCB_USBCLKUEN_ENA 0 +#define LPC_SCB_USBCLKDIV_DIV 0 + +#define LPC_SCB_CLKOUTSEL_ +#define LPC_SCB_CLKOUTUEN_ + +#define LPC_SCB_PDRUNCFG_IRCOUT_PD 0 +#define LPC_SCB_PDRUNCFG_IRC_PD 1 +#define LPC_SCB_PDRUNCFG_FLASH_PD 2 +#define LPC_SCB_PDRUNCFG_BOD_PD 3 +#define LPC_SCB_PDRUNCFG_ADC_PD 4 +#define LPC_SCB_PDRUNCFG_SYSOSC_PD 5 +#define LPC_SCB_PDRUNCFG_WDTOSC_PD 6 +#define LPC_SCB_PDRUNCFG_SYSPLL_PD 7 +#define LPC_SCB_PDRUNCFG_USBPLL_PD 8 +#define LPC_SCB_PDRUNCFG_USBPAD_PD 10 + +struct lpc_flash { + uint32_t r0[4]; /* 0x0 */ + + vuint32_t flashcfg; /* 0x10 */ +}; + +extern struct lpc_flash lpc_flash; + +struct lpc_gpio_pin { +}; + +extern struct lpc_gpio_pin lpc_gpio_pin; + +struct lpc_gpio_group0 { +}; + +extern struct lpc_gpio_group0 lpc_gpio_group0; + +struct lpc_gpio_group1 { +}; + +extern struct lpc_gpio_group1 lpc_gpio_group1; + +struct lpc_gpio { + vuint8_t byte[0x40]; /* 0x0000 */ + + uint8_t r0030[0x1000 - 0x40]; + + vuint32_t word[0x40]; /* 0x1000 */ + + uint8_t r1100[0x2000 - 0x1100]; + + vuint32_t dir[2]; /* 0x2000 */ + + uint8_t r2008[0x2080 - 0x2008]; + + vuint32_t mask[2]; /* 0x2080 */ + + uint8_t r2088[0x2100 - 0x2088]; + + vuint32_t pin[2]; /* 0x2100 */ + + uint8_t r2108[0x2200 - 0x2108]; + + vuint32_t set[2]; /* 0x2200 */ + + uint8_t r2208[0x2280 - 0x2208]; + + vuint32_t clr[2]; /* 0x2280 */ + + uint8_t r2288[0x2300 - 0x2288]; + + vuint32_t not[2]; /* 0x2300 */ +}; + +extern struct lpc_gpio lpc_gpio; + +struct lpc_systick { + uint8_t r0000[0x10]; /* 0x0000 */ + + vuint32_t csr; /* 0x0010 */ + vuint32_t rvr; + vuint32_t cvr; + vuint32_t calib; +}; + +extern struct lpc_systick lpc_systick; + +#define LPC_SYSTICK_CSR_ENABLE 0 +#define LPC_SYSTICK_CSR_TICKINT 1 +#define LPC_SYSTICK_CSR_CLKSOURCE 2 +#define LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2 0 +#define LPC_SYSTICK_CSR_CLKSOURCE_CPU 1 +#define LPC_SYSTICK_CSR_COUNTFLAG 16 + +struct lpc_usart { + vuint32_t rbr_thr; /* 0x0000 */ + vuint32_t ier; + vuint32_t iir_fcr; + vuint32_t lcr; + + vuint32_t mcr; /* 0x0010 */ + vuint32_t lsr; + vuint32_t msr; + vuint32_t scr; + + vuint32_t acr; /* 0x0020 */ + vuint32_t icr; + vuint32_t fdr; + vuint32_t osr; + + vuint32_t ter; /* 0x0030 */ + uint32_t r34[3]; + + vuint32_t hden; /* 0x0040 */ + uint32_t r44; + vuint32_t scictrl; + vuint32_t rs485ctrl; + + vuint32_t rs485addrmatch; /* 0x0050 */ + vuint32_t rs485dly; + vuint32_t syncctrl; +}; + +extern struct lpc_usart lpc_usart; + +#endif /* _LPC_H_ */ diff --git a/src/lpc/registers.ld b/src/lpc/registers.ld new file mode 100644 index 00000000..cd6ac5f5 --- /dev/null +++ b/src/lpc/registers.ld @@ -0,0 +1,9 @@ +lpc_usart = 0x40008000; +lpc_flash = 0x4003c000; +lpc_ioconf = 0x40044000; +lpc_scb = 0x40048000; +lpc_gpio_pin = 0x4004c000; +lpc_gpio_group0 = 0x4005c000; +lpc_gpio_group1 = 0x40060000; +lpc_gpio = 0x50000000; +lpc_systick = 0xe000e000; diff --git a/src/lpcxpresso/Makefile b/src/lpcxpresso/Makefile new file mode 100644 index 00000000..bac222cc --- /dev/null +++ b/src/lpcxpresso/Makefile @@ -0,0 +1,64 @@ +# +# AltOS build +# +# + +include ../lpc/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_pins.h \ + ao_product.h \ + lpc.h + +# +# Common AltOS sources +# +ALTOS_SRC = \ + ao_interrupt.c \ + ao_romconfig.c \ + ao_product.c \ + ao_panic.c \ + ao_led_lpc.c \ + ao_task.c \ + ao_timer_lpc.c \ + ao_serial_lpc.c \ + ao_stdio.c + +PRODUCT=LpcDemo-v0.0 +PRODUCT_DEF=-DLPC_DEMO +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os + +PROG=lpc-demo.elf + +SRC=$(ALTOS_SRC) ao_demo.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) + +LDFLAGS=-L../lpc -Wl,-Taltos.ld + +$(PROG): Makefile $(OBJ) + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +load: $(PROG) + lpc-load $(PROG) + +distclean: clean + +clean: + rm -f *.o $(PROG) + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/lpcxpresso/ao_pins.h b/src/lpcxpresso/ao_pins.h new file mode 100644 index 00000000..56391c2b --- /dev/null +++ b/src/lpcxpresso/ao_pins.h @@ -0,0 +1,47 @@ +/* + * Copyright © 2013 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define HAS_BEEP 0 +#define HAS_LED 1 + +/* Crystal on the board */ +#define AO_LPC_CLKIN 12000000 + +/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */ +#define AO_LPC_CLKOUT 48000000 + +/* System clock frequency */ +#define AO_LPC_SYSCLK 24000000 + +#define LED_PORT 0 +#define LED_PIN_RED 7 + +#define AO_LED_RED (1 << LED_PIN_RED) + +#define LEDS_AVAILABLE AO_LED_RED + +#define HAS_USB 0 + +#define PACKET_HAS_SLAVE 0 + +/* USART */ + +#define HAS_SERIAL 1 +#define SERIAL_0_18_19 1 +#define SERIAL_1_14_15 0 +#define SERIAL_1_17_18 0 +#define SERIAL_1_26_27 0 -- 2.30.2