Skip to content

Commit

Permalink
Added Timebase fix, so now systick uses timer 6. Works in the kernel …
Browse files Browse the repository at this point in the history
…and prior to the kernel being initialized. Also fixed a ThreadUART bug with the mutex (they weren't being initialized)
  • Loading branch information
aclowmclaughlin committed Dec 6, 2024
1 parent 41e011b commit ea9dc00
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 5 deletions.
15 changes: 11 additions & 4 deletions samples/rtos/threadx-demo/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ int main() {

// Setup UART
io::UART& uart = io::getUART<io::Pin::UART_TX, io::Pin::UART_RX>(9600);

//this verifies that we have correctly replaced systick with timer 6, because ThreadX takes over systick to run
//the kernel. time::wait() calls on the time_base timer, which should no longer be systick
uart.printf("Waiting...\n\r");
time::wait(1000);
uart.printf("Waited\n\r");

rtos::tsio::ThreadUART threadUART(uart);

log::LOGGER.setUART(&threadUART);
Expand All @@ -118,7 +125,7 @@ int main() {
generatorThreadEntry,
&generatorThreadArgs,
DEMO_STACK_SIZE,
1,
2,
1,
MS_TO_TICKS(50),
true);
Expand All @@ -132,13 +139,13 @@ int main() {

// create thread1
rtos::Thread<numberConsumerThreadArgs*> thread1(
(char*) "Thread 1", consumerThreadEntry, &thread_1_args, DEMO_STACK_SIZE, 1, 1, MS_TO_TICKS(50), true);
(char*) "Thread 1", consumerThreadEntry, &thread_1_args, DEMO_STACK_SIZE, 2, 1, MS_TO_TICKS(50), true);
// create thread2
rtos::Thread<numberConsumerThreadArgs*> thread2(
(char*) "Thread 2", consumerThreadEntry, &thread_2_args, DEMO_STACK_SIZE, 1, 1, MS_TO_TICKS(50), true);
(char*) "Thread 2", consumerThreadEntry, &thread_2_args, DEMO_STACK_SIZE, 2, 1, MS_TO_TICKS(50), true);
// create thread3
rtos::Thread<numberConsumerThreadArgs*> eventFlagThread(
(char*) "Thread 3", eventFlagThreadEntry, &thread_3_args, DEMO_STACK_SIZE, 1, 1, MS_TO_TICKS(50), true);
(char*) "Thread 3", eventFlagThreadEntry, &thread_3_args, DEMO_STACK_SIZE, 2, 1, MS_TO_TICKS(50), true);

uart.printf("\n\rAbout to start the kernel.\n\r");

Expand Down
131 changes: 131 additions & 0 deletions src/core/rtos/Threadx.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <core/rtos/BytePool.hpp>
#include <core/rtos/Threadx.hpp>
#include <core/utils/log.hpp>
#include <core/dev/platform/f4xx/Timerf4xx.hpp>
#include <../libs/HALf4/include/HALf4/stm32f4xx_hal.h>
#include <../libs/HALf4/include/HALf4/stm32f4xx_hal_tim.h>

namespace log = core::log;

Expand Down Expand Up @@ -59,3 +62,131 @@ TXError sleep(uint32_t sleepTime) {
}

} // namespace core::rtos

/********************************************/
/** SYSTICK OVERRIDE TO TIMER 6 **/
/********************************************/


TIM_HandleTypeDef htim6;

/**
* @brief This function configures the TIM6 as a time base source.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
* @param TickPriority: Tick interrupt priority.
* @retval HAL status
*/
extern "C" HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock, uwAPB1Prescaler = 0U;

uint32_t uwPrescalerValue = 0U;
uint32_t pFLatency;
HAL_StatusTypeDef status;

/* Enable TIM6 clock */
__HAL_RCC_TIM6_CLK_ENABLE();

/* Get clock configuration */
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);

