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

feat(epicardium): Enable tickless idle

parent 86d57a65
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#define MXC_ASSERT_ENABLE
#include "mxc_assert.h"
#include "max32665.h"
/* CMSIS keeps a global updated with current system clock in Hz */
......@@ -22,7 +25,14 @@
#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: 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 */
#define configUSE_IDLE_HOOK 0
......@@ -42,4 +52,17 @@
#define xPortPendSVHandler PendSV_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 */
#include <stdint.h>
#include <stdbool.h>
/*
* Semaphore used for API synchronization.
......
......@@ -18,20 +18,45 @@ int api_dispatcher_init()
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) {}
if (API_CALL_MEM->call_flag != _API_FLAG_CALLING) {
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;
}
id = API_CALL_MEM->id;
api_id_t id = API_CALL_MEM->id;
__api_dispatch_call(id, API_CALL_MEM->buffer);
API_CALL_MEM->call_flag = _API_FLAG_RETURNED;
event_ready = false;
SEMA_FreeSema(_API_SEMAPHORE);
/* Notify the caller that we returned */
......
......@@ -7,11 +7,20 @@
int api_dispatcher_init();
/*
* Attempt to dispatch a call, if the caller has requested one.
* Will return 0 if no call was dispatched and the ID of the dispatched
* call otherwise.
* Check whether the other core requested a call. If this function returns
* true, the dispatcher should call api_dispatcher_exec() to actually dispatch
* 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 */
void __api_dispatch_call(api_id_t id, void*buffer);
......@@ -12,17 +12,65 @@
#include "FreeRTOS.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)
{
leds_set(led, r, g, b);
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)
{
while (1) {
api_dispatcher_poll();
vTaskDelay(portTICK_PERIOD_MS * 10);
if (api_dispatcher_poll()) {
api_dispatcher_exec();
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}
......@@ -84,7 +132,7 @@ int main(void)
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 2,
NULL
&dispatcher_task_id
) != pdPASS) {
printf("Failed to create api dispatcher task!\n");
abort();
......@@ -97,12 +145,5 @@ int main(void)
core1_start();
vTaskStartScheduler();
printf("ERROR: FreeRTOS did not start due to above error!\n");
#if 0
while(1) {
__WFE();
api_dispatcher_poll();
}
#endif
printf("ERROR: FreeRTOS did not start due to unknown error!\n");
}
......@@ -3,6 +3,7 @@
#include "serial.h"
#include "max32665.h"
#include "cdcacm.h"
#include "uart.h"
#include "tmr_utils.h"
......@@ -11,16 +12,26 @@
#include "task.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;
/*
* API-call to write a string. Output goes to both CDCACM and UART
*/
void epic_uart_write_str(char*str, intptr_t length)
{
UART_Write(ConsoleUart, (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 chr;
......@@ -28,11 +39,39 @@ char epic_uart_read_chr(void)
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)
{
static uint8_t buffer[sizeof(char) * SERIAL_READ_BUFFER_SIZE];
static StaticQueue_t read_queue_data;
serial_task_id = xTaskGetCurrentTaskHandle();
/* Setup read queue */
read_queue = xQueueCreateStatic(
SERIAL_READ_BUFFER_SIZE,
......@@ -44,31 +83,31 @@ void vSerialTask(void*pvParameters)
/* Setup UART interrupt */
NVIC_ClearPendingIRQ(UART0_IRQn);
NVIC_DisableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn, 1);
NVIC_SetPriority(UART0_IRQn, 6);
NVIC_EnableIRQ(UART0_IRQn);
while (1) {
char chr;
/* TODO: Wait for interrupt on either device */
vTaskDelay(portTICK_PERIOD_MS * 10);
unsigned char data;
uart_req_t read_req = {
.data = &data,
.len = 1,
.callback = uart_callback,
};
if(UART_NumReadAvail(ConsoleUart) > 0) {
chr = UART_ReadByte(ConsoleUart);
} else if(cdcacm_num_read_avail() > 0) {
chr = cdcacm_read();
} else {
continue;
while (1) {
int ret = UART_ReadAsync(ConsoleUart, &read_req);
if (ret != E_NO_ERROR && ret != E_BUSY) {
printf("error reading uart: %d\n", ret);
vTaskDelay(portMAX_DELAY);
}
if (chr == 0x3) {
/* Control-C */
TMR_TO_Start(MXC_TMR5, 1, 0);
ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
if (read_req.num > 0) {
enqueue_char(*read_req.data);
}
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
/* Queue overran, wait a bit */
vTaskDelay(portTICK_PERIOD_MS * 50);
while (UART_NumReadAvail(ConsoleUart) > 0) {
enqueue_char(UART_ReadByte(ConsoleUart));
}
}
}
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