Skip to content
Snippets Groups Projects
Commit cb111dea authored by schneider's avatar schneider
Browse files

Merge branch 'rahix/interrupts' into 'master'

Dispatch interrupts asynchroneously

See merge request !377
parents fd55dc36 4b171bea
No related branches found
No related tags found
No related merge requests found
Showing with 248 additions and 80 deletions
...@@ -14,31 +14,34 @@ Epicardium ...@@ -14,31 +14,34 @@ Epicardium
Epicardium is based on `FreeRTOS <https://www.freertos.org/>`_. There are a Epicardium is based on `FreeRTOS <https://www.freertos.org/>`_. There are a
number of tasks that will have been keeping card10 running. These are: number of tasks that will have been keeping card10 running. These are:
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| Name | ID Global | Priority | Description | | Name | ID Global | Priority | Description |
+===================+===============================+==========+===========================================+ +====================+===============================+==========+===========================================+
| `vPmicTask`_ | ``pmic_task_id`` (static) | +4 | Power Management (and Reset Button) | | `vPmicTask`_ | ``pmic_task_id`` (static) | +4 | Power Management (and Reset Button) |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vLifecycleTask`_ | ``lifecycle_task`` (static) | +3 | Control of the payload running on core 1. | | `vLifecycleTask`_ | ``lifecycle_task`` (static) | +3 | Control of the payload running on core 1. |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vBleTask`_ | ``ble_task_id`` (static) | +3 | Bluetooth Low Energy Stack | | `vBleTask`_ | ``ble_task_id`` (static) | +3 | Bluetooth Low Energy Stack |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vSerialTask`_ | ``serial_task_id`` | +3 | Serial Output via UART/CDC-ACM/BLE | | `vSerialTask`_ | ``serial_task_id`` | +3 | Serial Output via UART/CDC-ACM/BLE |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vApiDispatcher`_ | ``dispatcher_task_id`` | +2 | Epicardium API dispatcher | | `vApiDispatcher`_ | ``dispatcher_task_id`` | +2 | Epicardium API dispatcher |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vInterruptsTask`_ | ``interrupts_task`` (static) | +2 | Interrupt dispatcher worker |
+--------------------+-------------------------------+----------+-------------------------------------------+
| `vLedTask`_ | -/- | +1 | LED Animations | | `vLedTask`_ | -/- | +1 | LED Animations |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vMAX30001Task`_ | ``max30001_task_id`` (static) | +1 | `MAX30001`_ ECG driver | | `vMAX30001Task`_ | ``max30001_task_id`` (static) | +1 | `MAX30001`_ ECG driver |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
| `vBhi160Task`_ | ``bhi160_task_id`` (static) | +1 | `BHI160`_ sensor fusion driver | | `vBhi160Task`_ | ``bhi160_task_id`` (static) | +1 | `BHI160`_ sensor fusion driver |
+-------------------+-------------------------------+----------+-------------------------------------------+ +--------------------+-------------------------------+----------+-------------------------------------------+
.. _vPmicTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/pmic.c#L281 .. _vPmicTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/pmic.c#L281
.. _vLifecycleTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/lifecycle.c#L361 .. _vLifecycleTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/lifecycle.c#L361
.. _vBleTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/ble/ble.c#L237 .. _vBleTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/ble/ble.c#L237
.. _vSerialTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/serial.c#L289 .. _vSerialTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/serial.c#L289
.. _vApiDispatcher: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/dispatcher.c#L25 .. _vApiDispatcher: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/dispatcher.c#L25
.. _vInterruptsTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/interrupts.c#L119
.. _vLedTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/personal_state.c#L58 .. _vLedTask: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/personal_state.c#L58
.. _vMAX30001Task: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/max30001.c#L378 .. _vMAX30001Task: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/max30001.c#L378
.. _vBhi160Task: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/bhi.c#L419 .. _vBhi160Task: https://git.card10.badge.events.ccc.de/card10/firmware/blob/master/epicardium/modules/bhi.c#L419
......
#include "epicardium.h" #include "epicardium.h"
#include "api/dispatcher.h" #include "api/dispatcher.h"
#include "api/interrupt-sender.h"
#include "modules/log.h" #include "modules/log.h"
#include "card10.h" #include "card10.h"
...@@ -10,6 +9,7 @@ ...@@ -10,6 +9,7 @@
#include "tmr.h" #include "tmr.h"
static void __core1_init(void); static void __core1_init(void);
extern void interrupt_trigger_sync(api_int_id_t id);
struct core1_info { struct core1_info {
/* Location of core1's interrupt vector table */ /* Location of core1's interrupt vector table */
...@@ -206,8 +206,13 @@ void core1_boot(void) ...@@ -206,8 +206,13 @@ void core1_boot(void)
void core1_trigger_reset(void) void core1_trigger_reset(void)
{ {
/* Signal core 1 that we intend to load a new payload. */ /*
api_interrupt_trigger(EPIC_INT_RESET); * Signal core 1 that we intend to load a new payload.
*
* This needs to be synchroneous because otherwise we will deadlock
* (Lifecycle task busy-spins and interrupt can never get dispatched).
*/
interrupt_trigger_sync(EPIC_INT_RESET);
} }
void core1_wait_ready(void) void core1_wait_ready(void)
......
#include "api/interrupt-sender.h" #include "api/interrupt-sender.h"
#include "api/common.h" #include "api/common.h"
#include "tmr_utils.h" #include "tmr_utils.h"
#include <assert.h>
static bool int_enabled[EPIC_INT_NUM];
int api_interrupt_trigger(api_int_id_t id)
{
if (id >= EPIC_INT_NUM) {
return -EINVAL;
}
if (int_enabled[id]) {
while (API_CALL_MEM->int_id != (api_int_id_t)(-1))
;
API_CALL_MEM->int_id = id;
TMR_TO_Start(MXC_TMR5, 1, 0);
}
return 0;
}
void api_interrupt_init(void) void api_interrupt_init(void)
{ {
API_CALL_MEM->int_id = (-1); API_CALL_MEM->int_id = (-1);
for (int i = 0; i < EPIC_INT_NUM; i++) {
int_enabled[i] = false;
} }
/* Reset interrupt is always enabled */ bool api_interrupt_is_ready(void)
int_enabled[EPIC_INT_RESET] = true;
}
int epic_interrupt_enable(api_int_id_t int_id)
{ {
if (int_id >= EPIC_INT_NUM) { return API_CALL_MEM->int_id == (api_int_id_t)(-1);
return -EINVAL;
} }
int_enabled[int_id] = true; void api_interrupt_trigger(api_int_id_t id)
return 0;
}
int epic_interrupt_disable(api_int_id_t int_id)
{ {
if (int_id >= EPIC_INT_NUM || int_id == EPIC_INT_RESET) { assert(API_CALL_MEM->int_id == (api_int_id_t)(-1));
return -EINVAL;
}
int_enabled[int_id] = false; API_CALL_MEM->int_id = id;
return 0; TMR_TO_Start(MXC_TMR5, 1, 0);
} }
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
#include "api/common.h" #include "api/common.h"
void api_interrupt_init(void); void api_interrupt_init(void);
int api_interrupt_trigger(api_int_id_t id); bool api_interrupt_is_ready(void);
void api_interrupt_trigger(api_int_id_t id);
...@@ -158,6 +158,10 @@ typedef uint32_t api_int_id_t; ...@@ -158,6 +158,10 @@ typedef uint32_t api_int_id_t;
* (masked/unmasked) using :c:func:`epic_interrupt_enable` and * (masked/unmasked) using :c:func:`epic_interrupt_enable` and
* :c:func:`epic_interrupt_disable`. * :c:func:`epic_interrupt_disable`.
* *
* These interrupts work similar to hardware interrupts: You will only get a
* single interrupt, even if multiple events occured since the ISR last ran
* (*this behavior is new since version 1.16*).
*
* .. warning:: * .. warning::
* *
* Never attempt to call the API from inside an ISR. This might trigger an * Never attempt to call the API from inside an ISR. This might trigger an
......
...@@ -133,6 +133,16 @@ int main(void) ...@@ -133,6 +133,16 @@ int main(void)
&dispatcher_task_id) != pdPASS) { &dispatcher_task_id) != pdPASS) {
panic("Failed to create %s task!", "API Dispatcher"); panic("Failed to create %s task!", "API Dispatcher");
} }
/* Interrupts */
if (xTaskCreate(
vInterruptsTask,
(const char *)"Interrupt Dispatcher",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 2,
NULL) != pdPASS) {
panic("Failed to create %s task!", "Interrupt Dispatcher");
}
/* BLE */ /* BLE */
if (ble_shall_start()) { if (ble_shall_start()) {
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "task.h" #include "task.h"
#include "queue.h" #include "queue.h"
#include "api/interrupt-sender.h"
#include "epicardium.h" #include "epicardium.h"
#include "modules/log.h" #include "modules/log.h"
#include "modules/modules.h" #include "modules/modules.h"
...@@ -320,7 +319,7 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data) ...@@ -320,7 +319,7 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
} }
if (wakeup) { if (wakeup) {
api_interrupt_trigger(epic_int); interrupt_trigger(epic_int);
} }
break; break;
default: default:
......
#include "epicardium.h" #include "epicardium.h"
#include "api/dispatcher.h" #include "api/dispatcher.h"
#include "api/interrupt-sender.h"
#include "usb/epc_usb.h" #include "usb/epc_usb.h"
#include "modules/filesystem.h" #include "modules/filesystem.h"
#include "modules/log.h" #include "modules/log.h"
...@@ -171,7 +170,7 @@ int hardware_early_init(void) ...@@ -171,7 +170,7 @@ int hardware_early_init(void)
/* /*
* API Dispatcher & API Interrupts * API Dispatcher & API Interrupts
*/ */
api_interrupt_init(); interrupt_init();
api_dispatcher_init(); api_dispatcher_init();
/* /*
...@@ -237,7 +236,7 @@ int hardware_reset(void) ...@@ -237,7 +236,7 @@ int hardware_reset(void)
/* /*
* API Dispatcher & API Interrupts * API Dispatcher & API Interrupts
*/ */
api_interrupt_init(); interrupt_init();
api_dispatcher_init(); api_dispatcher_init();
/* /*
......
#include "modules/mutex.h"
#include "modules/log.h"
#include "epicardium.h"
#include "api/interrupt-sender.h"
#include <assert.h>
struct interrupt_priv {
/* Whether this interrupt can be triggered */
bool int_enabled[EPIC_INT_NUM];
/* Whether this interrupt is waiting to be delivered */
bool int_pending[EPIC_INT_NUM];
/* Whether any interrupts are currently waiting to be triggered */
bool has_pending;
};
static struct interrupt_priv interrupt_data;
static struct mutex interrupt_mutex;
static TaskHandle_t interrupts_task;
void interrupt_trigger(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
if (interrupt_data.int_enabled[id]) {
interrupt_data.int_pending[id] = true;
interrupt_data.has_pending = true;
mutex_unlock(&interrupt_mutex);
xTaskNotifyGive(interrupts_task);
} else {
mutex_unlock(&interrupt_mutex);
}
}
void interrupt_trigger_sync(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
if (!interrupt_data.int_enabled[id])
goto out;
while (!api_interrupt_is_ready())
;
api_interrupt_trigger(id);
out:
mutex_unlock(&interrupt_mutex);
}
/*
* This function solely exists because of that one use of interrupts that breaks
* the rules: The RTC ALARM interrupt is triggered from a hardware ISR where
* interrupt_trigger_sync() won't work because it needs to lock a mutex.
*
* DO NOT USE THIS FUNCTION IN ANY NEW CODE.
*/
void __attribute__((deprecated)) interrupt_trigger_unsafe(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
if (!interrupt_data.int_enabled[id])
return;
while (!api_interrupt_is_ready())
;
api_interrupt_trigger(id);
}
static void interrupt_set_enabled(api_int_id_t id, bool enabled)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
interrupt_data.int_enabled[id] = enabled;
mutex_unlock(&interrupt_mutex);
}
void interrupt_init(void)
{
if (interrupt_mutex.name == NULL)
mutex_create(&interrupt_mutex);
api_interrupt_init();
/* Reset all irqs to disabled */
for (size_t i = 0; i < EPIC_INT_NUM; i++) {
interrupt_set_enabled(i, false);
}
/* Reset interrupt is always enabled */
interrupt_set_enabled(EPIC_INT_RESET, true);
}
/* Epic-calls {{{ */
int epic_interrupt_enable(api_int_id_t int_id)
{
if (int_id >= EPIC_INT_NUM) {
return -EINVAL;
}
interrupt_set_enabled(int_id, true);
return 0;
}
int epic_interrupt_disable(api_int_id_t int_id)
{
if (int_id >= EPIC_INT_NUM || int_id == EPIC_INT_RESET) {
return -EINVAL;
}
interrupt_set_enabled(int_id, false);
return 0;
}
/* }}} */
void vInterruptsTask(void *pvParameters)
{
interrupts_task = xTaskGetCurrentTaskHandle();
while (true) {
mutex_lock(&interrupt_mutex);
if (!interrupt_data.has_pending) {
/* Wait for a wakeup event from interrupt_trigger() */
mutex_unlock(&interrupt_mutex);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
mutex_lock(&interrupt_mutex);
}
while (!api_interrupt_is_ready()) {
mutex_unlock(&interrupt_mutex);
vTaskDelay(pdMS_TO_TICKS(5));
mutex_lock(&interrupt_mutex);
}
api_int_id_t current_irq = EPIC_INT_NUM;
for (size_t i = 0; i < EPIC_INT_NUM; i++) {
if (interrupt_data.int_pending[i]) {
current_irq = i;
interrupt_data.int_pending[i] = false;
break;
}
}
if (current_irq == EPIC_INT_NUM) {
interrupt_data.has_pending = false;
} else if (interrupt_data.int_enabled[current_irq]) {
api_interrupt_trigger(current_irq);
}
mutex_unlock(&interrupt_mutex);
}
}
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include "modules/config.h" #include "modules/config.h"
#include "modules/mutex.h" #include "modules/mutex.h"
#include "api/dispatcher.h" #include "api/dispatcher.h"
#include "api/interrupt-sender.h"
#include "l0der/l0der.h" #include "l0der/l0der.h"
#include "card10.h" #include "card10.h"
...@@ -355,9 +354,17 @@ void vLifecycleTask(void *pvParameters) ...@@ -355,9 +354,17 @@ void vLifecycleTask(void *pvParameters)
mutex_unlock(&core1_mutex); mutex_unlock(&core1_mutex);
/* If `main.py` exists, start it. Otherwise, start `menu.py`. */ /*
if (epic_exec("main.py") < 0) { * If `main.py` exists, start it. Otherwise, start `menu.py`.
return_to_menu(); *
* We are not using epic_exec() & return_to_menu() here because those
* trigger a reset which is undesirable during startup.
*/
mutex_lock(&core1_mutex);
int ret = load_sync("main.py", false);
mutex_unlock(&core1_mutex);
if (ret < 0) {
load_menu(false);
} }
hardware_init(); hardware_init();
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "task.h" #include "task.h"
#include "queue.h" #include "queue.h"
#include "api/interrupt-sender.h"
#include "epicardium.h" #include "epicardium.h"
#include "modules/log.h" #include "modules/log.h"
#include "modules/modules.h" #include "modules/modules.h"
...@@ -141,7 +140,7 @@ static void max30001_handle_samples(int16_t *sensor_data, int16_t n) ...@@ -141,7 +140,7 @@ static void max30001_handle_samples(int16_t *sensor_data, int16_t n)
LOG_WARN("max30001", "queue full"); LOG_WARN("max30001", "queue full");
} }
} }
api_interrupt_trigger(EPIC_INT_MAX30001_ECG); interrupt_trigger(EPIC_INT_MAX30001_ECG);
} }
/***** Functions *****/ /***** Functions *****/
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "task.h" #include "task.h"
#include "queue.h" #include "queue.h"
#include "api/interrupt-sender.h"
#include "modules/modules.h" #include "modules/modules.h"
static const gpio_cfg_t max86150_interrupt_pin = { static const gpio_cfg_t max86150_interrupt_pin = {
...@@ -140,7 +139,10 @@ static int max86150_handle_sample(struct max86150_sensor_data *data) ...@@ -140,7 +139,10 @@ static int max86150_handle_sample(struct max86150_sensor_data *data)
LOG_WARN("max86150", "queue full"); LOG_WARN("max86150", "queue full");
return -EIO; return -EIO;
} }
return api_interrupt_trigger(EPIC_INT_MAX86150);
interrupt_trigger(EPIC_INT_MAX86150);
return 0;
} }
static int max86150_fetch_fifo(void) static int max86150_fetch_fifo(void)
......
...@@ -9,6 +9,7 @@ module_sources = files( ...@@ -9,6 +9,7 @@ module_sources = files(
'gpio.c', 'gpio.c',
'hardware.c', 'hardware.c',
'hw-lock.c', 'hw-lock.c',
'interrupts.c',
'leds.c', 'leds.c',
'lifecycle.c', 'lifecycle.c',
'light_sensor.c', 'light_sensor.c',
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "gpio.h" #include "gpio.h"
#include "modules/mutex.h" #include "modules/mutex.h"
#include "epicardium.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -27,6 +28,15 @@ int hardware_reset(void); ...@@ -27,6 +28,15 @@ int hardware_reset(void);
void vLifecycleTask(void *pvParameters); void vLifecycleTask(void *pvParameters);
void return_to_menu(void); void return_to_menu(void);
/* ---------- Interrupts --------------------------------------------------- */
void interrupt_init(void);
void interrupt_trigger(api_int_id_t id);
void interrupt_trigger_sync(api_int_id_t id);
void interrupt_trigger_unsafe(api_int_id_t id) __attribute__((deprecated(
"interrupt_trigger_unsafe() is racy and only exists for legacy code."
)));
void vInterruptsTask(void *pvParameters);
/* ---------- Serial ------------------------------------------------------- */ /* ---------- Serial ------------------------------------------------------- */
#define SERIAL_READ_BUFFER_SIZE 128 #define SERIAL_READ_BUFFER_SIZE 128
#define SERIAL_WRITE_STREAM_BUFFER_SIZE 512 #define SERIAL_WRITE_STREAM_BUFFER_SIZE 512
......
#include "epicardium.h" #include "epicardium.h"
#include "modules/log.h" #include "modules/log.h"
#include "api/interrupt-sender.h" #include "modules/modules.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
...@@ -84,19 +84,23 @@ void epic_rtc_set_milliseconds(uint64_t milliseconds) ...@@ -84,19 +84,23 @@ void epic_rtc_set_milliseconds(uint64_t milliseconds)
monotonic_offset += diff; monotonic_offset += diff;
} }
/* We need to use interrupt_trigger_unsafe() here */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
void RTC_IRQHandler(void) void RTC_IRQHandler(void)
{ {
int flags = RTC_GetFlags(); int flags = RTC_GetFlags();
if (flags & MXC_F_RTC_CTRL_ALDF) { if (flags & MXC_F_RTC_CTRL_ALDF) {
RTC_ClearFlags(MXC_F_RTC_CTRL_ALDF); RTC_ClearFlags(MXC_F_RTC_CTRL_ALDF);
api_interrupt_trigger(EPIC_INT_RTC_ALARM); interrupt_trigger_unsafe(EPIC_INT_RTC_ALARM);
} else { } else {
LOG_WARN("rtc", "Unknown IRQ caught!"); LOG_WARN("rtc", "Unknown IRQ caught!");
/* Disable IRQ so it does not retrigger */ /* Disable IRQ so it does not retrigger */
NVIC_DisableIRQ(RTC_IRQn); NVIC_DisableIRQ(RTC_IRQn);
} }
} }
#pragma GCC diagnostic pop
int epic_rtc_schedule_alarm(uint32_t timestamp) int epic_rtc_schedule_alarm(uint32_t timestamp)
{ {
...@@ -107,7 +111,7 @@ int epic_rtc_schedule_alarm(uint32_t timestamp) ...@@ -107,7 +111,7 @@ int epic_rtc_schedule_alarm(uint32_t timestamp)
* immediately. * immediately.
*/ */
if (epic_rtc_get_seconds() >= timestamp) { if (epic_rtc_get_seconds() >= timestamp) {
api_interrupt_trigger(EPIC_INT_RTC_ALARM); interrupt_trigger(EPIC_INT_RTC_ALARM);
return 0; return 0;
} }
......
#include "epicardium.h" #include "epicardium.h"
#include "api/interrupt-sender.h"
#include "modules/log.h" #include "modules/log.h"
#include "modules/modules.h" #include "modules/modules.h"
...@@ -280,7 +279,7 @@ void serial_enqueue_char(char chr) ...@@ -280,7 +279,7 @@ void serial_enqueue_char(char chr)
{ {
if (chr == 0x3) { if (chr == 0x3) {
/* Control-C */ /* Control-C */
api_interrupt_trigger(EPIC_INT_CTRL_C); interrupt_trigger(EPIC_INT_CTRL_C);
} }
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) { if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
...@@ -288,7 +287,7 @@ void serial_enqueue_char(char chr) ...@@ -288,7 +287,7 @@ void serial_enqueue_char(char chr)
vTaskDelay(portTICK_PERIOD_MS * 50); vTaskDelay(portTICK_PERIOD_MS * 50);
} }
api_interrupt_trigger(EPIC_INT_UART_RX); interrupt_trigger(EPIC_INT_UART_RX);
} }
void vSerialTask(void *pvParameters) void vSerialTask(void *pvParameters)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment