Skip to content

Commit d271655

Browse files
committed
adds new c module that exposes FreeRTOS to Python.
This is for advanced users that know how to deal with semaphores and threads. It enables true parallel processing allowing use of both cores. It is only available for the ESP32-S3 for the time being and I will make it available to all dual core ESP32 MCU's. To enable using it you need to add `--py-freertos` to your build command. **WARNING** Using this disables the Python GIL so care much be given to control access to objects by multiple threads using semaphores and queues otherwise memory corruption will occur.
1 parent 861d2ae commit d271655

29 files changed

+5052
-4
lines changed

builder/esp32.py

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,9 +477,18 @@ def esp32_s3_args(extra_args):
477477
dest='oct_flash',
478478
action='store_true'
479479
)
480+
esp_argParser.add_argument(
481+
'--py-freertos',
482+
help='espose FreeRTOS to Python',
483+
dest='py_freertos',
484+
action='store_true'
485+
)
480486

481487
esp_args, extra_args = esp_argParser.parse_known_args(extra_args)
482488

489+
if esp_args.py_freertos:
490+
os.environ['PY_FREERTOS'] = '1'
491+
483492
oct_flash = esp_args.oct_flash
484493
board_variant = esp_args.board_variant
485494

@@ -984,6 +993,7 @@ def find_esp32_ports(chip):
984993

985994
SDKCONFIG_PATH = f'build/sdkconfig.board'
986995

996+
MPTHREADPORT_H_PATH = 'lib/micropython/ports/esp32/mpthreadport.h'
987997
MPTHREADPORT_PATH = 'lib/micropython/ports/esp32/mpthreadport.c'
988998
MPCONFIGPORT_PATH = 'lib/micropython/ports/esp32/mpconfigport.h'
989999
PANICHANDLER_PATH = 'lib/micropython/ports/esp32/panichandler.c'
@@ -996,8 +1006,55 @@ def find_esp32_ports(chip):
9961006

9971007

9981008
def update_mpthreadport():
999-
# data = read_file('esp32', MPTHREADPORT_PATH)
1000-
#
1009+
h_data = read_file('esp32', MPTHREADPORT_H_PATH)
1010+
1011+
if 'typedef mp_thread_mutex_t mp_thread_recursive_mutex_t;' not in h_data:
1012+
new_data = [
1013+
'} mp_thread_mutex_t;',
1014+
'',
1015+
'#if MICROPY_PY_THREAD_GIL == 0',
1016+
'typedef mp_thread_mutex_t mp_thread_recursive_mutex_t;',
1017+
'void mp_thread_recursive_mutex_init(mp_thread_recursive_mutex_t *mutex);',
1018+
'int mp_thread_recursive_mutex_lock(mp_thread_recursive_mutex_t *mutex, int wait);',
1019+
'void mp_thread_recursive_mutex_unlock(mp_thread_recursive_mutex_t *mutex);',
1020+
'#endif'
1021+
]
1022+
1023+
h_data = h_data.replace(
1024+
'} mp_thread_mutex_t;',
1025+
'\n'.join(new_data)
1026+
)
1027+
1028+
c_data = read_file('esp32', MPTHREADPORT_PATH)
1029+
1030+
new_data = [
1031+
'} mp_thread_t;',
1032+
'',
1033+
'#if MICROPY_PY_THREAD_GIL == 0',
1034+
'void mp_thread_recursive_mutex_init(mp_thread_recursive_mutex_t *mutex)',
1035+
'{',
1036+
' mutex->handle = xSemaphoreCreateRecursiveMutexStatic(&mutex->buffer);',
1037+
' xSemaphoreGiveRecursive(mutex->handle);',
1038+
'}',
1039+
'',
1040+
'int mp_thread_recursive_mutex_lock(mp_thread_recursive_mutex_t *mutex, int wait)',
1041+
'{',
1042+
' return pdTRUE == xSemaphoreTakeRecursive(mutex->handle, pdMS_TO_TICKS((uint32_t)wait));',
1043+
'}',
1044+
'',
1045+
'void mp_thread_recursive_mutex_unlock(mp_thread_recursive_mutex_t *mutex)',
1046+
'{',
1047+
' xSemaphoreGiveRecursive(mutex->handle);',
1048+
'}',
1049+
'#endif'
1050+
]
1051+
c_data = c_data.replace(
1052+
'} mp_thread_t;',
1053+
'\n'.join(new_data)
1054+
)
1055+
1056+
write_file(MPTHREADPORT_PATH, c_data)
1057+
10011058
# if '_CORE_ID' not in data:
10021059
# data = data.replace('MP_TASK_COREID', '_CORE_ID')
10031060
#
@@ -1014,7 +1071,7 @@ def update_mpthreadport():
10141071
#
10151072
# data = data.replace('#if MICROPY_PY_THREAD', '\n'.join(new_data), 1)
10161073
#
1017-
# write_file(MPTHREADPORT_PATH, data)
1074+
write_file(MPTHREADPORT_H_PATH, h_data)
10181075
pass
10191076

