Added thread rework, and cleaned up Tacos startup

This commit is contained in:
dario 2023-10-27 12:44:23 +02:00
parent 4efc0382f8
commit 5e23008b78
17 changed files with 194 additions and 52 deletions

View File

@ -5,7 +5,7 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="-647300400575309416" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1090266248531783773" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
@ -16,7 +16,7 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="-647300400575309416" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1090266248531783773" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>

View File

@ -31,7 +31,9 @@
// Settings for TACOS
#define STA_TACOS_MANAGER_PRIORITY osPriorityNormal
#define STA_TACOS_STATEMACHINE_PRIORITY osPriorityNormal
#define STA_TACOS_NUM_STATES 4
// Statemachine settings. Here, we only have a single state which is also the initial state.
#define STA_TACOS_NUM_STATES 1
#define STA_TACOS_INITIAL_STATE 0
#endif /* INC_STA_CONFIG_HPP_ */

View File

@ -12,6 +12,8 @@
#include <sta/tacos/manager.hpp>
#include <sta/tacos/statemachine.hpp>
#include <tasks/dummy.hpp>
#include <gpio.h>
#include <sta/devices/stm32/gpio_pin.hpp>
#include <memory>
@ -22,17 +24,47 @@ namespace sta
{
void onStatemachineInit()
{
STA_DEBUG_PRINTLN("Starting statemachine task!");
Statemachine::instance()->setStateFunction([](uint16_t state) -> uint16_t {
// ###### Implement your state transition function here! ######
/**
* This function should return some state within 0 and STA_TACOS_NUM_STATES (specified in the config.hpp).
* Return the same state as given as the argument for no state transition. Make sure, that this function is not
* computationally expensive.
*/
return state;
});
Statemachine::instance()->setTimerFunction([](uint16_t state, uint16_t lastState, uint32_t event) {
// ###### Set the failsafe and lockout timers here ######
/**
* This function is called after a state transition from lastState to state. Event corresponds to EventFlag enum in the Statemachine
* and encode how the state change happened.
*
* Setting a timer here is fully optional and depends on your system's specifications.
*/
uint32_t someFailsafeMillis = 42;
uint16_t someNextState = STA_TACOS_INITIAL_STATE;
uint32_t someLockoutMillis = 21;
// Start the failsafe timer to force a state transition to someNextState after someFailsafeMillis milliseconds.
Statemachine::instance()->setFailsafeTimer(someFailsafeMillis, someNextState);
// Start the lockout timer to block a state transition for the first someLockoutMillis milliseconds.
Statemachine::instance()->setLockoutTimer(someLockoutMillis);
});
}
void onManagerInit()
{
STA_DEBUG_PRINTLN("Starting manager task!");
// ###### Register different threads for different states here. ######
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("0"), {0});
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("1"), {1});
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("2"), {2});
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("3"), {3});
// The dummy task runs for state 0.
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("Dummy"), {0});
}
} // namespace tacos
} // namespace sta

View File

@ -29,8 +29,8 @@ namespace demo
void DummyTask::func()
{
STA_DEBUG_PRINTLN(this->getName());
// STA_DEBUG_PRINT("Executing ");
// STA_DEBUG_PRINTLN(this->getName());
osDelay(1000);
}
} // namespace demo

View File

@ -68,7 +68,7 @@
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES ( 56 )
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configMINIMAL_STACK_SIZE ((uint16_t)256)
#define configTOTAL_HEAP_SIZE ((size_t)15360)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
@ -77,6 +77,7 @@
#define configQUEUE_REGISTRY_SIZE 8
#define configCHECK_FOR_STACK_OVERFLOW 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configRECORD_STACK_HIGH_ADDRESS 1
@ -94,7 +95,7 @@
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 48 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256
#define configTIMER_TASK_STACK_DEPTH 512
/* The following flag must be enabled only when using newlib */
#define configUSE_NEWLIB_REENTRANT 1

View File

