arm: async echo app

This commit is contained in:
Paul Mathieu 2022-05-16 20:56:25 -07:00
parent 30d9a2d7c8
commit 932b8d4582
25 changed files with 3043 additions and 29 deletions

View File

@ -7,9 +7,12 @@ SECTIONS
{ {
.text : .text :
{ {
_text_begin = .;
KEEP(*(.app_init)) KEEP(*(.app_init))
*(.text*) *(.text*)
_text_end = .;
*(.rodata*) *(.rodata*)
} > ICTM } > ICTM
@ -30,5 +33,8 @@ SECTIONS
__exidx_end = .; __exidx_end = .;
} > ICTM } > ICTM
_heap_begin = .;
_initial_stack_pointer = 16384; _initial_stack_pointer = 16384;
_heap_end = _initial_stack_pointer - 1024;
} }

132
arm/async.cc Normal file
View File

@ -0,0 +1,132 @@
#include "async.h"
#include <array>
#include <atomic>
#include <chrono>
namespace async {
namespace {
using namespace std::literals::chrono_literals;
struct Stuff {
std::coroutine_handle<> h;
std::chrono::system_clock::time_point expiration;
Stuff* next;
};
std::atomic<Stuff*> work;
std::array<std::atomic<Stuff*>, static_cast<size_t>(AwaitableType::kNumTypes)>
queues;
} // namespace
void schedule(std::coroutine_handle<> h, int ms) {
std::chrono::system_clock::time_point exp =
std::chrono::system_clock::now() + std::chrono::milliseconds(ms);
Stuff* news = new Stuff{
.h = h,
.expiration = exp,
};
Stuff* stuff = work;
if (!stuff || stuff->expiration > exp) {
news->next = stuff;
work = news;
return;
}
Stuff* s = stuff;
while (s->next && s->next->expiration <= exp) {
s = s->next;
}
news->next = s->next;
s->next = news;
}
void main_loop(void (*idle_function)()) {
while (1) {
if (idle_function != nullptr) {
idle_function();
}
Stuff* stuff = work;
if (stuff == nullptr) {
continue; // busyloop
}
auto now = std::chrono::system_clock::now();
auto dt = stuff->expiration - now;
if (dt > 0ms) {
continue;
}
stuff->h();
if (stuff->h.done()) {
stuff->h.destroy();
}
Stuff* oldstuff = stuff;
work = stuff->next;
delete oldstuff;
}
}
void enqueue(std::coroutine_handle<> h, AwaitableType type) {
Stuff* item = new Stuff{.h = h};
auto ttype = static_cast<size_t>(type);
Stuff* stuff = queues[ttype];
if (stuff == nullptr) {
queues[ttype] = item;
return;
}
while (stuff->next != nullptr) {
stuff = stuff->next;
}
stuff->next = item;
}
void resume(AwaitableType type) {
auto ttype = static_cast<size_t>(type);
Stuff* stuff = queues[ttype];
if (stuff == nullptr) {
return;
}
queues[ttype] = stuff->next;
schedule(stuff->h);
delete stuff;
}
} // namespace async
#if 0
task<buffer> readline() {
int size = 0;
char c;
buffer buff = buffer::make(32);
// fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
while (true) {
int n = read(0, &c, 1);
if (n < 1) {
co_await co_waitio();
continue;
}
buff.data[size++] = static_cast<std::byte>(c);
if (c == '\n') {
buff.data = buff.data.subspan(0, size);
co_return buff;
}
}
}
#endif // 0

127
arm/async.h Normal file
View File

@ -0,0 +1,127 @@
#pragma once
#include <chrono>
#include <coroutine>
#include <utility>
namespace async {
template<typename T = void>
struct task {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct maybe_suspend {
bool await_ready() noexcept(true) { return !parent; }
void await_suspend(std::coroutine_handle<>) noexcept(true) {
if (parent) {
parent();
}
}
void await_resume() noexcept(true) { }
std::coroutine_handle<> parent;
};
struct promise_type {
task get_return_object() { return {.h = handle_type::from_promise(*this)}; }
std::suspend_always initial_suspend() noexcept { return {}; }
maybe_suspend final_suspend() noexcept { return { .parent = parent }; }
void return_value(T&& value) { ret_value = std::move(value); }
void unhandled_exception() {}
T ret_value;
std::coroutine_handle<> parent;
};
// awaitable
bool await_ready() { return h.done(); }
void await_suspend(std::coroutine_handle<> ha) {
h();
h.promise().parent = ha;
}
T await_resume() { return std::move(h.promise().ret_value); }
std::coroutine_handle<promise_type> h;
};
template<>
struct task<void> {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct maybe_suspend {
bool await_ready() noexcept(true) { return !parent; }
void await_suspend(std::coroutine_handle<>) noexcept(true) {
if (parent) {
parent();
}
}
void await_resume() noexcept(true) { }
std::coroutine_handle<> parent;
};
struct promise_type {
task get_return_object() { return {.h = handle_type::from_promise(*this)}; }
std::suspend_always initial_suspend() noexcept { return {}; }
maybe_suspend final_suspend() noexcept { return { .parent = parent }; }
void return_void() {}
void unhandled_exception() {}
std::coroutine_handle<> parent;
};
// awaitable
bool await_ready() { return h.done(); }
void await_suspend(std::coroutine_handle<> ha) {
h();
h.promise().parent = ha;
}
void await_resume() {}
std::coroutine_handle<promise_type> h;
};
enum class AwaitableType {
kUnknown = 0,
kUartRx = 1,
kNumTypes
};
void schedule(std::coroutine_handle<> h, int ms = 0);
void enqueue(std::coroutine_handle<> h, AwaitableType type);
void resume(AwaitableType type); // typically called from an ISR
void main_loop(void (*idle_function)());
inline auto await(AwaitableType type) {
struct awaitable {
AwaitableType type;
bool await_ready() { return false; };
void await_suspend(std::coroutine_handle<> h) {
enqueue(h, type);
}
void await_resume() {}
};
return awaitable{type};
}
inline auto delay(int ms) {
struct awaitable {
int ms;
bool await_ready() { return false; };
void await_suspend(std::coroutine_handle<> h) {
schedule(h, ms);
}
void await_resume() {}
};
return awaitable{ms};
}
} // namespace async

23
arm/buffer.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <span>
#include <utility>
struct buffer {
std::span<std::byte> data;
buffer() = default;
buffer(std::span<std::byte> d) : data(d) {}
static buffer make(size_t size) {
return buffer({new std::byte[size], size});
}
buffer(buffer& other) = delete;
buffer& operator=(buffer& other) = delete;
buffer(buffer&& other) : data(std::exchange(other.data, {})) {}
buffer& operator=(buffer&& other) { data = std::exchange(other.data, {}); return *this; }
~buffer() { if (data.data()) { delete[] data.data(); }; }
};

112
arm/crash.cc Normal file
View File

