diff --git a/libuavcan_drivers/stm32/driver/include/uavcan_stm32/build_config.hpp b/libuavcan_drivers/stm32/driver/include/uavcan_stm32/build_config.hpp index b3bf403594..0160cc662d 100644 --- a/libuavcan_drivers/stm32/driver/include/uavcan_stm32/build_config.hpp +++ b/libuavcan_drivers/stm32/driver/include/uavcan_stm32/build_config.hpp @@ -19,6 +19,10 @@ # define UAVCAN_STM32_BAREMETAL 0 #endif +#ifndef UAVCAN_STM32_FREERTOS +# define UAVCAN_STM32_FREERTOS 0 +#endif + /** * Number of interfaces must be enabled explicitly */ diff --git a/libuavcan_drivers/stm32/driver/include/uavcan_stm32/thread.hpp b/libuavcan_drivers/stm32/driver/include/uavcan_stm32/thread.hpp index ab7d25cc23..ee18eea0ae 100644 --- a/libuavcan_drivers/stm32/driver/include/uavcan_stm32/thread.hpp +++ b/libuavcan_drivers/stm32/driver/include/uavcan_stm32/thread.hpp @@ -17,6 +17,8 @@ # include # include #elif UAVCAN_STM32_BAREMETAL +#elif UAVCAN_STM32_FREERTOS +# include #else # error "Unknown OS" #endif @@ -136,7 +138,7 @@ public: (void)can_driver; } - bool wait(uavcan::MonotonicDuration) + bool wait(uavcan::MonotonicDuration duration) { (void)duration; bool lready = ready; @@ -161,6 +163,42 @@ public: void unlock() { } }; +#elif UAVCAN_STM32_FREERTOS + +class BusEvent +{ + SemaphoreHandle_t sem_; + BaseType_t higher_priority_task_woken; + +public: + BusEvent(CanDriver& can_driver) + { + (void)can_driver; + sem_ = xSemaphoreCreateBinary(); + } + + bool wait(uavcan::MonotonicDuration duration); + + void signal(); + + void signalFromInterrupt(); + + void yieldFromISR(); +}; + +class Mutex +{ + SemaphoreHandle_t mtx_; + +public: + Mutex(void) + { + mtx_ = xSemaphoreCreateMutex(); + } + void lock(); + void unlock(); +}; + #endif diff --git a/libuavcan_drivers/stm32/driver/src/internal.hpp b/libuavcan_drivers/stm32/driver/src/internal.hpp index 2bdee57a66..80e3864b06 100644 --- a/libuavcan_drivers/stm32/driver/src/internal.hpp +++ b/libuavcan_drivers/stm32/driver/src/internal.hpp @@ -15,6 +15,9 @@ # include #elif UAVCAN_STM32_BAREMETAL # include +#elif UAVCAN_STM32_FREERTOS +# include +# include #else # error "Unknown OS" #endif @@ -71,6 +74,15 @@ # endif #endif +#if UAVCAN_STM32_FREERTOS +/** + * Priority mask for timer and CAN interrupts. + */ +# ifndef UAVCAN_STM32_IRQ_PRIORITY_MASK +# define UAVCAN_STM32_IRQ_PRIORITY_MASK configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY +# endif +#endif + /** * Glue macros */ @@ -122,6 +134,22 @@ struct CriticalSectionLocker } }; +#elif UAVCAN_STM32_FREERTOS + +struct CriticalSectionLocker +{ + + CriticalSectionLocker() + { + taskENTER_CRITICAL(); + } + + ~CriticalSectionLocker() + { + taskEXIT_CRITICAL(); + } +}; + #endif namespace clock diff --git a/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp b/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp index 40a5888725..27a5c24967 100644 --- a/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp +++ b/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp @@ -16,6 +16,7 @@ # include #elif UAVCAN_STM32_BAREMETAL #include +#elif UAVCAN_STM32_FREERTOS #else # error "Unknown OS" #endif @@ -200,11 +201,13 @@ int CanIface::computeTimings(const uavcan::uint32_t target_bitrate, Timings& out * Hardware configuration */ #if UAVCAN_STM32_BAREMETAL - const uavcan::uint32_t pclk = STM32_PCLK1_FREQUENCY; + const uavcan::uint32_t pclk = STM32_PCLK1; #elif UAVCAN_STM32_CHIBIOS const uavcan::uint32_t pclk = STM32_PCLK1; #elif UAVCAN_STM32_NUTTX const uavcan::uint32_t pclk = STM32_PCLK1_FREQUENCY; +#elif UAVCAN_STM32_FREERTOS + const uavcan::uint32_t pclk = HAL_RCC_GetPCLK1Freq(); #else # error "Unknown OS" #endif @@ -454,7 +457,7 @@ uavcan::int16_t CanIface::configureFilters(const uavcan::CanFilterConfig* filter bool CanIface::waitMsrINakBitStateChange(bool target_state) { -#if UAVCAN_STM32_NUTTX || UAVCAN_STM32_CHIBIOS +#if UAVCAN_STM32_NUTTX || UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_FREERTOS const unsigned Timeout = 1000; #else const unsigned Timeout = 2000000; @@ -471,6 +474,9 @@ bool CanIface::waitMsrINakBitStateChange(bool target_state) #endif #if UAVCAN_STM32_CHIBIOS ::chThdSleep(MS2ST(1)); +#endif +#if UAVCAN_STM32_FREERTOS + ::osDelay(1); #endif } return false; @@ -617,6 +623,10 @@ void CanIface::handleTxInterrupt(const uavcan::uint64_t utc_usec) update_event_.signalFromInterrupt(); pollErrorFlagsFromISR(); + + #if UAVCAN_STM32_FREERTOS + update_event_.yieldFromISR(); + #endif } void CanIface::handleRxInterrupt(uavcan::uint8_t fifo_index, uavcan::uint64_t utc_usec) @@ -680,6 +690,10 @@ void CanIface::handleRxInterrupt(uavcan::uint8_t fifo_index, uavcan::uint64_t ut update_event_.signalFromInterrupt(); pollErrorFlagsFromISR(); + + #if UAVCAN_STM32_FREERTOS + update_event_.yieldFromISR(); + #endif } void CanIface::pollErrorFlagsFromISR() @@ -861,16 +875,21 @@ uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks, } -#if UAVCAN_STM32_BAREMETAL +#if UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS -static void nvicEnableVector(int irq, uint8_t prio) +static void nvicEnableVector(IRQn_Type irq, uint8_t prio) { + #if !defined (USE_HAL_DRIVER) NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = irq; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = prio; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); + #else + HAL_NVIC_SetPriority(irq, prio, 0); + HAL_NVIC_EnableIRQ(irq); + #endif } #endif @@ -923,7 +942,7 @@ void CanDriver::initOnce() IRQ_ATTACH(STM32_IRQ_CAN2RX1, can2_irq); # endif # undef IRQ_ATTACH -#elif UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL +#elif UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS { CriticalSectionLocker lock; nvicEnableVector(CAN1_TX_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); diff --git a/libuavcan_drivers/stm32/driver/src/uc_stm32_clock.cpp b/libuavcan_drivers/stm32/driver/src/uc_stm32_clock.cpp index 1a04569acc..42a51da079 100644 --- a/libuavcan_drivers/stm32/driver/src/uc_stm32_clock.cpp +++ b/libuavcan_drivers/stm32/driver/src/uc_stm32_clock.cpp @@ -14,7 +14,7 @@ /* * Timer instance */ -# if (UAVCAN_STM32_CHIBIOS && CH_KERNEL_MAJOR == 2) || UAVCAN_STM32_BAREMETAL +# if (UAVCAN_STM32_CHIBIOS && CH_KERNEL_MAJOR == 2) || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS # define TIMX UAVCAN_STM32_GLUE2(TIM, UAVCAN_STM32_TIMER_NUMBER) # define TIMX_IRQn UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQn) # define TIMX_INPUT_CLOCK STM32_TIMCLK1 @@ -81,16 +81,21 @@ uavcan::uint64_t time_utc = 0; } -#if UAVCAN_STM32_BAREMETAL +#if UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS -static void nvicEnableVector(int irq, uint8_t prio) +static void nvicEnableVector(IRQn_Type irq, uint8_t prio) { + #if !defined (USE_HAL_DRIVER) NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = irq; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = prio; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); + #else + HAL_NVIC_SetPriority(irq, prio, 0); + HAL_NVIC_EnableIRQ(irq); + #endif } @@ -106,7 +111,7 @@ void init() initialized = true; -# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL +# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS // Power-on and reset TIMX_RCC_ENR |= TIMX_RCC_ENR_MASK; TIMX_RCC_RSTR |= TIMX_RCC_RSTR_MASK; @@ -178,7 +183,7 @@ void setUtc(uavcan::UtcTime time) static uavcan::uint64_t sampleUtcFromCriticalSection() { -# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL +# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS UAVCAN_ASSERT(initialized); UAVCAN_ASSERT(TIMX->DIER & TIM_DIER_UIE); @@ -228,7 +233,7 @@ uavcan::MonotonicTime getMonotonic() volatile uavcan::uint64_t time = time_mono; -# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL +# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS volatile uavcan::uint32_t cnt = TIMX->CNT; if (TIMX->SR & TIM_SR_UIF) @@ -435,7 +440,7 @@ UAVCAN_STM32_IRQ_HANDLER(TIMX_IRQHandler) { UAVCAN_STM32_IRQ_PROLOGUE(); -# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL +# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS TIMX->SR = 0; # endif # if UAVCAN_STM32_NUTTX diff --git a/libuavcan_drivers/stm32/driver/src/uc_stm32_thread.cpp b/libuavcan_drivers/stm32/driver/src/uc_stm32_thread.cpp index 93b8c0a85c..9b9a0d2d79 100644 --- a/libuavcan_drivers/stm32/driver/src/uc_stm32_thread.cpp +++ b/libuavcan_drivers/stm32/driver/src/uc_stm32_thread.cpp @@ -7,6 +7,7 @@ #include #include "internal.hpp" + namespace uavcan_stm32 { @@ -79,6 +80,59 @@ void Mutex::unlock() # endif } + +#elif UAVCAN_STM32_FREERTOS + +bool BusEvent::wait(uavcan::MonotonicDuration duration) +{ + static const uavcan::int64_t MaxDelayMSec = 0x000FFFFF; + + const uavcan::int64_t msec = duration.toMSec(); + + BaseType_t ret; + + if (msec <= 0) + { + ret = xSemaphoreTake( sem_, ( TickType_t ) 0 ); + } + else + { + ret = xSemaphoreTake( sem_, (msec > MaxDelayMSec) ? (MaxDelayMSec/portTICK_RATE_MS) : (msec/portTICK_RATE_MS)); + } + return ret == pdTRUE; +} + +void BusEvent::signal() +{ + xSemaphoreGive( sem_ ); +} + +void BusEvent::signalFromInterrupt() +{ + higher_priority_task_woken = pdFALSE; + + xSemaphoreGiveFromISR( sem_, &higher_priority_task_woken ); +} + +void BusEvent::yieldFromISR() +{ + portYIELD_FROM_ISR( higher_priority_task_woken ); +} + +/* + * Mutex + */ +void Mutex::lock() +{ + xSemaphoreTake( mtx_, portMAX_DELAY ); +} + +void Mutex::unlock() +{ + xSemaphoreGive( mtx_ ); +} + + #elif UAVCAN_STM32_NUTTX const unsigned BusEvent::MaxPollWaiters;