Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3069fe6

Browse files
committed
Added a basic SysTick Scheduler
- Does not contain priorities - Can only add 3 threads
1 parent c486765 commit 3069fe6

File tree

8 files changed

+220
-101
lines changed

8 files changed

+220
-101
lines changed

Systick_Scheduler/.vscode/launch.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"configurations": [
33
{
44
"cwd": "${workspaceFolder}",
5-
"executable": "build/SVC_Handler.elf",
5+
"executable": "build/Systick_Scheduler.elf",
66
"configFiles": [
77
"stm32l4discovery.cfg"
88
],
@@ -16,7 +16,7 @@
1616
},
1717
{
1818
"cwd": "${workspaceFolder}",
19-
"executable": "build/SVC_Handler.elf",
19+
"executable": "build/Systick_Scheduler.elf",
2020
"configFiles": [
2121
"stm32l4discovery.cfg"
2222
],

Systick_Scheduler/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ set(CONTROLLER_NAME "STM32L475xx")
66

77
# Project start
88
set(CMAKE_TOOLCHAIN_FILE "cmake/toolchain.cmake")
9-
project(${PROJECT_NAME})
9+
project(${PROJECT_NAME}
10+
LANGUAGES C ASM
11+
)
1012

1113
# Get compiler and linker flags from here
1214
include(cmake/flags.cmake)
@@ -29,6 +31,7 @@ target_link_options(${USER_PROJECT_TARGET} PRIVATE
2931
# TODO, Add more subdirectories here
3032
add_subdirectory(l0_lowlevel)
3133
add_subdirectory(modules)
34+
add_subdirectory(application)
3235

3336
# Tools and various custom targets
3437
include(cmake/targets.cmake)

Systick_Scheduler/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# SysTick Scheduler
2+
3+
- Does not contain priorities
4+
- Currently cannot dynamically add threads
5+
6+
## Pre-Requisites
7+
8+
- Linked List for stack and thread functions
9+
```c
10+
struct tcb {
11+
uint32_t *stackPt;
12+
struct tcb *nextPt;
13+
};
14+
typedef struct tcb tcbType;
15+
```
16+
- Scheduler Launch
17+
- Systick Handler for loading threads and timekeeping
18+
19+
# Steps
20+
21+
## Adding Threads
22+
23+
- Each `tcb.nextPt` should point to the next `tcb`
24+
- The last `tcb` should point to the first `tcb` as a linked list
25+
- The `tcb.stackPt` should point to the first free stack space that can be used
26+
- `[STACKSIZE - 16]`
27+
- In ascending to descending order (99-84)
28+
- xPSR
29+
- PC
30+
- LR
31+
- r12
32+
- r3
33+
- r2
34+
- r1
35+
- r0
36+
- r11
37+
- r10
38+
- r9
39+
- r8
40+
- r7
41+
- r6
42+
- r5
43+
- r4
44+
- Make sure `xPSR` register is in thumb state i.e `[STACKSIZE - 1] = 0x01000000;`
45+
- Make sure `PC` register points to the thread function
46+
47+
## Launching Threads
48+
49+
- Make sure your SysTick is configured appropriately (with an appropriate quanta size)
50+
- Load the `SP` to `currentPt->stackPt`
51+
- POP all values from `R4-R11`, `R0-R3`, `R12`
52+
- POP `LR`
53+
54+
## SysTick Handler
55+
56+
- PUSH `R4-R11` on the stack
57+
- Including the above registers
58+
- Store old `SP` to `currentPt->stackPt`
59+
- Move to the next linked list
60+
- `current = current->nextPt`
61+
- Load new `SP` to `currentPt->stackPt`
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
target_sources(${USER_PROJECT_TARGET} PRIVATE
2+
osKernel.c
3+
osKernel.S
4+
)
5+
target_include_directories(${USER_PROJECT_TARGET} PRIVATE
6+
.
7+
)

Systick_Scheduler/application/main.c

Lines changed: 17 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,31 @@
1-
#include <stdint.h>
2-
#include <stdlib.h>
3-
#include <string.h>
1+
#include "osKernel.h"
42

5-
#include "gpio/gpio.h"
6-
#include "uart/uart.h"
3+
// * Add these variables to the debug watch window
4+
static uint32_t i, j, k;
75

8-
// NOTE, code cannot be a variable it has to be an immediate value (constant
9-
// value)
10-
#define SVC(code) __ASM volatile("svc %0" : : "I"(code) : "memory")
11-
12-
// Static functions
13-
14-
// SVC Services
15-
static uint32_t svc_service_add(uint32_t a, uint32_t b);
16-
// TODO, Define more svc services here
17-
18-
// UART
19-
static void main__uart_init(void);
20-
21-
// State Variables
22-
static UART_s uart_config;
23-
24-
// Stack contains:
25-
// (When there is NO floating point)
26-
// Page 40 of `Cortex M4 Generic User guide`
27-
// r0, r1, r2, r3, r12, LR, PC and xPSR (from svc_args[0] - svc_args[7])
28-
// First argument (r0) is svc_args[0]
29-
// PC - 2
30-
void SVC_Handler_Main(unsigned int *svc_args) {
31-
// char *r0_address = (char *)svc_args[0];
32-
// char *lr_address = (char *)svc_args[5];
33-
// char *pc_address = (char *)svc_args[6];
6+
void t1(void) {
7+
while (1) {
8+
i++;
9+
}
10+
}
3411

35-
uint32_t svc_number = ((char *)svc_args[6])[-2];
36-
switch (svc_number) {
37-
// Add operation
38-
case 3:
39-
svc_args[2] = svc_args[0] + svc_args[1];
40-
break;
41-
default:
42-
break;
12+
void t2(void) {
13+
while (1) {
14+
j++;
4315
}
4416
}
4517

46-
// * This attribute is VERY IMPORTANT
47-
// Compile with O0 to see the difference with and without
48-
// the __attribute__((naked)) option
49-
__attribute__((naked)) void SVC_Handler(void) {
50-
__ASM volatile(".global SVC_Handler_Main\n"
51-
"TST lr, #4\n"
52-
"ITE EQ\n"
53-
"MRSEQ r0, MSP\n"
54-
"MRSNE r0, PSP\n"
55-
"B SVC_Handler_Main\n" ::
56-
: "memory");
18+
void t3(void) {
19+
while (1) {
20+
k++;
21+
}
5722
}
5823

5924
int main(void) {
60-
main__uart_init();
61-
uart__write_string(&uart_config, "Hello World\r\n");
62-
char buffer[20] = {0};
63-
64-
uint32_t value, new_value;
65-
value = svc_service_add(3, 4);
66-
__itoa(value, buffer, 10);
67-
uart__write_string(&uart_config, buffer);
68-
memset(buffer, 0, sizeof(buffer));
69-
70-
new_value = svc_service_add(2, 3);
71-
__itoa(new_value, buffer, 10);
72-
uart__write_string(&uart_config, buffer);
73-
memset(buffer, 0, sizeof(buffer));
74-
75-
(void)value;
76-
(void)new_value;
77-
25+
osKernelAddThreads(t1, t2, t3);
26+
osKernelLaunch(10);
7827
while (1) {
7928
}
8029

8130
return 0;
8231
}
83-
84-
// STATIC FUNCTION
85-
static void main__uart_init(void) {
86-
// Activate USART1
87-
RCC->APB2ENR |= (1 << 14);
88-
// Activate GPIOB
89-
RCC->AHB2ENR |= (1 << 1);
90-
91-
GPIO_s config = {};
92-
config.mode = GPIO_mode_ALTERNATE_FUNCTION;
93-
config.type = GPIO_type_PUSH_PULL;
94-
config.speed = GPIO_speed_VERY_HIGH_SPEED;
95-
config.pull = GPIO_pull_NO_PULLUP_OR_PULLDOWN;
96-
config.alternate = GPIO_alternate_7;
97-
gpio__init(&config, GPIOB, 6);
98-
gpio__init(&config, GPIOB, 7);
99-
100-
uart_config.baud_rate = 115200U;
101-
uart_config.stop_bit = UART_stop_bit_1_0;
102-
uart_config.word_length = UART_word_length_8;
103-
uart_config.mode = UART_mode_RX_TX;
104-
uart__init(&uart_config, USART1);
105-
}
106-
107-
uint32_t svc_service_add(uint32_t a, uint32_t b) {
108-
SVC(3);
109-
// Named Register Variables
110-
register uint32_t r2_data __ASM("r2");
111-
return r2_data;
112-
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.global currentPt
2+
3+
.text 32
4+
.align 4
5+
.syntax unified
6+
7+
.global SysTick_Handler
8+
.thumb_func
9+
SysTick_Handler:
10+
CPSID i
11+
PUSH {R4-R11}
12+
LDR R0,=currentPt @ R0 points to currentPt
13+
LDR R1,[R0] @ Load currentPt to R1
14+
STR SP,[R1] @ Store SP to address at current->stackPt
15+
LDR R1, [R1, #4] @ r1 = currentPt->next
16+
STR R1, [R0] @ currentPt = r1
17+
LDR SP, [R1] @ SP = currentPt->stackPt
18+
POP {R4-R11}
19+
CPSIE i
20+
BX LR
21+
22+
23+
.global osSchedulerLaunch
24+
.thumb_func
25+
osSchedulerLaunch:
26+
LDR R0,=currentPt
27+
LDR R2,[R0] @ R2 = currentPt
28+
LDR SP,[R2] @ SP = currentPt->stackPt
29+
POP {R4-R11}
30+
POP {R0-R3}
31+
POP {R12}
32+
ADD SP,SP,#4
33+
POP {LR}
34+
ADD SP,SP,#4
35+
CPSIE i
36+
BX LR
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include "osKernel.h"
2+
3+
#include "stm32l4xx.h"
4+
5+
// Constants
6+
#define NUM_OF_THREADS 3
7+
#define STACKSIZE 100
8+
struct tcb {
9+
uint32_t *stackPt;
10+
struct tcb *nextPt;
11+
};
12+
typedef struct tcb tcbType;
13+
14+
// Static functions
15+
static void osKernelStackInit(int thread_number);
16+
17+
// Calls the assembly function
18+
extern void osSchedulerLaunch(void);
19+
20+
// State variables
21+
static tcbType tcbs[NUM_OF_THREADS];
22+
static uint32_t TCB_STACK[NUM_OF_THREADS][STACKSIZE];
23+
24+
// * NOTE, Do not make this static since it is used by the osKernel.S file
25+
tcbType *currentPt;
26+
27+
uint8_t osKernelAddThreads(void (*thread0)(void), void (*thread1)(void),
28+
void (*thread2)(void)) {
29+
__disable_irq();
30+
31+
// Create a Circular Linked list here
32+
tcbs[0].nextPt = &tcbs[1];
33+
tcbs[1].nextPt = &tcbs[2];
34+
tcbs[2].nextPt = &tcbs[0];
35+
36+
osKernelStackInit(0);
37+
TCB_STACK[0][STACKSIZE - 2] = (uint32_t)thread0;
38+
39+
osKernelStackInit(1);
40+
TCB_STACK[1][STACKSIZE - 2] = (uint32_t)thread1;
41+
42+
osKernelStackInit(2);
43+
TCB_STACK[2][STACKSIZE - 2] = (uint32_t)thread2;
44+
45+
// Initialize the currentPt
46+
currentPt = &tcbs[0];
47+
__enable_irq();
48+
return 1;
49+
}
50+
51+
void osKernelLaunch(uint32_t quanta) {
52+
// Disable the SysTick
53+
SysTick->CTRL = 0;
54+
55+
// Reset the initial value
56+
SysTick->VAL = 0;
57+
58+
// Set the lowest priority (largest possible value)
59+
NVIC_SetPriority(SysTick_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
60+
61+
// Set the counter
62+
const uint32_t MILLIS_PRESCALER = SystemCoreClock / 1000;
63+
SysTick->LOAD = quanta * MILLIS_PRESCALER - 1;
64+
65+
// Enable the SysTick source
66+
// enable = 1, tickint = 1, CLKSOURCE=Processor Clock (SystemCoreClock)
67+
SysTick->CTRL = 0x07;
68+
osSchedulerLaunch();
69+
}
70+
71+
// Static functions
72+
static void osKernelStackInit(int thread_number) {
73+
// STACKSIZE = 100
74+
// Last value is 99
75+
// 100 - 16 => 84 uint32_t value to be stored
76+
tcbs[thread_number].stackPt = &TCB_STACK[thread_number][STACKSIZE - 16];
77+
78+
// xPSR value needs to be in the thumb state
79+
// xPSR, PC, LR, r12, r3, r2, r1, r0
80+
// r11, r10, r9, r8, r7, r6, r5, r4
81+
TCB_STACK[thread_number][STACKSIZE - 1] = 0x01000000;
82+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef OS_KERNEL_H_
2+
#define OS_KERNEL_H_
3+
4+
#include <stdint.h>
5+
6+
uint8_t osKernelAddThreads(void (*thread0)(void), void (*thread1)(void),
7+
void (*thread2)(void));
8+
9+
void osKernelLaunch(uint32_t quanta);
10+
11+
#endif

0 commit comments

Comments
 (0)