diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2018-01-01 17:40:28 -0500 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2018-01-01 17:40:28 -0500 |
commit | 058c283919424ef8b4425cdf74739535dd1d8072 (patch) | |
tree | 7aa6c40d7c6aa1dad5b0fba24f22c22759fcab59 | |
parent | de7c4fb07d1ac0298e7fc62000c35193e221aaae (diff) |
heap; multitasking
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | clock.c | 13 | ||||
-rw-r--r-- | heap.c | 38 | ||||
-rw-r--r-- | include/heap.h | 11 | ||||
-rw-r--r-- | include/task.h | 10 | ||||
-rw-r--r-- | link.ld | 12 | ||||
-rw-r--r-- | main.c | 36 | ||||
-rw-r--r-- | startup_stm32l476xx.s | 2 | ||||
-rw-r--r-- | stm32l4xx_it.c | 14 | ||||
-rw-r--r-- | task.c | 108 |
10 files changed, 224 insertions, 22 deletions
@@ -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 @@ -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)); } @@ -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 index 0000000..e04b15e --- /dev/null +++ b/include/heap.h @@ -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 index 0000000..c57b2c0 --- /dev/null +++ b/include/task.h @@ -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_ @@ -34,15 +34,15 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */
_estack = 0x20018000; /* end of RAM */
-/* Generate a link error if heap and stack don't fit into RAM */
-_Min_Heap_Size = 0x200;; /* required amount of heap */
-_Min_Stack_Size = 0x400;; /* required amount of stack */
+
+_Min_Stack_Size = 0x0400; /* 1k min. stack */
+_Min_Heap_Size = 0x0400; /* 1k min. heap */
/* Specify the memory areas */
MEMORY
{
-FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
-RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
+ FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Define output sections */
@@ -166,4 +166,4 @@ SECTIONS .ARM.attributes 0 : { *(.ARM.attributes) }
}
-
+_total_ram = _estack - _end;
@@ -1,21 +1,26 @@ #include <stm32l476xx.h>
#include <clock.h>
+#include <heap.h>
+#include <task.h>
/**
* Accomplishments:
* - GPIO in/out
* - got to 80MHz clock
+ * - basic heap
+ * - multitask, can exit
*/
void pulse(uint8_t byte);
+void kmain(void);
int main(void)
{
+ asm("cpsid i");
+
// prepare flash latency for 40MHz operation
FLASH->ACR &= ~(FLASH_ACR_LATENCY);
- FLASH->ACR |= FLASH_ACR_LATENCY_2WS;
-
- clock_init();
+ FLASH->ACR |= FLASH_ACR_LATENCY_4WS;
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; // A clk enable
GPIOA->MODER &= ~(GPIO_MODER_MODE5 | GPIO_MODER_MODE6); // A5 -> output, A0 input
@@ -24,16 +29,37 @@ int main(void) GPIOA->PUPDR |= GPIO_PUPDR_PUPD5_0 | GPIO_PUPDR_PUPD6_0; // pulldown for button (1)
//if (GPIOA->IDR & 0x01)
+ clock_init();
+ task_init(kmain);
+
+ while (1);
+}
+
+void task(void);
+void kmain(void)
+{
+ asm("cpsie i");
+
+ task_start(task, 1024);
while (1) {
+ GPIOA->BSRR |= 1 << 6;
delay(500);
- GPIOA->BSRR |= 1 << 5;
GPIOA->BRR |= 1 << 6;
delay(500);
- GPIOA->BSRR |= 1 << 6;
+ }
+}
+
+void task(void)
+{
+ while (1) {
+ GPIOA->BSRR |= 1 << 5;
+ delay(200);
GPIOA->BRR |= 1 << 5;
+ delay(200);
}
}
+
void _exit(int code)
{ for (;;); }
diff --git a/startup_stm32l476xx.s b/startup_stm32l476xx.s index b93d40a..57b11cb 100644 --- a/startup_stm32l476xx.s +++ b/startup_stm32l476xx.s @@ -62,7 +62,7 @@ defined in linker script */ /* end address for the .bss section. defined in linker script */
.word _ebss
-.equ BootRAM, 0xF1E0F85F
+//.equ BootRAM, 0xF1E0F85F
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
diff --git a/stm32l4xx_it.c b/stm32l4xx_it.c index c3bd859..dc6dc16 100644 --- a/stm32l4xx_it.c +++ b/stm32l4xx_it.c @@ -1,25 +1,29 @@ -#include <stdint.h>
+#include <stm32l476xx.h>
void NMI_Handler(void) {}
void HardFault_Handler(void)
{
- while (1);
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
}
void MemManage_Handler(void)
{
- while (1);
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
}
void BusFault_Handler(void)
{
- while (1);
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
}
void UsageFault_Handler(void)
{
- while (1);
+ GPIOA->BSRR |= (1 << 5) | (1 << 6);
+ while (1);
}
void SVC_Handler(void) {}
@@ -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; \ + "); +} + |