diff --git a/BUILD_WITH_CMAKE.md b/BUILD_WITH_CMAKE.md index bfc8743..a29190b 100644 --- a/BUILD_WITH_CMAKE.md +++ b/BUILD_WITH_CMAKE.md @@ -71,4 +71,30 @@ Every time make -j 8" ``` -The romeo-obsw binary can now be found in the `build` directory. The next step to deploy it is here: [DEBUG_ON_ZEDBOARD.md](./DEBUG_ON_ZEDBOARD.md). \ No newline at end of file +The romeo-obsw binary can now be found in the `build` directory. The next step to deploy it is here: [DEBUG_ON_ZEDBOARD.md](./DEBUG_ON_ZEDBOARD.md). + +## Linux + +The obsw can also be compiled and run on linux using the gcc-posix port of FreeRTOS. + +### build + +Once: +```sh +mkdir -p build +cd build +cmake .. +``` + +Every time +```sh +make -j 8" +``` + +### run + +Run the binary + +```sh +./romeo-obsw +``` \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b5b4f5..4beaf4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,7 @@ cmake_minimum_required(VERSION 3.13) # Project Name -project(romeo-obsw C CXX ASM) - +project(romeo-obsw C ASM) # ############################################################################## # Pre-Sources preparation @@ -10,18 +9,13 @@ project(romeo-obsw C CXX ASM) -# Specify the C++ standard -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED True) - # Set names and variables set(TARGET_NAME ${CMAKE_PROJECT_NAME}) # Set path names set(FreeRTOS_PATH FreeRTOS-Kernel/) set(MISSION_PATH mission/) -set(FreeRTOS_CONFIG_PATH bsp_z7/freeRTOS) -set(BSP_PATH bsp_z7) + set (LWIP_DIR contrib/lwip) @@ -30,14 +24,18 @@ set (LWIP_DIR contrib/lwip) # Configuration # ############################################################################## -set(ZYNQ_UART UART1 CACHE STRING "Which PS UART to use for stdout") -set_property(CACHE ZYNQ_UART PROPERTY STRINGS UART0 UART1) +if (${CMAKE_CROSSCOMPILING}) + set(ZYNQ_UART UART1 CACHE STRING "Which PS UART to use for stdout") + set_property(CACHE ZYNQ_UART PROPERTY STRINGS UART0 UART1) -if(${ZYNQ_UART} STREQUAL UART0) - add_compile_definitions(ZYNQ_USE_UART0) + if(${ZYNQ_UART} STREQUAL UART0) + add_compile_definitions(ZYNQ_USE_UART0) + endif() +else() + unset(ZYNQ_UART) + unset(ZYNQ_UART CACHE) endif() - # ############################################################################## # Executable and Sources # ############################################################################## @@ -48,7 +46,7 @@ add_executable(${TARGET_NAME}) # lwip set (LWIP_INCLUDE_DIRS "${LWIP_DIR}/src/include" - "${BSP_PATH}/lwip" + "bsp_z7/lwip" ) #include(${LWIP_DIR}/src/Filelists.cmake) set(lwip_SRCS @@ -58,30 +56,48 @@ set(lwip_SRCS ${LWIP_DIR}/src/netif/slipif.c ${LWIP_DIR}/src/apps/tftp/tftp.c ) -add_library(lwip ${lwip_SRCS}) -target_include_directories(lwip PUBLIC ${LWIP_INCLUDE_DIRS}) - -#target_compile_options(${TARGET_NAME} PUBLIC -g -O0 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard) +if(${CMAKE_CROSSCOMPILING}) + add_library(lwip ${lwip_SRCS}) + target_include_directories(lwip PUBLIC ${LWIP_INCLUDE_DIRS}) +endif() # Add freeRTOS -set(FREERTOS_PORT GCC_ARM_CA9 CACHE STRING "") -set(FREERTOS_HEAP 1 CACHE STRING "") -add_library(freertos_config INTERFACE) -target_include_directories(freertos_config SYSTEM - INTERFACE ${FreeRTOS_CONFIG_PATH}) # The config file directory -target_compile_definitions(freertos_config - INTERFACE - projCOVERAGE_TEST=0) -target_include_directories( - freertos_config INTERFACE ${BSP_PATH}/ps7_cortexa9_0/include) -# our compiler options, will trickle down through the project -target_compile_options(freertos_config INTERFACE -c -fmessage-length=0 -g -O0 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -ffunction-sections -fdata-sections) - +if(${CMAKE_CROSSCOMPILING}) + #TODO: this somewhat hardcodes zynq as the only cross target + set(FREERTOS_PORT GCC_ARM_CA9 CACHE STRING "") + set(FREERTOS_HEAP 1 CACHE STRING "") + add_library(freertos_config INTERFACE) + target_include_directories(freertos_config SYSTEM + INTERFACE bsp_z7/freeRTOS) # The config file directory + target_compile_definitions(freertos_config + INTERFACE + projCOVERAGE_TEST=0) + target_include_directories( + freertos_config INTERFACE bsp_z7/ps7_cortexa9_0/include) + + if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL armv7a-none-eabihf) + # our compiler options, will trickle down through the project + target_compile_options(freertos_config INTERFACE -c -fmessage-length=0 -g -O0 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -ffunction-sections -fdata-sections) + else() + message(FATAL_ERROR "invalid architecture ${CMAKE_SYSTEM_PROCESSOR}") + endif() + add_subdirectory(bsp_z7) + target_link_options(${TARGET_NAME} PRIVATE -Wl,--cref -Wl,-Map=${TARGET_NAME}.map -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wl,-build-id=none -T${CMAKE_SOURCE_DIR}/bsp_z7/freeRTOS/lscript.ld -specs=${CMAKE_SOURCE_DIR}/bsp_z7/freeRTOS/Xilinx.spec ) +else() + set(FREERTOS_PORT GCC_POSIX CACHE STRING "") + add_library(freertos_config INTERFACE) + target_include_directories(freertos_config SYSTEM + INTERFACE bsp_linux/freeRTOS) # The config file directory + target_compile_options(freertos_config INTERFACE -c -fmessage-length=0 -g -O0 -ffunction-sections -fdata-sections) + target_compile_definitions(freertos_config + INTERFACE + projCOVERAGE_TEST=0 + projENABLE_TRACING=0) + add_subdirectory(bsp_linux) +endif() add_subdirectory(${FreeRTOS_PATH}) -add_subdirectory(bsp_z7) - add_subdirectory(common) @@ -93,14 +109,16 @@ add_subdirectory(mission_rust) # ############################################################################## # Add libraries for all sources. -target_link_libraries(lwip PUBLIC freertos_kernel) -target_link_libraries(${TARGET_NAME} PUBLIC freertos_kernel mission_rust lwip) +if(${CMAKE_CROSSCOMPILING}) + target_link_libraries(lwip PUBLIC freertos_kernel) + target_link_libraries(${TARGET_NAME} PUBLIC lwip) +endif() -target_include_directories( - ${TARGET_NAME} PUBLIC ${BSP_PATH}) +target_link_libraries(${TARGET_NAME} PUBLIC freertos_kernel mission_rust) +# target_include_directories( +# ${TARGET_NAME} PUBLIC ${BSP_PATH}) -target_link_options(${TARGET_NAME} PRIVATE -Wl,--cref -Wl,-Map=${TARGET_NAME}.map -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wl,-build-id=none -T${CMAKE_SOURCE_DIR}/${FreeRTOS_CONFIG_PATH}/lscript.ld -specs=${CMAKE_SOURCE_DIR}/${FreeRTOS_CONFIG_PATH}/Xilinx.spec ) # Removed unused sections. target_link_options(${TARGET_NAME} PRIVATE "-Wl,--gc-sections") diff --git a/bsp_linux/CMakeLists.txt b/bsp_linux/CMakeLists.txt new file mode 100644 index 0000000..43c1760 --- /dev/null +++ b/bsp_linux/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${TARGET_NAME} PRIVATE main.c) \ No newline at end of file diff --git a/bsp_linux/freeRTOS/FreeRTOSConfig.h b/bsp_linux/freeRTOS/FreeRTOSConfig.h new file mode 100644 index 0000000..307c0de --- /dev/null +++ b/bsp_linux/freeRTOS/FreeRTOSConfig.h @@ -0,0 +1,209 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See +* https://www.FreeRTOS.org/a00110.html +*----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) PTHREAD_STACK_MIN ) /* The stack size being passed is equal to the minimum stack size needed by pthread_create(). */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 200 * 1024 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 12 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 20 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configUSE_QUEUE_SETS 1 +#define configUSE_TASK_NOTIFICATIONS 1 + +/* The following 2 memory allocation schemes are possible for this demo: + * + * 1. Dynamic Only. + * #define configSUPPORT_STATIC_ALLOCATION 0 + * #define configSUPPORT_DYNAMIC_ALLOCATION 1 + * + * 2. Static and Dynamic. + * #define configSUPPORT_STATIC_ALLOCATION 1 + * #define configSUPPORT_DYNAMIC_ALLOCATION 1 + * + * Static only configuration is not possible for this demo as it utilizes + * dynamic allocation. + */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 + +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Software timer related configuration options. The maximum possible task + * priority is configMAX_PRIORITIES - 1. The priority of the timer task is + * deliberately set higher to ensure it is correctly capped back to + * configMAX_PRIORITIES - 1. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 20 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +#define configMAX_PRIORITIES ( 7 ) + +/* Run time stats gathering configuration options. */ +unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ +void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */ +#define configGENERATE_RUN_TIME_STATS 1 + +/* Co-routine related configuration options. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* This demo can use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Enables the test whereby a stack larger than the total heap size is + * requested. */ +#define configSTACK_DEPTH_TYPE uint32_t + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. In most cases the linker will remove unused + * functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskGetStackHighWaterMark2 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 + +#define configINCLUDE_MESSAGE_BUFFER_AMP_DEMO 0 +#if ( configINCLUDE_MESSAGE_BUFFER_AMP_DEMO == 1 ) + extern void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer ); + #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer ) +#endif /* configINCLUDE_MESSAGE_BUFFER_AMP_DEMO */ + +extern void vAssertCalled( const char * const pcFileName, + unsigned long ulLine ); + + + +/* projCOVERAGE_TEST should be defined on the command line so this file can be + * used with multiple project configurations. If it is + */ +#ifndef projCOVERAGE_TEST + #error projCOVERAGE_TEST should be defined to 1 or 0 on the command line. +#endif + +#ifndef projENABLE_TRACING + #error projENABLE_TRACING should be defined to 1 or 0 on the command line. +#endif + +#if ( projCOVERAGE_TEST == 1 ) + +/* Insert NOPs in empty decision paths to ensure both true and false paths + * are being tested. */ + #define mtCOVERAGE_TEST_MARKER() __asm volatile ( "NOP" ) + +/* Ensure the tick count overflows during the coverage test. */ + #define configINITIAL_TICK_COUNT 0xffffd800UL + +/* Allows tests of trying to allocate more than the heap has free. */ + #define configUSE_MALLOC_FAILED_HOOK 0 + +/* To test builds that remove the static qualifier for debug builds. */ + #define portREMOVE_STATIC_QUALIFIER +#else /* if ( projCOVERAGE_TEST == 1 ) */ + +/* It is a good idea to define configASSERT() while developing. configASSERT() + * uses the same semantics as the standard C assert() macro. Don't define + * configASSERT() when performing code coverage tests though, as it is not + * intended to asserts() to fail, some some code is intended not to run if no + * errors are present. */ + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) + + #define configUSE_MALLOC_FAILED_HOOK 1 + +/* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ + #if( projENABLE_TRACING == 1 ) + #include "trcRecorder.h" + #endif /* if ( projENABLE_TRACING == 1 ) */ +#endif /* if ( projCOVERAGE_TEST == 1 ) */ + +/* networking definitions */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* Prototype for the function used to print out. In this case it prints to the + * console before the network is connected then a UDP port after the network has + * connected. */ +extern void vLoggingPrintf( const char * pcFormatString, + ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to + * 1 then FreeRTOS_debug_printf should be defined to the function used to print + * out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 1 +#if ( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf( X ) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the + * FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 + * then FreeRTOS_printf should be set to the function used to print out the + * messages. */ +#define ipconfigHAS_PRINTF 0 +#if ( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf( X ) vLoggingPrintf X +#endif +#endif /* FREERTOS_CONFIG_H */ diff --git a/bsp_linux/main.c b/bsp_linux/main.c new file mode 100644 index 0000000..d884385 --- /dev/null +++ b/bsp_linux/main.c @@ -0,0 +1,25 @@ +#include +#include +#include + +void mission(void); + +void done() { + printf("done."); + exit(0); +} + +// Don't ask me, it makes the linker happy and does not seem +// to break anything ¯\_(ツ)_/¯ +void rust_eh_personality() { + puts("eh_personality"); +} + +void outbyte(uint8_t byte){ + printf("%c", byte); +} + +int main(void) { + mission(); + return 0; +} \ No newline at end of file diff --git a/bsp_z7/CMakeLists.txt b/bsp_z7/CMakeLists.txt index 240bf63..732ad32 100644 --- a/bsp_z7/CMakeLists.txt +++ b/bsp_z7/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(freeRTOS) -add_subdirectory(ps7_cortexa9_0) \ No newline at end of file +add_subdirectory(ps7_cortexa9_0) + +target_sources(${TARGET_NAME} PRIVATE main.c) \ No newline at end of file diff --git a/bsp_z7/cmake/arm-none-eabi.toolchain b/bsp_z7/cmake/arm-none-eabi.toolchain index 4c32f97..40f0e49 100644 --- a/bsp_z7/cmake/arm-none-eabi.toolchain +++ b/bsp_z7/cmake/arm-none-eabi.toolchain @@ -1,9 +1,10 @@ # the name of the target operating system set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR armv7a-none-eabihf) set(CMAKE_C_COMPILER /usr/bin/arm-none-eabi-gcc) set(CMAKE_CXX_COMPILER /usr/bin/arm-none-eabi-g++) -set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) +set(CMAKE_ASM_COMPILER /usr/bin/arm-none-eabi-gcc) # built in tests fail set(CMAKE_C_COMPILER_WORKS 1) diff --git a/mission/main.c b/bsp_z7/main.c similarity index 58% rename from mission/main.c rename to bsp_z7/main.c index c420bbf..0dbb160 100644 --- a/mission/main.c +++ b/bsp_z7/main.c @@ -1,65 +1,3 @@ -/* - * FreeRTOS V202212.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * https://www.FreeRTOS.org - * https://github.com/FreeRTOS - * - */ - -/****************************************************************************** - * - * See http://www.freertos.org/RTOS-Xilinx-Zynq.html for instructions. - * - * This project provides three demo applications. A simple blinky style - * project, a more comprehensive test and demo application, and an lwIP example. - * The mainSELECTED_APPLICATION setting (defined in this file) is used to - * select between the three. The simply blinky demo is implemented and - * described in main_blinky.c. The more comprehensive test and demo application - * is implemented and described in main_full.c. The lwIP example is implemented - * and described in main_lwIP.c. - * - * This file implements the code that is not demo specific, including the - * hardware setup and FreeRTOS hook functions. - * - * !!! IMPORTANT NOTE !!! - * The GCC libraries that ship with the Xilinx SDK make use of the floating - * point registers. To avoid this causing corruption it is necessary to avoid - * their use unless a task has been given a floating point context. See - * https://www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html - * for information on how to give a task a floating point context, and how to - * handle floating point operations in interrupts. As this demo does not give - * all tasks a floating point context main.c contains very basic C - * implementations of the standard C library functions memset(), memcpy() and - * memcmp(), which are are used by FreeRTOS itself. Defining these functions in - * the project prevents the linker pulling them in from the library. Any other - * standard C library functions that are used by the application must likewise - * be defined in C. - * - * ENSURE TO READ THE DOCUMENTATION PAGE FOR THIS PORT AND DEMO APPLICATION ON - * THE http://www.FreeRTOS.org WEB SITE FOR FULL INFORMATION ON USING THIS DEMO - * APPLICATION, AND ITS ASSOCIATE FreeRTOS ARCHITECTURE PORT! - * - */ - /* Standard includes. */ #include #include @@ -69,17 +7,6 @@ #include "semphr.h" #include "task.h" -// /* Standard demo includes. */ -// #include "EventGroupsDemo.h" -// #include "IntSemTest.h" -// #include "QueueOverwrite.h" -// #include "QueueSet.h" -// #include "StreamBufferDemo.h" -// #include "StreamBufferInterrupt.h" -// #include "TaskNotify.h" -// #include "TimerDemo.h" -// #include "partest.h" - /* Xilinx includes. */ // #include "platform.h" #include "xil_exception.h" @@ -88,7 +15,6 @@ #include "xscutimer.h" #include "xuartps_hw.h" - /* * Configure the hardware as necessary to run this demo. */ @@ -122,7 +48,7 @@ XScuGic xInterruptController; extern SemaphoreHandle_t malloc_mutex; /*-----------------------------------------------------------*/ -void mission(void *); +void mission(void); void initFreeRTOSHelper(); @@ -133,63 +59,9 @@ int main(void) { // printf("Booting Software\n"); - int taskParameters = 0; - - static const size_t stackSizeWords = 102400; - StaticTask_t xTaskBuffer; - StackType_t xStack[stackSizeWords]; - - xTaskCreate( - mission, /* The function that implements the task. */ - "init", /* The text name assigned to the task - for debug only as it is - not used by the kernel. */ - 10240, /* The size of the stack to allocate to the task. */ - &taskParameters, /* The parameter passed to the task - not used in this - simple case. */ - 4, /* The priority assigned to the task. */ - NULL); - - vTaskStartScheduler(); - - /* If all is well, the scheduler will now be running, and the following - line will never be reached. If the following line does execute, then - there was either insufficient FreeRTOS heap memory available for the idle - and/or timer tasks to be created, or vTaskStartScheduler() was called from - User mode. See the memory management section on the FreeRTOS web site for - more details on the FreeRTOS heap http://www.freertos.org/a00111.html. The - mode from which main() is called is set in the C start up code and must be - a privileged mode (not user mode). */ - for (;;) - ; - /* Don't expect to reach here. */ - return 0; + mission(); } -void testIp(); - -void rust_main(); - -// Marker for debugging sessions -__attribute__ ((noinline)) void done() { - asm (""); -} - -void mission(void *) { - - // printf("Starting Mission\n"); - - //testIp(); - - rust_main(); - - // printf("Started Tasks, deleting init task\n"); - - done(); - - vTaskDelete(NULL); -} -/*-----------------------------------------------------------*/ - static void prvSetupHardware(void) { BaseType_t xStatus; XScuGic_Config *pxGICConfig; @@ -234,124 +106,6 @@ static void prvSetupHardware(void) { } /*-----------------------------------------------------------*/ -void vApplicationMallocFailedHook(void) { - /* Called if a call to pvPortMalloc() fails because there is insufficient - free memory available in the FreeRTOS heap. pvPortMalloc() is called - internally by FreeRTOS API functions that create tasks, queues, software - timers, and semaphores. The size of the FreeRTOS heap is set by the - configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ - taskDISABLE_INTERRUPTS(); - //TODO panic - for (;;) - ; -} -/*-----------------------------------------------------------*/ - -void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { - (void)pcTaskName; - (void)pxTask; - - /* Run time stack overflow checking is performed if - configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook - function is called if a stack overflow is detected. */ - taskDISABLE_INTERRUPTS(); - //TODO panic - for (;;) - ; -} -/*-----------------------------------------------------------*/ - -void vApplicationIdleHook(void) { - volatile size_t xFreeHeapSpace, xMinimumEverFreeHeapSpace; - - /* This is just a trivial example of an idle hook. It is called on each - cycle of the idle task. It must *NOT* attempt to block. In this case the - idle task just queries the amount of FreeRTOS heap that remains. See the - memory management section on the http://www.FreeRTOS.org web site for memory - management options. If there is a lot of heap memory free then the - configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up - RAM. */ - // xFreeHeapSpace = xPortGetFreeHeapSize(); - // xMinimumEverFreeHeapSpace = xPortGetMinimumEverFreeHeapSize(); - - // /* Remove compiler warning about xFreeHeapSpace being set but never used. - // */ (void)xFreeHeapSpace; (void)xMinimumEverFreeHeapSpace; -} -/*-----------------------------------------------------------*/ - -void rust_assert_called(const char *pcFile, unsigned long ulLine); - - -void vAssertCalled(const char *pcFile, unsigned long ulLine) { - - rust_assert_called(pcFile, ulLine); - - - volatile unsigned long ul = 0; - - (void)pcFile; - (void)ulLine; - - taskENTER_CRITICAL(); - { - /* Set ul to a non-zero value using the debugger to step out of this - function. */ - while (ul == 0) { - portNOP(); - } - } - taskEXIT_CRITICAL(); -} -/*-----------------------------------------------------------*/ - -void vApplicationTickHook(void) { -#if (mainSELECTED_APPLICATION == 1) - { - /* The full demo includes a software timer demo/test that requires - prodding periodically from the tick interrupt. */ - vTimerPeriodicISRTests(); - - /* Call the periodic queue overwrite from ISR demo. */ - vQueueOverwritePeriodicISRDemo(); - - /* Call the periodic event group from ISR demo. */ - vPeriodicEventGroupsProcessing(); - - /* Use task notifications from an interrupt. */ - xNotifyTaskFromISR(); - - /* Use mutexes from interrupts. */ - vInterruptSemaphorePeriodicTest(); - - /* Writes to stream buffer byte by byte to test the stream buffer trigger - level functionality. */ - vPeriodicStreamBufferProcessing(); - - /* Writes a string to a string buffer four bytes at a time to demonstrate - a stream being sent from an interrupt to a task. */ - vBasicStreamBufferSendFromISR(); - -#if (configUSE_QUEUE_SETS == 1) - { vQueueSetAccessQueueSetFromISR(); } -#endif - -/* Test flop alignment in interrupts - calling printf from an interrupt -is BAD! */ -#if (configASSERT_DEFINED == 1) - { - char cBuf[20]; - UBaseType_t uxSavedInterruptStatus; - - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); - { sprintf(cBuf, "%1.3f", 1.234); } - portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); - - configASSERT(strcmp(cBuf, "1.234") == 0); - } -#endif /* configASSERT_DEFINED */ - } -#endif -} /*-----------------------------------------------------------*/ void vInitialiseTimerForRunTimeStats(void) { @@ -371,7 +125,6 @@ void vInitialiseTimerForRunTimeStats(void) { XScuWdt_SetTimerMode(&xWatchDogInstance); XScuWdt_Start(&xWatchDogInstance); } -/*-----------------------------------------------------------*/ /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an implementation of vApplicationGetIdleTaskMemory() to provide the memory that is @@ -428,3 +181,73 @@ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, configMINIMAL_STACK_SIZE is specified in words, not bytes. */ *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } + +// Marker for debugging sessions +__attribute__((noinline)) void done() { asm(""); } + +void vApplicationIdleHook(void) { + volatile size_t xFreeHeapSpace, xMinimumEverFreeHeapSpace; + + /* This is just a trivial example of an idle hook. It is called on each + cycle of the idle task. It must *NOT* attempt to block. In this case the + idle task just queries the amount of FreeRTOS heap that remains. See the + memory management section on the http://www.FreeRTOS.org web site for memory + management options. If there is a lot of heap memory free then the + configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up + RAM. */ + // xFreeHeapSpace = xPortGetFreeHeapSize(); + // xMinimumEverFreeHeapSpace = xPortGetMinimumEverFreeHeapSize(); + + // /* Remove compiler warning about xFreeHeapSpace being set but never used. + // */ (void)xFreeHeapSpace; (void)xMinimumEverFreeHeapSpace; +} + +void vApplicationTickHook(void) { +#if (mainSELECTED_APPLICATION == 1) + { + /* The full demo includes a software timer demo/test that requires + prodding periodically from the tick interrupt. */ + vTimerPeriodicISRTests(); + + /* Call the periodic queue overwrite from ISR demo. */ + vQueueOverwritePeriodicISRDemo(); + + /* Call the periodic event group from ISR demo. */ + vPeriodicEventGroupsProcessing(); + + /* Use task notifications from an interrupt. */ + xNotifyTaskFromISR(); + + /* Use mutexes from interrupts. */ + vInterruptSemaphorePeriodicTest(); + + /* Writes to stream buffer byte by byte to test the stream buffer trigger + level functionality. */ + vPeriodicStreamBufferProcessing(); + + /* Writes a string to a string buffer four bytes at a time to demonstrate + a stream being sent from an interrupt to a task. */ + vBasicStreamBufferSendFromISR(); + +#if (configUSE_QUEUE_SETS == 1) + { vQueueSetAccessQueueSetFromISR(); } +#endif + +/* Test flop alignment in interrupts - calling printf from an interrupt +is BAD! */ +#if (configASSERT_DEFINED == 1) + { + char cBuf[20]; + UBaseType_t uxSavedInterruptStatus; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { sprintf(cBuf, "%1.3f", 1.234); } + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); + + configASSERT(strcmp(cBuf, "1.234") == 0); + } +#endif /* configASSERT_DEFINED */ + } +#endif +} + diff --git a/mission/testIp.c b/bsp_z7/testIp.c similarity index 100% rename from mission/testIp.c rename to bsp_z7/testIp.c diff --git a/mission/CMakeLists.txt b/mission/CMakeLists.txt index d53a240..6a162fa 100644 --- a/mission/CMakeLists.txt +++ b/mission/CMakeLists.txt @@ -1 +1 @@ -target_sources(${TARGET_NAME} PRIVATE main.c testIp.c freeRTOS_rust_helper.c) \ No newline at end of file +target_sources(${TARGET_NAME} PRIVATE mission.c freeRTOS_rust_helper.c) \ No newline at end of file diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index 4e841a4..cc722c8 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -2,15 +2,17 @@ #include "semphr.h" #include "task.h" +#include + // TODO namespace the names SemaphoreHandle_t global_threading_semaphore = NULL; uint8_t global_threading_available_c() { if (global_threading_semaphore == NULL) { - + global_threading_semaphore = xSemaphoreCreateBinary(); - //xSemaphoreGive(global_threading_semaphore); + // xSemaphoreGive(global_threading_semaphore); } if (uxSemaphoreGetCount(global_threading_semaphore) == 1) { return 1; @@ -19,22 +21,42 @@ uint8_t global_threading_available_c() { } } -void enable_global_threading_c() { - xSemaphoreGive(global_threading_semaphore); -} +void enable_global_threading_c() { xSemaphoreGive(global_threading_semaphore); } void disable_global_threading_c() { xSemaphoreTake(global_threading_semaphore, portMAX_DELAY); } -const char *get_task_name() { return pcTaskGetName(NULL); } +const char *INVALID_TASK = "invalid task"; + +const char *get_task_name() { + /* this function is called from rust's panic, + * so we need to be extra sure to not cause another + * one. pcTaskGetName will trigger an assertion + * on debug builds if no task is running so we + * check if the current task is valid before using it. + * xTaskGetCurrentTaskHandle seems to be a lightweight + * way to do that */ + void *task_handle = xTaskGetCurrentTaskHandle(); + if (task_handle == NULL) { + return INVALID_TASK; + } + const char *name = pcTaskGetName(NULL); + if (name == NULL) { + return INVALID_TASK; + } + if (strlen(name) > configMAX_TASK_NAME_LEN) { + return INVALID_TASK; + } + return name; +} void stop_it() { taskENTER_CRITICAL(); } // TODO return some error code? void *create_task(TaskFunction_t taskFunction, void *parameter, uint32_t stack_size) { - //TODO verify uint32_t vs configSTACK_DEPTH_TYPE + // TODO verify uint32_t vs configSTACK_DEPTH_TYPE TaskHandle_t newTask; BaseType_t result = xTaskCreate(taskFunction, "rust", stack_size, parameter, 4, &newTask); @@ -46,16 +68,18 @@ void *create_task(TaskFunction_t taskFunction, void *parameter, } void task_delay(uint32_t milliseconds) { - //TODO verify uint32_t vs TickType_t + // TODO verify uint32_t vs TickType_t vTaskDelay(pdMS_TO_TICKS(milliseconds)); } -void delete_task(void * task){ - vTaskSuspend(task); //we can not use vDeleteTask as it would free the allocated memory which is forbidden using heap1 (which we use) +void delete_task(void *task) { + vTaskSuspend( + task); // we can not use vDeleteTask as it would free the allocated memory + // which is forbidden using heap1 (which we use) } void *create_queue(uint32_t length, uint32_t element_size) { - //TODO verify uint32_t vs UBaseType_t + // TODO verify uint32_t vs UBaseType_t QueueHandle_t newQueue = xQueueCreate(length, element_size); return newQueue; } @@ -76,11 +100,9 @@ uint8_t queue_send(void *queue, void *message) { } } -void *create_mutex() { - return xSemaphoreCreateRecursiveMutex(); -} +void *create_mutex() { return xSemaphoreCreateRecursiveMutex(); } -uint8_t take_mutex(void * handle) { +uint8_t take_mutex(void *handle) { // TODO check if global semaphore is free (ie, we are doing multitasking) // if not, pointers are invalid, bail out if (xSemaphoreTakeRecursive(handle, portMAX_DELAY) == pdPASS) { @@ -90,7 +112,7 @@ uint8_t take_mutex(void * handle) { } } -uint8_t give_mutex(void * handle) { +uint8_t give_mutex(void *handle) { // TODO check if global semaphore is free (ie, we are doing multitasking) // if not, pointers are invalid, bail out if (xSemaphoreGiveRecursive(handle) == pdPASS) { diff --git a/mission/mission.c b/mission/mission.c new file mode 100644 index 0000000..bfb0a3b --- /dev/null +++ b/mission/mission.c @@ -0,0 +1,102 @@ +/* Standard includes. */ +#include +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" + +void rust_main(); + +// called to stop execution (either a panic or program ended) +// to be implemented by bsp (do not return from it!) +void done(); + +void init_task(void *) { + // printf("Starting Mission\n"); + + rust_main(); + + // printf("Started Tasks, deleting init task\n"); + + done(); + + vTaskDelete(NULL); +} + +void mission(void) { + + int taskParameters = 0; + + static const size_t stackSizeWords = 102400; + StaticTask_t xTaskBuffer; + StackType_t xStack[stackSizeWords]; + + xTaskCreate(init_task, /* The function that implements the task. */ + "init", /* The text name assigned to the task - for debug only as + it is not used by the kernel. */ + 10240, /* The size of the stack to allocate to the task. */ + &taskParameters, /* The parameter passed to the task - not used in + this simple case. */ + 4, /* The priority assigned to the task. */ + NULL); + + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was either insufficient FreeRTOS heap memory available for the idle + and/or timer tasks to be created, or vTaskStartScheduler() was called from + User mode. See the memory management section on the FreeRTOS web site for + more details on the FreeRTOS heap http://www.freertos.org/a00111.html. The + mode from which main() is called is set in the C start up code and must be + a privileged mode (not user mode). */ + + done(); + + for (;;) + ; + /* Don't expect to reach here. */ + return; +} + +/*-----------------------------------------------------------*/ +void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { + (void)pcTaskName; + (void)pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + taskDISABLE_INTERRUPTS(); + // TODO panic + for (;;) + ; +} + +/*-----------------------------------------------------------*/ +void rust_alloc_failed(); + +void vApplicationMallocFailedHook(void) { + /* Called if a call to pvPortMalloc() fails because there is insufficient + free memory available in the FreeRTOS heap. pvPortMalloc() is called + internally by FreeRTOS API functions that create tasks, queues, software + timers, and semaphores. The size of the FreeRTOS heap is set by the + configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ + taskDISABLE_INTERRUPTS(); + rust_alloc_failed(); + for (;;) + ; +} + +void rust_assert_called(const char *pcFile, unsigned long ulLine); + +void vAssertCalled(const char *pcFile, unsigned long ulLine) { + taskDISABLE_INTERRUPTS(); + rust_assert_called(pcFile, ulLine); +} + +/*-----------------------------------------------------------*/ + +/*-----------------------------------------------------------*/ diff --git a/mission_rust/.cargo/config.toml b/mission_rust/.cargo/config.toml index 9941ccc..e69de29 100644 --- a/mission_rust/.cargo/config.toml +++ b/mission_rust/.cargo/config.toml @@ -1,5 +0,0 @@ -[build] -target = "armv7a-none-eabihf" - -[unstable] -build-std = ["core"] \ No newline at end of file diff --git a/mission_rust/CMakeLists.txt b/mission_rust/CMakeLists.txt index 217aba8..e850a3e 100644 --- a/mission_rust/CMakeLists.txt +++ b/mission_rust/CMakeLists.txt @@ -1,13 +1,33 @@ #TODO can we get CMake to configure cmake --build --clean to run cargo clean? +#TODO look into corrosion cmake plugin -add_custom_target( - mission_rust_internal - COMMAND cargo build $<$:--release> - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) +if (${CMAKE_CROSSCOMPILING}) -add_library(mission_rust INTERFACE) + add_custom_target( + mission_rust_internal + COMMAND cargo build -Zbuild-std=core --target=${CMAKE_SYSTEM_PROCESSOR} $<$:--release> + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) -add_dependencies(mission_rust mission_rust_internal) + add_library(mission_rust INTERFACE) -target_link_libraries(mission_rust INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/target/armv7a-none-eabihf/$,release,debug>/libmission_rust.a) \ No newline at end of file + add_dependencies(mission_rust mission_rust_internal) + + target_link_libraries(mission_rust INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/target/${CMAKE_SYSTEM_PROCESSOR}/$,release,debug>/libmission_rust.a) + +else() + + add_custom_target( + mission_rust_internal + COMMAND cargo build $<$:--release> + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + add_library(mission_rust INTERFACE) + + add_dependencies(mission_rust mission_rust_internal) + + target_link_libraries(mission_rust INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/target/$,release,debug>/libmission_rust.a) + + +endif() \ No newline at end of file diff --git a/mission_rust/Cargo.toml b/mission_rust/Cargo.toml index 5f705b3..d39fbfe 100644 --- a/mission_rust/Cargo.toml +++ b/mission_rust/Cargo.toml @@ -6,6 +6,12 @@ edition = "2021" [lib] crate-type = ["staticlib"] +[profile.dev] +panic = 'abort' + +[profile.release] +panic = 'abort' + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 2a0d92f..8ebd689 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -24,7 +24,7 @@ fn panic(panic: &PanicInfo<'_>) -> ! { sifln!(""); sif!("in task \""); unsafe { - //TODO is from_ptr safe enough? + //osal::get_task_name is implemented safely in C, so we trust it let task_name = core::ffi::CStr::from_ptr(osal::get_task_name()); let task_name_utf8 = core::str::from_utf8(task_name.to_bytes()); match task_name_utf8 { @@ -62,6 +62,11 @@ extern "C" fn rust_assert_called(ptr: *const core::ffi::c_char, line: core::ffi: panic!("assertion failed at {file_name}:{}", line); } +#[no_mangle] +extern "C" fn rust_alloc_failed(){ + panic!("allocation failed!"); +} + #[no_mangle] extern "C" fn rust_main() { sifln!("Rust startup 🚀");