]> code.bitgloo.com Git - clyne/calculator.git/commitdiff
heap; multitasking
authorClyne Sullivan <tullivan99@gmail.com>
Mon, 1 Jan 2018 22:40:28 +0000 (17:40 -0500)
committerClyne Sullivan <tullivan99@gmail.com>
Mon, 1 Jan 2018 22:40:28 +0000 (17:40 -0500)
Makefile
clock.c
heap.c [new file with mode: 0644]
include/heap.h [new file with mode: 0644]
include/task.h [new file with mode: 0644]
link.ld
main.c
startup_stm32l476xx.s
stm32l4xx_it.c
task.c [new file with mode: 0644]

index 4a7a22cf6d1dc7acd5f4abd567ac5d7325435da2..48175ff0fb1c518fd086d852aee74670289d1484 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,8 @@ all:
        arm-none-eabi-gcc $(CFLAGS) system_stm32l4xx.c -c -o out/system_stm32l4xx.o
        arm-none-eabi-gcc $(CFLAGS) stm32l4xx_it.c -c -o out/stm32l4xx_it.o
        arm-none-eabi-gcc $(CFLAGS) clock.c -c -o out/clock.o
+       arm-none-eabi-gcc $(CFLAGS) heap.c -c -o out/heap.o
+       arm-none-eabi-gcc $(CFLAGS) task.c -c -o out/task.o
        arm-none-eabi-gcc $(CFLAGS) main.c -c -o out/main.o
        arm-none-eabi-gcc $(CFLAGS) -T link.ld out/*.o -o out/main.elf
        arm-none-eabi-objcopy -O ihex out/main.elf main.hex
diff --git a/clock.c b/clock.c
index 8041cb22bb2e7aee2a073bd61fb6a73b98738b14..ab923867c77efd2d3be69d589db356ad402d50ff 100644 (file)
--- a/clock.c
+++ b/clock.c
@@ -45,15 +45,18 @@ void delay(uint32_t count)
        while (ticks < target);
 }
 
-void PendSV_Handler(void) {
-}
-
+__attribute__ ((naked))
 void SysTick_Handler(void)
 {
+       uint32_t lr;
+       asm("mov %0, lr" : "=r" (lr));
+
        // just keep counting
        ticks++;
 
-       if (!(ticks % 500))
-               SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; 
+       if (!(ticks % 10))
+               SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
+
+       asm("mov lr, %0; bx lr" :: "r" (lr));
 }
 
diff --git a/heap.c b/heap.c
new file mode 100644 (file)
index 0000000..0433a1f
--- /dev/null
+++ b/heap.c
@@ -0,0 +1,38 @@
+#include <heap.h>
+#include <stm32l476xx.h>
+
+#define RAM_END 0x20018000
+
+//extern void *end;
+//extern uint32_t _total_ram;
+static uint32_t offset = 0;
+
+__attribute__ ((section(".data")))
+uint8_t heap[8192];
+void *end = heap;
+
+void heap_init(void)
+{
+       // what to do...
+}
+
+uint32_t heap_available(void)
+{
+       return 0;//     return _total_ram - offset;
+}
+
+void *hmalloc(uint32_t size)
+{
+       void *alloc = end + offset;
+       offset += size;
+       return alloc;
+}
+
+void *hcalloc(uint32_t count, uint32_t size)
+{
+       uint32_t total = count * size;
+       void *alloc = hmalloc(total);
+       for (uint32_t i = 0; i < total; i++)
+               ((uint8_t *)alloc)[i] = 0;
+       return alloc;
+}
diff --git a/include/heap.h b/include/heap.h
new file mode 100644 (file)
index 0000000..e04b15e
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef HEAP_H_
+#define HEAP_H_
+
+#include <stdint.h>
+
+uint32_t heap_available(void);
+
+void *hmalloc(uint32_t size);
+void *hcalloc(uint32_t count, uint32_t size);
+
+#endif // HEAP_H_
diff --git a/include/task.h b/include/task.h
new file mode 100644 (file)
index 0000000..c57b2c0
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef TASK_H_
+#define TASK_H_
+
+#include <stdint.h>
+
+void task_init(void (*init)(void));
+
+void task_start(void (*task)(void), uint16_t stackSize);
+
+#endif // TASK_H_
diff --git a/link.ld b/link.ld
index e24ff34f853961290d616642a80594493c3ddd5b..8877898f6b5ab44f34e252c635f255340ee51300 100644 (file)
--- a/link.ld
+++ b/link.ld
@@ -34,15 +34,15 @@ ENTRY(Reset_Handler)
 \r
 /* Highest address of the user mode stack */\r
 _estack = 0x20018000;    /* end of RAM */\r
