From 970831ee0d3b91897196e92270d98b2a3067427f Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Mon, 7 May 2018 21:32:27 -0400 Subject: lpc176x: Add initial support for LPC176x processors Signed-off-by: Kevin O'Connor --- src/Kconfig | 3 ++ src/lpc176x/Kconfig | 34 ++++++++++++++++++++++ src/lpc176x/Makefile | 42 +++++++++++++++++++++++++++ src/lpc176x/gpio.c | 28 ++++++++++++++++++ src/lpc176x/internal.h | 7 +++++ src/lpc176x/main.c | 31 ++++++++++++++++++++ src/lpc176x/serial.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lpc176x/timer.c | 59 +++++++++++++++++++++++++++++++++++++ 8 files changed, 283 insertions(+) create mode 100644 src/lpc176x/Kconfig create mode 100644 src/lpc176x/Makefile create mode 100644 src/lpc176x/gpio.c create mode 100644 src/lpc176x/internal.h create mode 100644 src/lpc176x/main.c create mode 100644 src/lpc176x/serial.c create mode 100644 src/lpc176x/timer.c (limited to 'src') diff --git a/src/Kconfig b/src/Kconfig index cd07ae6b..0a135637 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -8,6 +8,8 @@ choice bool "Atmega AVR" config MACH_SAM3X8E bool "SAM3x8e (Arduino Due)" + config MACH_LPC176X + bool "LPC176x (Smoothieboard)" config MACH_STM32F1 bool "STMicroelectronics STM32F103" config MACH_PRU @@ -20,6 +22,7 @@ endchoice source "src/avr/Kconfig" source "src/sam3x8e/Kconfig" +source "src/lpc176x/Kconfig" source "src/stm32f1/Kconfig" source "src/pru/Kconfig" source "src/linux/Kconfig" diff --git a/src/lpc176x/Kconfig b/src/lpc176x/Kconfig new file mode 100644 index 00000000..d9f15dd1 --- /dev/null +++ b/src/lpc176x/Kconfig @@ -0,0 +1,34 @@ +# Kconfig settings for LPC176x processors + +if MACH_LPC176X + +config LPC_SELECT + bool + default y + +config BOARD_DIRECTORY + string + default "lpc176x" + +choice + prompt "Processor model" + config MACH_LPC1768 + bool "lpc1768 (100 Mhz)" + config MACH_LPC1769 + bool "lpc1769 (120 Mhz)" +endchoice + +config CLOCK_FREQ + int + default 25000000 if MACH_LPC1768 # 100000000 / 4 + default 30000000 if MACH_LPC1769 # 120000000 / 4 + +config SERIAL + bool + default y +config SERIAL_BAUD + depends on SERIAL + int "Baud rate for serial port" + default 250000 + +endif diff --git a/src/lpc176x/Makefile b/src/lpc176x/Makefile new file mode 100644 index 00000000..2ff7d174 --- /dev/null +++ b/src/lpc176x/Makefile @@ -0,0 +1,42 @@ +# lpc176x build rules + +# Setup the toolchain +CROSS_PREFIX=arm-none-eabi- + +dirs-y += src/lpc176x src/generic +dirs-y += lib/lpc176x/device lib/lpc176x/device/TOOLCHAIN_GCC_ARM + +CFLAGS += -mthumb -mcpu=cortex-m3 +CFLAGS += -Ilib/lpc176x/device -Ilib/lpc176x/device -Ilib/lpc176x/cmsis + +CFLAGS_klipper.elf += -T $(OUT)LPC1768.ld +CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs + +# Add source files +src-y += lpc176x/main.c lpc176x/timer.c lpc176x/gpio.c +src-y += generic/crc16_ccitt.c generic/alloc.c +src-y += generic/armcm_irq.c generic/timer_irq.c +src-y += ../lib/lpc176x/device/system_LPC17xx.c +src-$(CONFIG_SERIAL) += lpc176x/serial.c generic/serial_irq.c + +# Add the TOOLCHAIN_GCC_ARM files to the build +$(OUT)%.o: %.S + @echo " Assembling $@" + $(Q)$(AS) $< -o $@ + +asmsrc-y := ../lib/lpc176x/device/TOOLCHAIN_GCC_ARM/startup_LPC17xx.S + +$(OUT)klipper.elf: $(patsubst %.S, $(OUT)src/%.o,$(asmsrc-y)) + +target-y := $(OUT)LPC1768.ld $(target-y) + +$(OUT)LPC1768.ld: lib/lpc176x/device/TOOLCHAIN_GCC_ARM/LPC1768.ld $(OUT)board-link + @echo " Preprocessing $@" + $(Q)$(CPP) -P -MD -MT $@ $< -o $@ + +# Build the additional bin output file +target-y += $(OUT)klipper.bin + +$(OUT)klipper.bin: $(OUT)klipper.elf + @echo " Creating bin file $@" + $(Q)$(OBJCOPY) -O binary $< $@ diff --git a/src/lpc176x/gpio.c b/src/lpc176x/gpio.c new file mode 100644 index 00000000..756b0e7b --- /dev/null +++ b/src/lpc176x/gpio.c @@ -0,0 +1,28 @@ +// GPIO functions on lpc176x +// +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "LPC17xx.h" // LPC_PINCON +#include "internal.h" // gpio_peripheral +#include "board/irq.h" // irq_save + +// Set the mode and extended function of a pin +void +gpio_peripheral(int bank, int pin, int func, int pullup) +{ + uint32_t bank_pos = bank * 2, pin_pos = pin * 2; + if (pin_pos >= 32) { + pin_pos -= 32; + bank_pos++; + } + uint32_t sel_bits = (func & 0x03) << pin_pos, mask = ~(0x03 << pin_pos); + uint32_t mode_bits = (pullup ? 0x00 : 0x02) << pin_pos; + volatile uint32_t *pinsel = &LPC_PINCON->PINSEL0; + volatile uint32_t *pinmode = &LPC_PINCON->PINMODE0; + irqstatus_t flag = irq_save(); + pinsel[bank_pos] = (pinsel[bank_pos] & mask) | sel_bits; + pinmode[bank_pos] = (pinmode[bank_pos] & mask) | mode_bits; + irq_restore(flag); +} diff --git a/src/lpc176x/internal.h b/src/lpc176x/internal.h new file mode 100644 index 00000000..da1f169f --- /dev/null +++ b/src/lpc176x/internal.h @@ -0,0 +1,7 @@ +#ifndef __LPC176X_INTERNAL_H +#define __LPC176X_INTERNAL_H +// Local definitions for lpc176x code + +void gpio_peripheral(int bank, int pin, int func, int pullup); + +#endif // internal.h diff --git a/src/lpc176x/main.c b/src/lpc176x/main.c new file mode 100644 index 00000000..24cf6816 --- /dev/null +++ b/src/lpc176x/main.c @@ -0,0 +1,31 @@ +// Main starting point for LPC176x boards. +// +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "LPC17xx.h" // NVIC_SystemReset +#include "command.h" // DECL_CONSTANT +#include "sched.h" // sched_main + +DECL_CONSTANT(MCU, "lpc176x"); + + +/**************************************************************** + * misc functions + ****************************************************************/ + +void +command_reset(uint32_t *args) +{ + NVIC_SystemReset(); +} +DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset"); + +// Main entry point +int +main(void) +{ + sched_main(); + return 0; +} diff --git a/src/lpc176x/serial.c b/src/lpc176x/serial.c new file mode 100644 index 00000000..7f2a0db9 --- /dev/null +++ b/src/lpc176x/serial.c @@ -0,0 +1,79 @@ +// lpc176x serial port +// +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "LPC17xx.h" // LPC_UART0 +#include "autoconf.h" // CONFIG_SERIAL_BAUD +#include "board/irq.h" // irq_save +#include "board/serial_irq.h" // serial_rx_data +#include "internal.h" // gpio_peripheral +#include "sched.h" // DECL_INIT + +void +serial_init(void) +{ + // Setup baud + LPC_UART0->LCR = (1<<7); // set DLAB bit + LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x3<<6)) | (0x1<<6); + uint32_t pclk = SystemCoreClock; + uint32_t div = pclk / (CONFIG_SERIAL_BAUD * 16); + LPC_UART0->DLL = div & 0xff; + LPC_UART0->DLM = (div >> 8) & 0xff; + LPC_UART0->LCR = 3; // 8N1 ; clear DLAB bit + + // Enable fifo + LPC_UART0->FCR = 0x01; + + // Setup pins + gpio_peripheral(0, 2, 1, 0); + gpio_peripheral(0, 3, 1, 0); + + // Enable receive irq + NVIC_SetPriority(UART0_IRQn, 0); + NVIC_EnableIRQ(UART0_IRQn); + LPC_UART0->IER = 0x01; +} +DECL_INIT(serial_init); + +// Write tx bytes to the serial port +static void +kick_tx(void) +{ + for (;;) { + if (!(LPC_UART0->LSR & (1<<5))) { + // Output fifo full - enable tx irq + LPC_UART0->IER = 0x03; + break; + } + uint8_t data; + int ret = serial_get_tx_byte(&data); + if (ret) { + // No more data to send - disable tx irq + LPC_UART0->IER = 0x01; + break; + } + LPC_UART0->THR = data; + } +} + +void __visible +UART0_IRQHandler(void) +{ + uint32_t iir = LPC_UART0->IIR, status = iir & 0x0f; + if (status == 0x04) + serial_rx_byte(LPC_UART0->RBR); + else if (status == 0x02) + kick_tx(); +} + +void +serial_enable_tx_irq(void) +{ + if (LPC_UART0->LSR & (1<<5)) { + irqstatus_t flag = irq_save(); + kick_tx(); + irq_restore(flag); + } +} diff --git a/src/lpc176x/timer.c b/src/lpc176x/timer.c new file mode 100644 index 00000000..d6d6f9ed --- /dev/null +++ b/src/lpc176x/timer.c @@ -0,0 +1,59 @@ +// lpc176x timer interrupt scheduling +// +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "LPC17xx.h" // LPC_TIM0 +#include "board/irq.h" // irq_disable +#include "board/misc.h" // timer_read_time +#include "board/timer_irq.h" // timer_dispatch_many +#include "sched.h" // DECL_INIT + +// Set the next irq time +static void +timer_set(uint32_t value) +{ + LPC_TIM0->MR0 = value; + LPC_TIM0->IR = 0x01; +} + +// Return the current time (in absolute clock ticks). +uint32_t +timer_read_time(void) +{ + return LPC_TIM0->TC; +} + +// Activate timer dispatch as soon as possible +void +timer_kick(void) +{ + timer_set(timer_read_time() + 50); +} + +void +timer_init(void) +{ + // Disable timer + LPC_TIM0->TCR = 0x02; + // Enable interrupts + NVIC_SetPriority(TIMER0_IRQn, 1); + NVIC_EnableIRQ(TIMER0_IRQn); + LPC_TIM0->MCR = 0x01; + // Clear counter value + LPC_TIM0->TC = 0; + timer_kick(); + // Start timer + LPC_TIM0->TCR = 0x01; +} +DECL_INIT(timer_init); + +void __visible __aligned(16) // aligning helps stabilize perf benchmarks +TIMER0_IRQHandler(void) +{ + irq_disable(); + uint32_t next = timer_dispatch_many(); + timer_set(next); + irq_enable(); +} -- cgit v1.2.3-70-g09d2