import
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
#include <atomic.h>
|
||||
#include "cmsis.h"
|
||||
|
||||
/*
|
||||
* 注意:以下实现依赖于 CMSIS 提供的 CMSIS_LDREXW, CMSIS_STREXW, CMSIS_CLREX 等内建函数。
|
||||
* 如果使用 ARMCC,请替换为 __ldrex, __strex, __clrex。
|
||||
* 如果使用 IAR,请替换为 __LDREX, __STREX, CMSIS_CLREX。
|
||||
*/
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 内部辅助宏:编译器屏障 */
|
||||
/* ======================================================================== */
|
||||
#if defined(__GNUC__)
|
||||
#define COMPILER_BARRIER() __asm volatile ("" ::: "memory")
|
||||
#elif defined(__CC_ARM)
|
||||
#define COMPILER_BARRIER() __schedule_barrier()
|
||||
#endif
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 32位 原子操作实现 */
|
||||
/* ======================================================================== */
|
||||
|
||||
uint32_t atomic_load_32(const atomic_uint32_t *obj) {
|
||||
// Cortex-M3 普通加载即为原子加载(对齐情况下),但为了语义明确和防止重排
|
||||
uint32_t val;
|
||||
do {
|
||||
val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
} while (CMSIS_STREXW(val, (os_uint_t*)obj)); // 实际上 load 不需要 STREX,直接读即可,但为了严格内存序可加屏障
|
||||
// 更高效的 Load:
|
||||
return *obj;
|
||||
}
|
||||
|
||||
void atomic_store_32(atomic_uint32_t *obj, uint32_t desired) {
|
||||
// 简单存储在某些情况下可能不是原子的(如果涉及中断上下文竞争且非位带),
|
||||
// 但对于 M3,32位对齐写入是原子的。为了安全起见,使用独占序列确保完整性。
|
||||
uint32_t status;
|
||||
do {
|
||||
CMSIS_LDREXW((os_uint_t*)obj);
|
||||
status = CMSIS_STREXW(desired, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
}
|
||||
|
||||
uint32_t atomic_exchange_32(atomic_uint32_t *obj, uint32_t desired) {
|
||||
uint32_t old_val;
|
||||
uint32_t status;
|
||||
do {
|
||||
old_val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
status = CMSIS_STREXW(desired, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
return old_val;
|
||||
}
|
||||
|
||||
bool atomic_compare_exchange_strong_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired) {
|
||||
uint32_t current;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
current = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
if (current != *expected) {
|
||||
CMSIS_CLREX(); // 清除独占标记,避免总线锁定
|
||||
*expected = current; // 更新 expected 为当前实际值
|
||||
return false;
|
||||
}
|
||||
status = CMSIS_STREXW(desired, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool atomic_compare_exchange_weak_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired) {
|
||||
// 在 Cortex-M3 上,Weak 和 Strong 区别不大,因为硬件不支持虚假失败的优化循环通常由软件处理
|
||||
// 这里复用 Strong 逻辑,但在某些实现中 Weak 可能在第一次 STREX 失败时直接返回而不重试内部循环
|
||||
// 为了标准兼容性,我们提供标准的 CAS 行为
|
||||
return atomic_compare_exchange_strong_32(obj, expected, desired);
|
||||
}
|
||||
|
||||
uint32_t atomic_fetch_add_32(atomic_uint32_t *obj, uint32_t operand) {
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
old_val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
new_val = old_val + operand;
|
||||
status = CMSIS_STREXW(new_val, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
uint32_t atomic_fetch_sub_32(atomic_uint32_t *obj, uint32_t operand) {
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
old_val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
new_val = old_val - operand;
|
||||
status = CMSIS_STREXW(new_val, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
uint32_t atomic_fetch_and_32(atomic_uint32_t *obj, uint32_t operand) {
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
old_val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
new_val = old_val & operand;
|
||||
status = CMSIS_STREXW(new_val, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
uint32_t atomic_fetch_or_32(atomic_uint32_t *obj, uint32_t operand) {
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
old_val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
new_val = old_val | operand;
|
||||
status = CMSIS_STREXW(new_val, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
uint32_t atomic_fetch_xor_32(atomic_uint32_t *obj, uint32_t operand) {
|
||||
uint32_t old_val;
|
||||
uint32_t new_val;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
old_val = CMSIS_LDREXW((os_uint_t*)obj);
|
||||
new_val = old_val ^ operand;
|
||||
status = CMSIS_STREXW(new_val, (os_uint_t*)obj);
|
||||
} while (status != 0);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 8位 原子操作实现 (基于 32位 LDREX/STREX + 掩码) */
|
||||
/* ======================================================================== */
|
||||
|
||||
uint8_t atomic_load_8(const atomic_uint8_t *obj) {
|
||||
return *obj;
|
||||
}
|
||||
|
||||
void atomic_store_8(atomic_uint8_t *obj, uint8_t desired) {
|
||||
// 需要读取包含该字节的整个32位字,修改后写回
|
||||
volatile uint32_t *word_addr = (volatile uint32_t *)((uint32_t)obj & ~0x3);
|
||||
uint32_t shift = ((uint32_t)obj & 0x3) * 8;
|
||||
uint32_t mask = 0xFF << shift;
|
||||
|
||||
uint32_t old_word;
|
||||
uint32_t new_word;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
old_word = CMSIS_LDREXW((os_uint_t*)word_addr);
|
||||
new_word = (old_word & ~mask) | (((uint32_t)desired << shift) & mask);
|
||||
status = CMSIS_STREXW(new_word, (os_uint_t*)word_addr);
|
||||
} while (status != 0);
|
||||
}
|
||||
|
||||
uint8_t atomic_fetch_add_8(atomic_uint8_t *obj, uint8_t operand) {
|
||||
volatile uint32_t *word_addr = (volatile uint32_t *)((uint32_t)obj & ~0x3);
|
||||
uint32_t shift = ((uint32_t)obj & 0x3) * 8;
|
||||
uint32_t mask = 0xFF << shift;
|
||||
|
||||
uint32_t old_word;
|
||||
uint32_t new_word;
|
||||
uint32_t status;
|
||||
uint8_t old_val;
|
||||
|
||||
do {
|
||||
old_word = CMSIS_LDREXW((os_uint_t*)word_addr);
|
||||
old_val = (old_word >> shift) & 0xFF;
|
||||
uint8_t new_val = old_val + operand;
|
||||
new_word = (old_word & ~mask) | (((uint32_t)new_val << shift) & mask);
|
||||
status = CMSIS_STREXW(new_word, (os_uint_t*)word_addr);
|
||||
} while (status != 0);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
bool atomic_compare_exchange_strong_8(atomic_uint8_t *obj, uint8_t *expected, uint8_t desired) {
|
||||
volatile uint32_t *word_addr = (volatile uint32_t *)((uint32_t)obj & ~0x3);
|
||||
uint32_t shift = ((uint32_t)obj & 0x3) * 8;
|
||||
uint32_t mask = 0xFF << shift;
|
||||
|
||||
uint32_t old_word;
|
||||
uint32_t new_word;
|
||||
uint32_t status;
|
||||
uint8_t current_val;
|
||||
|
||||
do {
|
||||
old_word = CMSIS_LDREXW((os_uint_t*)word_addr);
|
||||
current_val = (old_word >> shift) & 0xFF;
|
||||
|
||||
if (current_val != *expected) {
|
||||
CMSIS_CLREX();
|
||||
*expected = current_val;
|
||||
return false;
|
||||
}
|
||||
|
||||
new_word = (old_word & ~mask) | (((uint32_t)desired << shift) & mask);
|
||||
status = CMSIS_STREXW(new_word, (os_uint_t*)word_addr);
|
||||
} while (status != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 位带操作实现 (绝对原子,无需 LDREX/STREX 循环) */
|
||||
/* ======================================================================== */
|
||||
|
||||
void atomic_bit_set(volatile void *addr, uint32_t bit) {
|
||||
// 向位带别名地址写入 1
|
||||
*BITBAND_PTR(addr, bit) = 1;
|
||||
}
|
||||
|
||||
void atomic_bit_clear(volatile void *addr, uint32_t bit) {
|
||||
// 向位带别名地址写入 0
|
||||
*BITBAND_PTR(addr, bit) = 0;
|
||||
}
|
||||
|
||||
uint32_t atomic_bit_read(volatile void *addr, uint32_t bit) {
|
||||
// 从位带别名地址读取,结果为 0 或 1
|
||||
return *BITBAND_PTR(addr, bit);
|
||||
}
|
||||
|
||||
void atomic_bit_toggle(volatile void *addr, uint32_t bit) {
|
||||
// 位带不支持直接 toggle,需要读-改-写,但因为是单比特映射,可以这样实现:
|
||||
// 读取当前位,然后写入相反值。由于读写的是不同的别名地址(如果是不同位)或同一地址,
|
||||
// 对于同一位的 toggle,最安全的方式还是 LDREX/STREX 或者关中断。
|
||||
// 但如果只是简单的 Set/Clear,位带是原子的。Toggle 通常不推荐在高位并发下使用位带,除非保证单线程访问该位。
|
||||
// 这里提供一个基于位带的简单 Toggle(注意:这在多核或极高并发中断下可能不安全,但在 M3 单核中断模型中,
|
||||
// 如果中断优先级管理得当,通常是安全的,或者更推荐使用 BSRR 寄存器进行 GPIO Toggle)
|
||||
|
||||
// 更推荐的 GPIO Toggle 是使用 BSRR:
|
||||
// 如果 addr 是 GPIO ODR,建议直接使用 BSRR 寄存器,而不是位带 Toggle。
|
||||
// 此处仅为演示位带读写能力,实际 Toggle 建议:
|
||||
uint32_t current = *BITBAND_PTR(addr, bit);
|
||||
*BITBAND_PTR(addr, bit) = !current;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#ifndef INCLUDED_ATOMIC_H
|
||||
#define INCLUDED_ATOMIC_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_OS_COMPILER_H
|
||||
#include <os_compiler.h>
|
||||
#endif /*INCLUDED_OS_COMPILER_H*/
|
||||
|
||||
#ifndef INCLUDED_CMSIS_H
|
||||
#include <cmsis.h>
|
||||
#endif /*INCLUDED_CMSIS_H*/
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 1. 内存序枚举 (简化版,适配 Cortex-M3 硬件特性) */
|
||||
/* ======================================================================== */
|
||||
typedef enum {
|
||||
memory_order_relaxed = 0, /* Maps to simple atomic access (no barriers) */
|
||||
memory_order_consume = 1,
|
||||
memory_order_acquire = 2, /* Usually implemented with a DMB instruction to ensure memory operations do not cross a boundary */
|
||||
memory_order_release = 3, /* Usually implemented with a DMB instruction to ensure memory operations do not cross a boundary */
|
||||
memory_order_acq_rel = 4,
|
||||
memory_order_seq_cst = 5 /* The default and safest; guarantees absolute ordering (uses DMB/DSB) */
|
||||
} atomic_memory_order;
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 2. 原子类型定义 */
|
||||
/* ======================================================================== */
|
||||
typedef volatile os_uint_t atomic_uint_t;
|
||||
typedef volatile os_int_t atomic_int_t;
|
||||
typedef volatile uint32_t atomic_uint32_t;
|
||||
typedef volatile int32_t atomic_int32_t;
|
||||
typedef volatile uint16_t atomic_uint16_t;
|
||||
typedef volatile int16_t atomic_int16_t;
|
||||
typedef volatile uint8_t atomic_uint8_t;
|
||||
typedef volatile int8_t atomic_int8_t;
|
||||
typedef volatile bool atomic_bool;
|
||||
|
||||
/* 指针原子类型 (32位系统) */
|
||||
typedef volatile void* atomic_ptr_t;
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 3. 位带操作宏 (仅适用于 SRAM 0x20000000-0x200FFFFF 和 PERIPH 0x40000000-0x400FFFFF) */
|
||||
/* ======================================================================== */
|
||||
#define BITBAND_SRAM_REF 0x20000000
|
||||
#define BITBAND_SRAM_BASE 0x22000000
|
||||
#define BITBAND_PERI_REF 0x40000000
|
||||
#define BITBAND_PERI_BASE 0x42000000
|
||||
|
||||
// 计算位带别名地址的宏
|
||||
// addr: 原始寄存器地址 (如 &GPIOA->ODR)
|
||||
// bit: 位序号 (0-31)
|
||||
#define BITBAND_ADDR(addr, bit) \
|
||||
(((uint32_t)(addr) & 0xF0000000) == 0x20000000 ? \
|
||||
(BITBAND_SRAM_BASE + ((uint32_t)(addr) - BITBAND_SRAM_REF) * 32 + (bit) * 4) : \
|
||||
(BITBAND_PERI_BASE + ((uint32_t)(addr) - BITBAND_PERI_REF) * 32 + (bit) * 4))
|
||||
|
||||
// 访问位带地址的指针宏
|
||||
#define BITBAND_PTR(addr, bit) ((volatile uint32_t *)BITBAND_ADDR(addr, bit))
|
||||
|
||||
// 示例:原子操作 GPIOA Pin 5 的输出
|
||||
// 定义一个指向位带别名地址的指针
|
||||
//#define PA5_OUT_BIT BITBAND_ADDR(&GPIOA->ODR, 5)
|
||||
|
||||
/* ======================================================================== */
|
||||
/* 4. 核心原子操作函数声明 */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* --- 基础加载与存储 --- */
|
||||
uint32_t atomic_load_32(const atomic_uint32_t *obj);
|
||||
void atomic_store_32(atomic_uint32_t *obj, uint32_t desired);
|
||||
|
||||
/* --- 交换操作, 返回交换前的值 --- */
|
||||
uint32_t atomic_exchange_32(atomic_uint32_t *obj, uint32_t desired);
|
||||
|
||||
/* --- 比较并交换 (CAS) --- */
|
||||
/* 返回 true 如果交换成功,false 如果失败 (expected 会被更新为当前值) */
|
||||
bool atomic_compare_exchange_strong_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired);
|
||||
bool atomic_compare_exchange_weak_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired);
|
||||
|
||||
/* --- 算术与位运算 (Fetch-and-Op) --- */
|
||||
/* 返回操作前的旧值 */
|
||||
uint32_t atomic_fetch_add_32(atomic_uint32_t *obj, uint32_t operand);
|
||||
uint32_t atomic_fetch_sub_32(atomic_uint32_t *obj, uint32_t operand);
|
||||
uint32_t atomic_fetch_and_32(atomic_uint32_t *obj, uint32_t operand);
|
||||
uint32_t atomic_fetch_or_32(atomic_uint32_t *obj, uint32_t operand);
|
||||
uint32_t atomic_fetch_xor_32(atomic_uint32_t *obj, uint32_t operand);
|
||||
|
||||
/* --- 8位/16位支持 (通过掩码和LDREX/STREX实现) --- */
|
||||
uint8_t atomic_load_8(const atomic_uint8_t *obj);
|
||||
void atomic_store_8(atomic_uint8_t *obj, uint8_t desired);
|
||||
uint8_t atomic_fetch_add_8(atomic_uint8_t *obj, uint8_t operand);
|
||||
bool atomic_compare_exchange_strong_8(atomic_uint8_t *obj, uint8_t *expected, uint8_t desired);
|
||||
|
||||
/* --- 位带专用原子操作 (仅用于 GPIO 或支持位带的寄存器/SRAM) --- */
|
||||
/* 设置指定位为 1 */
|
||||
void atomic_bit_set(volatile void *addr, os_uint_t bit);
|
||||
/* 清除指定位为 0 */
|
||||
void atomic_bit_clear(volatile void *addr, os_uint_t bit);
|
||||
/* 读取指定位的值 (0 或 1) */
|
||||
os_uint_t atomic_bit_read(volatile void *addr, os_uint_t bit);
|
||||
/* 翻转指定位 */
|
||||
void atomic_bit_toggle(volatile void *addr, os_uint_t bit);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#define atomic_load atomic_load_32
|
||||
#define atomic_store atomic_store_32
|
||||
#define atomic_exchange atomic_exchange_32
|
||||
#define atomic_compare_exchange_strong atomic_compare_exchange_strong_32
|
||||
#define atomic_compare_exchange_weak atomic_compare_exchange_weak_32
|
||||
#define atomic_fetch_add atomic_fetch_add_32
|
||||
#define atomic_fetch_sub atomic_fetch_sub_32
|
||||
#define atomic_fetch_and atomic_fetch_and_32
|
||||
#define atomic_fetch_or atomic_fetch_or_32
|
||||
#define atomic_fetch_xor atomic_fetch_xor_32
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*INCLUDED_ATOMIC_H*/
|
||||
@@ -0,0 +1,760 @@
|
||||
#include <cmsis.h>
|
||||
|
||||
/* ################### Compiler specific Intrinsics ########################### */
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
__ASM uint32_t CMSIS_get_IPSR(void)
|
||||
{
|
||||
mrs r0, ipsr
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
__ASM uint32_t CMSIS_get_PSP(void)
|
||||
{
|
||||
mrs r0, psp
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
__ASM void CMSIS_set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
msr psp, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
__ASM uint32_t CMSIS_get_MSP(void)
|
||||
{
|
||||
mrs r0, msp
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
__ASM void CMSIS_set_MSP(uint32_t mainStackPointer)
|
||||
{
|
||||
msr msp, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
__ASM uint32_t CMSIS_REV16(uint16_t value)
|
||||
{
|
||||
rev16 r0, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in signed short value with sign extension to integer
|
||||
*/
|
||||
__ASM int32_t CMSIS_REVSH(int16_t value)
|
||||
{
|
||||
revsh r0, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
#if (__ARMCC_VERSION < 400000)
|
||||
|
||||
/**
|
||||
* @brief Remove the exclusive lock created by ldrex
|
||||
*
|
||||
* Removes the exclusive lock which is created by ldrex.
|
||||
*/
|
||||
__ASM void CMSIS_CLREX(void)
|
||||
{
|
||||
clrex
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
__ASM uint32_t CMSIS_get_BASEPRI(void)
|
||||
{
|
||||
mrs r0, basepri
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
__ASM void CMSIS_set_BASEPRI(uint32_t basePri)
|
||||
{
|
||||
msr basepri, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
__ASM uint32_t CMSIS_get_PRIMASK(void)
|
||||
{
|
||||
mrs r0, primask
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
__ASM void CMSIS_set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
msr primask, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
__ASM uint32_t CMSIS_get_FAULTMASK(void)
|
||||
{
|
||||
mrs r0, faultmask
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
__ASM void CMSIS_set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
msr faultmask, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
__ASM uint32_t CMSIS_get_CONTROL(void)
|
||||
{
|
||||
mrs r0, control
|
||||
bx lr
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
__ASM void CMSIS_set_CONTROL(uint32_t control)
|
||||
{
|
||||
msr control, r0
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
#endif /* __ARMCC_VERSION */
|
||||
|
||||
#elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
#pragma diag_suppress=Pe940
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
uint32_t CMSIS_get_PSP(void)
|
||||
{
|
||||
__ASM("mrs r0, psp");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
void CMSIS_set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
__ASM("msr psp, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
uint32_t CMSIS_get_MSP(void)
|
||||
{
|
||||
__ASM("mrs r0, msp");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
void CMSIS_set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
__ASM("msr msp, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
uint32_t CMSIS_REV16(uint16_t value)
|
||||
{
|
||||
__ASM("rev16 r0, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse bit order of value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse bit order of value
|
||||
*/
|
||||
uint32_t CMSIS_RBIT(uint32_t value)
|
||||
{
|
||||
__ASM("rbit r0, r0");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (8 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 8 bit values)
|
||||
*/
|
||||
uint8_t CMSIS_LDREXB(uint8_t *addr)
|
||||
{
|
||||
__ASM("ldrexb r0, [r0]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (16 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 16 bit values
|
||||
*/
|
||||
uint16_t CMSIS_LDREXH(uint16_t *addr)
|
||||
{
|
||||
__ASM("ldrexh r0, [r0]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (32 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 32 bit values
|
||||
*/
|
||||
uint32_t CMSIS_LDREXW(uint32_t *addr)
|
||||
{
|
||||
__ASM("ldrex r0, [r0]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (8 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 8 bit values
|
||||
*/
|
||||
uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr)
|
||||
{
|
||||
__ASM("strexb r0, r0, [r1]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (16 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 16 bit values
|
||||
*/
|
||||
uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr)
|
||||
{
|
||||
__ASM("strexh r0, r0, [r1]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (32 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 32 bit values
|
||||
*/
|
||||
uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr)
|
||||
{
|
||||
__ASM("strex r0, r0, [r1]");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
|
||||
uint32_t CMSIS_get_IPSR(void)
|
||||
{
|
||||
__ASM("mrs r0, ipsr");
|
||||
__ASM("bx lr");
|
||||
}
|
||||
|
||||
#pragma diag_default=Pe940
|
||||
|
||||
|
||||
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
uint32_t CMSIS_get_PSP(void) __attribute__( ( naked ) );
|
||||
uint32_t CMSIS_get_PSP(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, psp\n\t"
|
||||
"MOV r0, %0 \n\t"
|
||||
"BX lr \n\t" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
void CMSIS_set_PSP(uint32_t topOfProcStack) __attribute__( ( naked ) );
|
||||
void CMSIS_set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
__ASM volatile ("MSR psp, %0\n\t"
|
||||
"BX lr \n\t" : : "r" (topOfProcStack) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
uint32_t CMSIS_get_MSP(void) __attribute__( ( naked ) );
|
||||
uint32_t CMSIS_get_MSP(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, msp\n\t"
|
||||
"MOV r0, %0 \n\t"
|
||||
"BX lr \n\t" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
void CMSIS_set_MSP(uint32_t topOfMainStack) __attribute__( ( naked ) );
|
||||
void CMSIS_set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
__ASM volatile ("MSR msp, %0\n\t"
|
||||
"BX lr \n\t" : : "r" (topOfMainStack) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
uint32_t CMSIS_get_BASEPRI(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
void CMSIS_set_BASEPRI(uint32_t value)
|
||||
{
|
||||
__ASM volatile ("MSR basepri, %0" : : "r" (value) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
uint32_t CMSIS_get_PRIMASK(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, primask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
void CMSIS_set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
__ASM volatile ("MSR primask, %0" : : "r" (priMask) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
uint32_t CMSIS_get_FAULTMASK(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
void CMSIS_set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
uint32_t CMSIS_get_CONTROL(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, control" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
void CMSIS_set_CONTROL(uint32_t control)
|
||||
{
|
||||
__ASM volatile ("MSR control, %0" : : "r" (control) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in integer value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in integer value
|
||||
*/
|
||||
uint32_t CMSIS_REV(uint32_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
uint32_t CMSIS_REV16(uint16_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in signed short value with sign extension to integer
|
||||
*/
|
||||
int32_t CMSIS_REVSH(int16_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reverse bit order of value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse bit order of value
|
||||
*/
|
||||
uint32_t CMSIS_RBIT(uint32_t value)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (8 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 8 bit value
|
||||
*/
|
||||
uint8_t CMSIS_LDREXB(uint8_t *addr)
|
||||
{
|
||||
uint8_t result=0;
|
||||
|
||||
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (16 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 16 bit values
|
||||
*/
|
||||
uint16_t CMSIS_LDREXH(uint16_t *addr)
|
||||
{
|
||||
uint16_t result=0;
|
||||
|
||||
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (32 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 32 bit values
|
||||
*/
|
||||
uint32_t CMSIS_LDREXW(uint32_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (8 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 8 bit values
|
||||
*/
|
||||
uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (16 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 16 bit values
|
||||
*/
|
||||
uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (32 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 32 bit values
|
||||
*/
|
||||
uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("strex %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
uint32_t CMSIS_get_IPSR(void)
|
||||
{
|
||||
uint32_t result=0;
|
||||
|
||||
__ASM volatile ("MRS %0, IPSR" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,739 @@
|
||||
#ifndef INCLUDED_CMSIS_H
|
||||
#define INCLUDED_CMSIS_H
|
||||
|
||||
#ifndef INCLUDED_STDINT_H
|
||||
#define INCLUDED_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif /*INCLUDED_STDINT_H*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#define __CORTEX_M (0x03) /*!< Cortex core */
|
||||
|
||||
#if defined (__ICCARM__)
|
||||
#include <intrinsics.h> /* IAR Intrinsics */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* IO definitions
|
||||
*
|
||||
* define access restrictions to peripheral registers
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define __I volatile /*!< defines 'read only' permissions */
|
||||
#else
|
||||
#define __I volatile const /*!< defines 'read only' permissions */
|
||||
#endif /* __cplusplus */
|
||||
#define __O volatile /*!< defines 'write only' permissions */
|
||||
#define __IO volatile /*!< defines 'read / write' permissions */
|
||||
|
||||
/* ################### Compiler specific Intrinsics ########################### */
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
#define __ASM __asm /*!< asm keyword for ARM Compiler */
|
||||
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
|
||||
#elif defined ( __ICCARM__ )
|
||||
#define __ASM __asm /*!< asm keyword for IAR Compiler */
|
||||
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
|
||||
#elif defined ( __GNUC__ )
|
||||
#define __ASM __asm /*!< asm keyword for GNU Compiler */
|
||||
#define __INLINE inline /*!< inline keyword for GNU Compiler */
|
||||
#elif defined ( __TASKING__ )
|
||||
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
|
||||
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
#define CMSIS_enable_fault_irq __enable_fiq
|
||||
#define CMSIS_disable_fault_irq __disable_fiq
|
||||
#define CMSIS_enable_irq __enable_irq
|
||||
#define CMSIS_disable_irq __disable_irq
|
||||
|
||||
#define CMSIS_NOP __nop
|
||||
#define CMSIS_WFI __wfi
|
||||
#define CMSIS_WFE __wfe
|
||||
#define CMSIS_SEV __sev
|
||||
#define CMSIS_ISB() __isb(0)
|
||||
#define CMSIS_DSB() __dsb(0)
|
||||
#define CMSIS_DMB() __dmb(0)
|
||||
#define CMSIS_REV __rev
|
||||
#define CMSIS_RBIT __rbit
|
||||
#define CMSIS_LDREXB(ptr) ((unsigned char ) __ldrex(ptr))
|
||||
#define CMSIS_LDREXH(ptr) ((unsigned short) __ldrex(ptr))
|
||||
#define CMSIS_LDREXW(ptr) ((unsigned int ) __ldrex(ptr))
|
||||
#define CMSIS_STREXB(value, ptr) __strex(value, ptr)
|
||||
#define CMSIS_STREXH(value, ptr) __strex(value, ptr)
|
||||
#define CMSIS_STREXW(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/* intrinsic unsigned long long __ldrexd(volatile void *ptr) */
|
||||
/* intrinsic int __strexd(unsigned long long val, volatile void *ptr) */
|
||||
/* intrinsic void __enable_irq(); */
|
||||
/* intrinsic void __disable_irq(); */
|
||||
|
||||
extern uint32_t CMSIS_get_IPSR(void);
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
extern uint32_t CMSIS_get_PSP(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
extern void CMSIS_set_PSP(uint32_t topOfProcStack);
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_MSP(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
extern void CMSIS_set_MSP(uint32_t topOfMainStack);
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
extern uint32_t CMSIS_REV16(uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in signed short value with sign extension to integer
|
||||
*/
|
||||
extern int32_t CMSIS_REVSH(int16_t value);
|
||||
|
||||
|
||||
#if (__ARMCC_VERSION < 400000)
|
||||
|
||||
/**
|
||||
* @brief Remove the exclusive lock created by ldrex
|
||||
*
|
||||
* Removes the exclusive lock which is created by ldrex.
|
||||
*/
|
||||
extern void CMSIS_CLREX(void);
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_BASEPRI(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
extern void CMSIS_set_BASEPRI(uint32_t basePri);
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_PRIMASK(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
extern void CMSIS_set_PRIMASK(uint32_t priMask);
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_FAULTMASK(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
extern void CMSIS_set_FAULTMASK(uint32_t faultMask);
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_CONTROL(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
extern void CMSIS_set_CONTROL(uint32_t control);
|
||||
|
||||
#else /* (__ARMCC_VERSION >= 400000) */
|
||||
|
||||
/**
|
||||
* @brief Remove the exclusive lock created by ldrex
|
||||
*
|
||||
* Removes the exclusive lock which is created by ldrex.
|
||||
*/
|
||||
#define CMSIS_CLREX __clrex
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
static __INLINE uint32_t CMSIS_get_BASEPRI(void)
|
||||
{
|
||||
register uint32_t __regBasePri __ASM("basepri");
|
||||
return(__regBasePri);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
static __INLINE void CMSIS_set_BASEPRI(uint32_t basePri)
|
||||
{
|
||||
register uint32_t __regBasePri __ASM("basepri");
|
||||
__regBasePri = (basePri & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
static __INLINE uint32_t CMSIS_get_PRIMASK(void)
|
||||
{
|
||||
register uint32_t __regPriMask __ASM("primask");
|
||||
return(__regPriMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
static __INLINE void CMSIS_set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
register uint32_t __regPriMask __ASM("primask");
|
||||
__regPriMask = (priMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
static __INLINE uint32_t CMSIS_get_FAULTMASK(void)
|
||||
{
|
||||
register uint32_t __regFaultMask __ASM("faultmask");
|
||||
return(__regFaultMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
static __INLINE void CMSIS_set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
register uint32_t __regFaultMask __ASM("faultmask");
|
||||
__regFaultMask = (faultMask & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
static __INLINE uint32_t CMSIS_get_CONTROL(void)
|
||||
{
|
||||
register uint32_t __regControl __ASM("control");
|
||||
return(__regControl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
static __INLINE void CMSIS_set_CONTROL(uint32_t control)
|
||||
{
|
||||
register uint32_t __regControl __ASM("control");
|
||||
__regControl = control;
|
||||
}
|
||||
|
||||
#endif /* __ARMCC_VERSION */
|
||||
|
||||
|
||||
|
||||
#elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
|
||||
#define CMSIS_enable_irq __enable_interrupt /*!< global Interrupt enable */
|
||||
#define CMSIS_disable_irq __disable_interrupt /*!< global Interrupt disable */
|
||||
|
||||
static __INLINE void CMSIS_enable_fault_irq() { __ASM ("cpsie f"); }
|
||||
static __INLINE void CMSIS_disable_fault_irq() { __ASM ("cpsid f"); }
|
||||
|
||||
#define CMSIS_NOP __no_operation /*!< no operation intrinsic in IAR Compiler */
|
||||
static __INLINE void CMSIS_WFI() { __ASM ("wfi"); }
|
||||
static __INLINE void CMSIS_WFE() { __ASM ("wfe"); }
|
||||
static __INLINE void CMSIS_SEV() { __ASM ("sev"); }
|
||||
static __INLINE void CMSIS_CLREX() { __ASM ("clrex"); }
|
||||
|
||||
/* intrinsic void CMSIS_ISB(void) */
|
||||
/* intrinsic void CMSIS_DSB(void) */
|
||||
/* intrinsic void CMSIS_DMB(void) */
|
||||
/* intrinsic void CMSIS_set_PRIMASK(); */
|
||||
/* intrinsic void CMSIS_get_PRIMASK(); */
|
||||
/* intrinsic void CMSIS_set_FAULTMASK(); */
|
||||
/* intrinsic void CMSIS_get_FAULTMASK(); */
|
||||
/* intrinsic uint32_t CMSIS_REV(uint32_t value); */
|
||||
/* intrinsic uint32_t CMSIS_REVSH(uint32_t value); */
|
||||
/* intrinsic unsigned long __STREX(unsigned long, unsigned long); */
|
||||
/* intrinsic unsigned long __LDREX(unsigned long *); */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
extern uint32_t CMSIS_get_PSP(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
extern void CMSIS_set_PSP(uint32_t topOfProcStack);
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_MSP(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
extern void CMSIS_set_MSP(uint32_t topOfMainStack);
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
extern uint32_t CMSIS_REV16(uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Reverse bit order of value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse bit order of value
|
||||
*/
|
||||
extern uint32_t CMSIS_RBIT(uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (8 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 8 bit values)
|
||||
*/
|
||||
extern uint8_t CMSIS_LDREXB(uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (16 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 16 bit values
|
||||
*/
|
||||
extern uint16_t CMSIS_LDREXH(uint16_t *addr);
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (32 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 32 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_LDREXW(uint32_t *addr);
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (8 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 8 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (16 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 16 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr);
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (32 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 32 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr);
|
||||
|
||||
|
||||
|
||||
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
static __INLINE void CMSIS_enable_irq() { __ASM volatile ("cpsie i"); }
|
||||
static __INLINE void CMSIS_disable_irq() { __ASM volatile ("cpsid i"); }
|
||||
|
||||
static __INLINE void CMSIS_enable_fault_irq() { __ASM volatile ("cpsie f"); }
|
||||
static __INLINE void CMSIS_disable_fault_irq() { __ASM volatile ("cpsid f"); }
|
||||
|
||||
static __INLINE void CMSIS_NOP() { __ASM volatile ("nop"); }
|
||||
static __INLINE void CMSIS_WFI() { __ASM volatile ("wfi"); }
|
||||
static __INLINE void CMSIS_WFE() { __ASM volatile ("wfe"); }
|
||||
static __INLINE void CMSIS_SEV() { __ASM volatile ("sev"); }
|
||||
static __INLINE void CMSIS_ISB() { __ASM volatile ("isb"); }
|
||||
static __INLINE void CMSIS_DSB() { __ASM volatile ("dsb"); }
|
||||
static __INLINE void CMSIS_DMB() { __ASM volatile ("dmb"); }
|
||||
static __INLINE void CMSIS_CLREX() { __ASM volatile ("clrex"); }
|
||||
|
||||
extern uint32_t CMSIS_get_IPSR(void);
|
||||
|
||||
/**
|
||||
* @brief Return the Process Stack Pointer
|
||||
*
|
||||
* @return ProcessStackPointer
|
||||
*
|
||||
* Return the actual process stack pointer
|
||||
*/
|
||||
extern uint32_t CMSIS_get_PSP(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Process Stack Pointer
|
||||
*
|
||||
* @param topOfProcStack Process Stack Pointer
|
||||
*
|
||||
* Assign the value ProcessStackPointer to the MSP
|
||||
* (process stack pointer) Cortex processor register
|
||||
*/
|
||||
extern void CMSIS_set_PSP(uint32_t topOfProcStack);
|
||||
|
||||
/**
|
||||
* @brief Return the Main Stack Pointer
|
||||
*
|
||||
* @return Main Stack Pointer
|
||||
*
|
||||
* Return the current value of the MSP (main stack pointer)
|
||||
* Cortex processor register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_MSP(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Main Stack Pointer
|
||||
*
|
||||
* @param topOfMainStack Main Stack Pointer
|
||||
*
|
||||
* Assign the value mainStackPointer to the MSP
|
||||
* (main stack pointer) Cortex processor register
|
||||
*/
|
||||
extern void CMSIS_set_MSP(uint32_t topOfMainStack);
|
||||
|
||||
/**
|
||||
* @brief Return the Base Priority value
|
||||
*
|
||||
* @return BasePriority
|
||||
*
|
||||
* Return the content of the base priority register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_BASEPRI(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Base Priority value
|
||||
*
|
||||
* @param basePri BasePriority
|
||||
*
|
||||
* Set the base priority register
|
||||
*/
|
||||
extern void CMSIS_set_BASEPRI(uint32_t basePri);
|
||||
|
||||
/**
|
||||
* @brief Return the Priority Mask value
|
||||
*
|
||||
* @return PriMask
|
||||
*
|
||||
* Return state of the priority mask bit from the priority mask register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_PRIMASK(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Priority Mask value
|
||||
*
|
||||
* @param priMask PriMask
|
||||
*
|
||||
* Set the priority mask bit in the priority mask register
|
||||
*/
|
||||
extern void CMSIS_set_PRIMASK(uint32_t priMask);
|
||||
|
||||
/**
|
||||
* @brief Return the Fault Mask value
|
||||
*
|
||||
* @return FaultMask
|
||||
*
|
||||
* Return the content of the fault mask register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_FAULTMASK(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Fault Mask value
|
||||
*
|
||||
* @param faultMask faultMask value
|
||||
*
|
||||
* Set the fault mask register
|
||||
*/
|
||||
extern void CMSIS_set_FAULTMASK(uint32_t faultMask);
|
||||
|
||||
/**
|
||||
* @brief Return the Control Register value
|
||||
*
|
||||
* @return Control value
|
||||
*
|
||||
* Return the content of the control register
|
||||
*/
|
||||
extern uint32_t CMSIS_get_CONTROL(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Control Register value
|
||||
*
|
||||
* @param control Control value
|
||||
*
|
||||
* Set the control register
|
||||
*/
|
||||
extern void CMSIS_set_CONTROL(uint32_t control);
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in integer value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in integer value
|
||||
*/
|
||||
extern uint32_t CMSIS_REV(uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in unsigned short value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in unsigned short value
|
||||
*/
|
||||
extern uint32_t CMSIS_REV16(uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse byte order in signed short value with sign extension to integer
|
||||
*/
|
||||
extern int32_t CMSIS_REVSH(int16_t value);
|
||||
|
||||
/**
|
||||
* @brief Reverse bit order of value
|
||||
*
|
||||
* @param value value to reverse
|
||||
* @return reversed value
|
||||
*
|
||||
* Reverse bit order of value
|
||||
*/
|
||||
extern uint32_t CMSIS_RBIT(uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (8 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 8 bit value
|
||||
*/
|
||||
extern uint8_t CMSIS_LDREXB(uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (16 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 16 bit values
|
||||
*/
|
||||
extern uint16_t CMSIS_LDREXH(uint16_t *addr);
|
||||
|
||||
/**
|
||||
* @brief LDR Exclusive (32 bit)
|
||||
*
|
||||
* @param *addr address pointer
|
||||
* @return value of (*address)
|
||||
*
|
||||
* Exclusive LDR command for 32 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_LDREXW(uint32_t *addr);
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (8 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 8 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (16 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 16 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr);
|
||||
|
||||
/**
|
||||
* @brief STR Exclusive (32 bit)
|
||||
*
|
||||
* @param value value to store
|
||||
* @param *addr address pointer
|
||||
* @return successful / failed
|
||||
*
|
||||
* Exclusive STR command for 32 bit values
|
||||
*/
|
||||
extern uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr);
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
#endif /*INCLUDED_CMSIS_H*/
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <dwt_delay.h>
|
||||
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
|
||||
//定义需使能位
|
||||
#define DEM_CR_TRCENA (1u<<24)
|
||||
#define DWT_CR_CYCCNTENA (1u<<0)
|
||||
|
||||
|
||||
//DWT init
|
||||
void DWT_Init(void)
|
||||
{
|
||||
DEM_CR |= (uint32_t)DEM_CR_TRCENA;
|
||||
DWT_CYCCNT = (uint32_t)0u;
|
||||
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
|
||||
}
|
||||
|
||||
void DWT_DelayUs(uint32_t us)
|
||||
{
|
||||
uint32_t start = DWT_CYCCNT;
|
||||
uint32_t cycles = us * (SystemCoreClock / 1000000);
|
||||
uint32_t elapsed;
|
||||
|
||||
while (1) {
|
||||
uint32_t current = DWT_CYCCNT;
|
||||
if (current >= start) {
|
||||
elapsed = current - start;
|
||||
} else {
|
||||
elapsed = (0xFFFFFFFFu - start) + current; // 处理溢出
|
||||
}
|
||||
if (elapsed >= cycles) break;
|
||||
}
|
||||
}
|
||||
|
||||
void DWT_DelayMs(uint32_t ms)
|
||||
{
|
||||
for (uint32_t i = 0; i < ms; i++) {
|
||||
DWT_DelayUs(1000);
|
||||
}
|
||||
}
|
||||
|
||||
//使用DWT测量函数运行时间
|
||||
float DTW_Time_DiffMs(volatile uint32_t start, volatile uint32_t stop)
|
||||
{
|
||||
uint32_t diff;
|
||||
if(stop > start)
|
||||
diff = stop - start;
|
||||
else
|
||||
diff = stop + 0XFFFFFFFFu - start;
|
||||
return (diff / (SystemCoreClock/1000));
|
||||
}
|
||||
|
||||
float DTW_Time_DiffUs(volatile uint32_t start, volatile uint32_t stop)
|
||||
{
|
||||
uint32_t diff;
|
||||
if(stop > start)
|
||||
diff = stop - start;
|
||||
else
|
||||
diff = stop + 0XFFFFFFFFu - start;
|
||||
return (diff / (SystemCoreClock/1000000));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef INCLUDED_DWT_DELAY_H
|
||||
#define INCLUDED_DWT_DELAY_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_OS_COMPILER_H
|
||||
#include <os_compiler.h>
|
||||
#endif /*INCLUDED_OS_COMPILER_H*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
//寄存器基地址
|
||||
#define DWT_CR *(uint32_t*)0xE0001000
|
||||
#define DWT_CYCCNT *(uint32_t*)0xE0001004
|
||||
#define DEM_CR *(uint32_t*)0xE000EDFC
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
uint32_t DWT_Get(void){
|
||||
return ((uint32_t )DWT_CYCCNT);
|
||||
}
|
||||
|
||||
void DWT_Init(void);
|
||||
|
||||
void DWT_DelayUs(uint32_t us);
|
||||
|
||||
void DWT_DelayMs(uint32_t ms);
|
||||
|
||||
float DTW_Time_DiffMs(volatile uint32_t start, volatile uint32_t stop);
|
||||
|
||||
float DTW_Time_DiffUs(volatile uint32_t start, volatile uint32_t stop);
|
||||
|
||||
#endif /*INCLUDED_DWT_DELAY_H*/
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <os_loopdelay.h>
|
||||
|
||||
#if defined (__CC_ARM) /*!< ARM Compiler */
|
||||
__asm void os_loop_delay(unsigned long ulCount)
|
||||
{
|
||||
subs r0, #1;
|
||||
bne os_loop_delay;
|
||||
bx lr;
|
||||
}
|
||||
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
|
||||
void os_loop_delay(unsigned long ulCount)
|
||||
{
|
||||
__asm(" subs r0, #1 \n"
|
||||
" bne.n os_loop_delay \n"
|
||||
" bx lr");
|
||||
}
|
||||
|
||||
#elif defined (__GNUC__) /*!< GNU Compiler */
|
||||
__attribute__((naked))
|
||||
void os_loop_delay(unsigned long ulCount){
|
||||
__asm(" subs r0, #1 \n"
|
||||
" bne os_loop_delay \n"
|
||||
" bx lr");
|
||||
}
|
||||
#endif /* __CC_ARM */
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef INCLUDED_OS_LOOPDELAY_H
|
||||
#define INCLUDED_OS_LOOPDELAY_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#define OS_LOOP_DELAY_US(n) (n * SystemCoreClock/3000000)
|
||||
#define OS_LOOP_DELAY_MS(n) (n * SystemCoreClock/3000)
|
||||
#define OS_LOOP_DELAY_S(n) (n * SystemCoreClock/3)
|
||||
|
||||
/*
|
||||
|
||||
72Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/72us=1/24us
|
||||
|
||||
SystemCoreClock=72000000
|
||||
|
||||
us级延时,延时n微秒
|
||||
LoopDelay(n*(SystemCoreClock/3000000));
|
||||
|
||||
ms级延时,延时n毫秒
|
||||
LoopDelay(n*(SystemCoreClock/3000));
|
||||
|
||||
m级延时,延时n秒
|
||||
LoopDelay(n*(SystemCoreClock/3));
|
||||
*/
|
||||
|
||||
void os_loop_delay(unsigned long ulCount);
|
||||
|
||||
#define OS_LoopDelayUS(n) os_loop_delay(OS_LOOP_DELAY_US(n))
|
||||
#define OS_LoopDelayMS(n) os_loop_delay(OS_LOOP_DELAY_MS(n))
|
||||
#define OS_LoopDelayS(n) os_loop_delay(OS_LOOP_DELAY_S(n))
|
||||
|
||||
#endif /*INCLUDED_OS_LOOPDELAY_H*/
|
||||
@@ -0,0 +1 @@
|
||||
#include <os_mpu.h>
|
||||
@@ -0,0 +1,250 @@
|
||||
#ifndef INCLUDED_OS_MPU_H
|
||||
#define INCLUDED_OS_MPU_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_OS_COMPILER_H
|
||||
#include <os_compiler.h>
|
||||
#endif /*INCLUDED_OS_COMPILER_H*/
|
||||
|
||||
#ifndef INCLUDED_CMSIS_H
|
||||
#include <cmsis.h>
|
||||
#endif /*INCLUDED_CMSIS_H*/
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
typedef struct {
|
||||
os_uintptr_t TYPE; /* 提供 MPU 信息 */
|
||||
os_uintptr_t CTRL; /* MPU使能/禁止的背景区域控制 */
|
||||
os_uintptr_t RNR; /* 选择待配置的MPU区域 */
|
||||
os_uintptr_t RBAR; /* 定义MPU区域的基地址 */
|
||||
os_uintptr_t RASR; /* 定义MPU区域的属性和大小 */
|
||||
os_uintptr_t RBAR_A1; /* RBAR的别名 */
|
||||
os_uintptr_t RBSR_A1; /* RASR的别名 */
|
||||
os_uintptr_t RBAR_A2; /* RBAR的别名 */
|
||||
os_uintptr_t RBSR_A2; /* RASR的别名 */
|
||||
os_uintptr_t RBAR_A3; /* RBAR的别名 */
|
||||
os_uintptr_t RBSR_A3; /* RASR的别名 */
|
||||
}os_mpu_t;
|
||||
|
||||
#define OS_MPU ((os_mpu_t*)(0xE000ED90u))
|
||||
|
||||
OS_PACKED_STRUCT(os_mpu_type_t){
|
||||
os_uint_t SEPARATE:1;
|
||||
os_uint_t RESERVED_0:7;
|
||||
os_uint_t DREGION:8;
|
||||
os_uint_t IREGION:8;
|
||||
os_uint_t RESERVED_1:8;
|
||||
}os_mpu_type_t;
|
||||
|
||||
OS_PACKED_STRUCT(os_mpu_ctrl_t){
|
||||
os_uint_t ENABLE:1;
|
||||
os_uint_t HFNMIENA:1;
|
||||
os_uint_t PRIVDEFENA:1;
|
||||
os_uint_t RESERVED:29;
|
||||
}os_mpu_ctrl_t;
|
||||
|
||||
OS_PACKED_STRUCT(os_mpu_rnr_t){
|
||||
os_uint_t REGION:8;
|
||||
os_uint_t RESERVED:24;
|
||||
}os_mpu_rnr_t;
|
||||
|
||||
OS_PACKED_STRUCT(os_mpu_rbar_t){
|
||||
os_uint_t REGION:4;
|
||||
os_uint_t VALID:1;
|
||||
os_uint_t ADDR:27;
|
||||
}os_mpu_rbar_t;
|
||||
|
||||
OS_PACKED_STRUCT(os_mpu_rasr_t){
|
||||
os_uint_t ENABLE:1; /* 区域使能 */
|
||||
os_uint_t SIZE:5; /* MPU保护区域大小 */
|
||||
os_uint_t RESERVED_0:2;
|
||||
os_uint_t SRD:8; /* 子区域禁止 */
|
||||
os_uint_t B:1; /* 可缓冲 */
|
||||
os_uint_t C:1; /* 可缓存 */
|
||||
os_uint_t S:1; /* 可共用 */
|
||||
os_uint_t TEX:3; /* 类型展开域 */
|
||||
os_uint_t RESERVED_1:2; /* 保留 */
|
||||
os_uint_t AP:3; /* 数据访问允许域 */
|
||||
os_uint_t RESERVED_2:1; /* 保留 */
|
||||
os_uint_t XN:1; /* 指令访问禁止(1=禁止该区域的取值, 非要这么做会引发存储器管理错误) */
|
||||
os_uint_t RESERVED_3:3; /* 保留 */
|
||||
}os_mpu_rasr_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
#define OS_MPU_RASR_ENABLE_Pos 0
|
||||
#define OS_MPU_RASR_SIZE_Pos 1
|
||||
#define OS_MPU_RASR_SRD_Pos 8
|
||||
#define OS_MPU_RASR_B_Pos 16
|
||||
#define OS_MPU_RASR_C_Pos 17
|
||||
#define OS_MPU_RASR_S_Pos 18
|
||||
#define OS_MPU_RASR_TEX_Pos 19
|
||||
#define OS_MPU_RASR_AP_Pos 24
|
||||
#define OS_MPU_RASR_XN_Pos 28
|
||||
|
||||
|
||||
#define OS_MPU_DEFS_RASR_SIZE_32B (0x04<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_64B (0x05<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_128B (0x06<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_256B (0x07<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_512B (0x08<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_1KB (0x09<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_2KB (0x0A<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_4KB (0x0B<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_8KB (0x0C<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_16KB (0x0D<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_32KB (0x0E<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_64KB (0x0F<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_128KB (0x10<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_256KB (0x11<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_512KB (0x12<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_1MB (0x13<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_2MB (0x14<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_4MB (0x15<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_8MB (0x16<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_16MB (0x17<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_32MB (0x18<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_64MB (0x19<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_128MB (0x1A<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_256MB (0x1B<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_512MB (0x1C<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_1GB (0x1D<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_2GB (0x1E<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_DEFS_RASR_SIZE_4GB (0x1F<<OS_MPU_RASR_SIZE_Pos)
|
||||
|
||||
|
||||
#define OS_MPU_DEFS_RASR_AP_NO_ACCESS (0x0 << OS_MPU_RASR_AP_Pos)
|
||||
#define OS_MPU_DEFS_RASR_AP_PRIV_RW (0x1 << OS_MPU_RASR_AP_Pos)
|
||||
#define OS_MPU_DEFS_RASR_AP_PRIV_RW_USER_RO (0x2 << OS_MPU_RASR_AP_Pos)
|
||||
#define OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS (0x3 << OS_MPU_RASR_AP_Pos)
|
||||
#define OS_MPU_DEFS_RASR_AP_PRIV_RO (0x5 << OS_MPU_RASR_AP_Pos)
|
||||
#define OS_MPU_DEFS_RASR_AP_RO (0x6 << OS_MPU_RASR_AP_Pos)
|
||||
|
||||
#define OS_MPU_RASR_B_Msk (1<<OS_MPU_RASR_B_Pos)
|
||||
#define OS_MPU_RASR_C_Msk (1<<OS_MPU_RASR_C_Pos)
|
||||
#define OS_MPU_RASR_S_Msk (1<<OS_MPU_RASR_S_Pos)
|
||||
#define OS_MPU_RASR_TEX_Msk (0x7<<OS_MPU_RASR_TEX_Pos)
|
||||
#define OS_MPU_RASR_SIZE_Msk (0x1f<<OS_MPU_RASR_SIZE_Pos)
|
||||
#define OS_MPU_RASR_ENABLE_Msk (0x1<<OS_MPU_RASR_ENABLE_Pos)
|
||||
#define OS_MPU_RASR_XN_Msk (0x1<<OS_MPU_RASR_XN_Pos)
|
||||
#define OS_MPU_RASR_SRD_Msk (0xff<<OS_MPU_RASR_SRD_Pos)
|
||||
|
||||
#define OS_MPU_DEFS_RASR_SRD_DISABLE (0x00 << OS_MPU_RASR_SRD_Pos)
|
||||
|
||||
#define OS_MPU_DEFS_RASR_TEX_LEVEL0 (0x0 << OS_MPU_RASR_TEX_Pos)
|
||||
#define OS_MPU_DEFS_RASR_TEX_LEVEL1 (0x1 << OS_MPU_RASR_TEX_Pos)
|
||||
#define OS_MPU_DEFS_RASR_TEX_LEVEL2 (0x2 << OS_MPU_RASR_TEX_Pos)
|
||||
|
||||
#define OS_MPU_DEFS_NORMAL_MEMORY_WT (OS_MPU_RASR_C_Msk)
|
||||
#define OS_MPU_DEFS_NORMAL_MEMORY_WB (OS_MPU_RASR_C_Msk | OS_MPU_RASR_B_Msk)
|
||||
#define OS_MPU_DEFS_NORMAL_MEMORY_SHARED_WT (OS_MPU_RASR_C_Msk | OS_MPU_RASR_S_Msk)
|
||||
#define OS_MPU_DEFS_NORMAL_MEMORY_SHARED_WB (OS_MPU_DEFS_NORMAL_MEMORY_WB | OS_MPU_RASR_S_Msk)
|
||||
#define OS_MPU_DEFS_SHARED_DEVICE (OS_MPU_RASR_B_Msk | OS_MPU_RASR_S_Msk)
|
||||
#define OS_MPU_DEFS_EXTERNAL_MEMORY (OS_MPU_RASR_C_Msk | OS_MPU_RASR_B_Msk | OS_MPU_RASR_S_Msk)
|
||||
#define OS_MPU_DEFS_STRONGLY_ORDERED_DEVICE (0x0)
|
||||
|
||||
#define OS_MPU_ACCESS_CACHEABLE (OS_MPU_RASR_C_Msk)
|
||||
#define OS_MPU_ACCESS_BUFFERABLE (OS_MPU_RASR_B_Msk)
|
||||
#define OS_MPU_ACCESS_SHAREABLE (OS_MPU_RASR_S_Msk)
|
||||
|
||||
#define OS_MPU_ACCESS_NOT_CACHEABLE (0x00 << OS_MPU_RASR_C_Pos)
|
||||
#define OS_MPU_ACCESS_NOT_BUFFERABLE (0x00 << OS_MPU_RASR_B_Pos)
|
||||
#define OS_MPU_ACCESS_NOT_SHAREABLE (0x00 << OS_MPU_RASR_S_Pos)
|
||||
|
||||
#define OS_MPU_CTRL_ENABLE_Pos (0)
|
||||
#define OS_MPU_CTRL_HFNMIENA_Pos (1)
|
||||
#define OS_MPU_CTRL_PRIVDEFENA_Pos (2)
|
||||
|
||||
#define OS_MPU_CTRL_ENABLE_Msk (1<<OS_MPU_CTRL_ENABLE_Pos)
|
||||
#define OS_MPU_CTRL_HFNMIENA_Msk (1<<OS_MPU_CTRL_HFNMIENA_Pos)
|
||||
#define OS_MPU_CTRL_PRIVDEFENA_Msk (1<<OS_MPU_CTRL_PRIVDEFENA_Pos)
|
||||
|
||||
|
||||
#define OS_MPU_RBAR_REGION_Pos 0
|
||||
#define OS_MPU_RBAR_VALID_Pos 4
|
||||
|
||||
#define OS_MPU_RBAR_VALID_Msk (1<<OS_MPU_RBAR_VALID_Pos)
|
||||
#define OS_MPU_RBAR_REGION_Msk (0xf << OS_MPU_RBAR_REGION_Pos)
|
||||
|
||||
#define OS_MPU_DEFS_RBAR_VALID_DISABLE (0<<OS_MPU_RBAR_VALID_Pos)
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void os_mpu_enable(os_uint_t options){
|
||||
OS_MPU->CTRL = OS_MPU_CTRL_ENABLE_Msk | options;
|
||||
CMSIS_DSB();
|
||||
CMSIS_ISB();
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void os_mpu_disable(void){
|
||||
CMSIS_DMB();
|
||||
OS_MPU->CTRL = 0;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void os_mpu_region_disable(os_uint_t region_num){
|
||||
OS_MPU->RNR = region_num;
|
||||
OS_MPU->RBAR = 0;
|
||||
OS_MPU->RASR = 0;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void os_mpu_region_config(os_uint_t region_num, os_uintptr_t addr, os_size_t size, os_uint_t attribute){
|
||||
OS_MPU->RNR = region_num;
|
||||
OS_MPU->RBAR = addr;
|
||||
OS_MPU->RASR = ((size << OS_MPU_RASR_SIZE_Pos) & OS_MPU_RASR_SIZE_Msk) | attribute;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* Example */
|
||||
|
||||
#if 0
|
||||
|
||||
/* 以下是 MPU 配置示例 */
|
||||
|
||||
int mpu_setup(void){
|
||||
if(OS_MPU->TYPE == 0){ return 1; /* 错误 */ }
|
||||
os_mpu_disable();
|
||||
/* 0 - Flash */
|
||||
os_mpu_region_config(0
|
||||
, 0x08000000
|
||||
, OS_MPU_DEFS_RASR_SIZE_1MB
|
||||
, OS_MPU_DEFS_NORMAL_MEMORY_WT | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk);
|
||||
/* 1 - SRAM */
|
||||
os_mpu_region_config(1
|
||||
, 0x20000000
|
||||
, OS_MPU_DEFS_RASR_SIZE_128KB
|
||||
, OS_MPU_DEFS_NORMAL_MEMORY_WT | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk);
|
||||
|
||||
/* 2 - GPIOD */
|
||||
os_mpu_region_config(2
|
||||
, GPIOD_BASE
|
||||
, OS_MPU_DEFS_RASR_SIZE_1KB
|
||||
, OS_MPU_DEFS_SHARED_DEVICE | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk);
|
||||
|
||||
/* 3 - 复位时钟 */
|
||||
os_mpu_region_config(3
|
||||
, RCC_BASE
|
||||
, OS_MPU_DEFS_RASR_SIZE_1KB
|
||||
, OS_MPU_DEFS_SHARED_DEVICE | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk);
|
||||
|
||||
os_mpu_region_disable(4);
|
||||
os_mpu_region_disable(5);
|
||||
os_mpu_region_disable(6);
|
||||
os_mpu_region_disable(7);
|
||||
|
||||
os_mpu_enable(0); /* 使能MPU,无需其它设置 */
|
||||
return 0; /* 无错误 */
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
#endif /*INCLUDED_OS_MPU_H*/
|
||||
@@ -0,0 +1,247 @@
|
||||
#include "os_port.h"
|
||||
#include "os_stack.h"
|
||||
#include "os_macros.h"
|
||||
#include "os_align.h"
|
||||
#include "cmsis.h"
|
||||
#include "os_compiler.h"
|
||||
#include "os_systick.h"
|
||||
#include "os_sched.h"
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#define OS_PORT_SYSCALL_ID 0x00
|
||||
#define OS_PORT_SYSCALL_OP_SAVE_DISABLE_IRQ 0x00
|
||||
#define OS_PORT_SYSCALL_OP_RESTORE_IRQ 0x01
|
||||
#define OS_PORT_SYSCALL_OP_SCHED 0x02
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
volatile os_uint_t svc_exc_return;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
int is_cpu_in_privilege(void){
|
||||
// 1. 检查是否在中断/异常中 (IPSR != 0 表示 Handler 模式)
|
||||
if ( CMSIS_get_IPSR() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2. 如果在 Thread 模式,检查 CONTROL 寄存器
|
||||
return ((CMSIS_get_CONTROL() & 0x01) == 0)?1:0;
|
||||
}
|
||||
|
||||
#if defined(__CC_ARM) /* armcc (AC5) */
|
||||
|
||||
#define SVC_CALL_ARGS0(num, type, name) \
|
||||
__svc(num) type name(void);
|
||||
|
||||
#define SVC_CALL_ARGS1(num, type, name, a0) \
|
||||
__svc(num) type name(os_uintptr_t a0);
|
||||
|
||||
#define SVC_CALL_ARGS2(num, type, name, a0, a1) \
|
||||
__svc(num) type name(os_uintptr_t a0, os_uintptr_t a1);
|
||||
|
||||
#define SVC_CALL_ARGS3(num, type, name, a0, a1, a2) \
|
||||
__svc(num) type name(os_uintptr_t a0, os_uintptr_t a1, os_uintptr_t a2);
|
||||
|
||||
#define SVC_CALL_ARGS4(num, type, name, a0, a1, a2, a3) \
|
||||
__svc(num) type name(os_uintptr_t a0, os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3);
|
||||
|
||||
|
||||
#elif defined(__GNUC__) /* gcc */
|
||||
|
||||
#define SVC_CALL_ARGS0(num, type, name) \
|
||||
static type name(void) { \
|
||||
register os_uintptr_t r0 __asm__("r0")=0; \
|
||||
__asm__ volatile ("svc " #num : : : "memory"); \
|
||||
return (type)r0; \
|
||||
}
|
||||
|
||||
#define SVC_CALL_ARGS1(num, type, name, a1) \
|
||||
OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1) { \
|
||||
register os_uintptr_t r0 __asm__("r0") = a1; \
|
||||
__asm__ volatile ("svc " #num :"=r"(r0):"r"(r0) : "memory"); \
|
||||
return (type)r0; \
|
||||
}
|
||||
|
||||
#define SVC_CALL_ARGS2(num, type, name, a1, a2) \
|
||||
OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2) { \
|
||||
register os_uintptr_t r0 __asm__("r0") = a1;\
|
||||
register os_uintptr_t r1 __asm__("r1") = a2;\
|
||||
__asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1) : "memory"); \
|
||||
return (type)r0; \
|
||||
}
|
||||
|
||||
#define SVC_CALL_ARGS3(num, type, name, a1, a2, a3) \
|
||||
OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3) { \
|
||||
register os_uintptr_t r0 __asm__("r0") = a1; \
|
||||
register os_uintptr_t r1 __asm__("r1") = a2; \
|
||||
register os_uintptr_t r2 __asm__("r2") = a3; \
|
||||
__asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1), "r"(r2) : "memory"); \
|
||||
return (type)r0; \
|
||||
}
|
||||
|
||||
#define SVC_CALL_ARGS4(num, type, name, a1, a2, a3, a4) \
|
||||
OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3, os_uintptr_t a4) { \
|
||||
register os_uintptr_t r0 __asm__("r0") = a1; \
|
||||
register os_uintptr_t r1 __asm__("r1") = a2; \
|
||||
register os_uintptr_t r2 __asm__("r2") = a3; \
|
||||
register os_uintptr_t r3 __asm__("r3") = a4; \
|
||||
__asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1), "r"(r2), "r"(r3) : "memory"); \
|
||||
return (type)r0; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
SVC_CALL_ARGS1(0, os_uint_t, os_port_svc0_args1, a1)
|
||||
SVC_CALL_ARGS2(0, void, os_port_svc0_args2, a1, a2)
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_uint_t os_port_save_disable_irq_in_svc(void){
|
||||
return os_port_svc0_args1(OS_PORT_SYSCALL_OP_SAVE_DISABLE_IRQ);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void os_port_restore_irq_in_svc(os_uint_t level){
|
||||
os_port_svc0_args2(OS_PORT_SYSCALL_OP_RESTORE_IRQ, level);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void os_port_sched_in_svc(void){
|
||||
os_port_svc0_args1(OS_PORT_SYSCALL_OP_SCHED);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
typedef struct {
|
||||
/* ==== 以下为手动压栈部分 ==== */
|
||||
os_uintptr_t exc_return; /* r2 - LR */ /* 这是地址最小的位置 */
|
||||
os_uintptr_t control; /* r3 */
|
||||
os_uintptr_t r4;
|
||||
os_uintptr_t r5;
|
||||
os_uintptr_t r6;
|
||||
os_uintptr_t r7;
|
||||
os_uintptr_t r8;
|
||||
os_uintptr_t r9;
|
||||
os_uintptr_t r10;
|
||||
os_uintptr_t r11;
|
||||
/* ==== 以下为自动压栈部分 ==== */
|
||||
os_uintptr_t r0;
|
||||
os_uintptr_t r1;
|
||||
os_uintptr_t r2;
|
||||
os_uintptr_t r3;
|
||||
os_uintptr_t r12;
|
||||
os_uintptr_t lr;
|
||||
os_uintptr_t pc;
|
||||
os_uintptr_t xPSR;
|
||||
}os_stack_frame_t;
|
||||
|
||||
#define STACK_FRAME_SIZE sizeof(os_stack_frame_t)
|
||||
|
||||
os_stack_t os_port_cpu_stack_init(os_task_entry_t entry, void* param
|
||||
, void* stack_base, os_size_t stack_size, void(*exit_entry)(void)){
|
||||
os_uintptr_t stack_max = (os_uintptr_t)((uint8_t *) stack_base + stack_size);
|
||||
os_uintptr_t real_max = OS_ALIGN_DOWN(stack_max, OS_ALIGN_SIZE); /* 实际栈顶的位置,对齐后的位置 */
|
||||
stack_size -= (stack_max - real_max); /* 实际栈大小 */
|
||||
|
||||
os_stack_frame_t* p_frame = (os_stack_frame_t*)(real_max - STACK_FRAME_SIZE);
|
||||
for(os_size_t i=0; i<STACK_FRAME_SIZE/sizeof(os_uintptr_t); i++){
|
||||
((os_uintptr_t*)(p_frame))[i] = 0x5ac0ffee;
|
||||
}
|
||||
|
||||
p_frame->r0 = (os_uintptr_t)param; /* 任务参数 */
|
||||
p_frame->pc = (os_uintptr_t)entry; /* 任务入口 */
|
||||
p_frame->lr = (os_uintptr_t)exit_entry; /* 退出地址 */
|
||||
|
||||
p_frame->xPSR = (1u << 24); /* THUMB */
|
||||
p_frame->control = 0x03; /* 任务使用用户权限,栈使用 PSP */
|
||||
p_frame->exc_return = 0xFFFFFFFDul; /* 任务在中断中切换,这里是退出中断的设置 */
|
||||
|
||||
os_stack_t stack;
|
||||
stack.min = (os_uintptr_t)stack_base;
|
||||
stack.max = (os_uintptr_t)real_max;
|
||||
stack.type = kOsStackType_MaxToMin;
|
||||
stack.sp = p_frame;
|
||||
return stack;
|
||||
}
|
||||
|
||||
void os_port_disable_irq(void){
|
||||
CMSIS_disable_irq();
|
||||
}
|
||||
|
||||
void os_port_enable_irq(void){
|
||||
CMSIS_enable_irq();
|
||||
}
|
||||
|
||||
os_uint_t os_port_save_disable_irq(void){
|
||||
if(is_cpu_in_privilege()){
|
||||
return os_port_save_disable_irq_in_isr();
|
||||
}else{
|
||||
return os_port_save_disable_irq_in_svc();
|
||||
}
|
||||
}
|
||||
|
||||
void os_port_restore_irq(os_uint_t level){
|
||||
if(is_cpu_in_privilege()){
|
||||
os_port_restore_irq_in_isr(level);
|
||||
}else{
|
||||
os_port_restore_irq_in_svc(level);
|
||||
}
|
||||
}
|
||||
|
||||
os_uint_t os_port_save_disable_irq_in_isr(void){
|
||||
os_uint_t level = CMSIS_get_BASEPRI();
|
||||
CMSIS_set_BASEPRI((OS_CFG_SYSCALL_PRIORITY+1) << 4);
|
||||
return level;
|
||||
}
|
||||
|
||||
void os_port_restore_irq_in_isr(os_uint_t level){
|
||||
CMSIS_set_BASEPRI(level);
|
||||
}
|
||||
|
||||
void os_sched(void){
|
||||
if(is_cpu_in_privilege()){
|
||||
os_sched_in_isr();
|
||||
}else{
|
||||
os_port_sched_in_svc();
|
||||
}
|
||||
}
|
||||
|
||||
void SVC_Handler_C(os_uintptr_t* svc_args){
|
||||
// 读取系统调用号:它存储在原本的 PC 指令前两个字节
|
||||
uint8_t svc_number = ((uint8_t *)svc_args[6])[-2];
|
||||
switch (svc_number) {
|
||||
case OS_PORT_SYSCALL_ID:{
|
||||
os_uint_t op = svc_args[0];
|
||||
switch (op) {
|
||||
case OS_PORT_SYSCALL_OP_SAVE_DISABLE_IRQ:{
|
||||
svc_args[0] = os_port_save_disable_irq_in_isr();
|
||||
break;
|
||||
}
|
||||
case OS_PORT_SYSCALL_OP_RESTORE_IRQ:{
|
||||
os_port_restore_irq_in_isr(svc_args[1]);
|
||||
break;
|
||||
}
|
||||
case OS_PORT_SYSCALL_OP_SCHED:{
|
||||
os_sched_in_isr();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void SysTick_Handler(void){
|
||||
os_systick_tick();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.section .text.PendSV_Handler,"ax",%progbits
|
||||
.global g_os_port_switch_from_sp
|
||||
.global g_os_port_switch_to_sp
|
||||
.global PendSV_Handler
|
||||
.thumb_func
|
||||
PendSV_Handler:
|
||||
mrs r1, primask // 获取值
|
||||
cpsid i // 关闭中断
|
||||
PUSH {R1}
|
||||
|
||||
LDR R1, =g_os_port_switch_from_sp // 加载当前任务指针地址
|
||||
LDR R1, [R1] // 加载 g_os_port_switch_from_sp 的值
|
||||
CBZ R1, __PendSV_SwitchTo
|
||||
|
||||
/* ---- 压栈 ---- */
|
||||
MRS R0, PSP
|
||||
MOV R2, LR
|
||||
MRS R3, CONTROL
|
||||
STMDB R0!, {R2-R11}
|
||||
|
||||
/* ---- sp值保存到变量中 ---- */
|
||||
STR R0, [R1] // 将 sp 的值加载到 R0
|
||||
|
||||
__PendSV_SwitchTo:
|
||||
BL os_port_on_switch_success // 执行切换完成后的设置
|
||||
|
||||
/* ---- 加载目标栈 ---- */
|
||||
LDR R2, =g_os_port_switch_to_sp // 获取目标任务指针变量地址
|
||||
LDR R2, [R2] // 获取切换目标任务的指针
|
||||
LDR R0, [R2] // 获取目标任务的 sp 指针
|
||||
LDMIA R0!, {R2-R11} // 恢复 R2-R11 寄存器的值
|
||||
MOV LR, R2 // 恢复 LR 寄存器值
|
||||
MSR CONTROL, R3 // 恢复 CONTROL 寄存器值, 这里是在 ISR 中,设置暂时不生效,直到退出 ISR 才生效,所以没有问题
|
||||
ISB // 设置 CONTROL 后确保生效
|
||||
|
||||
MSR PSP, R0 // 更新 PSP 指向下一个任务的栈
|
||||
POP {R1}
|
||||
MSR PRIMASK, R1 // 开中断
|
||||
BX LR
|
||||
|
||||
|
||||
.section .text.SVC_Handler,"ax",%progbits
|
||||
.global SVC_Handler
|
||||
.global svc_exc_return
|
||||
.global SVC_Handler_C
|
||||
.type SVC_Handler, %function
|
||||
SVC_Handler:
|
||||
tst lr, #4 // 检查 EXC_RETURN (LR) 的位 2
|
||||
ite eq
|
||||
mrseq r0, msp // 如果位 2 是 0,栈帧在 MSP
|
||||
mrsne r0, psp // 如果位 2 是 1,栈帧在 PSP
|
||||
ldr r1, =svc_exc_return
|
||||
str lr, [r1]
|
||||
bl SVC_Handler_C // 跳转到 C 实现,r0 作为第一个参数传入
|
||||
ldr r1, =svc_exc_return
|
||||
ldr lr, [r1]
|
||||
bx lr
|
||||
|
||||
.section .text.cpu_clz,"ax",%progbits
|
||||
.global cpu_clz
|
||||
.thumb_func
|
||||
cpu_clz:
|
||||
CLZ R0, R0
|
||||
BX LR
|
||||
|
||||
.align 4
|
||||
.end
|
||||
Reference in New Issue
Block a user