From 9b1c1262dc70cfb6b5cf5d27e3e3d8e41b5a4901 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 May 2016 14:28:15 +0100 Subject: cc3200: Define our own FreeRTOS heap so it can go in a special segment. --- cc3200/FreeRTOS/FreeRTOSConfig.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'cc3200/FreeRTOS/FreeRTOSConfig.h') diff --git a/cc3200/FreeRTOS/FreeRTOSConfig.h b/cc3200/FreeRTOS/FreeRTOSConfig.h index 2e9a514381..27ba880f62 100644 --- a/cc3200/FreeRTOS/FreeRTOSConfig.h +++ b/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -151,4 +151,7 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ version. */ #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +/* We provide a definition of ucHeap so it can go in a special segment. */ +#define configAPPLICATION_ALLOCATED_HEAP 1 + #endif /* FREERTOS_CONFIG_H */ -- cgit v1.2.3 From eef4f13a3390dc88902563acb047f0439eff0caf Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 May 2016 17:35:46 +0100 Subject: cc3200: Add basic threading capabilities. Can create a new thread and run it. Does not use the GIL at this point. --- cc3200/FreeRTOS/FreeRTOSConfig.h | 8 ++ cc3200/application.mk | 1 + cc3200/hal/cc3200_hal.c | 2 + cc3200/main.c | 12 +++ cc3200/mpconfigport.h | 2 + cc3200/mptask.c | 5 ++ cc3200/mpthreadport.c | 171 +++++++++++++++++++++++++++++++++++++++ cc3200/mpthreadport.h | 36 +++++++++ cc3200/util/gccollect.c | 6 ++ 9 files changed, 243 insertions(+) create mode 100644 cc3200/mpthreadport.c create mode 100644 cc3200/mpthreadport.h (limited to 'cc3200/FreeRTOS/FreeRTOSConfig.h') diff --git a/cc3200/FreeRTOS/FreeRTOSConfig.h b/cc3200/FreeRTOS/FreeRTOSConfig.h index 27ba880f62..abde289374 100644 --- a/cc3200/FreeRTOS/FreeRTOSConfig.h +++ b/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -154,4 +154,12 @@ version. */ /* We provide a definition of ucHeap so it can go in a special segment. */ #define configAPPLICATION_ALLOCATED_HEAP 1 +/* For threading */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#define configSUPPORT_STATIC_ALLOCATION 1 +#undef configUSE_MUTEXES +#define configUSE_MUTEXES 1 +#undef INCLUDE_vTaskDelete +#define INCLUDE_vTaskDelete 1 + #endif /* FREERTOS_CONFIG_H */ diff --git a/cc3200/application.mk b/cc3200/application.mk index b862212a54..dca6fcbc65 100644 --- a/cc3200/application.mk +++ b/cc3200/application.mk @@ -142,6 +142,7 @@ APP_UTIL_SRC_S = $(addprefix util/,\ APP_MAIN_SRC_C = \ main.c \ mptask.c \ + mpthreadport.c \ serverstask.c APP_LIB_SRC_C = $(addprefix lib/,\ diff --git a/cc3200/hal/cc3200_hal.c b/cc3200/hal/cc3200_hal.c index f0987ae9d2..f4d38d120e 100644 --- a/cc3200/hal/cc3200_hal.c +++ b/cc3200/hal/cc3200_hal.c @@ -111,6 +111,7 @@ mp_uint_t mp_hal_ticks_ms(void) { void mp_hal_delay_ms(mp_uint_t delay) { // only if we are not within interrupt context and interrupts are enabled if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + MP_THREAD_GIL_EXIT(); #ifdef USE_FREERTOS vTaskDelay (delay / portTICK_PERIOD_MS); #else @@ -121,6 +122,7 @@ void mp_hal_delay_ms(mp_uint_t delay) { __WFI(); } #endif + MP_THREAD_GIL_ENTER(); } else { for (int ms = 0; ms < delay; ms++) { UtilsDelay(UTILS_DELAY_US_TO_COUNT(1000)); diff --git a/cc3200/main.c b/cc3200/main.c index 4a6f6172bf..2aed70f76b 100644 --- a/cc3200/main.c +++ b/cc3200/main.c @@ -98,3 +98,15 @@ void stoupper (char *str) { str++; } } + +// We need this when configSUPPORT_STATIC_ALLOCATION is enabled +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize ) { + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index d3aacc082f..69114516a8 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -102,6 +102,8 @@ #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (1) #define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_THREAD (1) +#define MICROPY_PY_THREAD_GIL (0) #define MICROPY_PY_UBINASCII (0) #define MICROPY_PY_UCTYPES (0) #define MICROPY_PY_UZLIB (0) diff --git a/cc3200/mptask.c b/cc3200/mptask.c index f8f33c2959..828263c4a1 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -116,6 +116,11 @@ void TASK_Micropython (void *pvParameters) { soft_reset: + // Thread init + #if MICROPY_PY_THREAD + mp_thread_init(); + #endif + // GC init gc_init(&_boot, &_eheap); diff --git a/cc3200/mpthreadport.c b/cc3200/mpthreadport.c new file mode 100644 index 0000000000..7cc44d73dc --- /dev/null +++ b/cc3200/mpthreadport.c @@ -0,0 +1,171 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * 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 + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "task.h" + +#if MICROPY_PY_THREAD + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + TaskHandle_t id; // system id of thread + int ready; // whether the thread is ready and running + 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 + struct _thread_t *next; +} thread_t; + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; +STATIC thread_t thread_entry0; +STATIC thread_t *thread; // root pointer, handled bp mp_thread_gc_others + +void mp_thread_init(void) { + mp_thread_mutex_init(&thread_mutex); + mp_thread_set_state(&mp_state_ctx.thread); + + // create first entry in linked list of all threads + thread = &thread_entry0; + thread->id = NULL; // TODO + thread->ready = 1; + thread->arg = NULL; + thread->next = NULL; +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + gc_collect_root((void**)&thread, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root(&th->arg, 1); + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + if (!th->ready) { + continue; + } + gc_collect_root(th->stack, th->stack_len); + } + mp_thread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return pvTaskGetThreadLocalStoragePointer(NULL, 0); +} + +void mp_thread_set_state(void *state) { + vTaskSetThreadLocalStoragePointer(NULL, 0, state); +} + +void mp_thread_start(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 1; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +STATIC void *(*ext_thread_entry)(void*) = NULL; + +STATIC void freertos_entry(void *arg) { + if (ext_thread_entry) { + ext_thread_entry(arg); + } + vTaskDelete(NULL); + for (;;) { + } +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t stack_size) { + // store thread entry function into a global variable so we can access it + ext_thread_entry = entry; + + if (stack_size == 0) { + stack_size = 2048; // default stack size + } + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + StackType_t *stack = m_new(StackType_t, stack_size / sizeof(StackType_t)); + StaticTask_t *task_buf = m_new(StaticTask_t, 1); + TaskHandle_t id = xTaskCreateStatic(freertos_entry, "Thread", stack_size / sizeof(void*), arg, 2, stack, task_buf); + if (id == NULL) { + mp_thread_mutex_unlock(&thread_mutex); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, "can't create thread")); + } + + // add thread to linked list of all threads + thread_t *th = m_new_obj(thread_t); + th->id = id; + th->ready = 0; + th->arg = arg; + th->stack = stack; + th->stack_len = stack_size / sizeof(StackType_t); + th->next = thread; + thread = th; + + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_finish(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + // TODO unlink from list + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 0; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + *mutex = xSemaphoreCreateMutex(); + if (*mutex == NULL) { + // error! + } +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + int ret = xSemaphoreTake(*mutex, wait ? portMAX_DELAY : 0); + return ret == pdTRUE; +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + xSemaphoreGive(*mutex); + // TODO check return value +} + +#endif // MICROPY_PY_THREAD diff --git a/cc3200/mpthreadport.h b/cc3200/mpthreadport.h new file mode 100644 index 0000000000..83995915eb --- /dev/null +++ b/cc3200/mpthreadport.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * 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_CC3200_MPTHREADPORT_H__ +#define __MICROPY_INCLUDED_CC3200_MPTHREADPORT_H__ + +#include "FreeRTOS.h" + +typedef SemaphoreHandle_t mp_thread_mutex_t; + +void mp_thread_init(void); +void mp_thread_gc_others(void); + +#endif // __MICROPY_INCLUDED_CC3200_MPTHREADPORT_H__ diff --git a/cc3200/util/gccollect.c b/cc3200/util/gccollect.c index 094ca73bc6..bc9cba4b8d 100644 --- a/cc3200/util/gccollect.c +++ b/cc3200/util/gccollect.c @@ -30,6 +30,7 @@ #include "py/mpconfig.h" #include "py/gc.h" +#include "py/mpthread.h" #include "gccollect.h" #include "gchelper.h" @@ -57,6 +58,11 @@ void gc_collect(void) { // trace the stack, including the registers (since they live on the stack in this function) gc_collect_root((void**)sp, (stackend - sp) / sizeof(uint32_t)); + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif + // end the GC gc_collect_end(); } -- cgit v1.2.3 From 1d5aa9d245362d060843688a97f12a86b8fe1e46 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 5 Jun 2016 12:43:04 +0100 Subject: cc3200: In FreeRTOSConfig.h, comment on configSUPPORT_STATIC_ALLOCATION. This config variable is now needed regardless of whether threading is enabled or not. --- cc3200/FreeRTOS/FreeRTOSConfig.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'cc3200/FreeRTOS/FreeRTOSConfig.h') diff --git a/cc3200/FreeRTOS/FreeRTOSConfig.h b/cc3200/FreeRTOS/FreeRTOSConfig.h index abde289374..c0d50d0c1d 100644 --- a/cc3200/FreeRTOS/FreeRTOSConfig.h +++ b/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -154,9 +154,11 @@ version. */ /* We provide a definition of ucHeap so it can go in a special segment. */ #define configAPPLICATION_ALLOCATED_HEAP 1 +/* We use static versions of functions (like xTaskCreateStatic) */ +#define configSUPPORT_STATIC_ALLOCATION 1 + /* For threading */ #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 -#define configSUPPORT_STATIC_ALLOCATION 1 #undef configUSE_MUTEXES #define configUSE_MUTEXES 1 #undef INCLUDE_vTaskDelete -- cgit v1.2.3 From 469c623bb8e504ca78f1964508579ecefec76a98 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 5 Jun 2016 13:01:16 +0100 Subject: cc3200: Shrink the FreeRTOS heap and place TCB+stack in freed location. The 16k FreeRTOS heap originally had all TCBs and stacks dynamically allocated within it (plus semaphores and some other things). Now that xTaskCreateStatic is used instead of xTaskCreate, the TCBs and stacks are allocated statically and no longer use any of the FreeRTOS heap. Therefore, the FreeRTOS stack can be shrunk by the amount that has been made static. Furthermore, the TCBs and stack that are now static should be placed in the .rtos_heaps section of RAM because this RAM is treated specially by the bootloader (the bootloader executes from the first 16k of RAM and loads the firmware into the section starting after the 16k). After this patch the FreeRTOS heap (ucHeap) is 7200 bytes. The memory available for the MicroPython heap is 54936 bytes (including GC overhead). --- cc3200/FreeRTOS/FreeRTOSConfig.h | 8 +++++++- cc3200/main.c | 11 ++++++----- cc3200/serverstask.c | 7 +++++-- cc3200/simplelink/oslib/osi_freertos.c | 4 ++-- 4 files changed, 20 insertions(+), 10 deletions(-) (limited to 'cc3200/FreeRTOS/FreeRTOSConfig.h') diff --git a/cc3200/FreeRTOS/FreeRTOSConfig.h b/cc3200/FreeRTOS/FreeRTOSConfig.h index c0d50d0c1d..2f25bbd7e8 100644 --- a/cc3200/FreeRTOS/FreeRTOSConfig.h +++ b/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -84,7 +84,13 @@ #define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 ) #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 ) -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16384 ) ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( \ + 16384 /* 16kbytes for FreeRTOS data structures and heap */ \ + - sizeof(StaticTask_t) - configMINIMAL_STACK_SIZE * sizeof(StackType_t) /* TCB+stack for idle task */ \ + - sizeof(StaticTask_t) - 1024 /* TCB+stack for servers task */ \ + - sizeof(StaticTask_t) - 6656 /* TCB+stack for main MicroPython task */ \ + - sizeof(StaticTask_t) - 896 /* TCB+stack for simplelink spawn task */ \ + ) ) #define configMAX_TASK_NAME_LEN ( 8 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 0 diff --git a/cc3200/main.c b/cc3200/main.c index da6c5211b2..06b3604b67 100644 --- a/cc3200/main.c +++ b/cc3200/main.c @@ -50,6 +50,10 @@ DECLARE PRIVATE DATA ******************************************************************************/ +// This is the static memory (TCB and stack) for the idle task +static StaticTask_t xIdleTaskTCB __attribute__ ((section (".rtos_heap"))); +static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ @@ -61,8 +65,8 @@ OsiTaskHandle mpTaskHandle; uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); // This is the static memory (TCB and stack) for the main MicroPython task -StaticTask_t mpTaskTCB; -StackType_t mpTaskStack[MICROPY_TASK_STACK_LEN] __attribute__((aligned (8))); +StaticTask_t mpTaskTCB __attribute__ ((section (".rtos_heap"))); +StackType_t mpTaskStack[MICROPY_TASK_STACK_LEN] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); /****************************************************************************** DEFINE PUBLIC FUNCTIONS @@ -105,9 +109,6 @@ void stoupper (char *str) { void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { - static StaticTask_t xIdleTaskTCB; - static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; - *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; *ppxIdleTaskStackBuffer = uxIdleTaskStack; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; diff --git a/cc3200/serverstask.c b/cc3200/serverstask.c index 8bac3a756a..1305afda0b 100644 --- a/cc3200/serverstask.c +++ b/cc3200/serverstask.c @@ -67,8 +67,11 @@ static volatile bool sleep_sockets = false; /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ -StaticTask_t svTaskTCB; -StackType_t svTaskStack[SERVERS_STACK_LEN] __attribute__((aligned (8))); + +// This is the static memory (TCB and stack) for the servers task +StaticTask_t svTaskTCB __attribute__ ((section (".rtos_heap"))); +StackType_t svTaskStack[SERVERS_STACK_LEN] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + char servers_user[SERVERS_USER_PASS_LEN_MAX + 1]; char servers_pass[SERVERS_USER_PASS_LEN_MAX + 1]; diff --git a/cc3200/simplelink/oslib/osi_freertos.c b/cc3200/simplelink/oslib/osi_freertos.c index 90acc2e979..53822add73 100644 --- a/cc3200/simplelink/oslib/osi_freertos.c +++ b/cc3200/simplelink/oslib/osi_freertos.c @@ -62,8 +62,8 @@ TaskHandle_t xSimpleLinkSpawnTaskHndl = NULL; #define SL_SPAWN_MAX_WAIT_MS ( 200 ) // This is the static memory (TCB and stack) for the SL spawn task -static StaticTask_t spawnTaskTCB; -static portSTACK_TYPE spawnTaskStack[896 / sizeof(portSTACK_TYPE)] __attribute__((aligned (8))); +static StaticTask_t spawnTaskTCB __attribute__ ((section (".rtos_heap"))); +static portSTACK_TYPE spawnTaskStack[896 / sizeof(portSTACK_TYPE)] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); /*! \brief This function registers an interrupt in NVIC table -- cgit v1.2.3