1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

esp/esp*: move common code to cpu/esp_common

This commit is contained in:
Gunar Schorcht 2019-12-08 18:38:02 +01:00
parent 7d701f6fa8
commit 45c71f1a31
7 changed files with 9 additions and 584 deletions

View File

@ -1,103 +0,0 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief ESP system event handler
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH)
#define ENABLE_DEBUG 0
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "log.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "irq_arch.h"
#define MAX_HANDLER_NUM 5
static system_event_cb_t _handler[MAX_HANDLER_NUM] = {};
static void* _handler_arg[MAX_HANDLER_NUM] = {};
esp_err_t esp_system_event_add_handler (system_event_cb_t handler, void *arg)
{
int i;
/* determine next free handler entry */
for (i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] == NULL) {
break;
}
}
/* return if there is no free entry */
if (i == MAX_HANDLER_NUM) {
return ESP_FAIL;
}
/* set the handler and argument entry */
_handler[i] = handler;
_handler_arg[i] = arg;
return ESP_OK;
}
esp_err_t esp_system_event_del_handler (system_event_cb_t handler)
{
int i;
/* determine the handler entry */
for (i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] == handler) {
break;
}
}
/* return if entry was not found */
if (i == MAX_HANDLER_NUM) {
return ESP_FAIL;
}
/* clean handler and arg entry */
_handler[i] = NULL;
_handler_arg[i] = NULL;
return ESP_OK;
}
static esp_err_t esp_system_event_handler(void *ctx, system_event_t *event)
{
for (int i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] != NULL) {
_handler[i](_handler_arg[i], event);
}
}
return ESP_OK;
}
#endif
void esp_event_handler_init(void)
{
#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH)
esp_event_loop_init(esp_system_event_handler, NULL);
#endif
}

View File