10201077

@@ -1420,7 +1477,7 @@ def compile(*args): # NOQA
14201477
app_size = app_size.split('micropython.bin size', 1)[1]
14211478
app_size = int(app_size.split(':', 1)[0].strip(), 16)
14221479

1423-
partition.set_app_size(app_size)
1480+
partition.set_app_size(app_size) # NOQA
14241481
partition.save()
14251482

14261483
sys.stdout.write(

ext_mod/micropython.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
if(ESP_PLATFORM)
44
include(${CMAKE_CURRENT_LIST_DIR}/esp32_components.cmake)
55
include(${CMAKE_CURRENT_LIST_DIR}/spi3wire/micropython.cmake)
6+
7+
if(DEFINED ENV{PY_FREERTOS})
8+
include(${CMAKE_CURRENT_LIST_DIR}/mpy_freertos/micropython.cmake)
9+
endif()
10+
611
endif(ESP_PLATFORM)
712

813
include(${CMAKE_CURRENT_LIST_DIR}/lcd_bus/micropython.cmake)

ext_mod/mpy_freertos/freertos_mod.c

Lines changed: 384 additions & 0 deletions
Large diffs are not rendered by default.

ext_mod/mpy_freertos/freertos_mod.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "py/obj.h"
2+
#include "py/runtime.h"
3+
4+
#include "freertos/FreeRTOS.h"
5+
#include "freertos/atomic.h"
6+
#include "freertos/event_groups.h"
7+
#include "freertos/portmacro.h"
8+
#include "freertos/projdefs.h"
9+
#include "freertos/queue.h"
10+
#include "freertos/semphr.h"
11+
#include "freertos/stream_buffer.h"
12+
#include "freertos/message_buffer.h"
13+
#include "freertos/task.h"
14+
#include "freertos/timers.h"
15+
16+
#ifndef __FREERTOS_MOD_H__
17+
#define __FREERTOS_MOD_H__
18+
19+
typedef enum {
20+
mp_freertos_event_group_type = 1,
21+
mp_freertos_queue_type = 2,
22+
mp_freertos_queue_set_type = 3,
23+
mp_freertos_semaphore_type = 4,
24+
mp_freertos_task_type = 5,
25+
mp_freertos_timer_type = 6,
26+
mp_freertos_spinlock_type = 7,
27+
mp_freertos_message_buffer_type = 8,
28+
mp_freertos_stream_buffer_type = 9
29+
} mp_freertos_types;
30+
31+
#endif
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "py/obj.h"
2+
#include "py/runtime.h"
3+
4+
#include "freertos/FreeRTOS.h"
5+
#include "freertos/atomic.h"
6+
7+
8+
#ifndef __ATOMIC_H__
9+
#define __ATOMIC_H__
10+
11+
extern const mp_obj_fun_builtin_fixed_t mp_ATOMIC_ENTER_CRITICAL_obj;
12+
extern const mp_obj_fun_builtin_fixed_t mp_ATOMIC_EXIT_CRITICAL_obj;
13+
14+
#endif
15+
16+
17+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
5+
#include "freertos_mod.h"
6+
7+
#include "py/obj.h"
8+
#include "py/runtime.h"
9+
10+
#include "freertos/FreeRTOS.h"
11+
#include "freertos/event_groups.h"
12+
13+
14+
#ifndef __EVENT_GROUPS_H__
15+
#define __EVENT_GROUPS_H__
16+
17+
typedef struct _freertos_event_group_t {
18+
EventGroupHandle_t handle;
19+
StaticEventGroup_t buffer;
20+
} freertos_event_group_t;
21+
22+
23+
typedef struct _mp_obj_freertos_event_group_t {
24+
freertos_event_group_t event_group;
25+
mp_freertos_types type;
26+
} mp_obj_freertos_event_group_t;
27+
28+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupCreateStatic_obj;
29+
extern const mp_obj_fun_builtin_var_t mp_xEventGroupWaitBits_obj;
30+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupClearBits_obj;
31+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupClearBitsFromISR_obj;
32+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupSetBits_obj;
33+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupSetBitsFromISR_obj;
34+
extern const mp_obj_fun_builtin_var_t mp_xEventGroupSync_obj;
35+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupGetBits_obj;
36+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupGetBitsFromISR_obj;
37+
extern const mp_obj_fun_builtin_fixed_t mp_vEventGroupDelete_obj;
38+
39+
40+
41+
42+
43+
#endif
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <stdint.h>
2+
#include <stdlib.h>
3+
4+
#include "freertos_mod.h"
5+
6+
#include "py/obj.h"
7+
#include "py/runtime.h"
8+
9+
#include "freertos/FreeRTOS.h"
10+
#include "freertos/idf_additions.h"
11+
12+
#ifndef __IDF_ADDITIONS_H__
13+
#define __IDF_ADDITIONS_H__
14+
15+
extern const mp_obj_fun_builtin_var_t mp_xTaskCreateStaticPinnedToCore_obj;
16+
extern const mp_obj_fun_builtin_fixed_t mp_xTaskGetCoreID_obj;
17+
18+
#if !CONFIG_FREERTOS_SMP
19+
#if INCLUDE_xTaskGetIdleTaskHandle == 1
20+
extern const mp_obj_fun_builtin_fixed_t mp_xTaskGetIdleTaskHandleForCore_obj;
21+
#endif
22+
#if INCLUDE_xTaskGetIdleTaskHandle == 1 || configUSE_MUTEXES == 1
23+
extern const mp_obj_fun_builtin_fixed_t mp_xTaskGetCurrentTaskHandleForCore_obj;
24+
#endif
25+
#endif
26+
27+
extern const mp_obj_fun_builtin_var_t mp_xTaskCreatePinnedToCoreWithCaps_obj;
28+
extern const mp_obj_fun_builtin_var_t mp_xTaskCreateWithCaps_obj;
29+
extern const mp_obj_fun_builtin_fixed_t mp_vTaskDeleteWithCaps_obj;
30+
extern const mp_obj_fun_builtin_fixed_t mp_xQueueCreateWithCaps_obj;
31+
extern const mp_obj_fun_builtin_fixed_t mp_vQueueDeleteWithCaps_obj;
32+
extern const mp_obj_fun_builtin_fixed_t mp_xSemaphoreCreateBinaryWithCaps_obj;
33+
extern const mp_obj_fun_builtin_fixed_t mp_xSemaphoreCreateCountingWithCaps_obj;
34+
extern const mp_obj_fun_builtin_fixed_t mp_xSemaphoreCreateMutexWithCaps_obj;
35+
extern const mp_obj_fun_builtin_fixed_t mp_xSemaphoreCreateRecursiveMutexWithCaps_obj;
36+
extern const mp_obj_fun_builtin_fixed_t mp_vSemaphoreDeleteWithCaps_obj;
37+
extern const mp_obj_fun_builtin_fixed_t mp_xStreamBufferCreateWithCaps_obj;
38+
extern const mp_obj_fun_builtin_fixed_t mp_vStreamBufferDeleteWithCaps_obj;
39+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferCreateWithCaps_obj;
40+
extern const mp_obj_fun_builtin_fixed_t mp_vMessageBufferDeleteWithCaps_obj;
41+
extern const mp_obj_fun_builtin_fixed_t mp_xEventGroupCreateWithCaps_obj;
42+
extern const mp_obj_fun_builtin_fixed_t mp_vEventGroupDeleteWithCaps_obj;
43+
44+
#endif
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <stdint.h>
2+
#include <stdlib.h>
3+
4+
#include "freertos_mod.h"
5+
6+
#include "py/obj.h"
7+
#include "py/runtime.h"
8+
9+
#include "freertos/FreeRTOS.h"
10+
#include "freertos/task.h"
11+
#include "freertos/queue.h"
12+
#include "freertos/event_groups.h"
13+
#include "freertos/semphr.h"
14+
#include "freertos/timers.h"
15+
#include "freertos/message_buffer.h"
16+
17+
18+
#ifndef __MESSAGE_BUFFER_H__
19+
#define __MESSAGE_BUFFER_H__
20+
21+
typedef struct _freertos_message_buffer_t {
22+
MessageBufferHandle_t handle;
23+
StaticMessageBuffer_t buffer;
24+
} freertos_message_buffer_t;
25+
26+
typedef struct _mp_obj_freertos_message_buffer_t {
27+
freertos_message_buffer_t message_buffer;
28+
mp_freertos_types type;
29+
uint8_t *pucStreamBufferStorageArea;
30+
} mp_obj_freertos_message_buffer_t;
31+
32+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferCreateStatic_obj;
33+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferSend_obj;
34+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferSendFromISR_obj;
35+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferReceive_obj;
36+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferReceiveFromISR_obj;
37+
extern const mp_obj_fun_builtin_fixed_t mp_vMessageBufferDelete_obj;
38+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferIsFull_obj;
39+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferIsEmpty_obj;
40+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferReset_obj;
41+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferSpacesAvailable_obj;
42+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferNextLengthBytes_obj;
43+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferSendCompletedFromISR_obj;
44+
extern const mp_obj_fun_builtin_fixed_t mp_xMessageBufferReceiveCompletedFromISR_obj;
45+
46+
47+
#endif
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include <stdint.h>
2+
#include <stdlib.h>
3+
4+
#include "freertos_mod.h"
5+
6+
#include "py/obj.h"
7+
#include "py/runtime.h"
8+
9+
#include "freertos/FreeRTOS.h"
10+
#include "freertos/portmacro.h"
11+
12+
#ifndef __PORTMACRO_H__
13+
#define __PORTMACRO_H__
14+
15+
typedef struct _freertos_spinlock_t {
16+
spinlock_t *handle;
17+
void *buffer;
18+
} freertos_spinlock_t;
19+
20+
typedef struct _mp_obj_freertos_spinlock_t {
21+
freertos_spinlock_t spinlock;
22+
mp_freertos_types type;
23+
} mp_obj_freertos_spinlock_t;
24+
25+
extern const mp_obj_fun_builtin_fixed_t mp_portNOP_obj;
26+
extern const mp_obj_fun_builtin_fixed_t mp_xPortInIsrContext_obj;
27+
extern const mp_obj_fun_builtin_fixed_t mp_vPortAssertIfInISR_obj;
28+
extern const mp_obj_fun_builtin_fixed_t mp_xPortInterruptedFromISRContext_obj;
29+
extern const mp_obj_fun_builtin_fixed_t mp_xPortSetInterruptMaskFromISR_obj;
30+
extern const mp_obj_fun_builtin_fixed_t mp_vPortClearInterruptMaskFromISR_obj;
31+
extern const mp_obj_fun_builtin_fixed_t mp_portMUX_INITIALIZE_obj;
32+
extern const mp_obj_fun_builtin_fixed_t mp_xPortEnterCriticalTimeout_obj;
33+
extern const mp_obj_fun_builtin_fixed_t mp_vPortEnterCritical_obj;
34+
extern const mp_obj_fun_builtin_fixed_t mp_vPortExitCritical_obj;
35+
extern const mp_obj_fun_builtin_fixed_t mp_xPortEnterCriticalTimeoutCompliance_obj;
36+
extern const mp_obj_fun_builtin_fixed_t mp_vPortEnterCriticalCompliance_obj;
37+
extern const mp_obj_fun_builtin_fixed_t mp_vPortExitCriticalCompliance_obj;
38+
extern const mp_obj_fun_builtin_fixed_t mp_xPortEnterCriticalTimeoutSafe_obj;
39+
extern const mp_obj_fun_builtin_fixed_t mp_vPortEnterCriticalSafe_obj;
40+
extern const mp_obj_fun_builtin_fixed_t mp_vPortExitCriticalSafe_obj;
41+
extern const mp_obj_fun_builtin_fixed_t mp_vPortYield_obj;
42+
extern const mp_obj_fun_builtin_fixed_t mp_vPortYieldOtherCore_obj;
43+
extern const mp_obj_fun_builtin_fixed_t mp_xPortGetTickRateHz_obj;
44+
extern const mp_obj_fun_builtin_fixed_t mp_xPortGetCoreID_obj;
45+
extern const mp_obj_fun_builtin_fixed_t mp_portGET_CORE_ID_obj;
46+
extern const mp_obj_fun_builtin_fixed_t mp_portDISABLE_INTERRUPTS_obj;
47+
extern const mp_obj_fun_builtin_fixed_t mp_portENABLE_INTERRUPTS_obj;
48+
extern const mp_obj_fun_builtin_fixed_t mp_portSET_INTERRUPT_MASK_FROM_ISR_obj;
49+
extern const mp_obj_fun_builtin_fixed_t mp_portCLEAR_INTERRUPT_MASK_FROM_ISR_obj;
50+
extern const mp_obj_fun_builtin_fixed_t mp_portASSERT_IF_IN_ISR_obj;
51+
extern const mp_obj_fun_builtin_fixed_t mp_portCHECK_IF_IN_ISR_obj;
52+
extern const mp_obj_fun_builtin_fixed_t mp_portTRY_ENTER_CRITICAL_obj;
53+
extern const mp_obj_fun_builtin_fixed_t mp_portENTER_CRITICAL_obj;
54+
extern const mp_obj_fun_builtin_fixed_t mp_portEXIT_CRITICAL_obj;
55+
extern const mp_obj_fun_builtin_fixed_t mp_portTRY_ENTER_CRITICAL_ISR_obj;
56+
extern const mp_obj_fun_builtin_fixed_t mp_portENTER_CRITICAL_ISR_obj;
57+
extern const mp_obj_fun_builtin_fixed_t mp_portEXIT_CRITICAL_ISR_obj;
58+
extern const mp_obj_fun_builtin_fixed_t mp_portTRY_ENTER_CRITICAL_SAFE_obj;
59+
extern const mp_obj_fun_builtin_fixed_t mp_portENTER_CRITICAL_SAFE_obj;
60+
extern const mp_obj_fun_builtin_fixed_t mp_portEXIT_CRITICAL_SAFE_obj;
61+
extern const mp_obj_fun_builtin_fixed_t mp_portYIELD_obj;
62+
extern const mp_obj_fun_builtin_fixed_t mp__frxt_setup_switch_obj;
63+
extern const mp_obj_fun_builtin_fixed_t mp_portYIELD_FROM_ISR_NO_ARG_obj;
64+
extern const mp_obj_fun_builtin_fixed_t mp_portYIELD_FROM_ISR_ARG_obj;
65+
extern const mp_obj_fun_builtin_fixed_t mp_portYIELD_WITHIN_API_obj;
66+
extern const mp_obj_fun_builtin_fixed_t mp_portYIELD_CORE_obj;
67+
extern const mp_obj_fun_builtin_fixed_t mp_portGET_RUN_TIME_COUNTER_VALUE_obj;
68+
69+
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
70+
extern const mp_obj_fun_builtin_fixed_t mp_portRECORD_READY_PRIORITY_obj;
71+
extern const mp_obj_fun_builtin_fixed_t mp_portRESET_READY_PRIORITY_obj;
72+
extern const mp_obj_fun_builtin_fixed_t mp_portGET_HIGHEST_PRIORITY_obj;
73+
#endif
74+
75+
extern const mp_obj_fun_builtin_fixed_t mp_os_task_switch_is_pended_obj;
76+
77+
#endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
#include "py/obj.h"
3+
#include "py/runtime.h"
4+
5+
#include "freertos/FreeRTOS.h"
6+
#include "freertos/projdefs.h"
7+
8+
9+
#ifndef __PROJDEFS_H__
10+
#define __PROJDEFS_H__
11+
12+
extern const mp_obj_fun_builtin_fixed_t mp_pdMS_TO_TICKS_obj;
13+
extern const mp_obj_fun_builtin_fixed_t mp_pdTICKS_TO_MS_obj;
14+
#endif

0 commit comments

Comments
 (0)