lpc176x: Add initial support for LPC176x processors
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
@@ -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
34
src/lpc176x/Kconfig
Normal 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
42
src/lpc176x/Makefile
Normal 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
28
src/lpc176x/gpio.c
Normal 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
7
src/lpc176x/internal.h
Normal 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
31
src/lpc176x/main.c
Normal 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
79
src/lpc176x/serial.c
Normal 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
59
src/lpc176x/timer.c
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user