From f87de543ebd3366e898f2a76b919faf8f8e3819a Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Wed, 3 Jul 2019 20:28:44 +0200
Subject: [PATCH] feat(epicardium): Port to FreeRTOS

Signed-off-by: Rahix <rahix@rahix.de>
---
 epicardium/FreeRTOSConfig.h | 45 +++++++++++++++++++
 epicardium/cdcacm.c         |  3 ++
 epicardium/main.c           | 90 ++++++++++++++++++++++++++++++-------
 epicardium/meson.build      | 20 ++++++++-
 epicardium/serial.c         | 68 ++++++++++++++++++++++++++++
 epicardium/serial.h         |  8 ++++
 6 files changed, 216 insertions(+), 18 deletions(-)
 create mode 100644 epicardium/FreeRTOSConfig.h
 create mode 100644 epicardium/serial.c
 create mode 100644 epicardium/serial.h

diff --git a/epicardium/FreeRTOSConfig.h b/epicardium/FreeRTOSConfig.h
new file mode 100644
index 000000000..26e51bc4c
--- /dev/null
+++ b/epicardium/FreeRTOSConfig.h
@@ -0,0 +1,45 @@
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+#include "max32665.h"
+
+/* CMSIS keeps a global updated with current system clock in Hz */
+#define configCPU_CLOCK_HZ          ((unsigned long)120000000)
+
+/* TODO: Adjust this for tickless idle */
+#define configTICK_RATE_HZ          ((portTickType)1000)
+
+/* Memory */
+#define configTOTAL_HEAP_SIZE       ((size_t)(26 * 1024))
+#define configMINIMAL_STACK_SIZE    ((unsigned short)128)
+
+#define configMAX_PRIORITIES        5
+/* # of priority bits (configured in hardware) is provided by CMSIS */
+#define configPRIO_BITS             __NVIC_PRIO_BITS
+/* Priority 7, or 255 as only the top three bits are implemented.  This is the lowest priority. */
+#define configKERNEL_INTERRUPT_PRIORITY       ( ( unsigned char ) 7 << ( 8 - configPRIO_BITS) )
+/* Priority 5, or 160 as only the top three bits are implemented. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY  ( ( unsigned char ) 5 << ( 8 - configPRIO_BITS) )  
+
+/* We want to use preemption to easier integrate components */
+#define configUSE_PREEMPTION        1
+
+/* TODO: Adjust */
+#define configUSE_IDLE_HOOK         0
+#define configUSE_TICK_HOOK         0
+#define configUSE_CO_ROUTINES       0
+#define configUSE_16_BIT_TICKS      0
+#define configUSE_MUTEXES           1
+
+#define INCLUDE_vTaskSuspend        1
+#define INCLUDE_vTaskDelay          1
+
+/* Allow static allocation of data structures */
+#define configSUPPORT_STATIC_ALLOCATION 1
+
+/* Alias the default handler names to match CMSIS weak symbols */
+#define vPortSVCHandler       SVC_Handler
+#define xPortPendSVHandler    PendSV_Handler
+#define xPortSysTickHandler   SysTick_Handler
+
+#endif /* FREERTOS_CONFIG_H */
diff --git a/epicardium/cdcacm.c b/epicardium/cdcacm.c
index a11d38e05..5bc8f706d 100644
--- a/epicardium/cdcacm.c
+++ b/epicardium/cdcacm.c
@@ -344,7 +344,10 @@ void USB_IRQHandler(void)
 }
 
 /******************************************************************************/
+/* TODO: We probably need to fix something related to this */
+#if 0
 void SysTick_Handler(void)
 {
     mxc_delay_handler();
 }
+#endif /* 0 */
diff --git a/epicardium/main.c b/epicardium/main.c
index 40ef9e9ac..3490b026d 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -1,35 +1,59 @@
 #include <stdio.h>
-#include "card10.h"
+#include <stdlib.h>
+
 #include "uart.h"
 #include "cdcacm.h"
+
+#include "card10.h"
 #include "leds.h"
 #include "api/dispatcher.h"
+#include "serial.h"
 
-extern mxc_uart_regs_t * ConsoleUart;
+#include "FreeRTOS.h"
+#include "task.h"
 
-void epic_uart_write_str(char*str, intptr_t length)
+void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
 {
-	UART_Write(ConsoleUart, (uint8_t*)str, length);
-	cdcacm_write((uint8_t*)str, length);
+	leds_set(led, r, g, b);
+	leds_update();
 }
 
