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
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));
}
--- /dev/null
+#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;
+}
--- /dev/null
+#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_
--- /dev/null
+#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_
\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
.ARM.attributes 0 : { *(.ARM.attributes) }\r
}\r
\r
-\r
+_total_ram = _estack - _end;\r
#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
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
/* 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
-#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
--- /dev/null
+#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; \
+ ");
+}
+