diff --git a/Application/application.cpp b/Application/application.cpp index c7c347a..04831a4 100644 --- a/Application/application.cpp +++ b/Application/application.cpp @@ -53,15 +53,15 @@ uint16_t ReadTouch(SPI_TypeDef *spi, bool x) Application::Application() : GlobalsInitializer(&m_console) -, Task(3) +, Task(3, &Application::Loop) , m_console(USART1, DMA2, LL_DMA_STREAM_2, LL_DMA_STREAM_7, this, nullptr) { } -void Application::TaskFn(void *taskObj) -{ - static_cast(reinterpret_cast*>(taskObj))->Loop(); -} +//void Application::TaskFn(void *taskObj) +//{ +// static_cast(reinterpret_cast*>(taskObj))->Loop(); +//} void Application::Loop() { diff --git a/Application/application.h b/Application/application.h index 3190e25..97aab44 100644 --- a/Application/application.h +++ b/Application/application.h @@ -37,11 +37,10 @@ class Application : public GlobalsInitializer { public: Application(); - void Loop(); + void Loop(); friend class fsl::Task; private: - static void TaskFn(void *taskObj); virtual void LineReceived(void *userParam, f4ll_cpp::SerialConsole<257>::Buffer *buffer); virtual void TransmissionComplete(void *userParam, f4ll_cpp::SerialConsole<257>::Buffer *buffer); diff --git a/Core/Inc/FreeRTOSConfig.h b/Core/Inc/FreeRTOSConfig.h index 20b39a2..7af8114 100644 --- a/Core/Inc/FreeRTOSConfig.h +++ b/Core/Inc/FreeRTOSConfig.h @@ -51,6 +51,10 @@ #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) #include extern uint32_t SystemCoreClock; +/* USER CODE BEGIN 0 */ + extern void configureTimerForRunTimeStats(void); + extern unsigned long getRunTimeCounterValue(void); +/* USER CODE END 0 */ #endif #ifndef CMSIS_device_header #define CMSIS_device_header "stm32f4xx.h" @@ -70,6 +74,7 @@ #define configMINIMAL_STACK_SIZE ((uint16_t)128) #define configTOTAL_HEAP_SIZE ((size_t)15360) #define configMAX_TASK_NAME_LEN ( 16 ) +#define configGENERATE_RUN_TIME_STATS 1 #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 #define configUSE_MUTEXES 1 @@ -166,6 +171,12 @@ standard names. */ #define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 0 +/* USER CODE BEGIN 2 */ +/* Definitions needed when configGENERATE_RUN_TIME_STATS is on */ +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS configureTimerForRunTimeStats +#define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue +/* USER CODE END 2 */ + /* USER CODE BEGIN Defines */ /* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ /* USER CODE END Defines */ diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index 37035e6..8325a62 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -65,6 +65,23 @@ void StartDefaultTask(void *argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ +/* Hook prototypes */ +void configureTimerForRunTimeStats(void); +unsigned long getRunTimeCounterValue(void); + +/* USER CODE BEGIN 1 */ +/* Functions needed when configGENERATE_RUN_TIME_STATS is on */ +__weak void configureTimerForRunTimeStats(void) +{ + +} + +__weak unsigned long getRunTimeCounterValue(void) +{ +return 0; +} +/* USER CODE END 1 */ + /** * @brief FreeRTOS initialization * @param None diff --git a/Core/Src/main.c b/Core/Src/main.c index 5cb6fd4..ed6ace0 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -102,7 +102,7 @@ int main(void) /* USER CODE BEGIN 2 */ AppInit(); - /* USER CODE END 2 */ + /* USER CODE END 2 */ /* Init scheduler */ osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */ diff --git a/components/f4ll_cpp/serialconsole.h b/components/f4ll_cpp/serialconsole.h index 16e91a2..679dcc5 100644 --- a/components/f4ll_cpp/serialconsole.h +++ b/components/f4ll_cpp/serialconsole.h @@ -16,7 +16,7 @@ namespace f4ll_cpp { -template class SerialConsole : protected UartBase +template class SerialConsole : protected UartBase { public: struct Buffer { @@ -52,7 +52,7 @@ private: void *m_callbackUserParam; }; -template SerialConsole::SerialConsole( +template SerialConsole::SerialConsole( USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, ISerialConsoleCallback *callback, void *callbackUserParam ) @@ -63,13 +63,13 @@ template SerialConsole::SerialConsole( SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize); } -template void SerialConsole::SetupTransmit(void *buffer, uint16_t length) +template void SerialConsole::SetupTransmit(void *buffer, uint16_t length) { m_txBuffer.busy = true; UartBase::SetupTransmit(buffer, length); } -template void SerialConsole::HandleRxDmaIrq() +template void SerialConsole::HandleRxDmaIrq() { if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) { *m_rxDma.GetIfcReg() = m_rxDma.GetTcMask(); @@ -87,7 +87,7 @@ template void SerialConsole::HandleRxDmaIrq() SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize); } -template void SerialConsole::HandleTxDmaIrq() +template void SerialConsole::HandleTxDmaIrq() { if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete *m_txDma.GetIfcReg() = m_txDma.GetTcMask(); @@ -102,7 +102,7 @@ template void SerialConsole::HandleTxDmaIrq() } } -template void SerialConsole::HandleUsartIrq() +template void SerialConsole::HandleUsartIrq() { if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle // we assume that new line marker will arrive without an idle cycle even if it is CRLF @@ -136,7 +136,7 @@ template void SerialConsole::HandleUsartIrq() } } -template void SerialConsole::Send(char const *buffer, uint8_t length) +template void SerialConsole::Send(char const *buffer, uint8_t length) { if(!length) { auto computedLength = strlen(buffer); @@ -150,7 +150,7 @@ template void SerialConsole::Send(char const *buf } } -template void SerialConsole::SendLine(char const *buffer, uint8_t length) +template void SerialConsole::SendLine(char const *buffer, uint8_t length) { if(!length) { auto computedLength = strlen(buffer); diff --git a/components/fsl/ringbuffer.h b/components/fsl/ringbuffer.h new file mode 100644 index 0000000..edfc6dc --- /dev/null +++ b/components/fsl/ringbuffer.h @@ -0,0 +1,245 @@ +/* + * ringbuffer.h + * + * Created on: Sep 14, 2021 + * Author: Attila Body + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace fsl { + +template class RingBuffer +{ +public: + /** + * @brief Initializes the ring buffer internal structure with the corresponding parameters. + * Provided only for convenience, the structure also can be initialized locally + */ + RingBuffer(TaskHandle_t consumerTask, +// BaseType_t consumerNotifyIndex, + uint32_t consumerNotifyMask, + TaskHandle_t producerTask, +// BaseType_t producerNotifyIndex, + uint32_t producerNotifyMask); + + /** + * @brief Copies data to the ring buffer (without committing it) The amount of the committed data in the buffer + * should not exceed the size of the buffer. + * @param data Pointer to the data to copy + * @param len Length of the data to copy + */ + void Put(uint8_t const *data_buffer, size_t len); + + + /** + * @brief Commits the data already placed into the buffer and notifies the consumer about it's availability + */ + void Commit(); + + + /** + * @brief Waits until all the data from the ring buffer gets consumed. + */ + void Flush(); + + + /** + * @brief Gets a pointer to the next chunk of committed data in the buffer without administering the consumption + * of it. The caller should also call ringbuffer_RepostConsumption using the returned chunk length after + * it finished processing the data. + * @param[in] len_requested Length of the data requested from the buffer. The length of the actual data provided + * might be actually smaller (because either reaching the end of the buffer or not enough data in the buffer). + * @param[out] data Receives 1a pointer to the first byte of the available data in the buffer + * @param[out] len Receives the length of the chunk available in the buffer. Will not exceed len_requested. + * @retval true if the buffer has more available data, false otherwise + * @remark The caller should wait for notification from the producer task (using m_producerNotifyIndex + * and producer_notify_mask) before calling this function and consume the data + * (also registering each consumption cycle) until this function returns false + */ + bool GetChunk(size_t len_requested, uint8_t *&data, size_t &len); + + + /** + * @brief Marks the chunk returned by ringbuffer_GetChunk as available + * @param consumed The length of the chunk as returned by ringbuffer_GetChunk(..., len) + */ + void ReportConsumption(size_t consumed); + + +private: + size_t m_head; //!< Write position + size_t m_headShadow; //!< Shadowed write position for collecting data before committing it + size_t m_tail; //!< Read position + TaskHandle_t m_consumerTask; //!< Task handle of the consumer (to notify when data is available) + BaseType_t m_consumerNotifyIndex; //!< Notification index used for consumer notification + uint32_t m_consumerNotifyMask; //!< Notification data for the consumer + TaskHandle_t m_producerTask; //!< Task handle of the producer (to notify when available buffer space increased) + BaseType_t m_producerNotifyIndex; //!< Notification index used for producer notification + uint32_t m_producerNotifyMask; //!< Notification data for the producer + + uint8_t m_buffer[capacity]; //!< Pointer to the phisical memory bufer + + static inline size_t used(size_t s, size_t h, size_t t) + { + return (((h) >= (t)) ? ((h) - (t)) : ((s) - (t) + (h))); + } + + static inline size_t available(size_t s, size_t h, size_t t) + { + return ((s) - used(s, h, t)); + } + + void __ASSERT(bool pred) + { + } + +}; + +template RingBuffer::RingBuffer( + TaskHandle_t consumerTask, +// BaseType_t consumerNotifyIndex, + uint32_t consumerNotifyMask, + TaskHandle_t producerTask, +// BaseType_t producerNotifyIndex, + uint32_t producerNotifyMask) + : m_consumerTask(consumerTask) +// , m_consumerNotifyIndex(consumerNotifyIndex) + , m_consumerNotifyMask(consumerNotifyMask) + , m_producerTask(producerTask) +// , m_producerNotifyIndex(producerNotifyIndex) + , m_producerNotifyMask(producerNotifyMask) +{} + + +template void RingBuffer::Put(uint8_t const *data_buffer, size_t len) +{ + uint16_t chunk1 = 0; + uint16_t chunk2 = 0; + uint16_t uncommitted = 0; + uncommitted = used(capacity, m_headShadow, m_head); + + __ASSERT(uncommitted + len + 1 <= capacity); + + if(xPortIsInsideInterrupt()) { + if(available(capacity, m_headShadow, m_tail) < len + 1) { + __ASSERT(false); + return; + } + } else { + while(available(capacity, m_headShadow, m_tail) < len + 1) { +// xTaskNotifyWaitIndexed(m_producerNotifyIndex, 0, m_producerNotifyMask, NULL, portMAX_DELAY); + xTaskNotifyWait(0, m_producerNotifyMask, NULL, portMAX_DELAY); + } + } + + chunk1 = capacity - m_headShadow; + if(chunk1 >= len) { + chunk1 = len; + } else { + chunk2 = len - chunk1; + } + + memcpy(m_buffer + m_headShadow, data_buffer, chunk1); + m_headShadow += chunk1; + if(m_headShadow == capacity) { + m_headShadow = 0; + } + + if(chunk2) { + memcpy(m_buffer, data_buffer + chunk1, chunk2); + m_headShadow += chunk2; + if(m_headShadow == capacity) { + m_headShadow = 0; + } + } +} + + +template void RingBuffer::Commit() +{ + uint16_t uncommitted = used(capacity, m_headShadow, m_head); + + if(!uncommitted) { + return; + } + + m_head = m_headShadow; + + if(xPortIsInsideInterrupt()) { + BaseType_t woken_up = 0; +// xTaskNotifyIndexedFromISR(m_consumerTask, m_consumerNotifyIndex, m_consumerNotifyMask, eSetBits, &woken_up); + xTaskNotifyFromISR(m_consumerTask, m_consumerNotifyMask, eSetBits, &woken_up); + portYIELD_FROM_ISR(woken_up); // NOLINT(hicpp-no-assembler) + } else { +// xTaskNotifyIndexed(m_consumerTask, m_consumerNotifyIndex, m_consumerNotifyMask, eSetBits); + xTaskNotify(m_consumerTask, m_consumerNotifyMask, eSetBits); + } + +} + + +template void RingBuffer::Flush() +{ + while(m_head != m_tail) { + // TODO: Watchdog? +// xTaskNotifyWaitIndexed(m_producerNotifyIndex, 0, m_producerNotifyMask, NULL, portMAX_DELAY); + xTaskNotifyWait(0, m_producerNotifyMask, NULL, portMAX_DELAY); + } +} + + +template bool RingBuffer::GetChunk(size_t len_requested, uint8_t *&data, size_t &len) +{ + size_t head = m_head; + size_t tail = m_tail; + size_t chunk_size = head >= tail ? head - tail : capacity - tail; + if(!chunk_size) { + len = 0; + return false; + } + if(chunk_size > len_requested) { + chunk_size = len_requested; + } + data = m_buffer + tail; + len = chunk_size; + + tail += chunk_size; + if(tail == capacity) { + tail = 0; + } + return tail != head; +} + + +template void RingBuffer::ReportConsumption(size_t consumed) +{ + if(!consumed) { + return; + } + m_tail += consumed; + if(m_tail == capacity) { + m_tail = 0; + } + if(m_producerTask) { + if(xPortIsInsideInterrupt()) { + BaseType_t woken_up = 0; +// xTaskNotifyIndexedFromISR(m_producerTask, m_producerNotifyIndex, m_producerNotifyMask, eSetBits, &woken_up); + xTaskNotifyFromISR(m_producerTask, m_producerNotifyMask, eSetBits, &woken_up); + portYIELD_FROM_ISR(woken_up); // NOLINT(hicpp-no-assembler) + } else { +// xTaskNotifyIndexed(m_producerTask, m_producerNotifyIndex, producerNotifyMask, eSetBits); + xTaskNotify(m_producerTask, m_producerNotifyMask, eSetBits); + } + } +} + +} // fsl diff --git a/components/fsl/task.h b/components/fsl/task.h index 9b1a597..99c58e8 100644 --- a/components/fsl/task.h +++ b/components/fsl/task.h @@ -16,17 +16,26 @@ namespace fsl { template class Task { public: - Task(UBaseType_t priority) : m_priority(priority) {} + Task(UBaseType_t priority, void (T::*fp)()) : m_priority(priority), m_fp(fp) {} void Start(SemaphoreHandle_t doneSem = nullptr, bool waitForInit = false) { - m_handle = xTaskCreateStatic(T::TaskFn, getName(), sizeof(m_stack)/sizeof(m_stack[0]), + m_handle = xTaskCreateStatic(staticBridge, getName(), sizeof(m_stack)/sizeof(m_stack[0]), this, m_priority, m_stack, &m_tcb); } virtual ~Task() {}; virtual char const * getName() = 0; private: + static void staticBridge(void *taskObj) { + reinterpret_cast*>(taskObj)->taskBridge(); + } + + void taskBridge() { + (static_cast(this)->*m_fp)(); + } + TaskHandle_t m_handle; UBaseType_t m_priority; + void (T::*m_fp)(); StaticTask_t m_tcb; StackType_t m_stack[stackSize]; }; diff --git a/f407ve_freertos.ioc b/f407ve_freertos.ioc index f65ed46..c8e69e3 100644 --- a/f407ve_freertos.ioc +++ b/f407ve_freertos.ioc @@ -37,8 +37,9 @@ Dma.USART1_TX.2.PeriphInc=DMA_PINC_DISABLE Dma.USART1_TX.2.Priority=DMA_PRIORITY_LOW Dma.USART1_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode FREERTOS.FootprintOK=true -FREERTOS.IPParameters=Tasks01,configMINIMAL_STACK_SIZE,FootprintOK,configUSE_NEWLIB_REENTRANT +FREERTOS.IPParameters=Tasks01,configMINIMAL_STACK_SIZE,FootprintOK,configUSE_NEWLIB_REENTRANT,configGENERATE_RUN_TIME_STATS FREERTOS.Tasks01=defaultTask,24,384,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL +FREERTOS.configGENERATE_RUN_TIME_STATS=1 FREERTOS.configMINIMAL_STACK_SIZE=128 FREERTOS.configUSE_NEWLIB_REENTRANT=1 FSMC.AddressSetupTime1=1