Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • add_menu_vibration
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • dualcore
  • dx/flatten-config-module
  • dx/meh-bdf-to-stm
  • freertos-btle
  • genofire/ble-follow-py
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bluetooth-app-favorite
  • rahix/bma
  • rahix/user-space-ctx
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/212-reset-hardware-when-entering-repl
  • schneider/ancs
  • schneider/ble-buffers
  • schneider/ble-central
  • schneider/ble-ecg-stream-visu
  • schneider/ble-fixes-2020-3
  • schneider/ble-mini-demo
  • schneider/ble-stability
  • schneider/ble-stability-new-phy
  • schneider/bonding
  • schneider/bonding-fail-if-full
  • schneider/bootloader-update-9a0d158
  • schneider/deepsleep
  • schneider/deepsleep2
  • schneider/deepsleep4
  • schneider/default-main
  • schneider/freertos-list-debug
  • schneider/fundamental-test
  • schneider/iaq-python
  • schneider/ir
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-exception-print
  • schneider/mp-for-old-bl
  • schneider/png
  • schneider/schleicher-test
  • schneider/sdk-0.2.1-11
  • schneider/sdk-0.2.1-7
  • schneider/sleep-display
  • schneider/spo2-playground
  • schneider/stream-locks
  • schneider/v1.17-changelog
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.10
  • v1.11
  • v1.12
  • v1.13
  • v1.14
  • v1.15
  • v1.16
  • v1.17
  • v1.18
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
82 results

Target

Select target project
  • card10/firmware
  • annejan/firmware
  • astro/firmware
  • fpletz/firmware
  • gerd/firmware
  • fleur/firmware
  • swym/firmware
  • l/firmware
  • uberardy/firmware
  • wink/firmware
  • madonius/firmware
  • mot/firmware
  • filid/firmware
  • q3k/firmware
  • hauke/firmware
  • Woazboat/firmware
  • pink/firmware
  • mossmann/firmware
  • omniskop/firmware
  • zenox/firmware
  • trilader/firmware
  • Danukeru/firmware
  • shoragan/firmware
  • zlatko/firmware
  • sistason/firmware
  • datenwolf/firmware
  • bene/firmware
  • amedee/firmware
  • martinling/firmware
  • griffon/firmware
  • chris007/firmware
  • adisbladis/firmware
  • dbrgn/firmware
  • jelly/firmware
  • rnestler/firmware
  • mh/firmware
  • ln/firmware
  • penguineer/firmware
  • monkeydom/firmware
  • jens/firmware
  • jnaulty/firmware
  • jeffmakes/firmware
  • marekventur/firmware
  • pete/firmware
  • h2obrain/firmware
  • DooMMasteR/firmware
  • jackie/firmware
  • prof_r/firmware
  • Draradech/firmware
  • Kartoffel/firmware
  • hinerk/firmware
  • abbradar/firmware
  • JustTB/firmware
  • LuKaRo/firmware
  • iggy/firmware
  • ente/firmware
  • flgr/firmware
  • Lorphos/firmware
  • matejo/firmware
  • ceddral7/firmware
  • danb/firmware
  • joshi/firmware
  • melle/firmware
  • fitch/firmware
  • deurknop/firmware
  • sargon/firmware
  • markus/firmware
  • kloenk/firmware
  • lucaswerkmeister/firmware
  • derf/firmware
  • meh/firmware
  • dx/card10-firmware
  • torben/firmware
  • yuvadm/firmware
  • AndyBS/firmware
  • klausdieter1/firmware
  • katzenparadoxon/firmware
  • xiretza/firmware
  • ole/firmware
  • techy/firmware
  • thor77/firmware
  • TilCreator/firmware
  • fuchsi/firmware
  • dos/firmware
  • yrlf/firmware
  • PetePriority/firmware
  • SuperVirus/firmware
  • sur5r/firmware
  • tazz/firmware
  • Alienmaster/firmware
  • flo_h/firmware
  • baldo/firmware
  • mmu_man/firmware
  • Foaly/firmware
  • sodoku/firmware
  • Guinness/firmware
  • ssp/firmware
  • led02/firmware
  • Stormwind/firmware
  • arist/firmware
  • coon/firmware
  • mdik/firmware
  • pippin/firmware
  • royrobotiks/firmware
  • zigot83/firmware
  • mo_k/firmware
