Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for STM32 #302

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6de22f6
initial test for support for STM32
naichenzhao Nov 7, 2023
256abcc
Point to lingua-franca stm32 branch
lhstrh Nov 7, 2023
92fcfbe
fixed typo
naichenzhao Nov 11, 2023
dca5be8
please merge
naichenzhao Nov 11, 2023
89986a9
hard coded STM32 support
naichenzhao Nov 11, 2023
436b36b
we dont need STM_main anymore
naichenzhao Nov 19, 2023
bcbbf43
updated files to move stuff out of core cmake
naichenzhao Nov 22, 2023
48be057
fixed printing
naichenzhao Dec 7, 2023
31d62b2
changed naming
naichenzhao Dec 18, 2023
73aea2e
updated sleep functions
naichenzhao Jul 15, 2024
7899e6b
updated delay functions
naichenzhao Jul 15, 2024
d11f3ff
rebased in main
naichenzhao Aug 5, 2024
58d2323
change
naichenzhao Aug 5, 2024
5ae3be6
fixed typo
naichenzhao Nov 11, 2023
4bb9231
bruh
naichenzhao Aug 5, 2024
9527537
we dont need STM_main anymore
naichenzhao Nov 19, 2023
8a97bcd
changes
naichenzhao Aug 5, 2024
c46fbcc
fixed printing
naichenzhao Dec 7, 2023
b3097a8
changed naming
naichenzhao Dec 18, 2023
f92307f
updated sleep functions
naichenzhao Jul 15, 2024
f2554dd
updated delay functions
naichenzhao Jul 15, 2024
03124a5
merge
naichenzhao Aug 5, 2024
6d2964c
Merge branch 'stm32' of github.com:lf-lang/reactor-c into stm32
naichenzhao Aug 5, 2024
13ca0d8
Merge branch 'main' of github.com:lf-lang/reactor-c into stm32
naichenzhao Aug 31, 2024
cd0c9c1
quick commit
naichenzhao Aug 31, 2024
6d8d4db
Suppress unused parameter error
edwardalee Aug 9, 2024
bb75db6
Suppress unused parameter error
edwardalee Aug 9, 2024
6a66f47
deleted artifact from rebase
naichenzhao Aug 31, 2024
a285e52
works with newest version
naichenzhao Aug 31, 2024
6ba0f42
did formatting
naichenzhao Sep 7, 2024
a22a4fd
Update low_level_platform/api/platform/lf_STM32f4_support.h
naichenzhao Sep 16, 2024
42fc271
Update low_level_platform/api/platform/lf_STM32f4_support.h
naichenzhao Sep 16, 2024
895a8fb
Update low_level_platform/impl/src/lf_STM32f4_support.c
naichenzhao Sep 16, 2024
0d3af6d
Update low_level_platform/api/platform/lf_STM32f4_support.h
naichenzhao Sep 16, 2024
50603d7
Update low_level_platform/impl/src/lf_STM32f4_support.c
naichenzhao Sep 16, 2024
cba9193
resolved some more comments
naichenzhao Sep 17, 2024
cf36f59
changed macro
naichenzhao Sep 24, 2024
6e9e3c7
Merge branch 'main' into stm32
naichenzhao Oct 4, 2024
6974d8e
Merge branch 'main' into stm32
naichenzhao Oct 5, 2024
a2e1e4b
Merge branch 'stm32' of https://github.com/lf-lang/reactor-c into stm32
naichenzhao Oct 5, 2024
68ec2d7
Run clang-format
erlingrj Oct 5, 2024
2d23659
Update lf-ref to the new lf branch
erlingrj Oct 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,4 @@ define(LF_PACKAGE_DIRECTORY)
define(LF_FILE_SEPARATOR)
define(WORKERS_NEEDED_FOR_FEDERATE)
define(LF_ENCLAVES)

3 changes: 2 additions & 1 deletion lingua-franca-ref.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
master
stm32

30 changes: 30 additions & 0 deletions low_level_platform/api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,36 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")
target_link_libraries(lf-low-level-platform-api INTERFACE pico_stdlib)
target_link_libraries(lf-low-level-platform-api INTERFACE pico_multicore)
target_link_libraries(lf-low-level-platform-api INTERFACE pico_sync)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Stm32")
set(STM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../STM_sdk)
set(MCU_FAMILY STM32F4xx)
set(MCU_MODEL STM32F446xx)
set(CPU_PARAMETERS -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=softfp)