@ -0,0 +1,112 @@
#include <cstdint>
#include "gpio.h"
#include "itoa.h"
#include "sleep.h"
#include "uart.h"
extern "C" uint32_t _initial_stack_pointer, _text_begin, _text_end;
namespace crash {
namespace {
[[maybe_unused]] void CrashHexDump(uint32_t* begin, uint32_t* end,
int direction = 1) {
char number[] = "00000000 ";
char addr[] = "00000000: ";
int i = 0;
itoa(reinterpret_cast<uint32_t>(begin), addr);
UartSendCrash(addr);
for (uint32_t* ptr = begin; direction > 0 ? ptr < end : ptr > end;
ptr += direction, i++) {
itoa(*ptr, number);
UartSendCrash(number);
if (i % 4 == 3) {
UartSendCrash("\r\n");
itoa(reinterpret_cast<uint32_t>(ptr + 1), addr);
UartSendCrash(addr);
}
}
if (i % 4 != 3) {
UartSendCrash("\r\n");
}
}
void StackTrace(uint32_t* sp) {
char number[] = "00000000\r\n";
for (uint32_t* ptr = sp; ptr < &_initial_stack_pointer; ptr++) {
auto addr = reinterpret_cast<uint32_t*>(*ptr);
if (addr < &_text_begin || addr >= &_text_end || (*ptr & 0x1) == 0) {
continue;
}
itoa(*ptr, number);
UartSendCrash(number);
}
}
struct Armv6mRegs {
uintptr_t r4;
uintptr_t r5;
uintptr_t r6;
uintptr_t r7;
uintptr_t r8;
uintptr_t r9;
uintptr_t r10;
uintptr_t r11;
uintptr_t sp;
// saved by the CPU
uintptr_t r0;
uintptr_t r1;
uintptr_t r2;
uintptr_t r3;
uintptr_t r12;
uintptr_t lr;
uintptr_t pc;
uintptr_t xpsr;
};
void CrashHandler(Armv6mRegs* regs) {
char number[] = "00000000\r\n";
UartSendCrash("\r\n\r\nCra$h!!\r\n- xpsr: 0x");
itoa(regs->xpsr, number);
UartSendCrash(number);
UartSendCrash("- pc: 0x");
itoa(regs->pc, number);
UartSendCrash(number);
UartSendCrash("- lr: 0x");
itoa(regs->lr, number);
UartSendCrash(number);
UartSendCrash("- Stack trace:\r\n");
StackTrace(reinterpret_cast<uint32_t*>(regs->sp));
while (1) {
gpio0->data = 0x55;
sleep(100);
gpio0->data = 0xaa;
sleep(100);
}
}
} // namespace
__attribute__((naked)) void HardFaultHandler() {
asm volatile(
// set those leds first
"mov r0, %0 \n"
"mov r1, #0xa5 \n"
"str r1, [r0] \n"
"mov r0, r8 \n"
"mov r1, r9 \n"
"mov r2, r10 \n"
"mov r3, r11 \n"
"mrs lr, msp \n"
"push {r0-r3, lr} \n"
"push {r4-r7} \n"
"mrs r0, msp \n"
"mov r1, %1 \n"
"blx r1 \n"
:
: "r"(gpio0), "r"(CrashHandler));
}
} // namespace crash

5
arm/crash.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
namespace crash {
void HardFaultHandler();
} // namespace crash

View File

@ -7,3 +7,21 @@ struct Gpio {
}; };
#define gpio0 ((Gpio*) 0x40000000) #define gpio0 ((Gpio*) 0x40000000)
inline void ToggleLed(int which) {
uint8_t data = gpio0->data;
data ^= (0x1 << which);
gpio0->data = data;
}
inline void SetLed(int which) {
uint8_t data = gpio0->data;
data |= (0x1 << which);
gpio0->data = data;
}
inline void ClearLed(int which) {
uint8_t data = gpio0->data;
data &= ~(0x1 << which);
gpio0->data = data;
}

111
arm/hal/cmsis/aum1_cm1.h Normal file
View File

@ -0,0 +1,111 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------- Interrupt Number Definition ------------------------ */
typedef enum IRQn
{
/* ------------------- Cortex-M0 Processor Exceptions Numbers ------------------- */
NonMaskableInt_IRQn = -14, /* 2 Non Maskable Interrupt */
HardFault_IRQn = -13, /* 3 HardFault Interrupt */
//SVCall_IRQn = -5, /* 11 SV Call Interrupt */
//PendSV_IRQn = -2, /* 14 Pend SV Interrupt */
//SysTick_IRQn = -1, /* 15 System Tick Interrupt */
/* ---------------------- ARTY_CM1 Specific Interrupt Numbers ------------------- */
Unused0_IRQn = 0,
Uart0_IRQn = 1, /* GPIO 0 Interrupt */
Timer0_IRQn = 2, /* Timer 0 Interrupt */
Unused3_IRQn = 3,
Unused4_IRQn = 4,
Unused5_IRQn = 5,
Unused6_IRQn = 6,
Unused7_IRQn = 7,
Unused8_IRQn = 8,
Unused9_IRQn = 9,
Unused10_IRQn = 10,
Unused11_IRQn = 11,
Unused12_IRQn = 12,
Unused13_IRQn = 13,
Unused14_IRQn = 14,
Unused15_IRQn = 15,
Unused16_IRQn = 16,
Unused17_IRQn = 17,
Unused18_IRQn = 18,
Unused19_IRQn = 19,
Unused20_IRQn = 20,
Unused21_IRQn = 21,
Unused22_IRQn = 22,
Unused23_IRQn = 23,
Unused24_IRQn = 24,
Unused25_IRQn = 25,
Unused26_IRQn = 26,
Unused27_IRQn = 27,
Unused28_IRQn = 28,
Unused29_IRQn = 29,
Unused30_IRQn = 30,
Unused31_IRQn = 31,
} IRQn_Type;
/* ================================================================================ */
/* ================ Processor and Core Peripheral Section ================ */
/* ================================================================================ */
/* -------- Configuration of the Cortex-M0 Processor and Core Peripherals ------- */
#define __CM1_REV 0x0000 /* Core revision r0p0 */
#define __MPU_PRESENT 0 /* MPU present or not */
#define __NVIC_PRIO_BITS 2 /* Number of Bits used for Priority Levels */
#define __Vendor_SysTickConfig 1 /* Set to 1 if different SysTick Config is used */
#include <core_cm1.h> /* Processor and core peripherals */
/* ================================================================================ */
/* ================ Device Specific Peripheral Section ================ */
/* ================================================================================ */
/* ------------------- Start of section using anonymous unions ------------------ */
#if defined ( __CC_ARM )
#pragma push
#pragma anon_unions
#elif defined(__ICCARM__)
#pragma language=extended
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#elif defined(__TMS470__)
/* anonymous unions are enabled by default */
#elif defined(__TASKING__)
#pragma warning 586
#else
#warning Not supported compiler type
#endif
/* -------------------- End of section using anonymous unions ------------------- */
#if defined ( __CC_ARM )
#pragma pop
#elif defined(__ICCARM__)
/* leave anonymous unions enabled */
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#elif defined(__TMS470__)
/* anonymous unions are enabled by default */
#elif defined(__TASKING__)
#pragma warning restore
#else
#warning Not supported compiler type
#endif
#ifdef __cplusplus
}
#endif

692
arm/hal/cmsis/core_cm1.h Normal file
View File

