YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
task_msp432.cpp
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13//
14// Low-level task implementation for MSP432/Cortex M4(F)
15//
16#pragma GCC diagnostic push
17#pragma GCC diagnostic ignored "-Wpmf-conversions"
18
19#include <cassert>
20#include "task_msp432.h"
21#include "task.h"
22#include "task_idle.h"
23#include "yahal_config.h"
24
25#include "msp.h"
26// Global vars
28bool multitasking_on_core {false};
29task_idle idle_tasks[NUMBER_OF_CORES];
30
31void task::_setup_stack(bool priv) {
32 assert(_stack_size > sizeof(Stack_Frame));
33
34 _stack_ptr = _stack_base +
35 (_stack_size - sizeof(Stack_Frame));
36
37 auto *frame = (Stack_Frame *)_stack_ptr;
38 frame->crsr.psr = 0x01000000; // Set the Thumb-Bit
39 frame->crsr.pc = (void (*)(void))(&task::_run);
40 frame->crsr.r0 = this; // Set the 'this'-pointer
41 frame->cesr.exc_return = EXC_RETURN_THREAD_PSP;
42 frame->cesr.ctrl = priv ? 0x02 : 0x03;
43}
44
45void task::_context_switch() {
47}
48
49uint64_t task::millis() {
50 return _up_ticks[0];
51}
52
53bool task::is_irq_context() {
54 return __get_IPSR() != 0;
55}
56
57bool task::multitasking_running() {
58 return multitasking_on_core;
59}
60
61int8_t task::get_core() {
62 return 0;
63}
64
65void task::start_scheduler() {
66 assert(!multitasking_running());
67 sys_call(SYS_START_SCHEDULER);
68}
69
70void task::yield() {
71 if(multitasking_running()) {
72 sys_call(SYS_YIELD);
73 }
74}
75
76void task::cpu_sleep() {
77 __WFE();
78}
79
80void task::enterCritical() {
81 NVIC_DisableIRQ(PendSV_IRQn);
82// __disable_irq();
83 __DSB();
84 __ISB();
85}
86
87void task::leaveCritical() {
88 NVIC_EnableIRQ(PendSV_IRQn);
89// __enable_irq();
90 __ISB();
91}
92
93bool task::isPrivileged() const {
94 uint32_t ctrl;
95 if (_run_ptr[0] == this) {
96 ctrl = __get_CONTROL();
97 } else {
98 ctrl = _stack_ptr[0];
99 }
100 return (ctrl & 0x01) == 0;
101}
102
103bool task::isUsingFloat() const {
104 if (_run_ptr[0] == this) {
105 return __get_CONTROL() & 0x04;
106 } else {
107 return _stack_ptr[0] & 0x10;
108 }
109}
110
112// IRQ handlers
114
115extern "C" {
116
117void __attribute__((weak)) SysTick_Handler(void) {
118 task::_tick_handler();
119}
120
121uint8_t * switch_context(uint8_t * last_sp) {
122 task::_setStackPtr(last_sp);
123#ifdef CHECK_STACK_OVERFLOW
124 assert((last_sp - task::_getStackBase()) > 10);
125#endif
126 task::_switchToNext();
127 return task::_getStackPtr();
128}
129
130void __attribute__((naked)) PendSV_Handler(void) {
131 asm volatile(
132 " mrs r0, psp @ get the current SP \n"
133 " tst lr, #0x10 @ EXC_RETURN_INT_ONLY_STACK_FRAME \n"
134 " it eq @ \n"
135 " vstmdbeq r0!, {s16-s31} @ push additional FP registers \n"
136 " mov r2, lr @ \n"
137 " mrs r3, control @ \n"
138 " stmdb r0!, {r2-r11} @ save lr, control, r4-r11 \n"
139 " bl switch_context @ \n"
140 " ldmia r0!, {r2-r11} @ get lr, control, r4-r11 \n"
141 " mov lr, r2 @ \n"
142 " msr control, r3 @ \n"
143 " isb @ arch recommendation \n"
144 " tst lr, #0x10 @ EXC_RETURN_INT_ONLY_STACK_FRAME \n"
145 " it eq @ \n"
146 " vldmiaeq r0!, {s16-s31} @ pop additional FP registers \n"
147 " msr psp, r0 @ \n"
148 " bx lr @ jump to new task \n");
149}
150
151void __attribute__((naked)) SVC_Handler(void) {
152 asm volatile(
153 " tst lr, #4 @ EXC_RETURN_PROCESS_STACK_POINTER \n"
154 " ite eq @ \n"
155 " mrseq r0, msp @ R0 (SP) will be first parameter \n"
156 " mrsne r0, psp @ of SCV_Handler_C, \n"
157 " tst lr, 0x20 @ EXC_RETURN_NORMAL_CALLEE_STACKING \n"
158 " it eq @ \n"
159 " addeq r0, #40 @ skip additional context if existing \n"
160 " mov r1, lr @ R1 (LR) is second parameter \n"
161 " bl SVC_Handler_C @ Call C part of SVC handler \n"
162 " bx r0 @ Use return value as EXC_RETURN \n"
163 );
164}
165
166uint32_t SVC_Handler_C(uint32_t * sp, uint32_t exc_return) {
167
168 // Get the PC value from the stack
169 auto * pc = (uint16_t *)sp[6];
170 // Move back one instruction (SVC call) and extract parameter
171 uint16_t svc_arg = pc[-1] & 0xff;
172
173 // uint32_t p2 = sp[2]; // R2
174 // uint32_t p3 = sp[3]; // R3
175
176 switch(svc_arg) {
178 case SYS_START_SCHEDULER:
180 {
181 // Mark this core as multitasking
182 multitasking_on_core = true;
183
184 // Disable the sysTick Timer
185 SysTick->CTRL = 0;
186
187 // Start the Idle task with the lowest priority (1).
188 idle_tasks[0].sign_up(core_t::CURRENT_CORE, 1);
189
190 // The first Task to run is the first created task
191 task::_switchToHead();
192
193 // Set scheduler priority to lowest possible value
194 NVIC_SetPriority(PendSV_IRQn, 0xff);
195
196 // set SysTick to TICK_FREQUENCY
197 SysTick_Config(SystemCoreClock / TICK_FREQUENCY);
198
199 // Return to thread mode and use PSP
200 exc_return = EXC_RETURN_THREAD_PSP;
201
202 // Only restore registers r0-PSR, because these
203 // will be restored on return of the SVC-handler
204 __set_PSP((uint32_t)(task::_getStackPtr() +
205 sizeof(callee_saved_registers)));
206
207 // Set control register (set privileged)
208 __set_CONTROL(((Stack_Frame *)task::_getStackPtr())->cesr.ctrl);
209 __ISB();
210 break;
211 }
213 case SYS_YIELD:
215 {
216 task::_scheduler();
217 break;
218 }
220 default:
222 {
223 assert(false);
224 }
225 }
226 return exc_return;
227}
228
229} // extern "C"
230
231#pragma GCC diagnostic pop
#define SCB_ICSR_PENDSVSET_Msk
#define SCB
#define SysTick
#define __ISB()
Instruction Synchronization Barrier.
#define __DSB()
Data Synchronization Barrier.
#define __WFE
Wait For Event.
__STATIC_INLINE void __set_CONTROL(uint32_t control)
Set Control Register.
__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
Set Process Stack Pointer.
__STATIC_INLINE uint32_t __get_CONTROL(void)
Enable IRQ Interrupts.
__STATIC_INLINE uint32_t __get_IPSR(void)
Get IPSR Register.
void __attribute__((noreturn))(*rom_reset_usb_boot_fn)(uint32_t
Reboot the device into BOOTSEL mode.
Definition bootrom.h:66