/** * bldc_hw.c — 外设初始化实现 * * 包含: 系统时钟、GPIO、TIM1 PWM、TIM2 捕获、ADC1、NVIC * 全部寄存器级操作, 无 HAL 依赖 */ #include "bldc_hw.h" /* ==================== 系统时钟配置 (72MHz HSE + PLL) ==================== */ /* * HSE = 8MHz (外部晶振) * PLL: 8MHz × 9 = 72MHz * SYSCLK = 72MHz * AHB = 72MHz (HPRE = /1) * APB1 = 36MHz (PPRE1 = /2) * APB2 = 72MHz (PPRE2 = /1) * ADC = 12MHz (ADCPRE = /6) */ void HW_SystemClock_Config(void) { /* 1. 使能 HSE */ RCC->CR |= RCC_CR_HSEON; while (!(RCC->CR & RCC_CR_HSERDY)); /* 2. 配置 Flash 等待周期 (72MHz: 2 wait states) */ FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2; /* 3. 配置 PLL: HSE × 9 = 72MHz */ RCC->CFGR &= ~RCC_CFGR_PLLSRC; RCC->CFGR |= RCC_CFGR_PLLSRC; /* PLL 源 = HSE */ RCC->CFGR &= ~RCC_CFGR_PLLMULL; RCC->CFGR |= RCC_CFGR_PLLMULL9; /* × 9 */ /* 4. 使能 PLL */ RCC->CR |= RCC_CR_PLLON; while (!(RCC->CR & RCC_CR_PLLRDY)); /* 5. 配置 AHB/APB 分频 */ RCC->CFGR &= ~RCC_CFGR_HPRE; /* AHB = /1 = 72MHz */ RCC->CFGR &= ~RCC_CFGR_PPRE1; RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; /* APB1 = /2 = 36MHz */ RCC->CFGR &= ~RCC_CFGR_PPRE2; /* APB2 = /1 = 72MHz */ /* 6. 切换系统时钟到 PLL */ RCC->CFGR &= ~RCC_CFGR_SW; RCC->CFGR |= RCC_CFGR_SW_PLL; while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); /* 7. ADC 预分频: PCLK2 / 6 = 12MHz */ RCC->CFGR &= ~RCC_CFGR_ADCPRE; RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; } /* ==================== GPIO 初始化 ==================== */ void HW_GPIO_Init(void) { /* 1. 使能 GPIO 时钟 */ RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN; /* 2. TIM1 CH1/CH2/CH3 (PA8/PA9/PA10) — 推挽复用输出, 50MHz */ GPIOA->CRH &= ~(0xF << 0); /* PA8: CNF=10(复用), MODE=11(50MHz) */ GPIOA->CRH |= (0xB << 0); GPIOA->CRH &= ~(0xF << 4); /* PA9 */ GPIOA->CRH |= (0xB << 4); GPIOA->CRH &= ~(0xF << 8); /* PA10 */ GPIOA->CRH |= (0xB << 8); /* 3. TIM1 CH1N/CH2N/CH3N (PB13/PB14/PB15) — 推挽复用输出, 50MHz */ GPIOB->CRH &= ~(0xF << 20); /* PB13 */ GPIOB->CRH |= (0xB << 20); GPIOB->CRH &= ~(0xF << 24); /* PB14 */ GPIOB->CRH |= (0xB << 24); GPIOB->CRH &= ~(0xF << 28); /* PB15 */ GPIOB->CRH |= (0xB << 28); /* 4. TIM1_BKIN (PB12) — 输入, 上拉 (BKIN 自动识别为刹车输入) */ GPIOB->CRH &= ~(0xF << 16); GPIOB->CRH |= (0x8 << 16); /* CNF=10(上拉/下拉输入), MODE=00(输入) */ GPIOB->ODR |= GPIO_ODR_ODR12; /* 上拉 */ /* 5. ADC 输入 (PA0/PA1/PA2/PA3) — 模拟输入 */ GPIOA->CRL &= ~(0xF << 0); /* PA0: CNF=00(模拟), MODE=00(输入) */ GPIOA->CRL &= ~(0xF << 4); /* PA1 */ GPIOA->CRL &= ~(0xF << 8); /* PA2 */ GPIOA->CRL &= ~(0xF << 12); /* PA3 */ /* 6. 故障指示灯 (PC13) — 推挽输出, 2MHz */ GPIOC->CRH &= ~(0xF << 20); GPIOC->CRH |= (0x2 << 20); /* CNF=00(推挽), MODE=10(2MHz) */ GPIOC->ODR |= GPIO_ODR_ODR13; /* 初始灭 */ } /* ==================== TIM1 初始化 (PWM 生成 + 互补输出 + 死区 + 刹车) ==================== */ /* * 中心对齐模式1, 20kHz * 死区: 1μs (72 个时钟周期) * BKIN: PB12 低电平有效, 自动刹车 */ void HW_TIM1_Init(void) { /* 1. 使能 TIM1 时钟 */ RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; /* 2. 基本定时配置 */ TIM1->PSC = 0; /* 预分频 = 0, CK_CNT = 72MHz */ TIM1->ARR = PWM_ARR_VALUE - 1; /* 自动重载 = 1799 */ TIM1->CR1 = TIM_CR1_CMS | TIM_CR1_ARPE; /* 中心对齐模式1, 自动重载预装载 */ /* 3. 捕获/比较模式 */ /* CH1: PWM模式1 (OC1M=110), 预装载使能 */ TIM1->CCMR1 &= ~(TIM_CCMR1_OC1M | TIM_CCMR1_CC1S); TIM1->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE; /* CH2: PWM模式1 */ TIM1->CCMR1 &= ~(TIM_CCMR1_OC2M | TIM_CCMR1_CC2S); TIM1->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE; /* CH3: PWM模式1 */ TIM1->CCMR2 &= ~(TIM_CCMR2_OC3M | TIM_CCMR2_CC3S); TIM1->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE; /* 4. CCER — 先全部关闭, 由换相表使能 */ TIM1->CCER = 0; /* 5. 死区配置 */ /* BDTR[7:0] = DTG[7:0], 72MHz 时钟, 1μs = 72 个时钟周期 */ TIM1->BDTR = (PWM_DEADTIME_CLK & 0xFF) | TIM_BDTR_OSSR /* 运行模式下空闲时输出 */ | TIM_BDTR_OSSI; /* 空闲模式下输出 */ /* 6. BKIN 配置: 低电平有效, 自动刹车, 滤波器 */ TIM1->BDTR |= TIM_BDTR_BKE /* 使能刹车 */ | TIM_BDTR_BKP /* BKIN 高电平有效 */ | TIM_BDTR_AOE; /* 刹车后自动使能 */ /* 7. 刹车后所有输出强制关闭 (MOE=0) */ /* 初始 MOE=0, 由状态机使能 */ /* 8. 输出使能 (MOE 暂不使能, 由状态机控制) */ /* 9. 更新事件触发 ADC (TRGO) */ TIM1->CR2 &= ~TIM_CR2_MMS; TIM1->CR2 |= (0x2 << 4); /* MMS=010: Update event as TRGO */ /* 10. DIER: 使能更新中断 */ TIM1->DIER = TIM_DIER_UIE; } /* ==================== TIM2 初始化 (输入捕获, 测量换相间隔) ==================== */ /* * CH1: PA0, 上升沿捕获, 72MHz 无预分频 */ void HW_TIM2_Init(void) { /* 1. 使能 TIM2 时钟 */ RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; /* 2. 配置 PA0 为 TIM2_CH1 输入 */ GPIOA->CRL &= ~(0xF << 0); /* PA0: CNF=01(浮空输入), MODE=00 */ GPIOA->CRL |= (0x4 << 0); /* 3. TIM2 基本配置 */ TIM2->PSC = 0; /* 72MHz 计数 */ TIM2->ARR = 0xFFFF; /* 16位自动重载 */ TIM2->CR1 = TIM_CR1_ARPE; /* 4. CH1 输入捕获: TI1FP1, 上升沿, 无预分频, 无滤波 */ TIM2->CCMR1 &= ~(TIM_CCMR1_CC1S | TIM_CCMR1_IC1PSC | TIM_CCMR1_IC1F); TIM2->CCMR1 |= TIM_CCMR1_CC1S_0; /* CC1S=01: TI1 */ TIM2->CCER &= ~TIM_CCER_CC1P; /* 上升沿捕获 */ TIM2->CCER |= TIM_CCER_CC1E; /* 使能捕获 */ TIM2->DIER |= TIM_DIER_CC1IE; /* 使能捕获中断 */ /* 5. 使能定时器 (状态机启动再使能) */ /* TIM2->CR1 |= TIM_CR1_CEN; — 由 FSM_Start 使能 */ } /* ==================== ADC1 初始化 (注入组, TIM1 TRGO 触发) ==================== */ /* * ADC1 注入组: 4 通道 (U相/V相/W相端电压 + 母线电流) * 触发源: TIM1 TRGO (更新事件) * ADC 时钟: 12MHz, 采样时间: 239.5 周期 */ void HW_ADC_Init(void) { /* 1. 使能 ADC1 时钟 */ RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* 2. ADC 基本配置 */ ADC1->CR2 = 0; /* 先复位配置 */ ADC1->CR2 = ADC_CR2_EXTSEL; /* 外部触发选择 (默认, 后续配置) */ ADC1->CR2 &= ~ADC_CR2_EXTSEL; ADC1->CR2 |= (0x6 << 17); /* EXTSEL=110: TIM1_TRGO */ ADC1->CR2 |= ADC_CR2_EXTTRIG; /* 外部触发使能 (注入组) */ ADC1->CR1 |= ADC_CR1_SCAN; /* 扫描模式 */ ADC1->CR1 &= ~ADC_CR1_DUALMOD; /* 独立模式 */ /* 3. 注入组: 4 通道顺序采样 */ ADC1->JSQR = 0; ADC1->JSQR |= (ADC_INJ_CH_COUNT - 1) << 20; /* JL[1:0] = 3 (4通道) */ /* 注入组通道序列 (JSQx 每个 5 位) */ /* JSQ1: 通道0 (U相) */ ADC1->JSQR |= (uint32_t)ADC_INJ_CH_U << 0; /* JSQ2: 通道1 (V相) */ ADC1->JSQR |= (uint32_t)ADC_INJ_CH_V << 5; /* JSQ3: 通道2 (W相) */ ADC1->JSQR |= (uint32_t)ADC_INJ_CH_W << 10; /* JSQ4: 通道3 (母线电流) */ ADC1->JSQR |= (uint32_t)ADC_INJ_CH_I << 15; /* 4. 采样时间: 所有通道 239.5 周期 */ ADC1->SMPR2 = 0x2A4A4A4A; /* SMP0~3 = 111(239.5周期) */ /* 5. ADC 时钟分频 (已在系统时钟中配置 ADCPRE = /6 → 12MHz) */ /* 6. 校准 */ ADC1->CR2 |= ADC_CR2_CAL; while (ADC1->CR2 & ADC_CR2_CAL); /* 7. 不使能连续转换 (由 TIM1 TRGO 触发) */ /* 8. 不用 DMA */ } /* ==================== NVIC 配置 ==================== */ void HW_NVIC_Init(void) { /* TIM1 更新中断: 最高优先级 (PWM 中断最关键) */ NVIC_SetPriority(TIM1_UP_IRQn, 0); NVIC_EnableIRQ(TIM1_UP_IRQn); /* TIM2 捕获中断: 次高优先级 */ NVIC_SetPriority(TIM2_IRQn, 1); NVIC_EnableIRQ(TIM2_IRQn); /* ADC 不使用中断 (轮询读取) */ } /* ==================== 全局初始化入口 ==================== */ void HW_Init(void) { HW_SystemClock_Config(); HW_GPIO_Init(); HW_ADC_Init(); HW_TIM1_Init(); HW_TIM2_Init(); HW_NVIC_Init(); }