]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_M4_AMP_STM32H745I_Discovery_IAR/CM4/main.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS / Demo / CORTEX_M7_M4_AMP_STM32H745I_Discovery_IAR / CM4 / main.c
1 /*\r
2  * FreeRTOS Kernel V10.3.0\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /*\r
29  * See https://www.freertos.org/STM32H7_Dual_Core_AMP_RTOS_demo.html for usage\r
30  * instructions, and the following blog post for a more detailed explanation\r
31  * https://www.freertos.org/articles/001_simple_freertos_core_to_core_communication/simple_freertos_core_to_core_communication_AMP.html\r
32  *\r
33  * Behavior\r
34  * --------\r
35  *\r
36  * This example stress tests a simple Asymmetric Multi Processing (AMP) core to\r
37  * core communication mechanism implemented using FreeRTOS message buffers:\r
38  * https://www.freertos.org/RTOS-stream-message-buffers.html  Message buffers\r
39  * are used to pass an ASCII representation of an incrementing number (so "0",\r
40  * followed by "1", followed by "2", etc.) from a single 'sending' task that\r
41  * runs on the Arm Cortex-M7 core (the M7 core) to two "receiving" tasks\r
42  * running on the Arm Cortex-M4 core (the M4 core).  There are two data message\r
43  * buffers, one for each receiving task.  To distinguish between the receiving\r
44  * tasks one is assigned the task number 0, and the other task number 1.\r
45  *\r
46  * The M7 task sits in a loop sending the ascii strings to each M4 task.  If a\r
47  * receiving task receives the next expected value in the sequence it prints its\r
48  * task number to the UART.  If a receiving task receives anything else, or its\r
49  * attempt to receive data times out, then it hits an assert() that prints an\r
50  * error message to the UART before stopping all further processing on the M4\r
51  * core.  If the example is running correctly you will see lots of "0"s (from\r
52  * the receiving task assigned task number 0) and "1"s (from the receiving task\r
53  * assigned task number 1) streaming from the UART.  The time taken to output\r
54  * characters from the UART is the only thing throttling the speed of the core\r
55  * to core communication as it causes the message buffers to become full - which\r
56  * would probably happen anyway as the M7 core is executing at twice the\r
57  * frequency of the M4 core.\r
58  *\r
59  *\r
60  * Implementation of sbSEND_COMPLETED()\r
61  * ------------------------------------\r
62  *\r
63  * sbSEND_COMPLETED is a macro called by FreeRTOS after data has been sent to a\r
64  * message buffer in case there was a task blocked on the message buffer waiting\r
65  * for data to become available - in which case the waiting task would be\r
66  * unblocked:  https://www.freertos.org/RTOS-message-buffer-example.html\r
67  * However, the default sbSEND_COMPLETED implementation assumes the sending task\r
68  * (or interrupt) and the receiving task are under the control of the same\r
69  * instance of the FreeRTOS kernel and run on the same MCU core.  In this AMP\r
70  * example the sending task and the receiving tasks are under the control of two\r
71  * different instances of the FreeRTOS kernel, and run on different MCU cores,\r
72  * so the default sbSEND_COMPLETED implementation won't work (each FreeRTOS\r
73  * kernel instance only knowns about the tasks under its control).  AMP\r
74  * scenarios therefore require the sbSEND_COMPLETED macro (and potentially the\r
75  * sbRECEIVE_COMPLETED macro, see below) to be overridden, which is done by\r
76  * simply providing your own implementation in the project's FreeRTOSConfig.h\r
77  * file.  Note this example has a FreeRTOSConfig.h file used by the application\r
78  * that runs on the M7 core and a separate FreeRTOSConfig.h file used by the\r
79  * application that runs on the M4 core.  The implementation of sbSEND_COMPLETED\r
80  * used by the M7 core simply triggers an interrupt in the M4 core.  The\r
81  * interrupt's handler (the ISR that was triggered by the M7 core but executes\r
82  * on the M4 core) must then do the job that would otherwise be done by the\r
83  * default implementation of sbSEND_COMPLETE - namely unblock a task if the task\r
84  * was waiting to receive data from the message buffer that now contains data.\r
85  * There are two data message buffers though, so first ISR must determine which\r
86  * of the two contains data.\r
87  *\r
88  * This demo only has two data message buffers, so it would be reasonable to\r
89  * have the ISR simply query both to see which contained data, but that solution\r
90  * would not scale if there are many message buffers, or if the number of\r
91  * message buffers was unknown.  Therefore, to demonstrate a more scalable\r
92  * solution, this example introduced a third message buffer - a 'control'\r
93  * message buffer as opposed to a 'data' message buffer.  After the task on the\r
94  * M7 core writes to a data message buffer it writes the handle of the message\r
95  * buffer that contains data to the control message buffer.  The ISR running on\r
96  * the M4 core then reads from the control message buffer to know which data\r
97  * message buffer contains data.\r
98  *\r
99  * The above described scenario contains many implementation decisions.\r
100  * Alternative methods of enabling the M4 core to know data message buffer\r
101  * contains data include:\r
102  *\r
103  *  1) Using a different interrupt for each data message buffer.\r
104  *  2) Passing all data from the M7 core to the M4 core through a single message\r
105  *     buffer, along with additional data that tells the ISR running on the M4\r
106  *     core which task to forward the data to.\r
107  *\r
108  *\r
109  * Implementation of sbRECEIVE_COMPLETED()\r
110  * ---------------------------------------\r
111  *\r
112  * sbRECEIVE_COMPLETED is the complement of sbSEND_COMPLETED.  It is a macro\r
113  * called by FreeRTOS after data has been read from a message buffer in case\r
114  * there was a task blocked on the message buffer waiting for space to become\r
115  * available - in which case the waiting task would be unblocked so it can\r
116  * complete its write to the buffer.\r
117  *\r
118  * In this example the M7 task writes to the message buffers faster than the M4\r
119  * tasks read from them (in part because the M7 is running faster, and in part\r
120  * because the M4 cores write to the UART), so the buffers become full, and the\r
121  * M7 task enters the Blocked state to wait for space to become available.  As\r
122  * with the sbSEND_COMPLETED macro, the default implementation of the\r
123  * sbRECEIVE_COMPLETED macro only works if the sender and receiver are under the\r
124  * control of the same instance of FreeRTOS and execute on the same core.\r
125  * Therefore, just as the application that executes on the M7 core overrides\r
126  * the default implementation of sbSEND_SOMPLETED(), the application that runs\r
127  * on the M4 core overrides the default implementation of sbRECEIVE_COMPLETED()\r
128  * to likewise generate an interrupt in the M7 core - so sbRECEIVE_COMPLETED()\r
129  * executes on the M4 core and generates an interrupt on the M7 core.  To keep\r
130  * things simple the ISR that runs on the M7 core does not use a control\r
131  * message buffer to know which data message buffer contains space, and instead\r
132  * simply sends a notification to both data message buffers.  Note however that\r
133  * this overly simplistic implementation is only acceptable because it is\r
134  * known that there is only one sending task, and that task cannot be blocked on\r
135  * both message buffers at the same time.  Also, sending the notification to the\r
136  * data message buffer updates the receiving task's direct to task notification\r
137  * state: https://www.freertos.org/RTOS-task-notifications.html which is only ok\r
138  * because it is known the task is not using its notification state for any\r
139  * other purpose.\r
140  *\r
141  */\r
142 \r
143 /* Standard includes. */\r
144 #include "stdio.h"\r
145 #include "string.h"\r
146 \r
147 /* STM32 includes. */\r
148 #include "stm32h7xx_hal.h"\r
149 #include "stm32h745i_discovery.h"\r
150 \r
151 /* FreeRTOS includes. */\r
152 #include "FreeRTOS.h"\r
153 #include "task.h"\r
154 #include "message_buffer.h"\r
155 \r
156 /* Demo includes. */\r
157 #include "MessageBufferLocations.h"\r
158 \r
159 /*-----------------------------------------------------------*/\r
160 \r
161 /* Seen as an infinite block by the ST HAL. */\r
162 #define mainHAL_MAX_TIMEOUT     0xFFFFFFFFUL\r
163 \r
164 /* When the cores boot they very crudely wait for each other in a non chip\r
165 specific way by waiting for the other core to start incrementing a shared\r
166 variable within an array.  mainINDEX_TO_TEST sets the index within the array to\r
167 the variable this core tests to see if it is incrementing, and\r
168 mainINDEX_TO_INCREMENT sets the index within the array to the variable this core\r
169 increments to indicate to the other core that it is at the sync point.  Note\r
170 this is not a foolproof method and it is better to use a hardware specific\r
171 solution, such as having one core boot the other core when it was ready, or\r
172 using some kind of shared semaphore or interrupt. */\r
173 #define mainINDEX_TO_TEST               1\r
174 #define mainINDEX_TO_INCREMENT  0\r
175 \r
176 /*-----------------------------------------------------------*/\r
177 \r
178 /*\r
179  * Implements the tasks that receive messages from the M7 core.\r
180  */\r
181 static void prvM4CoreTasks( void *pvParameters );\r
182 \r
183 /*\r
184  * The interrupt triggered by the M7 core when there is data available in the\r
185  * message buffer used for core to core communication.\r
186  */\r
187 void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin );\r
188 \r
189 /*\r
190  * Just waits to see a variable being incremented by the M7 core to know when\r
191  * the M7 has created the message buffers used for core to core communication.\r
192  */\r
193 static void prvWaitForOtherCoreToStart( uint32_t ulIndexToTest, uint32_t ulIndexToIncrement );\r
194 \r
195 /*\r
196  * Configures the hardware ready to run this demo.\r
197  */\r
198 static void prvSetupHardware( void );\r
199 \r
200 /*-----------------------------------------------------------*/\r
201 \r
202 /* Handle to the UART used to output strings. */\r
203 static UART_HandleTypeDef xUARTHandle = { 0 };\r
204 \r
205 /*-----------------------------------------------------------*/\r
206 \r
207 int main( void )\r
208 {\r
209 static const uint8_t pucBootMessage[] = "\r\nM4 started and waiting for the M7 to run.\r\n";\r
210 static const uint8_t pucCreatingTasksMessage[] = "M4 core proceeding to create demo tasks.\r\n";\r
211 uint32_t x;\r
212 \r
213         /*** See the comments at the top of this page ***/\r
214 \r
215 \r
216         /* Prep the hardware to run this demo. */\r
217         prvSetupHardware();\r
218 \r
219         /* The M4 core task prints its status out at various places so you know what\r
220         it is doing when debugging the M7 core.  This messages is just to indicate\r
221         it has booted and is about to wait for the M7 core.  If the M7 is already\r
222         running then reset the hardware so both cores start at once. */\r
223         HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pucBootMessage, sizeof( pucBootMessage ), mainHAL_MAX_TIMEOUT );\r
224         prvWaitForOtherCoreToStart( mainINDEX_TO_TEST, mainINDEX_TO_INCREMENT );\r
225 \r
226         /* By this point the M7 should have initialized the message buffers used to\r
227         send data from the M7 to the M4 core.  The message buffers are statically\r
228         allocated at a known location so both cores know where they are.  See\r
229         MessageBufferLocations.h. */\r
230         configASSERT( ( xControlMessageBuffer != NULL ) && ( xDataMessageBuffers[ 0 ] != NULL ) && ( xDataMessageBuffers[ 1 ] != NULL ) );\r
231 \r
232         /* Everything seems as expected - print a message to say the M4 is about to\r
233         create the tasks that receive data from the M7 core. */\r
234         HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pucCreatingTasksMessage, sizeof( pucCreatingTasksMessage ), mainHAL_MAX_TIMEOUT );\r
235 \r
236         for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
237         {\r
238                 /* Pass the loop counter into the created task using the task's\r
239                 parameter.  The task then uses the value as an index into the\r
240                 xDataMessageBuffers arrays. */\r
241                 xTaskCreate( prvM4CoreTasks,                    /* Function that implements the task. */\r
242                                         "AMPM4Core",                                    /* Task name, for debugging only. */\r
243                                         configMINIMAL_STACK_SIZE,       /* Size of stack to allocate for this task - in words. */\r
244                                         ( void * ) x,                           /* Task parameter. */\r
245                                         tskIDLE_PRIORITY + 1,           /* Task priority. */\r
246                                         NULL );                                         /* Task handle.  Not used in this case. */\r
247         }\r
248 \r
249         /* Start scheduler */\r
250         vTaskStartScheduler();\r
251 \r
252         /* Will not get here if the scheduler starts successfully.  If you do end up\r
253         here then there wasn't enough heap memory available to start either the idle\r
254         task or the timer/daemon task.  https://www.freertos.org/a00111.html */\r
255         for( ;; );\r
256 }\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 static void prvM4CoreTasks( void *pvParameters )\r
260 {\r
261 static const uint8_t pucTaskStartedMessage[] = "M4 task started.\r\n";\r
262 BaseType_t xTaskNumber;\r
263 size_t xReceivedBytes;\r
264 uint32_t ulNextValue = 0;\r
265 char cExpectedString[ 15 ];\r
266 char cReceivedString[ 15 ];\r
267 char cMessage;\r
268 const TickType_t xShortBlockTime = pdMS_TO_TICKS( 200 );\r
269 \r
270         /* This task is created more than once so the task's parameter is used to\r
271         pass in a task number, which is then used as an index into the message\r
272         buffer array. */\r
273         xTaskNumber = ( BaseType_t ) pvParameters;\r
274         configASSERT( xTaskNumber < mbaNUMBER_OF_CORE_2_TASKS );\r
275 \r
276         vTaskSuspendAll();\r
277         {\r
278                 /* Message transmitted to indicate the task has started. */\r
279                 HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pucTaskStartedMessage, sizeof( pucTaskStartedMessage ), mainHAL_MAX_TIMEOUT );\r
280         }\r
281         xTaskResumeAll();\r
282 \r
283         /* The tasks print out a letter to indicate that the expected message was\r
284         received from the other core. */\r
285         if( xTaskNumber == 0 )\r
286         {\r
287                 cMessage = '0';\r
288         }\r
289         else\r
290         {\r
291                 cMessage = '1';\r
292         }\r
293 \r
294         for( ;; )\r
295         {\r
296                 /* The M7 core creates and sends to this core an ascii string of an\r
297                 incrementing number.  Create the string that is expected to be received\r
298                 this time round the loop. */\r
299                 sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue );\r
300 \r
301                 /* Wait to receive the next message from core 1. */\r
302                 memset( cReceivedString, 0x00, sizeof( cReceivedString ) );\r
303                 xReceivedBytes = xMessageBufferReceive( /* Handle of message buffer. */\r
304                                                                                                 xDataMessageBuffers[ xTaskNumber ],\r
305                                                                                                 /* Buffer into which received data is placed. */\r
306                                                                                                 cReceivedString,\r
307                                                                                                 /* Size of the receive buffer. */\r
308                                                                                                 sizeof( cReceivedString ),\r
309                                                                                                 /* Time to wait for data to arrive. */\r
310                                                                                                 xShortBlockTime );\r
311 \r
312                 /* Check the number of bytes received was as expected. */\r
313                 configASSERT( xReceivedBytes == strlen( cExpectedString ) );\r
314 \r
315                 /* If the received string matches that expected then output the task\r
316                 number to give visible indication that the task is still running. */\r
317                 if( strcmp( cReceivedString, cExpectedString ) == 0 )\r
318                 {\r
319                         /* Also print out the task number to give a visual indication that\r
320                         the M4 core is receiving the expected data. */\r
321                         vTaskSuspendAll();\r
322                         {\r
323                                 HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) &cMessage, sizeof( cMessage ), mainHAL_MAX_TIMEOUT );\r
324                         }\r
325                         xTaskResumeAll();\r
326                 }\r
327 \r
328                 /* Expect the next string in sequence the next time around. */\r
329                 ulNextValue++;\r
330         }\r
331 }\r
332 /*-----------------------------------------------------------*/\r
333 \r
334 void vGenerateM4ToM7Interrupt( void * xUpdatedMessageBuffer )\r
335 {\r
336         /* Called by the implementation of sbRECEIVE_COMPLETED() in FreeRTOSConfig.h.\r
337         See the comments at the top of this file.  Write the handle of the data\r
338         message buffer to which data was written to the control message buffer. */\r
339 \r
340         /* Generate interrupt in the M7 core. */\r
341         HAL_EXTI_D2_EventInputConfig( EXTI_LINE1, EXTI_MODE_IT, DISABLE );\r
342         HAL_EXTI_D1_EventInputConfig( EXTI_LINE1, EXTI_MODE_IT, ENABLE );\r
343         HAL_EXTI_GenerateSWInterrupt( EXTI_LINE1 );\r
344 }\r
345 /*-----------------------------------------------------------*/\r
346 \r
347 void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin )\r
348 {\r
349 MessageBufferHandle_t xUpdatedMessageBuffer;\r
350 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
351 \r
352         /* Avoid compiler warnings about unused parameters. */\r
353         ( void ) GPIO_Pin;\r
354 \r
355         /* Clear interrupt. */\r
356         HAL_EXTI_D2_ClearFlag( EXTI_LINE0 );\r
357 \r
358         configASSERT( ( xControlMessageBuffer != NULL ) && ( xDataMessageBuffers[ 0 ] != NULL ) && ( xDataMessageBuffers[ 1 ] != NULL ) );\r
359 \r
360         /* In this example there are mbaNUMBER_OF_CORE_2_TASKS receiving tasks that\r
361         run on the M4 core.  It would be possible for the M7 core to use a single\r
362         message buffer to send to both tasks, but that would require additional data\r
363         to be sent to the message buffer - namely an identifier to indicate which\r
364         receiving task a message was intended for along with some arbitration in the\r
365         ISR.  As an alternative, this example uses one message buffer per receiving\r
366         task and a control message buffer.  The M7 core sends data to a receiving\r
367         task using that task's dedicated message buffer, then sends the handle of\r
368         the message buffer that it just sent data to to the control task.  This\r
369         interrupt service routine receives the handle from the control task then\r
370         uses the handle to signal the message buffer that contains the data.\r
371 \r
372         Receive the handle of the message buffer that contains data from the\r
373         control message buffer. */\r
374         while( xMessageBufferReceiveFromISR(    xControlMessageBuffer,\r
375                                                                                         &xUpdatedMessageBuffer,\r
376                                                                                         sizeof( xUpdatedMessageBuffer ),\r
377                                                                                         &xHigherPriorityTaskWoken ) == sizeof( xUpdatedMessageBuffer ) )\r
378         {\r
379                 /* Call the API function that sends a notification to any task that is\r
380                 blocked on the xUpdatedMessageBuffer message buffer waiting for data to\r
381                 arrive. */\r
382                 xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );\r
383         }\r
384 \r
385         /* Normal FreeRTOS "yield from interrupt" semantics, where\r
386         xHigherPriorityTaskWoken is initialised to pdFALSE and will then get set to\r
387         pdTRUE if the interrupt unblocks a task that has a priority above that of\r
388         the currently executing task. */\r
389         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
390 }\r
391 /*-----------------------------------------------------------*/\r
392 \r
393 static void prvWaitForOtherCoreToStart( uint32_t ulIndexToTest, uint32_t ulIndexToIncrement )\r
394 {\r
395 volatile uint32_t ulInitialCount = ulStartSyncCounters[ ulIndexToTest ];\r
396 \r
397         /* When the cores boot they very crudely wait for each other in a non chip\r
398         specific way by waiting for the other core to start incrementing a shared\r
399         variable within an array.  mainINDEX_TO_TEST sets the index within the array\r
400         to the variable this core tests to see if it is incrementing, and\r
401         mainINDEX_TO_INCREMENT sets the index within the array to the variable this\r
402         core increments to indicate to the other core that it is at the sync point.\r
403         Note this is not a foolproof method and it is better to use a hardware\r
404         specific solution, such as having one core boot the other core when it was\r
405         ready, or using some kind of shared semaphore or interrupt. */\r
406 \r
407         for( ;; )\r
408         {\r
409                 /* Indicate to the M7 core that this core is at the synchronisation\r
410                 point. */\r
411                 ulStartSyncCounters[ ulIndexToIncrement ]++;\r
412 \r
413                 /* Has the counter incremented by the other core changed? */\r
414                 if( ulStartSyncCounters[ ulIndexToTest ] != ulInitialCount )\r
415                 {\r
416                         break;\r
417                 }\r
418         }\r
419 \r
420         /* One more increment before exiting to avoid race. */\r
421         ulStartSyncCounters[ ulIndexToIncrement ]++;\r
422 }\r
423 /*-----------------------------------------------------------*/\r
424 \r
425 void vAssertCalled( const char *pcFile, const uint32_t ulLine )\r
426 {\r
427 char pcLine[ 10 ];\r
428 const uint8_t pucM4AssertFile[] = "M4 Assert hit in file ";\r
429 const uint8_t pucM4AssertLine[] = "on line number ";\r
430 \r
431         /* Assert disables interrupts so no other code can run, prints out the\r
432         location of the offending assert(), then loops doing nothing waiting for\r
433         the user to inspect or reset. */\r
434         taskDISABLE_INTERRUPTS();\r
435         HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pucM4AssertFile, sizeof( pucM4AssertFile ), mainHAL_MAX_TIMEOUT );\r
436         HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pcFile, strlen( pcFile ), mainHAL_MAX_TIMEOUT );\r
437         HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pucM4AssertLine, sizeof( pucM4AssertLine ), mainHAL_MAX_TIMEOUT );\r
438         sprintf( pcLine, "%u\r\n", ulLine );\r
439         HAL_UART_Transmit( &xUARTHandle, ( uint8_t * ) pcLine, strlen( pcLine ), mainHAL_MAX_TIMEOUT );\r
440         for( ;; );\r
441 }\r
442 /*-----------------------------------------------------------*/\r
443 \r
444 static void prvSetupHardware( void )\r
445 {\r
446         /* Prevent the HAL's initialisation of SysTick actually starting the systick\r
447         interrupt as the kernel has not started yet. */\r
448         taskDISABLE_INTERRUPTS();\r
449         HAL_Init();\r
450         BSP_LED_Init( LED2 );\r
451 \r
452         /* This core uses the UART, so initialise it. */\r
453         xUARTHandle.Instance = USART3;\r
454         xUARTHandle.Init.BaudRate = 115200;\r
455         xUARTHandle.Init.WordLength = UART_WORDLENGTH_8B;\r
456         xUARTHandle.Init.StopBits = UART_STOPBITS_1;\r
457         xUARTHandle.Init.Parity = UART_PARITY_NONE;\r
458         xUARTHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;\r
459         xUARTHandle.Init.Mode = UART_MODE_TX_RX;\r
460         xUARTHandle.Init.ClockPrescaler = UART_PRESCALER_DIV1;\r
461         xUARTHandle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;\r
462         xUARTHandle.Init.OverSampling = UART_OVERSAMPLING_16;\r
463         HAL_UART_Init( &xUARTHandle );\r
464         HAL_UARTEx_SetRxFifoThreshold( &xUARTHandle, UART_RXFIFO_THRESHOLD_1_4 );\r
465         HAL_UARTEx_EnableFifoMode( &xUARTHandle );\r
466 \r
467         /* AIEC Common configuration: make CPU1 and CPU2 SWI line1 sensitive to\r
468         rising edge. */\r
469         HAL_EXTI_EdgeConfig( EXTI_LINE1, EXTI_RISING_EDGE );\r
470 \r
471         /* Interrupt used for M7 to M4 notifications. */\r
472         HAL_NVIC_SetPriority( EXTI0_IRQn, 0xFU, 0U );\r
473         HAL_NVIC_EnableIRQ( EXTI0_IRQn );\r
474 }\r