ca13734bf0
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.
223 lines
5.8 KiB
C
223 lines
5.8 KiB
C
/**
|
|
* @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);
|
|
}
|