@ -1,394 +0,0 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief Implementation of the kernel's architecture dependent thread interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
/*
* PLEASE NOTE: Some parts of the code are taken from the FreeRTOS port for
* Xtensa processors from Cadence Design Systems. These parts are marked
* accordingly. For these parts, the following license is valid:
*
* Copyright (c) 2003-2015 Cadence Design Systems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "cpu.h"
#include "irq.h"
#include "log.h"
#include "thread.h"
#include "sched.h"
#include "esp_common.h"
#include "irq_arch.h"
#include "syscalls.h"
#include "tools.h"
#include "esp/xtensa_ops.h"
#include "rom/ets_sys.h"
#include "soc/dport_reg.h"
#include "xtensa/xtensa_context.h"
/* User exception dispatcher when exiting */
extern void _xt_user_exit(void);
/* Switch context to the highest priority ready task without context save */
extern void _frxt_dispatch(void);
/* Set an flag indicating that a task switch is required on return from interrupt */
extern void _frxt_setup_switch(void);
/* Switch context to the highest priority ready task with context save */
extern void vPortYield(void);
extern void vPortYieldFromInt(void);
/* forward declarations */
NORETURN void task_exit(void);
char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_start, int stack_size)
{
/* Stack layout after task stack initialization
*
* +------------------------+
* | | TOP
* | thread_control_block |
* stack_start + stack_size ==> | | top_of_stack+1
* +------------------------+
* top_of_stack ==> | |
* | XT_CP_SA |
* | (optional) |
* | ... | ...
* | cpstored | XT_CPSTORED
* top_of_stack + 1 - XT_CP_SIZE ==> | cpenable | XT_CPENABLE
* (cp_state) +------------------------+
* | |
* | XT_STK_FRAME |
* | | XT_STK_...
* | a2 = arg | XT_STK_A2
* | a1 = sp + XT_STK_FRMSZ | XT_STK_A1
* | a0 = sched_task_exit | XT_STK_A0
* | ps = PS_UM | PS_EXCM | XT_STK_PS
* | pc = task_func | XT_STK_PC
* sp = top_of_stack + 1 - XT_CP_SIZE ==> | exit = _xt_user_exit | XT_STK_EXIT
* - XT_STK_FRMSZ +------------------------+
* | |
* | remaining stack space |
* | available for data |
* stack_start (preallocated var) ==> | | BOTTOM
* +------------------------+
*
* Initialized stack frame represents the registers as set when the
* the task function would have been called.
*
* Registers in a called function
*
* pc - PC at the beginning in the function
* a0 - return address from the function (return address to caller)
* a1 - current stack pointer at the beginning in the function
* a2 - first argument of the function
*/
/* stack is [stack_start+0 ... stack_start+stack_size-1] */
uint8_t *top_of_stack;
uint8_t *sp;
top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size - 1);
/* BEGIN - code from FreeRTOS port for Xtensa from Cadence */
/* Create interrupt stack frame aligned to 16 byte boundary */
sp = (uint8_t*)(((uint32_t)(top_of_stack + 1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf);
/* Clear whole stack with a known value to assist debugging */
#if !defined(DEVELHELP) && !defined(SCHED_TEST_STACK)
/* Unfortunately, this affects thread_measure_stack_free function */
memset(stack_start, 0, stack_size);
#else
memset(sp, 0, XT_STK_FRMSZ + XT_CP_SIZE);
#endif
/* ensure that stack is big enough */
assert (sp > (uint8_t*)stack_start);
XtExcFrame* exc_frame = (XtExcFrame*)sp;
/* Explicitly initialize certain saved registers for call0 ABI */
exc_frame->pc = (uint32_t)task_func; /* task entry point */
exc_frame->a0 = (uint32_t)task_exit; /* task exit point*/
exc_frame->a1 = (uint32_t)sp + XT_STK_FRMSZ; /* physical top of stack frame */
exc_frame->exit = (uint32_t)_xt_user_exit; /* user exception exit dispatcher */
/* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
/* Also set entry point argument parameter. */
#ifdef __XTENSA_CALL0_ABI__
/* for CALL0 ABI set in parameter a2 to task argument */
exc_frame->ps = PS_UM | PS_EXCM;
exc_frame->a2 = (uint32_t)arg; /* parameters for task_func */
#else
/* for Windowed Register ABI set PS.CALLINC=01 to handle task entry as
call4 return address in a4 and parameter in a6 and */
exc_frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
exc_frame->a4 = (uint32_t)task_exit; /* task exit point*/
exc_frame->a6 = (uint32_t)arg; /* parameters for task_func */
#endif
#ifdef XT_USE_SWPRI
/* Set the initial virtual priority mask value to all 1's. */
exc_frame->vpri = 0xFFFFFFFF;
#endif
#if XCHAL_CP_NUM > 0
/* Init the coprocessor save area (see xtensa_context.h) */
/* No access to TCB here, so derive indirectly. Stack growth is top to bottom. */
/* p = (uint32_t *) xMPUSettings->coproc_area; */
uint32_t *p;
p = (uint32_t *)(((uint32_t)(top_of_stack + 1) - XT_CP_SIZE));
p[0] = 0;
p[1] = 0;
p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
#endif
/* END - code from FreeRTOS port for Xtensa from Cadence */
DEBUG("%s start=%p size=%d top=%p sp=%p free=%u\n",
__func__, stack_start, stack_size, top_of_stack, sp, sp-(uint8_t*)stack_start);
return (char*)sp;
}
/**
* Context switches are realized using software interrupts since interrupt
* entry and exit functions are the only way to save and restore complete
* context including spilling the register windows to the stack
*/
void IRAM_ATTR thread_yield_isr(void* arg)
{
/* clear the interrupt first */
DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);
/* set the context switch flag (indicates that context has to be switched
is switch on exit from interrupt in _frxt_int_exit */
_frxt_setup_switch();
}
/**
* If we are already in an interrupt handler, the function simply sets the
* context switch flag, which indicates that the context has to be switched
* in the _frxt_int_exit function when exiting the interrupt. Otherwise, we
* will generate a software interrupt to force the context switch when
* terminating the software interrupt (see thread_yield_isr).
*/
void thread_yield_higher(void)
{
/* reset hardware watchdog */
system_wdt_feed();
/* yield next task */
#if defined(ENABLE_DEBUG) && defined(DEVELHELP)
if (sched_active_thread) {
DEBUG("%u old task %u %s %u\n", system_get_time(),
sched_active_thread->pid, sched_active_thread->name,
sched_active_thread->sp - sched_active_thread-> stack_start);
}
#endif
if (!irq_is_in()) {
/* generate the software interrupt to switch the context */
DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0);
}
else {
/* set the context switch flag */
_frxt_setup_switch();
}
#if defined(ENABLE_DEBUG) && defined(DEVELHELP)
if (sched_active_thread) {
DEBUG("%u new task %u %s %u\n", system_get_time(),
sched_active_thread->pid, sched_active_thread->name,
sched_active_thread->sp - sched_active_thread-> stack_start);
}
#endif
/*
* Instruction fetch synchronize: Waits for all previously fetched load,
* store, cache, and special register write instructions that affect
* instruction fetch to be performed before fetching the next instruction.
*/
__asm__("isync");
return;
}
void thread_stack_print(void)
{
/* Print the current stack to stdout. */
#if defined(DEVELHELP)
volatile thread_t* task = thread_get(sched_active_pid);
if (task) {
char* stack_top = task->stack_start + task->stack_size;
int size = stack_top - task->sp;
printf("Printing current stack of thread %" PRIkernel_pid "\n", thread_getpid());
esp_hexdump((void*)(task->sp), size >> 2, 'w', 8);
}
#else
NOT_SUPPORTED();
#endif
}
void thread_print_stack(void)
{
/* Prints human readable, ps-like thread information for debugging purposes. */
/* because of Xtensa stack structure and call ABI, it is not possible to implement */
NOT_YET_IMPLEMENTED();
return;
}
#ifdef DEVELHELP
extern uint8_t port_IntStack;
extern uint8_t port_IntStackTop;
void thread_isr_stack_init(void)
{
/* code from thread.c, please see the copyright notice there */
/* assign each int of the stack the value of it's address */
uintptr_t *stackmax = (uintptr_t *)&port_IntStackTop;
uintptr_t *stackp = (uintptr_t *)&port_IntStack;
while (stackp < stackmax) {
*stackp = (uintptr_t) stackp;
stackp++;
}
}
int thread_isr_stack_usage(void)
{
return &port_IntStackTop - &port_IntStack -
thread_measure_stack_free((char*)&port_IntStack);
}
void *thread_isr_stack_pointer(void)
{
/* Get the current ISR stack pointer. */
return &port_IntStackTop;
}
void *thread_isr_stack_start(void)
{
/* Get the start of the ISR stack. */
return &port_IntStack;
}
void thread_isr_stack_print(void)
{
printf("Printing current ISR\n");
esp_hexdump(&port_IntStack, &port_IntStackTop-&port_IntStack, 'w', 8);
}
#else /* DEVELHELP */
void thread_isr_stack_init(void) {}
#endif /* DEVELHELP */
static bool _initial_exit = true;
/**
* The function is used on task exit to switch to the context to the next
* running task. It realizes only the second half of a complete context by
* simulating the exit from an interrupt handling where a context switch is
* forced. The old context is not saved here since it is no longer needed.
*/
NORETURN void task_exit(void)
{
DEBUG("sched_task_exit: ending thread %" PRIkernel_pid "...\n",
sched_active_thread ? sched_active_thread->pid : KERNEL_PID_UNDEF);
(void) irq_disable();
/* remove old task from scheduling if it is not already done */
if (sched_active_thread) {
sched_threads[sched_active_pid] = NULL;
sched_num_threads--;
sched_set_status((thread_t *)sched_active_thread, STATUS_STOPPED);
sched_active_thread = NULL;
}
/* determine the new running task */
sched_run();
/* set the context switch flag (indicates that context has to be switched
is switch on exit from interrupt in _frxt_int_exit */
_frxt_setup_switch();
/* set interrupt nesting level to the right value */
irq_interrupt_nesting++;
/* reset windowed registers */
__asm__ volatile ("movi a2, 0\n"
"wsr a2, windowstart\n"
"wsr a2, windowbase\n"
"rsync\n");
/* exit from simulated interrupt to switch to the new context */
__asm__ volatile ("call0 _frxt_int_exit");
/* should not be executed */
UNREACHABLE();
}
NORETURN void cpu_switch_context_exit(void)
{
DEBUG("%s\n", __func__);
/* Switch context to the highest priority ready task without context save */
if (_initial_exit) {
_initial_exit = false;
__asm__ volatile ("call0 _frxt_dispatch");
}
else {
task_exit();
}
UNREACHABLE();
}