@ -0,0 +1,692 @@
/**************************************************************************//**
* @file core_cm1.h
* @brief CMSIS Cortex-M1 Core Peripheral Access Layer Header File
* @version V3.20
* @date 19. April 2018
*
* @note
*
******************************************************************************/
/* Copyright (c) 2009 - 2018 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 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.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __CORE_CM1_H_GENERIC
#define __CORE_CM1_H_GENERIC
/** \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions
CMSIS violates the following MISRA-C:2004 rules:
\li Required Rule 8.5, object/function definition in header file.<br>
Function definitions in header files are used to allow 'inlining'.
\li Required Rule 18.4, declaration of union type or object of union type: '{...}'.<br>
Unions are used for effective representation of core registers.
\li Advisory Rule 19.7, Function-like macro defined.<br>
Function-like macros are used to allow more efficient code.
*/
/*******************************************************************************
* CMSIS definitions
******************************************************************************/
/** \ingroup Cortex_M0
@{
*/
/* CMSIS CM1 definitions */
#define __CM1_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */
#define __CM1_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */
#define __CM1_CMSIS_VERSION ((__CM1_CMSIS_VERSION_MAIN << 16) | \
__CM1_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */
#define __CORTEX_M (0x00) /*!< Cortex-M Core */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE static __inline
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */
#define __STATIC_INLINE static inline
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#define __STATIC_INLINE static inline
#endif
/** __FPU_USED indicates whether an FPU is used or not. This core does not support an FPU at all
*/
#define __FPU_USED 0
#if defined ( __CC_ARM )
#if defined __TARGET_FPU_VFP
#warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __ICCARM__ )
#if defined __ARMVFP__
#warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __GNUC__ )
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
#warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __TASKING__ )
#if defined __FPU_VFP__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#endif
#include <stdint.h> /* standard types definitions */
#include <core_cmInstr.h> /* Core Instruction Access */
#include <core_cmFunc.h> /* Core Function Access */
#endif /* __CORE_CM1_H_GENERIC */
#ifndef __CMSIS_GENERIC
#ifndef __CORE_CM1_H_DEPENDANT
#define __CORE_CM1_H_DEPENDANT
/* check device defines and use defaults */
#if defined __CHECK_DEVICE_DEFINES
#ifndef __CM1_REV
#define __CM1_REV 0x0000
#warning "__CM1_REV not defined in device header file; using default!"
#endif
#ifndef __NVIC_PRIO_BITS
#define __NVIC_PRIO_BITS 2
#warning "__NVIC_PRIO_BITS not defined in device header file; using default!"
#endif
#ifndef __Vendor_SysTickConfig
#define __Vendor_SysTickConfig 0
#warning "__Vendor_SysTickConfig not defined in device header file; using default!"
#endif
#endif
/* IO definitions (access restrictions to peripheral registers) */
/**
\defgroup CMSIS_glob_defs CMSIS Global Defines
<strong>IO Type Qualifiers</strong> are used
\li to specify the access to peripheral variables.
\li for automatic generation of peripheral register debug information.
*/
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/*@} end of group Cortex_M0 */
/*******************************************************************************
* Register Abstraction
Core Register contain:
- Core Register
- Core NVIC Register
- Core SCB Register
- Core SysTick Register
******************************************************************************/
/** \defgroup CMSIS_core_register Defines and Type Definitions
\brief Type definitions and defines for Cortex-M processor based devices.
*/
/** \ingroup CMSIS_core_register
\defgroup CMSIS_CORE Status and Control Registers
\brief Core Register type definitions.
@{
*/
/** \brief Union type to access the Application Program Status Register (APSR).
*/
typedef union
{
struct
{
#if (__CORTEX_M != 0x04)
uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */
#else
uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */
uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */
uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */
#endif
uint32_t Q:1; /*!< bit: 27 Saturation condition flag */
uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
uint32_t C:1; /*!< bit: 29 Carry condition code flag */
uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
uint32_t N:1; /*!< bit: 31 Negative condition code flag */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} APSR_Type;
/** \brief Union type to access the Interrupt Program Status Register (IPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} IPSR_Type;
/** \brief Union type to access the Special-Purpose Program Status Registers (xPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
#if (__CORTEX_M != 0x04)
uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */
#else
uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */
uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */
uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */
#endif
uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */
uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */
uint32_t Q:1; /*!< bit: 27 Saturation condition flag */
uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
uint32_t C:1; /*!< bit: 29 Carry condition code flag */
uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
uint32_t N:1; /*!< bit: 31 Negative condition code flag */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} xPSR_Type;
/** \brief Union type to access the Control Registers (CONTROL).
*/
typedef union
{
struct
{
uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */
uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */
uint32_t FPCA:1; /*!< bit: 2 FP extension active flag */
uint32_t _reserved0:29; /*!< bit: 3..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} CONTROL_Type;
/*@} end of group CMSIS_CORE */
/** \ingroup CMSIS_core_register
\defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC)
\brief Type definitions for the NVIC Registers
@{
*/
/** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
*/
typedef struct
{
__IO uint32_t ISER[1]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[31];
__IO uint32_t ICER[1]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[31];
__IO uint32_t ISPR[1]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[31];
__IO uint32_t ICPR[1]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[31];
uint32_t RESERVED4[64];
__IO uint32_t IP[8]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
} NVIC_Type;
/*@} end of group CMSIS_NVIC */
/** \ingroup CMSIS_core_register
\defgroup CMSIS_SCB System Control Block (SCB)
\brief Type definitions for the System Control Block Registers
@{
*/
/** \brief Structure type to access the System Control Block (SCB).
*/
typedef struct
{
__I uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IO uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
uint32_t RESERVED0;
__IO uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IO uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IO uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
uint32_t RESERVED1;
__IO uint32_t SHP[2]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */
__IO uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
} SCB_Type;
/* SCB CPUID Register Definitions */
#define SCB_CPUID_IMPLEMENTER_Pos 24 /*!< SCB CPUID: IMPLEMENTER Position */
#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */
#define SCB_CPUID_VARIANT_Pos 20 /*!< SCB CPUID: VARIANT Position */
#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */
#define SCB_CPUID_ARCHITECTURE_Pos 16 /*!< SCB CPUID: ARCHITECTURE Position */
#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */
#define SCB_CPUID_PARTNO_Pos 4 /*!< SCB CPUID: PARTNO Position */
#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */
#define SCB_CPUID_REVISION_Pos 0 /*!< SCB CPUID: REVISION Position */
#define SCB_CPUID_REVISION_Msk (0xFUL << SCB_CPUID_REVISION_Pos) /*!< SCB CPUID: REVISION Mask */
/* SCB Interrupt Control State Register Definitions */
#define SCB_ICSR_NMIPENDSET_Pos 31 /*!< SCB ICSR: NMIPENDSET Position */
#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */
#define SCB_ICSR_PENDSVSET_Pos 28 /*!< SCB ICSR: PENDSVSET Position */
#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */
#define SCB_ICSR_PENDSVCLR_Pos 27 /*!< SCB ICSR: PENDSVCLR Position */
#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */
#define SCB_ICSR_PENDSTSET_Pos 26 /*!< SCB ICSR: PENDSTSET Position */
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
#define SCB_ICSR_PENDSTCLR_Pos 25 /*!< SCB ICSR: PENDSTCLR Position */
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
#define SCB_ICSR_ISRPREEMPT_Pos 23 /*!< SCB ICSR: ISRPREEMPT Position */
#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */
#define SCB_ICSR_ISRPENDING_Pos 22 /*!< SCB ICSR: ISRPENDING Position */
#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */
#define SCB_ICSR_VECTPENDING_Pos 12 /*!< SCB ICSR: VECTPENDING Position */
#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */
#define SCB_ICSR_VECTACTIVE_Pos 0 /*!< SCB ICSR: VECTACTIVE Position */
#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL << SCB_ICSR_VECTACTIVE_Pos) /*!< SCB ICSR: VECTACTIVE Mask */
/* SCB Application Interrupt and Reset Control Register Definitions */
#define SCB_AIRCR_VECTKEY_Pos 16 /*!< SCB AIRCR: VECTKEY Position */
#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */
#define SCB_AIRCR_VECTKEYSTAT_Pos 16 /*!< SCB AIRCR: VECTKEYSTAT Position */
#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */
#define SCB_AIRCR_ENDIANESS_Pos 15 /*!< SCB AIRCR: ENDIANESS Position */
#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */
#define SCB_AIRCR_SYSRESETREQ_Pos 2 /*!< SCB AIRCR: SYSRESETREQ Position */
#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */
#define SCB_AIRCR_VECTCLRACTIVE_Pos 1 /*!< SCB AIRCR: VECTCLRACTIVE Position */
#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */
/* SCB System Control Register Definitions */
#define SCB_SCR_SEVONPEND_Pos 4 /*!< SCB SCR: SEVONPEND Position */
#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */
#define SCB_SCR_SLEEPDEEP_Pos 2 /*!< SCB SCR: SLEEPDEEP Position */
#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */
#define SCB_SCR_SLEEPONEXIT_Pos 1 /*!< SCB SCR: SLEEPONEXIT Position */
#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */
/* SCB Configuration Control Register Definitions */
#define SCB_CCR_STKALIGN_Pos 9 /*!< SCB CCR: STKALIGN Position */
#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */
#define SCB_CCR_UNALIGN_TRP_Pos 3 /*!< SCB CCR: UNALIGN_TRP Position */
#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */
/* SCB System Handler Control and State Register Definitions */
#define SCB_SHCSR_SVCALLPENDED_Pos 15 /*!< SCB SHCSR: SVCALLPENDED Position */
#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */
/*@} end of group CMSIS_SCB */
/** \ingroup CMSIS_core_register
\defgroup CMSIS_SysTick System Tick Timer (SysTick)
\brief Type definitions for the System Timer Registers.
@{
*/
/** \brief Structure type to access the System Timer (SysTick).
*/
typedef struct
{
__IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1UL << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
#define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
/*@} end of group CMSIS_SysTick */
/** \ingroup CMSIS_core_register
\defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug)
\brief Cortex-M1 Core Debug Registers (DCB registers, SHCSR, and DFSR)
are only accessible over DAP and not via processor. Therefore
they are not covered by the Cortex-M1 header file.
@{
*/
/*@} end of group CMSIS_CoreDebug */
/** \ingroup CMSIS_core_register
\defgroup CMSIS_core_base Core Definitions
\brief Definitions for base addresses, unions, and structures.
@{
*/
/* Memory mapping of Cortex-M1 Hardware */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
/*@} */
/*******************************************************************************
* Hardware Abstraction Layer
Core Function Interface contains:
- Core NVIC Functions
- Core SysTick Functions
- Core Register Access Functions
******************************************************************************/
/** \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference
*/
/* ########################## NVIC functions #################################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_NVICFunctions NVIC Functions
\brief Functions that manage interrupts and exceptions via the NVIC.
@{
*/
/* Interrupt Priorities are WORD accessible only under ARMv6M */
/* The following MACROS handle generation of the register offset and byte masks */
#define _BIT_SHIFT(IRQn) ( (((uint32_t)(IRQn) ) & 0x03) * 8 )
#define _SHP_IDX(IRQn) ( ((((uint32_t)(IRQn) & 0x0F)-8) >> 2) )
#define _IP_IDX(IRQn) ( ((uint32_t)(IRQn) >> 2) )
/** \brief Enable External Interrupt
The function enables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->ISER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/** \brief Disable External Interrupt
The function disables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
NVIC->ICER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/** \brief Get Pending Interrupt
The function reads the pending register in the NVIC and returns the pending bit
for the specified interrupt.
\param [in] IRQn Interrupt number.
\return 0 Interrupt status is not pending.
\return 1 Interrupt status is pending.
*/
__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
return((uint32_t) ((NVIC->ISPR[0] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
/** \brief Set Pending Interrupt
The function sets the pending bit of an external interrupt.
\param [in] IRQn Interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
NVIC->ISPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/** \brief Clear Pending Interrupt
The function clears the pending bit of an external interrupt.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
NVIC->ICPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */
}
/** \brief Clear All Pending Interrupts
The function clears all pending bits.
*/
__STATIC_INLINE void NVIC_ClearAllPendingIRQ(void)
{
NVIC->ICPR[0] = 0xFFFFFFFF; /* Clear all pending interrupts */
}
/** \brief Set Interrupt Priority
The function sets the priority of an interrupt.
\note The priority cannot be set for every core interrupt.
\param [in] IRQn Interrupt number.
\param [in] priority Priority to set.
*/
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if(IRQn < 0) {
SCB->SHP[_SHP_IDX(IRQn)] = (SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
else {
NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
(((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
}
/** \brief Get Interrupt Priority
The function reads the priority of an interrupt. The interrupt
number can be positive to specify an external (device specific)
interrupt, or negative to specify an internal (core) interrupt.
\param [in] IRQn Interrupt number.
\return Interrupt Priority. Value is aligned automatically to the implemented
priority bits of the microcontroller.
*/
__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
{
if(IRQn < 0) {
return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0 system interrupts */
else {
return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */
}
/** \brief System Reset
The function initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
SCB_AIRCR_SYSRESETREQ_Msk);
__DSB(); /* Ensure completion of memory access */
while(1); /* wait until reset */
}
/*@} end of CMSIS_Core_NVICFunctions */
/* ################################## SysTick function ############################################ */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_SysTickFunctions SysTick Functions
\brief Functions that configure the System.
@{
*/
#if (__Vendor_SysTickConfig == 0)
/** \brief System Tick Configuration
The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
Counter is in free running mode to generate periodic interrupts.
\param [in] ticks Number of ticks between two interrupts.
\return 0 Function succeeded.
\return 1 Function failed.
\note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = ticks - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
#endif
/*@} end of CMSIS_Core_SysTickFunctions */
#endif /* __CORE_CM1_H_DEPENDANT */
#endif /* __CMSIS_GENERIC */
#ifdef __cplusplus
}
#endif

636
arm/hal/cmsis/core_cmFunc.h Normal file
View File

@ -0,0 +1,636 @@
/**************************************************************************//**
* @file core_cmFunc.h
* @brief CMSIS Cortex-M Core Function Access Header File
* @version V3.20
* @date 25. February 2013
*
* @note
*
******************************************************************************/
/* Copyright (c) 2009 - 2013 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 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.
---------------------------------------------------------------------------*/
#ifndef __CORE_CMFUNC_H
#define __CORE_CMFUNC_H
/* ########################### Core Function Access ########################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
@{
*/
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
/* ARM armcc specific functions */
#if (__ARMCC_VERSION < 400677)
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
#endif
/* intrinsic void __enable_irq(); */
/* intrinsic void __disable_irq(); */
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
__STATIC_INLINE uint32_t __get_CONTROL(void)
{
uint32_t __regControl __ASM("control");
return(__regControl);
}
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
__STATIC_INLINE void __set_CONTROL(uint32_t control)
{
uint32_t __regControl __ASM("control");
__regControl = control;
}
/** \brief Get IPSR Register
This function returns the content of the IPSR Register.
\return IPSR Register value
*/
__STATIC_INLINE uint32_t __get_IPSR(void)
{
uint32_t __regIPSR __ASM("ipsr");
return(__regIPSR);
}
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
__STATIC_INLINE uint32_t __get_APSR(void)
{
uint32_t __regAPSR __ASM("apsr");
return(__regAPSR);
}
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
__STATIC_INLINE uint32_t __get_xPSR(void)
{
uint32_t __regXPSR __ASM("xpsr");
return(__regXPSR);
}
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
__STATIC_INLINE uint32_t __get_PSP(void)
{
uint32_t __regProcessStackPointer __ASM("psp");
return(__regProcessStackPointer);
}
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
{
uint32_t __regProcessStackPointer __ASM("psp");
__regProcessStackPointer = topOfProcStack;
}
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
__STATIC_INLINE uint32_t __get_MSP(void)
{
uint32_t __regMainStackPointer __ASM("msp");
return(__regMainStackPointer);
}
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)
{
uint32_t __regMainStackPointer __ASM("msp");
__regMainStackPointer = topOfMainStack;
}
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
__STATIC_INLINE uint32_t __get_PRIMASK(void)
{
uint32_t __regPriMask __ASM("primask");
return(__regPriMask);
}
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
__STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
{
uint32_t __regPriMask __ASM("primask");
__regPriMask = (priMask);
}
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __enable_fault_irq __enable_fiq
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __disable_fault_irq __disable_fiq
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
__STATIC_INLINE uint32_t __get_BASEPRI(void)
{
uint32_t __regBasePri __ASM("basepri");
return(__regBasePri);
}
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
__STATIC_INLINE void __set_BASEPRI(uint32_t basePri)
{
uint32_t __regBasePri __ASM("basepri");
__regBasePri = (basePri & 0xff);
}
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask register.
\return Fault Mask register value
*/
__STATIC_INLINE uint32_t __get_FAULTMASK(void)
{
uint32_t __regFaultMask __ASM("faultmask");
return(__regFaultMask);
}
/** \brief Set Fault Mask
This function assigns the given value to the Fault Mask register.
\param [in] faultMask Fault Mask value to set
*/
__STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)
{
uint32_t __regFaultMask __ASM("faultmask");
__regFaultMask = (faultMask & (uint32_t)1);
}
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
__STATIC_INLINE uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
uint32_t __regfpscr __ASM("fpscr");
return(__regfpscr);
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
__STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
uint32_t __regfpscr __ASM("fpscr");
__regfpscr = (fpscr);
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
/* IAR iccarm specific functions */
#include <cmsis_iar.h>
#elif defined ( __TMS470__ ) /*---------------- TI CCS Compiler ------------------*/
/* TI CCS specific functions */
#include <cmsis_ccs.h>
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
/* GNU gcc specific functions */
/** \brief Enable IRQ Interrupts
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void)
{
__ASM volatile ("cpsie i" : : : "memory");
}
/** \brief Disable IRQ Interrupts
This function disables IRQ interrupts by setting the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void)
{
__ASM volatile ("cpsid i" : : : "memory");
}
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void)
{
uint32_t result;
__ASM volatile ("MRS %0, control" : "=r" (result) );
return(result);
}
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control)
{
__ASM volatile ("MSR control, %0" : : "r" (control) : "memory");
}
/** \brief Get IPSR Register
This function returns the content of the IPSR Register.
\return IPSR Register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, ipsr" : "=r" (result) );
return(result);
}
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, apsr" : "=r" (result) );
return(result);
}
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, xpsr" : "=r" (result) );
return(result);
}
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void)
{
uint32_t result;
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
return(result);
}
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
{
__ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp");
}
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void)
{
uint32_t result;
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
return(result);
}
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)
{
__ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp");
}
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void)
{
uint32_t result;
__ASM volatile ("MRS %0, primask" : "=r" (result) );
return(result);
}
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
{
__ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
}
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void)
{
__ASM volatile ("cpsie f" : : : "memory");
}
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void)
{
__ASM volatile ("cpsid f" : : : "memory");
}
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void)
{
uint32_t result;
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
return(result);
}
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value)
{
__ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory");
}
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask register.
\return Fault Mask register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void)
{
uint32_t result;
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
return(result);
}
/** \brief Set Fault Mask
This function assigns the given value to the Fault Mask register.
\param [in] faultMask Fault Mask value to set
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)
{
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory");
}
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
uint32_t result;
/* Empty asm statement works as a scheduling barrier */
__ASM volatile ("");
__ASM volatile ("VMRS %0, fpscr" : "=r" (result) );
__ASM volatile ("");
return(result);
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* Empty asm statement works as a scheduling barrier */
__ASM volatile ("");
__ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc");
__ASM volatile ("");
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
/* TASKING carm specific functions */
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all instrinsics,
* Including the CMSIS ones.
*/
#endif
/*@} end of CMSIS_Core_RegAccFunctions */
#endif /* __CORE_CMFUNC_H */

View File

@ -0,0 +1,688 @@
/**************************************************************************//**
* @file core_cmInstr.h
* @brief CMSIS Cortex-M Core Instruction Access Header File
* @version V3.20
* @date 05. March 2013
*
* @note
*
******************************************************************************/
/* Copyright (c) 2009 - 2013 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 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.
---------------------------------------------------------------------------*/
#ifndef __CORE_CMINSTR_H
#define __CORE_CMINSTR_H
/* ########################## Core Instruction Access ######################### */
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
Access to dedicated instructions
@{
*/
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
/* ARM armcc specific functions */
#if (__ARMCC_VERSION < 400677)
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
#endif
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
#define __NOP __nop
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
#define __WFI __wfi
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
#define __WFE __wfe
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
#define __SEV __sev
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
#define __ISB() __isb(0xF)
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
#define __DSB() __dsb(0xF)
/** \brief Data Memory Barrier
This function ensures the apparent order of the explicit memory operations before
and after the instruction, without ensuring their completion.
*/
#define __DMB() __dmb(0xF)
/** \brief Reverse byte order (32 bit)
This function reverses the byte order in integer value.
\param [in] value Value to reverse
\return Reversed value
*/
#define __REV __rev
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
#ifndef __NO_EMBEDDED_ASM
__attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value)
{
rev16 r0, r0
bx lr
}
#endif
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
#ifndef __NO_EMBEDDED_ASM
__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value)
{
revsh r0, r0
bx lr
}
#endif
/** \brief Rotate Right in unsigned value (32 bit)
This function Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.
\param [in] value Value to rotate
\param [in] value Number of Bits to rotate
\return Rotated value
*/
#define __ROR __ror
/** \brief Breakpoint
This function causes the processor to enter Debug state.
Debug tools can use this to investigate system state when the instruction at a particular address is reached.
\param [in] value is ignored by the processor.
If required, a debugger can use it to store additional information about the breakpoint.
*/
#define __BKPT(value) __breakpoint(value)
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
#define __RBIT __rbit
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
#define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr))
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
#define __LDREXH(ptr) ((uint16_t) __ldrex(ptr))
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
#define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr))
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXB(value, ptr) __strex(value, ptr)
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXH(value, ptr) __strex(value, ptr)
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXW(value, ptr) __strex(value, ptr)
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
#define __CLREX __clrex
/** \brief Signed Saturate
This function saturates a signed value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (1..32)
\return Saturated value
*/
#define __SSAT __ssat
/** \brief Unsigned Saturate
This function saturates an unsigned value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (0..31)
\return Saturated value
*/
#define __USAT __usat
/** \brief Count leading zeros
This function counts the number of leading zeros of a data value.
\param [in] value Value to count the leading zeros
\return number of leading zeros in value
*/
#define __CLZ __clz
#endif /* (__CORTEX_M >= 0x03) */
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
/* IAR iccarm specific functions */
#include <cmsis_iar.h>
#elif defined ( __TMS470__ ) /*---------------- TI CCS Compiler ------------------*/
/* TI CCS specific functions */
#include <cmsis_ccs.h>
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
/* GNU gcc specific functions */
/* Define macros for porting to both thumb1 and thumb2.
* For thumb1, use low register (r0-r7), specified by constrant "l"
* Otherwise, use general registers, specified by constrant "r" */
#if defined (__thumb__) && !defined (__thumb2__)
#define __CMSIS_GCC_OUT_REG(r) "=l" (r)
#define __CMSIS_GCC_USE_REG(r) "l" (r)
#else
#define __CMSIS_GCC_OUT_REG(r) "=r" (r)
#define __CMSIS_GCC_USE_REG(r) "r" (r)
#endif
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __NOP(void)
{
__ASM volatile ("nop");
}
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __WFI(void)
{
__ASM volatile ("wfi");
}
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __WFE(void)
{
__ASM volatile ("wfe");
}
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __SEV(void)
{
__ASM volatile ("sev");
}
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __ISB(void)
{
__ASM volatile ("isb");
}
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __DSB(void)
{
__ASM volatile ("dsb");
}
/** \brief Data Memory Barrier
This function ensures the apparent order of the explicit memory operations before
and after the instruction, without ensuring their completion.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __DMB(void)
{
__ASM volatile ("dmb");
}
/** \brief Reverse byte order (32 bit)
This function reverses the byte order in integer value.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV(uint32_t value)
{
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
return __builtin_bswap32(value);
#else
uint32_t result;
__ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
return(result);
#endif
}
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV16(uint32_t value)
{
uint32_t result;
__ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
return(result);
}
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __REVSH(int32_t value)
{
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
return (short)__builtin_bswap16(value);
#else
uint32_t result;
__ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
return(result);
#endif
}
/** \brief Rotate Right in unsigned value (32 bit)
This function Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.
\param [in] value Value to rotate
\param [in] value Number of Bits to rotate
\return Rotated value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
{
return (op1 >> op2) | (op1 << (32 - op2));
}
/** \brief Breakpoint
This function causes the processor to enter Debug state.
Debug tools can use this to investigate system state when the instruction at a particular address is reached.
\param [in] value is ignored by the processor.
If required, a debugger can use it to store additional information about the breakpoint.
*/
#define __BKPT(value) __ASM volatile ("bkpt "#value)
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __RBIT(uint32_t value)
{
uint32_t result;
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t *addr)
{
uint32_t result;
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
__ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) );
#else
/* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not
accepted by assembler. So has to use following less efficient pattern.
*/
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" );
#endif
return(result);
}
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint16_t __LDREXH(volatile uint16_t *addr)
{
uint32_t result;
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
__ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) );
#else
/* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not
accepted by assembler. So has to use following less efficient pattern.
*/
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" );
#endif
return(result);
}
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __LDREXW(volatile uint32_t *addr)
{
uint32_t result;
__ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) );
return(result);
}
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
uint32_t result;
__ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
return(result);
}
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
uint32_t result;
__ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
return(result);
}
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
{
uint32_t result;
__ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
return(result);
}
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE void __CLREX(void)
{
__ASM volatile ("clrex" ::: "memory");
}
/** \brief Signed Saturate
This function saturates a signed value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (1..32)
\return Saturated value
*/
#define __SSAT(ARG1,ARG2) \
({ \
uint32_t __RES, __ARG1 = (ARG1); \
__ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
__RES; \
})
/** \brief Unsigned Saturate
This function saturates an unsigned value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (0..31)
\return Saturated value
*/
#define __USAT(ARG1,ARG2) \
({ \
uint32_t __RES, __ARG1 = (ARG1); \
__ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
__RES; \
})
/** \brief Count leading zeros
This function counts the number of leading zeros of a data value.
\param [in] value Value to count the leading zeros
\return number of leading zeros in value
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __CLZ(uint32_t value)
{
uint32_t result;
__ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
#endif /* (__CORTEX_M >= 0x03) */
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
/* TASKING carm specific functions */
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
#endif
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
#endif /* __CORE_CMINSTR_H */

