kopia lustrzana https://github.com/micropython/micropython
ports/mimxrt: Add thread support.
Signed-off-by: tonyzhangnxp <tony.zhang@nxp.com>pull/13755/head
rodzic
31e131bd71
commit
d092ee8480
|
@ -215,6 +215,10 @@ SRC_C += \
|
||||||
systick.c \
|
systick.c \
|
||||||
ticks.c \
|
ticks.c \
|
||||||
tusb_port.c \
|
tusb_port.c \
|
||||||
|
mpthreadport.c \
|
||||||
|
pybthread.c\
|
||||||
|
gccollect.c\
|
||||||
|
|
||||||
|
|
||||||
SHARED_SRC_C += \
|
SHARED_SRC_C += \
|
||||||
shared/libc/printf.c \
|
shared/libc/printf.c \
|
||||||
|
|
|
@ -8,3 +8,5 @@ MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB
|
||||||
MICROPY_PY_NETWORK_NINAW10 ?= 1
|
MICROPY_PY_NETWORK_NINAW10 ?= 1
|
||||||
MICROPY_PY_SSL ?= 1
|
MICROPY_PY_SSL ?= 1
|
||||||
MICROPY_SSL_MBEDTLS ?= 1
|
MICROPY_SSL_MBEDTLS ?= 1
|
||||||
|
|
||||||
|
CFLAGS += -DMICROPY_PY_THREAD=0
|
|
@ -14,6 +14,8 @@ else
|
||||||
JLINK_CONNECTION_SETTINGS = -USB
|
JLINK_CONNECTION_SETTINGS = -USB
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
CFLAGS += -DMICROPY_PY_THREAD=0
|
||||||
|
|
||||||
deploy_jlink: $(BUILD)/firmware.hex
|
deploy_jlink: $(BUILD)/firmware.hex
|
||||||
$(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT)
|
$(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT)
|
||||||
$(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT)
|
$(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT)
|
||||||
|
|
|
@ -6,3 +6,5 @@ MICROPY_HW_FLASH_TYPE = qspi_nor_flash
|
||||||
MICROPY_HW_FLASH_SIZE = 0x1000000 # 16MB
|
MICROPY_HW_FLASH_SIZE = 0x1000000 # 16MB
|
||||||
|
|
||||||
MICROPY_BOOT_BUFFER_SIZE = (32 * 1024)
|
MICROPY_BOOT_BUFFER_SIZE = (32 * 1024)
|
||||||
|
|
||||||
|
CFLAGS += -DMICROPY_PY_THREAD=0
|
|
@ -3,11 +3,14 @@
|
||||||
|
|
||||||
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1070evk"
|
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1070evk"
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
#else
|
||||||
#define MICROPY_EVENT_POLL_HOOK \
|
#define MICROPY_EVENT_POLL_HOOK \
|
||||||
do { \
|
do { \
|
||||||
extern void mp_handle_pending(bool); \
|
extern void mp_handle_pending(bool); \
|
||||||
mp_handle_pending(true); \
|
mp_handle_pending(true); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// MIMXRT1170_EVK has 2 user LEDs
|
// MIMXRT1170_EVK has 2 user LEDs
|
||||||
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_04)
|
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_04)
|
||||||
|
|
|
@ -14,6 +14,8 @@ MICROPY_PY_LWIP = 1
|
||||||
MICROPY_PY_SSL = 1
|
MICROPY_PY_SSL = 1
|
||||||
MICROPY_SSL_MBEDTLS = 1
|
MICROPY_SSL_MBEDTLS = 1
|
||||||
|
|
||||||
|
CFLAGS += -DMICROPY_PY_THREAD=1
|
||||||
|
|
||||||
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
|
||||||
|
|
||||||
CFLAGS += -DCPU_MIMXRT1176DVMAA_cm7 \
|
CFLAGS += -DCPU_MIMXRT1176DVMAA_cm7 \
|
||||||
|
|
|
@ -7,6 +7,7 @@ MICROPY_HW_FLASH_SIZE = 0x200000 # 2MB
|
||||||
MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB
|
MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB
|
||||||
|
|
||||||
CFLAGS += -DMICROPY_HW_FLASH_DQS=kFlexSPIReadSampleClk_LoopbackInternally
|
CFLAGS += -DMICROPY_HW_FLASH_DQS=kFlexSPIReadSampleClk_LoopbackInternally
|
||||||
|
CFLAGS += -DMICROPY_PY_THREAD=0
|
||||||
|
|
||||||
SRC_C += \
|
SRC_C += \
|
||||||
hal/flexspi_nor_flash.c \
|
hal/flexspi_nor_flash.c \
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, 2014 Damien P. George
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/gc.h"
|
||||||
|
#include "py/mpthread.h"
|
||||||
|
#include "shared/runtime/gchelper.h"
|
||||||
|
#include "shared/runtime/softtimer.h"
|
||||||
|
#include "gccollect.h"
|
||||||
|
|
||||||
|
void gc_collect(void) {
|
||||||
|
// start the GC
|
||||||
|
gc_collect_start();
|
||||||
|
|
||||||
|
// trace the stack and registers
|
||||||
|
gc_helper_collect_regs_and_stack();
|
||||||
|
|
||||||
|
// trace root pointers from any threads
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
mp_thread_gc_others();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// trace soft timer nodes
|
||||||
|
soft_timer_gc_mark_all();
|
||||||
|
|
||||||
|
// end the GC
|
||||||
|
gc_collect_end();
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, 2014 Damien P. George
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_STM32_GCCOLLECT_H
|
||||||
|
#define MICROPY_INCLUDED_STM32_GCCOLLECT_H
|
||||||
|
|
||||||
|
// variables defining memory layout
|
||||||
|
// (these probably belong somewhere else...)
|
||||||
|
extern uint32_t _etext;
|
||||||
|
extern uint32_t _sidata;
|
||||||
|
extern uint32_t _ram_start;
|
||||||
|
extern uint32_t _sdata;
|
||||||
|
extern uint32_t _edata;
|
||||||
|
extern uint32_t _sbss;
|
||||||
|
extern uint32_t _ebss;
|
||||||
|
extern uint32_t _heap_start;
|
||||||
|
extern uint32_t _heap_end;
|
||||||
|
extern uint32_t _sstack;
|
||||||
|
extern uint32_t _estack;
|
||||||
|
extern uint32_t _ram_end;
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_STM32_GCCOLLECT_H
|
|
@ -56,6 +56,10 @@
|
||||||
#include "systick.h"
|
#include "systick.h"
|
||||||
#include "extmod/modnetwork.h"
|
#include "extmod/modnetwork.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
static pyb_thread_t pyb_thread_main;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end;
|
extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end;
|
||||||
|
|
||||||
void board_init(void);
|
void board_init(void);
|
||||||
|
@ -64,7 +68,9 @@ int main(void) {
|
||||||
board_init();
|
board_init();
|
||||||
ticks_init();
|
ticks_init();
|
||||||
pendsv_init();
|
pendsv_init();
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
pyb_thread_init(&pyb_thread_main);
|
||||||
|
#endif
|
||||||
#if MICROPY_PY_LWIP
|
#if MICROPY_PY_LWIP
|
||||||
// lwIP doesn't allow to reinitialise itself by subsequent calls to this function
|
// lwIP doesn't allow to reinitialise itself by subsequent calls to this function
|
||||||
// because the system timeout list (next_timeout) is only ever reset by BSS clearing.
|
// because the system timeout list (next_timeout) is only ever reset by BSS clearing.
|
||||||
|
@ -96,6 +102,11 @@ int main(void) {
|
||||||
led_init();
|
led_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Python threading init
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
mp_thread_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
mp_stack_set_top(&_estack);
|
mp_stack_set_top(&_estack);
|
||||||
mp_stack_set_limit(&_estack - &_sstack - 1024);
|
mp_stack_set_limit(&_estack - &_sstack - 1024);
|
||||||
|
|
||||||
|
@ -163,12 +174,6 @@ int main(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc_collect(void) {
|
|
||||||
gc_collect_start();
|
|
||||||
gc_helper_collect_regs_and_stack();
|
|
||||||
gc_collect_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nlr_jump_fail(void *val) {
|
void nlr_jump_fail(void *val) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,11 @@ uint32_t trng_random_u32(void);
|
||||||
#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL)
|
#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL)
|
||||||
// #define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL)
|
// #define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL)
|
||||||
|
|
||||||
|
#ifndef MICROPY_PY_THREAD
|
||||||
|
#define MICROPY_PY_THREAD (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
|
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
|
||||||
#endif
|
#endif
|
||||||
|
@ -182,6 +187,24 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type;
|
||||||
|
|
||||||
#define MP_STATE_PORT MP_STATE_VM
|
#define MP_STATE_PORT MP_STATE_VM
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
|
||||||
|
#define MICROPY_EVENT_POLL_HOOK \
|
||||||
|
do { \
|
||||||
|
extern void mp_handle_pending(bool); \
|
||||||
|
mp_handle_pending(true); \
|
||||||
|
if (pyb_thread_enabled) { \
|
||||||
|
MP_THREAD_GIL_EXIT(); \
|
||||||
|
pyb_thread_yield(); \
|
||||||
|
MP_THREAD_GIL_ENTER(); \
|
||||||
|
} else { \
|
||||||
|
__WFE(); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define MICROPY_THREAD_YIELD() pyb_thread_yield()
|
||||||
|
|
||||||
|
#else
|
||||||
// Miscellaneous settings
|
// Miscellaneous settings
|
||||||
#ifndef MICROPY_EVENT_POLL_HOOK
|
#ifndef MICROPY_EVENT_POLL_HOOK
|
||||||
#define MICROPY_EVENT_POLL_HOOK \
|
#define MICROPY_EVENT_POLL_HOOK \
|
||||||
|
@ -192,6 +215,10 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type;
|
||||||
} while (0);
|
} while (0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MICROPY_THREAD_YIELD()
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
|
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
|
||||||
|
|
||||||
#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) \
|
#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) \
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "fsl_snvs_lp.h"
|
#include "fsl_snvs_lp.h"
|
||||||
|
#include "led.h"
|
||||||
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
|
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
|
||||||
#define MICROPY_HW_STDIN_BUFFER_LEN 512
|
#define MICROPY_HW_STDIN_BUFFER_LEN 512
|
||||||
#endif
|
#endif
|
||||||
|
@ -112,6 +112,24 @@ int mp_hal_stdin_rx_chr(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NORETURN void boardctrl_fatal_error(const char *msg) {
|
||||||
|
for (volatile uint delay = 0; delay < 10000000; delay++) {
|
||||||
|
}
|
||||||
|
led_state(1, 1);
|
||||||
|
|
||||||
|
mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14);
|
||||||
|
mp_hal_stdout_tx_strn(msg, strlen(msg));
|
||||||
|
for (uint i = 0;;) {
|
||||||
|
led_toggle(1);
|
||||||
|
for (volatile uint delay = 0; delay < 10000000; delay++) {
|
||||||
|
}
|
||||||
|
if (i >= 16) {
|
||||||
|
// to conserve power
|
||||||
|
__WFI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
|
mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
|
||||||
mp_uint_t ret = len;
|
mp_uint_t ret = len;
|
||||||
bool did_write = false;
|
bool did_write = false;
|
||||||
|
|
|
@ -154,5 +154,5 @@ void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
|
||||||
void mp_hal_get_mac(int idx, uint8_t buf[6]);
|
void mp_hal_get_mac(int idx, uint8_t buf[6]);
|
||||||
void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
|
void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
|
||||||
void mp_hal_get_unique_id(uint8_t id[]);
|
void mp_hal_get_unique_id(uint8_t id[]);
|
||||||
|
NORETURN void boardctrl_fatal_error(const char *msg);
|
||||||
#endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H
|
#endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Damien P. George
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "py/gc.h"
|
||||||
|
#include "py/mpthread.h"
|
||||||
|
#include "gccollect.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
|
||||||
|
// the mutex controls access to the linked list
|
||||||
|
static mp_thread_mutex_t thread_mutex;
|
||||||
|
|
||||||
|
void mp_thread_init(void) {
|
||||||
|
mp_thread_mutex_init(&thread_mutex);
|
||||||
|
mp_thread_set_state(&mp_state_ctx.thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_thread_gc_others(void) {
|
||||||
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||||
|
for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) {
|
||||||
|
gc_collect_root((void **)&th, 1);
|
||||||
|
gc_collect_root(&th->arg, 1);
|
||||||
|
gc_collect_root(&th->stack, 1);
|
||||||
|
if (th != pyb_thread_cur) {
|
||||||
|
gc_collect_root(th->stack, th->stack_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mp_thread_mutex_unlock(&thread_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_uint_t mp_thread_get_id(void) {
|
||||||
|
return (uint32_t)pyb_thread_cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) {
|
||||||
|
if (*stack_size == 0) {
|
||||||
|
*stack_size = 4096; // default stack size
|
||||||
|
} else if (*stack_size < 2048) {
|
||||||
|
*stack_size = 2048; // minimum stack size
|
||||||
|
}
|
||||||
|
|
||||||
|
// round stack size to a multiple of the word size
|
||||||
|
size_t stack_len = *stack_size / sizeof(uint32_t);
|
||||||
|
*stack_size = stack_len * sizeof(uint32_t);
|
||||||
|
|
||||||
|
// allocate stack and linked-list node (must be done outside thread_mutex lock)
|
||||||
|
uint32_t *stack = m_new(uint32_t, stack_len);
|
||||||
|
pyb_thread_t *th = m_new_obj(pyb_thread_t);
|
||||||
|
|
||||||
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||||
|
|
||||||
|
// create thread
|
||||||
|
uint32_t id = pyb_thread_new(th, stack, stack_len, entry, arg);
|
||||||
|
if (id == 0) {
|
||||||
|
mp_thread_mutex_unlock(&thread_mutex);
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't create thread"));
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_thread_mutex_unlock(&thread_mutex);
|
||||||
|
|
||||||
|
// adjust stack_size to provide room to recover from hitting the limit
|
||||||
|
*stack_size -= 1024;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_thread_start(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_thread_finish(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_THREAD
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Damien P. George
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/mpthread.h"
|
||||||
|
#include "pybthread.h"
|
||||||
|
|
||||||
|
typedef pyb_mutex_t mp_thread_mutex_t;
|
||||||
|
|
||||||
|
void mp_thread_init(void);
|
||||||
|
void mp_thread_gc_others(void);
|
||||||
|
|
||||||
|
static inline void mp_thread_set_state(struct _mp_state_thread_t *state) {
|
||||||
|
pyb_thread_set_local(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct _mp_state_thread_t *mp_thread_get_state(void) {
|
||||||
|
return pyb_thread_get_local();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mp_thread_mutex_init(mp_thread_mutex_t *m) {
|
||||||
|
pyb_mutex_init(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mp_thread_mutex_lock(mp_thread_mutex_t *m, int wait) {
|
||||||
|
return pyb_mutex_lock(m, wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mp_thread_mutex_unlock(mp_thread_mutex_t *m) {
|
||||||
|
pyb_mutex_unlock(m);
|
||||||
|
}
|
|
@ -30,11 +30,17 @@
|
||||||
#include "pendsv.h"
|
#include "pendsv.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
|
|
||||||
|
void *pendsv_object;
|
||||||
|
|
||||||
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
||||||
|
uint32_t pendsv_dispatch_active;
|
||||||
pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
|
pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pendsv_init(void) {
|
void pendsv_init(void) {
|
||||||
|
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
||||||
|
pendsv_dispatch_active = false;
|
||||||
|
#endif
|
||||||
// set PendSV interrupt at lowest priority
|
// set PendSV interrupt at lowest priority
|
||||||
NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
|
NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
|
||||||
}
|
}
|
||||||
|
@ -42,10 +48,11 @@ void pendsv_init(void) {
|
||||||
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
||||||
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
|
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
|
||||||
pendsv_dispatch_table[slot] = f;
|
pendsv_dispatch_table[slot] = f;
|
||||||
|
pendsv_dispatch_active = true;
|
||||||
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PendSV_Handler(void) {
|
void pendsv_dispatch_handler(void) {
|
||||||
for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
|
for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
|
||||||
if (pendsv_dispatch_table[i] != NULL) {
|
if (pendsv_dispatch_table[i] != NULL) {
|
||||||
pendsv_dispatch_t f = pendsv_dispatch_table[i];
|
pendsv_dispatch_t f = pendsv_dispatch_table[i];
|
||||||
|
@ -55,3 +62,99 @@ void PendSV_Handler(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
__attribute__((naked)) void PendSV_Handler(void) {
|
||||||
|
// Handle a PendSV interrupt
|
||||||
|
//
|
||||||
|
// For the case of an asynchronous exception, re-jig the
|
||||||
|
// stack so that when we return from this interrupt handler
|
||||||
|
// it returns instead to nlr_jump with argument pendsv_object
|
||||||
|
// note that stack has a different layout if DEBUG is enabled
|
||||||
|
//
|
||||||
|
// For the case of a thread switch, swap stacks.
|
||||||
|
//
|
||||||
|
// on entry to this (naked) function, stack has the following layout:
|
||||||
|
//
|
||||||
|
// stack layout with DEBUG disabled:
|
||||||
|
// sp[6]: pc=r15
|
||||||
|
// sp[5]: lr=r14
|
||||||
|
// sp[4]: r12
|
||||||
|
// sp[3]: r3
|
||||||
|
// sp[2]: r2
|
||||||
|
// sp[1]: r1
|
||||||
|
// sp[0]: r0
|
||||||
|
//
|
||||||
|
// stack layout with DEBUG enabled:
|
||||||
|
// sp[8]: pc=r15
|
||||||
|
// sp[7]: lr=r14
|
||||||
|
// sp[6]: r12
|
||||||
|
// sp[5]: r3
|
||||||
|
// sp[4]: r2
|
||||||
|
// sp[3]: r1
|
||||||
|
// sp[2]: r0
|
||||||
|
// sp[1]: 0xfffffff9
|
||||||
|
// sp[0]: ?
|
||||||
|
|
||||||
|
__asm volatile (
|
||||||
|
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
||||||
|
// Check if there are any pending calls to dispatch to
|
||||||
|
"ldr r1, pendsv_dispatch_active_ptr\n"
|
||||||
|
"ldr r0, [r1]\n"
|
||||||
|
"cmp r0, #0\n"
|
||||||
|
"beq .no_dispatch\n"
|
||||||
|
"mov r2, #0\n"
|
||||||
|
"str r2, [r1]\n" // clear pendsv_dispatch_active
|
||||||
|
"b pendsv_dispatch_handler\n" // jump to the handler
|
||||||
|
".no_dispatch:\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check if there is an active object to throw via nlr_jump
|
||||||
|
"ldr r1, pendsv_object_ptr\n"
|
||||||
|
"ldr r0, [r1]\n"
|
||||||
|
"cmp r0, #0\n"
|
||||||
|
"beq .no_obj\n"
|
||||||
|
#if defined(PENDSV_DEBUG)
|
||||||
|
"str r0, [sp, #8]\n" // store to r0 on stack
|
||||||
|
#else
|
||||||
|
"str r0, [sp, #0]\n" // store to r0 on stack
|
||||||
|
#endif
|
||||||
|
"mov r0, #0\n"
|
||||||
|
"str r0, [r1]\n" // clear pendsv_object
|
||||||
|
"ldr r0, nlr_jump_ptr\n"
|
||||||
|
#if defined(PENDSV_DEBUG)
|
||||||
|
"str r0, [sp, #32]\n" // store to pc on stack
|
||||||
|
#else
|
||||||
|
"str r0, [sp, #24]\n" // store to pc on stack
|
||||||
|
#endif
|
||||||
|
"bx lr\n" // return from interrupt; will return to nlr_jump
|
||||||
|
".no_obj:\n" // pendsv_object==NULL
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
// Do a thread context switch
|
||||||
|
"push {r4-r11, lr}\n"
|
||||||
|
"vpush {s16-s31}\n"
|
||||||
|
"mrs r5, primask\n" // save PRIMASK in r5
|
||||||
|
"cpsid i\n" // disable interrupts while we change stacks
|
||||||
|
"mov r0, sp\n" // pass sp to save
|
||||||
|
"mov r4, lr\n" // save lr because we are making a call
|
||||||
|
"bl pyb_thread_next\n" // get next thread to execute
|
||||||
|
"mov lr, r4\n" // restore lr
|
||||||
|
"mov sp, r0\n" // switch stacks
|
||||||
|
"msr primask, r5\n" // re-enable interrupts
|
||||||
|
"vpop {s16-s31}\n"
|
||||||
|
"pop {r4-r11, lr}\n"
|
||||||
|
"bx lr\n" // return from interrupt; will return to new thread
|
||||||
|
#else
|
||||||
|
// Spurious pendsv, just return
|
||||||
|
"bx lr\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Data
|
||||||
|
".align 2\n"
|
||||||
|
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
|
||||||
|
"pendsv_dispatch_active_ptr: .word pendsv_dispatch_active\n"
|
||||||
|
#endif
|
||||||
|
"pendsv_object_ptr: .word pendsv_object\n"
|
||||||
|
"nlr_jump_ptr: .word nlr_jump\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Damien P. George
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/obj.h"
|
||||||
|
|
||||||
|
#include "gccollect.h"
|
||||||
|
#include "irq.h"
|
||||||
|
#include "pybthread.h"
|
||||||
|
#include "mphalport.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
|
||||||
|
#define PYB_MUTEX_UNLOCKED ((void *)0)
|
||||||
|
#define PYB_MUTEX_LOCKED ((void *)1)
|
||||||
|
|
||||||
|
#ifndef MICROPY_BOARD_FATAL_ERROR
|
||||||
|
#define MICROPY_BOARD_FATAL_ERROR boardctrl_fatal_error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// These macros are used when we only need to protect against a thread
|
||||||
|
// switch; other interrupts are still allowed to proceed.
|
||||||
|
#define RAISE_IRQ_PRI() raise_irq_pri(IRQ_PRI_PENDSV)
|
||||||
|
#define RESTORE_IRQ_PRI(state) restore_irq_pri(state)
|
||||||
|
|
||||||
|
volatile int pyb_thread_enabled;
|
||||||
|
pyb_thread_t *volatile pyb_thread_all;
|
||||||
|
pyb_thread_t *volatile pyb_thread_cur;
|
||||||
|
|
||||||
|
static inline void pyb_thread_add_to_runable(pyb_thread_t *thread) {
|
||||||
|
thread->run_prev = pyb_thread_cur->run_prev;
|
||||||
|
thread->run_next = pyb_thread_cur;
|
||||||
|
pyb_thread_cur->run_prev->run_next = thread;
|
||||||
|
pyb_thread_cur->run_prev = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pyb_thread_remove_from_runable(pyb_thread_t *thread) {
|
||||||
|
if (thread->run_next == thread) {
|
||||||
|
MICROPY_BOARD_FATAL_ERROR("deadlock");
|
||||||
|
}
|
||||||
|
thread->run_prev->run_next = thread->run_next;
|
||||||
|
thread->run_next->run_prev = thread->run_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pyb_thread_init(pyb_thread_t *thread) {
|
||||||
|
pyb_thread_enabled = 0;
|
||||||
|
pyb_thread_all = thread;
|
||||||
|
pyb_thread_cur = thread;
|
||||||
|
thread->sp = NULL; // will be set when this thread switches out
|
||||||
|
thread->local_state = 0; // will be set by mp_thread_init
|
||||||
|
thread->arg = NULL;
|
||||||
|
thread->stack = &_sstack;
|
||||||
|
thread->stack_len = ((uint32_t)&_estack - (uint32_t)&_sstack) / sizeof(uint32_t);
|
||||||
|
thread->all_next = NULL;
|
||||||
|
thread->run_prev = thread;
|
||||||
|
thread->run_next = thread;
|
||||||
|
thread->queue_next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pyb_thread_deinit() {
|
||||||
|
uint32_t irq_state = disable_irq();
|
||||||
|
pyb_thread_enabled = 0;
|
||||||
|
pyb_thread_all = pyb_thread_cur;
|
||||||
|
pyb_thread_cur->all_next = NULL;
|
||||||
|
pyb_thread_cur->run_prev = pyb_thread_cur;
|
||||||
|
pyb_thread_cur->run_next = pyb_thread_cur;
|
||||||
|
enable_irq(irq_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pyb_thread_terminate(void) {
|
||||||
|
uint32_t irq_state = disable_irq();
|
||||||
|
pyb_thread_t *thread = pyb_thread_cur;
|
||||||
|
// take current thread off the run list
|
||||||
|
pyb_thread_remove_from_runable(thread);
|
||||||
|
// take current thread off the list of all threads
|
||||||
|
for (pyb_thread_t **n = (pyb_thread_t **)&pyb_thread_all;; n = &(*n)->all_next) {
|
||||||
|
if (*n == thread) {
|
||||||
|
*n = thread->all_next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clean pointers as much as possible to help GC
|
||||||
|
thread->all_next = NULL;
|
||||||
|
thread->queue_next = NULL;
|
||||||
|
thread->stack = NULL;
|
||||||
|
if (pyb_thread_all->all_next == NULL) {
|
||||||
|
// only 1 thread left
|
||||||
|
pyb_thread_enabled = 0;
|
||||||
|
}
|
||||||
|
// thread switch will occur after we enable irqs
|
||||||
|
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||||
|
enable_irq(irq_state);
|
||||||
|
// should not return
|
||||||
|
MICROPY_BOARD_FATAL_ERROR("could not terminate");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pyb_thread_new(pyb_thread_t *thread, void *stack, size_t stack_len, void *entry, void *arg) {
|
||||||
|
uint32_t *stack_top = (uint32_t *)stack + stack_len; // stack is full descending
|
||||||
|
*--stack_top = 0x01000000; // xPSR (thumb bit set)
|
||||||
|
*--stack_top = (uint32_t)entry & 0xfffffffe; // pc (must have bit 0 cleared, even for thumb code)
|
||||||
|
*--stack_top = (uint32_t)pyb_thread_terminate; // lr
|
||||||
|
*--stack_top = 0; // r12
|
||||||
|
*--stack_top = 0; // r3
|
||||||
|
*--stack_top = 0; // r2
|
||||||
|
*--stack_top = 0; // r1
|
||||||
|
*--stack_top = (uint32_t)arg; // r0
|
||||||
|
*--stack_top = 0xfffffff9; // lr (return to thread mode, non-FP, use MSP)
|
||||||
|
stack_top -= 8; // r4-r11
|
||||||
|
stack_top -= 16; // s16-s31 (we assume all threads use FP registers)
|
||||||
|
thread->sp = stack_top;
|
||||||
|
thread->local_state = 0;
|
||||||
|
thread->arg = arg;
|
||||||
|
thread->stack = stack;
|
||||||
|
thread->stack_len = stack_len;
|
||||||
|
thread->queue_next = NULL;
|
||||||
|
uint32_t irq_state = disable_irq();
|
||||||
|
pyb_thread_enabled = 1;
|
||||||
|
thread->all_next = pyb_thread_all;
|
||||||
|
pyb_thread_all = thread;
|
||||||
|
pyb_thread_add_to_runable(thread);
|
||||||
|
enable_irq(irq_state);
|
||||||
|
return (uint32_t)thread; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
void pyb_thread_dump(const mp_print_t *print) {
|
||||||
|
if (!pyb_thread_enabled) {
|
||||||
|
mp_printf(print, "THREAD: only main thread\n");
|
||||||
|
} else {
|
||||||
|
mp_printf(print, "THREAD:\n");
|
||||||
|
for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) {
|
||||||
|
bool runable = false;
|
||||||
|
for (pyb_thread_t *th2 = pyb_thread_cur;; th2 = th2->run_next) {
|
||||||
|
if (th == th2) {
|
||||||
|
runable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (th2->run_next == pyb_thread_cur) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mp_printf(print, " id=%p sp=%p sz=%u", th, th->stack, th->stack_len);
|
||||||
|
if (runable) {
|
||||||
|
mp_printf(print, " (runable)");
|
||||||
|
}
|
||||||
|
mp_printf(print, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// should only be called from pendsv_isr_handler
|
||||||
|
void *pyb_thread_next(void *sp) {
|
||||||
|
pyb_thread_cur->sp = sp;
|
||||||
|
pyb_thread_cur = pyb_thread_cur->run_next;
|
||||||
|
pyb_thread_cur->timeslice = 4; // in milliseconds
|
||||||
|
return pyb_thread_cur->sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pyb_mutex_init(pyb_mutex_t *m) {
|
||||||
|
*m = PYB_MUTEX_UNLOCKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pyb_mutex_lock(pyb_mutex_t *m, int wait) {
|
||||||
|
uint32_t irq_state = RAISE_IRQ_PRI();
|
||||||
|
if (*m == PYB_MUTEX_UNLOCKED) {
|
||||||
|
// mutex is available
|
||||||
|
*m = PYB_MUTEX_LOCKED;
|
||||||
|
RESTORE_IRQ_PRI(irq_state);
|
||||||
|
} else {
|
||||||
|
// mutex is locked
|
||||||
|
if (!wait) {
|
||||||
|
RESTORE_IRQ_PRI(irq_state);
|
||||||
|
return 0; // failed to lock mutex
|
||||||
|
}
|
||||||
|
if (*m == PYB_MUTEX_LOCKED) {
|
||||||
|
*m = pyb_thread_cur;
|
||||||
|
} else {
|
||||||
|
for (pyb_thread_t *n = *m;; n = n->queue_next) {
|
||||||
|
if (n->queue_next == NULL) {
|
||||||
|
n->queue_next = pyb_thread_cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pyb_thread_cur->queue_next = NULL;
|
||||||
|
// take current thread off the run list
|
||||||
|
pyb_thread_remove_from_runable(pyb_thread_cur);
|
||||||
|
// thread switch will occur after we enable irqs
|
||||||
|
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||||
|
RESTORE_IRQ_PRI(irq_state);
|
||||||
|
// when we come back we have the mutex
|
||||||
|
}
|
||||||
|
return 1; // have mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
void pyb_mutex_unlock(pyb_mutex_t *m) {
|
||||||
|
uint32_t irq_state = RAISE_IRQ_PRI();
|
||||||
|
if (*m == PYB_MUTEX_LOCKED) {
|
||||||
|
// no threads are blocked on the mutex
|
||||||
|
*m = PYB_MUTEX_UNLOCKED;
|
||||||
|
} else {
|
||||||
|
// at least one thread is blocked on this mutex
|
||||||
|
pyb_thread_t *th = *m;
|
||||||
|
if (th->queue_next == NULL) {
|
||||||
|
// no other threads are blocked
|
||||||
|
*m = PYB_MUTEX_LOCKED;
|
||||||
|
} else {
|
||||||
|
// at least one other thread is still blocked
|
||||||
|
*m = th->queue_next;
|
||||||
|
}
|
||||||
|
// put unblocked thread on runable list
|
||||||
|
pyb_thread_add_to_runable(th);
|
||||||
|
}
|
||||||
|
RESTORE_IRQ_PRI(irq_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_THREAD
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Damien P. George
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_STM32_PYBTHREAD_H
|
||||||
|
#define MICROPY_INCLUDED_STM32_PYBTHREAD_H
|
||||||
|
|
||||||
|
#include "py/mpprint.h"
|
||||||
|
|
||||||
|
typedef struct _pyb_thread_t {
|
||||||
|
void *sp;
|
||||||
|
uint32_t local_state;
|
||||||
|
void *arg; // thread Python args, a GC root pointer
|
||||||
|
void *stack; // pointer to the stack
|
||||||
|
size_t stack_len; // number of words in the stack
|
||||||
|
uint32_t timeslice;
|
||||||
|
struct _pyb_thread_t *all_next;
|
||||||
|
struct _pyb_thread_t *run_prev;
|
||||||
|
struct _pyb_thread_t *run_next;
|
||||||
|
struct _pyb_thread_t *queue_next;
|
||||||
|
} pyb_thread_t;
|
||||||
|
|
||||||
|
typedef pyb_thread_t *pyb_mutex_t;
|
||||||
|
|
||||||
|
extern volatile int pyb_thread_enabled;
|
||||||
|
extern pyb_thread_t *volatile pyb_thread_all;
|
||||||
|
extern pyb_thread_t *volatile pyb_thread_cur;
|
||||||
|
|
||||||
|
void pyb_thread_init(pyb_thread_t *th);
|
||||||
|
void pyb_thread_deinit();
|
||||||
|
uint32_t pyb_thread_new(pyb_thread_t *th, void *stack, size_t stack_len, void *entry, void *arg);
|
||||||
|
void pyb_thread_dump(const mp_print_t *print);
|
||||||
|
|
||||||
|
static inline uint32_t pyb_thread_get_id(void) {
|
||||||
|
return (uint32_t)pyb_thread_cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pyb_thread_set_local(void *value) {
|
||||||
|
pyb_thread_cur->local_state = (uint32_t)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *pyb_thread_get_local(void) {
|
||||||
|
return (void *)pyb_thread_cur->local_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pyb_thread_yield(void) {
|
||||||
|
if (pyb_thread_cur->run_next == pyb_thread_cur) {
|
||||||
|
__WFI();
|
||||||
|
} else {
|
||||||
|
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pyb_mutex_init(pyb_mutex_t *m);
|
||||||
|
int pyb_mutex_lock(pyb_mutex_t *m, int wait);
|
||||||
|
void pyb_mutex_unlock(pyb_mutex_t *m);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_STM32_PYBTHREAD_H
|
|
@ -51,6 +51,18 @@ void SysTick_Handler(void) {
|
||||||
if (soft_timer_next == uw_tick) {
|
if (soft_timer_next == uw_tick) {
|
||||||
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
|
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_THREAD
|
||||||
|
if (pyb_thread_enabled) {
|
||||||
|
if (pyb_thread_cur->timeslice == 0) {
|
||||||
|
if (pyb_thread_cur->run_next != pyb_thread_cur) {
|
||||||
|
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
--pyb_thread_cur->timeslice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
|
bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
|
||||||
|
|
Ładowanie…
Reference in New Issue