View File

@ -1,80 +0,0 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief Implementation of some tools
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#include <stdio.h>
#include <malloc.h>
#ifdef MCU_ESP8266
#include <inttypes.h>
#include "sdk/sdk.h"
#else
#include "rom/ets_sys.h"
#endif
#include "esp/common_macros.h"
#include "tools.h"
extern void malloc_stats (void);
extern unsigned int get_free_heap_size (void);
extern uint8_t _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */
extern uint8_t _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */
void print_meminfo (void)
{
struct mallinfo minfo = mallinfo();
ets_printf("heap: %lu (free %lu) byte\n", &_eheap - &_sheap, get_free_heap_size());
ets_printf("sysmem: %d (used %d, free %d)\n", minfo.arena, minfo.uordblks, minfo.fordblks);
}
void esp_hexdump (const void* addr, uint32_t num, char width, uint8_t per_line)
{
uint32_t count = 0;
uint32_t size;
uint8_t* addr8 = (uint8_t*) addr;
uint16_t* addr16 = (uint16_t*)addr;
uint32_t* addr32 = (uint32_t*)addr;
uint64_t* addr64 = (uint64_t*)addr;
switch (width) {
case 'b': size = 1; break;
case 'h': size = 2; break;
case 'w': size = 4; break;
case 'g': size = 8; break;
default : size = 1; break;
}
while (count < num) {
if (count % per_line == 0) {
ets_printf ("%08" PRIx32 ": ", (uint32_t)((uint8_t*)addr+count*size));
}
switch (width) {
case 'b': ets_printf("%02" PRIx8 " ", addr8[count++]); break;
case 'h': ets_printf("%04" PRIx16 " ", addr16[count++]); break;
case 'w': ets_printf("%08" PRIx32 " ", addr32[count++]); break;
case 'g': ets_printf("%016" PRIx64 " ", addr64[count++]); break;
default : ets_printf("."); count++; break;
}
if (count % per_line == 0) {
ets_printf ("\n");
}
}
ets_printf ("\n");
}

View File

@ -7,7 +7,7 @@
*/
/**
* @ingroup cpu_esp8266
* @ingroup cpu_esp_common
* @{
*
* @file

View File

@ -0,0 +1,3 @@
MODULE = esp_common_periph
include $(RIOTMAKE)/periph.mk

View File

@ -7,7 +7,7 @@
*/
/**
* @ingroup cpu_esp8266
* @ingroup cpu_esp_common
* @{
*
* @file
@ -302,7 +302,7 @@ void IRAM_ATTR thread_yield_higher(void)
return;
}
void thread_stack_print(void)
void thread_stack_print(void)
{
/* Print the current stack to stdout. */
@ -320,7 +320,7 @@ void thread_stack_print(void)
#endif
}
void thread_print_stack(void)
void thread_print_stack(void)
{
/* Prints human readable, ps-like thread information for debugging purposes. */
/* because of Xtensa stack structure and call0 ABI, it is not possible to implement */

View File

@ -7,11 +7,11 @@
*/
/**
* @ingroup cpu_esp32
* @ingroup cpu_esp_common
* @{
*
* @file
* @brief Implementation of some tools
* @brief Implementation of some tools for ESP SoCs
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
@ -20,7 +20,6 @@
#include <stdio.h>
#include "esp/common_macros.h"
#include "rom/ets_sys.h"
#include "tools.h"
void esp_hexdump (const void* addr, uint32_t num, char width, uint8_t per_line)