Skip to content

Commit b3c0438

Browse files
authored
Zynq7000 demo w/SMP and single core support (#21)
1 parent 353bae8 commit b3c0438

File tree

18 files changed

+3936
-0
lines changed

18 files changed

+3936
-0
lines changed

CORTEX_A9_Zynq7000_GCC/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.o
2+
*.d
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.
2+
# SPDX-License-Identifier: MIT
3+
cmake_minimum_required(VERSION 3.16)
4+
5+
include(${CMAKE_CURRENT_SOURCE_DIR}/Hello_worldExample.cmake)
6+
include(${CMAKE_CURRENT_SOURCE_DIR}/UserConfig.cmake)
7+
set(APP_NAME hello_world)
8+
project(${APP_NAME})
9+
10+
enable_language(C ASM CXX)
11+
find_package(common)
12+
collect(PROJECT_LIB_DEPS xilstandalone)
13+
collect(PROJECT_LIB_DEPS xil)
14+
collect(PROJECT_LIB_DEPS gcc)
15+
collect(PROJECT_LIB_DEPS c)
16+
17+
collect (PROJECT_LIB_SOURCES platform.c)
18+
collect (PROJECT_LIB_SOURCES helloworld.c)
19+
collector_list (_sources PROJECT_LIB_SOURCES)
20+
foreach (source ${_sources})
21+
get_filename_component(ext ${source} EXT)
22+
list(APPEND src_ext ${ext})
23+
endforeach()
24+
25+
find_project_type ("${src_ext}" PROJECT_TYPE)
26+
27+
if("${PROJECT_TYPE}" STREQUAL "c++")
28+
collect(PROJECT_LIB_DEPS stdc++)
29+
endif()
30+
collector_list (_deps PROJECT_LIB_DEPS)
31+
list (APPEND _deps ${USER_LINK_LIBRARIES})
32+
33+
if("${PROJECT_TYPE}" STREQUAL "c++")
34+
string (REPLACE ";" ",-l" _deps "${_deps}")
35+
endif()
36+
if(CMAKE_EXPORT_COMPILE_COMMANDS)
37+
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
38+
set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES})
39+
endif()
40+
linker_gen("${CMAKE_CURRENT_SOURCE_DIR}/linker_files/")
41+
string(APPEND CMAKE_C_FLAGS ${USER_COMPILE_OPTIONS})
42+
string(APPEND CMAKE_CXX_FLAGS ${USER_COMPILE_OPTIONS})
43+
string(APPEND CMAKE_C_LINK_FLAGS ${USER_LINK_OPTIONS})
44+
string(APPEND CMAKE_CXX_LINK_FLAGS ${USER_LINK_OPTIONS})
45+
add_dependency_on_bsp(_sources)
46+
add_executable(${APP_NAME}.elf ${_sources})
47+
set_target_properties(${APP_NAME}.elf PROPERTIES LINK_DEPENDS ${USER_LINKER_SCRIPT})
48+
target_link_libraries(${APP_NAME}.elf -Wl,-T -Wl,\"${USER_LINKER_SCRIPT}\" -L\"${CMAKE_SOURCE_DIR}/\" -L\"${CMAKE_LIBRARY_PATH}/\" -L\"${USER_LINK_DIRECTORIES}/\" -Wl,--start-group,-l${_deps} -Wl,--end-group)
49+
target_compile_definitions(${APP_NAME}.elf PUBLIC ${USER_COMPILE_DEFINITIONS})
50+
target_include_directories(${APP_NAME}.elf PUBLIC ${USER_INCLUDE_DIRECTORIES})
51+
print_elf_size(CMAKE_SIZE ${APP_NAME})

CORTEX_A9_Zynq7000_GCC/FreeRTOSDemo/Demo/FreeRTOSConfig.h

Lines changed: 805 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
/*
2+
* FreeRTOS V202212.00
3+
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
* this software and associated documentation files (the "Software"), to deal in
7+
* the Software without restriction, including without limitation the rights to
8+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
* the Software, and to permit persons to whom the Software is furnished to do so,
10+
* subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in all
13+
* copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*
22+
* https://www.FreeRTOS.org
23+
* https://github.com/FreeRTOS
24+
*
25+
*/
26+
27+
/*
28+
* This file initialises three timers as follows:
29+
*
30+
* Timer 0 and Timer 1 provide the interrupts that are used with the IntQ
31+
* standard demo tasks, which test interrupt nesting and using queues from
32+
* interrupts. Both these interrupts operate below the maximum syscall
33+
* interrupt priority.
34+
*
35+
* Timer 2 is a much higher frequency timer that tests the nesting of interrupts
36+
* that execute above the maximum syscall interrupt priority.
37+
*
38+
* All the timers can nest with the tick interrupt - creating a maximum
39+
* interrupt nesting depth of 4.
40+
*/
41+
42+
/* Scheduler includes. */
43+
#include "FreeRTOS.h"
44+
45+
/* Demo includes. */
46+
#include "IntQueueTimer.h"
47+
#include "IntQueue.h"
48+
49+
/* Xilinx includes. */
50+
#include "xttcps.h"
51+
#include "xscugic.h"
52+
53+
/* The frequencies at which the first two timers expire are slightly offset to
54+
ensure they don't remain synchronised. The frequency of the interrupt that
55+
operates above the max syscall interrupt priority is 10 times faster so really
56+
hammers the interrupt entry and exit code. */
57+
#define tmrTIMERS_USED 3
58+
#define tmrTIMER_0_FREQUENCY ( 2000UL )
59+
#define tmrTIMER_1_FREQUENCY ( 2001UL )
60+
#define tmrTIMER_2_FREQUENCY ( 20000UL )
61+
62+
#if ( configNUMBER_OF_CORES > 1)
63+
/* NOTE: vInitialiseTimerForIntQueueTest is executed on one of the
64+
available cores because it is called, after the scheduler is initialized,
65+
inside one of the tasks created in IntQueue.c.
66+
The timers used to generate the interrupts are SPIs so every core
67+
can configure the interrupts for the core that should handle them.
68+
*/
69+
70+
/* Core that handles the interrupts in multi-core. */
71+
#ifndef configINTERRUPT_QUEUE_TIMER_CORE
72+
#define tmrCORE portCORE0
73+
#else
74+
#if ( configINTERRUPT_QUEUE_TIMER_CORE < 0 || configINTERRUPT_QUEUE_TIMER_CORE >= configNUMBER_OF_CORES )
75+
#error Invalid core ID, accepted values must be 0 <= xCoreID < configNUMBER_OF_CORES.
76+
#endif
77+
78+
#define tmrCORE configINTERRUPT_QUEUE_TIMER_CORE
79+
#endif
80+
#endif
81+
/*-----------------------------------------------------------*/
82+
83+
/*
84+
* The single interrupt service routines that is used to service all three
85+
* timers.
86+
*/
87+
static void prvTimerHandler( void *CallBackRef );
88+
89+
/*-----------------------------------------------------------*/
90+
91+
/* Timer configuration settings. */
92+
typedef struct
93+
{
94+
uint32_t OutputHz; /* Output frequency. */
95+
uint16_t Interval; /* Interval value. */
96+
uint8_t Prescaler; /* Prescaler value. */
97+
uint16_t Options; /* Option settings. */
98+
} TmrCntrSetup;
99+
100+
/* Hardware constants. */
101+
static const BaseType_t xDeviceIDs[ tmrTIMERS_USED ] = { XPAR_XTTCPS_0_DEVICE_ID, XPAR_XTTCPS_1_DEVICE_ID, XPAR_XTTCPS_2_DEVICE_ID };
102+
static const BaseType_t xInterruptIDs[ tmrTIMERS_USED ] = { XPAR_XTTCPS_0_INTR, XPAR_XTTCPS_1_INTR, XPAR_XTTCPS_2_INTR };
103+
104+
/* Timer configuration settings. */
105+
static TmrCntrSetup xTimerSettings[ tmrTIMERS_USED ] =
106+
{
107+
{ tmrTIMER_0_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE },
108+
{ tmrTIMER_1_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE },
109+
{ tmrTIMER_2_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE }
110+
};
111+
112+
/* Lower priority number means higher logical priority, so
113+
configMAX_API_CALL_INTERRUPT_PRIORITY - 1 is above the maximum system call
114+
interrupt priority. */
115+
static const UBaseType_t uxInterruptPriorities[ tmrTIMERS_USED ] =
116+
{
117+
configMAX_API_CALL_INTERRUPT_PRIORITY + 1,
118+
configMAX_API_CALL_INTERRUPT_PRIORITY,
119+
configMAX_API_CALL_INTERRUPT_PRIORITY - 1
120+
};
121+
122+
static XTtcPs xTimerInstances[ tmrTIMERS_USED ];
123+
124+
/* Used to provide a means of ensuring the intended interrupt nesting depth is
125+
actually being reached. */
126+
#if ( configNUMBER_OF_CORES == 1 )
127+
extern volatile uint32_t ulPortInterruptNesting;
128+
#else
129+
extern volatile uint32_t ulPortInterruptNesting[ configNUMBER_OF_CORES ];
130+
#endif
131+
static uint32_t ulMaxRecordedNesting = 0;
132+
133+
/* Used to ensure the high frequency timer is running at the expected
134+
frequency. */
135+
static volatile uint32_t ulHighFrequencyTimerCounts = 0;
136+
/*-----------------------------------------------------------*/
137+
138+
#if ( configNUMBER_OF_CORES == 1 )
139+
void vInitialiseTimerForIntQueueTest( void )
140+
{
141+
BaseType_t xStatus;
142+
TmrCntrSetup *pxTimerSettings;
143+
extern XScuGic xInterruptController;
144+
BaseType_t xTimer;
145+
XTtcPs *pxTimerInstance;
146+
XTtcPs_Config *pxTimerConfiguration;
147+
const uint8_t ucHighLevel = 1;
148+
149+
for( xTimer = 0; xTimer < tmrTIMERS_USED; xTimer++ )
150+
{
151+
/* Look up the timer's configuration. */
152+
pxTimerInstance = &( xTimerInstances[ xTimer ] );
153+
pxTimerConfiguration = XTtcPs_LookupConfig( xDeviceIDs[ xTimer ] );
154+
configASSERT( pxTimerConfiguration );
155+
156+
pxTimerSettings = &( xTimerSettings[ xTimer ] );
157+
158+
/* Initialise the device. */
159+
xStatus = XTtcPs_CfgInitialize( pxTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
160+
if( xStatus != XST_SUCCESS )
161+
{
162+
/* Not sure how to do this before XTtcPs_CfgInitialize is called
163+
as pxTimerInstance is set within XTtcPs_CfgInitialize(). */
164+
XTtcPs_Stop( pxTimerInstance );
165+
xStatus = XTtcPs_CfgInitialize( pxTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
166+
configASSERT( xStatus == XST_SUCCESS );
167+
}
168+
169+
/* Set the options. */
170+
XTtcPs_SetOptions( pxTimerInstance, pxTimerSettings->Options );
171+
172+
/* The timer frequency is preset in the pxTimerSettings structure.
173+
Derive the values for the other structure members. */
174+
XTtcPs_CalcIntervalFromFreq( pxTimerInstance, pxTimerSettings->OutputHz, &( pxTimerSettings->Interval ), &( pxTimerSettings->Prescaler ) );
175+
176+
/* Set the interval and prescale. */
177+
XTtcPs_SetInterval( pxTimerInstance, pxTimerSettings->Interval );
178+
XTtcPs_SetPrescaler( pxTimerInstance, pxTimerSettings->Prescaler );
179+
180+
/* The priority must be the lowest possible. */
181+
XScuGic_SetPriorityTriggerType( &xInterruptController, xInterruptIDs[ xTimer ], uxInterruptPriorities[ xTimer ] << portPRIORITY_SHIFT, ucHighLevel );
182+
183+
/* Connect to the interrupt controller. */
184+
xStatus = XScuGic_Connect( &xInterruptController, xInterruptIDs[ xTimer ], ( Xil_InterruptHandler ) prvTimerHandler, ( void * ) pxTimerInstance );
185+
configASSERT( xStatus == XST_SUCCESS);
186+
187+
/* Enable the interrupt in the GIC. */
188+
XScuGic_Enable( &xInterruptController, xInterruptIDs[ xTimer ] );
189+
190+
/* Enable the interrupts in the timer. */
191+
XTtcPs_EnableInterrupts( pxTimerInstance, XTTCPS_IXR_INTERVAL_MASK );
192+
193+
/* Start the timer. */
194+
XTtcPs_Start( pxTimerInstance );
195+
}
196+
}
197+
198+
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
199+
200+
/* This function is also used to test the interrupt management
201+
APIs provided in the port layer for the applications. */
202+
203+
void vInitialiseTimerForIntQueueTest( void )
204+
{
205+
BaseType_t xStatus;
206+
TmrCntrSetup *pxTimerSettings;
207+
BaseType_t xTimer;
208+
XTtcPs *pxTimerInstance;
209+
XTtcPs_Config *pxTimerConfiguration;
210+
const uint8_t ucHighLevel = 1;
211+
212+
for( xTimer = 0; xTimer < tmrTIMERS_USED; xTimer++ )
213+
{
214+
/* Look up the timer's configuration. */
215+
pxTimerInstance = &( xTimerInstances[ xTimer ] );
216+
pxTimerConfiguration = XTtcPs_LookupConfig( xDeviceIDs[ xTimer ] );
217+
configASSERT( pxTimerConfiguration );
218+
219+
pxTimerSettings = &( xTimerSettings[ xTimer ] );
220+
221+
/* Initialise the device. */
222+
xStatus = XTtcPs_CfgInitialize( pxTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
223+
if( xStatus != XST_SUCCESS )
224+
{
225+
/* Not sure how to do this before XTtcPs_CfgInitialize is called
226+
as pxTimerInstance is set within XTtcPs_CfgInitialize(). */
227+
XTtcPs_Stop( pxTimerInstance );
228+
xStatus = XTtcPs_CfgInitialize( pxTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
229+
configASSERT( xStatus == XST_SUCCESS );
230+
}
231+
232+
/* Set the options. */
233+
XTtcPs_SetOptions( pxTimerInstance, pxTimerSettings->Options );
234+
235+
/* The timer frequency is preset in the pxTimerSettings structure.
236+
Derive the values for the other structure members. */
237+
XTtcPs_CalcIntervalFromFreq( pxTimerInstance, pxTimerSettings->OutputHz, &( pxTimerSettings->Interval ), &( pxTimerSettings->Prescaler ) );
238+
239+
/* Set the interval and prescale. */
240+
XTtcPs_SetInterval( pxTimerInstance, pxTimerSettings->Interval );
241+
XTtcPs_SetPrescaler( pxTimerInstance, pxTimerSettings->Prescaler );
242+
243+
/* The priority must be the lowest possible. */
244+
vPortConfigureInterrupt( xInterruptIDs[ xTimer ], uxInterruptPriorities[ xTimer ] << portPRIORITY_SHIFT, ucHighLevel);
245+
246+
/* Connect to the interrupt controller. */
247+
vPortInstallInterruptHandler( xInterruptIDs[ xTimer ], ( Xil_InterruptHandler ) prvTimerHandler, ( void * ) pxTimerInstance );
248+
249+
/* Enable the interrupt in the GIC for the selected core. */
250+
vPortEnableInterrupt( xInterruptIDs[ xTimer ], tmrCORE );
251+
252+
/* Enable the interrupts in the timer. */
253+
XTtcPs_EnableInterrupts( pxTimerInstance, XTTCPS_IXR_INTERVAL_MASK );
254+
255+
/* Start the timer. */
256+
XTtcPs_Start( pxTimerInstance );
257+
}
258+
}
259+
260+
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
261+
/*-----------------------------------------------------------*/
262+
263+
static void prvTimerHandler( void *pvCallBackRef )
264+
{
265+
uint32_t ulInterruptStatus;
266+
XTtcPs *pxTimer = ( XTtcPs * ) pvCallBackRef;
267+
BaseType_t xYieldRequired;
268+
269+
/* Read the interrupt status to clear the interrupt. */
270+
ulInterruptStatus = XTtcPs_GetInterruptStatus( pxTimer );
271+
__asm volatile ("DSB SY");
272+
__asm volatile ("ISB SY");
273+
274+
/* Only one interrupt event type is expected. */
275+
configASSERT( ( XTTCPS_IXR_INTERVAL_MASK & ulInterruptStatus ) != 0 );
276+
( void ) ulInterruptStatus; /* Prevent compiler warning when configASSERT() is not defined. */
277+
278+
/* Check the device ID to know which IntQueue demo to call. */
279+
if( pxTimer->Config.DeviceId == xDeviceIDs[ 0 ] )
280+
{
281+
282+
xYieldRequired = xFirstTimerHandler();
283+
284+
}
285+
else if( pxTimer->Config.DeviceId == xDeviceIDs[ 1 ] )
286+
{
287+
288+
xYieldRequired = xSecondTimerHandler();
289+
290+
}
291+
else
292+
{
293+
/* Used to check the timer is running at the expected frequency. */
294+
ulHighFrequencyTimerCounts++;
295+
296+
297+
xYieldRequired = pdFALSE;
298+
}
299+
300+
#if ( configNUMBER_OF_CORES == 1 )
301+
/* Latch the highest interrupt nesting count detected. */
302+
if( ulPortInterruptNesting > ulMaxRecordedNesting )
303+
{
304+
ulMaxRecordedNesting = ulPortInterruptNesting;
305+
}
306+
#else
307+
/* Latch the highest interrupt nesting count detected. */
308+
if( ulPortInterruptNesting[ tmrCORE ] > ulMaxRecordedNesting )
309+
{
310+
ulMaxRecordedNesting = ulPortInterruptNesting[ tmrCORE ];
311+
}
312+
313+
/* Check that we are on the correct core. */
314+
configASSERT( portGET_CORE_ID() == tmrCORE );
315+
#endif
316+
317+
/* If xYieldRequired is not pdFALSE then calling either xFirstTimerHandler()
318+
or xSecondTimerHandler() resulted in a task leaving the blocked state and
319+
the task that left the blocked state had a priority higher than the currently
320+
running task (the task this interrupt interrupted) - so a context switch
321+
should be performed so the interrupt returns directly to the higher priority
322+
task. xYieldRequired is tested inside the following macro. */
323+
portYIELD_FROM_ISR( xYieldRequired );
324+
}
325+

0 commit comments

Comments
 (0)