-char epic_uart_read_chr(void)
+void vApiDispatcher(void*pvParameters)
 {
-	while(1) {
-		if(UART_NumReadAvail(ConsoleUart) > 0) {
-			return UART_ReadByte(ConsoleUart);
-		}
-
-		if(cdcacm_num_read_avail() > 0) {
-			return cdcacm_read();
-		}
+	while (1) {
+		api_dispatcher_poll();
+		vTaskDelay(portTICK_PERIOD_MS * 10);
 	}
 }
 
-void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
+void vApplicationGetIdleTaskMemory(
+	StaticTask_t**ppxIdleTaskTCBBuffer,
+	StackType_t**ppxIdleTaskStackBuffer,
+	uint32_t *pulIdleTaskStackSize)
 {
-	leds_set(led, r, g, b);
-	leds_update();
+	/*
+	 * If the buffers to be provided to the Idle task are declared inside this
+	 * function then they must be declared static - otherwise they will be allocated on
+	 * the stack and so not exists after this function exits.
+	 */
+	static StaticTask_t xIdleTaskTCB;
+	static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
+
+	/*
+	 * Pass out a pointer to the StaticTask_t structure in which the Idle task's
+	 * ktate will be stored.
+	 */
+	*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
+
+	/* Pass out the array that will be used as the Idle task's stack. */
+	*ppxIdleTaskStackBuffer = uxIdleTaskStack;
+
+	/*
+	 * Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
+	 * Note that, as the array is necessarily of type StackType_t,
+	 * configMINIMAL_STACK_SIZE is specified in words, not bytes.
+	 */
+	*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
 }
 
 int main(void)
@@ -39,14 +63,46 @@ int main(void)
 
 	cdcacm_init();
 
+	printf("Initializing tasks ...\n");
+
+	/* Serial */
+	if (xTaskCreate(
+		vSerialTask,
+		(const char*)"Serial",
+		configMINIMAL_STACK_SIZE,
+		NULL,
+		tskIDLE_PRIORITY + 1,
+		NULL
+	) != pdPASS) {
+		printf("Failed to create serial-comms task!\n");
+		abort();
+	}
+
+	if (xTaskCreate(
+		vApiDispatcher,
+		(const char*)"API Dispatcher",
+		configMINIMAL_STACK_SIZE,
+		NULL,
+		tskIDLE_PRIORITY  + 2,
+		NULL
+	) != pdPASS) {
+		printf("Failed to create api dispatcher task!\n");
+		abort();
+	}
+
 	printf("Initializing dispatcher ...\n");
 	api_dispatcher_init();
 
 	printf("Staring core1 payload ...\n");
 	core1_start();
 
+	vTaskStartScheduler();
+	printf("ERROR: FreeRTOS did not start due to above error!\n");
+
+#if 0
 	while(1) {
 		__WFE();
 		api_dispatcher_poll();
 	}
+#endif
 }
diff --git a/epicardium/meson.build b/epicardium/meson.build
index f84abbe79..7aa214405 100644
--- a/epicardium/meson.build
+++ b/epicardium/meson.build
@@ -39,6 +39,22 @@ api_dispatcher_lib = static_library(
   dependencies: periphdriver,
 )
 
+##########################################################################
+#
+# FreeRTOS
+#
+##########################################################################
+
+freertos = static_library(
+  'freertos',
+  freertos_sources,
+  dependencies: periphdriver,
+  include_directories: [
+    freertos_includes,
+    include_directories('./'),
+  ],
+)
+
 ##########################################################################
 #
 # Epicardium executable
@@ -49,9 +65,11 @@ elf = executable(
   name + '.elf',
   'main.c',
   'cdcacm.c',
+  'serial.c',
   dependencies: [libcard10, max32665_startup_core0, maxusb],
-  link_with: api_dispatcher_lib,
+  link_with: [api_dispatcher_lib, freertos],
   link_whole: [max32665_startup_core0_lib, board_card10_lib],
+  include_directories: [freertos_includes],
   link_args: [
     '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
   ],
diff --git a/epicardium/serial.c b/epicardium/serial.c
new file mode 100644
index 000000000..0a062c23d
--- /dev/null
+++ b/epicardium/serial.c
@@ -0,0 +1,68 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "serial.h"
+
+#include "cdcacm.h"
+#include "uart.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+extern mxc_uart_regs_t * ConsoleUart;
+
+static QueueHandle_t read_queue;
+
+void epic_uart_write_str(char*str, intptr_t length)
+{
+	UART_Write(ConsoleUart, (uint8_t*)str, length);
+	cdcacm_write((uint8_t*)str, length);
+}
+
+char epic_uart_read_chr(void)
+{
+	char chr;
+	xQueueReceive(read_queue, &chr, portMAX_DELAY);
+	return chr;
+}
+
+void vSerialTask(void*pvParameters)
+{
+	static uint8_t buffer[sizeof(char) * SERIAL_READ_BUFFER_SIZE];
+	static StaticQueue_t read_queue_data;
+
+	/* Setup read queue */
+	read_queue = xQueueCreateStatic(
+		SERIAL_READ_BUFFER_SIZE,
+		sizeof(char),
+		buffer,
+		&read_queue_data
+	);
+
+	/* Setup UART interrupt */
+	NVIC_ClearPendingIRQ(UART0_IRQn);
+	NVIC_DisableIRQ(UART0_IRQn);
+	NVIC_SetPriority(UART0_IRQn, 1);
+	NVIC_EnableIRQ(UART0_IRQn);
+
+	while (1) {
+		char chr;
+
+		/* TODO: Wait for interrupt on either device */
+		vTaskDelay(portTICK_PERIOD_MS * 10);
+
+		if(UART_NumReadAvail(ConsoleUart) > 0) {
+			chr = UART_ReadByte(ConsoleUart);
+		} else if(cdcacm_num_read_avail() > 0) {
+			chr = cdcacm_read();
+		} else {
+			continue;
+		}
+
+		if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
+			/* Queue overran, wait a bit */
+			vTaskDelay(portTICK_PERIOD_MS * 50);
+		}
+	}
+}
diff --git a/epicardium/serial.h b/epicardium/serial.h
new file mode 100644
index 000000000..5e2e17795
--- /dev/null
+++ b/epicardium/serial.h
@@ -0,0 +1,8 @@
+#ifndef EPIC_SERIAL_H
+#define EPIC_SERIAL_H
+
+#define SERIAL_READ_BUFFER_SIZE 128
+
+void vSerialTask(void*pvParameters);
+
+#endif /* EPIC_SERIAL_H */
-- 
GitLab