Verified Commit 0ca995ad authored by Rahix's avatar Rahix
Browse files

feat(epicardium): Enable tickless idle

parent 86d57a65
#ifndef FREERTOS_CONFIG_H #ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H
#define MXC_ASSERT_ENABLE
#include "mxc_assert.h"
#include "max32665.h" #include "max32665.h"
/* CMSIS keeps a global updated with current system clock in Hz */ /* CMSIS keeps a global updated with current system clock in Hz */
...@@ -22,7 +25,14 @@ ...@@ -22,7 +25,14 @@
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( ( unsigned char ) 5 << ( 8 - configPRIO_BITS) ) #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( ( unsigned char ) 5 << ( 8 - configPRIO_BITS) )
/* We want to use preemption to easier integrate components */ /* We want to use preemption to easier integrate components */
#define configUSE_PREEMPTION 1 /* TODO: Figure out why turning this on does not work ... */
#define configUSE_PREEMPTION 0
/*
* Tickless idle from the FreeRTOS port + our own hooks (defined further down in
* this file)
*/
#define configUSE_TICKLESS_IDLE 1
/* TODO: Adjust */ /* TODO: Adjust */
#define configUSE_IDLE_HOOK 0 #define configUSE_IDLE_HOOK 0
...@@ -42,4 +52,17 @@ ...@@ -42,4 +52,17 @@
#define xPortPendSVHandler PendSV_Handler #define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler #define xPortSysTickHandler SysTick_Handler
/* Assert */
#define configASSERT(x) MXC_ASSERT(x)
/* Tickless idle hooks */
typedef uint32_t TickType_t;
void pre_idle_sleep(TickType_t xExpectedIdleTime);
#define configPRE_SLEEP_PROCESSING(xModifiableIdleTime) \
pre_idle_sleep(xModifiableIdleTime); xModifiableIdleTime = 0
void post_idle_sleep(TickType_t xExpectedIdleTime);
#define configPOST_SLEEP_PROCESSING(xExpectedIdleTime) \
post_idle_sleep(xExpectedIdleTime)
#endif /* FREERTOS_CONFIG_H */ #endif /* FREERTOS_CONFIG_H */
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
/* /*
* Semaphore used for API synchronization. * Semaphore used for API synchronization.
......
...@@ -18,20 +18,45 @@ int api_dispatcher_init() ...@@ -18,20 +18,45 @@ int api_dispatcher_init()
return ret; return ret;
} }
api_id_t api_dispatcher_poll() static bool event_ready = false;
bool api_dispatcher_poll_once()
{ {
api_id_t id = 0; if (event_ready) {
return false;
}
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {} while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {}
if (API_CALL_MEM->call_flag != _API_FLAG_CALLING) { if (API_CALL_MEM->call_flag != _API_FLAG_CALLING) {
SEMA_FreeSema(_API_SEMAPHORE); SEMA_FreeSema(_API_SEMAPHORE);
return false;
}
event_ready = true;
return true;
}
bool api_dispatcher_poll()
{
if (event_ready) {
return true;
}
return api_dispatcher_poll_once();
}
api_id_t api_dispatcher_exec()
{
if (!event_ready) {
return 0; return 0;
} }
id = API_CALL_MEM->id; api_id_t id = API_CALL_MEM->id;
__api_dispatch_call(id, API_CALL_MEM->buffer); __api_dispatch_call(id, API_CALL_MEM->buffer);
API_CALL_MEM->call_flag = _API_FLAG_RETURNED; API_CALL_MEM->call_flag = _API_FLAG_RETURNED;
event_ready = false;
SEMA_FreeSema(_API_SEMAPHORE); SEMA_FreeSema(_API_SEMAPHORE);
/* Notify the caller that we returned */ /* Notify the caller that we returned */
......
...@@ -7,11 +7,20 @@ ...@@ -7,11 +7,20 @@
int api_dispatcher_init(); int api_dispatcher_init();
/* /*
* Attempt to dispatch a call, if the caller has requested one. * Check whether the other core requested a call. If this function returns
* Will return 0 if no call was dispatched and the ID of the dispatched * true, the dispatcher should call api_dispatcher_exec() to actually dispatch
* call otherwise. * the call. Consecutive calls to this function will return false. Use
* api_dispatcher_poll() if your need to recheck.
*/ */
api_id_t api_dispatcher_poll(); bool api_dispatcher_poll_once();
bool api_dispatcher_poll();
/*
* Attempt to dispatch a call, if one had been polled using
* api_dispatcher_poll(). Will return 0 if no call was dispatched or the ID of
* the dispatched call otherwise.
*/
api_id_t api_dispatcher_exec();
/* This function is defined by the generated dispatcher code */ /* This function is defined by the generated dispatcher code */
void __api_dispatch_call(api_id_t id, void*buffer); void __api_dispatch_call(api_id_t id, void*buffer);
...@@ -12,17 +12,65 @@ ...@@ -12,17 +12,65 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
static TaskHandle_t dispatcher_task_id;
/* TODO: Move out of main.c */
void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b) void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
{ {
leds_set(led, r, g, b); leds_set(led, r, g, b);
leds_update(); leds_update();
} }
/*
* This hook is called before FreeRTOS enters tickless idle.
*/
void pre_idle_sleep(TickType_t xExpectedIdleTime)
{
if (xExpectedIdleTime > 0) {
/*
* WFE because the other core should be able to notify
* epicardium if it wants to issue an API call.
*/
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "wfe" );
__asm volatile( "isb" );
}
}
/*
* This hook is called after FreeRTOS exits tickless idle.
*/
void post_idle_sleep(TickType_t xExpectedIdleTime)
{
/* Check whether a new API call was issued. */
if (api_dispatcher_poll_once()) {
xTaskNotifyGive(dispatcher_task_id);
}
}
#if 0
void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)
{
if (xExpectedIdleTime > 0) {
__WFE();
if (api_dispatcher_poll()) {
xTaskNotifyGive(dispatcher_task_id);
}
}
}
#endif
/*
* API dispatcher task. This task will sleep until an API call is issued and
* then wake up to dispatch it.
*/
void vApiDispatcher(void*pvParameters) void vApiDispatcher(void*pvParameters)
{ {
while (1) { while (1) {
api_dispatcher_poll(); if (api_dispatcher_poll()) {
vTaskDelay(portTICK_PERIOD_MS * 10); api_dispatcher_exec();
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
} }
} }
...@@ -84,7 +132,7 @@ int main(void) ...@@ -84,7 +132,7 @@ int main(void)
configMINIMAL_STACK_SIZE, configMINIMAL_STACK_SIZE,
NULL, NULL,
tskIDLE_PRIORITY + 2, tskIDLE_PRIORITY + 2,
NULL &dispatcher_task_id
) != pdPASS) { ) != pdPASS) {
printf("Failed to create api dispatcher task!\n"); printf("Failed to create api dispatcher task!\n");
abort(); abort();
...@@ -97,12 +145,5 @@ int main(void) ...@@ -97,12 +145,5 @@ int main(void)
core1_start(); core1_start();
vTaskStartScheduler(); vTaskStartScheduler();
printf("ERROR: FreeRTOS did not start due to above error!\n"); printf("ERROR: FreeRTOS did not start due to unknown error!\n");
#if 0
while(1) {
__WFE();
api_dispatcher_poll();
}
#endif
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "serial.h" #include "serial.h"
#include "max32665.h"
#include "cdcacm.h" #include "cdcacm.h"
#include "uart.h" #include "uart.h"
#include "tmr_utils.h" #include "tmr_utils.h"
...@@ -11,16 +12,26 @@ ...@@ -11,16 +12,26 @@
#include "task.h" #include "task.h"
#include "queue.h" #include "queue.h"
extern mxc_uart_regs_t * ConsoleUart; /* Task ID for the serial handler */
TaskHandle_t serial_task_id;
/* The serial console in use (UART0) */
extern mxc_uart_regs_t* ConsoleUart;
/* Read queue, filled by both UART and CDCACM */
static QueueHandle_t read_queue; static QueueHandle_t read_queue;
/*
* API-call to write a string. Output goes to both CDCACM and UART
*/
void epic_uart_write_str(char*str, intptr_t length) void epic_uart_write_str(char*str, intptr_t length)
{ {
UART_Write(ConsoleUart, (uint8_t*)str, length); UART_Write(ConsoleUart, (uint8_t*)str, length);
cdcacm_write((uint8_t*)str, length); cdcacm_write((uint8_t*)str, length);
} }
/*
* Blocking API-call to read a character from the queue.
*/
char epic_uart_read_chr(void) char epic_uart_read_chr(void)
{ {
char chr; char chr;
...@@ -28,11 +39,39 @@ char epic_uart_read_chr(void) ...@@ -28,11 +39,39 @@ char epic_uart_read_chr(void)
return chr; return chr;
} }
/* Interrupt handler needed for SDK UART implementation */
void UART0_IRQHandler(void)
{
UART_Handler(ConsoleUart);
}
static void uart_callback(uart_req_t*req, int error)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(serial_task_id, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static void enqueue_char(char chr)
{
if (chr == 0x3) {
/* Control-C */
TMR_TO_Start(MXC_TMR5, 1, 0);
}
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
/* Queue overran, wait a bit */
vTaskDelay(portTICK_PERIOD_MS * 50);
}
}
void vSerialTask(void*pvParameters) void vSerialTask(void*pvParameters)
{ {
static uint8_t buffer[sizeof(char) * SERIAL_READ_BUFFER_SIZE]; static uint8_t buffer[sizeof(char) * SERIAL_READ_BUFFER_SIZE];
static StaticQueue_t read_queue_data; static StaticQueue_t read_queue_data;
serial_task_id = xTaskGetCurrentTaskHandle();
/* Setup read queue */ /* Setup read queue */
read_queue = xQueueCreateStatic( read_queue = xQueueCreateStatic(
SERIAL_READ_BUFFER_SIZE, SERIAL_READ_BUFFER_SIZE,
...@@ -44,31 +83,31 @@ void vSerialTask(void*pvParameters) ...@@ -44,31 +83,31 @@ void vSerialTask(void*pvParameters)
/* Setup UART interrupt */ /* Setup UART interrupt */
NVIC_ClearPendingIRQ(UART0_IRQn); NVIC_ClearPendingIRQ(UART0_IRQn);
NVIC_DisableIRQ(UART0_IRQn); NVIC_DisableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn, 1); NVIC_SetPriority(UART0_IRQn, 6);
NVIC_EnableIRQ(UART0_IRQn); NVIC_EnableIRQ(UART0_IRQn);
while (1) { unsigned char data;
char chr; uart_req_t read_req = {
.data = &data,
.len = 1,
.callback = uart_callback,
};
/* TODO: Wait for interrupt on either device */ while (1) {
vTaskDelay(portTICK_PERIOD_MS * 10); int ret = UART_ReadAsync(ConsoleUart, &read_req);
if (ret != E_NO_ERROR && ret != E_BUSY) {
if(UART_NumReadAvail(ConsoleUart) > 0) { printf("error reading uart: %d\n", ret);
chr = UART_ReadByte(ConsoleUart); vTaskDelay(portMAX_DELAY);
} else if(cdcacm_num_read_avail() > 0) {
chr = cdcacm_read();
} else {
continue;
} }
if (chr == 0x3) { ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
/* Control-C */
TMR_TO_Start(MXC_TMR5, 1, 0); if (read_req.num > 0) {
enqueue_char(*read_req.data);
} }
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) { while (UART_NumReadAvail(ConsoleUart) > 0) {
/* Queue overran, wait a bit */ enqueue_char(UART_ReadByte(ConsoleUart));
vTaskDelay(portTICK_PERIOD_MS * 50);
} }
} }
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment