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:
@@ -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 */
|
||||
Reference in New Issue
Block a user