下面详细说明程序的结构和功能的实现。
对于一个比较复杂的项目来说,程序框架的好坏决定了后续的可维护性,功能可扩展性。在这个项目中,笔者参考了MX的数字电源插件X-CUBE-DPower中的例程框架,将该框架移植到了本项目中。在本文的附件中,有st官方开发板B-G474-DPOW1的例子程序,本文中的代码大部分来自于这些例程。
在这个程序框架中,框架本质上是一个状态机,这个状态机做为main()函数中的主循环的主体,实现了电源工作状态的切换、LED状态的指示、告警、开机软启动和恒压恒流环路的计算等功能。
从上图可以看到状态机的一个工作流程,需要在本程序建立这个状态机框架。
因为从下面开始的大部分的代码编写都不在MX生成的代码中进行,为了以后不干扰用户自己编写的代码,需要在程序的工程目录中再创建一个新的目录,专门保存和管理用户自己编写的代码。
笔者创建了个“app”的目录,里面有四个文件,如下图:
LED.*为LED灯的相关代码,Status_Machine.*为状态机的相关代码。
在进行状态机框架建立之前,要先说一下LED灯的工作方式。
下图是三个LED输出引脚定义。
在本项目中,用到了三个LED灯,LED引脚分别是PB9——LED1、PE0——LED2、PE1——LED3。每个LED灯都有四种工作方式:1常亮、2常灭、3连续闪(闪动的时间可设置)、4连续闪n次间隔一段时间(m毫秒)后,再闪n次,其中闪动次数n,连续闪动间隔时间和下次闪动的间隔时间m都可以设定。
当定义好LED用到的数据类型后,将LED的功能函数移植过来,在stm32g4xx_it.c文件中的系统中断——tick定时器中断服务中将LED计数器递减。当需要设置LED工作状态机用下面函数:
LED_SetParams(&LED1_Status, LED_BLINK_N, LED_RUN_BLINK_NUM, LED_BLINK_PERIOD_MS, LED_BLINK_REPETITION_PERIOD_MS);
LED_SetParams(&LED2_Status, LED_BLINK_INF, 0, LED_BLINK_PERIOD_LONG_MS,0);
LED_SetParams(&LED3_Status, LED_BLINK_N, LED_STARTUP_BLINK_NUM, LED_BLINK_PERIOD_SHORT_MS, LED_BLINK_REPETITION_PERIOD_MS);
然后在main.c的主循环中运行
while (1)
{
LED_Task(&LED1_Status);
LED_Task(&LED2_Status);
LED_Task(&LED3_Status);
}
这样,每个LED有四个状态,通过三个LED灯不同状态的组合,就能指示多种芯片内部运行状态,在调试过程中非常有用。
在进入状态机循环之前,应该先将需要的外设使能。
/* Init 2p2z using the FMAC */
if (__3p3zInitFmacInt16( &USER_APPL_FMAC, &cntrlFmac,
A1, A2, 0.0,
B0, B1, B2, 0.0,
post_shift, DUTY_TICKS_MIN, DUTY_TICKS_MAX ) != HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
/* Init 2p2z using the CPU */
CNTRL_3p3zInit(&myDcdc.iLoop, iREF,
iA1, iA2, 0.0,
iB0, iB1, iB2, 0.0,
iK, (float_t)iDUTY_TICKS_MIN, (float_t)iDUTY_TICKS_MAX );
/* Start the FMAC and wait for DMA transfer */
if (__StartFmacInt16( &USER_APPL_FMAC, &cntrlFmac ) != HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
/* Initialise soft start ramp */
CNTRL_RampFloatConfig( &myDcdc.vRamp, 0, (VOUT_SET*VOUT_ADC_COFF), STARTUP_DCDC_RAMP_DURATION, 1000 );
/* Perform an ADCx automatic self-calibration and enable ADC */
if(HAL_ADCEx_Calibration_Start(&USER_APPL_ADC3, ADC_SINGLE_ENDED) != HAL_OK)
{
/* ADC initialization Error */
Init_Error_Handler();
}
/* Start ADCx with DMA request */
if(HAL_ADC_Start_DMA(&USER_APPL_ADC3, (uint32_t *) &USER_APPL_FMAC.Instance->WDATA, 1) != HAL_OK)
{
/* ADC initiliazation Error */
Init_Error_Handler();
}
if(HAL_ADCEx_Calibration_Start(&USER_APPL_ADC1, ADC_SINGLE_ENDED) != HAL_OK)
{
/* ADC initialization Error */
Init_Error_Handler();
}
/* Start ADCx with DMA request */
if(HAL_ADC_Start_IT(&USER_APPL_ADC1) != HAL_OK)
{
/* ADC initiliazation Error */
Init_Error_Handler();
}
/* Disable the DMA interrupts */
__HAL_DMA_DISABLE_IT(&USER_APPL_DMA3, DMA_IT_HT | DMA_IT_TC );
/* Enables DAC1 and starts conversion of the channel 1 */
if (HAL_DAC_Start(&USER_APPL_DAC1, DAC_CHANNEL_1) != HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
/* Enables DAC3 and starts conversion of the channel 1 */
if (HAL_DAC_Start(&USER_APPL_DAC3, DAC_CHANNEL_1) != HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
/* Start the comparator1 to detect the peak current trip threshold */
if (HAL_COMP_Start(&USER_APPL_CURRENT_SENSE1) != HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
/* Start the comparator3 to detect the peak current trip threshold */
if (HAL_COMP_Start(&USER_APPL_CURRENT_SENSE2) != HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
/* Start the UART2 */
if (HAL_UART_Receive_IT(&huart2, (uint8_t *)&RX2_buff, 8)!= HAL_OK)
{
/* Configuration Error */
Init_Error_Handler();
}
将上述外设使能后,还要先将串口调试成功,在程序的调试过程中,通过串口可以将程序运行时的变量传递出来。
本例中,是通过串口中断回调函数来完成的。
因为在前面已经通过函数
HAL_UART_Receive_IT(&huart2, (uint8_t *)&RX2_buff, 8)
打开了串口的接收端口,所以只要串口收到数据,就会进入上面的回调函数,进行数据的处理。如果向外界发送数据,用函数
HAL_UART_Transmit_IT(&huart2, (uint8_t *)&TX2_buff, 5)
至于接收和发送的内容,可以自己填写。
然后将status_machine.c中的StM_Process()状态机的本体移植进主循环中。至于状态机如何运行的,可以详细阅读附件中的例程,这里就不再详述。
下面着重介绍一下斜率补偿是如何实现的。
因为峰值电流型控制,需要有斜率补偿。在STM32G474VE这颗芯片中,是通过HRTIM和DAC相互配合来实现的,下图为斜率补偿的产生机制。
其中STRSTDATA[11:0]是由FMAC完成的环路补偿计算的结果,用来更新DAC负向输入端的参考值。STRSTTRIG是复位信号,表示DAC从何时开始产生斜率。STINCTRIG是步长时间间隔信号,表示每隔多长时间就将STRSTDATA[11:0]的值减去一个定值。STRSTTRIG与STINCTRIG是HRTIM的关联信号。
DAC斜率补偿的步长时间,只能通过TA(或TB...TF)的compare2来设定,下图能清楚的说明DAC的斜率补偿的工作原理。
然后在DAC1中进行设置。
因为ResetData和StepData这两个寄存器的值要随时根据环路计算值的变化而变化,这里可以先设为零,在程序中动态修改。
因为DAC1是控制TA1和TA2的占空比的,要与TA的时基同步,所以Trigger和Trigger2要选择RST Out1 event和STEP Out1 event。
同理,设置TB和DAC3
斜率补偿设置完成了。因为MOS管导通时会对电流互感器的采样电流产生干扰,进而对comp比较器的输出产生影响,使环路出现不稳定的状态,所以有必要进行前沿消隐。
对于TA和TB的前沿消隐,分别用TA-compare3和TB-compare3做为消隐时间计数器。
TB的消隐也是如此设置。
从上面可以看到TA和TB的前沿消隐配置完成了。