From 410ff88e267f788ae6e1b0086cd86e4b1d3d093b Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 11:02:51 +0200 Subject: [PATCH 01/19] initial import of sources --- Makefile | 81 ++++++++++++++++++ README.md | 3 + main.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.ld | 71 ++++++++++++++++ syscall.c | 141 ++++++++++++++++++++++++++++++++ usartu.c | 19 +++++ usartu.h | 7 ++ 7 files changed, 561 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 main.c create mode 100644 main.ld create mode 100644 syscall.c create mode 100644 usartu.c create mode 100644 usartu.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..053411b --- /dev/null +++ b/Makefile @@ -0,0 +1,81 @@ +# +# Copyright: Oleg Borodin 2018 +# + +.SECONDARY: + +CFLAGS+= -I. -Os -DSTM32F4 -std=c99 +#CFLAGS+= -mthumb +#CFLAGS+= -march=armv7e-m +CFLAGS+= -mfloat-abi=hard +#CFLAGS+= -mfpu=fpv4-sp-d16 +CFLAGS+= -mcpu=cortex-m4 +CFLAGS+= -fno-common -ffunction-sections -fdata-sections +CFLAGS+= -g -gdwarf-2 +CFLAGS+= -Wall + +LDFLAGS+= ${CFLAGS} +LDFLAGS+= --static +#LDFLAGS+= -nostartfiles +LDFLAGS+= -T main.ld + +LDFLAGS+= -Wl,-Map=main.map +LDFLAGS+= -Wl,--cref -Wl,--gc-sections +LDFLAGS+= -lopencm3_stm32f4 +LDFLAGS+= -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group + +TARGET= arm-eabi + +all: main.bin + +OBJS+= main.o +OBJS+= syscall.o +OBJS+= usartu.o + +main.elf: $(OBJS) + $(TARGET)-gcc $(^F) $(LDFLAGS) -o $@ + $(TARGET)-size --format=berkeley $@ + +%.o: %.c + $(TARGET)-gcc $(CFLAGS) -c -o $@ $< + +%.o: %.S + $(TARGET)-as $(ASFLAGS) -o $@ $< + +%.bin: %.elf + $(TARGET)-objcopy -O binary $< $@ + +%.elf: %.o + $(TARGET)-gcc $(^F) $(LDFLAGS) -o $@ + $(TARGET)-size --format=berkeley $@ + +clean: + rm -f *.i *.o *.elf *.bin *.map *~ *.hex *.d *.s + +flash: main.bin + @openocd \ + -c 'puts "--- START --------------------"' \ + -f 'interface/stlink.cfg' \ + -f 'target/stm32f4x.cfg' \ + -c 'puts "--- INIT --------------------"' \ + -c "init" \ + -c "reset halt" \ + -c 'puts "--- WRITE --------------------"' \ + -c "flash write_image erase $< 0x08000000"\ + -c 'puts "--- VERIFY --------------------"' \ + -c "verify_image $<" \ + -c 'puts "--- RESET --------------------"' \ + -c "reset" \ + -c 'puts "--- DONE --------------------"' \ + -c "shutdown" + +debug: main.bin + @openocd \ + -c 'puts "--- START --------------------"' \ + -f 'interface/stlink.cfg' \ + -f 'target/stm32f4x.cfg' \ + -c 'puts "--- INIT --------------------"' \ + -c "init" \ + -c "halt" \ + -c "poll" +#EOF diff --git a/README.md b/README.md new file mode 100644 index 0000000..2daf97f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ + +# Minimal STM32 F4 task sheduler + diff --git a/main.c b/main.c new file mode 100644 index 0000000..9bfb803 --- /dev/null +++ b/main.c @@ -0,0 +1,239 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#include +#include +#include + +#include +#include +#include + + +#include +#include +#include +#include + +#include "usartu.h" + +void delay(uint32_t n) { + for (volatile int i = 0; i < n * 800; i++) + __asm__("nop"); +} + +static void clock_setup(void) { + rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]); + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_USART1); +} + +static void usart_setup(void) { + + usart_disable(USART1); + nvic_disable_irq(NVIC_USART1_IRQ); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO10); + gpio_set_af(GPIOA, GPIO_AF7, GPIO9 | GPIO10); + + usart_set_baudrate(USART1, 115200); + usart_set_databits(USART1, 8); + usart_set_stopbits(USART1, USART_STOPBITS_1); + usart_set_parity(USART1, USART_PARITY_NONE); + usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); + usart_set_mode(USART1, USART_MODE_TX_RX); + + usart_disable_rx_interrupt(USART1); + + usart_enable(USART1); +} + +static void systick_setup(void) { + systick_set_frequency(10000, rcc_ahb_frequency); + systick_interrupt_enable(); + systick_counter_enable(); +} + + +void scheduler_yield(void); +int g_uptime; + +void sys_tick_handler(void) { + g_uptime++; + scheduler_yield(); +} + +#define SCHEDULER_NUM_TASKS 4 +#define TASK_STACK_SIZE 2048 + +typedef struct { + void (*entry)(void); + void *stack; + unsigned stack_size; + uint32_t sp; + bool runnable; +} task_t; + + +#define TASK_COUNT_REG 9 + +typedef struct __attribute__((packed)) { + struct { + uint32_t registers[TASK_COUNT_REG]; + } sw_frame; + struct { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; + } nvic_frame; +} stack_frame_t; + +typedef struct { + task_t tasks[SCHEDULER_NUM_TASKS]; + uint8_t current_task; +} scheduler_t; + +static scheduler_t g_scheduler = { + .current_task = 0 +}; + + +static void task_exit_func(void) { + while (true); +} + +#define RETURN_PSR 0x21000000 +#define STACK_FILL 0xA5 + +#define SCHEDULER_MAX_TASKS 16 + +void scheduler_init(scheduler_t *scheduler) { + for (int i = 0; i < SCHEDULER_NUM_TASKS; i++) { + task_t *task = &(scheduler->tasks[i]); + task->stack = NULL; + task->stack_size = 0; + task->sp = (uint32_t)NULL; + task->runnable = false; + } + scheduler->current_task = 0; +} + +void scheduler_task(scheduler_t *scheduler, int task_no, void (*entry)(void)) { + + task_t *task = &(scheduler->tasks[task_no]); + task->stack = (void*)malloc(TASK_STACK_SIZE); + task->stack_size = TASK_STACK_SIZE; + memset(task->stack, STACK_FILL, task->stack_size); + + task->sp = (uint32_t)(task->stack + task->stack_size); + task->sp -= sizeof(stack_frame_t); + + stack_frame_t *frame = (stack_frame_t*)task->sp; + frame->nvic_frame.lr = (uint32_t)task_exit_func; + frame->nvic_frame.pc = (uint32_t)entry; + frame->nvic_frame.psr = RETURN_PSR; + + task->runnable = true; +} + +static void scheduler_switch(scheduler_t *scheduler) { + do { + scheduler->current_task = (scheduler->current_task + 1) % SCHEDULER_NUM_TASKS; + } while (!scheduler->tasks[scheduler->current_task].runnable); +} + +#define EXC_RETURN_MODE_THREAD 0x00000004 +#define RETURN_ON_PSP_THREAD 0xFFFFFFFD + + +void __attribute__((naked)) pend_sv_handler(void) { + + const uint32_t RETURN_ON_PSP = RETURN_ON_PSP_THREAD; + + __asm__("cpsid if":::"memory"); + uint32_t lr; + __asm__("mov %0, lr\n":"=r"(lr)); + + if (lr & EXC_RETURN_MODE_THREAD) { + uint32_t psp; + __asm__( + "mrs %0, psp\n" + "stmdb %0!, {r2,r4-r11}\n" + "msr psp, %0\n" : "=r"(psp) + ); + g_scheduler.tasks[g_scheduler.current_task].sp = psp; + } else { + __asm__( + "stmdb sp!, {r2,r4-r11}\n"); + } + + scheduler_switch(&g_scheduler); + + uint32_t psp = (uint32_t)g_scheduler.tasks[g_scheduler.current_task].sp; + __asm__( + "ldmfd %0!, {r2,r4-r11}\n" + "msr psp, %0\n"::"r"(psp) + ); + + __asm__("cpsie if" ::: "memory"); + __asm__("bx %0\n"::"r"(RETURN_ON_PSP)); +} + +void scheduler_yield(void) { + SCB_ICSR |= SCB_ICSR_PENDSVSET; + __asm__( + "nop\n" + "nop\n" + "nop\n" + "nop\n" + ); +} + +void task1(void) { + while (true) { + printf("task 1 %d\r\n", g_uptime); + delay(3000); + }; +} + +void task2(void) { + while (true) { + printf("task 2 %d\r\n", g_uptime); + delay(3100); + }; +} + +void task3(void) { + while (true) { + printf("task 3 %d\r\n", g_uptime); + delay(3200); + }; +} + +void task4(void) { + while (true) { + printf("task 4 %d\r\n", g_uptime); + delay(3300); + }; +} + +int main(void) { + g_uptime = 0; + clock_setup(); + usart_setup(); + scheduler_init(&g_scheduler); + scheduler_task(&g_scheduler, 0, task1); + scheduler_task(&g_scheduler, 1, task2); + scheduler_task(&g_scheduler, 2, task3); + scheduler_task(&g_scheduler, 3, task4); + + systick_setup(); + + while (true); +} diff --git a/main.ld b/main.ld new file mode 100644 index 0000000..49c4b7e --- /dev/null +++ b/main.ld @@ -0,0 +1,71 @@ + +MEMORY { + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +EXTERN (vector_table) + +ENTRY(reset_handler) + +SECTIONS +{ + .text : { + *(.vectors) + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + } >FLASH + + .preinit_array : { + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + } >FLASH + + .init_array : { + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } >FLASH + + .fini_array : { + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + } >FLASH + + . = ALIGN(4); + _etext = .; + + .data : { + _data = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >SRAM AT >FLASH + + _data_loadaddr = LOADADDR(.data); + + .bss : { + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >SRAM + + + . = ALIGN(4); + _end = .; +} + +PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); + +PROVIDE(_heap = _end ); +PROVIDE(_eheap = ORIGIN(SRAM) + LENGTH(SRAM)); diff --git a/syscall.c b/syscall.c new file mode 100644 index 0000000..618d8c5 --- /dev/null +++ b/syscall.c @@ -0,0 +1,141 @@ +/* + * Copyright 2022 Oleg Borodin + */ + + +#include + +#include +#include +#include +#include +#include + +#include + +#undef errno +extern int errno; + +char *__env[1] = { 0 }; + +char **environ = __env; + +int _execve(char *name, char **argv, char **env) { + errno = ENOMEM; + return -1; +} + +int _fork(void) { + errno = EAGAIN; + return -1; +} + +int _getpid(void) { + return 1; +} + +int _kill(int pid, int sig) { + errno = EINVAL; + return -1; +} + +int _exit() { + while (1); +} + +int _isatty(int file) { + return 1; +} + +int _fstat(int file, struct stat *st) { + st->st_mode = S_IFCHR; + return 0; +} + +int _link(char *old, char *new) { + errno = EMLINK; + return -1; +} + +int _lseek(int file, int ptr, int dir) { + return 0; +} + +int _open(const char *name, int flags, int mode) { + return -1; +} + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 3 + + +int _read(int file, char *ptr, int len) { + int i = 0; + while (i < len) { + ptr[i++] = 0; + } + return i; +} + + +int _write(int file, char *ptr, int len) { + int i; + + if ((file == STDOUT) || (file == STDERR)) { + for (i = 0; i < len; i++) { + usart_putc(USART1, ptr[i]); + } + return len; + } + return 0; +} + +int _stat(char *file, struct stat *st) { + st->st_mode = S_IFCHR; + return 0; +} + +int _close(int file) { + return -1; +} + + +int _times(struct tms *buf) { + return -1; +} + +int _unlink(char *name) { + errno = ENOENT; + return -1; +} + +int _wait(int *status) { + errno = ECHILD; + return -1; +} + + +void *_sbrk(int incr) { + extern const void *_heap; + extern const void *_eheap; + + void *prev_heap; + static void *heap = NULL; + + if (heap == NULL) { + heap = (void *)&_heap; + } + + void* next_heap = heap + incr; + + if (next_heap >= (void*)&_eheap) { + errno = ENOMEM; + return NULL; + } + + prev_heap = heap; + heap = next_heap; + + return (void*)prev_heap; +} diff --git a/usartu.c b/usartu.c new file mode 100644 index 0000000..e0b15db --- /dev/null +++ b/usartu.c @@ -0,0 +1,19 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#include + +#include +#include + +void usart_puts(uint32_t usart, uint8_t * str) { + uint16_t i = 0; + while (str[i] != 0) { + usart_send_blocking(usart, str[i++]); + } +} + +void usart_putc(uint32_t usart, uint8_t c) { + usart_send_blocking(usart, c); +} diff --git a/usartu.h b/usartu.h new file mode 100644 index 0000000..9d1243f --- /dev/null +++ b/usartu.h @@ -0,0 +1,7 @@ +#ifndef _USARTU_H_XYZ +#define _USARTU_H_XYZ + +void usart_puts(uint32_t usart, uint8_t * str); +void usart_putc(uint32_t usart, uint8_t c); + +#endif From b8970a05b3a90e58617a2ab28abecfe0aa3c6e35 Mon Sep 17 00:00:00 2001 From: Oleg B Date: Tue, 30 Aug 2022 11:10:45 +0200 Subject: [PATCH 02/19] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2daf97f..83c1f58 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # Minimal STM32 F4 task sheduler +NanoOS: "It is impossible to do less" =) From 2322d89b31214b09e59582daeb0f67fddd1d08df Mon Sep 17 00:00:00 2001 From: Oleg B Date: Tue, 30 Aug 2022 11:26:25 +0200 Subject: [PATCH 03/19] Update README.md --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index 83c1f58..8fe802a 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,44 @@ # Minimal STM32 F4 task sheduler NanoOS: "It is impossible to do less" =) + +## Register frame description + +``` +/* + * ABI: r0..r3 are caller-saved (scratch registers), R4..R12 are callee-saved. + * It is appropriate to use R12 for a system call opcode (saved by NVIC). The + * stack pointer points to the current extent of the stack -- it is decremented + * before being used as index in a store. The stack grows downwards, to lower + * addresses. When an interrupt is processed, 8 registers are stored. LR is set + * to a special value that makes an ordinary function return into a return from + * interrupt. The LR value indicates which stack is going to be used (process + * or main) and can be modified before return. + * + * ____________________ + * Stack | | + * | | + * higher | R4 | <-- SP saved in TCB (64B context) + * addresses | R5 | ^ + * | ^ | R6 | | + * | | | R7 | | 8 registers pushed by handler: + * | | | R8 | | R4..R11 + * | | | R9 | | Full task context is now stored + * V | | R10 | | + * | | R11 | | + * direction | R0 | <-- SP when SVC handler gets control + * of growth | R1 | ^ + * | R2 | | + * | R3 | | 8 registers are pushed by + * | R12 | | the NVIC hardware: + * | LR (R14) | | xPSR, PC, LR, R12, R3..R0 + * | PC (R15) | | + * | xPSR | | + * | | <-- SP before SVC + * | (stuff) | + * Stack + | | + * StackSize |____________________| + * + */ + +``` From 1b79fc48d6bb450bc2a6c79fd60d226ee176c436 Mon Sep 17 00:00:00 2001 From: Oleg B Date: Tue, 30 Aug 2022 12:11:55 +0200 Subject: [PATCH 04/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fe802a..c456049 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Minimal STM32 F4 task sheduler -NanoOS: "It is impossible to do less" =) +NanoOS: "Make less makes no sense" =) ## Register frame description From 5887252da51d0592e4dc2018ddfdd3782c8403f3 Mon Sep 17 00:00:00 2001 From: Oleg B Date: Tue, 30 Aug 2022 12:12:25 +0200 Subject: [PATCH 05/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c456049..1dc29bb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Minimal STM32 F4 task sheduler +## Minimal STM32 F4/F7 task sheduler NanoOS: "Make less makes no sense" =) -## Register frame description +### Register frame description ``` /* From 02c112b94519a3fbe677e5e79e02d2fde9004961 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 12:19:19 +0200 Subject: [PATCH 06/19] removed double r2 saving/restoring --- main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index 9bfb803..31c77c5 100644 --- a/main.c +++ b/main.c @@ -76,7 +76,7 @@ typedef struct { } task_t; -#define TASK_COUNT_REG 9 +#define TASK_COUNT_REG 8 typedef struct __attribute__((packed)) { struct { @@ -164,20 +164,20 @@ void __attribute__((naked)) pend_sv_handler(void) { uint32_t psp; __asm__( "mrs %0, psp\n" - "stmdb %0!, {r2,r4-r11}\n" + "stmdb %0!, {r4-r11}\n" "msr psp, %0\n" : "=r"(psp) ); g_scheduler.tasks[g_scheduler.current_task].sp = psp; } else { __asm__( - "stmdb sp!, {r2,r4-r11}\n"); + "stmdb sp!, {r4-r11}\n"); } scheduler_switch(&g_scheduler); uint32_t psp = (uint32_t)g_scheduler.tasks[g_scheduler.current_task].sp; __asm__( - "ldmfd %0!, {r2,r4-r11}\n" + "ldmfd %0!, {r4-r11}\n" "msr psp, %0\n"::"r"(psp) ); From 4393e8962447bb4cca2f44ec594ccc3122b97f86 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 16:23:54 +0200 Subject: [PATCH 07/19] added .gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3ca5774 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.elf +*.bin +*.map +*.geany +*.o +*~ +work From f5d433f177a47fcacd2fe16c2a2972c04e2da4c7 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 16:25:19 +0200 Subject: [PATCH 08/19] scheduler logic moved to semaphore.* --- Makefile | 2 + main.c | 151 +++++----------------------------------------------- scheduler.c | 124 ++++++++++++++++++++++++++++++++++++++++++ scheduler.h | 30 +++++++++++ 4 files changed, 168 insertions(+), 139 deletions(-) create mode 100644 scheduler.c create mode 100644 scheduler.h diff --git a/Makefile b/Makefile index 053411b..8024a4c 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ all: main.bin OBJS+= main.o OBJS+= syscall.o OBJS+= usartu.o +OBJS+= scheduler.o + main.elf: $(OBJS) $(TARGET)-gcc $(^F) $(LDFLAGS) -o $@ diff --git a/main.c b/main.c index 31c77c5..7df08d3 100644 --- a/main.c +++ b/main.c @@ -16,8 +16,10 @@ #include #include +#include "scheduler.h" #include "usartu.h" + void delay(uint32_t n) { for (volatile int i = 0; i < n * 800; i++) __asm__("nop"); @@ -55,146 +57,8 @@ static void systick_setup(void) { systick_counter_enable(); } - -void scheduler_yield(void); int g_uptime; -void sys_tick_handler(void) { - g_uptime++; - scheduler_yield(); -} - -#define SCHEDULER_NUM_TASKS 4 -#define TASK_STACK_SIZE 2048 - -typedef struct { - void (*entry)(void); - void *stack; - unsigned stack_size; - uint32_t sp; - bool runnable; -} task_t; - - -#define TASK_COUNT_REG 8 - -typedef struct __attribute__((packed)) { - struct { - uint32_t registers[TASK_COUNT_REG]; - } sw_frame; - struct { - uint32_t r0; - uint32_t r1; - uint32_t r2; - uint32_t r3; - uint32_t r12; - uint32_t lr; - uint32_t pc; - uint32_t psr; - } nvic_frame; -} stack_frame_t; - -typedef struct { - task_t tasks[SCHEDULER_NUM_TASKS]; - uint8_t current_task; -} scheduler_t; - -static scheduler_t g_scheduler = { - .current_task = 0 -}; - - -static void task_exit_func(void) { - while (true); -} - -#define RETURN_PSR 0x21000000 -#define STACK_FILL 0xA5 - -#define SCHEDULER_MAX_TASKS 16 - -void scheduler_init(scheduler_t *scheduler) { - for (int i = 0; i < SCHEDULER_NUM_TASKS; i++) { - task_t *task = &(scheduler->tasks[i]); - task->stack = NULL; - task->stack_size = 0; - task->sp = (uint32_t)NULL; - task->runnable = false; - } - scheduler->current_task = 0; -} - -void scheduler_task(scheduler_t *scheduler, int task_no, void (*entry)(void)) { - - task_t *task = &(scheduler->tasks[task_no]); - task->stack = (void*)malloc(TASK_STACK_SIZE); - task->stack_size = TASK_STACK_SIZE; - memset(task->stack, STACK_FILL, task->stack_size); - - task->sp = (uint32_t)(task->stack + task->stack_size); - task->sp -= sizeof(stack_frame_t); - - stack_frame_t *frame = (stack_frame_t*)task->sp; - frame->nvic_frame.lr = (uint32_t)task_exit_func; - frame->nvic_frame.pc = (uint32_t)entry; - frame->nvic_frame.psr = RETURN_PSR; - - task->runnable = true; -} - -static void scheduler_switch(scheduler_t *scheduler) { - do { - scheduler->current_task = (scheduler->current_task + 1) % SCHEDULER_NUM_TASKS; - } while (!scheduler->tasks[scheduler->current_task].runnable); -} - -#define EXC_RETURN_MODE_THREAD 0x00000004 -#define RETURN_ON_PSP_THREAD 0xFFFFFFFD - - -void __attribute__((naked)) pend_sv_handler(void) { - - const uint32_t RETURN_ON_PSP = RETURN_ON_PSP_THREAD; - - __asm__("cpsid if":::"memory"); - uint32_t lr; - __asm__("mov %0, lr\n":"=r"(lr)); - - if (lr & EXC_RETURN_MODE_THREAD) { - uint32_t psp; - __asm__( - "mrs %0, psp\n" - "stmdb %0!, {r4-r11}\n" - "msr psp, %0\n" : "=r"(psp) - ); - g_scheduler.tasks[g_scheduler.current_task].sp = psp; - } else { - __asm__( - "stmdb sp!, {r4-r11}\n"); - } - - scheduler_switch(&g_scheduler); - - uint32_t psp = (uint32_t)g_scheduler.tasks[g_scheduler.current_task].sp; - __asm__( - "ldmfd %0!, {r4-r11}\n" - "msr psp, %0\n"::"r"(psp) - ); - - __asm__("cpsie if" ::: "memory"); - __asm__("bx %0\n"::"r"(RETURN_ON_PSP)); -} - -void scheduler_yield(void) { - SCB_ICSR |= SCB_ICSR_PENDSVSET; - __asm__( - "nop\n" - "nop\n" - "nop\n" - "nop\n" - ); -} - void task1(void) { while (true) { printf("task 1 %d\r\n", g_uptime); @@ -223,8 +87,17 @@ void task4(void) { }; } +void sys_tick_handler(void) { + g_uptime++; + scheduler_yield(); +} + + int main(void) { - g_uptime = 0; + g_uptime = 0; + + static scheduler_t g_scheduler; + clock_setup(); usart_setup(); scheduler_init(&g_scheduler); diff --git a/scheduler.c b/scheduler.c new file mode 100644 index 0000000..8b4087b --- /dev/null +++ b/scheduler.c @@ -0,0 +1,124 @@ +/* + * Copyright 2022 Oleg Borodin + * + */ + +#include + +#include +#include +#include +#include + +#include "scheduler.h" + + +static scheduler_t* m_scheduler; + +#define TASK_COUNT_REG 8 + +typedef struct __attribute__((packed)) { + struct { + uint32_t registers[TASK_COUNT_REG]; + } sw_frame; + struct { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; + } nvic_frame; +} stack_frame_t; + +static void task_exit_func(void) { + while (true); +} + +#define RETURN_PSR 0x21000000 +#define STACK_FILL 0xA5 + +void scheduler_init(scheduler_t *scheduler) { + + for (int i = 0; i < SCHEDULER_NUM_TASKS; i++) { + task_t *task = &(scheduler->tasks[i]); + task->stack = NULL; + task->stack_size = 0; + task->sp = (uint32_t)NULL; + task->runnable = false; + } + scheduler->current_task = 0; + m_scheduler = scheduler; +} + +void scheduler_task(scheduler_t *scheduler, int task_no, void (*entry)(void)) { + + task_t *task = &(scheduler->tasks[task_no]); + task->stack = (void*)malloc(TASK_STACK_SIZE); + task->stack_size = TASK_STACK_SIZE; + memset(task->stack, STACK_FILL, task->stack_size); + + task->sp = (uint32_t)(task->stack + task->stack_size); + task->sp -= sizeof(stack_frame_t); + + stack_frame_t *frame = (stack_frame_t*)task->sp; + frame->nvic_frame.lr = (uint32_t)task_exit_func; + frame->nvic_frame.pc = (uint32_t)entry; + frame->nvic_frame.psr = RETURN_PSR; + + task->runnable = true; +} + +static void scheduler_switch(scheduler_t *scheduler) { + do { + scheduler->current_task = (scheduler->current_task + 1) % SCHEDULER_NUM_TASKS; + } while (!scheduler->tasks[scheduler->current_task].runnable); +} + +#define EXC_RETURN_MODE_THREAD 0x00000004 +#define RETURN_ON_PSP_THREAD 0xFFFFFFFD + +void __attribute__((naked)) pend_sv_handler(void) { + + const uint32_t RETURN_ON_PSP = RETURN_ON_PSP_THREAD; + + __asm__("cpsid if":::"memory"); + uint32_t lr; + __asm__("mov %0, lr\n":"=r"(lr)); + + if (lr & EXC_RETURN_MODE_THREAD) { + uint32_t psp; + __asm__( + "mrs %0, psp\n" + "stmdb %0!, {r4-r11}\n" + "msr psp, %0\n" : "=r"(psp) + ); + m_scheduler->tasks[m_scheduler->current_task].sp = psp; + } else { + __asm__( + "stmdb sp!, {r4-r11}\n"); + } + + scheduler_switch(m_scheduler); + + uint32_t psp = (uint32_t)m_scheduler->tasks[m_scheduler->current_task].sp; + __asm__( + "ldmfd %0!, {r4-r11}\n" + "msr psp, %0\n"::"r"(psp) + ); + + __asm__("cpsie if" ::: "memory"); + __asm__("bx %0\n"::"r"(RETURN_ON_PSP)); +} + +void scheduler_yield(void) { + SCB_ICSR |= SCB_ICSR_PENDSVSET; + __asm__( + "nop\n" + "nop\n" + "nop\n" + "nop\n" + ); +} diff --git a/scheduler.h b/scheduler.h new file mode 100644 index 0000000..c99e380 --- /dev/null +++ b/scheduler.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022 Oleg Borodin + * + */ + +#ifndef SCHEDULER_H_QWERTY +#define SCHEDULER_H_QWERTY + +#define SCHEDULER_NUM_TASKS 4 +#define TASK_STACK_SIZE 2048 + +typedef struct { + void (*entry)(void); + void *stack; + unsigned stack_size; + uint32_t sp; + bool runnable; +} task_t; + +typedef struct { + task_t tasks[SCHEDULER_NUM_TASKS]; + uint8_t current_task; +} scheduler_t; + + +void scheduler_init(scheduler_t *scheduler); +void scheduler_task(scheduler_t *scheduler, int task_no, void (*entry)(void)); +void scheduler_yield(void); + +#endif From 4c67d0bba4347085ae71ff7d2ad57347e1d7c8ae Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 16:26:29 +0200 Subject: [PATCH 09/19] added primitive semaphore --- semaphore.c | 23 +++++++++++++++++++++++ semaphore.h | 12 ++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 semaphore.c create mode 100644 semaphore.h diff --git a/semaphore.c b/semaphore.c new file mode 100644 index 0000000..f6b885a --- /dev/null +++ b/semaphore.c @@ -0,0 +1,23 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#include "semaphore.h" + +typedef struct { + int value; +} sem_t; + +int sem_init(sem_t* sem, int value) { + sem->value = value; +} + +int sem_wait(sem_t* sem) { + while(sem->value > 0); + sem->value--; +} + + +int sem_post(sem_t* sem) { + sem->value++; +} diff --git a/semaphore.h b/semaphore.h new file mode 100644 index 0000000..0cf2b8e --- /dev/null +++ b/semaphore.h @@ -0,0 +1,12 @@ +/* + * Copyright 2022 Oleg Borodin + */ + + +typedef struct { + int value; +} sem_t; + +int sem_init(sem_t* sem, int value); +int sem_wait(sem_t* sem); +int sem_post(sem_t* sem); From 6974c2b8e60dcc23246640990d90431fcad77c26 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 19:01:21 +0200 Subject: [PATCH 10/19] added mem-block semaphore --- Makefile | 6 ++++-- main.c | 6 +++++- semaphore.c | 20 +++++++++----------- semaphore.h | 10 ++++++---- semoper.S | 31 +++++++++++++++++++++++++++++++ semoper.h | 13 +++++++++++++ 6 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 semoper.S create mode 100644 semoper.h diff --git a/Makefile b/Makefile index 8024a4c..0ae82bd 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ CFLAGS+= -fno-common -ffunction-sections -fdata-sections CFLAGS+= -g -gdwarf-2 CFLAGS+= -Wall + LDFLAGS+= ${CFLAGS} LDFLAGS+= --static #LDFLAGS+= -nostartfiles @@ -32,7 +33,8 @@ OBJS+= main.o OBJS+= syscall.o OBJS+= usartu.o OBJS+= scheduler.o - +OBJS+= semoper.o +OBJS+= semaphore.o main.elf: $(OBJS) $(TARGET)-gcc $(^F) $(LDFLAGS) -o $@ @@ -42,7 +44,7 @@ main.elf: $(OBJS) $(TARGET)-gcc $(CFLAGS) -c -o $@ $< %.o: %.S - $(TARGET)-as $(ASFLAGS) -o $@ $< + $(TARGET)-gcc $(CFLAGS) -c -o $@ $< %.bin: %.elf $(TARGET)-objcopy -O binary $< $@ diff --git a/main.c b/main.c index 7df08d3..55b5668 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,7 @@ #include "scheduler.h" #include "usartu.h" +#include "semoper.h" void delay(uint32_t n) { @@ -81,8 +82,11 @@ void task3(void) { } void task4(void) { + static volatile int32_t t4; + while (true) { - printf("task 4 %d\r\n", g_uptime); + sem_post32(&t4, (int32_t)1); + printf("task 4 %d %lu\r\n", g_uptime, t4); delay(3300); }; } diff --git a/semaphore.c b/semaphore.c index f6b885a..a8e0032 100644 --- a/semaphore.c +++ b/semaphore.c @@ -3,21 +3,19 @@ */ #include "semaphore.h" +#include "semoper.h" -typedef struct { - int value; -} sem_t; - -int sem_init(sem_t* sem, int value) { +void sem_init(sem_t* sem, int32_t value) { sem->value = value; } -int sem_wait(sem_t* sem) { - while(sem->value > 0); - sem->value--; +int32_t sem_wait(sem_t* sem) { + //while(sem->value > 0); + //sem->value--; + return sem_wait32(&(sem->value), (int32_t)1); } - -int sem_post(sem_t* sem) { - sem->value++; +int32_t sem_post(sem_t* sem) { + //sem->value++; + return sem_post32(&(sem->value), (int32_t)1); } diff --git a/semaphore.h b/semaphore.h index 0cf2b8e..c8d005c 100644 --- a/semaphore.h +++ b/semaphore.h @@ -3,10 +3,12 @@ */ +#include + typedef struct { - int value; + int32_t value; } sem_t; -int sem_init(sem_t* sem, int value); -int sem_wait(sem_t* sem); -int sem_post(sem_t* sem); +void sem_init(sem_t* sem, int32_t value); +int32_t sem_wait(sem_t* sem); +int32_t sem_post(sem_t* sem); diff --git a/semoper.S b/semoper.S new file mode 100644 index 0000000..561f1f2 --- /dev/null +++ b/semoper.S @@ -0,0 +1,31 @@ +.thumb +.syntax unified + +.text + +.globl sem_post32 +.type sem_post32, %function + +sem_post32: +1: + ldrex r2, [r0] + add r2, r2, r1 + strex r3, r2, [r0] + teq r3, #0 + bne 1b + mov r0, r2 + bx lr + + +.globl sem_wait32 +.type sem_wait32, %function + +sem_wait32: +1: + ldrex r2, [r0] + sub r2, r2, r1 + strex r3, r2, [r0] + teq r3, #0 + bne 1b + mov r0, r2 + bx lr diff --git a/semoper.h b/semoper.h new file mode 100644 index 0000000..23d2d10 --- /dev/null +++ b/semoper.h @@ -0,0 +1,13 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#ifndef SEMOPER_H_QWERTY +#define SEMOPER_H_QWERTY + +#include + +int32_t sem_post32(volatile int32_t *addr, int32_t value); +int32_t sem_wait32(volatile int32_t *addr, int32_t value); + +#endif From 099f4a5b7861acfa8ec445be179767b2750c6195 Mon Sep 17 00:00:00 2001 From: Oleg B Date: Tue, 30 Aug 2022 19:07:10 +0200 Subject: [PATCH 11/19] Update README.md --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 1dc29bb..c9ef718 100644 --- a/README.md +++ b/README.md @@ -43,3 +43,27 @@ NanoOS: "Make less makes no sense" =) */ ``` +#### Ouput + +``` +task 1 6932 +task 2 7157 +task 3 7390 +task 4 7627 2 +task 1 13844 +task 2 14301 +task 3 14762 +task 4 15235 3 +task 1 20760 +task 2 21449 +task 3 22138 +task 4 22843 4 +task 1 27676 +task 2 28597 +task 3 29514 +task 4 30451 5 +task 1 34592 +task 2 35745 +task 3 36890 +task 4 38059 6 +``` From ededa698590344a0a926033be97ee21ee61ee1d7 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Tue, 30 Aug 2022 19:42:30 +0200 Subject: [PATCH 12/19] fixed mistakes around semaphores --- main.c | 2 +- semaphore.c | 5 +++-- semoper.S | 12 ++++++------ semoper.h | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/main.c b/main.c index 55b5668..d50c57d 100644 --- a/main.c +++ b/main.c @@ -85,7 +85,7 @@ void task4(void) { static volatile int32_t t4; while (true) { - sem_post32(&t4, (int32_t)1); + atom_inc32(&t4, (int32_t)1); printf("task 4 %d %lu\r\n", g_uptime, t4); delay(3300); }; diff --git a/semaphore.c b/semaphore.c index a8e0032..df8ff1e 100644 --- a/semaphore.c +++ b/semaphore.c @@ -12,10 +12,11 @@ void sem_init(sem_t* sem, int32_t value) { int32_t sem_wait(sem_t* sem) { //while(sem->value > 0); //sem->value--; - return sem_wait32(&(sem->value), (int32_t)1); + while (atom_dec32(&(sem->value), (int32_t)0) > 0); + return atom_dec32(&(sem->value), (int32_t)1); } int32_t sem_post(sem_t* sem) { //sem->value++; - return sem_post32(&(sem->value), (int32_t)1); + return atom_inc32(&(sem->value), (int32_t)1); } diff --git a/semoper.S b/semoper.S index 561f1f2..52d185d 100644 --- a/semoper.S +++ b/semoper.S @@ -3,10 +3,10 @@ .text -.globl sem_post32 -.type sem_post32, %function +.globl atom_inc32 +.type atom_inc32, %function -sem_post32: +atom_inc32: 1: ldrex r2, [r0] add r2, r2, r1 @@ -17,10 +17,10 @@ sem_post32: bx lr -.globl sem_wait32 -.type sem_wait32, %function +.globl atom_dec32 +.type atom_dec32, %function -sem_wait32: +atom_dec32: 1: ldrex r2, [r0] sub r2, r2, r1 diff --git a/semoper.h b/semoper.h index 23d2d10..90563eb 100644 --- a/semoper.h +++ b/semoper.h @@ -7,7 +7,7 @@ #include -int32_t sem_post32(volatile int32_t *addr, int32_t value); -int32_t sem_wait32(volatile int32_t *addr, int32_t value); +int32_t atom_inc32(volatile int32_t *addr, int32_t value); +int32_t atom_dec32(volatile int32_t *addr, int32_t value); #endif From eadaa6fc8f4b57d914e3aee8b0c0c3188a85c7a8 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Wed, 31 Aug 2022 08:42:35 +0200 Subject: [PATCH 13/19] added semaphore to tasks for sample/testing --- Makefile | 2 +- main.c | 19 ++++++++++++++----- scheduler.c | 39 ++++++++++++++++++++++----------------- semaphore.c | 6 ++++-- semoper.S | 6 ++---- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 0ae82bd..05b64cc 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ .SECONDARY: -CFLAGS+= -I. -Os -DSTM32F4 -std=c99 +CFLAGS+= -I. -O1 -DSTM32F4 -std=c99 #CFLAGS+= -mthumb #CFLAGS+= -march=armv7e-m CFLAGS+= -mfloat-abi=hard diff --git a/main.c b/main.c index d50c57d..8b54559 100644 --- a/main.c +++ b/main.c @@ -19,6 +19,7 @@ #include "scheduler.h" #include "usartu.h" #include "semoper.h" +#include "semaphore.h" void delay(uint32_t n) { @@ -59,35 +60,43 @@ static void systick_setup(void) { } int g_uptime; +sem_t g_sem; void task1(void) { while (true) { + sem_wait(&g_sem); printf("task 1 %d\r\n", g_uptime); + sem_post(&g_sem); delay(3000); }; } void task2(void) { while (true) { + sem_wait(&g_sem); printf("task 2 %d\r\n", g_uptime); - delay(3100); + sem_post(&g_sem); + delay(3000); }; } void task3(void) { while (true) { + sem_wait(&g_sem); printf("task 3 %d\r\n", g_uptime); - delay(3200); + sem_post(&g_sem); + delay(3000); }; } void task4(void) { static volatile int32_t t4; - while (true) { atom_inc32(&t4, (int32_t)1); + sem_wait(&g_sem); printf("task 4 %d %lu\r\n", g_uptime, t4); - delay(3300); + sem_post(&g_sem); + delay(3000); }; } @@ -99,7 +108,7 @@ void sys_tick_handler(void) { int main(void) { g_uptime = 0; - + sem_init(&g_sem, 1); static scheduler_t g_scheduler; clock_setup(); diff --git a/scheduler.c b/scheduler.c index 8b4087b..c0aae0d 100644 --- a/scheduler.c +++ b/scheduler.c @@ -83,42 +83,47 @@ static void scheduler_switch(scheduler_t *scheduler) { void __attribute__((naked)) pend_sv_handler(void) { const uint32_t RETURN_ON_PSP = RETURN_ON_PSP_THREAD; - - __asm__("cpsid if":::"memory"); uint32_t lr; - __asm__("mov %0, lr\n":"=r"(lr)); + + __asm__( + "cpsid if \n" + "mov %0, lr \n" + :"=r"(lr) + ); if (lr & EXC_RETURN_MODE_THREAD) { uint32_t psp; __asm__( - "mrs %0, psp\n" - "stmdb %0!, {r4-r11}\n" - "msr psp, %0\n" : "=r"(psp) + "mrs %0, psp \n" + "stmdb %0!, {r4-r11} \n" + "msr psp, %0 \n" + : "=r"(psp) ); m_scheduler->tasks[m_scheduler->current_task].sp = psp; } else { __asm__( - "stmdb sp!, {r4-r11}\n"); + "stmdb sp!, {r4-r11} \n" + ); } scheduler_switch(m_scheduler); uint32_t psp = (uint32_t)m_scheduler->tasks[m_scheduler->current_task].sp; - __asm__( - "ldmfd %0!, {r4-r11}\n" - "msr psp, %0\n"::"r"(psp) + __asm__ ( + "ldmfd %0!, {r4-r11} \n" + "msr psp, %0 \n" + "cpsie if \n" + "bx %1 \n" + :: "r"(psp), "r"(RETURN_ON_PSP) ); - - __asm__("cpsie if" ::: "memory"); - __asm__("bx %0\n"::"r"(RETURN_ON_PSP)); } void scheduler_yield(void) { SCB_ICSR |= SCB_ICSR_PENDSVSET; __asm__( - "nop\n" - "nop\n" - "nop\n" - "nop\n" + "nop \n" + "nop \n" + "nop \n" + "nop \n" ); } diff --git a/semaphore.c b/semaphore.c index df8ff1e..f83d9bf 100644 --- a/semaphore.c +++ b/semaphore.c @@ -10,13 +10,15 @@ void sem_init(sem_t* sem, int32_t value) { } int32_t sem_wait(sem_t* sem) { - //while(sem->value > 0); + //while(sem->value <= 0); //sem->value--; - while (atom_dec32(&(sem->value), (int32_t)0) > 0); + //return sem->value; + while (atom_dec32(&(sem->value), (int32_t)0) <= 0); return atom_dec32(&(sem->value), (int32_t)1); } int32_t sem_post(sem_t* sem) { //sem->value++; + //return sem->value; return atom_inc32(&(sem->value), (int32_t)1); } diff --git a/semoper.S b/semoper.S index 52d185d..cfe6668 100644 --- a/semoper.S +++ b/semoper.S @@ -7,8 +7,7 @@ .type atom_inc32, %function atom_inc32: -1: - ldrex r2, [r0] +1: ldrex r2, [r0] add r2, r2, r1 strex r3, r2, [r0] teq r3, #0 @@ -21,8 +20,7 @@ atom_inc32: .type atom_dec32, %function atom_dec32: -1: - ldrex r2, [r0] +1: ldrex r2, [r0] sub r2, r2, r1 strex r3, r2, [r0] teq r3, #0 From f9856341c1f4f40f7612b250cf102b90c8bb59e1 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Wed, 31 Aug 2022 08:50:20 +0200 Subject: [PATCH 14/19] semoper.* renamed to atomic.* --- Makefile | 2 +- README.md | 36 ++++++++++++++++-------------------- semoper.S => atomic.S | 4 ++-- semoper.h => atomic.h | 0 main.c | 2 +- semaphore.c | 2 +- 6 files changed, 21 insertions(+), 25 deletions(-) rename semoper.S => atomic.S (89%) rename semoper.h => atomic.h (100%) diff --git a/Makefile b/Makefile index 05b64cc..45e656c 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ OBJS+= main.o OBJS+= syscall.o OBJS+= usartu.o OBJS+= scheduler.o -OBJS+= semoper.o +OBJS+= atomic.o OBJS+= semaphore.o main.elf: $(OBJS) diff --git a/README.md b/README.md index c9ef718..38c1082 100644 --- a/README.md +++ b/README.md @@ -46,24 +46,20 @@ NanoOS: "Make less makes no sense" =) #### Ouput ``` -task 1 6932 -task 2 7157 -task 3 7390 -task 4 7627 2 -task 1 13844 -task 2 14301 -task 3 14762 -task 4 15235 3 -task 1 20760 -task 2 21449 -task 3 22138 -task 4 22843 4 -task 1 27676 -task 2 28597 -task 3 29514 -task 4 30451 5 -task 1 34592 -task 2 35745 -task 3 36890 -task 4 38059 6 +task 2 1 +task 3 14 +task 4 27 1 +task 1 44 +task 2 6341 +task 3 6362 +task 4 6379 2 +task 1 6400 +task 2 12689 +task 3 12710 +task 4 12727 3 +task 1 12752 +task 2 19037 +task 3 19058 +task 4 19079 4 +task 1 19104 ``` diff --git a/semoper.S b/atomic.S similarity index 89% rename from semoper.S rename to atomic.S index cfe6668..4f72bd6 100644 --- a/semoper.S +++ b/atomic.S @@ -20,10 +20,10 @@ atom_inc32: .type atom_dec32, %function atom_dec32: -1: ldrex r2, [r0] +2: ldrex r2, [r0] sub r2, r2, r1 strex r3, r2, [r0] teq r3, #0 - bne 1b + bne 2b mov r0, r2 bx lr diff --git a/semoper.h b/atomic.h similarity index 100% rename from semoper.h rename to atomic.h diff --git a/main.c b/main.c index 8b54559..3fcffdc 100644 --- a/main.c +++ b/main.c @@ -18,7 +18,7 @@ #include "scheduler.h" #include "usartu.h" -#include "semoper.h" +#include "atomic.h" #include "semaphore.h" diff --git a/semaphore.c b/semaphore.c index f83d9bf..c8edee4 100644 --- a/semaphore.c +++ b/semaphore.c @@ -3,7 +3,7 @@ */ #include "semaphore.h" -#include "semoper.h" +#include "atomic.h" void sem_init(sem_t* sem, int32_t value) { sem->value = value; From 330efbdbb2230ed8fafe602e6180fc3db3dc8ff6 Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Wed, 31 Aug 2022 08:57:57 +0200 Subject: [PATCH 15/19] atom_* renamed to atomic_*; add mutex.* --- Makefile | 2 ++ atomic.S | 12 ++++++------ atomic.h | 4 ++-- main.c | 2 +- mutex.c | 24 ++++++++++++++++++++++++ mutex.h | 14 ++++++++++++++ semaphore.c | 6 +++--- 7 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 mutex.c create mode 100644 mutex.h diff --git a/Makefile b/Makefile index 45e656c..03db139 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,8 @@ OBJS+= usartu.o OBJS+= scheduler.o OBJS+= atomic.o OBJS+= semaphore.o +OBJS+= mutex.o + main.elf: $(OBJS) $(TARGET)-gcc $(^F) $(LDFLAGS) -o $@ diff --git a/atomic.S b/atomic.S index 4f72bd6..cc67731 100644 --- a/atomic.S +++ b/atomic.S @@ -3,10 +3,10 @@ .text -.globl atom_inc32 -.type atom_inc32, %function +.globl atomic_inc32 +.type atomic_inc32, %function -atom_inc32: +atomic_inc32: 1: ldrex r2, [r0] add r2, r2, r1 strex r3, r2, [r0] @@ -16,10 +16,10 @@ atom_inc32: bx lr -.globl atom_dec32 -.type atom_dec32, %function +.globl atomic_dec32 +.type atomic_dec32, %function -atom_dec32: +atomic_dec32: 2: ldrex r2, [r0] sub r2, r2, r1 strex r3, r2, [r0] diff --git a/atomic.h b/atomic.h index 90563eb..2cd54c3 100644 --- a/atomic.h +++ b/atomic.h @@ -7,7 +7,7 @@ #include -int32_t atom_inc32(volatile int32_t *addr, int32_t value); -int32_t atom_dec32(volatile int32_t *addr, int32_t value); +int32_t atomic_inc32(volatile int32_t *addr, int32_t value); +int32_t atomic_dec32(volatile int32_t *addr, int32_t value); #endif diff --git a/main.c b/main.c index 3fcffdc..0f7a993 100644 --- a/main.c +++ b/main.c @@ -92,7 +92,7 @@ void task3(void) { void task4(void) { static volatile int32_t t4; while (true) { - atom_inc32(&t4, (int32_t)1); + atomic_inc32(&t4, (int32_t)1); sem_wait(&g_sem); printf("task 4 %d %lu\r\n", g_uptime, t4); sem_post(&g_sem); diff --git a/mutex.c b/mutex.c new file mode 100644 index 0000000..6a87ea3 --- /dev/null +++ b/mutex.c @@ -0,0 +1,24 @@ +/* + * Copyright 2022 Oleg Borodin + */ + +#include "mutex.h" +#include "atomic.h" + +void mutex_init(mutex_t* mutex) { + mutex->value = 1; +} + +int32_t mutex_wait(mutex_t* mutex) { + //while(mutex->value <= 0); + //mutex->value--; + //return mutex->value; + while (atomic_dec32(&(mutex->value), (int32_t)0) <= 0); + return atomic_dec32(&(mutex->value), (int32_t)1); +} + +int32_t mutex_post(mutex_t* mutex) { + //mutex->value++; + //return mutex->value; + return atomic_inc32(&(mutex->value), (int32_t)1); +} diff --git a/mutex.h b/mutex.h new file mode 100644 index 0000000..6c3e03d --- /dev/null +++ b/mutex.h @@ -0,0 +1,14 @@ +/* + * Copyright 2022 Oleg Borodin + */ + + +#include + +typedef struct { + int32_t value; +} mutex_t; + +void mutex_init(mutex_t* mutex); +int32_t mutex_wait(mutex_t* mutex); +int32_t mutex_post(mutex_t* mutex); diff --git a/semaphore.c b/semaphore.c index c8edee4..5cd116b 100644 --- a/semaphore.c +++ b/semaphore.c @@ -13,12 +13,12 @@ int32_t sem_wait(sem_t* sem) { //while(sem->value <= 0); //sem->value--; //return sem->value; - while (atom_dec32(&(sem->value), (int32_t)0) <= 0); - return atom_dec32(&(sem->value), (int32_t)1); + while (atomic_dec32(&(sem->value), (int32_t)0) <= 0); + return atomic_dec32(&(sem->value), (int32_t)1); } int32_t sem_post(sem_t* sem) { //sem->value++; //return sem->value; - return atom_inc32(&(sem->value), (int32_t)1); + return atomic_inc32(&(sem->value), (int32_t)1); } From 5424edfe5e2952479cda920faf09ffade8d96a8c Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Wed, 31 Aug 2022 09:02:04 +0200 Subject: [PATCH 16/19] rename mutex oper to conv lock/unlock --- mutex.c | 4 ++-- mutex.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mutex.c b/mutex.c index 6a87ea3..05a84a5 100644 --- a/mutex.c +++ b/mutex.c @@ -9,7 +9,7 @@ void mutex_init(mutex_t* mutex) { mutex->value = 1; } -int32_t mutex_wait(mutex_t* mutex) { +int32_t mutex_lock(mutex_t* mutex) { //while(mutex->value <= 0); //mutex->value--; //return mutex->value; @@ -17,7 +17,7 @@ int32_t mutex_wait(mutex_t* mutex) { return atomic_dec32(&(mutex->value), (int32_t)1); } -int32_t mutex_post(mutex_t* mutex) { +int32_t mutex_unlock(mutex_t* mutex) { //mutex->value++; //return mutex->value; return atomic_inc32(&(mutex->value), (int32_t)1); diff --git a/mutex.h b/mutex.h index 6c3e03d..80c612e 100644 --- a/mutex.h +++ b/mutex.h @@ -10,5 +10,5 @@ typedef struct { } mutex_t; void mutex_init(mutex_t* mutex); -int32_t mutex_wait(mutex_t* mutex); -int32_t mutex_post(mutex_t* mutex); +int32_t mutex_lock(mutex_t* mutex); +int32_t mutex_unlock(mutex_t* mutex); From d071c0957b0e606b68ce159987dc6a6008c1935d Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Wed, 31 Aug 2022 10:10:35 +0200 Subject: [PATCH 17/19] added atomic_dec32le0 for sem/mutex lock --- atomic.S | 18 ++++++++++++++++-- atomic.h | 2 ++ mutex.c | 3 +-- scheduler.c | 2 +- semaphore.c | 4 ++-- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/atomic.S b/atomic.S index cc67731..782a3e8 100644 --- a/atomic.S +++ b/atomic.S @@ -20,10 +20,24 @@ atomic_inc32: .type atomic_dec32, %function atomic_dec32: -2: ldrex r2, [r0] +1: ldrex r2, [r0] sub r2, r2, r1 strex r3, r2, [r0] teq r3, #0 - bne 2b + bne 1b + mov r0, r2 + bx lr + +.globl atomic_dec32le0 +.type atomic_dec32le0, %function + +atomic_dec32le0: +1: ldrex r2, [r0] + cmp r2, #0 + ble 1b + sub r2, r2, r1 + strex r3, r2, [r0] + teq r3, #0 + bne 1b mov r0, r2 bx lr diff --git a/atomic.h b/atomic.h index 2cd54c3..66258d2 100644 --- a/atomic.h +++ b/atomic.h @@ -10,4 +10,6 @@ int32_t atomic_inc32(volatile int32_t *addr, int32_t value); int32_t atomic_dec32(volatile int32_t *addr, int32_t value); + +int32_t atomic_dec32le0(volatile int32_t *addr, int32_t value); #endif diff --git a/mutex.c b/mutex.c index 05a84a5..e9c4a06 100644 --- a/mutex.c +++ b/mutex.c @@ -13,8 +13,7 @@ int32_t mutex_lock(mutex_t* mutex) { //while(mutex->value <= 0); //mutex->value--; //return mutex->value; - while (atomic_dec32(&(mutex->value), (int32_t)0) <= 0); - return atomic_dec32(&(mutex->value), (int32_t)1); + return atomic_dec32le0(&(mutex->value), (int32_t)1); } int32_t mutex_unlock(mutex_t* mutex) { diff --git a/scheduler.c b/scheduler.c index c0aae0d..8c426dc 100644 --- a/scheduler.c +++ b/scheduler.c @@ -73,7 +73,7 @@ void scheduler_task(scheduler_t *scheduler, int task_no, void (*entry)(void)) { static void scheduler_switch(scheduler_t *scheduler) { do { - scheduler->current_task = (scheduler->current_task + 1) % SCHEDULER_NUM_TASKS; + scheduler->current_task = (scheduler->current_task) % SCHEDULER_NUM_TASKS; } while (!scheduler->tasks[scheduler->current_task].runnable); } diff --git a/semaphore.c b/semaphore.c index 5cd116b..ba22e6a 100644 --- a/semaphore.c +++ b/semaphore.c @@ -13,8 +13,8 @@ int32_t sem_wait(sem_t* sem) { //while(sem->value <= 0); //sem->value--; //return sem->value; - while (atomic_dec32(&(sem->value), (int32_t)0) <= 0); - return atomic_dec32(&(sem->value), (int32_t)1); + //while (atomic_dec32(&(sem->value), (int32_t)0) <= 0); + return atomic_dec32le0(&(sem->value), (int32_t)1); } int32_t sem_post(sem_t* sem) { From c93d68a9143d10802ebb960f37532cab57b9b29d Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Wed, 31 Aug 2022 10:40:55 +0200 Subject: [PATCH 18/19] nanofix of missed increment --- scheduler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scheduler.c b/scheduler.c index 8c426dc..c0aae0d 100644 --- a/scheduler.c +++ b/scheduler.c @@ -73,7 +73,7 @@ void scheduler_task(scheduler_t *scheduler, int task_no, void (*entry)(void)) { static void scheduler_switch(scheduler_t *scheduler) { do { - scheduler->current_task = (scheduler->current_task) % SCHEDULER_NUM_TASKS; + scheduler->current_task = (scheduler->current_task + 1) % SCHEDULER_NUM_TASKS; } while (!scheduler->tasks[scheduler->current_task].runnable); } From 73af1476a6750f702ac2838a60ad39ab24c6101b Mon Sep 17 00:00:00 2001 From: Oleg Borodin Date: Fri, 2 Sep 2022 09:51:36 +0200 Subject: [PATCH 19/19] moved g_* yo begin --- Makefile | 2 +- main.c | 14 +++++++------- scheduler.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 03db139..c2ca199 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ .SECONDARY: -CFLAGS+= -I. -O1 -DSTM32F4 -std=c99 +CFLAGS+= -I. -Os -DSTM32F4 -std=c99 #CFLAGS+= -mthumb #CFLAGS+= -march=armv7e-m CFLAGS+= -mfloat-abi=hard diff --git a/main.c b/main.c index 0f7a993..705bfca 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,4 @@ + /* * Copyright 2022 Oleg Borodin */ @@ -10,7 +11,6 @@ #include #include - #include #include #include @@ -21,9 +21,12 @@ #include "atomic.h" #include "semaphore.h" +static int g_uptime; +static sem_t g_sem; +static scheduler_t g_scheduler; void delay(uint32_t n) { - for (volatile int i = 0; i < n * 800; i++) + for (int i = 0; i < n * 800; i++) __asm__("nop"); } @@ -59,9 +62,6 @@ static void systick_setup(void) { systick_counter_enable(); } -int g_uptime; -sem_t g_sem; - void task1(void) { while (true) { sem_wait(&g_sem); @@ -91,6 +91,7 @@ void task3(void) { void task4(void) { static volatile int32_t t4; + while (true) { atomic_inc32(&t4, (int32_t)1); sem_wait(&g_sem); @@ -105,14 +106,13 @@ void sys_tick_handler(void) { scheduler_yield(); } - int main(void) { g_uptime = 0; sem_init(&g_sem, 1); - static scheduler_t g_scheduler; clock_setup(); usart_setup(); + scheduler_init(&g_scheduler); scheduler_task(&g_scheduler, 0, task1); scheduler_task(&g_scheduler, 1, task2); diff --git a/scheduler.c b/scheduler.c index c0aae0d..d54c6f1 100644 --- a/scheduler.c +++ b/scheduler.c @@ -41,8 +41,8 @@ static void task_exit_func(void) { #define STACK_FILL 0xA5 void scheduler_init(scheduler_t *scheduler) { - - for (int i = 0; i < SCHEDULER_NUM_TASKS; i++) { + int i; + for (i = 0; i < SCHEDULER_NUM_TASKS; i++) { task_t *task = &(scheduler->tasks[i]); task->stack = NULL; task->stack_size = 0;