--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.2.0\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/*\r
+ * See https://www.freertos.org/STM32H7_Dual_Core_AMP_RTOS_demo.html for usage\r
+ * instructions (TBD, not available at the time of writing).\r
+ *\r
+ * Behavior\r
+ * --------\r
+ *\r
+ * This example stress tests a simple Asymmetric Multi Processing (AMP) core to\r
+ * core communication mechanism implemented using FreeRTOS message buffers:\r
+ * https://www.freertos.org/RTOS-stream-message-buffers.html Message buffers\r
+ * are used to pass an ASCII representation of an incrementing number (so "0",\r
+ * followed by "1", followed by "2", etc.) from a single 'sending' task that\r
+ * runs on the Arm Cortex-M7 core (the M7 core) to two "receiving" tasks\r
+ * running on the Arm Cortex-M4 core (the M4 core). There are two data message\r
+ * buffers, one for each receiving task. To distinguish between the receiving\r
+ * tasks one is assigned the task number 0, and the other task number 1.\r
+ *\r
+ * The M7 task sits in a loop sending the ascii strings to each M4 task. If a\r
+ * receiving task receives the next expected value in the sequence it prints its\r
+ * task number to the UART. If a receiving task receives anything else, or its\r
+ * attempt to receive data times out, then it hits an assert() that prints an\r
+ * error message to the UART before stopping all further processing on the M4\r
+ * core. If the example is running correctly you will see lots of "0"s (from\r
+ * the receiving task assigned task number 0) and "1"s (from the receiving task\r
+ * assigned task number 1) streaming from the UART. The time taken to output\r
+ * characters from the UART is the only thing throttling the speed of the core\r
+ * to core communication as it causes the message buffers to become full - which\r
+ * would probably happen anyway as the M7 core is executing at twice the\r
+ * frequency of the M4 core.\r
+ *\r
+ *\r
+ * Implementation of sbSEND_COMPLETED()\r
+ * ------------------------------------\r
+ *\r
+ * sbSEND_COMPLETED is a macro called by FreeRTOS after data has been sent to a\r
+ * message buffer in case there was a task blocked on the message buffer waiting\r
+ * for data to become available - in which case the waiting task would be\r
+ * unblocked: https://www.freertos.org/RTOS-message-buffer-example.html\r
+ * However, the default sbSEND_COMPLETED implementation assumes the sending task\r
+ * (or interrupt) and the receiving task are under the control of the same\r
+ * instance of the FreeRTOS kernel and run on the same MCU core. In this AMP\r
+ * example the sending task and the receiving tasks are under the control of two\r
+ * different instances of the FreeRTOS kernel, and run on different MCU cores,\r
+ * so the default sbSEND_COMPLETED implementation won't work (each FreeRTOS\r
+ * kernel instance only knowns about the tasks under its control). AMP\r
+ * scenarios therefore require the sbSEND_COMPLETED macro (and potentially the\r
+ * sbRECEIVE_COMPLETED macro, see below) to be overridden, which is done by\r
+ * simply providing your own implementation in the project's FreeRTOSConfig.h\r
+ * file. Note this example has a FreeRTOSConfig.h file used by the application\r
+ * that runs on the M7 core and a separate FreeRTOSConfig.h file used by the\r
+ * application that runs on the M4 core. The implementation of sbSEND_COMPLETED\r
+ * used by the M7 core simply triggers an interrupt in the M4 core. The\r
+ * interrupt's handler (the ISR that was triggered by the M7 core but executes\r
+ * on the M4 core) must then do the job that would otherwise be done by the\r
+ * default implementation of sbSEND_COMPLETE - namely unblock a task if the task\r
+ * was waiting to receive data from the message buffer that now contains data.\r
+ * There are two data message buffers though, so first ISR must determine which\r
+ * of the two contains data.\r
+ *\r
+ * This demo only has two data message buffers, so it would be reasonable to\r
+ * have the ISR simply query both to see which contained data, but that solution\r
+ * would not scale if there are many message buffers, or if the number of\r
+ * message buffers was unknown. Therefore, to demonstrate a more scalable\r
+ * solution, this example introduced a third message buffer - a 'control'\r
+ * message buffer as opposed to a 'data' message buffer. After the task on the\r
+ * M7 core writes to a data message buffer it writes the handle of the message\r
+ * buffer that contains data to the control message buffer. The ISR running on\r
+ * the M4 core then reads from the control message buffer to know which data\r
+ * message buffer contains data.\r
+ *\r
+ * The above described scenario contains many implementation decisions.\r
+ * Alternative methods of enabling the M4 core to know data message buffer\r
+ * contains data include:\r
+ *\r
+ * 1) Using a different interrupt for each data message buffer.\r
+ * 2) Passing all data from the M7 core to the M4 core through a single message\r
+ * buffer, along with additional data that tells the ISR running on the M4\r
+ * core which task to forward the data to.\r
+ *\r
+ *\r
+ * Implementation of sbRECEIVE_COMPLETED()\r
+ * ---------------------------------------\r
+ *\r
+ * sbRECEIVE_COMPLETED is the complement of sbSEND_COMPLETED. It is a macro\r
+ * called by FreeRTOS after data has been read from a message buffer in case\r
+ * there was a task blocked on the message buffer waiting for space to become\r
+ * available - in which case the waiting task would be unblocked so it can\r
+ * complete its write to the buffer.\r
+ *\r
+ * In this example the M7 task writes to the message buffers faster than the M4\r
+ * tasks read from them (in part because the M7 is running faster, and in part\r
+ * because the M4 cores write to the UART), so the buffers become full, and the\r
+ * M7 task enters the Blocked state to wait for space to become available. As\r
+ * with the sbSEND_COMPLETED macro, the default implementation of the\r
+ * sbRECEIVE_COMPLETED macro only works if the sender and receiver are under the\r
+ * control of the same instance of FreeRTOS and execute on the same core.\r
+ * Therefore, just as the application that executes on the M7 core overrides\r
+ * the default implementation of sbSEND_SOMPLETED(), the application that runs\r
+ * on the M4 core overrides the default implementation of sbRECEIVE_COMPLETED()\r
+ * to likewise generate an interrupt in the M7 core - so sbRECEIVE_COMPLETED()\r
+ * executes on the M4 core and generates an interrupt on the M7 core. To keep\r
+ * things simple the ISR that runs on the M7 core does not use a control\r
+ * message buffer to know which data message buffer contains space, and instead\r
+ * simply sends a notification to both data message buffers. Note however that\r
+ * this overly simplistic implementation is only acceptable because it is\r
+ * known that there is only one sending task, and that task cannot be blocked on\r
+ * both message buffers at the same time. Also, sending the notification to the\r
+ * data message buffer updates the receiving task's direct to task notification\r
+ * state: https://www.freertos.org/RTOS-task-notifications.html which is only ok\r
+ * because it is known the task is not using its notification state for any\r
+ * other purpose.\r
+ *\r
+ */\r
+\r
+/* Standard includes. */\r
+#include "stdio.h"\r
+#include "string.h"\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "message_buffer.h"\r
+#include "MessageBufferLocations.h"\r
+\r
+/* ST includes. */\r
+#include "stm32h7xx_hal.h"\r
+#include "stm32h745i_discovery.h"\r
+\r
+/* When the cores boot they very crudely wait for each other in a non chip\r
+specific way by waiting for the other core to start incrementing a shared\r
+variable within an array. mainINDEX_TO_TEST sets the index within the array to\r
+the variable this core tests to see if it is incrementing, and\r
+mainINDEX_TO_INCREMENT sets the index within the array to the variable this core\r
+increments to indicate to the other core that it is at the sync point. Note\r
+this is not a foolproof method and it is better to use a hardware specific\r
+solution, such as having one core boot the other core when it was ready, or\r
+using some kind of shared semaphore or interrupt. */\r
+#define mainINDEX_TO_TEST 0\r
+#define mainINDEX_TO_INCREMENT 1\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Implements the task that sends messages to the M7 core.\r
+ */\r
+static void prvM7CoreTasks( void *pvParameters );\r
+\r
+/*\r
+ * configSUPPORT_STATIC_ALLOCATION is set to 1, requiring this callback to\r
+ * provide statically allocated data for use by the idle task, which is a task\r
+ * created by the scheduler when it starts.\r
+ */\r
+void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, uint32_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );\r
+\r
+/*\r
+ * Just waits to see a variable being incremented by the M4 core to know when\r
+ * the M4 has created the message buffers used for core to core communication.\r
+ */\r
+static void prvWaitForOtherCoreToStart( uint32_t ulIndexToTest, uint32_t ulIndexToIncrement );\r
+\r
+/*\r
+ * Setup the hardware ready to run this demo.\r
+ */\r
+static void prvSetupHardware( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+static TaskHandle_t xM7AMPTask = NULL;\r
+\r
+int main( void )\r
+{\r
+BaseType_t x;\r
+\r
+ /*** See the comments at the top of this page ***/\r
+\r
+ prvSetupHardware();\r
+\r
+ /* Create the control and data message buffers, as described at the top of\r
+ this file. The message buffers are statically allocated at a known location\r
+ as both cores need to know where they are. See MessageBufferLocations.h. */\r
+ xControlMessageBuffer = xMessageBufferCreateStatic( /* The buffer size in bytes. */\r
+ mbaCONTROL_MESSAGE_BUFFER_SIZE,\r
+ /* Statically allocated buffer storage area. */\r
+ ucControlBufferStorage,\r
+ /* Message buffer handle. */\r
+ &xControlMessageBufferStruct );\r
+ for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
+ {\r
+ xDataMessageBuffers[ x ] = xMessageBufferCreateStatic( mbaTASK_MESSAGE_BUFFER_SIZE,\r
+ &( ucDataBufferStorage[ x ][ 0 ] ),\r
+ &( xDataMessageBufferStructs[ x ] ) );\r
+ }\r
+\r
+ /* The message buffers have been initialised so it is safe for both cores to\r
+ synchronise their startup. */\r
+ prvWaitForOtherCoreToStart( mainINDEX_TO_TEST, mainINDEX_TO_INCREMENT );\r
+\r
+ /* Start the task that executes on the M7 core. */\r
+ xTaskCreate( prvM7CoreTasks, /* Function that implements the task. */\r
+ "AMPM7Core", /* Task name, for debugging only. */\r
+ configMINIMAL_STACK_SIZE, /* Size of stack (in words) to allocate for this task. */\r
+ NULL, /* Task parameter, not used in this case. */\r
+ tskIDLE_PRIORITY, /* Task priority. */\r
+ &xM7AMPTask ); /* Task handle, used to unblock task from interrupt. */\r
+\r
+ /* Start scheduler */\r
+ vTaskStartScheduler();\r
+\r
+ /* Will not get here if the scheduler starts successfully. If you do end up\r
+ here then there wasn't enough heap memory available to start either the idle\r
+ task or the timer/daemon task. https://www.freertos.org/a00111.html */\r
+ for( ;; );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvM7CoreTasks( void *pvParameters )\r
+{\r
+BaseType_t x;\r
+uint32_t ulNextValue = 0;\r
+const TickType_t xDelay = pdMS_TO_TICKS( 25 );\r
+char cString[ 15 ];\r
+size_t xStringLength;\r
+\r
+ /* Remove warning about unused parameters. */\r
+ ( void ) pvParameters;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Create the next string to send. The value is incremented on each\r
+ loop iteration, and the length of the string changes as the number of\r
+ digits in the value increases. */\r
+ sprintf( cString, "%lu", ( unsigned long ) ulNextValue );\r
+ xStringLength = strlen( cString );\r
+\r
+ /* This task runs on the M7 core, use the message buffers to send the\r
+ strings to the tasks running on the M4 core. This will result in\r
+ sbSEND_COMPLETED() being executed, which in turn will write the handle\r
+ of the message buffer written to into xControlMessageBuffer then\r
+ generate an interrupt in M4 core. */\r
+ for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
+ {\r
+ while( xMessageBufferSend( xDataMessageBuffers[ x ],\r
+ ( void * ) cString,\r
+ xStringLength,\r
+ portMAX_DELAY ) != xStringLength );\r
+\r
+ /* Delay before repeating */\r
+// vTaskDelay( xDelay );\r
+ }\r
+\r
+ ulNextValue++;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vGenerateM7ToM4Interrupt( void * xUpdatedMessageBuffer )\r
+{\r
+MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;\r
+\r
+ /* Called by the implementation of sbSEND_COMPLETED() in FreeRTOSConfig.h.\r
+ See the comments at the top of this file. Write the handle of the data\r
+ message buffer to which data was written to the control message buffer. */\r
+ if( xUpdatedBuffer != xControlMessageBuffer )\r
+ {\r
+ while( xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK ) != sizeof( xUpdatedBuffer ) )\r
+ {\r
+ /* Nothing to do here. Note it is very bad to loop in an interrupt\r
+ service routine. If a loop is really required then defer the\r
+ routine to a task. */\r
+ }\r
+\r
+ /* Generate interrupt in the M4 core. */\r
+ HAL_EXTI_D1_EventInputConfig( EXTI_LINE0, EXTI_MODE_IT, DISABLE );\r
+ HAL_EXTI_D2_EventInputConfig( EXTI_LINE0, EXTI_MODE_IT, ENABLE );\r
+ HAL_EXTI_GenerateSWInterrupt( EXTI_LINE0 );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, uint32_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )\r
+{\r
+/* If the buffers to be provided to the Idle task are declared inside this\r
+function then they must be declared static - otherwise they will be allocated on\r
+the stack and so not exists after this function exits. */\r
+static StaticTask_t xIdleTaskTCB;\r
+static uint32_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];\r
+\r
+ /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide\r
+ an implementation of vApplicationGetIdleTaskMemory() to provide the memory\r
+ that is used by the Idle task.\r
+ https://www.freertos.org/a00110.html#configSUPPORT_STATIC_ALLOCATION */\r
+\r
+ /* Pass out a pointer to the StaticTask_t structure in which the Idle task's\r
+ state will be stored. */\r
+ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;\r
+\r
+ /* Pass out the array that will be used as the Idle task's stack. */\r
+ *ppxIdleTaskStackBuffer = uxIdleTaskStack;\r
+\r
+ /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.\r
+ Note that, as the array is necessarily of type StackType_t,\r
+ configMINIMAL_STACK_SIZE is specified in words, not bytes. */\r
+ *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvWaitForOtherCoreToStart( uint32_t ulIndexToTest, uint32_t ulIndexToIncrement )\r
+{\r
+volatile uint32_t ulInitialCount = ulStartSyncCounters[ ulIndexToTest ], x;\r
+const uint32_t ulCrudeLoopDelay = 0xfffffUL;\r
+\r
+ /* When the cores boot they very crudely wait for each other in a non chip\r
+ specific way by waiting for the other core to start incrementing a shared\r
+ variable within an array. mainINDEX_TO_TEST sets the index within the array\r
+ to the variable this core tests to see if it is incrementing, and\r
+ mainINDEX_TO_INCREMENT sets the index within the array to the variable this\r
+ core increments to indicate to the other core that it is at the sync point.\r
+ Note this is not a foolproof method and it is better to use a hardware\r
+ specific solution, such as having one core boot the other core when it was\r
+ ready, or using some kind of shared semaphore or interrupt. */\r
+\r
+ /* Wait for the other core to reach the synchronisation point. */\r
+ while( ulStartSyncCounters[ ulIndexToTest ] == ulInitialCount );\r
+ ulInitialCount = ulStartSyncCounters[ ulIndexToTest ];\r
+\r
+ for( ;; )\r
+ {\r
+ ulStartSyncCounters[ ulIndexToIncrement ]++;\r
+ if( ulStartSyncCounters[ ulIndexToTest ] != ulInitialCount )\r
+ {\r
+ ulStartSyncCounters[ ulIndexToIncrement ]++;\r
+ break;\r
+ }\r
+\r
+ /* Unlike the M4 core, this core does not have direct access to the UART,\r
+ so simply toggle an LED to show its status. */\r
+ for( x = 0; x < ulCrudeLoopDelay; x++ ) __asm volatile( "NOP" );\r
+ BSP_LED_Off( LED2 );\r
+ for( x = 0; x < ulCrudeLoopDelay; x++ ) __asm volatile( "NOP" );\r
+ BSP_LED_On( LED2 );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin )\r
+{\r
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+uint32_t x;\r
+\r
+ configASSERT( xM7AMPTask );\r
+\r
+ HAL_EXTI_D1_ClearFlag( EXTI_LINE1 );\r
+\r
+ /* Task can't be blocked on both so just send the notification to both. */\r
+ for( x = 0; x < mbaNUMBER_OF_CORE_2_TASKS; x++ )\r
+ {\r
+ xMessageBufferReceiveCompletedFromISR( xDataMessageBuffers[ x ], &xHigherPriorityTaskWoken );\r
+ }\r
+\r
+ /* Normal FreeRTOS "yield from interrupt" semantics, where\r
+ xHigherPriorityTaskWoken is initialzed to pdFALSE and will then get set to\r
+ pdTRUE if the interrupt unblocks a task that has a priority above that of\r
+ the currently executing task. */\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSetupHardware( void )\r
+{\r
+MPU_Region_InitTypeDef MPU_InitStruct;\r
+RCC_ClkInitTypeDef RCC_ClkInitStruct;\r
+RCC_OscInitTypeDef RCC_OscInitStruct;\r
+\r
+ /* Configure the MPU attributes as Not Cachable for Internal D3SRAM. The\r
+ Base Address is 0x38000000 (D3_SRAM_BASE), and the size is 64K. */\r
+ HAL_MPU_Disable();\r
+ MPU_InitStruct.Enable = MPU_REGION_ENABLE;\r
+ MPU_InitStruct.BaseAddress = D3_SRAM_BASE;\r
+ MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;\r
+ MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;\r
+ MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;\r
+ MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;\r
+ MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;\r
+ MPU_InitStruct.Number = MPU_REGION_NUMBER0;\r
+ MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;\r
+ MPU_InitStruct.SubRegionDisable = 0x00;\r
+ MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;\r
+ HAL_MPU_ConfigRegion(&MPU_InitStruct);\r
+ HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);\r
+\r
+ /* Enable I-Cache */\r
+ SCB_EnableICache();\r
+\r
+ /* Enable D-Cache */\r
+ SCB_EnableDCache();\r
+\r
+ HAL_Init();\r
+ BSP_LED_Init(LED1);\r
+\r
+\r
+ /*\r
+ System Clock Configuration:\r
+ System Clock source = PLL (HSE)\r
+ SYSCLK(Hz) = 400000000 (Cortex-M7 CPU Clock)\r
+ HCLK(Hz) = 200000000 (Cortex-M4 CPU, Bus matrix Clocks)\r
+ AHB Prescaler = 2\r
+ D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)\r
+ D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)\r
+ D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)\r
+ D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)\r
+ HSE Frequency(Hz) = 25000000\r
+ PLL_M = 5\r
+ PLL_N = 160\r
+ PLL_P = 2\r
+ PLL_Q = 4\r
+ PLL_R = 2\r
+ VDD(V) = 3.3\r
+ Flash Latency(WS) = 4\r
+ */\r
+\r
+ HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);\r
+\r
+ /* The voltage scaling allows optimizing the power consumption when the\r
+ device is clocked below the maximum system frequency, to update the voltage\r
+ scaling value regarding system frequency refer to product datasheet. */\r
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);\r
+\r
+ while( !__HAL_PWR_GET_FLAG( PWR_FLAG_VOSRDY ) )\r
+ {\r
+ __asm volatile ( "NOP" );\r
+ }\r
+\r
+ /* Enable HSE Oscillator and activate PLL with HSE as source */\r
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;\r
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;\r
+ RCC_OscInitStruct.HSIState = RCC_HSI_OFF;\r
+ RCC_OscInitStruct.CSIState = RCC_CSI_OFF;\r
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;\r
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;\r
+\r
+ RCC_OscInitStruct.PLL.PLLM = 5;\r
+ RCC_OscInitStruct.PLL.PLLN = 160;\r
+ RCC_OscInitStruct.PLL.PLLFRACN = 0;\r
+ RCC_OscInitStruct.PLL.PLLP = 2;\r
+ RCC_OscInitStruct.PLL.PLLR = 2;\r
+ RCC_OscInitStruct.PLL.PLLQ = 4;\r
+\r
+ RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;\r
+ RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;\r
+ configASSERT( HAL_RCC_OscConfig( &RCC_OscInitStruct ) == HAL_OK );\r
+\r
+ /* Select PLL as system clock source and configure bus clocks dividers */\r
+ RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \\r
+ RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1 );\r
+\r
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;\r
+ RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;\r
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;\r
+ RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;\r
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;\r
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;\r
+ RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;\r
+ configASSERT( HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_4 ) == HAL_OK );\r
+\r
+ /* AIEC Common configuration: make CPU1 and CPU2 SWI line0 sensitive to\r
+ rising edge. */\r
+ HAL_EXTI_EdgeConfig( EXTI_LINE0, EXTI_RISING_EDGE );\r
+\r
+ /* Interrupt used for M4 to M7 notifications. */\r
+ HAL_NVIC_SetPriority( EXTI1_IRQn, 0xFU, 0U );\r
+ HAL_NVIC_EnableIRQ( EXTI1_IRQn );\r
+}\r
+\r