106 results
Select Git revision
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • drawcall_clipping
  • dualcore
  • faulty_unsigned_comparisons
  • freertos-btle
  • fuchsi-ecg-app
  • genofire/ble-follow-py
  • genofire/haule-ble-fs-deactive
  • genofire/leds_rgb_get_state
  • genofire/rockets-state
  • gpio_in_adc_fix
  • ios-workarounds
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/gfx_rle
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bma
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/ble-buffers
  • schneider/bonding
  • schneider/bootloader-update-9a0d158
  • schneider/bsec
  • schneider/fundamental-test
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-for-old-bl
  • schneider/schleicher-test
  • schneider/stream-locks
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
55 results
Show changes
Showing
with 670 additions and 60 deletions
#pragma once
#include "epicardium.h"
/* ---------- 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);
#include "epicardium.h"
#include "os/core.h"
#include "modules/modules.h"
#include "os/config.h"
#include "os/mutex.h"
#include "user_core/user_core.h"
#include "api/dispatcher.h"
#include "l0der/l0der.h"
#include "card10.h"
#include "FreeRTOS.h"
#include "task.h"
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdbool.h>
#define PYCARDIUM_IVT (void *)0x100a0000
#define BLOCK_WAIT pdMS_TO_TICKS(1000)
/*
* Loading an empty filename into Pycardium will drop straight into the
* interpreter. This define is used to make it more clear when we intend
* to go into the interpreter.
*/
#define PYINTERPRETER ""
static TaskHandle_t lifecycle_task = NULL;
static struct mutex core1_mutex = { 0 };
enum payload_type {
PL_INVALID = 0,
PL_PYTHON_SCRIPT = 1,
PL_PYTHON_DIR = 2,
PL_PYTHON_INTERP = 3,
PL_L0DABLE = 4,
};
struct load_info {
bool do_reset;
enum payload_type type;
char name[256];
};
static volatile struct load_info async_load = {
.do_reset = false,
.name = { 0 },
.type = PL_INVALID,
};
/* Whether to write the menu script before attempting to load. */
static volatile bool write_menu = false;
static bool execute_elfs = false;
/* Helpers {{{ */
/*
* Check if the payload is a valid file (or module) and if so, return its type.
*/
static int load_stat(char *name)
{
size_t name_len = strlen(name);
if (name_len == 0) {
return PL_PYTHON_INTERP;
}
struct epic_stat stat;
if (epic_file_stat(name, &stat) < 0) {
return -ENOENT;
}
if (stat.type == EPICSTAT_DIR) {
/* This might be a python module. */
return PL_PYTHON_DIR;
}
if (strcmp(name + name_len - 3, ".py") == 0) {
/* A python script */
return PL_PYTHON_SCRIPT;
} else if (strcmp(name + name_len - 4, ".elf") == 0) {
return PL_L0DABLE;
}
return -ENOEXEC;
}
/*
* Actually load a payload into core 1. Optionally reset the core first.
*/
static int do_load(struct load_info *info)
{
struct l0dable_info l0dable;
int res;
/* Callers of do_load() must first lock the core1_mutex. */
mutex_assert_locked(&core1_mutex);
if (*info->name == '\0') {
LOG_INFO("lifecycle", "Loading Python interpreter ...");
} else {
LOG_INFO("lifecycle", "Loading \"%s\" ...", info->name);
}
if (info->type == PL_L0DABLE && !execute_elfs) {
LOG_WARN(
"lifecycle", "Execution of .elf l0dables is disabled."
);
return -EPERM;
}
/* Signal the dispatcher to return early from applicable API calls. */
xTaskNotifyGive(dispatcher_task_id);
mutex_lock(&api_mutex);
if (info->do_reset) {
LOG_DEBUG("lifecycle", "Triggering core 1 reset.");
core1_trigger_reset();
}
/*
* Wait for the core to become ready to accept a new payload.
*
* If it is not yet ready, hand back control of the API mutex to the
* dispatcher so it can finish dispatching a current API call. This is
* necessary for payloads which have interrupts disabled during an API
* call.
*/
while (!core1_is_ready()) {
/*
* Wake up the dispatcher task prematurely. This is needed so
* the second xTaskNotifyGive() below can then break out the
* dispatcher from e.g. an epic_sleep() call.
*/
xTaskNotifyGive(dispatcher_task_id);
mutex_unlock(&api_mutex);
/* Sleep so the dispatcher task can take the lock. */
vTaskDelay(8);
/* Signal the dispatcher to return early from applicable API calls. */
xTaskNotifyGive(dispatcher_task_id);
mutex_lock(&api_mutex);
}
/*
* Reinitialize Hardware & Drivers
*/
res = hardware_reset();
if (res < 0) {
goto out_free_api;
}
switch (info->type) {
case PL_PYTHON_SCRIPT:
case PL_PYTHON_DIR:
case PL_PYTHON_INTERP:
core1_load(PYCARDIUM_IVT, info->name);
break;
case PL_L0DABLE:
assert(execute_elfs);
res = l0der_load_path(info->name, &l0dable);
if (res != 0) {
LOG_ERR("lifecycle", "l0der failed: %d\n", res);
res = -ENOEXEC;
goto out_free_api;
}
core1_load(l0dable.isr_vector, "");
break;
default:
LOG_ERR("lifecyle",
"Attempted to load invalid payload (%s)",
info->name);
res = -EINVAL;
goto out_free_api;
}
res = 0;
out_free_api:
mutex_unlock(&api_mutex);
return res;
}
/*
* Do a synchroneous load.
*/
static int load_sync(char *name, bool reset)
{
/* Callers of load_sync() must first lock the core1_mutex. */
mutex_assert_locked(&core1_mutex);
int ret = load_stat(name);
if (ret < 0) {
return ret;
}
struct load_info info = {
.name = { 0 },
.type = ret,
.do_reset = reset,
};
strncpy(info.name, name, sizeof(info.name));
return do_load(&info);
}
/*
* Do an asynchroneous load. This will return immediately if the payload seems
* valid and call the lifecycle task to actually perform the load later.
*/
static int load_async(char *name, bool reset)
{
/* Callers of load_async() must first lock the core1_mutex. */
mutex_assert_locked(&core1_mutex);
int ret = load_stat(name);
if (ret < 0) {
return ret;
}
async_load.type = ret;
async_load.do_reset = reset;
strncpy((char *)async_load.name, name, sizeof(async_load.name));
if (lifecycle_task != NULL) {
xTaskNotifyGive(lifecycle_task);
}
return 0;
}
/*
* Epicardium contains an embedded default menu script which it writes to
* external flash if none is found there. This way, you won't make your card10
* unusable by accidentally removing the menu script.
*
* You can find the sources for the menu-script in `preload/menu.py`.
*/
/*
* Embed the menu.py script in the Epicardium binary.
*/
__asm(".section \".rodata\"\n"
"_menu_script_start:\n"
".incbin \"../preload/menu.py\"\n"
"_menu_script_end:\n"
".previous\n");
extern const uint8_t _menu_script_start;
extern const uint8_t _menu_script_end;
static int write_default_menu(void)
{
const size_t length =
(uintptr_t)&_menu_script_end - (uintptr_t)&_menu_script_start;
int ret;
LOG_INFO("lifecycle", "Writing default menu ...");
int fd = epic_file_open("menu.py", "w");
if (fd < 0) {
return fd;
}
ret = epic_file_write(fd, &_menu_script_start, length);
if (ret < 0) {
return ret;
}
ret = epic_file_close(fd);
if (ret < 0) {
return ret;
}
return 0;
}
/*
* Go back to the menu.
*/
static void load_menu(bool reset)
{
LOG_DEBUG("lifecycle", "Into the menu");
mutex_lock(&core1_mutex);
int ret = load_async("menu.py", reset);
if (ret < 0) {
LOG_WARN("lifecycle", "No menu script found.");
/* The lifecycle task will perform the write */
write_menu = true;
async_load.type = PL_PYTHON_SCRIPT;
async_load.do_reset = reset;
strncpy((char *)async_load.name,
"menu.py",
sizeof(async_load.name));
if (lifecycle_task != NULL) {
xTaskNotifyGive(lifecycle_task);
}
}
mutex_unlock(&core1_mutex);
}
/* Helpers }}} */
/* API {{{ */
/*
* Restart the firmware
*/
void epic_system_reset(void)
{
card10_reset();
}
/*
* This is NOT the epic_exec() called from Pycardium, but an implementation of
* the same call for use in Epicardium. This function is synchroneous and will
* wait until the call returns.
*/
int epic_exec(char *name)
{
mutex_lock(&core1_mutex);
int ret = load_sync(name, true);
mutex_unlock(&core1_mutex);
return ret;
}
/*
* This is the underlying call for epic_exec() from Pycardium. It is
* asynchroneous and will return early to allow Pycardium (or a l0dable) to jump
* to the reset handler.
*
* The lifecycle task will deal with actually loading the new payload.
*/
int __epic_exec(char *name)
{
mutex_lock(&core1_mutex);
int ret = load_async(name, false);
mutex_unlock(&core1_mutex);
return ret;
}
/*
* This is the underlying call for epic_exit() from Pycardium. It is
* asynchroneous and will return early to allow Pycardium (or a l0dable) to jump
* to the reset handler.
*
* The lifecycle task will deal with actually loading the new payload.
*/
void __epic_exit(int ret)
{
if (ret == 0) {
LOG_INFO("lifecycle", "Payload returned successfully");
} else {
LOG_WARN("lifecycle", "Payload returned with %d.", ret);
}
load_menu(false);
}
/*
* This function can be used in Epicardium to jump back to the menu.
*
* It is asynchroneous and will return immediately. The lifecycle task will
* take care of actually jumping back.
*/
void return_to_menu(void)
{
load_menu(true);
}
/* API }}} */
void vLifecycleTask(void *pvParameters)
{
lifecycle_task = xTaskGetCurrentTaskHandle();
mutex_create(&core1_mutex);
mutex_lock(&core1_mutex);
LOG_DEBUG("lifecycle", "Booting core 1 ...");
core1_boot();
vTaskDelay(pdMS_TO_TICKS(10));
mutex_unlock(&core1_mutex);
/*
* If `main.py` exists, start it. Otherwise, start `menu.py`.
*
* 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();
execute_elfs = config_get_boolean_with_default("execute_elf", false);
/* When triggered, reset core 1 to menu */
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
mutex_lock(&core1_mutex);
if (write_menu) {
write_menu = false;
int ret = write_default_menu();
if (ret < 0) {
LOG_ERR("lifecycle",
"Failed to write default menu: %d",
ret);
load_async(PYINTERPRETER, "");
ulTaskNotifyTake(pdTRUE, 0);
}
}
ret = do_load((struct load_info *)&async_load);
mutex_unlock(&core1_mutex);
if (ret < 0) {
LOG_ERR("lifecycle", "Error loading payload: %d", ret);
return_to_menu();
}
}
}
user_core_sources = files(
'dispatcher.c',
'interrupts.c',
'lifecycle.c',
'migration.c',
)
#include "epicardium.h"
#include "os/core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void migration_delete_app_launchers(void)
{
int fd = epic_file_opendir("/");
struct epic_stat entry;
for (;;) {
epic_file_readdir(fd, &entry);
if (entry.type == EPICSTAT_NONE) {
// End
break;
}
const char *dot = strrchr(entry.name, '.');
if (dot && !strcmp(dot, ".py")) {
const char launcher[] = "# Launcher script for ";
char launcher_buf[strlen(launcher)];
int fd = epic_file_open(entry.name, "r");
if (fd >= 0) {
int n = epic_file_read(
fd, launcher_buf, sizeof(launcher_buf)
);
epic_file_close(fd);
if (n == (int)sizeof(launcher_buf) &&
!memcmp(launcher,
launcher_buf,
sizeof(launcher_buf))) {
LOG_INFO(
"migration",
"Delete old launcher %s",
entry.name
);
epic_file_unlink(entry.name);
}
}
}
}
epic_file_close(fd);
}
#pragma once
#include "FreeRTOS.h"
#include "os/mutex.h"
/* ---------- Dispatcher --------------------------------------------------- */
void vApiDispatcher(void *pvParameters);
void dispatcher_mutex_init(void);
extern struct mutex api_mutex;
extern TaskHandle_t dispatcher_task_id;
/* ---------- Lifecycle ---------------------------------------------------- */
void vLifecycleTask(void *pvParameters);
void return_to_menu(void);
/* ---------- Migration ---------------------------------------------------- */
void migration_delete_app_launchers(void);
epicardium/version-splash.png

