diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b1f087b5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +# Tags (such as V10.6.2) are not allowed in .gitmodules, only commit hashes + +[submodule "sdk/FreeRTOS-Kernel"] + path = sdk/FreeRTOS-Kernel + url = git@github.com:FreeRTOS/FreeRTOS-Kernel.git + branch = 18ed888 diff --git a/scripts/check-format-freertos0.sh b/scripts/check-format-freertos0.sh new file mode 100644 index 00000000..6288b6ee --- /dev/null +++ b/scripts/check-format-freertos0.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +result=0 +find sdk/freertos_app_cpu0 -iname *.h -o -iname *.c | xargs ./scripts/clang-format -style=file -output-replacements-xml | grep "/dev/null + +if [ $? -ne 1 ]; then + echo "Formatting mismatch, please run clang-format" + result=1 + + find sdk/freertos_app_cpu0/ -iname *.h -o -iname *.c | xargs python ./scripts/run-clang-format.py --clang-format-executable=./scripts/clang-format +else + echo "Formatting matches!" +fi + +exit $result diff --git a/scripts/check-format-freertos1.sh b/scripts/check-format-freertos1.sh new file mode 100644 index 00000000..98171c6e --- /dev/null +++ b/scripts/check-format-freertos1.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +result=0 +find sdk/freertos_app_cpu1 -iname *.h -o -iname *.c | xargs ./scripts/clang-format -style=file -output-replacements-xml | grep "/dev/null + +if [ $? -ne 1 ]; then + echo "Formatting mismatch, please run clang-format" + result=1 + + find sdk/freertos_app_cpu1/ -iname *.h -o -iname *.c | xargs python ./scripts/run-clang-format.py --clang-format-executable=./scripts/clang-format +else + echo "Formatting matches!" +fi + +exit $result diff --git a/scripts/format-freertos.sh b/scripts/format-freertos.sh new file mode 100644 index 00000000..e02868fe --- /dev/null +++ b/scripts/format-freertos.sh @@ -0,0 +1,2 @@ +find sdk/freertos_app_cpu0/ -iname *.h -o -iname *.c | xargs ./scripts/clang-format -style=file -i +find sdk/freertos_app_cpu1/ -iname *.h -o -iname *.c | xargs ./scripts/clang-format -style=file -i diff --git a/sdk/FreeRTOS-Kernel b/sdk/FreeRTOS-Kernel new file mode 160000 index 00000000..c0ce7252 --- /dev/null +++ b/sdk/FreeRTOS-Kernel @@ -0,0 +1 @@ +Subproject commit c0ce725293bb8cf9b30626a8bba173af33163533 diff --git a/sdk/README.md b/sdk/README.md index 7baaf5e2..1c81e0a9 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -4,9 +4,11 @@ This folder contains the C code which is ran on the DSP on the AMDC hardware. -Each folder is a complete project which can be compiled and ran on the Xilinx Zynq-7000 SoC. There are currently two projects: +## Application Folders -## 1. `app_cpuX` — Core framework for AMDC (**actively maintained**) +The following folders are complete application projects which can be compiled and ran on the Xilinx Zynq-7000 SoC: + +### 1. `app_cpuX` — Core framework for AMDC (**actively maintained**) Combination of both `app_cpu0` and `app_cpu1`: @@ -17,8 +19,31 @@ Combination of both `app_cpu0` and `app_cpu1`: - Logging capabilities (buffered memory + streaming) - Control algorithm injection point framework -## 2. `basic` — Preliminary C code developed for ZedBoard (*archived and not maintained*) +### 2. `freertos_app_cpuX` — Core framework for AMDC (**actively maintained**) + +Combination of both `freertos_app_cpu0` and `freertos_app_cpu1`: + +- Designed for AMDC hardware platform (using PicoZed processor module) +- Dual-core AMP design +- Based on [FreeRTOS](https://freertos.org/) +- User applications built neatly on top of core library code + +### 3. `basic` — Preliminary C code developed for ZedBoard (*archived and not maintained*) - Designed for BM control (based on ZedBoard) - Control performed in ISR context - Real-time Ethernet (lwIP) / serial logging capabilities + +## Source Folders + +The following folders contain source code reference by the applications: + +### 1. `FreeRTOS-Kernel` + +- Is a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) of the [FreeRTOS-Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) source code, referenced by the FreeRTOS application projects + +### 2. `shared` + +- Contains system level and hardware driver code commonly referenced by `v2` application projects +- See `shared/README.md` for more details + diff --git a/sdk/freertos_app_cpu0/.cproject b/sdk/freertos_app_cpu0/.cproject new file mode 100644 index 00000000..12744bde --- /dev/null +++ b/sdk/freertos_app_cpu0/.cproject @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/freertos_app_cpu0/.project b/sdk/freertos_app_cpu0/.project new file mode 100644 index 00000000..23ac0f12 --- /dev/null +++ b/sdk/freertos_app_cpu0/.project @@ -0,0 +1,38 @@ + + + freertos_app_cpu0 + Created by SDK v2019.1. amdc_freertos_bsp_cpu0 - ps7_cortexa9_0 + + amdc_freertos_bsp_cpu0 + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + FreeRTOS-Kernel + 2 + S:/School/WEMPEC/firmware-rtos-e/sdk/FreeRTOS-Kernel + + + shared + 2 + S:/School/WEMPEC/firmware-rtos-e/sdk/shared + + + diff --git a/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h b/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h new file mode 100644 index 00000000..b92d6969 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h @@ -0,0 +1,247 @@ +/* README!!! + * + * This configuration is copied from the FreeRTOS v10.1.1 + * based example project for the Zynq 7000 platform (for + * compatibility). However, you can add to it. + * + * Another example configuration file is available at + * "sdk/FreeRTOS-Kernel/examples/sample_configuration/FreeRTOSConfig.h" + * Because that example is in the submodule, it may update + * from time-to-time when the submodule is updated. + */ + +/* + * Copyright (C) 2018 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "xparameters.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 http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* + * The FreeRTOS Cortex-A port implements a full interrupt nesting model. + * + * Interrupts that are assigned a priority at or below + * configMAX_API_CALL_INTERRUPT_PRIORITY (which counter-intuitively in the ARM + * generic interrupt controller [GIC] means a priority that has a numerical + * value above configMAX_API_CALL_INTERRUPT_PRIORITY) can call FreeRTOS safe API + * functions and will nest. + * + * Interrupts that are assigned a priority above + * configMAX_API_CALL_INTERRUPT_PRIORITY (which in the GIC means a numerical + * value below configMAX_API_CALL_INTERRUPT_PRIORITY) cannot call any FreeRTOS + * API functions, will nest, and will not be masked by FreeRTOS critical + * sections (although it is necessary for interrupts to be globally disabled + * extremely briefly as the interrupt mask is updated in the GIC). + * + * FreeRTOS functions that can be called from an interrupt are those that end in + * "FromISR". FreeRTOS maintains a separate interrupt safe API to enable + * interrupt entry to be shorter, faster, simpler and smaller. + * + * The Zynq implements 256 unique interrupt priorities. For the purpose of + * setting configMAX_API_CALL_INTERRUPT_PRIORITY 255 represents the lowest + * priority. + */ +#define configMAX_API_CALL_INTERRUPT_PRIORITY 18 + +#define configCPU_CLOCK_HZ 100000000UL +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configTICK_RATE_HZ ((TickType_t) 1000) +#define configPERIPHERAL_CLOCK_HZ (33333000UL) +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 // TODO: For low-power, set 1 and implement vApplicationIdleHook() +#define configUSE_TICK_HOOK 0 // TODO: Set as 1 if we want to run function every tick +#define configMAX_PRIORITIES (7) +#define configTOTAL_HEAP_SIZE (125 * 1024) +#define configMAX_TASK_NAME_LEN (10) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* AMDC ADDITION: Need to specify this callback config so we can create message buffers with callbacks + * This is done for Inter-Core Communication (src/sys/icc.c) */ +#define configUSE_SB_COMPLETED_CALLBACK 1 + +/* Include the query-heap CLI command to query the free heap space. */ +#define configINCLUDE_QUERY_HEAP_COMMAND 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) + +/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or undefined) then each task will +be created without an FPU context, and a task must call vTaskUsesFPU() before +making use of any FPU registers. If configUSE_TASK_FPU_SUPPORT is set to 2 then +tasks are created with an FPU context by default, and calling vTaskUsesFPU() has +no effect. */ +#define configUSE_TASK_FPU_SUPPORT 2 +#define configMINIMAL_STACK_SIZE ((unsigned short) 250) // Large since all tasks have FPU context + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 + +/* This demo makes 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 + +/* The private watchdog is used to generate run time stats. */ +/* +#include "xscuwdt.h" +extern XScuWdt xWatchDogInstance; +extern void vInitialiseTimerForRunTimeStats( void ); +#define configGENERATE_RUN_TIME_STATS 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ( ( 0xffffffffUL - XScuWdt_ReadReg( xWatchDogInstance.Config.BaseAddr, +XSCUWDT_COUNTER_OFFSET ) ) >> 1 ) +*/ + +/* The size of the global output buffer that is available for use when there +are multiple command interpreters running at once (for example, one on a UART +and one on TCP/IP). This is done to prevent an output buffer being defined by +each implementation - which would waste RAM. In this case, there is only one +command interpreter running. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled(const char *pcFile, unsigned long ulLine); + +// Original Implementation +//#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ); + +#define configASSERT(x) \ + if ((x) == 0) \ + while (1) \ + ; + +/* If configTASK_RETURN_ADDRESS is not defined then a task that attempts to +return from its implementing function will end up in a "task exit error" +function - which contains a call to configASSERT(). However this can give GCC +some problems when it tries to unwind the stack, as the exit error function has +nothing to return to. To avoid this define configTASK_RETURN_ADDRESS to 0. */ +#define configTASK_RETURN_ADDRESS NULL + +/****** Hardware specific settings. *******************************************/ + +/* + * The application must provide a function that configures a peripheral to + * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() + * in FreeRTOSConfig.h to call the function. This file contains a function + * that is suitable for use on the Zynq MPU. FreeRTOS_Tick_Handler() must + * be installed as the peripheral's interrupt handler. + */ +void vConfigureTickInterrupt(void); +#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() + +void vClearTickInterrupt(void); +#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() + +/* The following constant describe the hardware, and are correct for the +Zynq MPU. */ +#define configINTERRUPT_CONTROLLER_BASE_ADDRESS (XPAR_PS7_SCUGIC_0_DIST_BASEADDR) +#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET (-0xf00) +#define configUNIQUE_INTERRUPT_PRIORITIES 32 + +/****** Network configuration settings - only used when the lwIP example is +built. See the page that documents this demo on the http://www.FreeRTOS.org +website for more information. ***********************************************/ + +/* The priority for the task that unblocked by the MAC interrupt to process +received packets. */ +#define configMAC_INPUT_TASK_PRIORITY (configMAX_PRIORITIES - 1) + +/* The priority of the task that runs the lwIP stack. */ +#define configLWIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) + +/* The priority of the task that uses lwIP sockets to provide a simple command +line interface. */ +#define configCLI_TASK_PRIORITY (tskIDLE_PRIORITY) + +/* MAC address configuration. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x13 +#define configMAC_ADDR2 0x14 +#define configMAC_ADDR3 0x15 +#define configMAC_ADDR4 0x15 +#define configMAC_ADDR5 0x16 + +/* IP address configuration. */ +#define configIP_ADDR0 172 +#define configIP_ADDR1 25 +#define configIP_ADDR2 218 +#define configIP_ADDR3 200 + +/* Netmask configuration. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +#endif /* FREERTOS_CONFIG_H */ diff --git a/sdk/freertos_app_cpu0/src/Xilinx.spec b/sdk/freertos_app_cpu0/src/Xilinx.spec new file mode 100644 index 00000000..9c27dcad --- /dev/null +++ b/sdk/freertos_app_cpu0/src/Xilinx.spec @@ -0,0 +1,2 @@ +*startfile: +crti%O%s crtbegin%O%s diff --git a/sdk/freertos_app_cpu0/src/lscript.ld b/sdk/freertos_app_cpu0/src/lscript.ld new file mode 100644 index 00000000..3e782b7f --- /dev/null +++ b/sdk/freertos_app_cpu0/src/lscript.ld @@ -0,0 +1,295 @@ +/************************************************************************************/ +/* */ +/* This file was automatically generated by the linker script generator, but was */ +/* modified to configure the DRAM regions for Dual-Core apps to run correctly on */ +/* the AMDC's Zynq-7000 SoC */ +/* */ +/* See the documentation here: */ +/* docs.amdc.dev/firmware/xilinx-tools/dual-core.html#configure-dram-memory-regions */ +/* */ +/* */ +/* Version: 2019.1 */ +/* */ +/* Copyright (c) 2010-2016 Xilinx, Inc. All rights reserved. */ +/* */ +/* Description : Cortex-A9 Linker Script */ +/* */ +/************************************************************************************/ + +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000; + +_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; +_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; +_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; +_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; +_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; + +/* Define Memories in the system */ + +MEMORY +{ + ps7_ddr_0 : ORIGIN = 0x100000, LENGTH = 0x1FF80000 + ps7_qspi_linear_0 : ORIGIN = 0xFC000000, LENGTH = 0x1000000 + ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000 + ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00 +} + +/* Specify the default entry point to the program */ + +ENTRY(_vector_table) + +/* Define the sections, and where they are mapped in memory */ + +SECTIONS +{ +.text : { + *(.freertos_vectors) + KEEP (*(.vectors)) + *(.boot) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.plt) + *(.gnu_warning) + *(.gcc_execpt_table) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > ps7_ddr_0 + +.init : { + KEEP (*(.init)) +} > ps7_ddr_0 + +.fini : { + KEEP (*(.fini)) +} > ps7_ddr_0 + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > ps7_ddr_0 + +.rodata1 : { + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > ps7_ddr_0 + +.sdata2 : { + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > ps7_ddr_0 + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > ps7_ddr_0 + +.data : { + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > ps7_ddr_0 + +.data1 : { + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > ps7_ddr_0 + +.got : { + *(.got) +} > ps7_ddr_0 + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > ps7_ddr_0 + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > ps7_ddr_0 + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > ps7_ddr_0 + +.eh_frame : { + *(.eh_frame) +} > ps7_ddr_0 + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > ps7_ddr_0 + +.gcc_except_table : { + *(.gcc_except_table) +} > ps7_ddr_0 + +.mmu_tbl (ALIGN(16384)) : { + __mmu_tbl_start = .; + *(.mmu_tbl) + __mmu_tbl_end = .; +} > ps7_ddr_0 + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > ps7_ddr_0 + +.preinit_array : { + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > ps7_ddr_0 + +.init_array : { + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > ps7_ddr_0 + +.fini_array : { + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > ps7_ddr_0 + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > ps7_ddr_0 + +.sdata : { + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > ps7_ddr_0 + +.sbss (NOLOAD) : { + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + __sbss_end = .; +} > ps7_ddr_0 + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > ps7_ddr_0 + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > ps7_ddr_0 + +.bss (NOLOAD) : { + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; +} > ps7_ddr_0 + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* Generate Stack and Heap definitions */ + +.heap (NOLOAD) : { + . = ALIGN(16); + _heap = .; + HeapBase = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + HeapLimit = .; +} > ps7_ddr_0 + +.stack (NOLOAD) : { + . = ALIGN(16); + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(16); + _stack = .; + __stack = _stack; + . = ALIGN(16); + _irq_stack_end = .; + . += _IRQ_STACK_SIZE; + . = ALIGN(16); + __irq_stack = .; + _supervisor_stack_end = .; + . += _SUPERVISOR_STACK_SIZE; + . = ALIGN(16); + __supervisor_stack = .; + _abort_stack_end = .; + . += _ABORT_STACK_SIZE; + . = ALIGN(16); + __abort_stack = .; + _fiq_stack_end = .; + . += _FIQ_STACK_SIZE; + . = ALIGN(16); + __fiq_stack = .; + _undef_stack_end = .; + . += _UNDEF_STACK_SIZE; + . = ALIGN(16); + __undef_stack = .; +} > ps7_ddr_0 + +_end = .; +} + diff --git a/sdk/freertos_app_cpu0/src/main.c b/sdk/freertos_app_cpu0/src/main.c new file mode 100644 index 00000000..9a77b434 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/main.c @@ -0,0 +1,412 @@ +/* + Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + Copyright (C) 2012 - 2018 Xilinx, Inc. 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. If you wish to use our Amazon + FreeRTOS name, please do so in a fair use way that does not cause confusion. + + 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. + + http://www.FreeRTOS.org + http://aws.amazon.com/freertos + + + 1 tab == 4 spaces! +*/ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "queue.h" +#include "task.h" +#include "timers.h" +/* Xilinx includes. */ +#include "platform.h" +#include "xil_cache.h" +#include "xil_io.h" +#include "xil_mmu.h" +#include "xil_printf.h" +#include "xparameters.h" +/* Firmware includes */ +#include "sys/icc.h" +#include "sys/intr.h" + +/* Begin User Includes */ +#include "drv/led.h" +/* End User Includes */ + +#define TIMER_ID 1 +#define DELAY_10_SECONDS 10000UL +#define DELAY_1_SECOND 1000UL +#define TIMER_CHECK_THRESHOLD 9 +/*-----------------------------------------------------------*/ + +/* The Tx and Rx tasks as described at the top of this file. */ +static void prvTxTask(void *pvParameters); +static void prvRxTask(void *pvParameters); +static void prvBlinkyTask(void *pvParameters); +static void vTimerCallback(TimerHandle_t pxTimer); +/*-----------------------------------------------------------*/ + +/* This project has configSUPPORT_STATIC_ALLOCATION set to 1 (for Inter-Core Communication) so + * the following application callback function must be provided to supply the RAM that will + * get used for the Idle task data structures and stack. + */ +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize); + +/* This project has configSUPPORT_STATIC_ALLOCATION set to 1 (for Inter-Core Communication) + * and configUSE_TIMERS set to 1 so the following application callback function must be + * provided to supply the RAM that will get used for the Timer task data structures and stack. + */ +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, + StackType_t **ppxTimerTaskStackBuffer, + uint32_t *pulTimerTaskStackSize); + +/* + * The Xilinx projects use a BSP that do not allow the start up code to be + * altered easily. Therefore the vector table used by FreeRTOS is defined in + * FreeRTOS_asm_vectors.S, which is part of this project. Switch to use the + * FreeRTOS vector table. + */ +extern void vPortInstallFreeRTOSVectorTable(void); + +/*-----------------------------------------------------------*/ + +/* Parameters for the queue used by the Tx and Rx tasks, as described at the top of this file. */ + +#define QUEUE_LENGTH 10 +#define ITEM_SIZE sizeof(uint32_t) + +static TaskHandle_t xTxTaskHandle; +static TaskHandle_t xRxTaskHandle; +static TaskHandle_t xBlinkyTaskHandle; +static QueueHandle_t xQueue = NULL; +static TimerHandle_t xTimer = NULL; + +char HWstring[32] = "CPU0 - Hello World"; +long RxtaskCntr = 0; + +uint8_t message_status = 0; +// 0 - sending messages +// 1 - complete, success +// 2 - complete, failure + +int main(void) +{ + // Both CPUs: Disable cache on OCM + // S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0 + Xil_SetTlbAttributes(0xFFFF0000, 0x14de2); + +#if 1 + // CPU0 ONLY: + // This code is required to start CPU1 from CPU0 during boot. + // + // This only applies when booting from flash via the FSBL. + // During development with JTAG loading, these low-level + // calls in this #if block are not needed! However, we'll + // keep them here since it doesn't affect performance... + + // Write starting base address for CPU1 PC. + // It will look for this address upon waking up + static const uintptr_t CPU1_START_ADDR = 0xFFFFFFF0; + static const uint32_t CPU1_BASE_ADDR = 0x20080000; + Xil_Out32(CPU1_START_ADDR, CPU1_BASE_ADDR); + + // Waits until write has finished + // DMB = Data Memory Barrier + dmb(); + + // Wake up CPU1 by sending the SEV command + // SEV = Set Event, which causes CPU1 to wake up and jump to CPU1_BASE_ADDR + __asm__("sev"); +#endif + + Xil_ExceptionInit(); + intr_init(); + icc_init(); + vPortInstallFreeRTOSVectorTable(); + + /////////////////////////// + // BEGIN USER CODE HERE // + ///////////////////////// + + led_init(); + + const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS); + + xil_printf("CPU0 - Hello from FreeRTOS example main()!\r\n"); + + /* Create the three tasks */ + xTaskCreate(prvTxTask, /* The function that implements the task. */ + (const char *) "CPU0_Tx", /* Text name for the task, provided to assist debugging only. */ + configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */ + NULL, /* The task parameter is not used, so set to NULL. */ + tskIDLE_PRIORITY, /* The task runs at the idle priority. */ + &xTxTaskHandle); + + xTaskCreate(prvRxTask, /* The function that implements the task. */ + (const char *) "CPU0_Rx", /* Text name for the task, provided to assist debugging only. */ + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 1, + &xRxTaskHandle); + + // Create additional blinky task - CPU0 only + xTaskCreate(prvBlinkyTask, + (const char *) "CPU0_Blinky", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY, + &xBlinkyTaskHandle); + + /* Create the queue used by the tasks. The Rx task has a higher priority + than the Tx task, so will preempt the Tx task and remove values from the + queue as soon as the Tx task writes to the queue - therefore the queue can + never have more than one item in it. */ + xQueue = xQueueCreate(1, sizeof(HWstring)); + + /* Check the queue was created. */ + configASSERT(xQueue); + + /* Create a timer with a timer expiry of 10 seconds. The timer would expire + after 10 seconds and the timer call back would get called. In the timer call back + checks are done to ensure that the tasks have been running properly till then. + The tasks are deleted in the timer call back and a message is printed to convey that + the example has run successfully. + The timer expiry is set to 10 seconds and the timer set to not auto reload. */ + xTimer = xTimerCreate((const char *) "CPU0_Timer", x10seconds, pdFALSE, (void *) TIMER_ID, vTimerCallback); + + /* Check the timer was created. */ + configASSERT(xTimer); + + /* start the timer with a block time of 0 ticks. This means as soon + as the schedule starts the timer will start running and will expire after + 10 seconds */ + xTimerStart(xTimer, 0); + + ///////////////////////// + // END USER CODE HERE // + /////////////////////// + + /* Start the tasks and timer running. */ + 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 + insufficient FreeRTOS heap memory available for the idle and/or timer tasks + to be created. See the memory management section on the FreeRTOS web site + for more details. */ + for (;;) { + } +} + +/*-----------------------------------------------------------*/ +static void prvTxTask(void *pvParameters) +{ + const TickType_t x1second = pdMS_TO_TICKS(DELAY_1_SECOND); + + for (;;) { + if (message_status > 0) { + // Cannot delete tasks created using heap_1 implementation, so instead we suspend immediately if done + vTaskSuspend(NULL); + } else { + /* Delay for 1 second. */ + vTaskDelay(x1second); + + /* Send the next value on the queue. The queue should always be + empty at this point so a block time of 0 is used. */ + // xQueueSend(xQueue, /* The queue being written to. */ + // HWstring, /* The address of the data being sent. */ + // 0UL); /* The block time. */ + + xil_printf("DEBUG: CPU 0 about to attempt send\r\n"); + + // Send a message to the other core + size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBuffer, HWstring, sizeof(HWstring), 0UL); + + xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); + + if (bytes_sent == 0) { + xil_printf("ERROR: CPU 0 failed to write to ICC buffer\r\n"); + } + } + } +} + +/*-----------------------------------------------------------*/ +static void prvRxTask(void *pvParameters) +{ + char Rcvdstring[32] = ""; + + for (;;) { + if (message_status > 0) { + // Cannot delete tasks created using heap_1 implementation, so instead we suspend immediately if done + vTaskSuspend(NULL); + } else { + + // /* Block to wait for data arriving on the queue. */ + // xQueueReceive(xQueue, /* The queue being read. */ + // Rcvdstring, /* Data is read into this address. */ + // portMAX_DELAY); /* Wait without a timeout for data. */ + + xil_printf("DEBUG: CPU 0 about to attempt rcv\r\n"); + + size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBuffer, Rcvdstring, 32, portMAX_DELAY); + + xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + + if (bytes_rcvd == 0) { + xil_printf("CPU 0 failed to receive from ICC buffer\r\n"); + } else { + /* Print the received data. */ + xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); + RxtaskCntr++; + } + } + } +} + +/*-----------------------------------------------------------*/ +static void prvBlinkyTask(void *pvParameters) +{ + const TickType_t x250ms = pdMS_TO_TICKS(DELAY_1_SECOND / 4); + uint8_t led_offset = 0; + + for (;;) { + if (message_status == 0) { + // If not complete, cycle yellow every 250ms + vTaskDelay(x250ms); + + led_set_color(0 + led_offset, LED_COLOR_YELLOW); + led_set_color(1 + led_offset, LED_COLOR_BLACK); + led_set_color(2 + led_offset, LED_COLOR_BLACK); + led_set_color(3 + led_offset, LED_COLOR_BLACK); + + led_offset = (led_offset + 1) % 4; + } else if (message_status == 1) { + // If complete, flash all green every 250ms + vTaskDelay(x250ms); + + led_set_color(LED0, LED_COLOR_BLACK); + led_set_color(LED1, LED_COLOR_BLACK); + led_set_color(LED2, LED_COLOR_BLACK); + led_set_color(LED3, LED_COLOR_BLACK); + + vTaskDelay(x250ms); + + led_set_color(LED0, LED_COLOR_GREEN); + led_set_color(LED1, LED_COLOR_GREEN); + led_set_color(LED2, LED_COLOR_GREEN); + led_set_color(LED3, LED_COLOR_GREEN); + } else { + // message_status must be 2, meaning failure + // flash all red every 250ms + vTaskDelay(x250ms); + + led_set_color(LED0, LED_COLOR_BLACK); + led_set_color(LED1, LED_COLOR_BLACK); + led_set_color(LED2, LED_COLOR_BLACK); + led_set_color(LED3, LED_COLOR_BLACK); + + vTaskDelay(x250ms); + + led_set_color(LED0, LED_COLOR_RED); + led_set_color(LED1, LED_COLOR_RED); + led_set_color(LED2, LED_COLOR_RED); + led_set_color(LED3, LED_COLOR_RED); + } + } +} + +/*-----------------------------------------------------------*/ +static void vTimerCallback(TimerHandle_t pxTimer) +{ + long lTimerId; + configASSERT(pxTimer); + + lTimerId = (long) pvTimerGetTimerID(pxTimer); + + if (lTimerId != TIMER_ID) { + xil_printf("CPU0 - FreeRTOS Hello World Example FAILED"); + } + + /* If the RxtaskCntr is updated every time the Rx task is called. The + Rx task is called every time the Tx task sends a message. The Tx task + sends a message every 1 second. + The timer expires after 10 seconds. We expect the RxtaskCntr to at least + have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ + if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { + message_status = 1; + xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n"); + } else { + message_status = 2; + xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n"); + } +} + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an + * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is + * used by the Idle task. */ +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; +} +/*-----------------------------------------------------------*/ + +/* configUSE_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, + * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} diff --git a/sdk/freertos_app_cpu1/.cproject b/sdk/freertos_app_cpu1/.cproject new file mode 100644 index 00000000..f04ca3b5 --- /dev/null +++ b/sdk/freertos_app_cpu1/.cproject @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/freertos_app_cpu1/.project b/sdk/freertos_app_cpu1/.project new file mode 100644 index 00000000..0e6c64d2 --- /dev/null +++ b/sdk/freertos_app_cpu1/.project @@ -0,0 +1,38 @@ + + + freertos_app_cpu1 + Created by SDK v2019.1. amdc_freertos_bsp_cpu1 - ps7_cortexa9_1 + + amdc_freertos_bsp_cpu1 + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + FreeRTOS-Kernel + 2 + S:/School/WEMPEC/firmware-rtos-e/sdk/FreeRTOS-Kernel + + + shared + 2 + S:/School/WEMPEC/firmware-rtos-e/sdk/shared + + + diff --git a/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h b/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h new file mode 100644 index 00000000..b92d6969 --- /dev/null +++ b/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h @@ -0,0 +1,247 @@ +/* README!!! + * + * This configuration is copied from the FreeRTOS v10.1.1 + * based example project for the Zynq 7000 platform (for + * compatibility). However, you can add to it. + * + * Another example configuration file is available at + * "sdk/FreeRTOS-Kernel/examples/sample_configuration/FreeRTOSConfig.h" + * Because that example is in the submodule, it may update + * from time-to-time when the submodule is updated. + */ + +/* + * Copyright (C) 2018 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "xparameters.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 http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* + * The FreeRTOS Cortex-A port implements a full interrupt nesting model. + * + * Interrupts that are assigned a priority at or below + * configMAX_API_CALL_INTERRUPT_PRIORITY (which counter-intuitively in the ARM + * generic interrupt controller [GIC] means a priority that has a numerical + * value above configMAX_API_CALL_INTERRUPT_PRIORITY) can call FreeRTOS safe API + * functions and will nest. + * + * Interrupts that are assigned a priority above + * configMAX_API_CALL_INTERRUPT_PRIORITY (which in the GIC means a numerical + * value below configMAX_API_CALL_INTERRUPT_PRIORITY) cannot call any FreeRTOS + * API functions, will nest, and will not be masked by FreeRTOS critical + * sections (although it is necessary for interrupts to be globally disabled + * extremely briefly as the interrupt mask is updated in the GIC). + * + * FreeRTOS functions that can be called from an interrupt are those that end in + * "FromISR". FreeRTOS maintains a separate interrupt safe API to enable + * interrupt entry to be shorter, faster, simpler and smaller. + * + * The Zynq implements 256 unique interrupt priorities. For the purpose of + * setting configMAX_API_CALL_INTERRUPT_PRIORITY 255 represents the lowest + * priority. + */ +#define configMAX_API_CALL_INTERRUPT_PRIORITY 18 + +#define configCPU_CLOCK_HZ 100000000UL +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configTICK_RATE_HZ ((TickType_t) 1000) +#define configPERIPHERAL_CLOCK_HZ (33333000UL) +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 // TODO: For low-power, set 1 and implement vApplicationIdleHook() +#define configUSE_TICK_HOOK 0 // TODO: Set as 1 if we want to run function every tick +#define configMAX_PRIORITIES (7) +#define configTOTAL_HEAP_SIZE (125 * 1024) +#define configMAX_TASK_NAME_LEN (10) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* AMDC ADDITION: Need to specify this callback config so we can create message buffers with callbacks + * This is done for Inter-Core Communication (src/sys/icc.c) */ +#define configUSE_SB_COMPLETED_CALLBACK 1 + +/* Include the query-heap CLI command to query the free heap space. */ +#define configINCLUDE_QUERY_HEAP_COMMAND 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) + +/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or undefined) then each task will +be created without an FPU context, and a task must call vTaskUsesFPU() before +making use of any FPU registers. If configUSE_TASK_FPU_SUPPORT is set to 2 then +tasks are created with an FPU context by default, and calling vTaskUsesFPU() has +no effect. */ +#define configUSE_TASK_FPU_SUPPORT 2 +#define configMINIMAL_STACK_SIZE ((unsigned short) 250) // Large since all tasks have FPU context + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 + +/* This demo makes 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 + +/* The private watchdog is used to generate run time stats. */ +/* +#include "xscuwdt.h" +extern XScuWdt xWatchDogInstance; +extern void vInitialiseTimerForRunTimeStats( void ); +#define configGENERATE_RUN_TIME_STATS 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ( ( 0xffffffffUL - XScuWdt_ReadReg( xWatchDogInstance.Config.BaseAddr, +XSCUWDT_COUNTER_OFFSET ) ) >> 1 ) +*/ + +/* The size of the global output buffer that is available for use when there +are multiple command interpreters running at once (for example, one on a UART +and one on TCP/IP). This is done to prevent an output buffer being defined by +each implementation - which would waste RAM. In this case, there is only one +command interpreter running. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled(const char *pcFile, unsigned long ulLine); + +// Original Implementation +//#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ); + +#define configASSERT(x) \ + if ((x) == 0) \ + while (1) \ + ; + +/* If configTASK_RETURN_ADDRESS is not defined then a task that attempts to +return from its implementing function will end up in a "task exit error" +function - which contains a call to configASSERT(). However this can give GCC +some problems when it tries to unwind the stack, as the exit error function has +nothing to return to. To avoid this define configTASK_RETURN_ADDRESS to 0. */ +#define configTASK_RETURN_ADDRESS NULL + +/****** Hardware specific settings. *******************************************/ + +/* + * The application must provide a function that configures a peripheral to + * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() + * in FreeRTOSConfig.h to call the function. This file contains a function + * that is suitable for use on the Zynq MPU. FreeRTOS_Tick_Handler() must + * be installed as the peripheral's interrupt handler. + */ +void vConfigureTickInterrupt(void); +#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() + +void vClearTickInterrupt(void); +#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() + +/* The following constant describe the hardware, and are correct for the +Zynq MPU. */ +#define configINTERRUPT_CONTROLLER_BASE_ADDRESS (XPAR_PS7_SCUGIC_0_DIST_BASEADDR) +#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET (-0xf00) +#define configUNIQUE_INTERRUPT_PRIORITIES 32 + +/****** Network configuration settings - only used when the lwIP example is +built. See the page that documents this demo on the http://www.FreeRTOS.org +website for more information. ***********************************************/ + +/* The priority for the task that unblocked by the MAC interrupt to process +received packets. */ +#define configMAC_INPUT_TASK_PRIORITY (configMAX_PRIORITIES - 1) + +/* The priority of the task that runs the lwIP stack. */ +#define configLWIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) + +/* The priority of the task that uses lwIP sockets to provide a simple command +line interface. */ +#define configCLI_TASK_PRIORITY (tskIDLE_PRIORITY) + +/* MAC address configuration. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x13 +#define configMAC_ADDR2 0x14 +#define configMAC_ADDR3 0x15 +#define configMAC_ADDR4 0x15 +#define configMAC_ADDR5 0x16 + +/* IP address configuration. */ +#define configIP_ADDR0 172 +#define configIP_ADDR1 25 +#define configIP_ADDR2 218 +#define configIP_ADDR3 200 + +/* Netmask configuration. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +#endif /* FREERTOS_CONFIG_H */ diff --git a/sdk/freertos_app_cpu1/src/Xilinx.spec b/sdk/freertos_app_cpu1/src/Xilinx.spec new file mode 100644 index 00000000..9c27dcad --- /dev/null +++ b/sdk/freertos_app_cpu1/src/Xilinx.spec @@ -0,0 +1,2 @@ +*startfile: +crti%O%s crtbegin%O%s diff --git a/sdk/freertos_app_cpu1/src/lscript.ld b/sdk/freertos_app_cpu1/src/lscript.ld new file mode 100644 index 00000000..d1980e29 --- /dev/null +++ b/sdk/freertos_app_cpu1/src/lscript.ld @@ -0,0 +1,295 @@ +/************************************************************************************/ +/* */ +/* This file was automatically generated by the linker script generator, but was */ +/* modified to configure the DRAM regions for Dual-Core apps to run correctly on */ +/* the AMDC's Zynq-7000 SoC */ +/* */ +/* See the documentation here: */ +/* docs.amdc.dev/firmware/xilinx-tools/dual-core.html#configure-dram-memory-regions */ +/* */ +/* */ +/* Version: 2019.1 */ +/* */ +/* Copyright (c) 2010-2016 Xilinx, Inc. All rights reserved. */ +/* */ +/* Description : Cortex-A9 Linker Script */ +/* */ +/************************************************************************************/ + +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000; + +_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; +_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; +_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; +_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; +_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; + +/* Define Memories in the system */ + +MEMORY +{ + ps7_ddr_0 : ORIGIN = 0x20080000, LENGTH = 0x1FF80000 + ps7_qspi_linear_0 : ORIGIN = 0xFC000000, LENGTH = 0x1000000 + ps7_ram_0 : ORIGIN = 0x0, LENGTH = 0x30000 + ps7_ram_1 : ORIGIN = 0xFFFF0000, LENGTH = 0xFE00 +} + +/* Specify the default entry point to the program */ + +ENTRY(_vector_table) + +/* Define the sections, and where they are mapped in memory */ + +SECTIONS +{ +.text : { + *(.freertos_vectors) + KEEP (*(.vectors)) + *(.boot) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.plt) + *(.gnu_warning) + *(.gcc_execpt_table) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > ps7_ddr_0 + +.init : { + KEEP (*(.init)) +} > ps7_ddr_0 + +.fini : { + KEEP (*(.fini)) +} > ps7_ddr_0 + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > ps7_ddr_0 + +.rodata1 : { + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > ps7_ddr_0 + +.sdata2 : { + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > ps7_ddr_0 + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > ps7_ddr_0 + +.data : { + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > ps7_ddr_0 + +.data1 : { + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > ps7_ddr_0 + +.got : { + *(.got) +} > ps7_ddr_0 + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > ps7_ddr_0 + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > ps7_ddr_0 + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > ps7_ddr_0 + +.eh_frame : { + *(.eh_frame) +} > ps7_ddr_0 + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > ps7_ddr_0 + +.gcc_except_table : { + *(.gcc_except_table) +} > ps7_ddr_0 + +.mmu_tbl (ALIGN(16384)) : { + __mmu_tbl_start = .; + *(.mmu_tbl) + __mmu_tbl_end = .; +} > ps7_ddr_0 + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > ps7_ddr_0 + +.preinit_array : { + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > ps7_ddr_0 + +.init_array : { + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > ps7_ddr_0 + +.fini_array : { + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > ps7_ddr_0 + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > ps7_ddr_0 + +.sdata : { + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > ps7_ddr_0 + +.sbss (NOLOAD) : { + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + __sbss_end = .; +} > ps7_ddr_0 + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > ps7_ddr_0 + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > ps7_ddr_0 + +.bss (NOLOAD) : { + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; +} > ps7_ddr_0 + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* Generate Stack and Heap definitions */ + +.heap (NOLOAD) : { + . = ALIGN(16); + _heap = .; + HeapBase = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + HeapLimit = .; +} > ps7_ddr_0 + +.stack (NOLOAD) : { + . = ALIGN(16); + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(16); + _stack = .; + __stack = _stack; + . = ALIGN(16); + _irq_stack_end = .; + . += _IRQ_STACK_SIZE; + . = ALIGN(16); + __irq_stack = .; + _supervisor_stack_end = .; + . += _SUPERVISOR_STACK_SIZE; + . = ALIGN(16); + __supervisor_stack = .; + _abort_stack_end = .; + . += _ABORT_STACK_SIZE; + . = ALIGN(16); + __abort_stack = .; + _fiq_stack_end = .; + . += _FIQ_STACK_SIZE; + . = ALIGN(16); + __fiq_stack = .; + _undef_stack_end = .; + . += _UNDEF_STACK_SIZE; + . = ALIGN(16); + __undef_stack = .; +} > ps7_ddr_0 + +_end = .; +} + diff --git a/sdk/freertos_app_cpu1/src/main.c b/sdk/freertos_app_cpu1/src/main.c new file mode 100644 index 00000000..3565a044 --- /dev/null +++ b/sdk/freertos_app_cpu1/src/main.c @@ -0,0 +1,326 @@ +/* + Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + Copyright (C) 2012 - 2018 Xilinx, Inc. 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. If you wish to use our Amazon + FreeRTOS name, please do so in a fair use way that does not cause confusion. + + 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. + + http://www.FreeRTOS.org + http://aws.amazon.com/freertos + + + 1 tab == 4 spaces! +*/ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "queue.h" +#include "task.h" +#include "timers.h" +/* Xilinx includes. */ +#include "platform.h" +#include "xil_cache.h" +#include "xil_io.h" +#include "xil_mmu.h" +#include "xil_printf.h" +#include "xparameters.h" +/* Firmware includes */ +#include "sys/icc.h" +#include "sys/intr.h" + +/* Begin User Includes */ + +/* End User Includes */ + +#define TIMER_ID 1 +#define DELAY_10_SECONDS 10000UL +#define DELAY_1_SECOND 1000UL +#define TIMER_CHECK_THRESHOLD 9 +/*-----------------------------------------------------------*/ + +/* The Tx and Rx tasks as described at the top of this file. */ +static void prvTxTask(void *pvParameters); +static void prvRxTask(void *pvParameters); +static void vTimerCallback(TimerHandle_t pxTimer); +/*-----------------------------------------------------------*/ + +/* This project has configSUPPORT_STATIC_ALLOCATION set to 1 (for Inter-Core Communication) so + * the following application callback function must be provided to supply the RAM that will + * get used for the Idle task data structures and stack. + */ +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize); + +/* This project has configSUPPORT_STATIC_ALLOCATION set to 1 (for Inter-Core Communication) + * and configUSE_TIMERS set to 1 so the following application callback function must be + * provided to supply the RAM that will get used for the Timer task data structures and stack. + */ +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, + StackType_t **ppxTimerTaskStackBuffer, + uint32_t *pulTimerTaskStackSize); + +/* + * The Xilinx projects use a BSP that do not allow the start up code to be + * altered easily. Therefore the vector table used by FreeRTOS is defined in + * FreeRTOS_asm_vectors.S, which is part of this project. Switch to use the + * FreeRTOS vector table. + */ +extern void vPortInstallFreeRTOSVectorTable(void); + +/*-----------------------------------------------------------*/ + +/* The queue used by the Tx and Rx tasks, as described at the top of this +file. */ + +#define QUEUE_LENGTH 10 +#define ITEM_SIZE sizeof(uint32_t) + +static TaskHandle_t xTxTaskHandle; +static TaskHandle_t xRxTaskHandle; +static QueueHandle_t xQueue = NULL; +static TimerHandle_t xTimer = NULL; + +char HWstring[32] = "CPU1 - Hello World"; +long RxtaskCntr = 0; + +uint8_t message_status = 0; +// 0 - sending messages +// 1 - complete, success +// 2 - complete, failure + +int main(void) +{ + // Both CPUs: Disable cache on OCM + // S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0 + Xil_SetTlbAttributes(0xFFFF0000, 0x14de2); + + intr_init(); + icc_init(); + vPortInstallFreeRTOSVectorTable(); + + /////////////////////////// + // BEGIN USER CODE HERE // + ///////////////////////// + + const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS); + + xil_printf("CPU1 - Hello from FreeRTOS example main()!\r\n"); + + /* Create the two tasks. The Tx task is given a lower priority than the + Rx task, so the Rx task will leave the Blocked state and pre-empt the Tx + task as soon as the Tx task places an item in the queue. */ + xTaskCreate(prvTxTask, /* The function that implements the task. */ + (const char *) "CPU1_Tx", /* Text name for the task, provided to assist debugging only. */ + configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */ + NULL, /* The task parameter is not used, so set to NULL. */ + tskIDLE_PRIORITY, /* The task runs at the idle priority. */ + &xTxTaskHandle); + + xTaskCreate(prvRxTask, /* The function that implements the task. */ + (const char *) "CPU1_Rx", /* Text name for the task, provided to assist debugging only. */ + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 1, + &xRxTaskHandle); + + /* Create the queue used by the tasks. The Rx task has a higher priority + than the Tx task, so will preempt the Tx task and remove values from the + queue as soon as the Tx task writes to the queue - therefore the queue can + never have more than one item in it. */ + xQueue = xQueueCreate(1, sizeof(HWstring)); + + /* Check the queue was created. */ + configASSERT(xQueue); + + /* Create a timer with a timer expiry of 10 seconds. The timer would expire + after 10 seconds and the timer call back would get called. In the timer call back + checks are done to ensure that the tasks have been running properly till then. + The tasks are deleted in the timer call back and a message is printed to convey that + the example has run successfully. + The timer expiry is set to 10 seconds and the timer set to not auto reload. */ + xTimer = xTimerCreate((const char *) "CPU1_Timer", x10seconds, pdFALSE, (void *) TIMER_ID, vTimerCallback); + + /* Check the timer was created. */ + configASSERT(xTimer); + + /* start the timer with a block time of 0 ticks. This means as soon + as the schedule starts the timer will start running and will expire after + 10 seconds */ + xTimerStart(xTimer, 0); + + ///////////////////////// + // END USER CODE HERE // + /////////////////////// + + /* Start the tasks and timer running. */ + 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 + insufficient FreeRTOS heap memory available for the idle and/or timer tasks + to be created. See the memory management section on the FreeRTOS web site + for more details. */ + for (;;) { + } +} + +/*-----------------------------------------------------------*/ +static void prvTxTask(void *pvParameters) +{ + const TickType_t x1second = pdMS_TO_TICKS(DELAY_1_SECOND); + + for (;;) { + if (message_status > 0) { + // Cannot delete tasks created using heap_1 implementation, so instead we suspend immediately if done + vTaskSuspend(NULL); + } else { + /* Delay for 1 second. */ + vTaskDelay(x1second); + + // /* Send the next value on the queue. The queue should always be + // empty at this point so a block time of 0 is used. */ + // xQueueSend(xQueue, /* The queue being written to. */ + // HWstring, /* The address of the data being sent. */ + // 0UL); /* The block time. */ + + xil_printf("DEBUG: CPU 1 about to attempt send\r\n"); + + // Send a message to the other core + size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBuffer, HWstring, sizeof(HWstring), 0UL); + + xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent); + + if (bytes_sent == 0) { + xil_printf("ERROR: CPU 1 failed to write to ICC buffer\r\n"); + } + } + } +} + +/*-----------------------------------------------------------*/ +static void prvRxTask(void *pvParameters) +{ + char Rcvdstring[32] = ""; + + for (;;) { + if (message_status > 0) { + // Cannot delete tasks created using heap_1 implementation, so instead we suspend immediately if done + vTaskSuspend(NULL); + } else { + + // /* Block to wait for data arriving on the queue. */ + // xQueueReceive(xQueue, /* The queue being read. */ + // Rcvdstring, /* Data is read into this address. */ + // portMAX_DELAY); /* Wait without a timeout for data. */ + + xil_printf("DEBUG: CPU 1 about to attempt rcv\r\n"); + + size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBuffer, Rcvdstring, 32, portMAX_DELAY); + + xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer", bytes_rcvd); + + if (bytes_rcvd == 0) { + xil_printf("CPU 1 failed to receive from ICC buffer\r\n"); + } else { + /* Print the received data. */ + xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring); + RxtaskCntr++; + } + } + } +} + +/*-----------------------------------------------------------*/ +static void vTimerCallback(TimerHandle_t pxTimer) +{ + long lTimerId; + configASSERT(pxTimer); + + lTimerId = (long) pvTimerGetTimerID(pxTimer); + + if (lTimerId != TIMER_ID) { + xil_printf("CPU1 - FreeRTOS Hello World Example FAILED"); + } + + /* If the RxtaskCntr is updated every time the Rx task is called. The + Rx task is called every time the Tx task sends a message. The Tx task + sends a message every 1 second. + The timer expires after 10 seconds. We expect the RxtaskCntr to at least + have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ + if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { + message_status = 1; + xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n"); + } else { + message_status = 2; + xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n"); + } +} + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an + * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is + * used by the Idle task. */ +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; +} +/*-----------------------------------------------------------*/ + +/* configUSE_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, + * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} diff --git a/sdk/shared/FreeRTOS_asm_vectors.S b/sdk/shared/FreeRTOS_asm_vectors.S new file mode 100644 index 00000000..f46de6e2 --- /dev/null +++ b/sdk/shared/FreeRTOS_asm_vectors.S @@ -0,0 +1,144 @@ +/****************************************************************************** +* +* (c) Copyright 2009-13 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* @file asm_vectors.s +* +* This file contains the initial vector table for the Cortex A9 processor +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who     Date     Changes
+* ----- ------- -------- ---------------------------------------------------
+* 1.00a ecm/sdm 10/20/09 Initial version
+* 3.05a sdm	02/02/12 Save lr when profiling is enabled
+* 3.10a srt     04/18/13 Implemented ARM Erratas. Please refer to file
+*			 'xil_errata.h' for errata description
+* 
+* +* @note +* +* None. +* +******************************************************************************/ + +#include "xil_errata.h" + +.org 0 +.text +.arm + +.global _boot +.global _freertos_vector_table + +.global FIQInterrupt +.global DataAbortInterrupt +.global PrefetchAbortInterrupt +.global vPortInstallFreeRTOSVectorTable + +.extern FreeRTOS_IRQ_Handler +.extern FreeRTOS_SWI_Handler + +.section .freertos_vectors +_freertos_vector_table: + B _boot + B FreeRTOS_Undefined + ldr pc, _swi + B FreeRTOS_PrefetchAbortHandler + B FreeRTOS_DataAbortHandler + NOP /* Placeholder for address exception vector*/ + LDR PC, _irq + B FreeRTOS_FIQHandler + +_irq: .word FreeRTOS_IRQ_Handler +_swi: .word FreeRTOS_SWI_Handler + + +.align 4 +FreeRTOS_FIQHandler: /* FIQ vector handler */ + stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code */ +FIQLoop: + blx FIQInterrupt /* FIQ vector */ + ldmia sp!,{r0-r3,r12,lr} /* state restore from compiled code */ + subs pc, lr, #4 /* adjust return */ + +.align 4 +FreeRTOS_Undefined: /* Undefined handler */ + b . + +.align 4 +FreeRTOS_DataAbortHandler: /* Data Abort handler */ +#ifdef CONFIG_ARM_ERRATA_775420 + dsb +#endif + stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code */ + blx DataAbortInterrupt /*DataAbortInterrupt :call C function here */ + ldmia sp!,{r0-r3,r12,lr} /* state restore from compiled code */ + subs pc, lr, #4 /* adjust return */ + +.align 4 +FreeRTOS_PrefetchAbortHandler: /* Prefetch Abort handler */ +#ifdef CONFIG_ARM_ERRATA_775420 + dsb +#endif + stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code */ + blx PrefetchAbortInterrupt /* PrefetchAbortInterrupt: call C function here */ + ldmia sp!,{r0-r3,r12,lr} /* state restore from compiled code */ + subs pc, lr, #4 /* adjust return */ + +.align 4 +.type vPortInstallFreeRTOSVectorTable, %function +vPortInstallFreeRTOSVectorTable: + + /* Set VBAR to the vector table that contains the FreeRTOS handlers. */ + ldr r0, =_freertos_vector_table + mcr p15, 0, r0, c12, c0, 0 + dsb + isb + bx lr + + +.end + + + + diff --git a/sdk/shared/FreeRTOS_tick_config.c b/sdk/shared/FreeRTOS_tick_config.c new file mode 100644 index 00000000..8ed8452d --- /dev/null +++ b/sdk/shared/FreeRTOS_tick_config.c @@ -0,0 +1,138 @@ +/* + * FreeRTOS Kernel V10.1.1 + * Copyright (C) 2018 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Xilinx includes. */ +#include "xscugic.h" +#include "xscutimer.h" + +#define XSCUTIMER_CLOCK_HZ (XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 2UL) + +static XScuTimer xTimer; +XScuGic xInterruptController; /* Interrupt controller instance */ + +/* + * The application must provide a function that configures a peripheral to + * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() + * in FreeRTOSConfig.h to call the function. This file contains a function + * that is suitable for use on the Zynq SoC. + */ +void vConfigureTickInterrupt(void) +{ + BaseType_t xStatus; + extern void FreeRTOS_Tick_Handler(void); + XScuTimer_Config *pxTimerConfig; + XScuGic_Config *pxGICConfig; + const uint8_t ucRisingEdge = 3; + + /* This function is called with the IRQ interrupt disabled, and the IRQ + interrupt should be left disabled. It is enabled automatically when the + scheduler is started. */ + + /* Ensure XScuGic_CfgInitialize() has been called. In this demo it has + already been called from prvSetupHardware() in main(). */ + pxGICConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID); + xStatus = XScuGic_CfgInitialize(&xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress); + configASSERT(xStatus == XST_SUCCESS); + (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + /* The priority must be the lowest possible. */ + XScuGic_SetPriorityTriggerType(&xInterruptController, + XPAR_SCUTIMER_INTR, + portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, + ucRisingEdge); + + /* Install the FreeRTOS tick handler. */ + xStatus = XScuGic_Connect( + &xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, (void *) &xTimer); + configASSERT(xStatus == XST_SUCCESS); + (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + /* Initialise the timer. */ + pxTimerConfig = XScuTimer_LookupConfig(XPAR_SCUTIMER_DEVICE_ID); + xStatus = XScuTimer_CfgInitialize(&xTimer, pxTimerConfig, pxTimerConfig->BaseAddr); + configASSERT(xStatus == XST_SUCCESS); + (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + /* Enable Auto reload mode. */ + XScuTimer_EnableAutoReload(&xTimer); + + /* Ensure there is no prescale. */ + XScuTimer_SetPrescaler(&xTimer, 0); + + /* Load the timer counter register. */ + XScuTimer_LoadTimer(&xTimer, XSCUTIMER_CLOCK_HZ / configTICK_RATE_HZ); + + /* Start the timer counter and then wait for it to timeout a number of + times. */ + XScuTimer_Start(&xTimer); + + /* Enable the interrupt for the xTimer in the interrupt controller. */ + XScuGic_Enable(&xInterruptController, XPAR_SCUTIMER_INTR); + + /* Enable the interrupt in the xTimer itself. */ + vClearTickInterrupt(); + XScuTimer_EnableInterrupt(&xTimer); +} +/*-----------------------------------------------------------*/ + +void vClearTickInterrupt(void) +{ + XScuTimer_ClearInterruptStatus(&xTimer); +} +/*-----------------------------------------------------------*/ + +/* This is the callback function which is called by the FreeRTOS Cortex-A port +layer in response to an interrupt. If the function is called +vApplicationFPUSafeIRQHandler() then it is called after the floating point +registers have been saved. If the function is called vApplicationIRQHandler() +then it will be called without first having saved the FPU registers. See +http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html for +more information */ +void vApplicationFPUSafeIRQHandler(uint32_t ulICCIAR) +{ + extern const XScuGic_Config XScuGic_ConfigTable[]; + static const XScuGic_VectorTableEntry *pxVectorTable + = XScuGic_ConfigTable[XPAR_SCUGIC_SINGLE_DEVICE_ID].HandlerTable; + uint32_t ulInterruptID; + const XScuGic_VectorTableEntry *pxVectorEntry; + + /* Re-enable interrupts. */ + __asm("cpsie i"); + + /* The ID of the interrupt is obtained by bitwise anding the ICCIAR value + with 0x3FF. */ + ulInterruptID = ulICCIAR & 0x3FFUL; + if (ulInterruptID < XSCUGIC_MAX_NUM_INTR_INPUTS) { + /* Call the function installed in the array of installed handler functions. */ + pxVectorEntry = &(pxVectorTable[ulInterruptID]); + pxVectorEntry->Handler(pxVectorEntry->CallBackRef); + } +} diff --git a/sdk/shared/README.md b/sdk/shared/README.md new file mode 100644 index 00000000..acf8ca46 --- /dev/null +++ b/sdk/shared/README.md @@ -0,0 +1,30 @@ +# Shared Code Folder + +This folder (`AMDC-Firmware/sdk/shared`) contains source code shared by both CPU applications in the v2, FreeRTOS-based firmware. + +Shared code includes system-level source code for inter-core communication, interrupts, etc, as well as the [FreeRTOS-Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) source code, which is available in `AMDC-Firmware/sdk/FreeRTOS-Kernel` as a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). + +### Differentiating code between CPUs + +If you need to include or run slightly different code on CPU 0 and CPU 1 in a shared source file, it can be done using the `#if` directive like so: + +```c +#include xparameters.h // Must be included to gain access to the XPAR_CPU_ID definition +#include foo.h +#include bar.h + +// Code to be included on both CPUs + +#if XPAR_CPU_ID == 0 + +// Code for CPU 0 only + +#elif XPAR_CPU_ID == 1 + +// Code for CPU 1 only + +#endif + +// More code to be included on both CPUs + +``` diff --git a/sdk/shared/drv/led.c b/sdk/shared/drv/led.c new file mode 100644 index 00000000..a3669709 --- /dev/null +++ b/sdk/shared/drv/led.c @@ -0,0 +1,72 @@ +#include "led.h" +#include "xil_io.h" +#include + +// Color Data Bit Format +// ===================== +// +// NOTE: see datasheet for bit ordering: +// +// 24-bit data format +// +// MSB -- G8R8B8 -- LSB +// +// Bits 23-16 : green +// Bits 15-8 : red +// Bits 7-0 : blue + +void led_init(void) +{ + // Turn off all LEDs to start + for (uint8_t i = 0; i < NUM_LEDS; i++) { + led_set_raw(i, 0); + } +} + +void led_set_color(led_t idx, led_color_t color) +{ + uint32_t raw = 0; + raw |= ((uint32_t) color.g & 0x000000FF) << 16; + raw |= ((uint32_t) color.r & 0x000000FF) << 8; + raw |= ((uint32_t) color.b & 0x000000FF) << 0; + + led_set_raw(idx, raw); +} + +void led_set_color_bytes(led_t idx, uint8_t r, uint8_t g, uint8_t b) +{ + uint32_t raw = 0; + raw |= ((uint32_t) g & 0x000000FF) << 16; + raw |= ((uint32_t) r & 0x000000FF) << 8; + raw |= ((uint32_t) b & 0x000000FF) << 0; + + led_set_raw(idx, raw); +} + +void led_set_raw(led_t idx, uint32_t color) +{ + // NOTE: Writing color values to the device registers will + // automatically trigger the transmission of color data + // out to the LEDs. + // + // The user does not have to manually trigger the transmission. + + Xil_Out32(LED_BASE_ADDR + (idx * sizeof(uint32_t)), color); +} + +led_color_t led_get_color(led_t idx) +{ + uint32_t raw = led_get_raw(idx); + + led_color_t ret; + ret.g = (raw & 0x00FF0000) >> 16; + ret.r = (raw & 0x0000FF00) >> 8; + ret.b = (raw & 0x000000FF) >> 0; + + return ret; +} + +uint32_t led_get_raw(led_t idx) +{ + return Xil_In32(LED_BASE_ADDR + (idx * sizeof(uint32_t))); +} diff --git a/sdk/shared/drv/led.h b/sdk/shared/drv/led.h new file mode 100644 index 00000000..ea6ab5fc --- /dev/null +++ b/sdk/shared/drv/led.h @@ -0,0 +1,42 @@ +#ifndef LED_H +#define LED_H + +#include + +#define LED_BASE_ADDR (XPAR_AMDC_LEDS_0_S00_AXI_BASEADDR) + +typedef struct led_color_t { + uint8_t r; + uint8_t g; + uint8_t b; +} led_color_t; + +// clang-format off +static const led_color_t LED_COLOR_RED = { 020, 000, 000 }; +static const led_color_t LED_COLOR_GREEN = { 000, 020, 000 }; +static const led_color_t LED_COLOR_BLUE = { 000, 000, 020 }; +static const led_color_t LED_COLOR_YELLOW = { 020, 020, 000 }; +static const led_color_t LED_COLOR_CYAN = { 000, 020, 020 }; +static const led_color_t LED_COLOR_MAGENTA = { 020, 000, 020 }; +static const led_color_t LED_COLOR_WHITE = { 020, 020, 020 }; +static const led_color_t LED_COLOR_BLACK = { 000, 000, 000 }; +// clang-format on + +typedef enum { + LED0 = 0, + LED1, + LED2, + LED3, + NUM_LEDS, +} led_t; + +void led_init(void); + +void led_set_color(led_t idx, led_color_t color); +void led_set_color_bytes(led_t idx, uint8_t r, uint8_t g, uint8_t b); +void led_set_raw(led_t idx, uint32_t color); + +led_color_t led_get_color(led_t idx); +uint32_t led_get_raw(led_t idx); + +#endif // LED_H diff --git a/sdk/shared/platform.c b/sdk/shared/platform.c new file mode 100644 index 00000000..97678f86 --- /dev/null +++ b/sdk/shared/platform.c @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * Copyright (C) 2010 - 2015 Xilinx, Inc. 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. + * + * Use of the Software is limited solely to applications: + * (a) running on a Xilinx device, or + * (b) that interact with a Xilinx device through a bus or interconnect. + * + * 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 + * XILINX 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. + * + * Except as contained in this notice, the name of the Xilinx shall not be used + * in advertising or otherwise to promote the sale, use or other dealings in + * this Software without prior written authorization from Xilinx. + * + ******************************************************************************/ + +#include "xil_cache.h" +#include "xparameters.h" + +#include "platform_config.h" + +/* + * Uncomment one of the following two lines, depending on the target, + * if ps7/psu init source files are added in the source directory for + * compiling example outside of SDK. + */ +/*#include "ps7_init.h"*/ +/*#include "psu_init.h"*/ + +#ifdef STDOUT_IS_16550 +#include "xuartns550_l.h" + +#define UART_BAUD 9600 +#endif + +void enable_caches() +{ +#ifdef __PPC__ + Xil_ICacheEnableRegion(CACHEABLE_REGION_MASK); + Xil_DCacheEnableRegion(CACHEABLE_REGION_MASK); +#elif __MICROBLAZE__ +#ifdef XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheEnable(); +#endif +#ifdef XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheEnable(); +#endif +#endif +} + +void disable_caches() +{ + Xil_DCacheDisable(); + Xil_ICacheDisable(); +} + +void init_uart() +{ +#ifdef STDOUT_IS_16550 + XUartNs550_SetBaud(STDOUT_BASEADDR, XPAR_XUARTNS550_CLOCK_HZ, UART_BAUD); + XUartNs550_SetLineControlReg(STDOUT_BASEADDR, XUN_LCR_8_DATA_BITS); +#endif + /* Bootrom/BSP configures PS7/PSU UART to 115200 bps */ +} + +void init_platform() +{ + /* + * If you want to run this example outside of SDK, + * uncomment one of the following two lines and also #include "ps7_init.h" + * or #include "ps7_init.h" at the top, depending on the target. + * Make sure that the ps7/psu_init.c and ps7/psu_init.h files are included + * along with this example source files for compilation. + */ + /* ps7_init();*/ + /* psu_init();*/ + enable_caches(); + init_uart(); +} + +void cleanup_platform() +{ + disable_caches(); +} diff --git a/sdk/shared/platform.h b/sdk/shared/platform.h new file mode 100644 index 00000000..33113bee --- /dev/null +++ b/sdk/shared/platform.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright (C) 2008 - 2014 Xilinx, Inc. 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. + * + * Use of the Software is limited solely to applications: + * (a) running on a Xilinx device, or + * (b) that interact with a Xilinx device through a bus or interconnect. + * + * 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 + * XILINX 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. + * + * Except as contained in this notice, the name of the Xilinx shall not be used + * in advertising or otherwise to promote the sale, use or other dealings in + * this Software without prior written authorization from Xilinx. + * + ******************************************************************************/ + +#ifndef __PLATFORM_H_ +#define __PLATFORM_H_ + +#include "platform_config.h" + +void init_platform(); +void cleanup_platform(); + +#endif diff --git a/sdk/shared/platform_config.h b/sdk/shared/platform_config.h new file mode 100644 index 00000000..3e9b7f18 --- /dev/null +++ b/sdk/shared/platform_config.h @@ -0,0 +1,6 @@ +#ifndef __PLATFORM_CONFIG_H_ +#define __PLATFORM_CONFIG_H_ + +#define STDOUT_IS_PS7_UART +#define UART_DEVICE_ID 0 +#endif diff --git a/sdk/shared/sys/icc.c b/sdk/shared/sys/icc.c new file mode 100644 index 00000000..2673a593 --- /dev/null +++ b/sdk/shared/sys/icc.c @@ -0,0 +1,91 @@ +#include "icc.h" + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +void icc_init(uint32_t cpu_num) +{ +#if XPAR_CPU_ID == 0 + // ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS + + /* Create two message buffers for inter-core communication that use the callback + * functions below as send and receive completed callback functions. */ + xCPU0to1MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, + ICC_CPU0to1_BufferSpaceAddr, + ICC_CPU0to1_BufferStructAddr, + vCPU0to1SendCallback, + vCPU0to1ReceiveCallback); + + xCPU1to0MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, + ICC_CPU1to0_BufferSpaceAddr, + ICC_CPU1to0_BufferStructAddr, + vCPU1to0SendCallback, + vCPU1to0ReceiveCallback); +#endif +} + +/* From FreeRTOS: + * Insert code into callback which is invoked when a message is written to the message buffer. + * This is useful when a message buffer is used to pass messages between + * cores on a multicore processor. In that scenario, this callback + * can be implemented to generate an interrupt in the other CPU core, + * and the interrupt's service routine can then use the + * xMessageBufferSendCompletedFromISR() API function to check, and if + * necessary unblock, a task that was waiting for message. */ + +/* !! IMPORTANT !! + * These callback functions must ALL exist in BOTH CPUs for the above Message Buffer creations + * to work. HOWEVER, the callbacks only have to DO SOMETHING in the relevant CPU + * For example, the behavior of the 0 to 1 Send Callback must be implemented in CPU 0, since + * CPU 0 needs to send an interrupt to CPU 1 when it sends to the buffer. But CPU 1 will never + * send to the 0 to 1 buffer, so in CPU 1 this callback doesn't need to DO ANYTHING except exist. + * - Patrick */ + +void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 0 + xil_printf("DEBUG: CPU 0 to 1 Send Callback reached\r\n"); + // In CPU 0, this callback should send an interrupt to CPU 1's Rx task + XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID); +#endif +} + +void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 0 + xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached\r\n"); + // In CPU 0, this callback should send an interrupt to CPU 1's Tx task + XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID); +#endif +} + +void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 1 + xil_printf("DEBUG: CPU 1 to 0 Send Callback reached\r\n"); + // In CPU 1, this callback should send an interrupt to CPU 0's Rx task + XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID); +#endif +} + +void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 1 + xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached\r\n"); + // In CPU 1, this callback should send an interrupt to CPU 0's Tx task + XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID); +#endif +} diff --git a/sdk/shared/sys/icc.h b/sdk/shared/sys/icc.h new file mode 100644 index 00000000..c8d82879 --- /dev/null +++ b/sdk/shared/sys/icc.h @@ -0,0 +1,89 @@ +#ifndef ICC_H +#define ICC_H + +#include "FreeRTOS.h" +#include "intr.h" +#include "message_buffer.h" +#include "xil_printf.h" +#include + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +// ======================== +// Inter-Core Communication +// ======================== +// +// This module implements communication between the two cores, CPU0 and CPU1. +// CPU0 acts as the master and initializes all shared memory spaces. +// +// In the OCM, we implement two FreeRTOS Message Buffers: one from CPU0 to CPU1, +// and one from CPU1 to CPU0. Each FIFO and associated data are used to build a +// simple producer-consumer system. +// +// This implementation is known to be thread (dual-core) safe. +// +// For more details and pseudo code, see these resources: +// https://www.freertos.org/RTOS-message-buffer-API.html +// https://www.freertos.org/2020/02/simple-multicore-core-to-core-communication-using-freertos-message-buffers.html + +// Per Zynq-7000 TRM Ch. 4: System Addresses (page 106), the initial mapping +// of OCM is split between low addresses and high addresses in 64 KB chunks. +// +// We will pick to use the highest 64 KB chunk as our base address: +#define OCM_BASE_ADDR (0xFFFF0000) +#define ICC_BUFFER_STRUCT_SIZE (sizeof(StaticMessageBuffer_t)) +#define ICC_BUFFER_SIZE (4 * 1024) +#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) + + +/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in shared memory. + * The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. + * The two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual message buffers. */ +#define ICC_CPU0to1_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) +#define ICC_CPU1to0_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) + +#define ICC_CPU0to1_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) + + +/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and gets the handles + * from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything and gets the handles from CPU0, via + * these drop-zones) */ +#define ICC_CPU0to1_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) +#define ICC_CPU1to0_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) + +#define ICC_getCPU0to1Handle (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr)) +#define ICC_setCPU0to1Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr) = handle) +#define ICC_getCPU1to0Handle (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr)) +#define ICC_setCPU1to0Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr) = handle) + + + +/* These are the handles for the Message Buffers that need to be used by other tasks + * In reality, the handle is just the pointer to the message buffer struct (its memory address) + * These should end up being the addresses computed above */ +MessageBufferHandle_t xCPU0to1MessageBuffer; +MessageBufferHandle_t xCPU1to0MessageBuffer; + + +void icc_init(); +void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); +void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); +void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); +void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); + +#endif /* ICC_H */ diff --git a/sdk/shared/sys/intr.c b/sdk/shared/sys/intr.c new file mode 100644 index 00000000..253dcbbc --- /dev/null +++ b/sdk/shared/sys/intr.c @@ -0,0 +1,114 @@ +#include "intr.h" + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +/* The functions in this file are responsible for setting up the + * Xilinx Generic Interrupt Controller (GIC). + * + * Interrupts are needed for Inter-Core Communication, specifically + * the ability to trigger an interrupt in the receiving CPU after a + * message is placed into an empty ICC Message Buffer, + * OR + * the ability to trigger an interrupt in the sending CPU after a + * message is removed from a full ICC Message Buffer + * + * See sys/icc.c for more info. + */ + +int intr_init() +{ + int Status = XST_FAILURE; + + XScuGic_Config *IntcConfig; + + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + XScuGic_CfgInitialize(&InterruptController, IntcConfig, IntcConfig->CpuBaseAddress); + + /* + * Perform a self-test to ensure that the hardware was built + * correctly + */ + Status = XScuGic_SelfTest(&InterruptController); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + // Initialize the interrupt controller + Xil_ExceptionRegisterHandler( + XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &InterruptController); + Xil_ExceptionEnable(); + +#if XPAR_CPU_ID == 0 + // Connect the given interrupt with its handler + XScuGic_Connect(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeRxHandler, NULL); + XScuGic_Connect(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeTxHandler, NULL); + +#elif XPAR_CPU_ID == 1 + // Connect the given interrupt with its handler + XScuGic_Connect(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeRxHandler, NULL); + XScuGic_Connect(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeTxHandler, NULL); +#endif + + /* + // Enable the interrupt for the second CPU core + XScuGic_SetPriorityTriggerType(&InterruptController, INTC_INTERRUPT_ID, 0xA0, 3); // Set priority and trigger type + XScuGic_Enable(&InterruptController, INTC_INTERRUPT_ID); + + // Enable the interrupt for CPU1 + Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_PRIOR_OFFSET + (CPU1_ID * 4), 0xFF); + Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_TARGET_OFFSET + (CPU1_ID * 4), 0x1); + + // Enable interrupts globally + Xil_ExceptionEnableMask(XIL_EXCEPTION_NON_CRITICAL); + + print("Interrupt system setup complete.\r\n"); + */ + + return XST_SUCCESS; +} + +/* We only need to define the handlers in the appropriate core + */ +#if XPAR_CPU_ID == 0 +void CPU0WakeTxHandler() +{ + xil_printf("CPU 0 - WakeTxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +void CPU0WakeRxHandler() +{ + xil_printf("CPU 0 - WakeRxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferSendCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} +#elif XPAR_CPU_ID == 1 +void CPU1WakeTxHandler() +{ + xil_printf("CPU 1 - WakeTxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +void CPU1WakeRxHandler() +{ + xil_printf("CPU 1 - WakeRxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferSendCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} +#endif diff --git a/sdk/shared/sys/intr.h b/sdk/shared/sys/intr.h new file mode 100644 index 00000000..137771a4 --- /dev/null +++ b/sdk/shared/sys/intr.h @@ -0,0 +1,51 @@ +#ifndef INTR_H +#define INTR_H + +#include "FreeRTOS.h" +#include "icc.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include "xparameters.h" +#include "xscugic.h" + +#include +#include +#include + +// test + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +#define CPU0_ID (XSCUGIC_SPI_CPU0_MASK << 0) +#define CPU1_ID (XSCUGIC_SPI_CPU0_MASK << 1) + +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID + +#define INTC_0TO1_SEND_INTERRUPT_ID 0U +#define INTC_1TO0_RCVE_INTERRUPT_ID 1U +#define INTC_1TO0_SEND_INTERRUPT_ID 2U +#define INTC_0TO1_RCVE_INTERRUPT_ID 3U + +// Interrupt Controller Instance +// Defined here to be accessable in sys/icc.c +static XScuGic InterruptController; + +int intr_init(); + +/* We only need to define the handlers in the appropriate core + */ +#if XPAR_CPU_ID == 0 +void CPU0WakeTxHandler(); +void CPU0WakeRxHandler(); +#elif XPAR_CPU_ID == 1 +void CPU1WakeTxHandler(); +void CPU1WakeRxHandler(); +#endif + +#endif /* INTR_H */