From 00a000d1cb29db6b222f383d8aa5c6b3fdf4dc4d Mon Sep 17 00:00:00 2001 From: jzlv Date: Tue, 19 Oct 2021 18:59:58 +0800 Subject: [PATCH] [feat][examples/freertos] add freertos tickless demo --- .../freertos/freertos_tickless/CMakeLists.txt | 6 + examples/freertos/freertos_tickless/main.c | 270 ++++++++++++++++++ examples/freertos/freertos_tickless/readme.md | 8 + 3 files changed, 284 insertions(+) create mode 100644 examples/freertos/freertos_tickless/CMakeLists.txt create mode 100644 examples/freertos/freertos_tickless/main.c create mode 100644 examples/freertos/freertos_tickless/readme.md diff --git a/examples/freertos/freertos_tickless/CMakeLists.txt b/examples/freertos/freertos_tickless/CMakeLists.txt new file mode 100644 index 00000000..5e9054d4 --- /dev/null +++ b/examples/freertos/freertos_tickless/CMakeLists.txt @@ -0,0 +1,6 @@ +set(BSP_COMMON_DIR ${CMAKE_SOURCE_DIR}/bsp/bsp_common) +set(TARGET_REQUIRED_LIBS freertos) +set(mains main.c) +generate_bin() + + diff --git a/examples/freertos/freertos_tickless/main.c b/examples/freertos/freertos_tickless/main.c new file mode 100644 index 00000000..7a8e7753 --- /dev/null +++ b/examples/freertos/freertos_tickless/main.c @@ -0,0 +1,270 @@ +/** + * @file main.c + * @brief + * + * Copyright (c) 2021 Bouffalolab team + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ +#include "hal_uart.h" +#include +#include "semphr.h" +#include "bflb_platform.h" +#include "timers.h" +#include "task.h" + +static uint8_t freertos_heap[configTOTAL_HEAP_SIZE]; + +static HeapRegion_t xHeapRegions[] = { + { (uint8_t *)freertos_heap, 0 }, + { NULL, 0 }, /* Terminates the array. */ + { NULL, 0 } /* Terminates the array. */ +}; +static StackType_t consumer_stack[512]; +static StaticTask_t consumer_handle; +static StackType_t producer_stack[512]; +static StaticTask_t producer_handle; + +uint8_t sharedBuf[16]; +SemaphoreHandle_t sem_empty = NULL; +SemaphoreHandle_t sem_full = NULL; +SemaphoreHandle_t mtx_lock = NULL; + +TimerHandle_t timer0; + +void vAssertCalled(void) +{ + MSG("vAssertCalled\r\n"); + + while (1) + ; +} + +void vApplicationTickHook(void) +{ + //MSG("vApplicationTickHook\r\n"); +} + +void vApplicationStackOverflowHook(void) +{ + MSG("vApplicationStackOverflowHook\r\n"); + + while (1) + ; +} + +void vApplicationMallocFailedHook(void) +{ + MSG("vApplicationMallocFailedHook\r\n"); + + while (1) + ; +} +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} + +/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} + +static void consumer_task(void *pvParameters) +{ + MSG("Consumer task enter \r\n"); + vTaskDelay(1000); + MSG("Consumer task start \r\n"); + MSG("begin to loop %s\r\n", __FILE__); + + while (1) { + if (xSemaphoreTake(sem_full, portMAX_DELAY) == pdTRUE) { + xSemaphoreTake(mtx_lock, portMAX_DELAY); + MSG("Consumer get:%s\r\n", sharedBuf); + xSemaphoreGive(mtx_lock); + xSemaphoreGive(sem_empty); + } else { + MSG("Take sem_full fail\r\n"); + } + } + + vTaskDelete(NULL); +} + +static void producer_task(void *pvParameters) +{ + uint8_t buf = 100; + + MSG("Producer task enter \r\n"); + vTaskDelay(1000); + MSG("Producer task start \r\n"); + + while (1) { + if (xSemaphoreTake(sem_empty, portMAX_DELAY) == pdTRUE) { + xSemaphoreTake(mtx_lock, portMAX_DELAY); + buf++; + sprintf((char *)sharedBuf, "%d", buf); + MSG("Producer generates:%s\r\n", sharedBuf); + xSemaphoreGive(mtx_lock); + xSemaphoreGive(sem_full); + vTaskDelay(buf); + } else { + MSG("Take sem_empty fail\r\n"); + } + } + + vTaskDelete(NULL); +} + +void timer_callback(TimerHandle_t xTimer) +{ + static uint32_t enter = 1; + if (enter) { + MSG("enter\r\n"); + enter = 0; + } else { + MSG("exit\r\n"); + enter = 1; + } +} +int main(void) +{ + bflb_platform_init(0); + + xHeapRegions[0].xSizeInBytes = configTOTAL_HEAP_SIZE; + vPortDefineHeapRegions(xHeapRegions); + + configASSERT((configMAX_PRIORITIES > 4)); + + /* Create semaphore */ + vSemaphoreCreateBinary(sem_empty); + vSemaphoreCreateBinary(sem_full); + vSemaphoreCreateBinary(mtx_lock); + + if (sem_empty == NULL || sem_full == NULL || mtx_lock == NULL) { + MSG("Create sem fail\r\n"); + BL_CASE_FAIL; + } + + MSG("[OS] Starting consumer task...\r\n"); + xTaskCreateStatic(consumer_task, (char *)"consumer_task", sizeof(consumer_stack) / 4, NULL, configMAX_PRIORITIES - 2, consumer_stack, &consumer_handle); + MSG("[OS] Starting producer task...\r\n"); + xTaskCreateStatic(producer_task, (char *)"producer_task", sizeof(producer_stack) / 4, NULL, configMAX_PRIORITIES - 3, producer_stack, &producer_handle); + timer0 = xTimerCreate("timer0", pdMS_TO_TICKS(100), 1, NULL, timer_callback); + xTimerStart(timer0, 0); + vTaskStartScheduler(); + + BL_CASE_SUCCESS; + while (1) { + bflb_platform_delay_ms(100); + } +} + +extern uint64_t ullNextTime; +extern const size_t uxTimerIncrementsForOneTick; +void vApplicationSleep(uint32_t xExpectedIdleTime) +{ + uint64_t sleep_start_time = 0; + uint64_t sleep_end_time = 0; + uint64_t record_ullNextTime = 0; + uint32_t actual_compensate_mstime = 0; + static uint32_t actual_compensate_ustime = 0; + if (eTaskConfirmSleepModeStatus() != eAbortSleep) { + MSG("enter wfi,xExpectedIdleTime:%d\r\n", xExpectedIdleTime); + if (xExpectedIdleTime > 60 * 1000) { + xExpectedIdleTime = 60 * 1000; + } + + cpu_global_irq_disable(); + + /*prepare to enter wfi, record start time*/ + sleep_start_time = bflb_platform_get_time_us(); + /*minus one tick, bacause ullNextTime has increased one tick in last mtimer interrupt */ + ullNextTime -= uxTimerIncrementsForOneTick; + /*record current ullNextTime*/ + record_ullNextTime = ullNextTime; + /*set mtimer cmp reg for xExpectedIdleTime ticks*/ + ullNextTime += uxTimerIncrementsForOneTick * (xExpectedIdleTime - 1); + *(volatile uint64_t *)(0x02000000 + 0x4000) = ullNextTime; + /* Prepare the time to use after the next tick interrupt. */ + ullNextTime += uxTimerIncrementsForOneTick; + + __WFI(); + + /*exit wfi, record end time*/ + sleep_end_time = bflb_platform_get_time_us(); + + /*mtimer interrupt cause*/ + if (xExpectedIdleTime == pdMS_TO_TICKS((sleep_end_time - sleep_start_time + 500) / 1000)) { + /*compensate os tick*/ + vTaskStepTick(xExpectedIdleTime); + } else { /*external interrupt cause*/ + ullNextTime = record_ullNextTime; + /*caculate actual sleep time*/ + ullNextTime += (sleep_end_time - sleep_start_time); + *(volatile uint64_t *)(0x02000000 + 0x4000) = ullNextTime; + /* Prepare the time to use after the next tick interrupt. */ + ullNextTime += uxTimerIncrementsForOneTick; + + actual_compensate_ustime += (sleep_end_time - sleep_start_time); + if (actual_compensate_ustime / 1000) { + actual_compensate_mstime = actual_compensate_ustime / 1000; /*How many ms to increase*/ + actual_compensate_ustime -= actual_compensate_ustime / 1000 * 1000; /*How many us to be remainded*/ + } + MSG("ms:%d\r\n", actual_compensate_mstime); + /*compensate os tick*/ + vTaskStepTick(pdMS_TO_TICKS(actual_compensate_mstime)); + } + MSG("exit,sleep_time:%dus\r\n", (uint32_t)(sleep_end_time - sleep_start_time)); + cpu_global_irq_enable(); + } +} \ No newline at end of file diff --git a/examples/freertos/freertos_tickless/readme.md b/examples/freertos/freertos_tickless/readme.md new file mode 100644 index 00000000..8106e242 --- /dev/null +++ b/examples/freertos/freertos_tickless/readme.md @@ -0,0 +1,8 @@ +- **FreeRTOSConfig.h 中开启 configUSE_TICKLESS_IDLE** +- **devcube烧录时flash 选择 xclk** + +```bash + +$ make APP=freertos_tickless BOARD=bl706_lp + +``` \ No newline at end of file