15 KiB

source init.gdb
set confirm off
mon max32xxx mass_erase 0
mon max32xxx mass_erase 1
echo #### BOOTLOADER ####\n
load build/bootloader/bootloader.elf
echo #### EPICARDIUM ####\n
load build/epicardium/epicardium.elf
echo #### PYCARDIUM ####\n
load build/pycardium/pycardium.elf
reset
quit
source init.gdb
set confirm off
echo #### BOOTLOADER ####\n
load build/bootloader/bootloader.elf
reset
quit
source init.gdb
set confirm off
echo #### EPICARDIUM ####\n
load build/epicardium/epicardium.elf
echo #### PYCARDIUM ####\n
load build/pycardium/pycardium.elf
reset
quit
source init.gdb
set confirm off
echo #### EPICARDIUM ####\n
load build/epicardium/epicardium.elf
reset
quit
source init.gdb
set confirm off
echo #### PYCARDIUM ####\n
load build/pycardium/pycardium.elf
reset
quit
......@@ -3,27 +3,33 @@
******************************************************************************/
/***** Includes *****/
#include "pmic.h"
#include "leds.h"
#include "card10.h"
#include "leds.h"
#include "pmic.h"
#include "gfx.h"
#include "display.h"
#include "gfx.h"
#include "tmr_utils.h"
#include <stdio.h>
#include <Heart.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <Heart.h>
int main(void)
{
card10_init();
card10_diag();
gfx_copy_region_raw(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart)
gfx_copy_region(
&display_screen,
0,
0,
160,
80,
GFX_RGB565,
(const void *)(Heart)
);
gfx_update(&display_screen);
......
......@@ -401,11 +401,11 @@ int main(void)
uint32_t ecgFIFO, readECGSamples, idx, ETAG[32], status;
int16_t ecgSample[32];
const int EINT_STATUS_MASK = 1 << 23;
const int FIFO_OVF_MASK = 0x7;
const int FIFO_VALID_SAMPLE_MASK = 0x0;
const int FIFO_FAST_SAMPLE_MASK = 0x1;
const int ETAG_BITS_MASK = 0x7;
const uint32_t EINT_STATUS_MASK = 1 << 23;
const uint32_t FIFO_OVF_MASK = 0x7;
const uint32_t FIFO_VALID_SAMPLE_MASK = 0x0;
const uint32_t FIFO_FAST_SAMPLE_MASK = 0x1;
const uint32_t ETAG_BITS_MASK = 0x7;
while (1) {
#if 1
......
......@@ -30,8 +30,14 @@ int main(void)
card10_init();
card10_diag();
gfx_copy_region_raw(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart)
gfx_copy_region(
&display_screen,
0,
0,
160,
80,
GFX_RGB565,
(const void *)(Heart)
);
gfx_update(&display_screen);
......
......@@ -37,22 +37,22 @@ int main(void)
gfx_line(&display_screen, 100, 10, 70, 40, 2, yellow);
gfx_circle(&display_screen, 85, 25, 22, 2, green);
gfx_copy_region_raw(
gfx_copy_region(
&display_screen,
120,
0,
40,
40,
2,
GFX_RGB565,
(const void *)(gImage_40X40)
);
gfx_copy_region_raw(
gfx_copy_region(
&display_screen,
0,
0,
160,
80,
2,
GFX_RGB565,
(const void *)(gImage_160X80)
);
gfx_update(&display_screen);
......
......@@ -3,3 +3,33 @@ target remote localhost:3333
define reset
mon mww 0x40000004 0x80000000
end
# usage: task_backtrace <tskTCB*>
define task_backtrace
set $taskbt_task_ptr = $arg0
set $taskbt_stack_ptr = $taskbt_task_ptr->pxTopOfStack
set $taskbt_frame_offset = 9
if ((*(uint32_t*)($taskbt_stack_ptr + 8)) & 0x10 == 0)
echo FPU is on\n
set $taskbt_frame_offset += 16
else
echo FPU is off\n
end
set $taskbt_reg_lr = $lr
set $taskbt_reg_pc = $pc
set $taskbt_reg_sp = $sp
set $lr = *($taskbt_stack_ptr + $taskbt_frame_offset + 5)
set $pc = *($taskbt_stack_ptr + $taskbt_frame_offset + 6)
set $sp = $taskbt_stack_ptr + $taskbt_frame_offset + 8
bt
set $lr = $taskbt_reg_lr
set $pc = $taskbt_reg_pc
set $sp = $taskbt_reg_sp
end
alias tbt = task_backtrace
#include "epicardium.h"
#include <math.h>
#include <stdio.h>
int levels[11] = { 0 };
int levels_display[11] = { 0 };
// From https://learn.adafruit.com/led-tricks-gamma-correction/the-quick-fix
const uint8_t gamma8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7,
7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11,
11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17,
18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35,
35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 66, 67, 68, 69, 70, 72, 73, 74, 75, 77, 78,
79, 81, 82, 83, 85, 86, 87, 89, 90, 92, 93, 95, 96, 98,
99, 101, 102, 104, 105, 107, 109, 110, 112, 114, 115, 117, 119, 120,
122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142, 144, 146,
148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208,
210, 213, 215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244,
247, 249, 252, 255
};
void fade()
{
for (int i = 0; i < 11; i++) {
int level = gamma8[levels[i]];
int level = levels[i];
if (levels_display[i] > 0) {
epic_leds_set(i, level, 0, 0);
if (level == 0) {
......@@ -46,9 +24,16 @@ void fade()
/*
* main() is called when l0dable is loaded and executed.
*
* When main() returns, card10 goes back to the menu. A non-zero return value
* can be used to signal some kind of failure during l0dable execution.
*/
int main(void)
{
printf("Hello from blinky!\n");
epic_leds_dim_top(6);
// l0dables are running on a separate, exclusive-to-l0dables core.
// Busy-waiting will not block the main operating system on core0 from
// running - but it will drain batteries.
......
......@@ -20,8 +20,8 @@
* are backed by weak referenced symbols, which you can override just
* by defining them in C code.
*/
.section .data
.align 2
.section .text.isr_vector
.align 7
.globl __isr_vector
__isr_vector:
.long 0 /* Top of Stack, overriden by l0der at load time */
......@@ -157,12 +157,9 @@ Reset_Handler:
ldr r0, =main
blx r0
/*
* C code done, spin forever.
* TODO(q3k): let epicardium know we're done.
*/
.spin:
bl .spin
/* C code done, return to menu. Return code is what main() returned. */
ldr r4, =epic_exit
blx r4
/*
* Used by __libc_init_array.
......@@ -190,15 +187,6 @@ DefaultHandler:
/*
* Declare all default ISRs.
*/
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler MemManage_Handler
def_irq_handler BusFault_Handler
def_irq_handler UsageFault_Handler
def_irq_handler SVC_Handler
def_irq_handler DebugMon_Handler
def_irq_handler PendSV_Handler
def_irq_handler PF_IRQHandler
def_irq_handler WDT0_IRQHandler
def_irq_handler RTC_IRQHandler
......
......@@ -128,3 +128,25 @@ uint32_t _sbrk(int incr)
brk += incr;
return (uint32_t)prev_brk;
}
void HardFault_Handler(void)
{
/*
* We pray that we're not currently in an API call and attempt
* returning. This is okay because a HardFault during an API call is
* extremely unlikely.
*
* In the future, we could improve this by "finishing" an ongoing API
* call before firing epic_exit().
*/
epic_exit(255);
}
/* Alias all other exception handlers to the HardFault_Handler. */
void NMI_Handler(void) __attribute__((alias("HardFault_Handler")));
void MemManage_Handler(void) __attribute__((alias("HardFault_Handler")));
void BusFault_Handler(void) __attribute__((alias("HardFault_Handler")));
void UsageFault_Handler(void) __attribute__((alias("HardFault_Handler")));
void SVC_Handler(void) __attribute__((alias("HardFault_Handler")));
void DebugMon_Handler(void) __attribute__((alias("HardFault_Handler")));
void PendSV_Handler(void) __attribute__((alias("HardFault_Handler")));
......@@ -33,6 +33,9 @@ SECTIONS {
.text :
{
/* The vector table needs 128 byte alignment */
. = ALIGN(128);
KEEP(*(.text.isr_vector))
*(.text*)
*(.rodata*)
......