diff --git a/Makefile b/Makefile
index 97343f6..02fbad2 100644
--- a/Makefile
+++ b/Makefile
@@ -25,37 +25,26 @@ AS = as
MCUFLAGS = -mthumb -mcpu=cortex-m4 #-mfloat-abi=hard -mfpu=fpv4-sp-d16
AFLAGS = $(MCUFLAGS)
CFLAGS = $(MCUFLAGS) -ggdb \
- -Iinclude -Iinclude/cmsis \
+ -I.. \
-fno-builtin -fsigned-char -ffreestanding \
-Wall -Werror -Wextra -pedantic \
-Wno-overlength-strings -Wno-discarded-qualifiers
LFLAGS = -T link.ld
-CFILES = $(wildcard src/*.c)
-AFILES = $(wildcard src/*.s)
+OUT = main.elf
-OUTDIR = out
-OFILES = $(patsubst src/%.c, $(OUTDIR)/%.o, $(CFILES)) \
- $(patsubst src/%.s, $(OUTDIR)/%.asm.o, $(AFILES))
+export
-OUT = out/main.elf
-
-all: $(OUT)
-
-$(OUT): $(OFILES)
+all:
+ @$(MAKE) -C src/kernel
+ @$(MAKE) -C src/user
@echo " LINK " $(OUT)
- @$(CROSS)$(CC) $(CFLAGS) $(LFLAGS) out/*.o -o $(OUT)
+ @$(CROSS)$(CC) $(CFLAGS) $(LFLAGS) -o $(OUT) $$(find src/ -name "*.o")
-$(OUTDIR)/%.o: src/%.c
- @echo " CC " $<
- @$(CROSS)$(CC) $(CFLAGS) -c $< -o $@
-
-$(OUTDIR)/%.asm.o: src/%.s
- @echo " AS " $<
- @$(CROSS)$(AS) $(AFLAGS) -c $< -o $@
clean:
@echo " CLEAN"
- @rm -rf out/*
-
+ @$(MAKE) -C src/kernel clean
+ @$(MAKE) -C src/user clean
+ @rm -f $(OUT)
diff --git a/include/priv_gpio.h b/include/priv_gpio.h
deleted file mode 100644
index a97e294..0000000
--- a/include/priv_gpio.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef PRIV_GPIO_H_
-#define PRIV_GPIO_H_
-
-#define GPIO_MODE 0
-#define GPIO_TYPE 1
-#define GPIO_PUPD 2
-#define GPIO_SPEED 3
-#define GPIO_OUT 4
-
-void gpio(uint32_t call, uint32_t pin, uint32_t value)
-{
- register uint32_t r0 asm("r0") = call;
- register uint32_t r1 asm("r1") = pin;
- register uint32_t r2 asm("r2") = value;
-
- asm("\
- mov r0, %0; \
- mov r1, %1; \
- mov r2, %2; \
- svc 1; \
- " :: "r" (r0), "r" (r1), "r" (r2));
-}
-
-#endif // PRIV_GPIO_H_
diff --git a/include/cmsis/cmsis_gcc.h b/src/arch/cmsis/cmsis_gcc.h
similarity index 100%
rename from include/cmsis/cmsis_gcc.h
rename to src/arch/cmsis/cmsis_gcc.h
diff --git a/include/cmsis/core_cm4.h b/src/arch/cmsis/core_cm4.h
similarity index 100%
rename from include/cmsis/core_cm4.h
rename to src/arch/cmsis/core_cm4.h
diff --git a/include/cmsis/core_cmFunc.h b/src/arch/cmsis/core_cmFunc.h
similarity index 100%
rename from include/cmsis/core_cmFunc.h
rename to src/arch/cmsis/core_cmFunc.h
diff --git a/include/cmsis/core_cmInstr.h b/src/arch/cmsis/core_cmInstr.h
similarity index 100%
rename from include/cmsis/core_cmInstr.h
rename to src/arch/cmsis/core_cmInstr.h
diff --git a/include/cmsis/core_cmSimd.h b/src/arch/cmsis/core_cmSimd.h
similarity index 100%
rename from include/cmsis/core_cmSimd.h
rename to src/arch/cmsis/core_cmSimd.h
diff --git a/include/stm32l476xx.h b/src/arch/stm/stm32l476xx.h
similarity index 100%
rename from include/stm32l476xx.h
rename to src/arch/stm/stm32l476xx.h
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
new file mode 100644
index 0000000..d22fbf3
--- /dev/null
+++ b/src/kernel/Makefile
@@ -0,0 +1,22 @@
+CFILES = $(wildcard *.c)
+AFILES = $(wildcard *.s)
+OFILES = $(patsubst %.c, %.o, $(CFILES)) \
+ $(patsubst %.s, %.asm.o, $(AFILES))
+
+CFLAGS += -I.. -I../arch/cmsis
+
+all: $(OFILES)
+
+%.o: %.c
+ @echo " CC " $<
+ @$(CROSS)$(CC) $(CFLAGS) -c $< -o $@
+
+%.asm.o: %.s
+ @echo " AS " $<
+ @$(CROSS)$(AS) $(AFLAGS) -c $< -o $@
+
+clean:
+ @echo " CLEAN"
+ @rm -f $(OFILES)
+
+
diff --git a/src/clock.c b/src/kernel/clock.c
similarity index 76%
rename from src/clock.c
rename to src/kernel/clock.c
index c94695b..44b7722 100644
--- a/src/clock.c
+++ b/src/kernel/clock.c
@@ -18,12 +18,19 @@
* along with this program. If not, see .
*/
-#include
-#include
+#include "clock.h"
+#include
// ticks since init
volatile uint32_t ticks = 0;
+volatile uint8_t tim2_finished = 1;
+
+void clock_svc(uint32_t *args)
+{
+ udelay(args[0]);
+}
+
void clock_init(void)
{
// turn on HSI (16MHz)
@@ -53,6 +60,15 @@ void clock_init(void)
// SysTick init. 80MHz / 80000 = 1kHz, ms precision
SysTick->LOAD = 80000;
SysTick->CTRL |= 0x07; // no div, interrupt, enable
+
+ // Prepare TIM2 for microsecond timing
+ NVIC_EnableIRQ(TIM2_IRQn);
+
+ RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;
+ TIM2->DIER |= TIM_DIER_UIE;
+ TIM2->PSC = 40 - 1;
+ TIM2->ARR = 100;
+ TIM2->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
}
void delay(uint32_t count)
@@ -61,12 +77,27 @@ void delay(uint32_t count)
while (ticks < target);
}
+void udelay(uint32_t count)
+{
+ tim2_finished = 0;
+ TIM2->ARR = count;
+ TIM2->CR1 |= TIM_CR1_CEN;
+ while (tim2_finished == 0);
+}
+
void SysTick_Handler(void)
{
// just keep counting
ticks++;
+ // task switch every four ticks (4ms)
if (!(ticks & 3))
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
+void TIM2_IRQHandler(void)
+{
+ TIM2->SR &= ~(TIM_SR_UIF);
+ tim2_finished |= 1;
+}
+
diff --git a/include/clock.h b/src/kernel/clock.h
similarity index 82%
rename from include/clock.h
rename to src/kernel/clock.h
index 7446dd1..c3554f6 100644
--- a/include/clock.h
+++ b/src/kernel/clock.h
@@ -1,6 +1,6 @@
/**
* @file clock.h
- * Basic clock utilities
+ * Clock utilities
*
* Copyright (C) 2018 Clyne Sullivan
*
@@ -30,8 +30,14 @@ extern void clock_init(void);
/**
* Sleeps for given amount of milliseconds.
- * @param ms number of milliseconds to sleep for
+ * @param ms Number of milliseconds to sleep for
*/
void delay(uint32_t ms);
+/**
+ * Sleeps for the given amount of microseconds.
+ * @param count Number of microseconds to sleep for
+ */
+void udelay(uint32_t count);
+
#endif // CLOCK_H_
diff --git a/src/fault.c b/src/kernel/fault.c
similarity index 100%
rename from src/fault.c
rename to src/kernel/fault.c
diff --git a/src/gpio.c b/src/kernel/gpio.c
similarity index 99%
rename from src/gpio.c
rename to src/kernel/gpio.c
index 27bfdd3..1c81d11 100644
--- a/src/gpio.c
+++ b/src/kernel/gpio.c
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-#include
+#include "gpio.h"
static const GPIO_TypeDef *gpio_ports[8] = {
GPIOA, GPIOB, GPIOC, GPIOD,
diff --git a/include/gpio.h b/src/kernel/gpio.h
similarity index 76%
rename from include/gpio.h
rename to src/kernel/gpio.h
index 08feb86..ea7e837 100644
--- a/include/gpio.h
+++ b/src/kernel/gpio.h
@@ -1,6 +1,6 @@
/**
* @file gpio.h
- * Abstracts gpio access, makes things easier
+ * GPIO Abstraction and access
*
* Copyright (C) 2018 Clyne Sullivan
*
@@ -21,17 +21,17 @@
#ifndef GPIO_H_
#define GPIO_H_
-#include
+#include
/**
* Helps simplify gpio calls.
- * @param p port, e.g. GPIOA
- * @param b pin, e.g. 4
+ * @param p Port, e.g. A
+ * @param b Pin, e.g. 4
*/
#define GPIO_PORT(p, b) GPIO##p, b
/**
- * Defines possible modes for a gpio pin
+ * Defines possible modes for a gpio pin.
*/
enum GPIO_MODE
{
@@ -72,59 +72,59 @@ enum GPIO_PUPD
};
/**
- * Initializes the gpio.
+ * Prepares for GPIO usage.
*/
void gpio_init(void);
/**
* Enables or disables pullup/pulldown for the given pin.
- * @param port the port, e.g. GPIOA
- * @param pin the pin
- * @param pupd pullup/pulldown enable
+ * @param port The port, e.g. GPIOA
+ * @param pin The pin
+ * @param pupd Pullup/pulldown enable
* @see GPIO_PUPD
*/
void gpio_pupd(GPIO_TypeDef *port, uint32_t pin, uint32_t pupd);
/**
* Sets whether to use push-pull or open drain for the given pin.
- * @param port the port
- * @param pin the pin
- * @param type what to use
+ * @param port The port
+ * @param pin The pin
+ * @param type What type to use
* @see GPIO_TYPE
*/
void gpio_type(GPIO_TypeDef *port, uint32_t pin, uint32_t type);
/**
* Sets the pin's speed.
- * @param port the port
- * @param pin the pin
- * @param speed the speed to use
+ * @param port The port
+ * @param pin The pin
+ * @param speed The speed to use
* @see GPIO_SPEED
*/
void gpio_speed(GPIO_TypeDef *port, uint32_t pin, uint32_t speed);
/**
* Sets the pin's i/o mode.
- * @param port the port
- * @param pin the pin
- * @param mode the mode to use
+ * @param port The port
+ * @param pin The pin
+ * @param mode The mode to use
* @see GPIO_MODE
*/
void gpio_mode(GPIO_TypeDef *port, uint32_t pin, uint32_t mode);
/**
* Sets the state of a digital output pin.
- * @param port the port
- * @param pin the pin
- * @param val non-zero for high, zero for low
+ * @param port The port
+ * @param pin The pin
+ * @param val Non-zero for high, zero for low
*/
void gpio_dout(GPIO_TypeDef *port, uint32_t pin, uint32_t val);
/**
* Reads a digital input pin.
- * @param port the port
- * @param pin the pin
- * @return non-zero for high, zero for low
+ * @param port The port
+ * @param pin The pin
+ * @return Non-zero for high, zero for low
*/
uint32_t gpio_din(GPIO_TypeDef *port, uint32_t pin);
diff --git a/src/heap.c b/src/kernel/heap.c
similarity index 96%
rename from src/heap.c
rename to src/kernel/heap.c
index 354087f..ff5dd9e 100644
--- a/src/heap.c
+++ b/src/kernel/heap.c
@@ -18,10 +18,15 @@
* along with this program. If not, see .
*/
-#include
+#include "heap.h"
#define HEAP_ALIGN 4
+typedef struct {
+ uint32_t size;
+ void *next;
+} __attribute__ ((packed)) alloc_t;
+
static alloc_t *free_blocks;
static void *heap_end;
diff --git a/include/heap.h b/src/kernel/heap.h
similarity index 70%
rename from include/heap.h
rename to src/kernel/heap.h
index acbf81c..c817e4d 100644
--- a/include/heap.h
+++ b/src/kernel/heap.h
@@ -23,43 +23,38 @@
#include
-typedef struct {
- uint32_t size;
- void *next;
-} __attribute__ ((packed)) alloc_t;
-
/**
* Initializes memory management of the given heap.
- * No overflow stuff is done, so...
- * @param buf the heap to use for allocations
+ * No overflow stuff is done, so... be careful.
+ * @param buf The heap to use for allocations
*/
void heap_init(void *buf);
/**
- * Returns the amount of free memory, in bytes.
- * @return amount of free memory in bytes
+ * Returns the amount of free, allocatable memory, in bytes.
+ * @return Amount of free memory in bytes
*/
uint32_t heap_free(void);
/**
* Allocates a chunk of memory.
- * @param size how many bytes to claim
- * @return pointer to the allocated buffer
+ * @param size How many bytes to claim
+ * @return Pointer to the allocated buffer
*/
void *malloc(uint32_t size);
/**
* Allocates and zeros a chunk of memory.
- * @param count how many of whatever to allocate
- * @param size byte count of each whatever
- * @return pointer to the allocated buffer
+ * @param count How many of whatever to allocate
+ * @param size Byte count of each whatever
+ * @return Pointer to the allocated buffer
*/
void *calloc(uint32_t count, uint32_t size);
/**
* Frees the buffer allocated through malloc/calloc.
* Please don't double-free.
- * @param the buffer to release
+ * @param The buffer to release
*/
void free(void *buf);
diff --git a/src/main.c b/src/kernel/init.c
similarity index 62%
rename from src/main.c
rename to src/kernel/init.c
index bbcd09b..e4ac115 100644
--- a/src/main.c
+++ b/src/kernel/init.c
@@ -1,6 +1,6 @@
/**
- * @file main.c
- * Entry point for operating system
+ * @file init.c
+ * Kernel initialization procedure
*
* Copyright (C) 2018 Clyne Sullivan
*
@@ -18,16 +18,15 @@
* along with this program. If not, see .
*/
-#include
-#include
-#include
-#include
-#include
-#include
+#include "clock.h"
+#include "gpio.h"
+#include "heap.h"
+#include "task.h"
+#include
extern uint8_t __bss_end__;
-void kmain(void);
+extern void user_main(void);
int main(void)
{
@@ -47,35 +46,7 @@ int main(void)
// enable FPU
//SCB->CPACR |= (0xF << 20);
- task_init(kmain);
+ task_init(user_main);
while (1);
}
-void task2(void);
-void kmain(void)
-{
- gpio(GPIO_MODE, 5, OUTPUT);
- task_start(task2, 512);
-
- for (int i = 0; i < 8; i++) {
- gpio(GPIO_OUT, 5, !(i & 1));
- delay(200);
- }
-}
-
-void task3(void);
-void task2(void)
-{
- delay(400);
- task_start(task3, 1024);
-}
-
-void task3(void)
-{
- int state = 0;
- delay(2500);
- while (1) {
- gpio(GPIO_OUT, 5, state ^= 1);
- delay(500);
- }
-}
diff --git a/src/startup_stm32l476xx.s b/src/kernel/startup_stm32l476xx.s
similarity index 100%
rename from src/startup_stm32l476xx.s
rename to src/kernel/startup_stm32l476xx.s
diff --git a/src/svc.c b/src/kernel/svc.c
similarity index 91%
rename from src/svc.c
rename to src/kernel/svc.c
index f132571..62324f7 100644
--- a/src/svc.c
+++ b/src/kernel/svc.c
@@ -20,11 +20,12 @@
*/
#include
-#include
-#include
-#include
+#include "gpio.h"
+#include "clock.h"
+#include "task.h"
extern void gpio_svc(uint32_t *);
+extern void clock_svc(uint32_t *);
void svc_handler(uint32_t *args)
{
@@ -38,6 +39,8 @@ void svc_handler(uint32_t *args)
case 1:
gpio_svc(args);
break;
+ case 2:
+ clock_svc(args);
default:
break;
}
diff --git a/src/task.c b/src/kernel/task.c
similarity index 97%
rename from src/task.c
rename to src/kernel/task.c
index 4da2be1..1a1c16b 100644
--- a/src/task.c
+++ b/src/kernel/task.c
@@ -18,9 +18,9 @@
* along with this program. If not, see .
*/
-#include
-#include
-#include
+#include "task.h"
+#include "heap.h"
+#include
task_t *current, *prev;
static uint8_t task_disable = 0;
@@ -167,6 +167,7 @@ void PendSV_Handler(void)
asm("bx lr");
// TODO why, and what does this do
+ // TODO get back to c, implement task sleeping
asm("\
mrs r0, psp; \
isb; \
diff --git a/include/task.h b/src/kernel/task.h
similarity index 93%
rename from include/task.h
rename to src/kernel/task.h
index 916a87c..3d331ae 100644
--- a/include/task.h
+++ b/src/kernel/task.h
@@ -54,8 +54,10 @@ void task_start(void (*task)(void), uint16_t stackSize);
*/
void task_hold(uint8_t hold);
+/**
+ * Frees the task's resources and removes it from the running task list.
+ * @param code An unused exit code
+ */
void _exit(int code);
-//int fork(void);
-
#endif // TASK_H_
diff --git a/src/user/Makefile b/src/user/Makefile
new file mode 100644
index 0000000..d22fbf3
--- /dev/null
+++ b/src/user/Makefile
@@ -0,0 +1,22 @@
+CFILES = $(wildcard *.c)
+AFILES = $(wildcard *.s)
+OFILES = $(patsubst %.c, %.o, $(CFILES)) \
+ $(patsubst %.s, %.asm.o, $(AFILES))
+
+CFLAGS += -I.. -I../arch/cmsis
+
+all: $(OFILES)
+
+%.o: %.c
+ @echo " CC " $<
+ @$(CROSS)$(CC) $(CFLAGS) -c $< -o $@
+
+%.asm.o: %.s
+ @echo " AS " $<
+ @$(CROSS)$(AS) $(AFLAGS) -c $< -o $@
+
+clean:
+ @echo " CLEAN"
+ @rm -f $(OFILES)
+
+
diff --git a/src/user/priv_gpio.h b/src/user/priv_gpio.h
new file mode 100644
index 0000000..6b349fe
--- /dev/null
+++ b/src/user/priv_gpio.h
@@ -0,0 +1,58 @@
+/**
+ * @file priv_gpio.h
+ * GPIO access for unpriviledged processes
+ *
+ * Copyright (C) 2018 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef PRIV_GPIO_H_
+#define PRIV_GPIO_H_
+
+// For value flags
+#include
+
+/**
+ * Possible GPIO calls.
+ */
+enum GPIO_CALLS {
+ GPIO_MODE = 0, /**< Change GPIO mode */
+ GPIO_TYPE, /**< Change GPIO type (PuPd/ODrain) */
+ GPIO_PUPD, /**< Set/clear pullup/pulldown */
+ GPIO_SPEED, /**< Set GPIO speed */
+ GPIO_OUT, /**< Set GPIO output state */
+};
+
+/**
+ * Provides unpriviledged GPIO access.
+ * @param call The type of GPIO call to make
+ * @param pin The pin to modify (0-15 = A, 16-31 = B, ...)
+ * @param value The value to pass to the call
+ */
+void gpio(uint32_t call, uint32_t pin, uint32_t value)
+{
+ register uint32_t r0 asm("r0") = call;
+ register uint32_t r1 asm("r1") = pin;
+ register uint32_t r2 asm("r2") = value;
+
+ asm("\
+ mov r0, %0; \
+ mov r1, %1; \
+ mov r2, %2; \
+ svc 1; \
+ " :: "r" (r0), "r" (r1), "r" (r2));
+}
+
+#endif // PRIV_GPIO_H_
diff --git a/src/user/user.c b/src/user/user.c
new file mode 100644
index 0000000..fc51d29
--- /dev/null
+++ b/src/user/user.c
@@ -0,0 +1,35 @@
+#include
+#include "priv_gpio.h"
+#include
+
+void task1(void);
+void task2(void);
+
+
+
+void user_main(void)
+{
+ gpio(GPIO_MODE, 5, OUTPUT);
+ task_start(task1, 512);
+
+ for (int i = 0; i < 8; i++) {
+ gpio(GPIO_OUT, 5, !(i & 1));
+ delay(200);
+ }
+}
+
+void task1(void)
+{
+ delay(400);
+ task_start(task2, 1024);
+}
+
+void task2(void)
+{
+ int state = 0;
+ delay(2500);
+ while (1) {
+ gpio(GPIO_OUT, 5, state ^= 1);
+ delay(500);
+ }
+}