-/* Generate a link error if heap and stack don't fit into RAM */\r
-_Min_Heap_Size = 0x200;;      /* required amount of heap  */\r
-_Min_Stack_Size = 0x400;; /* required amount of stack */\r
+\r
+_Min_Stack_Size = 0x0400; /* 1k min. stack */\r
+_Min_Heap_Size = 0x0400; /* 1k min. heap */\r
 \r
 /* Specify the memory areas */\r
 MEMORY\r
 {\r
-FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K\r
-RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 96K\r
+       FLASH (rx)      : ORIGIN = 0x8000000,   LENGTH = 1024K\r
+       RAM   (xrw)     : ORIGIN = 0x20000000,  LENGTH = 96K\r
 }\r
 \r
 /* Define output sections */\r
@@ -166,4 +166,4 @@ SECTIONS
   .ARM.attributes 0 : { *(.ARM.attributes) }\r
 }\r
 \r
-\r
+_total_ram = _estack - _end;\r
diff --git a/main.c b/main.c
index e640a6bacb5e2fc78b95a005aa1c817e5b8cb063..9a95465e539af6fa5be22986dad23e1a059a0f0f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,21 +1,26 @@
 #include <stm32l476xx.h>\r
 #include <clock.h>\r
+#include <heap.h>\r
+#include <task.h>\r
 \r
 /**\r
  * Accomplishments:\r
  *   - GPIO in/out\r
  *   - got to 80MHz clock\r
+ *   - basic heap\r
+ *   - multitask, can exit\r
  */\r
 \r
 void pulse(uint8_t byte);\r
+void kmain(void);\r
 \r
 int main(void)\r
 {\r
+       asm("cpsid i");\r
+\r
        // prepare flash latency for 40MHz operation\r
        FLASH->ACR &= ~(FLASH_ACR_LATENCY);\r
-       FLASH->ACR |= FLASH_ACR_LATENCY_2WS;\r
-\r
-       clock_init();\r
+       FLASH->ACR |= FLASH_ACR_LATENCY_4WS;\r
 \r
        RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;    // A clk enable\r
        GPIOA->MODER &= ~(GPIO_MODER_MODE5 | GPIO_MODER_MODE6); // A5 -> output, A0 input\r
@@ -24,16 +29,37 @@ int main(void)
        GPIOA->PUPDR |= GPIO_PUPDR_PUPD5_0 | GPIO_PUPDR_PUPD6_0; // pulldown for button (1)\r
        //if (GPIOA->IDR & 0x01)\r
 \r
+       clock_init();\r
+       task_init(kmain);\r
+\r
+       while (1);\r
+}\r
+\r
+void task(void);\r
+void kmain(void)\r
+{\r
+       asm("cpsie i");\r
+\r
+       task_start(task, 1024);\r
        while (1) {\r
+               GPIOA->BSRR |= 1 << 6;\r
                delay(500);\r
-               GPIOA->BSRR |= 1 << 5;\r
                GPIOA->BRR |= 1 << 6;\r
                delay(500);\r
-               GPIOA->BSRR |= 1 << 6;\r
+       }\r
+}\r
+\r
+void task(void)\r
+{\r
+       while (1) {\r
+               GPIOA->BSRR |= 1 << 5;\r
+               delay(200);\r
                GPIOA->BRR |= 1 << 5;\r
+               delay(200);\r
        }\r
 }\r
 \r
+\r
 void _exit(int code)\r
 { for (;;); }\r
 \r
index b93d40a09ac6058790f3b0f675330b8ba682b163..57b11cb33c796690597416b4551a20d9d6581e8e 100644 (file)
@@ -62,7 +62,7 @@ defined in linker script */
 /* end address for the .bss section. defined in linker script */\r
 .word  _ebss\r
 \r
