lpc176x: Add initial support for LPC176x processors

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor
2018-05-07 21:32:27 -04:00
parent 5ae22a5e51
commit 970831ee0d
20 changed files with 6856 additions and 0 deletions

View File

@@ -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"

34
src/lpc176x/Kconfig Normal file
View File

@@ -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

42
src/lpc176x/Makefile Normal file
View File

@@ -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 $< $@

28
src/lpc176x/gpio.c Normal file
View File

@@ -0,0 +1,28 @@
// GPIO functions on lpc176x
//
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
//
// 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);
}

7
src/lpc176x/internal.h Normal file
View File

@@ -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

31
src/lpc176x/main.c Normal file
View File

@@ -0,0 +1,31 @@
// Main starting point for LPC176x boards.
//
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
//
// 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;
}

79
src/lpc176x/serial.c Normal file
View File

@@ -0,0 +1,79 @@
// lpc176x serial port
//
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
//
// 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);
}
}

59
src/lpc176x/timer.c Normal file
View File

@@ -0,0 +1,59 @@
// lpc176x timer interrupt scheduling
//
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
//
// 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();
}