file(GLOB_RECURSE STM32CUBEMX_SOURCES ${STM_DIR}/Core/*.c ${STM_DIR}/Drivers/${MCU_FAMILY}_HAL_Driver/*.c)
set(CUBEMX_INCLUDE_DIRECTORIES
${STM_DIR}/Core/Inc
${STM_DIR}/Drivers/${MCU_FAMILY}_HAL_Driver/Inc
${STM_DIR}/Drivers/CMSIS/Device/ST/${MCU_FAMILY}/Include
${STM_DIR}/Drivers/CMSIS/Include
)
target_compile_options(lf-low-level-platform-api INTERFACE
${CPU_PARAMETERS}
-Wall
-Wextra
-Wpedantic
-Wno-unused-parameter
$<$<COMPILE_LANGUAGE:CXX>:
-Wno-volatile
-Wold-style-cast
-Wuseless-cast
-Wsuggest-override>
$<$<CONFIG:Debug>:-Og -g3 -ggdb>
$<$<CONFIG:Release>:-Og -g0>)

target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_STM32F4)
target_include_directories(lf-low-level-platform-api INTERFACE ${CUBEMX_INCLUDE_DIRECTORIES})
target_compile_definitions(lf-low-level-platform-api INTERFACE ${MCU_MODEL} USE_HAL_DRIVER)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET")
target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET)
target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk)
Expand Down
2 changes: 2 additions & 0 deletions low_level_platform/api/low_level_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ int lf_critical_section_exit(environment_t* env);
#include "platform/lf_patmos_support.h"
#elif defined(PLATFORM_RP2040)
#include "platform/lf_rp2040_support.h"
#elif defined(PLATFORM_STM32F4)
#include "platform/lf_STM32f4_support.h"
#elif defined(PLATFORM_FLEXPRET)
#include "platform/lf_flexpret_support.h"
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
Expand Down
23 changes: 23 additions & 0 deletions low_level_platform/api/platform/lf_STM32f4_support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* STM32 API support for the C target of Lingua Franca. */

#ifndef LF_STM32F4_SUPPORT_H
#define LF_STM32F4_SUPPORT_H

// I have no idea what the fuck TTY is so i guess we dont support it
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
#define NO_TTY

#include <stm32f4xx_hal.h>

// Defines for formatting time in printf for pico
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
#define PRINTF_TAG "(" PRINTF_TIME ", " PRINTF_MICROSTEP ")"
#define PRINTF_TIME "%lld"
#define PRINTF_MICROSTEP "%d"

#define LF_TIME_BUFFER_LENGTH 80
#define _LF_TIMEOUT 1

#ifdef LF_THREADED
#error "I have no idea how to support threading"
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
#endif // LF_THREADED

#endif
5 changes: 5 additions & 0 deletions low_level_platform/impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")
${CMAKE_CURRENT_LIST_DIR}/src/lf_rp2040_support.c
${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c
)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Stm32")
set(LF_LOW_LEVEL_PLATFORM_FILES
${CMAKE_CURRENT_LIST_DIR}/src/lf_STM32f4_support.c
${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c
)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET")
set(LF_LOW_LEVEL_PLATFORM_FILES
${CMAKE_CURRENT_LIST_DIR}/src/lf_flexpret_support.c
Expand Down
238 changes: 238 additions & 0 deletions low_level_platform/impl/src/lf_STM32f4_support.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#if defined(PLATFORM_STM32F4)

#include "platform/lf_STM32f4_support.h"
#include "low_level_platform.h"
#include "tag.h"

// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
// | Important defines and global variables
// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +

static volatile bool _lf_sleep_interrupted = false;
static volatile bool _lf_async_event = false;

// nested critical section counter
static uint32_t _lf_num_nested_crit_sec = 0;

// Timer upper half (for overflow)
static uint32_t _lf_time_us_high = 0;

#define LF_MIN_SLEEP_NS 10

// Combine 2 32bit works to a 64 bit word (Takes from nrf52 support)
#define COMBINE_HI_LO(hi, lo) ((((uint64_t)hi) << 32) | ((uint64_t)lo))

void lf_SystemClock_Config();
void Error_Handler();

// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
// | Code for timer functions
// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
// We use timer 5 for our clock (probably better than dealing with sysTick)
void _lf_initialize_clock(void) {
// Standard initializations from generated code
HAL_Init();
lf_SystemClock_Config();

// Configure TIM5 as our 32-bit clock timer
__HAL_RCC_TIM5_CLK_ENABLE(); // initialize counter
TIM5->CR1 = TIM_CR1_CEN; // enable counter

// set prescaler to (16 - 1) = 15
// CPU runs a 16MHz so timer ticks at 1MHz
// Which means period of 1 microsecond
TIM5->PSC = 15;

// Setup ISR to increment upper bits
TIM5->DIER |= TIM_DIER_CC1IE;
NVIC_EnableIRQ(TIM5_IRQn);

/* This is to make the Prescaler actually work
erlingrj marked this conversation as resolved.
Show resolved Hide resolved
* For some reason, the Prescaler only kicks in once the timer has reset once.
* Thus, the current solution is to manually ret the value to a really large
* and force it to reset once. Its really jank but its the only way I could
* find to make it work
*/
TIM5->CNT = 0xFFFFFFFE;
}

// ISR for handling timer overflow -> We increment the upper timer
void TIM5_IRQHandler(void) {
if (TIM5->SR & (1 << 1)) {
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
TIM5->SR &= ~(1 << 1);
_lf_time_us_high += 1;
}
}

/**
* Write the time since boot into time variable
*/
int _lf_clock_gettime(instant_t* t) {
// Timer is cooked
if (!t) {
return 1;
}
// Get the current microseconds from TIM5
uint32_t _lf_time_us_low = TIM5->CNT;
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved

// Combine upper and lower timers (Yoinked from lf_nrf52 support)
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
uint64_t now_us = COMBINE_HI_LO((_lf_time_us_high - 1), _lf_time_us_low);
*t = ((instant_t)now_us) * 1000;
return 0;
}

/**
* Make the STM32 sleep for set nanoseconds
* Based on the lf_nrf52 support implementation
*/
int lf_sleep(interval_t sleep_duration) {
instant_t target_time;
instant_t current_time;

_lf_clock_gettime(&current_time);
target_time = current_time + sleep_duration;
// HAL_Delay only supports miliseconds. We try to use that for as long as possible
// before switching to another meothd for finer tuned delay times
long delaytime_ms = sleep_duration / 1000000;
HAL_Delay(delaytime_ms);

while (current_time <= target_time)
_lf_clock_gettime(&current_time);

return 0;
}

/**
* Make the STM32 sleep for set nanoseconds
* Based on the lf_nrf52 support implementation
*/
static void lf_busy_wait_until(instant_t wakeup_time) {
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
instant_t current_time;
_lf_clock_gettime(&current_time);

// We repurpose the lf_sleep function here, just to better streamline the code
interval_t sleep_duration = wakeup_time - current_time;
lf_sleep(sleep_duration);
}

// I am pretty sure this function doesnt work
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
/* sleep until wakeup time but wake up if there is an async event
*/
int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) {
// Get the current time and sleep time
instant_t now;
_lf_clock_gettime(&now);
interval_t duration = wakeup_time - now;

// Edge case handling for super small duration
if (duration <= 0) {
return 0;
} else if (duration < LF_MIN_SLEEP_NS) {
lf_busy_wait_until(wakeup_time);
return 0;
}

// Enable interrupts and prepare to wait
_lf_async_event = false;
lf_enable_interrupts_nested();

do {
_lf_clock_gettime(&now);
// Exit when the timer is up or there is an exception
} while (!_lf_async_event && (now < wakeup_time));
Comment on lines +141 to +144
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be low-power sleep, not busy-waiting. Is there anything in the HAL for doing low-power sleep?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be a low power sleep mode, but its only interrupt based. It seems most timed delay implementations just use a while loop. Im not sure it itll be worth it trying to create some workaround now? or just merge now and maybe improve the implementation later.


// Disable interrupts again on exit
lf_disable_interrupts_nested();

if (!_lf_async_event) {
return 0;
} else {
return 1;
}
}

// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
// | Code for enabling and disabling Interrupts
// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +

// disables the IRQ (checks if its already disabled)
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
int lf_disable_interrupts_nested() {
// Disable interrupts if they are currently enabled
if (_lf_num_nested_crit_sec == 0) {
__disable_irq();
}

// update the depth of disabling interrupts
_lf_num_nested_crit_sec++;
return 0;
}

// enables the IRQ (checks if other programs still want it disabled first)
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
int lf_enable_interrupts_nested() {
// Left the critical section more often than it was entered.

if (_lf_num_nested_crit_sec <= 0) {
return 1;
}

// update the depth of disabling interrupts
_lf_num_nested_crit_sec--;

// If we have exited all important programs, we can enable them again
naichenzhao marked this conversation as resolved.
Show resolved Hide resolved
if (_lf_num_nested_crit_sec == 0) {
__enable_irq();
}
return 0;
}

int _lf_single_threaded_notify_of_event() {
_lf_async_event = true;
return 0;
}

// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
// | Other functions -> taken from the generated main.c
// + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
void lf_SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}

/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
Error_Handler();
}
}