/* Get APB1 prescaler */
uwAPB1Prescaler = clkconfig.APB1CLKDivider;
/* Compute TIM6 clock */
if (uwAPB1Prescaler == RCC_HCLK_DIV1)
{
uwTimclock = HAL_RCC_GetPCLK1Freq();
}
else
{
uwTimclock = 2UL * HAL_RCC_GetPCLK1Freq();
}

/* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);

/* Initialize TIM6 */
htim6.Instance = TIM6;

/* Initialize TIMx peripheral as follow:
+ Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base.
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
+ ClockDivision = 0
+ Counter direction = Up
*/
htim6.Init.Period = (1000000U / 1000U) - 1U;
htim6.Init.Prescaler = uwPrescalerValue;
htim6.Init.ClockDivision = 0;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

status = HAL_TIM_Base_Init(&htim6);
if (status == HAL_OK)
{
/* Start the TIM time Base generation in interrupt mode */
status = HAL_TIM_Base_Start_IT(&htim6);
if (status == HAL_OK)
{
/* Enable the TIM6 global Interrupt */
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
/* Configure the TIM IRQ priority */
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority, 0U);
uwTickPrio = TickPriority;
}
else
{
status = HAL_ERROR;
}
}
}

/* Return function status */
return status;
}

/**
* @brief Suspend Tick increment.
* @note Disable the tick increment by disabling TIM6 update interrupt.
* @param None
* @retval None
*/
extern "C" void HAL_SuspendTick(void)
{
/* Disable TIM6 update Interrupt */
__HAL_TIM_DISABLE_IT(&htim6, TIM_IT_UPDATE);
}

/**
* @brief Resume Tick increment.
* @note Enable the tick increment by Enabling TIM6 update interrupt.
* @param None
* @retval None
*/
extern "C" void HAL_ResumeTick(void)
{
/* Enable TIM6 Update interrupt */
__HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE);
}

extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM6) {
HAL_IncTick();
}
}

/**
* @brief This function handles TIM6 global interrupt and DAC1, DAC2 underrun error interrupts.
*/
extern "C" void TIM6_DAC_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim6);
}
19 changes: 18 additions & 1 deletion src/core/rtos/tsio/ThreadUART.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,24 @@ TXError ThreadUART::init(BytePoolBase& pool) {
log::Logger::LogLevel::ERROR, "Errored on ThreadUART Queue initialization. Error code %u\n", status);
return static_cast<TXError>(status);
}
status = writeMutex.init(pool);
if (status != TXE_SUCCESS) {
log::LOGGER.log(
log::Logger::LogLevel::ERROR, "Errored on ThreadUART Write Mutex initialization. Error code %u\n", status);
return static_cast<TXError>(status);
}
status = readMutex.init(pool);
if (status != TXE_SUCCESS) {
log::LOGGER.log(
log::Logger::LogLevel::ERROR, "Errored on ThreadUART Read Mutex initialization. Error code %u\n", status);
return static_cast<TXError>(status);
}
status = thread.init(pool);
if (status != TXE_SUCCESS) {
log::LOGGER.log(
log::Logger::LogLevel::ERROR, "Errored on ThreadUART Thread initialization. Error code %u\n", status);
return static_cast<TXError>(status);
}
return static_cast<TXError>(status);
}

Expand Down Expand Up @@ -144,7 +161,7 @@ void ThreadUART::write(uint8_t byte) {

void ThreadUART::sendFirstQueueMessage() {
char buffer[THREADUART_QUEUE_MESSAGE_SIZE_BYTES]; // Buffer array to hold the message
queue.receive(buffer, TXW_WAIT_FOREVER); // Receives the message and assigns it to the buffer variable
queue.receive(buffer, TXW_WAIT_FOREVER);// Receives the message and assigns it to the buffer variable
copyUART.writeBytes((uint8_t*) (buffer), strlen(buffer));
}

Expand Down

0 comments on commit ea9dc00

Please sign in to comment.