@ -222,7 +222,7 @@
/* Section 2: PHY configuration section */
/* DP83848_PHY_ADDRESS Address*/
#define DP83848_PHY_ADDRESS 0x01U
#define DP83848_PHY_ADDRESS
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY 0x000000FFU
/* PHY Configuration delay */
@ -252,10 +252,10 @@
#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */
#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
#define PHY_SR ((uint16_t)) /*!< PHY status register Offset */
#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
#define PHY_SPEED_STATUS ((uint16_t)) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)) /*!< PHY Duplex mask */
/* ################## SPI peripheral configuration ########################## */

View File

@ -75,6 +75,7 @@ void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* Hook prototypes */
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName);
void vApplicationMallocFailedHook(void);
/* USER CODE BEGIN 4 */
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
@ -85,6 +86,22 @@ void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
}
/* USER CODE END 4 */
/* USER CODE BEGIN 5 */
void vApplicationMallocFailedHook(void)
{
/* vApplicationMallocFailedHook() will only be called if
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
function that will get called if a call to pvPortMalloc() fails.
pvPortMalloc() is called internally by the kernel whenever a task, queue,
timer or semaphore is created. It is also called by various parts of the
demo application. If heap_1.c or heap_2.c are used, then the size of the
heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
to query the size of free heap space that remains (although it does not
provide information on how the remaining heap might be fragmented). */
}
/* USER CODE END 5 */
/**
* @brief FreeRTOS initialization
* @param None

View File

@ -99,6 +99,7 @@ int main(void)
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */

View File

@ -20,6 +20,7 @@
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

@ -1 +1 @@
Subproject commit d591560c95a4eae525cbbbdb4e4bc15642852473
Subproject commit 067a48c30953fb5ee2c9f442f9a93a062c16ac1e

42
TACOS-Demo Debug.cfg Normal file
View File

@ -0,0 +1,42 @@
# This is an genericBoard board with a single STM32F411RETx chip
#
# Generated by STM32CubeIDE
# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s)
source [find interface/stlink-dap.cfg]
set WORKAREASIZE 0x8000
transport select "dapdirect_swd"
set CHIPNAME STM32F411RETx
set BOARDNAME genericBoard
# Enable debug when in low power modes
set ENABLE_LOW_POWER 1
# Stop Watchdog counters when halt
set STOP_WATCHDOG 1
# STlink Debug clock frequency
set CLOCK_FREQ 8000
# Reset configuration
# use hardware reset, connect under reset
# connect_assert_srst needed if low power mode application running (WFI...)
reset_config srst_only srst_nogate connect_assert_srst
set CONNECT_UNDER_RESET 1
set CORE_RESET 0
# ACCESS PORT NUMBER
set AP_NUM 0
# GDB PORT
set GDB_PORT 3333
# BCTM CPU variables
source [find target/stm32f4x.cfg]

View File

@ -3,12 +3,14 @@ CAD.formats=
CAD.pinconfig=
CAD.provider=
FREERTOS.FootprintOK=true
FREERTOS.IPParameters=Tasks01,configUSE_NEWLIB_REENTRANT,configRECORD_STACK_HIGH_ADDRESS,configCHECK_FOR_STACK_OVERFLOW,Mutexes01,FootprintOK,configTIMER_TASK_PRIORITY
FREERTOS.IPParameters=Tasks01,configUSE_NEWLIB_REENTRANT,configRECORD_STACK_HIGH_ADDRESS,configCHECK_FOR_STACK_OVERFLOW,Mutexes01,FootprintOK,configTIMER_TASK_PRIORITY,configMINIMAL_STACK_SIZE,configUSE_MALLOC_FAILED_HOOK
FREERTOS.Mutexes01=uartMutex,Static,uartMutex_cb
FREERTOS.Tasks01=defaultTask,24,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
FREERTOS.configCHECK_FOR_STACK_OVERFLOW=1
FREERTOS.configMINIMAL_STACK_SIZE=256
FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1
FREERTOS.configTIMER_TASK_PRIORITY=48
FREERTOS.configUSE_MALLOC_FAILED_HOOK=1
FREERTOS.configUSE_NEWLIB_REENTRANT=1
File.Version=6
KeepUserPlacement=false
@ -28,8 +30,8 @@ Mcu.PinsNb=3
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F411RETx
MxCube.Version=6.8.0
MxDb.Version=DB.6.0.80
MxCube.Version=6.9.2
MxDb.Version=DB.6.0.92
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
NVIC.ForceEnableDMAVector=true
@ -76,6 +78,8 @@ ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=STM32CubeIDE
ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=true
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_USART2_UART_Init-USART2-false-HAL-true
RCC.AHBFreq_Value=16000000