void Error_Handler(void) {
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1) {
}
/* USER CODE END Error_Handler_Debug */
}

#endif
2 changes: 1 addition & 1 deletion low_level_platform/impl/src/lf_atomic_irq.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_NRF52) || defined(PLATFORM_ZEPHYR) || defined(PLATFORM_RP2040) || \
defined(PLATFORM_FLEXPRET) || defined(PLATFORM_PATMOS)
defined(PLATFORM_FLEXPRET) || defined(PLATFORM_PATMOS) || defined(PLATFORM_STM32F4)
/**
* @author Erling Rennemo Jellum
* @copyright (c) 2023
Expand Down
6 changes: 2 additions & 4 deletions tag/api/tag.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,11 @@
#define NEVER_TAG \
(tag_t) { .time = NEVER, .microstep = NEVER_MICROSTEP }
// Need a separate initializer expression to comply with some C compilers
#define NEVER_TAG_INITIALIZER \
{ NEVER, NEVER_MICROSTEP }
#define NEVER_TAG_INITIALIZER {NEVER, NEVER_MICROSTEP}
#define FOREVER_TAG \
(tag_t) { .time = FOREVER, .microstep = FOREVER_MICROSTEP }
// Need a separate initializer expression to comply with some C compilers
#define FOREVER_TAG_INITIALIZER \
{ FOREVER, FOREVER_MICROSTEP }
#define FOREVER_TAG_INITIALIZER {FOREVER, FOREVER_MICROSTEP}
#define ZERO_TAG \
(tag_t) { .time = 0LL, .microstep = 0u }

Expand Down
Loading