Verified Commit 60f1ebea authored by Felix Kopp's avatar Felix Kopp
Browse files

arch: use CMSIS after all

It was inevitable, tbh.  I really wanted to do
everything entirely from scratch, but all those
hardware registers are just too much to be
maintained by a single person.  And since i plan
on supporting different boards at some point in
the future, it would be complete madness to redo
everything for that board.
parent b122e54e
[submodule "contrib/arduino-cmsis"]
path = contrib/arduino-cmsis
url = https://github.com/arduino/ArduinoModule-CMSIS-Atmel.git
[submodule "contrib/cmsis"]
path = contrib/cmsis
url = https://github.com/ARM-software/CMSIS_5.git
......@@ -15,6 +15,17 @@ endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
option(GIT_SUBMODULE "Update git submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Git submodule update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
......
......@@ -4,7 +4,13 @@ add_library(ardix_arch STATIC)
target_link_libraries(ardix INTERFACE ardix_arch)
target_compile_options(ardix_arch PRIVATE ${ARDIX_COMPILE_OPTIONS})
target_include_directories(ardix_arch PRIVATE ${ARDIX_INCLUDE_DIRS})
target_include_directories(ardix_arch PRIVATE
${ARDIX_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../contrib/arduino-cmsis/CMSIS-Atmel/CMSIS/Device/ATMEL/sam3xa/include
${CMAKE_CURRENT_SOURCE_DIR}/../../contrib/cmsis/CMSIS/Core/Include
)
target_compile_definitions(ardix_arch PRIVATE ARDIX_ARCH)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/config.ld.in
......@@ -22,7 +28,6 @@ target_sources(ardix_arch PRIVATE
handle_pend_sv.S
handle_reset.c
handle_svc.S
interrupt.c
mutex.S
sched.c
serial.c
......
......@@ -10,22 +10,22 @@
/** Setup UART to manual byte-by-byte control */
static inline void uart_emergency_setup(void)
{
REG_UART_PDC_PTCR = REG_UART_PDC_PTCR_RXTDIS_MASK | REG_UART_PDC_PTCR_TXTDIS_MASK;
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
REG_UART_CR = REG_UART_CR_RXDIS_MASK | REG_UART_CR_RSTRX_MASK
| REG_UART_CR_TXDIS_MASK | REG_UART_CR_RSTTX_MASK;
UART->UART_CR = UART_CR_RXDIS | UART_CR_RSTRX
| UART_CR_TXDIS | UART_CR_RSTTX;
REG_UART_IDR = 0xffffffff;
UART->UART_IDR = 0xffffffff;
REG_UART_CR = REG_UART_CR_RXEN_MASK | REG_UART_CR_TXEN_MASK;
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
static void uart_write_sync(const char *s)
{
char c;
while ((c = *s++) != '\0') {
mom_are_we_there_yet(REG_UART_SR & REG_UART_SR_TXRDY_MASK);
REG_UART_THR = c;
mom_are_we_there_yet(UART->UART_SR & UART_SR_TXRDY);
UART->UART_THR = c;
}
}
......
This diff is collapsed.
/* See the end of this file for copyright, license, and warranty information. */
#include <arch/hardware.h>
#include <arch/interrupt.h>
void arch_irq_enable(enum irqno irqno)
{
if (irqno >= 0)
REG_NVIC_ISER((uint32_t)irqno >> 5) = 1 << ( ((uint32_t)irqno) & 0x1F );
}
void arch_irq_disable(enum irqno irqno)
{
if (irqno >= 0)
REG_NVIC_ICER((uint32_t)irqno >> 5) = 1 << ( ((uint32_t)irqno) & 0x1F );
}
void arch_irq_invoke(enum irqno irqno)
{
if (irqno < 0) {
switch (irqno) {
case IRQNO_PEND_SV:
REG_SCB_ICSR = REG_SCB_ICSR_PENDSVSET_BIT;
break;
case IRQNO_SYS_TICK:
REG_SCB_ICSR = REG_SCB_ICSR_PENDSTSET_BIT;
break;
default:
/* TODO: Implement the rest of interrupts < 0 */
break;
}
} else {
REG_NVIC_ISPR((uint32_t)irqno >> 5) = 1 << ( ((uint32_t)irqno) & 0x1F );
}
}
/*
* This file is part of Ardix.
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
*
* Ardix is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/
......@@ -33,34 +33,32 @@ int arch_serial_init(struct serial_device *dev)
return -1;
/* enable peripheral clock for UART (which has peripheral id 8) */
REG_PMC_PCER0 |= REG_PMC_PCER0_PID(8);
PMC->PMC_PCER0 |= PMC_PCER0_PID8;
/* ensure the PIO controller is turned off on the serial pins */
REG_PIO_PDR(PIOA) = (1 << 8) | (1 << 9);
PIOA->PIO_PDR = PIO_PDR_P8 | PIO_PDR_P9;
/* configure peripheral DMA controller */
REG_UART_PDC_PTCR = REG_UART_PDC_PTCR_RXTDIS_MASK | REG_UART_PDC_PTCR_TXTEN_MASK;
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTEN;
/* reset & disable rx and tx */
REG_UART_CR = REG_UART_CR_RXDIS_MASK | REG_UART_CR_RSTRX_MASK
| REG_UART_CR_TXDIS_MASK | REG_UART_CR_RSTTX_MASK;
UART->UART_CR = UART_CR_RXDIS | UART_CR_RSTRX
| UART_CR_TXDIS | UART_CR_RSTTX;
/* no parity, normal mode */
REG_UART_MR = REG_UART_MR_PAR_NO | REG_UART_MR_CHMODE_NORMAL;
UART->UART_MR = UART_MR_PAR_NO | UART_MR_CHMODE_NORMAL;
/* From Atmel Datasheet: baud rate = MCK / (REG_UART_BRGR * 16) */
REG_UART_BRGR = (uint16_t)(( sys_core_clock / (uint32_t)dev->baud ) >> 4);
UART->UART_BRGR = UART_BRGR_CD(( SystemCoreClock / (uint32_t)dev->baud ) >> 4);
/* choose the events we want an interrupt on */
REG_UART_IDR = 0xFFFFFFFF; /* make sure all interrupts are disabled first */
REG_UART_IER = REG_UART_IER_RXRDY_MASK
| REG_UART_IER_OVRE_MASK
| REG_UART_IER_FRAME_MASK;
UART->UART_IDR = 0xffffffff; /* make sure all interrupts are disabled first */
UART->UART_IER = UART_IER_RXRDY | UART_IER_OVRE | UART_IER_FRAME;
arch_irq_enable(IRQNO_UART);
NVIC_EnableIRQ(UART_IRQn);
/* enable receiver and transmitter */
REG_UART_CR = REG_UART_CR_RXEN_MASK | REG_UART_CR_TXEN_MASK;
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
return 0;
}
......@@ -71,12 +69,12 @@ void arch_serial_exit(struct serial_device *dev)
return;
/* disable receiver and transmitter */
REG_UART_CR = REG_UART_CR_RXDIS_MASK | REG_UART_CR_TXDIS_MASK;
UART->UART_CR = UART_CR_RXDIS | UART_CR_TXDIS;
arch_irq_disable(IRQNO_UART);
NVIC_DisableIRQ(UART_IRQn);
/* disable peripheral clock for UART (PID is taken from Atmel Datasheet, Section 9.1 */
REG_PMC_PCDR0 = REG_PMC_PCDR0_PID(8);
PMC->PMC_PCDR0 = PMC_PCDR0_PID8;
dev->id = -1;
}
......@@ -111,14 +109,14 @@ ssize_t serial_write_dma(struct serial_device *dev, struct dmabuf *buf)
if (arch_dev->tx_current == NULL) {
arch_dev->tx_current = buf;
REG_UART_PDC_TPR = (uint32_t)buf->data;
REG_UART_PDC_TCR = len;
UART->UART_TPR = (uint32_t)buf->data;
UART->UART_TCR = len;
/* we weren't transmitting, so the interrupt was masked */
REG_UART_IER = REG_UART_IER_ENDTX_MASK;
UART->UART_IER = UART_IER_ENDTX;
} else {
arch_dev->tx_next = buf;
REG_UART_PDC_TNPR = (uint32_t)buf->data;
REG_UART_PDC_TNCR = len;
UART->UART_TNPR = (uint32_t)buf->data;
UART->UART_TNCR = len;
}
return (ssize_t)len;
......@@ -127,11 +125,11 @@ ssize_t serial_write_dma(struct serial_device *dev, struct dmabuf *buf)
void irq_uart(void)
{
uint8_t tmp;
uint32_t state = REG_UART_SR;
uint32_t state = UART->UART_SR;
/* RX has received a byte, store it into the ring buffer */
if (state & REG_UART_SR_RXRDY_MASK) {
tmp = REG_UART_RHR;
if (state & UART_SR_RXRDY) {
tmp = (uint8_t)UART->UART_RHR;
ringbuf_write(arch_serial_default_device.device.rx, &tmp, sizeof(tmp));
device_kevent_create_and_dispatch(&serial_default_device->device,
......@@ -139,7 +137,7 @@ void irq_uart(void)
}
/* REG_UART_PDC_TCR has reached zero */
if (state & REG_UART_SR_ENDTX_MASK) {
if (state & UART_SR_ENDTX) {
if (arch_serial_default_device.tx_current != NULL)
dmabuf_put(arch_serial_default_device.tx_current);
......@@ -148,16 +146,16 @@ void irq_uart(void)
arch_serial_default_device.tx_next = NULL;
if (arch_serial_default_device.tx_current == NULL)
REG_UART_IDR = REG_UART_IDR_ENDTX_MASK;
UART->UART_IDR = UART_IDR_ENDTX;
device_kevent_create_and_dispatch(&serial_default_device->device,
DEVICE_CHANNEL_OUT);
}
/* check for error conditions */
if ((state & REG_UART_SR_OVRE_MASK) || (state & REG_UART_SR_FRAME_MASK)) {
if ((state & UART_SR_OVRE) || (state & UART_SR_FRAME)) {
/* TODO: write some proper error handling routines ffs */
REG_UART_CR = REG_UART_CR_RSTSTA_MASK;
UART->UART_CR = UART_CR_RSTSTA;
}
__clrex();
......
......@@ -9,6 +9,16 @@
#include <string.h>
#include <toolchain.h>
#define SYS_BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8))
#define SYS_BOARD_MCKR (PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK)
#define SYS_BOARD_PLLAR ( \
CKGR_PLLAR_ONE \
| CKGR_PLLAR_MULA(0xdUL) \
| CKGR_PLLAR_PLLACOUNT(0x3fUL) \
| CKGR_PLLAR_DIVA(0x1UL) \
)
/*
* The initial sys_core_clock on system boot would actually be 4000000 because
* the 4 MHz RC oscillator is used by default. However, for performance
......@@ -18,7 +28,7 @@
* So, since we trust the clock to be configured correctly before this global
* variable is accessed anywhere, we initialize it to the 84 MHz clock.
*/
uint32_t sys_core_clock = 84000000UL;
uint32_t SystemCoreClock = 84000000UL;
void sys_init(void)
{
......@@ -28,33 +38,29 @@ void sys_init(void)
*/
/* # of wait states as per hardware spec (stolen from SAM SysInit) */
REG_EEFC0_FMR = REG_EEFC_FWS_VAL(4);
REG_EEFC1_FMR = REG_EEFC_FWS_VAL(4);
EFC0->EEFC_FMR = EEFC_FMR_FWS(4);
EFC1->EEFC_FMR = EEFC_FMR_FWS(4);
/*
* 1. Enabling the Main Oscillator
*/
/* initialize main osc */
if (!(REG_CKGR_MOR & REG_CKGR_MOR_MOSCSEL_BIT)) {
REG_CKGR_MOR = REG_CKGR_MOR_KEY_VAL(REG_CKGR_MOR_KEY_MAGIC)
| REG_CKGR_MOR_MOSCXTST_VAL(8)
| REG_CKGR_MOR_MOSCRCEN_BIT
| REG_CKGR_MOR_MOSCXTEN_BIT;
mom_are_we_there_yet(REG_PMC_SR & REG_PMC_SR_MOSCXTS_BIT);
if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)) {
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| SYS_BOARD_OSCOUNT
| CKGR_MOR_MOSCRCEN
| CKGR_MOR_MOSCXTEN;
mom_are_we_there_yet(PMC->PMC_SR & PMC_SR_MOSCXTS);
}
/* switch to Xtal osc */
REG_CKGR_MOR = REG_CKGR_MOR_KEY_VAL(REG_CKGR_MOR_KEY_MAGIC)
| REG_CKGR_MOR_MOSCXTST_VAL(8)
| REG_CKGR_MOR_MOSCRCEN_BIT
| REG_CKGR_MOR_MOSCXTEN_BIT
| REG_CKGR_MOR_MOSCSEL_BIT;
mom_are_we_there_yet(REG_PMC_SR & REG_PMC_SR_MOSCSELS_BIT);
REG_PMC_MCKR = (REG_PMC_MCKR & ~REG_PMC_MCKR_CSS_MASK)
| REG_PMC_MCKR_CSS_VAL(1 /* = main clock */);
mom_are_we_there_yet(REG_PMC_SR & REG_PMC_SR_MCKRDY_BIT);
/* Switch to 3-20MHz Xtal oscillator */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| SYS_BOARD_OSCOUNT
| CKGR_MOR_MOSCRCEN
| CKGR_MOR_MOSCXTEN
| CKGR_MOR_MOSCSEL;
mom_are_we_there_yet(PMC->PMC_SR & PMC_SR_MOSCSELS);
/*
* 2. Checking the Main Oscillator Frequency (Optional)
......@@ -66,24 +72,24 @@ void sys_init(void)
* 3. Setting PLL and Divider
*/
REG_CKGR_PLLAR = REG_CKGR_PLLAR_ONE_BIT
| REG_CKGR_PLLAR_MULA_VAL(0xD)
| REG_CKGR_PLLAR_PLLACOUNT_VAL(0x3F /* maximum value */)
| REG_CKGR_PLLAR_DIVA_VAL(0x1);
mom_are_we_there_yet(REG_PMC_SR & REG_PMC_SR_LOCKA_BIT);
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
mom_are_we_there_yet(PMC->PMC_SR & PMC_SR_MCKRDY);
/*
* 4. Selection of Master Clock and Processor Clock
*/
REG_PMC_MCKR = REG_PMC_MCKR_PRES_VAL(1 /* = as fast as it gets */)
| REG_PMC_MCKR_CSS_VAL(1 /* = main clock */);
mom_are_we_there_yet(REG_PMC_SR & REG_PMC_SR_MCKRDY_BIT);
/* Initialize PLLA */
PMC->CKGR_PLLAR = SYS_BOARD_PLLAR;
mom_are_we_there_yet(PMC->PMC_SR & PMC_SR_LOCKA);
/* PMC_MCKR must not be configured within one clock cycle */
REG_PMC_MCKR = REG_PMC_MCKR_PRES_VAL(1 /* = as fast as it gets */)
| REG_PMC_MCKR_CSS_VAL(2 /* = PLLA clock */);
mom_are_we_there_yet(REG_PMC_SR & REG_PMC_SR_MCKRDY_BIT);
/* Switch to MCK */
PMC->PMC_MCKR = (SYS_BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
mom_are_we_there_yet(PMC->PMC_SR & PMC_SR_MCKRDY);
/* Switch to PLLA */
PMC->PMC_MCKR = SYS_BOARD_MCKR;
mom_are_we_there_yet(PMC->PMC_SR & PMC_SR_MCKRDY);
}
/*
......@@ -97,4 +103,30 @@ void sys_init(void)
*
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*
* ===========================================================================
*
* Parts of this file are derived from the Atmel SAM Software Package.
* Copyright (c) 2015, Atmel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following condition is met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
......@@ -6,7 +6,7 @@
int arch_watchdog_init(void)
{
/* we don't use the watchdog at all for now */
REG_WDT_MR = REG_WDT_MR_WDDIS_BIT;
WDT->WDT_MR = WDT_MR_WDDIS;
return 0;
}
......
Subproject commit 46ab1021146152a64caf1ddbb837d8181b8faa35
Subproject commit 13b9f72f212688d2306d0d085d87cbb4bf9e5d3f
......@@ -13,7 +13,7 @@ struct task; /* see include/ardix/sched.h */
*
* @param freq: The timer frequency in Hertz.
*/
int arch_sched_hwtimer_init(unsigned int freq);
int arch_sched_init(unsigned int freq);
/**
* Initialize a new process.
......
......@@ -57,7 +57,7 @@ int sched_init(void)
if (i != 0)
goto out;
i = arch_sched_hwtimer_init(CONFIG_SCHED_FREQ);
i = arch_sched_init(CONFIG_SCHED_FREQ);
if (i != 0)
goto out;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment