// STDLIB includes #include #include #include // HAL includes #include #include #include #include // OS-related includes #include #include // our includes #include "cliutils/cli.h" #include "cmds.h" #include "flexptp/event.h" #include "flexptp/logging.h" #include "flexptp/profiles.h" #include "flexptp/ptp_profile_presets.h" #include "flexptp/settings_interface.h" #include "standard_output/serial_io.h" #include "standard_output/standard_output.h" #include "standard_output/term_colors.h" #ifdef ETH_ETHERLIB #include "ethernet/ethernet_etherlib.h" #elif defined(ETH_LWIP) #include "ethernet/ethernet_lwip.h" #endif #define FLEXPTP_INITIAL_PROFILE ("gPTP") // ------------------------ void Error_Handler(void); // ------------------------ #define TARGET_SYSCLK_MHZ (configCPU_CLOCK_HZ / 1000000) void init_osc_and_clk() { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; // TODO: turn HSE bypass OFF if using X3 instead of the board controller's clock output RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = HSE_VALUE / 2000000; RCC_OscInitStruct.PLL.PLLN = 2 * TARGET_SYSCLK_MHZ; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Activate the Over-Drive mode */ if (HAL_PWREx_EnableOverDrive() != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } // compute SYSCLK values (HSE_VALUE must be correct when invoking this) SystemCoreClockUpdate(); // set tick frequency HAL_SetTickFreq(HAL_TICK_FREQ_1KHZ); // configure internal voltage regulator __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); // configure GPIOs for high-speed operation __HAL_RCC_SYSCFG_CLK_ENABLE(); HAL_EnableCompensationCell(); // apply silicon bug workaround if (HAL_GetREVID() == 0x1001) { /* Enable the Flash prefetch */ __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); } } void print_welcome_message() { MSGraw("\033[2J\033[H"); MSG(ANSI_COLOR_BGREEN "Hi!" ANSI_COLOR_BYELLOW " This is a flexPTP demo for the STMicroelectronics NUCLEO-F746ZG (STM32F746) board.\n\n" "The application is built on FreeRTOS, flexPTP is currenty compiled against %s and uses the supplied example %s Network Stack Driver. " "In this demo, the underlying Ethernet stack can be either lwip or EtherLib, the 'ETH_STACK' CMake variable (in the main CMakeLists.txt file) determines which one will be used. " "The STM32F7xx PTP hardware module driver is also picked from the bundled ones. This flexPTP instance features a full CLI control interface, the help can be listed by typing '?' once the flexPTP has loaded. " "The initial PTP preset that loads upon flexPTP initialization is the 'gPTP' (802.1AS) profile. It's a nowadays common profile, but we encourage " "you to also try out the 'default' (plain IEEE 1588) profile and fiddle around with other options as well. The application will try to acquire an IP-address with DHCP. " "Once the IP-address is secured, you might start the flexPTP module by typing 'flexptp'. 'Have a great time! :)'\n\n" ANSI_COLOR_RESET, ETH_STACK, ETH_STACK); MSG(ANSI_COLOR_BRED "By default, the MCU clock is sourced by the onboard (STLink) board controller on this devboard. According to our observations, this clock signal is loaded " "with heavy noise rendering the clock synchronization unable to settle precisely. We highly recommend to solder a 8 MHz oscillator onto " "the designated X3 pads to achieve the best results!\n\n" ANSI_COLOR_RESET); // MSG("Freq: %u\n", SystemCoreClock); } void task_startup(void *arg) { // initialize serial IO serial_io_init(); // print welcome message print_welcome_message(); // initialize CLI cli_init(); // initialize CLI commands cmd_init(); // initialize Ethernet #ifdef ETH_ETHERLIB init_ethernet(); #elif defined(ETH_LWIP) init_ethernet(); #endif for (;;) { osDelay(1000); } } void flexptp_user_event_cb(PtpUserEventCode uev) { switch (uev) { case PTP_UEV_INIT_DONE: ptp_load_profile(ptp_profile_preset_get(FLEXPTP_INITIAL_PROFILE)); ptp_print_profile(); ptp_log_enable(PTP_LOG_DEF, true); ptp_log_enable(PTP_LOG_BMCA, true); break; default: break; } } void init_randomizer() { __HAL_RCC_RNG_CLK_ENABLE(); LL_RNG_Enable(RNG); while (!LL_RNG_IsActiveFlag_DRDY(RNG)) { } srand(LL_RNG_ReadRandData32(RNG)); } int main(void) { // initialize FPU and several system blocks SystemInit(); // initialize oscillator and clocking init_osc_and_clk(); // initialize rand() init_randomizer(); // initialize HAL HAL_Init(); // initialize the FreeRTOS kernel osKernelInitialize(); // create startup thread osThreadAttr_t attr; memset(&attr, 0, sizeof(attr)); attr.stack_size = 2048; attr.name = "init"; osThreadNew(task_startup, NULL, &attr); // start the FreeRTOS! osKernelStart(); /* Loop forever */ for (;;) ; } // ------------------------ uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__((section(".FreeRTOSHeapSection"))); // ------------------------ void vApplicationTickHook(void) { HAL_IncTick(); } void vApplicationIdleHook(void) { return; } void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } void NMI_Handler(void) { /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE END NonMaskableInt_IRQn 0 */ /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ while (1) { } /* USER CODE END NonMaskableInt_IRQn 1 */ } /** * @brief This function handles Hard fault interrupt. */ void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ } } /** * @brief This function handles Memory management fault. */ void MemManage_Handler(void) { /* USER CODE BEGIN MemoryManagement_IRQn 0 */ /* USER CODE END MemoryManagement_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ /* USER CODE END W1_MemoryManagement_IRQn 0 */ } } /** * @brief This function handles Pre-fetch fault, memory access fault. */ void BusFault_Handler(void) { /* USER CODE BEGIN BusFault_IRQn 0 */ /* USER CODE END BusFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_BusFault_IRQn 0 */ /* USER CODE END W1_BusFault_IRQn 0 */ } } /** * @brief This function handles Undefined instruction or illegal state. */ void UsageFault_Handler(void) { /* USER CODE BEGIN UsageFault_IRQn 0 */ /* USER CODE END UsageFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ /* USER CODE END W1_UsageFault_IRQn 0 */ } } /** * @brief This function handles Debug monitor. */ void DebugMon_Handler(void) { /* USER CODE BEGIN DebugMonitor_IRQn 0 */ /* USER CODE END DebugMonitor_IRQn 0 */ /* USER CODE BEGIN DebugMonitor_IRQn 1 */ /* USER CODE END DebugMonitor_IRQn 1 */ }