]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_M4_AMP_STM32H745I_Discovery_IAR/CM7/main.c
87b41ee2163800148877f006dadcac9960f9fdc2
[freertos] / FreeRTOS / Demo / CORTEX_M7_M4_AMP_STM32H745I_Discovery_IAR / CM7 / main.c
1 /*\r
2  * FreeRTOS Kernel V10.2.0\r
3  * Copyright (C) 2019 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 (TBD, not available at the time of writing).\r
31  *\r
32  * Behavior\r
33  * --------\r
34  *\r
35  * This example stress tests a simple Asymmetric Multi Processing (AMP) core to\r
36  * core communication mechanism implemented using FreeRTOS message buffers:\r
37  * https://www.freertos.org/RTOS-stream-message-buffers.html  Message buffers\r
38  * are used to pass an ASCII representation of an incrementing number (so "0",\r
39  * followed by "1", followed by "2", etc.) from a single 'sending' task that\r
40  * runs on the Arm Cortex-M7 core (the M7 core) to two "receiving" tasks\r
41  * running on the Arm Cortex-M4 core (the M4 core).  There are two data message\r
42  * buffers, one for each receiving task.  To distinguish between the receiving\r
43  * tasks one is assigned the task number 0, and the other task number 1.\r
44  *\r
45  * The M7 task sits in a loop sending the ascii strings to each M4 task.  If a\r
46  * receiving task receives the next expected value in the sequence it prints its\r
47  * task number to the UART.  If a receiving task receives anything else, or its\r
48  * attempt to receive data times out, then it hits an assert() that prints an\r
49  * error message to the UART before stopping all further processing on the M4\r
50  * core.  If the example is running correctly you will see lots of "0"s (from\r
51  * the receiving task assigned task number 0) and "1"s (from the receiving task\r
52  * assigned task number 1) streaming from the UART.  The time taken to output\r
53  * characters from the UART is the only thing throttling the speed of the core\r
54  * to core communication as it causes the message buffers to become full - which\r
55  * would probably happen anyway as the M7 core is executing at twice the\r
56  * frequency of the M4 core.\r
57  *\r
58  *\r
59  * Implementation of sbSEND_COMPLETED()\r
60  * ------------------------------------\r
61  *\r
62  * sbSEND_COMPLETED is a macro called by FreeRTOS after data has been sent to a\r
63  * message buffer in case there was a task blocked on the message buffer waiting\r
64  * for data to become available - in which case the waiting task would be\r
65  * unblocked:  https://www.freertos.org/RTOS-message-buffer-example.html\r
66  * However, the default sbSEND_COMPLETED implementation assumes the sending task\r
67  * (or interrupt) and the receiving task are under the control of the same\r
68  * instance of the FreeRTOS kernel and run on the same MCU core.  In this AMP\r
69  * example the sending task and the receiving tasks are under the control of two\r
70  * different instances of the FreeRTOS kernel, and run on different MCU cores,\r
71  * so the default sbSEND_COMPLETED implementation won't work (each FreeRTOS\r
72  * kernel instance only knowns about the tasks under its control).  AMP\r
73  * scenarios therefore require the sbSEND_COMPLETED macro (and potentially the\r
74  * sbRECEIVE_COMPLETED macro, see below) to be overridden, which is done by\r
75  * simply providing your own implementation in the project's FreeRTOSConfig.h\r
76  * file.  Note this example has a FreeRTOSConfig.h file used by the application\r
77  * that runs on the M7 core and a separate FreeRTOSConfig.h file used by the\r
78  * application that runs on the M4 core.  The implementation of sbSEND_COMPLETED\r
79  * used by the M7 core simply triggers an interrupt in the M4 core.  The\r
80  * interrupt's handler (the ISR that was triggered by the M7 core but executes\r
81  * on the M4 core) must then do the job that would otherwise be done by the\r
82  * default implementation of sbSEND_COMPLETE - namely unblock a task if the task\r
83  * was waiting to receive data from the message buffer that now contains data.\r
84  * There are two data message buffers though, so first ISR must determine which\r
85  * of the two contains data.\r
86  *\r
87  * This demo only has two data message buffers, so it would be reasonable to\r
88  * have the ISR simply query both to see which contained data, but that solution\r
89  * would not scale if there are many message buffers, or if the number of\r
90  * message buffers was unknown.  Therefore, to demonstrate a more scalable\r
91  * solution, this example introduced a third message buffer - a 'control'\r
92  * message buffer as opposed to a 'data' message buffer.  After the task on the\r
93  * M7 core writes to a data message buffer it writes the handle of the message\r
94  * buffer that contains data to the control message buffer.  The ISR running on\r
95  * the M4 core then reads from the control message buffer to know which data\r
96  * message buffer contains data.\r
97  *\r
98  * The above described scenario contains many implementation decisions.\r
99  * Alternative methods of enabling the M4 core to know data message buffer\r
100  * contains data include:\r
101  *\r
102  *  1) Using a different interrupt for each data message buffer.\r
103  *  2) Passing all data from the M7 core to the M4 core through a single message\r
104  *     buffer, along with additional data that tells the ISR running on the M4\r
105  *     core which task to forward the data to.\r
106  *\r
107  *\r
108  * Implementation of sbRECEIVE_COMPLETED()\r
109  * ---------------------------------------\r
110  *\r
111  * sbRECEIVE_COMPLETED is the complement of sbSEND_COMPLETED.  It is a macro\r
112  * called by FreeRTOS after data has been read from a message buffer in case\r
113  * there was a task blocked on the message buffer waiting for space to become\r
114  * available - in which case the waiting task would be unblocked so it can\r
115  * complete its write to the buffer.\r
116  *\r
117  * In this example the M7 task writes to the message buffers faster than the M4\r
118  * tasks read from them (in part because the M7 is running faster, and in part\r
119  * because the M4 cores write to the UART), so the buffers become full, and the\r
120  * M7 task enters the Blocked state to wait for space to become available.  As\r
121  * with the sbSEND_COMPLETED macro, the default implementation of the\r
122  * sbRECEIVE_COMPLETED macro only works if the sender and receiver are under the\r
123  * control of the same instance of FreeRTOS and execute on the same core.\r
124  * Therefore, just as the application that executes on the M7 core overrides\r
125  * the default implementation of sbSEND_SOMPLETED(), the application that runs\r
126  * on the M4 core overrides the default implementation of sbRECEIVE_COMPLETED()\r
127  * to likewise generate an interrupt in the M7 core - so sbRECEIVE_COMPLETED()\r
128  * executes on the M4 core and generates an interrupt on the M7 core.  To keep\r
129  * things simple the ISR that runs on the M7 core does not use a control\r
130  * message buffer to know which data message buffer contains space, and instead\r
131  * simply sends a notification to both data message buffers.  Note however that\r
132  * this overly simplistic implementation is only acceptable because it is\r
133  * known that there is only one sending task, and that task cannot be blocked on\r
134  * both message buffers at the same time.  Also, sending the notification to the\r
135  * data message buffer updates the receiving task's direct to task notification\r
136  * state: https://www.freertos.org/RTOS-task-notifications.html which is only ok\r
137  * because it is known the task is not using its notification state for any\r
138  * other purpose.\r
139  *\r
140  */\r
141 \r
142 /* Standard includes. */\r
143 #include "stdio.h"\r
144 #include "string.h"\r
145 \r
146 /* FreeRTOS includes. */\r
147 #include "FreeRTOS.h"\r
148 #include "task.h"\r
149 #include "message_buffer.h"\r
150 #include "MessageBufferLocations.h"\r
151 \r
152 /* ST includes. */\r
153 #include "stm32h7xx_hal.h"\r
154 #include "stm32h745i_discovery.h"\r
155 \r
156 /* When the cores boot they very crudely wait for each other in a non chip\r
157 specific way by waiting for the other core to start incrementing a shared\r
158 variable within an array.  mainINDEX_TO_TEST sets the index within the array to\r
159 the variable this core tests to see if it is incrementing, and\r
160 mainINDEX_TO_INCREMENT sets the index within the array to the variable this core\r
161 increments to indicate to the other core that it is at the sync point.  Note\r
162 this is not a foolproof method and it is better to use a hardware specific\r
163 solution, such as having one core boot the other core when it was ready, or\r
164 using some kind of shared semaphore or interrupt. */\r
165 #define mainINDEX_TO_TEST               0\r
166 #define mainINDEX_TO_INCREMENT  1\r
167 \r
168 /*-----------------------------------------------------------*/\r
169 \r
170 /*\r
171  * Implements the task that sends messages to the M7 core.\r
172  */\r
173 static void prvM7CoreTasks( void *pvParameters );\r
174 \r
175 /*\r
176  * configSUPPORT_STATIC_ALLOCATION is set to 1, requiring this callback to\r
177  * provide statically allocated data for use by the idle task, which is a task\r
178  * created by the scheduler when it starts.\r
179  */\r
180 void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, uint32_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );\r
181 \r
182 /*\r
183  * Just waits to see a variable being incremented by the M4 core to know when\r
184  * the M4 has created the message buffers used for core to core communication.\r
185  */\r
186 static void prvWaitForOtherCoreToStart( uint32_t ulIndexToTest, uint32_t ulIndexToIncrement );\r
187 \r
188 /*\r
189  * Setup the hardware ready to run this demo.\r
190  */\r
191 static void prvSetupHardware( void );\r
192 \r
193 /*-----------------------------------------------------------*/\r
194 \r
195 static TaskHandle_t xM7AMPTask = NULL;\r
196 \r
197 int main( void )\r
198 {\r
199 BaseType_t x;\r
200 \r
201         /*** See the comments at the top of this page ***/\r
202 \r
203         prvSetupHardware();\r
204 \r
205         /* Create the control and data message buffers, as described at the top of\r
206         this file.  The message buffers are statically allocated at a known location\r
207         as both cores need to know where they are.  See MessageBufferLocations.h. */\r
208         xControlMessageBuffer = xMessageBufferCreateStatic( /* The buffer size in bytes. */\r
209                                                                                                                 mbaCONTROL_MESSAGE_BUFFER_SIZE,\r
210                                                                                                                 /* Statically allocated buffer storage area. */\r
211                                                                                                                 ucControlBufferStorage,\r
212                                                                                                                 /* Message buffer handle. */\r
213                                                                                                                 &xControlMessageBufferStruct );\r
214         for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
215         {\r
216                 xDataMessageBuffers[ x ] = xMessageBufferCreateStatic( mbaTASK_MESSAGE_BUFFER_SIZE,\r
217                                                                                                                            &( ucDataBufferStorage[ x ][ 0 ] ),\r
218                                                                                                                            &( xDataMessageBufferStructs[ x ] ) );\r
219         }\r
220 \r
221         /* The message buffers have been initialised so it is safe for both cores to\r
222         synchronise their startup. */\r
223         prvWaitForOtherCoreToStart( mainINDEX_TO_TEST, mainINDEX_TO_INCREMENT );\r
224 \r
225         /* Start the task that executes on the M7 core. */\r
226         xTaskCreate( prvM7CoreTasks,                    /* Function that implements the task. */\r
227                                  "AMPM7Core",                           /* Task name, for debugging only. */\r
228                                  configMINIMAL_STACK_SIZE,  /* Size of stack (in words) to allocate for this task. */\r
229                                  NULL,                                          /* Task parameter, not used in this case. */\r
230                                  tskIDLE_PRIORITY,                      /* Task priority. */\r
231                                  &xM7AMPTask );                         /* Task handle, used to unblock task from interrupt. */\r
232 \r
233         /* Start scheduler */\r
234         vTaskStartScheduler();\r
235 \r
236         /* Will not get here if the scheduler starts successfully.  If you do end up\r
237         here then there wasn't enough heap memory available to start either the idle\r
238         task or the timer/daemon task.  https://www.freertos.org/a00111.html */\r
239         for( ;; );\r
240 }\r
241 /*-----------------------------------------------------------*/\r
242 \r
243 static void prvM7CoreTasks( void *pvParameters )\r
244 {\r
245 BaseType_t x;\r
246 uint32_t ulNextValue = 0;\r
247 const TickType_t xDelay = pdMS_TO_TICKS( 25 );\r
248 char cString[ 15 ];\r
249 size_t xStringLength;\r
250 \r
251         /* Remove warning about unused parameters. */\r
252         ( void ) pvParameters;\r
253 \r
254         for( ;; )\r
255         {\r
256                 /* Create the next string to send.  The value is incremented on each\r
257                 loop iteration, and the length of the string changes as the number of\r
258                 digits in the value increases. */\r
259                 sprintf( cString, "%lu", ( unsigned long ) ulNextValue );\r
260                 xStringLength = strlen( cString );\r
261 \r
262                 /* This task runs on the M7 core, use the message buffers to send the\r
263                 strings to the tasks running on the M4 core.  This will result in\r
264                 sbSEND_COMPLETED() being executed, which in turn will write the handle\r
265                 of the message buffer written to into xControlMessageBuffer then\r
266                 generate an interrupt in M4 core. */\r
267                 for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
268                 {\r
269                         while( xMessageBufferSend(      xDataMessageBuffers[ x ],\r
270                                                                                 ( void * ) cString,\r
271                                                                                 xStringLength,\r
272                                                                                 portMAX_DELAY ) != xStringLength );\r
273 \r
274                         /* Delay before repeating */\r
275 //                      vTaskDelay( xDelay );\r
276                 }\r
277 \r
278                 ulNextValue++;\r
279         }\r
280 }\r
281 /*-----------------------------------------------------------*/\r
282 \r
283 void vGenerateM7ToM4Interrupt( void * xUpdatedMessageBuffer )\r
284 {\r
285 MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;\r
286 \r
287         /* Called by the implementation of sbSEND_COMPLETED() in FreeRTOSConfig.h.\r
288         See the comments at the top of this file.  Write the handle of the data\r
289         message buffer to which data was written to the control message buffer. */\r
290         if( xUpdatedBuffer != xControlMessageBuffer )\r
291         {\r
292                 while( xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK ) != sizeof( xUpdatedBuffer ) )\r
293                 {\r
294                         /* Nothing to do here.  Note it is very bad to loop in an interrupt\r
295                         service routine.  If a loop is really required then defer the\r
296                         routine to a task. */\r
297                 }\r
298 \r
299                 /* Generate interrupt in the M4 core. */\r
300                 HAL_EXTI_D1_EventInputConfig( EXTI_LINE0, EXTI_MODE_IT, DISABLE );\r
301                 HAL_EXTI_D2_EventInputConfig( EXTI_LINE0, EXTI_MODE_IT, ENABLE );\r
302                 HAL_EXTI_GenerateSWInterrupt( EXTI_LINE0 );\r
303         }\r
304 }\r
305 /*-----------------------------------------------------------*/\r
306 \r
307 void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, uint32_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )\r
308 {\r
309 /* If the buffers to be provided to the Idle task are declared inside this\r
310 function then they must be declared static - otherwise they will be allocated on\r
311 the stack and so not exists after this function exits. */\r
312 static StaticTask_t xIdleTaskTCB;\r
313 static uint32_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];\r
314 \r
315         /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide\r
316         an implementation of vApplicationGetIdleTaskMemory() to provide the memory\r
317         that is used by the Idle task.\r
318         https://www.freertos.org/a00110.html#configSUPPORT_STATIC_ALLOCATION */\r
319 \r
320         /* Pass out a pointer to the StaticTask_t structure in which the Idle task's\r
321         state will be stored. */\r
322         *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;\r
323 \r
324         /* Pass out the array that will be used as the Idle task's stack. */\r
325         *ppxIdleTaskStackBuffer = uxIdleTaskStack;\r
326 \r
327         /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.\r
328         Note that, as the array is necessarily of type StackType_t,\r
329         configMINIMAL_STACK_SIZE is specified in words, not bytes. */\r
330         *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;\r
331 }\r
332 /*-----------------------------------------------------------*/\r
333 \r
334 static void prvWaitForOtherCoreToStart( uint32_t ulIndexToTest, uint32_t ulIndexToIncrement )\r
335 {\r
336 volatile uint32_t ulInitialCount = ulStartSyncCounters[ ulIndexToTest ], x;\r
337 const uint32_t ulCrudeLoopDelay = 0xfffffUL;\r
338 \r
339         /* When the cores boot they very crudely wait for each other in a non chip\r
340         specific way by waiting for the other core to start incrementing a shared\r
341         variable within an array.  mainINDEX_TO_TEST sets the index within the array\r
342         to the variable this core tests to see if it is incrementing, and\r
343         mainINDEX_TO_INCREMENT sets the index within the array to the variable this\r
344         core increments to indicate to the other core that it is at the sync point.\r
345         Note this is not a foolproof method and it is better to use a hardware\r
346         specific solution, such as having one core boot the other core when it was\r
347         ready, or using some kind of shared semaphore or interrupt. */\r
348 \r
349         /* Wait for the other core to reach the synchronisation point. */\r
350         while( ulStartSyncCounters[ ulIndexToTest ] == ulInitialCount );\r
351         ulInitialCount = ulStartSyncCounters[ ulIndexToTest ];\r
352 \r
353         for( ;; )\r
354         {\r
355                 ulStartSyncCounters[ ulIndexToIncrement ]++;\r
356                 if( ulStartSyncCounters[ ulIndexToTest ] != ulInitialCount )\r
357                 {\r
358                         ulStartSyncCounters[ ulIndexToIncrement ]++;\r
359                         break;\r
360                 }\r
361 \r
362                 /* Unlike the M4 core, this core does not have direct access to the UART,\r
363                 so simply toggle an LED to show its status. */\r
364                 for( x = 0; x < ulCrudeLoopDelay; x++ ) __asm volatile( "NOP" );\r
365                 BSP_LED_Off( LED2 );\r
366                 for( x = 0; x < ulCrudeLoopDelay; x++ ) __asm volatile( "NOP" );\r
367                 BSP_LED_On( LED2 );\r
368         }\r
369 }\r
370 /*-----------------------------------------------------------*/\r
371 \r
372 void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin )\r
373 {\r
374 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
375 uint32_t x;\r
376 \r
377         configASSERT( xM7AMPTask );\r
378 \r
379         HAL_EXTI_D1_ClearFlag( EXTI_LINE1 );\r
380 \r
381         /* Task can't be blocked on both so just send the notification to both. */\r
382         for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
383         {\r
384                 xMessageBufferReceiveCompletedFromISR( xDataMessageBuffers[ x ], &xHigherPriorityTaskWoken );\r
385         }\r
386 \r
387         /* Normal FreeRTOS "yield from interrupt" semantics, where\r
388         xHigherPriorityTaskWoken is initialzed to pdFALSE and will then get set to\r
389         pdTRUE if the interrupt unblocks a task that has a priority above that of\r
390         the currently executing task. */\r
391         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
392 }\r
393 /*-----------------------------------------------------------*/\r
394 \r
395 static void prvSetupHardware( void )\r
396 {\r
397 MPU_Region_InitTypeDef MPU_InitStruct;\r
398 RCC_ClkInitTypeDef RCC_ClkInitStruct;\r
399 RCC_OscInitTypeDef RCC_OscInitStruct;\r
400 \r
401         /* Configure the MPU attributes as Not Cachable for Internal D3SRAM.  The\r
402         Base Address is 0x38000000 (D3_SRAM_BASE), and the size is 64K. */\r
403         HAL_MPU_Disable();\r
404         MPU_InitStruct.Enable = MPU_REGION_ENABLE;\r
405         MPU_InitStruct.BaseAddress = D3_SRAM_BASE;\r
406         MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;\r
407         MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;\r
408         MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;\r
409         MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;\r
410         MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;\r
411         MPU_InitStruct.Number = MPU_REGION_NUMBER0;\r
412         MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;\r
413         MPU_InitStruct.SubRegionDisable = 0x00;\r
414         MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;\r
415         HAL_MPU_ConfigRegion(&MPU_InitStruct);\r
416         HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);\r
417 \r
418         /* Enable I-Cache */\r
419         SCB_EnableICache();\r
420 \r
421         /* Enable D-Cache */\r
422         SCB_EnableDCache();\r
423 \r
424         HAL_Init();\r
425         BSP_LED_Init(LED1);\r
426 \r
427 \r
428         /*\r
429         System Clock Configuration:\r
430                 System Clock source    = PLL (HSE)\r
431                 SYSCLK(Hz)             = 400000000 (Cortex-M7 CPU Clock)\r
432                 HCLK(Hz)               = 200000000 (Cortex-M4 CPU, Bus matrix Clocks)\r
433                 AHB Prescaler          = 2\r
434                 D1 APB3 Prescaler      = 2 (APB3 Clock  100MHz)\r
435                 D2 APB1 Prescaler      = 2 (APB1 Clock  100MHz)\r
436                 D2 APB2 Prescaler      = 2 (APB2 Clock  100MHz)\r
437                 D3 APB4 Prescaler      = 2 (APB4 Clock  100MHz)\r
438                 HSE Frequency(Hz)      = 25000000\r
439                 PLL_M                  = 5\r
440                 PLL_N                  = 160\r
441                 PLL_P                  = 2\r
442                 PLL_Q                  = 4\r
443                 PLL_R                  = 2\r
444                 VDD(V)                 = 3.3\r
445                 Flash Latency(WS)      = 4\r
446         */\r
447 \r
448         HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);\r
449 \r
450         /* The voltage scaling allows optimizing the power consumption when the\r
451         device is clocked below the maximum system frequency, to update the voltage\r
452         scaling value regarding system frequency refer to product datasheet. */\r
453         __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);\r
454 \r
455         while( !__HAL_PWR_GET_FLAG( PWR_FLAG_VOSRDY ) )\r
456         {\r
457                 __asm volatile ( "NOP" );\r
458         }\r
459 \r
460         /* Enable HSE Oscillator and activate PLL with HSE as source */\r
461         RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;\r
462         RCC_OscInitStruct.HSEState = RCC_HSE_ON;\r
463         RCC_OscInitStruct.HSIState = RCC_HSI_OFF;\r
464         RCC_OscInitStruct.CSIState = RCC_CSI_OFF;\r
465         RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;\r
466         RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;\r
467 \r
468         RCC_OscInitStruct.PLL.PLLM = 5;\r
469         RCC_OscInitStruct.PLL.PLLN = 160;\r
470         RCC_OscInitStruct.PLL.PLLFRACN = 0;\r
471         RCC_OscInitStruct.PLL.PLLP = 2;\r
472         RCC_OscInitStruct.PLL.PLLR = 2;\r
473         RCC_OscInitStruct.PLL.PLLQ = 4;\r
474 \r
475         RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;\r
476         RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;\r
477         configASSERT( HAL_RCC_OscConfig( &RCC_OscInitStruct ) == HAL_OK );\r
478 \r
479         /* Select PLL as system clock source and configure  bus clocks dividers */\r
480         RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \\r
481                                                                     RCC_CLOCKTYPE_PCLK2  | RCC_CLOCKTYPE_D3PCLK1 );\r
482 \r
483         RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;\r
484         RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;\r
485         RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;\r
486         RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;\r
487         RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;\r
488         RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;\r
489         RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;\r
490         configASSERT( HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_4 ) == HAL_OK );\r
491 \r
492         /* AIEC Common configuration: make CPU1 and CPU2 SWI line0 sensitive to\r
493         rising edge. */\r
494         HAL_EXTI_EdgeConfig( EXTI_LINE0, EXTI_RISING_EDGE );\r
495 \r
496         /* Interrupt used for M4 to M7 notifications. */\r
497         HAL_NVIC_SetPriority( EXTI1_IRQn, 0xFU, 0U );\r
498         HAL_NVIC_EnableIRQ( EXTI1_IRQn );\r
499 }\r
500 \r