Files
root ca13734bf0 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.
2026-08-23 03:35:29 -04:00

261 lines
7.0 KiB
C

/**
* @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;
}