13
arm/itoa.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
// out must be at least 8 bytes long
inline void itoa(int val, char* out) {
for (int i = 0; i < 8; i++) {
uint8_t digit = (val >> (28 - 4 * i)) & 0xf;
if (digit < 0xa) {
out[i] = '0' + digit;
} else {
out[i] = 'a' + digit - 0xa;
}
}
}

18
arm/lock.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "aum1_cm1.h"
struct InterruptLock {
bool was_locked;
InterruptLock()
: was_locked(__get_PRIMASK() != 0) {
__disable_irq();
}
~InterruptLock() {
if (!was_locked) {
__enable_irq();
}
}
};

View File

@ -1,32 +1,83 @@
#include "async.h"
#include "aum1_cm1.h"
#include "buffer.h"
#include "crash.h"
#include "gpio.h" #include "gpio.h"
#include "timer.h"
#include "trace.h"
#include "uart.h"
namespace { namespace {
using async::AwaitableType;
[[maybe_unused]] void HandleUartRxFromIsr(void*, unsigned int) {
void sleep(int ms) { tracing::trace(tracing::TraceEvent::kUartRxCb);
for (int i = 0; i < ms; i++) { async::resume(AwaitableType::kUartRx);
// sleep for 1 ms
for (int j = 0; j < 22000; j++) {
asm("");
}
}
} }
void Uart0Isr() {
tracing::trace(tracing::TraceEvent::kUartIsr);
XUartLite_InterruptHandler(uart0);
}
void Timer0Isr() {
tracing::dump();
__builtin_trap();
}
void SetupUart() {
InitUarts();
auto* vector_table = reinterpret_cast<uint32_t*>(0x0);
vector_table[16 + HardFault_IRQn] =
reinterpret_cast<uint32_t>(crash::HardFaultHandler);
vector_table[16 + Uart0_IRQn] = reinterpret_cast<uint32_t>(Uart0Isr);
vector_table[16 + Timer0_IRQn] = reinterpret_cast<uint32_t>(Timer0Isr);
NVIC_SetPriority(Uart0_IRQn, 3);
NVIC_EnableIRQ(Uart0_IRQn);
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
XUartLite_EnableInterrupt(uart0);
}
void SetupTimer() {
NVIC_EnableIRQ(Timer0_IRQn);
timer0->SetupAsWdt(100000 * 4000);
timer0->EnableT1();
}
} // namespace } // namespace
extern "C" int main() { async::task<buffer> UartRead(int size) {
uint8_t cnt = 0; auto buff = buffer::make(size);
auto* data = reinterpret_cast<uint8_t*>(buff.data.data());
for (int i = 0; i < 256; i++) { size_t received = XUartLite_Recv(uart0, data, buff.data.size());
gpio0->data = cnt; if (received < buff.data.size()) {
cnt++; co_await async::await(AwaitableType::kUartRx);
}
sleep(125); co_return buff;
} }
auto* airc = reinterpret_cast<volatile uint32_t*>(0xe000ed0c); async::task<> echo() {
uint32_t a = *airc; while (1) {
*airc = a | 0x04; buffer buff = co_await UartRead(1);
UartSend(buff.data);
while (1) {} }
}
int main() {
SetupUart();
SetupTimer();
async::schedule(echo().h);
async::main_loop([]() {
static int cnt = 0;
timer0->Pet();
if ((cnt++ % 100000) == 0) {
ToggleLed(0);
}
});
// should never get here
} }

View File

@ -15,14 +15,16 @@ LDFLAGS = -march=armv6-m \
-Wl,--gc-sections -Os \ -Wl,--gc-sections -Os \
-Wl,--print-memory-usage -flto -Wl,--print-memory-usage -flto
includes += -Ihal/cmsis
sources += hal/lib/common/xil_assert.c sources += hal/lib/common/xil_assert.c
includes += -Ihal/lib/common includes += -Ihal/lib/common
sources += hal/uart/xuartlite.c hal/uart/xuartlite_stats.c sources += hal/uart/xuartlite.c hal/uart/xuartlite_stats.c hal/uart/xuartlite_intr.c
includes += -Ihal/uart includes += -Ihal/uart
bootloader_objects = uart.o bootloader.o vector_table.o $(sources:.c=.o) bootloader_objects = uart.o bootloader.o vector_table.o $(sources:.c=.o)
app_objects = app_init.o main.o app_objects = app_init.o crash.o main.o uart.o stdlib.o async.o trace.o $(sources:.c=.o)
CPPFLAGS += $(includes) CPPFLAGS += $(includes)
@ -37,10 +39,21 @@ bootloader.elf: $(bootloader_objects) bootloader.ld
app.elf: $(app_objects) app.ld app.elf: $(app_objects) app.ld
$(LD) -Wl,-Tapp.ld $(LDFLAGS) -o $@ $(app_objects) $(LD) -Wl,-Tapp.ld $(LDFLAGS) -o $@ $(app_objects)
%.elf: .PHONY: clean test
$(LD) -Wl,-Tapp.ld $(LDFLAGS) -o $@ $^
.PHONY: clean deps = $(app_objects:.o=.d) $(bootloader_objects:.o=.d)
clean: clean:
rm -rf *.elf *.bin $(app_objects) $(bootloader_objects) rm -rf *.elf *.bin $(tests) $(app_objects) $(bootloader_objects) $(deps)
HOSTCXX = clang++
tests = ring_buffer_test
test: $(tests)
ring_buffer_test: ring_buffer_test.cc
$(HOSTCXX) -std=c++2a -o $@ $< -lgmock -lgtest -lgtest_main
./$@
-include $(deps)

87
arm/ring_buffer.h Normal file
View File

@ -0,0 +1,87 @@
#pragma once
#include <atomic>
#include <span>
struct RingBuffer {
std::span<std::byte> buffer;
std::atomic<size_t> read_ptr = 0;
std::atomic<size_t> write_ptr = 0;
std::atomic<bool> full = 0;
bool Store(std::span<const std::byte> data) {
if (data.size() > FreeSpace()) {
return false;
}
const size_t to_copy = std::min(buffer.size() - write_ptr, data.size());
std::copy(data.begin(), data.begin() + to_copy, buffer.begin() + write_ptr);
if (to_copy < data.size()) {
std::copy(data.begin() + to_copy, data.end(), buffer.begin());
}
Push(data.size());
return true;
}
bool Load(std::span<std::byte> out) {
if (out.size() > AvailableData()) {
return false;
}
const size_t to_copy = std::min(buffer.size() - read_ptr, out.size());
std::copy(buffer.begin() + read_ptr, buffer.begin() + read_ptr + to_copy, out.begin());
if (to_copy < out.size()) {
std::copy(buffer.begin(), buffer.begin() + out.size() - to_copy, out.begin() + to_copy);
}
Pop(out.size());
return true;
}
bool Push(size_t amount) {
if (amount > FreeSpace()) {
return false;
}
write_ptr = (write_ptr + amount) % buffer.size();
if (read_ptr == write_ptr) {
full = true;
}
return true;
}
bool Pop(size_t amount) {
if (amount > AvailableData()) {
return false;
}
read_ptr = (read_ptr + amount) % buffer.size();
if (amount > 0) {
full = false;
}
return true;
}
size_t FreeSpace() const {
return buffer.size() - AvailableData();
}
size_t AvailableData() const {
if (read_ptr == write_ptr) {
return full ? buffer.size() : 0;
}
return (buffer.size() + write_ptr - read_ptr) % buffer.size();
}
uint8_t* RawReadPointer() const {
return reinterpret_cast<uint8_t*>(buffer.data() + read_ptr);
}
size_t ContiguousAvailableData() const {
if (read_ptr < write_ptr) {
return AvailableData();
}
if (full) {
return 0;
}
return buffer.size() - read_ptr;
}
};

42
arm/ring_buffer_test.cc Normal file
View File

@ -0,0 +1,42 @@
#include "ring_buffer.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <array>
using namespace ::testing;
TEST(RingBuffer, BasicStoreLoad) {
std::array<char, 20> arr;
RingBuffer rb{.buffer = std::as_writable_bytes(std::span{arr})};
std::array<char, 10> a0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::array<char, 10> a1 = {};
ASSERT_TRUE(rb.Store(std::as_bytes(std::span{a0})));
ASSERT_TRUE(rb.Load(std::as_writable_bytes(std::span{a1})));
EXPECT_THAT(a1, ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
}
TEST(RingBuffer, StoreOverflow) {
std::array<char, 10> arr;
RingBuffer rb{.buffer = std::as_writable_bytes(std::span{arr})};
std::array<char, 8> a0 = {0, 1, 2, 3, 4, 5, 6, 7};
std::array<char, 8> a1 = {};
ASSERT_TRUE(rb.Store(std::as_bytes(std::span{a0})));
ASSERT_FALSE(rb.Store(std::as_bytes(std::span{a0})));
EXPECT_EQ(rb.AvailableData(), 8);
ASSERT_TRUE(rb.Pop(7));
EXPECT_EQ(rb.AvailableData(), 1);
EXPECT_TRUE(rb.Store(std::as_bytes(std::span{a0})));
ASSERT_TRUE(rb.Load(std::as_writable_bytes(std::span{a1})));
// one byte leftover from first run, then 7 more
EXPECT_THAT(a1, ElementsAre(7, 0, 1, 2, 3, 4, 5, 6));
}

10
arm/sleep.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
inline void sleep(int ms) {
for (int i = 0; i < ms; i++) {
// sleep for 1 ms
for (int j = 0; j < 22000; j++) {
asm("");
}
}
}

53
arm/stdlib.cc Normal file
View File

@ -0,0 +1,53 @@
#include <sys/time.h>
#include <cstdint>
#include "itoa.h"
#include "lock.h"
#include "timer.h"
#include "uart.h"
extern unsigned char _heap_begin, _heap_end;
namespace {
void LogStats(unsigned char* heap) {
char number[] = "00000000\r\n";
UartSend("Program break now at 0x");
itoa(reinterpret_cast<int>(heap), number);
UartSend(number);
}
} // namespace
extern "C" void* _sbrk(int increment) {
static unsigned char* heap = &_heap_begin;
unsigned char* prev_heap = heap;
if (heap + increment >= &_heap_end) {
UartSend("Heap overflow!\r\n");
return reinterpret_cast<void*>(-1);
}
heap += increment;
LogStats(heap);
return prev_heap;
}
extern "C" int _gettimeofday(struct timeval* tv, void* tzvp) {
uint32_t ticks = timer0->GetT1Ticks();
tv->tv_sec = ticks / 100000000;
tv->tv_usec = (ticks % 100000000) / 100;
return 0;
}
extern "C" uint8_t __atomic_exchange_1(volatile void* ptr, uint8_t val,
int memorder) {
auto* dest = reinterpret_cast<volatile uint8_t*>(ptr);
bool ret;
{
InterruptLock lock;
ret = *dest;
*dest = val;
}
return ret;
}

63
arm/timer.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
struct TimerControl {
union {
struct {
uint32_t MDT0 : 1;
uint32_t UDT0 : 1;
uint32_t GENT0 : 1;
uint32_t CAPT0 : 1;
uint32_t ARHT0 : 1;
uint32_t LOAD0 : 1;
uint32_t ENIT0 : 1;
uint32_t ENT0 : 1;
uint32_t T0INT : 1;
uint32_t PWMA0 : 1;
uint32_t ENALL : 1;
uint32_t CASC : 1;
uint32_t reserved : 20;
};
uint32_t raw;
};
};
struct Timer {
volatile TimerControl TCSR0;
volatile uint32_t TLR0;
volatile uint32_t TCR0;
uint32_t _reserved;
volatile TimerControl TCSR1;
volatile uint32_t TLR1;
volatile uint32_t TCR1;
void EnableT1() {
TCSR1.ARHT0 = 1;
TCSR1.ENT0 = 1;
}
uint32_t GetT1Ticks() {
return TCR1;
}
void SetupAsWdt(uint32_t timeout_ticks) {
TLR0 = timeout_ticks;
TCSR0.LOAD0 = 1; // reset counter
TCSR0.UDT0 = 1; // count backwards from the load value
TCSR0.ENIT0 = 1; // enable interrupt
TCSR0.LOAD0 = 0; // allow counter to run
TCSR0.ENT0 = 1; // enable timer
}
void Pet() {
TCSR0.ENT0 = 0;
TCSR0.LOAD0 = 1;
TCSR0.LOAD0 = 0;
TCSR0.ENT0 = 1;
}
};
#define timer0 ((Timer*) 0x40002000)

38
arm/trace.cc Normal file
View File

@ -0,0 +1,38 @@
#include "trace.h"
#include <algorithm>
#include "itoa.h"
#include "lock.h"
#include "uart.h"
namespace tracing {
namespace {
constexpr size_t kTraceBufferSize = 256;
std::array<TraceEvent, kTraceBufferSize> buffer;
size_t write_ptr = 0;
} // namespace
void trace(int raw_event) { trace(static_cast<TraceEvent>(raw_event)); }
void trace(TraceEvent event) {
InterruptLock lock;
buffer[write_ptr] = event;
write_ptr = (write_ptr + 1) % buffer.size();
}
void dump() {
std::rotate(buffer.begin(), buffer.begin() + write_ptr, buffer.end());
char number[] = "00000000\r\n";
for (TraceEvent event : buffer) {
itoa(static_cast<int>(event), number);
UartSendCrash(number);
}
}
} // namespace tracing

17
arm/trace.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
namespace tracing {
enum class TraceEvent : uint8_t {
kUnknown = 0,
kUartIsr,
kUartRxCb,
kUartTxCb,
};
void trace(TraceEvent event);
void trace(int raw_event);
void dump();
} // namespace tracing

View File

@ -1,5 +1,9 @@
#include "uart.h" #include "uart.h"
#include "gpio.h"
#include "ring_buffer.h"
#include "trace.h"
namespace { namespace {
constexpr uintptr_t kUart0BaseAddress = 0x40001000; constexpr uintptr_t kUart0BaseAddress = 0x40001000;
@ -12,6 +16,10 @@ XUartLite_Config uart0_config = {
.DataBits = 8, .DataBits = 8,
}; };
constexpr size_t kUartTxBufferSize = 256;
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
} // namespace } // namespace
XUartLite* uart0 = &uart0_inst; XUartLite* uart0 = &uart0_inst;
@ -19,3 +27,39 @@ XUartLite* uart0 = &uart0_inst;
void InitUarts() { void InitUarts() {
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr); XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
} }
extern "C" uint8_t XUartLite_GetSR(XUartLite* InstancePtr);
#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
void UartSendCrash(std::span<const std::byte> data) {
while (data.size() > 0) {
while ((XUartLite_GetSR(uart0) & XUL_SR_TX_FIFO_EMPTY) == 0) {
}
auto* dat =
reinterpret_cast<uint8_t*>(const_cast<std::byte*>(data.data()));
uint8_t sent = XUartLite_Send(uart0, dat, data.size());
data = data.subspan(sent);
}
while ((XUartLite_GetSR(uart0) & XUL_SR_TX_FIFO_EMPTY) == 0) {
}
}
// blocking
void UartSend(std::span<const std::byte> data) {
while (!tx_ring_buffer.Store(data)) {
}
if (!XUartLite_IsSending(uart0)) {
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
}
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
tracing::trace(tracing::TraceEvent::kUartTxCb);
tx_ring_buffer.Pop(transmitted);
if (tx_ring_buffer.AvailableData() > 0) {
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
}

View File

@ -1,7 +1,22 @@
#pragma once #pragma once
#include <span>
#include <string_view>
#include "xuartlite.h" #include "xuartlite.h"
extern XUartLite* uart0; extern XUartLite* uart0;
void InitUarts(); void InitUarts();
// blocking
void UartSend(std::span<const std::byte> data);
inline void UartSend(std::string_view s) {
return UartSend(std::as_bytes(std::span{s.data(), s.size()}));
}
void UartSendCrash(std::span<const std::byte> data);
inline void UartSendCrash(std::string_view s) {
return UartSendCrash(std::as_bytes(std::span{s.data(), s.size()}));
}
void HandleUartTxFromIsr(void*, unsigned int transmitted);

View File

@ -23,7 +23,7 @@ void ResetHandler() {
} // namespace } // namespace
__attribute__((section(".vector_table"))) __attribute__((section(".vector_table"), used))
uint32_t vector_table[16] = { uint32_t vector_table[16] = {
[StackPointer] = reinterpret_cast<uint32_t>(&_initial_stack_pointer), [StackPointer] = reinterpret_cast<uint32_t>(&_initial_stack_pointer),
[Reset] = reinterpret_cast<uint32_t>(ResetHandler), [Reset] = reinterpret_cast<uint32_t>(ResetHandler),