/** * Аппаратный порт STM32G474RB: векторы приложения, тактирование и GPIO. * Алгоритмы UMP/TMS/IGBT находятся в общем C-ядре templates; здесь только пины. */ #include "board.h" #include "board_config.h" #include "transport.h" #include "emulator.h" #include "igbt_emulator.h" #include "stm32g4xx_hal.h" volatile uint32_t clock_fault; uint32_t SystemCoreClock=16000000u; const uint8_t AHBPrescTable[16]={0,0,0,0,0,0,0,0,1,2,3,4,6,7,8,9}; const uint8_t APBPrescTable[8]={0,0,0,0,1,2,3,4}; static uint8_t usb_clock_ready; /* Восемь входов IGBT: PB0,PB1,PB2,PB10..PB14. PB3/SWO и PB8/PB9 CAN свободны. */ static const uint16_t input_pins[8]={GPIO_PIN_0,GPIO_PIN_1,GPIO_PIN_2, GPIO_PIN_10,GPIO_PIN_11,GPIO_PIN_12,GPIO_PIN_13,GPIO_PIN_14}; /* До C runtime разрешены только регистровые операции; глобальные данные ещё не готовы. */ void SystemInit(void) { SCB->CPACR|=0xFu<<20; SCB->VTOR=0x08010000u; } void SystemCoreClockUpdate(void) { RCC_ClkInitTypeDef config; uint32_t latency; HAL_RCC_GetClockConfig(&config,&latency); SystemCoreClock=HAL_RCC_GetSysClockFreq() >> AHBPrescTable[config.AHBCLKDivider >> RCC_CFGR_HPRE_Pos]; } /* ISR только считает миллисекунды: протоколы и модели обслуживаются главным циклом. */ void SysTick_Handler(void) { HAL_IncTick(); } void board_fatal(uint32_t code) { clock_fault=code; for (;;) {} } static void peripheral_clock(void) { RCC_OscInitTypeDef osc={0}; RCC_ClkInitTypeDef clk={0}; RCC_PeriphCLKInitTypeDef peripheral={0}; RCC_CRSInitTypeDef crs={0}; __HAL_RCC_PWR_CLK_ENABLE(); /* Для 160 МГц нужен Range1 Boost; Flash 4 wait states по таблице ST. */ if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST)!=HAL_OK) board_fatal(3); osc.OscillatorType=RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI48; osc.HSIState=RCC_HSI_ON; osc.HSICalibrationValue=RCC_HSICALIBRATION_DEFAULT; osc.HSI48State=RCC_HSI48_ON; osc.PLL.PLLState=RCC_PLL_ON; osc.PLL.PLLSource=RCC_PLLSOURCE_HSI; /* HSI16 / 4 * 80 / 2 = 160 МГц; PLLQ также 160 МГц, FDCAN берёт PCLK1. */ osc.PLL.PLLM=RCC_PLLM_DIV4; #if EMU_USE_HSE #if EMU_HSE_HZ != 24000000u #error This board profile supports 24 MHz HSE or internal HSI16 #endif osc.OscillatorType|=RCC_OSCILLATORTYPE_HSE; osc.HSEState=EMU_HSE_BYPASS ? RCC_HSE_BYPASS : RCC_HSE_ON; osc.PLL.PLLSource=RCC_PLLSOURCE_HSE; osc.PLL.PLLM=RCC_PLLM_DIV6; #endif osc.PLL.PLLN=80; osc.PLL.PLLP=RCC_PLLP_DIV2; osc.PLL.PLLQ=RCC_PLLQ_DIV2; osc.PLL.PLLR=RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&osc)!=HAL_OK) board_fatal(3); clk.ClockType=RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; clk.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; clk.AHBCLKDivider=RCC_SYSCLK_DIV1; clk.APB1CLKDivider=RCC_HCLK_DIV2; clk.APB2CLKDivider=RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&clk,FLASH_LATENCY_4)!=HAL_OK) board_fatal(3); /* USB не зависит от PLL/HSE. USART2 и FDCAN получают 80 МГц PCLK1. */ peripheral.PeriphClockSelection=RCC_PERIPHCLK_USB|RCC_PERIPHCLK_FDCAN|RCC_PERIPHCLK_USART2; peripheral.UsbClockSelection=RCC_USBCLKSOURCE_HSI48; peripheral.FdcanClockSelection=RCC_FDCANCLKSOURCE_PCLK1; peripheral.Usart2ClockSelection=RCC_USART2CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&peripheral)!=HAL_OK) board_fatal(3); __HAL_RCC_CRS_CLK_ENABLE(); crs.Prescaler=RCC_CRS_SYNC_DIV1; crs.Source=RCC_CRS_SYNC_SOURCE_USB; crs.Polarity=RCC_CRS_SYNC_POLARITY_RISING; crs.ReloadValue=__HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000u,1000u); crs.ErrorLimitValue=RCC_CRS_ERRORLIMIT_DEFAULT; crs.HSI48CalibrationValue=RCC_CRS_HSI48CALIBRATION_DEFAULT; HAL_RCCEx_CRSConfig(&crs); usb_clock_ready=1; } void board_init(void) { GPIO_InitTypeDef gpio={0}; /* Этот образ связан с RB-загрузчиком: 128 КБ Flash, непрерывная карта DBANK=0. */ __HAL_RCC_SYSCFG_CLK_ENABLE(); if (*(const uint16_t *)FLASHSIZE_BASE!=128u || (FLASH->OPTR&(FLASH_OPTR_DBANK|FLASH_OPTR_BFB2)) || (SYSCFG->MEMRMP&SYSCFG_MEMRMP_FB_MODE)) board_fatal(5); peripheral_clock(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_FDCAN_CLK_ENABLE(); /* ST-LINK VCP физически подключён к PA2/PA3; выбираем USART2 AF7, формат 8N1. */ gpio.Pin=GPIO_PIN_2|GPIO_PIN_3; gpio.Mode=GPIO_MODE_AF_PP; gpio.Speed=GPIO_SPEED_FREQ_VERY_HIGH; gpio.Pull=GPIO_PULLUP; gpio.Alternate=GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA,&gpio); gpio.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14; gpio.Mode=GPIO_MODE_INPUT; gpio.Pull=GPIO_PULLDOWN; HAL_GPIO_Init(GPIOB,&gpio); /* PC0..PC7 — восемь ответов IGBT. Устанавливаем нули до включения выходов. */ gpio.Pin=0xff; gpio.Mode=GPIO_MODE_OUTPUT_PP; gpio.Pull=GPIO_NOPULL; HAL_GPIO_WritePin(GPIOC,0xff,GPIO_PIN_RESET); HAL_GPIO_Init(GPIOC,&gpio); #if EMU_RS485_DE gpio.Pin=GPIO_PIN_15; HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET); HAL_GPIO_Init(GPIOB,&gpio); #endif /* FDCAN1 Classic CAN: PB8 RX, PB9 TX. PA11/PA12 остаются для USB FS. */ gpio.Pin=GPIO_PIN_8|GPIO_PIN_9; gpio.Mode=GPIO_MODE_AF_PP; gpio.Pull=GPIO_PULLUP; gpio.Alternate=GPIO_AF9_FDCAN1; HAL_GPIO_Init(GPIOB,&gpio); transport_init(); } uint8_t board_usb_ready(void) { return usb_clock_ready; } /* Один шаг 1 мс. Бит n соответствует элементу input_pins[n], выход — PCn. */ void board_tick(void) { uint8_t inputs=0,outputs; unsigned i; for(i=0;i<8;++i) if(HAL_GPIO_ReadPin(GPIOB,input_pins[i])==GPIO_PIN_SET) inputs|=(uint8_t)(1u<