View File

@ -42,7 +42,7 @@ namespace sta
namespace tacos
{
typedef std::function<uint16_t(uint16_t)> state_fn;
typedef std::function<void(uint16_t, uint16_t, uint16_t)> timer_fn;
typedef std::function<void(uint16_t, uint16_t, uint32_t)> timer_fn;
class Statemachine : public TacosThread
@ -135,6 +135,7 @@ namespace sta
private:
uint16_t currentState_;
uint16_t failsafeState_;
RtosTimer lockoutTimer_;
RtosTimer failsafeTimer_;

View File

@ -61,13 +61,16 @@ namespace sta
/**
* @brief This function is executed first when this thread is started.
*/
virtual void init() = 0;
virtual void init();
/**
* @brief The body of the thread's loop. Has to be implemented by the user.
*/
virtual void func() = 0;
virtual void cleanup();
private:
/**
@ -75,8 +78,10 @@ namespace sta
*/
static void entry_point(void* arg);
private:
osThreadId_t instance_;
osThreadAttr_t attribs_;
bool running_;
};
}
}

View File

@ -11,6 +11,8 @@
#include <algorithm>
#include <FreeRTOS.h>
namespace sta
{
@ -41,6 +43,8 @@ namespace sta
void Manager::stopThreads(uint16_t state)
{
std::set<std::shared_ptr<TacosThread>> terminated;
for (uint16_t other = 0; other < STA_TACOS_NUM_STATES; ++other)
{
if (other == state)
@ -51,13 +55,11 @@ namespace sta
for (std::shared_ptr<TacosThread> thread : threads_[other])
{
// If the thread is currently running but not part of the set of threads that should be running...
if (thread->isRunning() && threads_[state].count(thread) == 0)
if (thread->isRunning() && terminated.count(thread) == 0 && threads_[state].count(thread) == 0)
{
// ...politely request termination.
thread->requestTermination();
STA_DEBUG_PRINT("KILLING ");
STA_DEBUG_PRINTLN(thread->getName());
terminated.emplace(thread);
}
}
}
@ -67,8 +69,8 @@ namespace sta
{
uint16_t state = Statemachine::instance()->getCurrentState();
startThreads(state);
stopThreads(state);
startThreads(state);
}
void Manager::init()
@ -80,8 +82,6 @@ namespace sta
{
Statemachine::stateChangeEvent.wait(Statemachine::EventFlags::ALL, osWaitForever);
STA_DEBUG_PRINTLN("UPDATING THREADS");
// Start all new tasks and stop all the tasks that aren't supposed to be running.
updateThreads();
}

View File

@ -17,6 +17,7 @@ namespace sta
Statemachine::Statemachine()
: TacosThread{"Statemachine", STA_TACOS_STATEMACHINE_PRIORITY},
currentState_{STA_TACOS_INITIAL_STATE},
failsafeState_{STA_TACOS_INITIAL_STATE},
lockoutTimer_{[](void *){}, nullptr},
failsafeTimer_{[](void *){}, nullptr},
transitionFunc_{[](uint16_t) -> uint16_t { return Statemachine::instance()->getCurrentState(); }},
@ -39,15 +40,21 @@ namespace sta
// Check if a state change is desired. Block if the lockoutTimer is still running.
if (next != currentState_ && !lockoutTimer_.isRunning())
{
if (failsafeTimer_.isRunning())
{
failsafeTimer_.stop();
}
// Call user space code to set the timers again.
timerFunc_(next, currentState_, EventFlags::NORMAL);
// Update the state and trigger the global state changed event.
currentState_ = next;
Statemachine::stateChangeEvent.set(EventFlags::NORMAL);
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
}
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
osThreadYield();
}
uint16_t Statemachine::getCurrentState() const
@ -74,16 +81,16 @@ namespace sta
STA_ASSERT(nextState < STA_TACOS_NUM_STATES);
STA_ASSERT(!failsafeTimer_.isRunning());
failsafeTimer_.setCallback([nextState](void *) {
failsafeTimer_.setCallback([nextState](void* arg) {
Statemachine::instance()->forceStateTransition(nextState);
}, nullptr);
}, &failsafeState_);
failsafeTimer_.start(millis);
}
void Statemachine::setLockoutTimer(uint32_t millis)
{
STA_ASSERT(!failsafeTimer_.isRunning());
STA_ASSERT(!lockoutTimer_.isRunning());
lockoutTimer_.setCallback([](void *) { }, nullptr);
lockoutTimer_.start(millis);
@ -91,6 +98,17 @@ namespace sta
void Statemachine::forceStateTransition(uint16_t state)
{
if (failsafeTimer_.isRunning())
{
failsafeTimer_.stop();
}
if (lockoutTimer_.isRunning())
{
lockoutTimer_.stop();
}
timerFunc_(state, currentState_, EventFlags::FORCED);
currentState_ = state;
Statemachine::stateChangeEvent.set(EventFlags::FORCED);

View File

@ -22,13 +22,15 @@ namespace sta
TacosThread::TacosThread(const char* name, osPriority_t prio)
: RtosThread(RtosHandle<osThreadId_t>(Handle::Deferred(&instance_))),
instance_{ NULL },
attribs_{ .name = name, .priority = prio }
attribs_{ .name = name, .priority = prio },
running_{false}
{}
TacosThread::TacosThread()
: RtosThread(RtosHandle<osThreadId_t>(Handle::Deferred(&instance_))),
instance_{ NULL },
attribs_{ }
attribs_{ },
running_{false}
{}
void TacosThread::entry_point(void* arg)
@ -43,16 +45,21 @@ namespace sta
{
STA_ASSERT(!isRunning());
instance_ = osThreadNew(entry_point, this, &attribs_);
// If this is the first time starting the thread, it has to be started via rtos first.
if (instance_ == NULL)
{
instance_ = osThreadNew(entry_point, this, &attribs_);
STA_ASSERT(instance_ != NULL);
STA_ASSERT(instance_ != NULL);
}
// SetFlag(THREAD_START);
// Send a thread start signal.
sysNotify(STA_RTOS_THREAD_FLAG_START);
}
bool TacosThread::isRunning()
{
return instance_ != NULL;
return running_;
}
osThreadId_t TacosThread::getInstance()
@ -67,26 +74,37 @@ namespace sta
return attribs_.name;
}
void TacosThread::init() {}
void TacosThread::loop()
{
// The thread has to wait until the startup has been completed.
rtos::waitForStartupEvent();
// wait(THREAD_START)
init();
// Run the thread until the termination flag is set.
while ((getFlags() & STA_RTOS_THREAD_FLAG_TERMINATE) == 0)
// Infinite loop allowing quick restarts of this thread after termination.
while (true)
{
func();
}
// The thread has to wait until the startup has been completed.
rtos::waitForStartupEvent();
instance_ = NULL;
// Wait for a thread start flag.
wait(STA_RTOS_THREAD_FLAG_START);
running_ = true;
init();
// Run the thread until the termination flag is set.
while (!checkTerminationRequest())
{
func();
}
cleanup();
running_ = false;
}
osThreadExit();
}
void TacosThread::cleanup() {}
bool TacosThread::operator==(const TacosThread& other) const
{
return std::strcmp(this->getName(), other.getName()) == 0;