-.equ  BootRAM,        0xF1E0F85F\r
+//.equ  BootRAM,        0xF1E0F85F\r
 /**\r
  * @brief  This is the code that gets called when the processor first\r
  *          starts execution following a reset event. Only the absolutely\r
index c3bd859b8f51e970db3e4132851969fae8d15fe4..dc6dc160a2dca8085c115375207d85644b2c8daf 100644 (file)
@@ -1,25 +1,29 @@
-#include <stdint.h>\r
+#include <stm32l476xx.h>\r
 \r
 void NMI_Handler(void) {}\r
 \r
 void HardFault_Handler(void)\r
 {\r
-  while (1);\r
+       GPIOA->BSRR |= (1 << 5) | (1 << 6);\r
+       while (1);\r
 }\r
 \r
 void MemManage_Handler(void)\r
 {\r
-  while (1);\r
+       GPIOA->BSRR |= (1 << 5) | (1 << 6);\r
+       while (1);\r
 }\r
 \r
 void BusFault_Handler(void)\r
 {\r
-  while (1);\r
+       GPIOA->BSRR |= (1 << 5) | (1 << 6);\r
+       while (1);\r
 }\r
 \r
 void UsageFault_Handler(void)\r
 {\r
-  while (1);\r
+       GPIOA->BSRR |= (1 << 5) | (1 << 6);\r
+       while (1);\r
 }\r
 \r
 void SVC_Handler(void) {}\r
diff --git a/task.c b/task.c
new file mode 100644 (file)
index 0000000..b77d4f5
--- /dev/null
+++ b/task.c
@@ -0,0 +1,108 @@
+#include <task.h>
+#include <heap.h>
+#include <stm32l476xx.h>
+
+typedef struct {
+       uint32_t *sp;
+       uint8_t use;
+       uint32_t *stack;
+       void (*code)(void);
+} task_t;
+
+#define MAX_TASKS      4
+
+static task_t tasks[MAX_TASKS];
+static int next_idx = 0;
+
+void task_init(void (*init)(void))
+{
+       for (int i = 0; i < MAX_TASKS; i++)
+               tasks[i].use = 0;
+
+       task_start(init, 1024);
+       asm("\
+               msr psp, %0; \
+               mrs r0, control; \
+               orr r0, r0, #2; \
+               msr control, r0; \
+               isb; \
+       " :: "r" (tasks[0].sp));
+
+       init();
+
+       // force switch to tasking, call pendsv
+       //SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
+}
+
+extern void _exit(int);
+void task_exit(void)
+{
+       // TODO free stack?
+       asm("cpsid i"); // hope to catch next_idx
+       tasks[next_idx].use = 0;
+       asm("cpsie i");
+       while (1); // bye
+       //_exit(0);
+}
+
+void task_start(void (*task)(void), uint16_t stackSize)
+{
+       asm("cpsid i"); // just to be safe
+
+       for (int i = 0; i < MAX_TASKS; i++) {
+               if (tasks[i].use == 0) {
+                       tasks[i].stack = hmalloc(stackSize);
+                       tasks[i].sp = tasks[i].stack + stackSize - 16;
+                       tasks[i].sp[13] = (uint32_t)task_exit;
+                       tasks[i].sp[14] = (uint32_t)task;
+                       tasks[i].sp[15] = 0x01000000;
+                       tasks[i].use = 1;
+                       tasks[i].code = task;
+                       asm("cpsie i");
+                       return;
+               }
+       }
+
+       // TODO handle error
+}
+
+__attribute__ ((naked))
+void PendSV_Handler(void) 
+{
+       // save state
+       //stmdb r0!, {r4-r11};
+       asm("\
+               cpsid i; \
+               isb; \
+               dsb; \
+               mrs r0, psp; \
+               stmdb r0!, {r4-r11}; \
+               mov %0, r0; \
+       " : "=r" (tasks[next_idx].sp));
+
+       // find next task (round-robin style)
+       do {
+               if (++next_idx == MAX_TASKS) {
+                       next_idx = 0;
+                       break; // task 0 better exist
+               }
+       } while (tasks[next_idx].use == 0);
+
+       // restore
+       //ldmia r0!, {r4-r11};
+       asm("\
+               mov r0, %0; \
+               ldmia r0!, {r4-r11}; \
+               msr psp, r0; \
+               isb; \
+               dsb; \
+       " :: "r" (tasks[next_idx].sp));
+
+       // end
+       asm("\
+               mov r0, #0xFFFFFFFD; \
+               cpsie i; \
+               bx r0; \
+       ");
+}
+