Add full automotive RTOS project

Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
This commit is contained in:
root
2026-08-23 03:35:29 -04:00
parent f113bf0a05
commit ca13734bf0
151 changed files with 23945 additions and 0 deletions
+195
View File
@@ -0,0 +1,195 @@
/**
* @file port.c
* @brief ARM Cortex-M0 architecture specific port
* @note Cortex-M0 is used in low-power automotive applications
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "portmacro.h"
/* Global variables for context switching */
uint32_t* current_task_sp = NULL;
uint32_t* next_task_sp = NULL;
/* Initialize Architecture Port */
void port_init(void) {
/* Configure SysTick for 1ms interrupts */
SysTick->LOAD = (SystemCoreClock / 1000) - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
/* Set lowest priority for SysTick and PendSV */
NVIC_SetPriority(SysTick_IRQn, 3);
NVIC_SetPriority(PendSV_IRQn, 3);
/* Enable interrupts */
__enable_irq();
}
/* Start First Task */
void port_start_first_task(void) {
TaskHandle_t first_task = scheduler_get_current_task();
if (first_task == NULL) {
return;
}
/* Set PSP to task stack pointer */
__set_PSP((uint32_t)first_task->stack_pointer);
/* Switch to using PSP */
__set_CONTROL(0x02);
__ISB();
/* Restore context and start task */
__asm volatile (
"POP {R4-R7}\n"
"MOV R8, R4\n"
"MOV R9, R5\n"
"MOV R10, R6\n"
"MOV R11, R7\n"
"POP {R4-R7}\n"
"POP {R0-R3}\n"
"POP {R12}\n"
"POP {LR}\n"
"POP {PC}\n"
);
}
/* Context Switch Trigger */
void port_context_switch(uint32_t* current_context, uint32_t* next_context) {
current_task_sp = current_context;
next_task_sp = next_context;
/* Trigger PendSV */
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
/* Yield from ISR */
void port_yield_from_isr(void) {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
/* Enter Critical Section */
void port_disable_interrupts(void) {
__disable_irq();
}
/* Exit Critical Section */
void port_enable_interrupts(void) {
__enable_irq();
}
/* Get Current Exception Number */
uint32_t port_get_current_exception(void) {
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
}
/* Initialize Task Stack */
uint32_t* port_initialize_task_stack(TaskFunction_t task_function,
void* parameters,
uint32_t* stack_top) {
uint32_t* stack_ptr = stack_top;
/* Align stack to 8 bytes */
stack_ptr = (uint32_t*)((uint32_t)stack_ptr & ~0x7);
/* Initial stack frame for Cortex-M0 */
*(--stack_ptr) = 0x01000000; /* xPSR */
*(--stack_ptr) = (uint32_t)task_function; /* PC */
*(--stack_ptr) = 0xFFFFFFFD; /* LR (return to thread mode) */
*(--stack_ptr) = 0x00000000; /* R12 */
*(--stack_ptr) = 0x00000003; /* R3 */
*(--stack_ptr) = 0x00000002; /* R2 */
*(--stack_ptr) = 0x00000001; /* R1 */
*(--stack_ptr) = (uint32_t)parameters; /* R0 */
/* Additional registers */
*(--stack_ptr) = 0x0000000B; /* R11 */
*(--stack_ptr) = 0x0000000A; /* R10 */
*(--stack_ptr) = 0x00000009; /* R9 */
*(--stack_ptr) = 0x00000008; /* R8 */
*(--stack_ptr) = 0x00000007; /* R7 */
*(--stack_ptr) = 0x00000006; /* R6 */
*(--stack_ptr) = 0x00000005; /* R5 */
*(--stack_ptr) = 0x00000004; /* R4 */
return stack_ptr;
}
/* SysTick Handler */
void SysTick_Handler(void) {
/* Increment tick count */
extern void kernel_tick_handler(void);
kernel_tick_handler();
}
/* PendSV Handler */
void PendSV_Handler(void) {
/* Save current context */
__asm volatile (
"MRS R0, PSP\n"
"SUBS R0, R0, #32\n"
"STMIA R0!, {R4-R7}\n"
"MOV R4, R8\n"
"MOV R5, R9\n"
"MOV R6, R10\n"
"MOV R7, R11\n"
"STMIA R0!, {R4-R7}\n"
"SUBS R0, R0, #32\n"
"LDR R1, =current_task_sp\n"
"STR R0, [R1]\n"
);
/* Load next context */
__asm volatile (
"LDR R0, =next_task_sp\n"
"LDR R1, [R0]\n"
"LDMIA R1!, {R4-R7}\n"
"MOV R8, R4\n"
"MOV R9, R5\n"
"MOV R10, R6\n"
"MOV R11, R7\n"
"LDMIA R1!, {R4-R7}\n"
"MSR PSP, R1\n"
"BX LR\n"
);
}
/* SVC Handler */
void SVC_Handler(void) {
/* Handle system calls */
__asm volatile (
"TST LR, #4\n"
"ITE EQ\n"
"MRSEQ R0, MSP\n"
"MRSNE R0, PSP\n"
"LDR R0, [R0, #24]\n"
"LDRB R0, [R0, #-2]\n"
"BX LR\n"
);
}
/* Hard Fault Handler */
void HardFault_Handler(void) {
/* Save fault information */
uint32_t fault_address;
uint32_t fault_status;
__asm volatile (
"MRS %0, BFAR\n"
"MRS %1, BFSR\n"
: "=r" (fault_address), "=r" (fault_status)
);
/* Call fault handler */
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(1, fault_address, fault_status);
/* Infinite loop */
while(1);
}
+113
View File
@@ -0,0 +1,113 @@
/**
* @file port_asm.s
* @brief ARM Cortex-M0 assembly routines
*/
.syntax unified
.thumb
.arch armv6-m
.section .text
/* Global symbols */
.global current_task_sp
.global next_task_sp
.global port_context_switch
.global port_start_first_task
.global port_initialize_task_stack
/* Variables */
.section .bss
.align 2
current_task_sp: .word 0
next_task_sp: .word 0
.section .text
.thumb_func
/* Start First Task */
port_start_first_task:
/* Load task stack pointer */
ldr r0, =next_task_sp
ldr r1, [r0]
/* Set PSP */
msr PSP, r1
/* Switch to PSP */
movs r0, #2
msr CONTROL, r0
isb
/* Restore context */
pop {r4-r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
pop {r4-r7}
pop {r0-r3}
pop {r12}
pop {lr}
pop {pc}
/* PendSV Handler */
PendSV_Handler:
/* Save context */
mrs r0, PSP
subs r0, r0, #32
stmia r0!, {r4-r7}
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
stmia r0!, {r4-r7}
subs r0, r0, #32
ldr r1, =current_task_sp
str r0, [r1]
/* Load next context */
ldr r0, =next_task_sp
ldr r1, [r0]
ldmia r1!, {r4-r7}
mov r8, r4
mov r9, r5
mov r10, r6
mov r11, r7
ldmia r1!, {r4-r7}
msr PSP, r1
bx lr
/* SVC Handler */
SVC_Handler:
tst lr, #4
ite eq
mrseq r0, MSP
mrsne r0, PSP
ldr r0, [r0, #24]
ldrb r0, [r0, #-2]
bx lr
/* Hard Fault Handler */
HardFault_Handler:
/* Save registers */
mrs r0, PSP
stmdb r0!, {r4-r7}
mov r4, r8
mov r5, r9
mov r6, r10
mov r7, r11
stmdb r0!, {r4-r7}
/* Get fault information */
mrs r0, BFAR
mrs r1, BFSR
/* Call fault handler */
movs r2, #1
bl fault_handler_process
/* Infinite loop */
b .
.end
+40
View File
@@ -0,0 +1,40 @@
/**
* @file portmacro.h
* @brief ARM Cortex-M0 specific macros
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdint.h>
/* Data Types */
typedef uint32_t port_stack_type_t;
typedef uint32_t port_base_type_t;
/* Architecture Constants */
#define PORT_STACK_GROWTH_DIRECTION (-1)
#define PORT_BYTE_ALIGNMENT 8
#define PORT_MAX_SYSCALL_INTERRUPT_PRIORITY 3
/* Critical Section Macros */
#define portENTER_CRITICAL() __disable_irq()
#define portEXIT_CRITICAL() __enable_irq()
/* Interrupt Control */
#define portENABLE_INTERRUPTS() __enable_irq()
#define portDISABLE_INTERRUPTS() __disable_irq()
/* Context Switch */
#define portYIELD() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
#define portYIELD_FROM_ISR() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
/* Memory Barriers */
#define portMEMORY_BARRIER() __asm volatile("DMB")
#define portSYNC_BARRIER() __asm volatile("DSB")
#define portINSTRUCTION_BARRIER() __asm volatile("ISB")
/* NOP */
#define portNOP() __asm volatile("NOP")
#endif /* PORTMACRO_H */
+222
View File
@@ -0,0 +1,222 @@
/**
* @file port.c
* @brief ARM Cortex-M3 architecture specific port
* @note Cortex-M3 is widely used in automotive ECUs
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "portmacro.h"
/* Context storage */
uint32_t* current_task_sp = NULL;
uint32_t* next_task_sp = NULL;
/* Exception priorities */
#define SYSTICK_PRIORITY 0xFF
#define PENDSV_PRIORITY 0xFF
#define SVC_PRIORITY 0x00
/* Initialize Architecture Port */
void port_init(void) {
/* Set priority grouping - 4 bits preemption, 0 bits sub-priority */
NVIC_SetPriorityGrouping(4);
/* Configure SysTick */
SysTick->LOAD = (SystemCoreClock / 1000) - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
/* Set exception priorities */
NVIC_SetPriority(SysTick_IRQn, SYSTICK_PRIORITY);
NVIC_SetPriority(PendSV_IRQn, PENDSV_PRIORITY);
NVIC_SetPriority(SVCall_IRQn, SVC_PRIORITY);
/* Enable faults */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk |
SCB_SHCSR_BUSFAULTENA_Msk |
SCB_SHCSR_USGFAULTENA_Msk;
}
/* Start First Task */
void port_start_first_task(void) {
TaskHandle_t first_task = scheduler_get_current_task();
if (first_task == NULL) {
return;
}
/* Set PSP */
__set_PSP((uint32_t)first_task->stack_pointer);
/* Switch to PSP */
__set_CONTROL(0x02);
__ISB();
/* Restore context */
__asm volatile (
"LDMIA R0!, {R4-R11}\n"
"MSR PSP, R0\n"
"MOV LR, #0xFFFFFFFD\n"
"BX LR\n"
);
}
/* Context Switch */
void port_context_switch(uint32_t* current_context, uint32_t* next_context) {
current_task_sp = current_context;
next_task_sp = next_context;
/* Trigger PendSV */
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
/* Data synchronization barrier */
__DSB();
__ISB();
}
/* Yield */
void port_yield(void) {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
/* Yield from ISR */
void port_yield_from_isr(void) {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
/* Enter Critical Section */
void port_disable_interrupts(void) {
__disable_irq();
}
/* Exit Critical Section */
void port_enable_interrupts(void) {
__enable_irq();
}
/* Get Current Exception Number */
uint32_t port_get_current_exception(void) {
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
}
/* Initialize Task Stack */
uint32_t* port_initialize_task_stack(TaskFunction_t task_function,
void* parameters,
uint32_t* stack_top) {
uint32_t* stack_ptr = stack_top;
/* 8-byte alignment */
stack_ptr = (uint32_t*)((uint32_t)stack_ptr & ~0x7);
/* Exception frame */
*(--stack_ptr) = 0x01000000; /* xPSR */
*(--stack_ptr) = (uint32_t)task_function; /* PC */
*(--stack_ptr) = 0xFFFFFFFD; /* LR */
*(--stack_ptr) = 0x00000000; /* R12 */
*(--stack_ptr) = 0x00000003; /* R3 */
*(--stack_ptr) = 0x00000002; /* R2 */
*(--stack_ptr) = 0x00000001; /* R1 */
*(--stack_ptr) = (uint32_t)parameters; /* R0 */
/* Additional context */
*(--stack_ptr) = 0x0000000B; /* R11 */
*(--stack_ptr) = 0x0000000A; /* R10 */
*(--stack_ptr) = 0x00000009; /* R9 */
*(--stack_ptr) = 0x00000008; /* R8 */
*(--stack_ptr) = 0x00000007; /* R7 */
*(--stack_ptr) = 0x00000006; /* R6 */
*(--stack_ptr) = 0x00000005; /* R5 */
*(--stack_ptr) = 0x00000004; /* R4 */
return stack_ptr;
}
/* SysTick Handler */
void SysTick_Handler(void) {
extern void kernel_tick_handler(void);
kernel_tick_handler();
}
/* PendSV Handler */
__attribute__((naked)) void PendSV_Handler(void) {
__asm volatile (
"MRS R0, PSP\n"
"STMDB R0!, {R4-R11}\n"
"LDR R1, =current_task_sp\n"
"STR R0, [R1]\n"
"LDR R0, =next_task_sp\n"
"LDR R1, [R0]\n"
"LDMIA R1!, {R4-R11}\n"
"MSR PSP, R1\n"
"BX LR\n"
);
}
/* SVC Handler */
__attribute__((naked)) void SVC_Handler(void) {
__asm volatile (
"TST LR, #4\n"
"ITE EQ\n"
"MRSEQ R0, MSP\n"
"MRSNE R0, PSP\n"
"LDR R0, [R0, #24]\n"
"LDRB R0, [R0, #-2]\n"
"PUSH {LR}\n"
"BL svc_handler\n"
"POP {LR}\n"
"BX LR\n"
);
}
/* Memory Management Fault Handler */
void MemManage_Handler(void) {
uint32_t fault_address;
uint32_t fault_status;
fault_address = SCB->MMFAR;
fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(2, fault_address, fault_status);
while(1);
}
/* Bus Fault Handler */
void BusFault_Handler(void) {
uint32_t fault_address;
uint32_t fault_status;
fault_address = SCB->BFAR;
fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(3, fault_address, fault_status);
while(1);
}
/* Usage Fault Handler */
void UsageFault_Handler(void) {
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(4, 0, fault_status);
while(1);
}
/* Hard Fault Handler */
void HardFault_Handler(void) {
uint32_t fault_address = 0;
uint32_t fault_status = SCB->HFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(1, fault_address, fault_status);
while(1);
}
+162
View File
@@ -0,0 +1,162 @@
/**
* @file port_asm.s
* @brief ARM Cortex-M3 assembly routines
*/
.syntax unified
.thumb
.arch armv7-m
.section .text
/* Global symbols */
.global current_task_sp
.global next_task_sp
.global port_context_switch
.global port_start_first_task
.global port_initialize_task_stack
.global port_disable_interrupts
.global port_enable_interrupts
/* Variables */
.section .bss
.align 2
current_task_sp: .word 0
next_task_sp: .word 0
.section .text
.thumb_func
/* Start First Task */
port_start_first_task:
/* Load task stack pointer */
ldr r0, =next_task_sp
ldr r1, [r0]
/* Set PSP */
msr PSP, r1
/* Switch to PSP */
mov r0, #2
msr CONTROL, r0
isb
/* Restore context */
ldmia r1!, {r4-r11}
msr PSP, r1
mov lr, #0xFFFFFFFD
bx lr
/* PendSV Handler */
PendSV_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
ldr r1, =current_task_sp
str r0, [r1]
/* Load next context */
ldr r0, =next_task_sp
ldr r1, [r0]
ldmia r1!, {r4-r11}
msr PSP, r1
bx lr
/* SVC Handler */
SVC_Handler:
tst lr, #4
ite eq
mrseq r0, MSP
mrsne r0, PSP
ldr r0, [r0, #24]
ldrb r0, [r0, #-2]
push {lr}
bl svc_handler
pop {lr}
bx lr
/* Disable Interrupts */
port_disable_interrupts:
cpsid i
bx lr
/* Enable Interrupts */
port_enable_interrupts:
cpsie i
bx lr
/* Memory Management Fault */
MemManage_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault information */
ldr r1, =0xE000ED34 /* MMFAR */
ldr r1, [r1]
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #2
bl fault_handler_process
/* Infinite loop */
b .
/* Bus Fault Handler */
BusFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault information */
ldr r1, =0xE000ED38 /* BFAR */
ldr r1, [r1]
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #3
bl fault_handler_process
/* Infinite loop */
b .
/* Usage Fault Handler */
UsageFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault status */
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #4
movs r1, #0
bl fault_handler_process
/* Infinite loop */
b .
/* Hard Fault Handler */
HardFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault status */
ldr r2, =0xE000ED2C /* HFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #1
movs r1, #0
bl fault_handler_process
/* Infinite loop */
b .
.end
+43
View File
@@ -0,0 +1,43 @@
/**
* @file portmacro.h
* @brief ARM Cortex-M3 specific macros
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdint.h>
/* Data Types */
typedef uint32_t port_stack_type_t;
typedef uint32_t port_base_type_t;
/* Architecture Constants */
#define PORT_STACK_GROWTH_DIRECTION (-1)
#define PORT_BYTE_ALIGNMENT 8
#define PORT_MAX_SYSCALL_INTERRUPT_PRIORITY 0x50
/* Critical Section Macros */
#define portENTER_CRITICAL() __asm volatile("CPSID I" ::: "memory")
#define portEXIT_CRITICAL() __asm volatile("CPSIE I" ::: "memory")
/* Interrupt Control */
#define portENABLE_INTERRUPTS() __asm volatile("CPSIE I" ::: "memory")
#define portDISABLE_INTERRUPTS() __asm volatile("CPSID I" ::: "memory")
/* Context Switch */
#define portYIELD() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
#define portYIELD_FROM_ISR() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
/* Memory Barriers */
#define portMEMORY_BARRIER() __asm volatile("DMB" ::: "memory")
#define portSYNC_BARRIER() __asm volatile("DSB" ::: "memory")
#define portINSTRUCTION_BARRIER() __asm volatile("ISB" ::: "memory")
/* NOP */
#define portNOP() __asm volatile("NOP")
/* Endian Definition */
#define portBYTE_ORDER LITTLE_ENDIAN
#endif /* PORTMACRO_H */
+251
View File
@@ -0,0 +1,251 @@
/**
* @file port.c
* @brief ARM Cortex-M4 architecture specific port with FPU support
* @note Cortex-M4 with FPU is common in modern automotive MCUs
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "portmacro.h"
/* Context storage */
uint32_t* current_task_sp = NULL;
uint32_t* next_task_sp = NULL;
/* FPU context storage */
uint32_t current_fpu_context[32];
uint32_t next_fpu_context[32];
/* Exception priorities */
#define SYSTICK_PRIORITY 0xFF
#define PENDSV_PRIORITY 0xFF
#define SVC_PRIORITY 0x00
/* Initialize Architecture Port */
void port_init(void) {
/* Set priority grouping - 4 bits preemption, 0 bits sub-priority */
NVIC_SetPriorityGrouping(4);
/* Enable FPU */
SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2));
/* Configure SysTick */
SysTick->LOAD = (SystemCoreClock / 1000) - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
/* Set exception priorities */
NVIC_SetPriority(SysTick_IRQn, SYSTICK_PRIORITY);
NVIC_SetPriority(PendSV_IRQn, PENDSV_PRIORITY);
NVIC_SetPriority(SVCall_IRQn, SVC_PRIORITY);
/* Enable faults */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk |
SCB_SHCSR_BUSFAULTENA_Msk |
SCB_SHCSR_USGFAULTENA_Msk;
/* Enable divide by zero trap */
SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
/* Enable unaligned access trap */
SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk;
}
/* Start First Task */
void port_start_first_task(void) {
TaskHandle_t first_task = scheduler_get_current_task();
if (first_task == NULL) {
return;
}
/* Restore FPU context if task uses FPU */
if (first_task->context[31] & 0x10) {
/* FPU was used - restore FPU registers */
__asm volatile (
"VLDM R0!, {S16-S31}\n"
"VLDM R0!, {S0-S15}\n"
:
: "r" (first_task->context)
);
}
/* Set PSP */
__set_PSP((uint32_t)first_task->stack_pointer);
/* Switch to PSP */
__set_CONTROL(0x02);
__ISB();
/* Restore context */
__asm volatile (
"LDMIA R0!, {R4-R11}\n"
"MSR PSP, R0\n"
"MOV LR, #0xFFFFFFFD\n"
"BX LR\n"
:
: "r" (first_task->stack_pointer)
);
}
/* Context Switch */
void port_context_switch(uint32_t* current_context, uint32_t* next_context) {
current_task_sp = current_context;
next_task_sp = next_context;
/* Trigger PendSV */
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
/* Data synchronization barrier */
__DSB();
__ISB();
}
/* Initialize Task Stack with FPU support */
uint32_t* port_initialize_task_stack(TaskFunction_t task_function,
void* parameters,
uint32_t* stack_top) {
uint32_t* stack_ptr = stack_top;
/* 8-byte alignment */
stack_ptr = (uint32_t*)((uint32_t)stack_ptr & ~0x7);
/* Exception frame with FPU */
*(--stack_ptr) = 0x01000000; /* xPSR */
*(--stack_ptr) = (uint32_t)task_function; /* PC */
*(--stack_ptr) = 0xFFFFFFFD; /* LR */
*(--stack_ptr) = 0x00000000; /* R12 */
*(--stack_ptr) = 0x00000003; /* R3 */
*(--stack_ptr) = 0x00000002; /* R2 */
*(--stack_ptr) = 0x00000001; /* R1 */
*(--stack_ptr) = (uint32_t)parameters; /* R0 */
/* Additional context */
*(--stack_ptr) = 0x0000000B; /* R11 */
*(--stack_ptr) = 0x0000000A; /* R10 */
*(--stack_ptr) = 0x00000009; /* R9 */
*(--stack_ptr) = 0x00000008; /* R8 */
*(--stack_ptr) = 0x00000007; /* R7 */
*(--stack_ptr) = 0x00000006; /* R6 */
*(--stack_ptr) = 0x00000005; /* R5 */
*(--stack_ptr) = 0x00000004; /* R4 */
/* FPU context (S0-S31) */
for (int i = 0; i < 32; i++) {
*(--stack_ptr) = 0;
}
/* FPSCR */
*(--stack_ptr) = 0;
return stack_ptr;
}
/* SysTick Handler */
void SysTick_Handler(void) {
extern void kernel_tick_handler(void);
kernel_tick_handler();
}
/* PendSV Handler with FPU context saving */
__attribute__((naked)) void PendSV_Handler(void) {
__asm volatile (
/* Check if FPU was used */
"TST LR, #0x10\n"
"IT EQ\n"
"BEQ 1f\n"
/* Save FPU context */
"MRS R0, CONTROL\n"
"TST R0, #0x04\n"
"IT EQ\n"
"BEQ 1f\n"
/* Save FPU registers */
"VSTMDB R0!, {S16-S31}\n"
"VSTMDB R0!, {S0-S15}\n"
"1:\n"
/* Save core context */
"MRS R0, PSP\n"
"STMDB R0!, {R4-R11}\n"
"LDR R1, =current_task_sp\n"
"STR R0, [R1]\n"
/* Load next context */
"LDR R0, =next_task_sp\n"
"LDR R1, [R0]\n"
"LDMIA R1!, {R4-R11}\n"
"MSR PSP, R1\n"
/* Restore FPU context if needed */
"TST LR, #0x10\n"
"IT EQ\n"
"BEQ 2f\n"
/* Restore FPU registers */
"VLDMIA R0!, {S0-S15}\n"
"VLDMIA R0!, {S16-S31}\n"
"2:\n"
"BX LR\n"
);
}
/* SVC Handler */
__attribute__((naked)) void SVC_Handler(void) {
__asm volatile (
"TST LR, #4\n"
"ITE EQ\n"
"MRSEQ R0, MSP\n"
"MRSNE R0, PSP\n"
"LDR R0, [R0, #24]\n"
"LDRB R0, [R0, #-2]\n"
"PUSH {LR}\n"
"BL svc_handler\n"
"POP {LR}\n"
"BX LR\n"
);
}
/* Fault Handlers */
void MemManage_Handler(void) {
uint32_t fault_address = SCB->MMFAR;
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(2, fault_address, fault_status);
while(1);
}
void BusFault_Handler(void) {
uint32_t fault_address = SCB->BFAR;
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(3, fault_address, fault_status);
while(1);
}
void UsageFault_Handler(void) {
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(4, 0, fault_status);
while(1);
}
void HardFault_Handler(void) {
uint32_t fault_status = SCB->HFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(1, 0, fault_status);
while(1);
}
+226
View File
@@ -0,0 +1,226 @@
/**
* @file port_asm.s
* @brief ARM Cortex-M4 assembly routines with FPU support
*/
.syntax unified
.thumb
.arch armv7e-m
.fpu fpv4-sp-d16
.section .text
/* Global symbols */
.global current_task_sp
.global next_task_sp
.global port_context_switch
.global port_start_first_task
.global port_initialize_task_stack
.global port_disable_interrupts
.global port_enable_interrupts
.global port_enable_fpu
.global port_disable_fpu
/* Variables */
.section .bss
.align 3
current_task_sp: .word 0
next_task_sp: .word 0
.section .text
.thumb_func
/* Start First Task */
port_start_first_task:
/* Load task stack pointer */
ldr r0, =next_task_sp
ldr r1, [r0]
/* Check if FPU context needs restoring */
tst lr, #0x10
beq 1f
/* Restore FPU registers */
add r1, r1, #64
vldmia r1!, {s16-s31}
vldmia r1!, {s0-s15}
sub r1, r1, #128
1:
/* Set PSP */
msr PSP, r1
/* Switch to PSP */
mov r0, #2
msr CONTROL, r0
isb
/* Restore core context */
ldmia r1!, {r4-r11}
msr PSP, r1
mov lr, #0xFFFFFFFD
bx lr
/* PendSV Handler */
PendSV_Handler:
/* Check if using PSP */
mrs r0, CONTROL
tst r0, #2
beq 1f
/* Check if FPU was used */
tst lr, #0x10
beq 1f
/* Save FPU context */
mrs r0, PSP
add r0, r0, #64
vstmdb r0!, {s16-s31}
vstmdb r0!, {s0-s15}
1:
/* Save core context */
mrs r0, PSP
stmdb r0!, {r4-r11}
ldr r1, =current_task_sp
str r0, [r1]
/* Load next context */
ldr r0, =next_task_sp
ldr r1, [r0]
ldmia r1!, {r4-r11}
msr PSP, r1
/* Restore FPU context if needed */
tst lr, #0x10
beq 2f
/* Restore FPU registers */
add r1, r1, #64
vldmia r1!, {s0-s15}
vldmia r1!, {s16-s31}
2:
/* Return from exception */
bx lr
/* SVC Handler */
SVC_Handler:
tst lr, #4
ite eq
mrseq r0, MSP
mrsne r0, PSP
ldr r0, [r0, #24]
ldrb r0, [r0, #-2]
push {lr}
bl svc_handler
pop {lr}
bx lr
/* Enable FPU */
port_enable_fpu:
/* Enable CP10 and CP11 */
ldr r0, =0xE000ED88 /* CPACR */
ldr r1, [r0]
orr r1, r1, #(0xF << 20)
str r1, [r0]
dsb
isb
bx lr
/* Disable FPU */
port_disable_fpu:
/* Disable CP10 and CP11 */
ldr r0, =0xE000ED88 /* CPACR */
ldr r1, [r0]
bic r1, r1, #(0xF << 20)
str r1, [r0]
dsb
isb
bx lr
/* Disable Interrupts */
port_disable_interrupts:
cpsid i
bx lr
/* Enable Interrupts */
port_enable_interrupts:
cpsie i
bx lr
/* Memory Management Fault */
MemManage_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault information */
ldr r1, =0xE000ED34 /* MMFAR */
ldr r1, [r1]
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #2
bl fault_handler_process
/* Infinite loop */
b .
/* Bus Fault Handler */
BusFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault information */
ldr r1, =0xE000ED38 /* BFAR */
ldr r1, [r1]
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #3
bl fault_handler_process
/* Infinite loop */
b .
/* Usage Fault Handler */
UsageFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault status */
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #4
movs r1, #0
bl fault_handler_process
/* Infinite loop */
b .
/* Hard Fault Handler */
HardFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault status */
ldr r2, =0xE000ED2C /* HFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #1
movs r1, #0
bl fault_handler_process
/* Infinite loop */
b .
.end
+65
View File
@@ -0,0 +1,65 @@
/**
* @file portmacro.h
* @brief ARM Cortex-M4 specific macros with FPU support
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdint.h>
#include "stm32f4xx.h" /* Adjust for specific MCU */
/* Data Types */
typedef uint32_t port_stack_type_t;
typedef uint32_t port_base_type_t;
/* Architecture Constants */
#define PORT_STACK_GROWTH_DIRECTION (-1)
#define PORT_BYTE_ALIGNMENT 8
#define PORT_MAX_SYSCALL_INTERRUPT_PRIORITY 0x50
/* Critical Section Macros */
#define portENTER_CRITICAL() __asm volatile("CPSID I" ::: "memory")
#define portEXIT_CRITICAL() __asm volatile("CPSIE I" ::: "memory")
/* Interrupt Control */
#define portENABLE_INTERRUPTS() __asm volatile("CPSIE I" ::: "memory")
#define portDISABLE_INTERRUPTS() __asm volatile("CPSID I" ::: "memory")
/* Context Switch */
#define portYIELD() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
#define portYIELD_FROM_ISR() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
/* Memory Barriers */
#define portMEMORY_BARRIER() __asm volatile("DMB" ::: "memory")
#define portSYNC_BARRIER() __asm volatile("DSB" ::: "memory")
#define portINSTRUCTION_BARRIER() __asm volatile("ISB" ::: "memory")
/* NOP */
#define portNOP() __asm volatile("NOP")
/* FPU Control */
#define portENABLE_FPU() \
do { \
SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2)); \
__DSB(); \
__ISB(); \
} while(0)
#define portDISABLE_FPU() \
do { \
SCB->CPACR &= ~((3UL << 10*2) | (3UL << 11*2)); \
__DSB(); \
__ISB(); \
} while(0)
/* Endian Definition */
#define portBYTE_ORDER LITTLE_ENDIAN
/* Optimization */
#define portFORCE_INLINE __attribute__((always_inline)) inline
/* Task Utilities */
#define portTASK_RETURN_ADDRESS (0xFFFFFFFD)
#endif /* PORTMACRO_H */
+40
View File
@@ -0,0 +1,40 @@
/**
* @file port_common.h
* @brief Common port interface definitions
*/
#ifndef PORT_COMMON_H
#define PORT_COMMON_H
#include "kernel.h"
/* Common port function declarations */
void port_common_init(void);
void port_common_context_switch(TaskHandle_t current, TaskHandle_t next);
uint32_t* port_common_init_stack(TaskFunction_t function,
void* parameters,
uint32_t* stack_top,
uint32_t stack_size);
void port_common_fault_handler(uint32_t fault_type, uint32_t fault_address,
uint32_t fault_status);
void port_enter_safe_state(void);
void port_set_safe_outputs(void);
void port_log_fault(void* fault_info);
/* Architecture-specific functions that must be implemented */
void port_init(void);
void port_start_first_task(void);
void port_context_switch(uint32_t* current_context, uint32_t* next_context);
uint32_t* port_initialize_task_stack(TaskFunction_t function,
void* parameters,
uint32_t* stack_top);
void port_save_context(uint32_t* context);
void port_restore_context(uint32_t* context);
void port_disable_interrupts(void);
void port_enable_interrupts(void);
uint32_t port_get_current_exception(void);
void port_service_watchdog(void);
void port_yield(void);
void port_yield_from_isr(void);
#endif /* PORT_COMMON_H */
+262
View File
@@ -0,0 +1,262 @@
/**
* @file port.c
* @brief Infineon TriCore TC3xx architecture specific port
* @note TriCore is widely used in automotive powertrain and safety applications
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "portmacro.h"
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxStm.h"
#include "IfxScuWdt.h"
/* Context storage */
uint32_t* current_task_sp = NULL;
uint32_t* next_task_sp = NULL;
/* STM configuration for system tick */
static IfxStm_CompareConfig stmCompareConfig;
static volatile uint32_t stmTickCount = 0;
/* CSA (Context Save Area) management */
#define MAX_CSA_AREAS 64
static uint32_t csa_areas[MAX_CSA_AREAS][16] __attribute__((aligned(64)));
static uint32_t csa_index = 0;
/* Interrupt priorities */
#define SYSTICK_PRIORITY 255
#define PENDSV_PRIORITY 255
#define SVC_PRIORITY 0
/* Initialize Architecture Port */
void port_init(void) {
/* Initialize CPU configuration */
IfxCpu_init();
/* Disable global interrupts during initialization */
IfxCpu_disableInterrupts();
/* Initialize CSA areas */
for (uint32_t i = 0; i < MAX_CSA_AREAS; i++) {
/* Initialize PCXI register for each CSA */
uint32_t pcxi_value = ((uint32_t)&csa_areas[i][0]) & 0xFFFFF000;
pcxi_value |= (i << 16); /* Set previous context pointer */
csa_areas[i][0] = pcxi_value;
}
/* Configure STM for 1ms tick */
IfxStm_initCompareConfig(&stmCompareConfig);
stmCompareConfig.triggerPriority = SYSTICK_PRIORITY;
stmCompareConfig.typeOfService = IfxSrc_Tos_cpu0;
stmCompareConfig.ticks = IfxStm_getFrequency(&MODULE_STM0) / 1000;
/* Initialize STM compare */
IfxStm_initCompare(&MODULE_STM0, &stmCompareConfig);
/* Enable safety watchdog */
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_clearCpuEndinit(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_enableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword(),
100, 200);
IfxScuWdt_setCpuEndinit(IfxScuWdt_getCpuWatchdogPassword());
/* Enable global interrupts */
IfxCpu_enableInterrupts();
}
/* Start First Task */
void port_start_first_task(void) {
TaskHandle_t first_task = scheduler_get_current_task();
if (first_task == NULL) {
return;
}
/* Get task context from CSA */
uint32_t* context = (uint32_t*)first_task->context;
uint32_t pcxi = context[0];
uint32_t pc = context[1];
uint32_t sp = context[2];
/* Set up context for first task execution */
__asm volatile (
"mov.a %%sp, %0\n" /* Set stack pointer */
"mov %%a11, %1\n" /* Set return address */
"mtsv %%pcxi, %2\n" /* Set context */
"rslcx\n" /* Restore lower context */
"rfe\n" /* Return from exception */
:
: "r" (sp), "r" (pc), "r" (pcxi)
: "a11", "memory"
);
}
/* Context Switch */
void port_context_switch(uint32_t* current_context, uint32_t* next_context) {
current_task_sp = current_context;
next_task_sp = next_context;
/* Trigger software interrupt for context switch */
__asm volatile (
"syscall 0\n" /* System call for context switch */
);
}
/* Initialize Task Stack */
uint32_t* port_initialize_task_stack(TaskFunction_t task_function,
void* parameters,
uint32_t* stack_top) {
uint32_t* stack_ptr = stack_top;
/* Align to 64 bytes */
stack_ptr = (uint32_t*)((uint32_t)stack_ptr & ~0x3F);
/* Allocate CSA for task */
if (csa_index >= MAX_CSA_AREAS) {
return NULL; /* Out of CSA areas */
}
uint32_t* csa = csa_areas[csa_index];
csa_index++;
/* Initialize CSA */
csa[0] = 0; /* PCXI will be set during first context switch */
csa[1] = (uint32_t)task_function; /* PC */
csa[2] = (uint32_t)stack_ptr; /* SP */
csa[3] = (uint32_t)parameters; /* A4 (first argument) */
/* Initialize upper context registers */
csa[4] = 0; /* A5 */
csa[5] = 0; /* A6 */
csa[6] = 0; /* A7 */
csa[7] = 0; /* A8 */
csa[8] = 0; /* A9 */
csa[9] = 0; /* A10 */
csa[10] = 0; /* A11 */
csa[11] = 0; /* A12 */
csa[12] = 0; /* A13 */
csa[13] = 0; /* A14 */
csa[14] = 0; /* A15 */
csa[15] = 0; /* D8 */
/* Store CSA pointer in task context */
TaskHandle_t task = scheduler_get_current_task();
if (task != NULL) {
task->context[0] = (uint32_t)csa;
}
return stack_ptr;
}
/* System Timer Interrupt Handler */
IFX_INTERRUPT(stm_compare_match_isr, 0, SYSTICK_PRIORITY) {
/* Clear interrupt flag */
IfxStm_clearCompareFlag(&MODULE_STM0, stmCompareConfig.comparator);
/* Update compare value for next interrupt */
IfxStm_increaseCompare(&MODULE_STM0, stmCompareConfig.comparator,
IfxStm_getFrequency(&MODULE_STM0) / 1000);
/* Call kernel tick handler */
extern void kernel_tick_handler(void);
kernel_tick_handler();
/* Refresh watchdog */
IfxScuWdt_clearSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
}
/* Software Interrupt Handler for Context Switch */
IFX_INTERRUPT(software_context_switch_isr, 0, PENDSV_PRIORITY) {
__asm volatile (
/* Save current context */
"svlcx\n" /* Save lower context */
"mov %%d15, %%a11\n" /* Save return address */
/* Store current stack pointer */
"mov.a %%a15, %%sp\n"
"mov.aa %0, %%a15\n"
/* Load next stack pointer */
"mov.aa %%a15, %1\n"
"mov.a %%sp, %%a15\n"
/* Restore lower context */
"rslcx\n"
"mov %%a11, %%d15\n" /* Restore return address */
"rfe\n" /* Return from exception */
:
: "m" (current_task_sp), "m" (next_task_sp)
: "a15", "d15", "memory"
);
}
/* System Call Handler */
IFX_INTERRUPT(syscall_handler, 0, SVC_PRIORITY) {
/* Get system call number */
uint32_t syscall_number;
__asm volatile (
"mov %0, %%d15\n" /* Get syscall number from D15 */
: "=r" (syscall_number)
);
/* Handle system calls */
switch (syscall_number) {
case 0: /* Context switch */
software_context_switch_isr();
break;
case 1: /* Yield */
scheduler_yield();
break;
case 2: /* Task exit */
task_delete(scheduler_get_current_task());
break;
default:
break;
}
}
/* Trap Handlers */
IFX_INTERRUPT(trap_handler, 0, 0) {
/* Get trap information */
uint32_t trap_class;
uint32_t trap_id;
__asm volatile (
"mov %0, %%d15\n" /* Trap class */
"mov %1, %%d14\n" /* Trap ID */
: "=r" (trap_class), "=r" (trap_id)
);
/* Call fault handler */
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(trap_class, trap_id, 0);
/* Enter safe state */
while(1) {
/* Safe state - wait for watchdog */
IfxScuWdt_clearSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
}
}
/* Enter Critical Section */
void port_disable_interrupts(void) {
IfxCpu_disableInterrupts();
}
/* Exit Critical Section */
void port_enable_interrupts(void) {
IfxCpu_enableInterrupts();
}
/* Get Current Exception Number */
uint32_t port_get_current_exception(void) {
uint32_t icr;
__asm volatile (
"mfcr %0, $ICR\n" /* Get Interrupt Control Register */
: "=r" (icr)
);
return (icr >> 16) & 0xFF; /* Extract current CPU priority */
}
@@ -0,0 +1,105 @@
/**
* @file port_asm.s
* @brief Infineon TriCore TC3xx assembly routines
*/
.section .text
.align 2
/* Global symbols */
.global current_task_sp
.global next_task_sp
.global port_context_switch
.global port_start_first_task
.global port_disable_interrupts
.global port_enable_interrupts
/* Variables */
.section .bss
.align 2
current_task_sp: .word 0
next_task_sp: .word 0
.section .text
/* Start First Task */
port_start_first_task:
/* Load task context */
mov.a a15, [next_task_sp]
ld.a a14, [a15] /* Load CSA pointer */
/* Set up context */
mtsv pcxi, a14 /* Set previous context */
ld.a sp, [a14+8] /* Load stack pointer */
ld.a a11, [a14+4] /* Load return address */
/* Restore context and start */
rslcx /* Restore lower context */
rfe /* Return from exception */
/* Context Switch */
port_context_switch:
/* Save current context */
svlcx /* Save lower context */
/* Store current stack pointer */
mov.a a15, sp
mov.aa [current_task_sp], a15
/* Load next stack pointer */
mov.aa a15, [next_task_sp]
mov.a sp, a15
/* Restore next context */
rslcx /* Restore lower context */
rfe /* Return from exception */
/* Disable Interrupts */
port_disable_interrupts:
disable /* Disable interrupts */
ret
/* Enable Interrupts */
port_enable_interrupts:
enable /* Enable interrupts */
ret
/* System Timer Interrupt */
stm_compare_match_isr:
/* Save context */
svlcx
/* Clear interrupt */
movh.a a15, 0xF000 /* STM base address */
lea a15, [a15]0x0010 /* STM interrupt clear register */
st.w [a15], 0x1 /* Clear compare match flag */
/* Update compare value */
movh.a a15, 0xF000
lea a15, [a15]0x0020 /* STM compare register */
ld.w d15, [a15]
movh.a a14, 0xF000
lea a14, [a14]0x0024 /* STM compare update register */
add d15, d15, 1000 /* Add 1ms */
st.w [a14], d15
/* Call kernel tick handler */
call kernel_tick_handler
/* Restore context */
rslcx
rfe
/* Trap Handler */
trap_handler:
/* Save trap information */
mov d15, d15 /* Trap class */
mov d14, d14 /* Trap ID */
/* Call fault handler */
call fault_handler_process
/* Enter safe state */
j .
.end
@@ -0,0 +1,52 @@
/**
* @file portmacro.h
* @brief Infineon TriCore TC3xx specific macros
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdint.h>
#include "Ifx_Types.h"
#include "IfxCpu.h"
/* Data Types */
typedef uint32_t port_stack_type_t;
typedef uint32_t port_base_type_t;
/* Architecture Constants */
#define PORT_STACK_GROWTH_DIRECTION (-1)
#define PORT_BYTE_ALIGNMENT 64
/* Critical Section Macros */
#define portENTER_CRITICAL() IfxCpu_disableInterrupts()
#define portEXIT_CRITICAL() IfxCpu_enableInterrupts()
/* Interrupt Control */
#define portENABLE_INTERRUPTS() IfxCpu_enableInterrupts()
#define portDISABLE_INTERRUPTS() IfxCpu_disableInterrupts()
/* Context Switch */
#define portYIELD() __asm volatile("syscall 0")
#define portYIELD_FROM_ISR() __asm volatile("syscall 0")
/* Memory Barriers */
#define portMEMORY_BARRIER() __asm volatile("dsync")
#define portSYNC_BARRIER() __asm volatile("dsync")
#define portINSTRUCTION_BARRIER() __asm volatile("isync")
/* NOP */
#define portNOP() __asm volatile("nop")
/* CSA Management */
#define portALLOCATE_CSA() __port_allocate_csa()
#define portFREE_CSA(csa) __port_free_csa(csa)
/* Safety Features */
#define portENABLE_SAFETY_WATCHDOG(timeout) \
IfxScuWdt_enableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword(), timeout, timeout*2)
#define portSERVICE_WATCHDOG() \
IfxScuWdt_clearSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword())
#endif /* PORTMACRO_H */
+260
View File
@@ -0,0 +1,260 @@
/**
* @file port.c
* @brief NXP S32K architecture specific port
* @note S32K is designed for automotive body and safety applications
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "portmacro.h"
#include "S32K144.h"
#include "interrupt_manager.h"
/* Context storage */
uint32_t* current_task_sp = NULL;
uint32_t* next_task_sp = NULL;
/* LPIT configuration */
#define LPIT_CHANNEL 0
#define LPIT_TICK_PERIOD 1000 /* 1ms at 1MHz */
/* Interrupt priorities */
#define SYSTICK_PRIORITY 15
#define PENDSV_PRIORITY 15
#define SVC_PRIORITY 0
/* Initialize Architecture Port */
void port_init(void) {
/* Disable global interrupts */
__disable_irq();
/* Configure system clock */
/* Assuming 8MHz external crystal, PLL to 160MHz */
SCG->SPLLCSR = SCG_SPLLCSR_SPLLEN_MASK;
SCG->SPLLDIV = SCG_SPLLDIV_SPLLDIV1(1) | SCG_SPLLDIV_SPLLDIV2(1);
SCG->SPLLCFG = SCG_SPLLCFG_MULT(20); /* 8MHz * 20 = 160MHz */
/* Wait for PLL lock */
while(!(SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK));
/* Switch to PLL */
SCG->RCCR = SCG_RCCR_DIVCORE(1) | SCG_RCCR_DIVBUS(2) |
SCG_RCCR_DIVSLOW(4) | SCG_RCCR_SCS(6);
/* Enable clock to LPIT */
PCC->PCCn[PCC_LPIT0_INDEX] = PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK;
/* Configure LPIT for system tick */
LPIT0->MCR = LPIT_MCR_M_CEN_MASK; /* Enable module */
/* Configure channel 0 */
LPIT0->TMR[LPIT_CHANNEL].TVAL = LPIT_TICK_PERIOD;
LPIT0->TMR[LPIT_CHANNEL].TCTRL =
LPIT_TMR_TCTRL_T_EN_MASK | /* Enable timer */
LPIT_TMR_TCTRL_MODE_MASK; /* 32-bit counter mode */
/* Enable LPIT interrupt */
LPIT0->MIER |= (1 << LPIT_CHANNEL);
/* Set interrupt priority */
NVIC_SetPriority(LPIT0_IRQn, SYSTICK_PRIORITY);
NVIC_EnableIRQ(LPIT0_IRQn);
/* Configure watchdog */
WDOG->CNT = 0x1000; /* 4s timeout */
WDOG->TOVAL = 0x1000;
WDOG->CS = WDOG_CS_EN_MASK | WDOG_CS_CLK(1) |
WDOG_CS_WIN_MASK | WDOG_CS_UPDATE_MASK;
/* Enable faults */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk |
SCB_SHCSR_BUSFAULTENA_Msk |
SCB_SHCSR_USGFAULTENA_Msk;
/* Enable global interrupts */
__enable_irq();
}
/* Start First Task */
void port_start_first_task(void) {
TaskHandle_t first_task = scheduler_get_current_task();
if (first_task == NULL) {
return;
}
/* Set PSP */
__set_PSP((uint32_t)first_task->stack_pointer);
/* Switch to PSP */
__set_CONTROL(0x02);
__ISB();
/* Restore context */
__asm volatile (
"LDMIA R0!, {R4-R11}\n"
"MSR PSP, R0\n"
"MOV LR, #0xFFFFFFFD\n"
"BX LR\n"
:
: "r" (first_task->stack_pointer)
);
}
/* Context Switch */
void port_context_switch(uint32_t* current_context, uint32_t* next_context) {
current_task_sp = current_context;
next_task_sp = next_context;
/* Trigger PendSV */
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
/* Data synchronization barrier */
__DSB();
__ISB();
}
/* Initialize Task Stack */
uint32_t* port_initialize_task_stack(TaskFunction_t task_function,
void* parameters,
uint32_t* stack_top) {
uint32_t* stack_ptr = stack_top;
/* 8-byte alignment */
stack_ptr = (uint32_t*)((uint32_t)stack_ptr & ~0x7);
/* Exception frame */
*(--stack_ptr) = 0x01000000; /* xPSR */
*(--stack_ptr) = (uint32_t)task_function; /* PC */
*(--stack_ptr) = 0xFFFFFFFD; /* LR */
*(--stack_ptr) = 0x00000000; /* R12 */
*(--stack_ptr) = 0x00000003; /* R3 */
*(--stack_ptr) = 0x00000002; /* R2 */
*(--stack_ptr) = 0x00000001; /* R1 */
*(--stack_ptr) = (uint32_t)parameters; /* R0 */
/* Additional context */
*(--stack_ptr) = 0x0000000B; /* R11 */
*(--stack_ptr) = 0x0000000A; /* R10 */
*(--stack_ptr) = 0x00000009; /* R9 */
*(--stack_ptr) = 0x00000008; /* R8 */
*(--stack_ptr) = 0x00000007; /* R7 */
*(--stack_ptr) = 0x00000006; /* R6 */
*(--stack_ptr) = 0x00000005; /* R5 */
*(--stack_ptr) = 0x00000004; /* R4 */
return stack_ptr;
}
/* LPIT Interrupt Handler */
void LPIT0_IRQHandler(void) {
/* Clear interrupt flag */
LPIT0->MSR |= (1 << LPIT_CHANNEL);
/* Call kernel tick handler */
extern void kernel_tick_handler(void);
kernel_tick_handler();
/* Service watchdog */
WDOG->CNT = 0xB480; /* Refresh sequence */
WDOG->CNT = 0x4B80;
}
/* PendSV Handler */
__attribute__((naked)) void PendSV_Handler(void) {
__asm volatile (
"MRS R0, PSP\n"
"STMDB R0!, {R4-R11}\n"
"LDR R1, =current_task_sp\n"
"STR R0, [R1]\n"
"LDR R0, =next_task_sp\n"
"LDR R1, [R0]\n"
"LDMIA R1!, {R4-R11}\n"
"MSR PSP, R1\n"
"BX LR\n"
);
}
/* SVC Handler */
__attribute__((naked)) void SVC_Handler(void) {
__asm volatile (
"TST LR, #4\n"
"ITE EQ\n"
"MRSEQ R0, MSP\n"
"MRSNE R0, PSP\n"
"LDR R0, [R0, #24]\n"
"LDRB R0, [R0, #-2]\n"
"PUSH {LR}\n"
"BL svc_handler\n"
"POP {LR}\n"
"BX LR\n"
);
}
/* Fault Handlers */
void MemManage_Handler(void) {
uint32_t fault_address = SCB->MMFAR;
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(2, fault_address, fault_status);
while(1) {
/* Safe state */
WDOG->CNT = 0xB480;
WDOG->CNT = 0x4B80;
}
}
void BusFault_Handler(void) {
uint32_t fault_address = SCB->BFAR;
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(3, fault_address, fault_status);
while(1) {
WDOG->CNT = 0xB480;
WDOG->CNT = 0x4B80;
}
}
void UsageFault_Handler(void) {
uint32_t fault_status = SCB->CFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(4, 0, fault_status);
while(1) {
WDOG->CNT = 0xB480;
WDOG->CNT = 0x4B80;
}
}
void HardFault_Handler(void) {
uint32_t fault_status = SCB->HFSR;
extern void fault_handler_process(uint32_t type, uint32_t address, uint32_t status);
fault_handler_process(1, 0, fault_status);
while(1) {
WDOG->CNT = 0xB480;
WDOG->CNT = 0x4B80;
}
}
/* Enter Critical Section */
void port_disable_interrupts(void) {
__disable_irq();
}
/* Exit Critical Section */
void port_enable_interrupts(void) {
__enable_irq();
}
/* Get Current Exception Number */
uint32_t port_get_current_exception(void) {
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
}
+185
View File
@@ -0,0 +1,185 @@
/**
* @file port_asm.s
* @brief NXP S32K assembly routines
*/
.syntax unified
.thumb
.arch armv7e-m
.section .text
/* Global symbols */
.global current_task_sp
.global next_task_sp
.global port_context_switch
.global port_start_first_task
.global port_disable_interrupts
.global port_enable_interrupts
/* Variables */
.section .bss
.align 3
current_task_sp: .word 0
next_task_sp: .word 0
.section .text
.thumb_func
/* Start First Task */
port_start_first_task:
/* Load task stack pointer */
ldr r0, =next_task_sp
ldr r1, [r0]
/* Set PSP */
msr PSP, r1
/* Switch to PSP */
mov r0, #2
msr CONTROL, r0
isb
/* Restore context */
ldmia r1!, {r4-r11}
msr PSP, r1
mov lr, #0xFFFFFFFD
bx lr
/* PendSV Handler */
PendSV_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
ldr r1, =current_task_sp
str r0, [r1]
/* Load next context */
ldr r0, =next_task_sp
ldr r1, [r0]
ldmia r1!, {r4-r11}
msr PSP, r1
bx lr
/* SVC Handler */
SVC_Handler:
tst lr, #4
ite eq
mrseq r0, MSP
mrsne r0, PSP
ldr r0, [r0, #24]
ldrb r0, [r0, #-2]
push {lr}
bl svc_handler
pop {lr}
bx lr
/* Disable Interrupts */
port_disable_interrupts:
cpsid i
bx lr
/* Enable Interrupts */
port_enable_interrupts:
cpsie i
bx lr
/* LPIT Interrupt Handler */
LPIT0_IRQHandler:
/* Save context */
push {r4-r11, lr}
/* Clear interrupt flag */
ldr r0, =0x40037008 /* LPIT0->MSR */
movs r1, #1
str r1, [r0]
/* Call kernel tick handler */
bl kernel_tick_handler
/* Service watchdog */
ldr r0, =0x40052000 /* WDOG->CNT */
ldr r1, =0xB480
str r1, [r0]
ldr r1, =0x4B80
str r1, [r0]
/* Restore context */
pop {r4-r11, lr}
bx lr
/* Hard Fault Handler */
HardFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault status */
ldr r2, =0xE000ED2C /* HFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #1
movs r1, #0
bl fault_handler_process
/* Safe state */
b .
/* Memory Management Fault */
MemManage_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault information */
ldr r1, =0xE000ED34 /* MMFAR */
ldr r1, [r1]
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #2
bl fault_handler_process
/* Safe state */
b .
/* Bus Fault Handler */
BusFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault information */
ldr r1, =0xE000ED38 /* BFAR */
ldr r1, [r1]
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #3
bl fault_handler_process
/* Safe state */
b .
/* Usage Fault Handler */
UsageFault_Handler:
/* Save context */
mrs r0, PSP
stmdb r0!, {r4-r11}
/* Get fault status */
ldr r2, =0xE000ED28 /* CFSR */
ldr r2, [r2]
/* Call fault handler */
movs r0, #4
movs r1, #0
bl fault_handler_process
/* Safe state */
b .
.end
+55
View File
@@ -0,0 +1,55 @@
/**
* @file portmacro.h
* @brief NXP S32K specific macros
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdint.h>
#include "S32K144.h"
/* Data Types */
typedef uint32_t port_stack_type_t;
typedef uint32_t port_base_type_t;
/* Architecture Constants */
#define PORT_STACK_GROWTH_DIRECTION (-1)
#define PORT_BYTE_ALIGNMENT 8
#define PORT_MAX_SYSCALL_INTERRUPT_PRIORITY 0x50
/* Critical Section Macros */
#define portENTER_CRITICAL() __asm volatile("CPSID I" ::: "memory")
#define portEXIT_CRITICAL() __asm volatile("CPSIE I" ::: "memory")
/* Interrupt Control */
#define portENABLE_INTERRUPTS() __asm volatile("CPSIE I" ::: "memory")
#define portDISABLE_INTERRUPTS() __asm volatile("CPSID I" ::: "memory")
/* Context Switch */
#define portYIELD() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
#define portYIELD_FROM_ISR() SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk
/* Memory Barriers */
#define portMEMORY_BARRIER() __asm volatile("DMB" ::: "memory")
#define portSYNC_BARRIER() __asm volatile("DSB" ::: "memory")
#define portINSTRUCTION_BARRIER() __asm volatile("ISB" ::: "memory")
/* NOP */
#define portNOP() __asm volatile("NOP")
/* Watchdog Control */
#define portSERVICE_WATCHDOG() \
do { \
WDOG->CNT = 0xB480; \
WDOG->CNT = 0x4B80; \
} while(0)
/* Low Power Modes */
#define portENTER_SLEEP() __asm volatile("WFI")
#define portENTER_DEEP_SLEEP() __asm volatile("WFE")
/* Endian Definition */
#define portBYTE_ORDER LITTLE_ENDIAN
#endif /* PORTMACRO_H */
+237
View File
@@ -0,0 +1,237 @@
/**
* @file port.c
* @brief RISC-V RV32 architecture specific port
* @note RISC-V is emerging in automotive applications
*/
#include "kernel.h"
#include "task.h"
#include "scheduler.h"
#include "portmacro.h"
/* Context storage */
uint32_t* current_task_sp = NULL;
uint32_t* next_task_sp = NULL;
/* Machine Timer registers */
#define MTIME_ADDR 0x0200BFF8
#define MTIMECMP_ADDR 0x02004000
/* Initialize Architecture Port */
void port_init(void) {
/* Configure machine timer for 1ms interrupts */
volatile uint32_t* mtime = (uint32_t*)MTIME_ADDR;
volatile uint32_t* mtimecmp = (uint32_t*)MTIMECMP_ADDR;
uint32_t current_time = *mtime;
*mtimecmp = current_time + (SystemCoreClock / 1000);
/* Enable machine timer interrupt */
__asm volatile (
"li t0, 0x80\n" /* Machine Timer Interrupt Enable */
"csrs mie, t0\n"
);
/* Enable global interrupts */
__asm volatile (
"csrsi mstatus, 0x8\n" /* Machine Interrupt Enable */
);
}
/* Start First Task */
void port_start_first_task(void) {
TaskHandle_t first_task = scheduler_get_current_task();
if (first_task == NULL) {
return;
}
/* Load task stack pointer */
__asm volatile (
"mv sp, %0\n"
"ret\n"
:
: "r" (first_task->stack_pointer)
);
}
/* Context Switch */
void port_context_switch(uint32_t* current_context, uint32_t* next_context) {
current_task_sp = current_context;
next_task_sp = next_context;
/* Trigger software interrupt */
__asm volatile (
"li t0, 0x8\n" /* Machine Software Interrupt */
"csrs mip, t0\n"
);
}
/* Initialize Task Stack */
uint32_t* port_initialize_task_stack(TaskFunction_t task_function,
void* parameters,
uint32_t* stack_top) {
uint32_t* stack_ptr = stack_top;
/* Align to 16 bytes */
stack_ptr = (uint32_t*)((uint32_t)stack_ptr & ~0xF);
/* Initial stack frame */
*(--stack_ptr) = (uint32_t)parameters; /* a0 */
*(--stack_ptr) = 0; /* a1 */
*(--stack_ptr) = 0; /* a2 */
*(--stack_ptr) = 0; /* a3 */
*(--stack_ptr) = 0; /* a4 */
*(--stack_ptr) = 0; /* a5 */
*(--stack_ptr) = 0; /* a6 */
*(--stack_ptr) = 0; /* a7 */
*(--stack_ptr) = (uint32_t)task_function; /* ra */
*(--stack_ptr) = 0; /* t0 */
*(--stack_ptr) = 0; /* t1 */
*(--stack_ptr) = 0; /* t2 */
*(--stack_ptr) = 0; /* t3 */
*(--stack_ptr) = 0; /* t4 */
*(--stack_ptr) = 0; /* t5 */
*(--stack_ptr) = 0; /* t6 */
*(--stack_ptr) = 0; /* s0 */
*(--stack_ptr) = 0; /* s1 */
*(--stack_ptr) = 0; /* s2 */
*(--stack_ptr) = 0; /* s3 */
*(--stack_ptr) = 0; /* s4 */
*(--stack_ptr) = 0; /* s5 */
*(--stack_ptr) = 0; /* s6 */
*(--stack_ptr) = 0; /* s7 */
*(--stack_ptr) = 0; /* s8 */
*(--stack_ptr) = 0; /* s9 */
*(--stack_ptr) = 0; /* s10 */
*(--stack_ptr) = 0; /* s11 */
*(--stack_ptr) = 0; /* gp */
*(--stack_ptr) = 0; /* tp */
/* mstatus */
*(--stack_ptr) = 0x00001880; /* MPP = Machine mode */
return stack_ptr;
}
/* Machine Timer Interrupt Handler */
void machine_timer_interrupt_handler(void) {
/* Clear interrupt */
volatile uint32_t* mtimecmp = (uint32_t*)MTIMECMP_ADDR;
volatile uint32_t* mtime = (uint32_t*)MTIME_ADDR;
*mtimecmp = *mtime + (SystemCoreClock / 1000);
/* Call kernel tick handler */
extern void kernel_tick_handler(void);
kernel_tick_handler();
}
/* Machine Software Interrupt Handler */
void machine_software_interrupt_handler(void) {
/* Clear interrupt */
__asm volatile (
"li t0, 0x8\n"
"csrc mip, t0\n"
);
/* Perform context switch */
__asm volatile (
/* Save current context */
"addi sp, sp, -128\n"
"sw ra, 0(sp)\n"
"sw t0, 4(sp)\n"
"sw t1, 8(sp)\n"
"sw t2, 12(sp)\n"
"sw s0, 16(sp)\n"
"sw s1, 20(sp)\n"
"sw a0, 24(sp)\n"
"sw a1, 28(sp)\n"
"sw a2, 32(sp)\n"
"sw a3, 36(sp)\n"
"sw a4, 40(sp)\n"
"sw a5, 44(sp)\n"
"sw a6, 48(sp)\n"
"sw a7, 52(sp)\n"
"sw s2, 56(sp)\n"
"sw s3, 60(sp)\n"
"sw s4, 64(sp)\n"
"sw s5, 68(sp)\n"
"sw s6, 72(sp)\n"
"sw s7, 76(sp)\n"
"sw s8, 80(sp)\n"
"sw s9, 84(sp)\n"
"sw s10, 88(sp)\n"
"sw s11, 92(sp)\n"
"sw t3, 96(sp)\n"
"sw t4, 100(sp)\n"
"sw t5, 104(sp)\n"
"sw t6, 108(sp)\n"
"csrr t0, mstatus\n"
"sw t0, 112(sp)\n"
"csrr t0, mepc\n"
"sw t0, 116(sp)\n"
/* Save current stack pointer */
"la t0, current_task_sp\n"
"sw sp, 0(t0)\n"
/* Load next stack pointer */
"la t0, next_task_sp\n"
"lw sp, 0(t0)\n"
/* Restore next context */
"lw ra, 0(sp)\n"
"lw t0, 4(sp)\n"
"lw t1, 8(sp)\n"
"lw t2, 12(sp)\n"
"lw s0, 16(sp)\n"
"lw s1, 20(sp)\n"
"lw a0, 24(sp)\n"
"lw a1, 28(sp)\n"
"lw a2, 32(sp)\n"
"lw a3, 36(sp)\n"
"lw a4, 40(sp)\n"
"lw a5, 44(sp)\n"
"lw a6, 48(sp)\n"
"lw a7, 52(sp)\n"
"lw s2, 56(sp)\n"
"lw s3, 60(sp)\n"
"lw s4, 64(sp)\n"
"lw s5, 68(sp)\n"
"lw s6, 72(sp)\n"
"lw s7, 76(sp)\n"
"lw s8, 80(sp)\n"
"lw s9, 84(sp)\n"
"lw s10, 88(sp)\n"
"lw s11, 92(sp)\n"
"lw t3, 96(sp)\n"
"lw t4, 100(sp)\n"
"lw t5, 104(sp)\n"
"lw t6, 108(sp)\n"
"lw t0, 112(sp)\n"
"csrw mstatus, t0\n"
"lw t0, 116(sp)\n"
"csrw mepc, t0\n"
"addi sp, sp, 128\n"
/* Return from interrupt */
"mret\n"
);
}
/* Enter Critical Section */
void port_disable_interrupts(void) {
__asm volatile (
"csrci mstatus, 0x8\n" /* Clear Machine Interrupt Enable */
);
}
/* Exit Critical Section */
void port_enable_interrupts(void) {
__asm volatile (
"csrsi mstatus, 0x8\n" /* Set Machine Interrupt Enable */
);
}
+39
View File
@@ -0,0 +1,39 @@
/**
* @file portmacro.h
* @brief RISC-V RV32 specific macros
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdint.h>
/* Data Types */
typedef uint32_t port_stack_type_t;
typedef uint32_t port_base_type_t;
/* Architecture Constants */
#define PORT_STACK_GROWTH_DIRECTION (-1)
#define PORT_BYTE_ALIGNMENT 16
/* Critical Section Macros */
#define portENTER_CRITICAL() __asm volatile("csrci mstatus, 0x8")
#define portEXIT_CRITICAL() __asm volatile("csrsi mstatus, 0x8")
/* Interrupt Control */
#define portENABLE_INTERRUPTS() __asm volatile("csrsi mstatus, 0x8")
#define portDISABLE_INTERRUPTS() __asm volatile("csrci mstatus, 0x8")
/* Context Switch */
#define portYIELD() __asm volatile("li t0, 0x8\ncsrs mip, t0")
#define portYIELD_FROM_ISR() __asm volatile("li t0, 0x8\ncsrs mip, t0")
/* Memory Barriers */
#define portMEMORY_BARRIER() __asm volatile("fence")
#define portSYNC_BARRIER() __asm volatile("fence")
#define portINSTRUCTION_BARRIER() __asm volatile("fence.i")
/* NOP */
#define portNOP() __asm volatile("nop")
#endif /* PORTMACRO_H */