Digital Power com STM32F334 – Firmware do Conversor Boost Síncrono ‘Open Loop’ – Parte IV

Conversor Boost Síncrono
Este post faz parte da série Digital Power com STM32F334

Olá caro leitor, voltemos a explorar alguns conceitos de digital power utilizando a placa de avaliação fornecida pela STMicroelectronics voltada para conversão de energia utilizando um controlador digital de sinais. No artigo anterior explicamos a teoria envolvida e como a placa discovery poderia nos fornecer recursos para implementar um conversor boost síncrono.

Apenas para relembrarmos, consideremos a figura 1 novamente, onde temos um completo sistema do tipo buck-boost síncrono na placa de avaliação.

Conversor Boost Síncrono
Figura 1: Buck-Boost síncrono

Como explicamos no artigo anterior, do sistema inteiro, utilizaremos apenas os transistores do lado direito do esquema elétrico, ou seja, T5 e T12, enquanto que T4 e T11 servirão apenas com o propósito de desligar a alimentação do circuito quando uma função contida no firmware de halt for chamada. Sabemos ainda que o nosso conversor boost síncrono, em modo contínuo de  operação e em estado de equilíbrio, obedece a seguinte equação.

Equação 1
Equação 1

Sabemos que o modo de operação de um conversor DC-DC pode ser determinado escolhendo a frequência de chaveamento, tal que em 1 ciclo dessa o indutor L3 termine com alguma (contínuo) ou nenhma (descontínuo) energia armazenada. Se escolhemos essa frequência para o modo contínuo de operação o firmware pode se encarregar de calcular o ciclo ativo do gerador de PWM de modo a produzir a tensão de saída desejada. Em nosso sistema trabalharemos com uma tensão de entrada de 5,0 V e o conversor poderá elevar esse valor até o máximo de 15,0 V, limitado internamente por firmware.

O Firmware do Conversor Boost Síncrono

O firmware do sistema em sí é bem simples pois não opera em malha fechada, não requerendo qualquer leitura da tensão de saída para efetuar algum tipo de compensação. O firmware ainda foi desenvolvido de modo a separar completamente o sistema conversor boost síncrono do restante da aplicação, ou seja, todos os tratamentos de hardware e vetores de interrupção ficam internos, sem acesso direto do usuário, o qual poderá comandar o conversor através das funções abaixo:

//
// 			SERIE DIGITAL POWER COM A DISCOVERY EMBARCADOS
//
//	@file boost.h
//  @brief Arquivo contendo modulo de operacao de boost converter, pode rodar em
//         modo openloop ou closed loop usando a estrategia voltage mode controller
//
//
#ifndef __BOOST_H
#define __BOOST_H

#include "stdint.h"

//
// Configuracao do conversor:
//
#define BOOST_SW_FREQ     			250000 	//Frequencia do PWM em HZ
#define BOOST_MAX_VOLTAGE	   		15.0f 	//Maxima tensao do boost em [V]
#define BOOST_VFB_MAX_VOLTAGE       2.98f    //Maxima tensao que pode ser lida pelo feed
#define BOOST_CTL_TYPE              0      // 0 - openLoop
											// 1 - VMC closed loop

//
// API para inicializacao e start do conversor:
//

//
// @fn BoostInit()
// @brief Inicializa o conversor boost sincrono da discovery
//
void BoostInit(float inputVoltage, float outputVoltage);

//
// @fn BoostStart()
// @brief depois de configurado o usuario pode chamar essa funcao
//        pra disparar a operacao do boost
void BoostStart(void);

//
// @fn BoostVoltageChange()
// @brief Modifica a tensao de saida do boost converter:
//
void BoostVoltageChange(float newVoltage);

//
// @fn BoostHalt()
// @brief como o boost usado eh sincrono o user pode chamar essa funcao
//        para derrubar a operacao do boost e impor 0.0v na saida independente
//        da entrada.
void BoostHalt(void);


#endif

A função BoostInit coloca o conversor boost síncrono digital em um estado inicial conhecido e configura todo seu hardware. Além disso o conversor permanece em estado de pausa (halt) até que o usuário chame a função BoostStart, que efetivamente dispara os PWMs e faz o firmware buscar para primeira tensão de saída desejada (é importante que a tensão de entrada passada para a função Init corresponda ao valor real da tensão de entrada no sistema boost). A tensão de saída pode ser modificada a qualquer momento pelo uso da função BoostVoltageChange e por fim o usuário pode desativar o sistema através de BoostHalt e retomar o funcionamento chamando novamente a função Start.

Além das funções algumas constantes no arquivo .h podem ser alteradas, de acordo com sistemas personalizados. A primeira delas é a frequência de chaveamento do PWM, e peço ao leitor que notem o valor elevado de 250 KHz. Se relembrarmos a série de digital power com o Arduino vamos notar que a frequência de chaveamento escolhida era muito menor e com resolução limitada em 6 bits. Pois bem, é nesse ponto em que os processadores STM32F334 se sobressaem para aplicações que envolvam digital power. Graças ao módulo HRTIM podemos gerar sinais de PWM de altíssima resolução, e com isso atingindo frequências elevadas de chaveamento. Para fins de comparação os 250 KHz gerados nessa aplicação nos fornecem mais de 14 bits de resolução (sim, sendo possível atingir frequências ainda mais elevadas da ordem de MHz sem prejudicar a granularidade do sistema). As outras constantes de configurações se referem aos limites máximos de tensão de saída e também cálculo de escala do conversor A/D para o sinal de feedback que não será usado no momento. E a constante BOOST_CTL_TYPE determina se vamos operar em malha aberta ou fechada, e como já citado, ela sera colocada em 0 pois ainda não fecharemos a malha de controle.

O modulo Boost.c também é simples e encapsula todas as funções dependentes do hardware, vamos dar uma olhada no que temos aqui:

//
// 			SERIE DIGITAL POWER COM A DISCOVERY EMBARCADOS
//
//	@file boost.c
//  @brief Arquivo contendo modulo de operacao de boost converter, pode rodar em
//         modo openloop ou closed loop usando a estrategia voltage mode controller
//
//
#include "stm32f30x.h"
#include "stm32f30x_rcc.h"
#include "stm32f30x_comp.h"
#include "stm32f30x_hrtim.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_dac.h"
#include "stm32f30x_adc.h"
#include "boost.h"
//
// Constantes de configuracao, internas e hardware:
//

//
// Sobre o HRTIM:
//
#define BOOST_PWM_L_PIN      GPIO_Pin_10 //diodo sincrono
#define BOOST_PWM_H_PIN      GPIO_Pin_11 //low side
#define BOOST_IN_PIN         GPIO_Pin_8 //low side


#define BOOST_PWM_PORT       GPIOA      //
#define BOOST_HRTIM_LOAD_VAL(x) 	(x == 0?0:((SystemCoreClock/x) * 64)) //VAlor de recarga do HRTIM

//
// sobre o VFB apenas em modo closed loop:
//
#define BOOST_VFB_PIN       GPIO_Pin_3
#define BOOST_VIN_PIN       GPIO_Pin_1
#define BOOST_VFB_PORT      GPIOA

//
// estados de operacao do conversor boost:
//
#define BOOST_RUN  0x00000001
#define BOOST_HALT 0x00000002
#define BOOST_OFF  0x00000008

//
// Variaveis estaticas:
//
static float transferRatio = 0.0f;
static float vfbScale      = 1.0f;
static float inVoltage  = 0.0f;
static float outVoltage  = 0.0f;
static float vfbVal      = 0.0f;


static uint16_t dutyCicle  = 0;
static uint32_t boostFlags = BOOST_OFF;
static uint32_t adcStep = 0;

struct loopcontrolwork
{
	float *pfeed;
	float *perr;
	float *pAcoeff;
	float *pBCoeff;
	float *pxn;
	float *pyn;
	int16_t *pOut;
};



//variaveis da malha de controle:
struct loopcontrolwork loopwork;

float a_n[3] = {0.0f,0.0f,0.0f};
float b_n[3] = {0.0f,0.0f,0.0f};
float x_n[4] = {0.0f,0.0f,0.0f, 0.0f};
float y_n[4] = {0.0f,0.0f,0.0f, 0.0f};
int16_t output = 0;


//
// forward references as funcoes usadas internamente:
//

#if BOOST_CTL_TYPE == 1
extern void DigitalPowerLoopFunc(void);
void DigitalPowerLoopSetCoef(float kp, float ki, float kd);
#endif

void Boost_HW_SetAnalog(void);
void Boost_HW_SetPwm(void);
void Boost_HW_SetInterrupts(void);
void Boost_HW_SetDutyCicle(uint16_t dc);
void HRTIM1_TIMB_IRQHandler(void);
void ADC1_2_IRQHandler(void);

//
// codigos de erro do buck converter:
//
typedef enum
{
	knoError = 0,
	koutVoltageTooLow = -1,
	koutVoltageTooHigh,
	kboostIsDiscontinuous,

}errorcode;



//
// Funcoes internas:
//

//
// Boost_HW_SetAnalog
//
void Boost_HW_SetAnalog(void)
{
	GPIO_InitTypeDef analogIo, vin;
	analogIo.GPIO_Mode = GPIO_Mode_AN;
	analogIo.GPIO_Pin = BOOST_VFB_PIN;

	vin.GPIO_Mode = GPIO_Mode_AN;
	vin.GPIO_Pin = BOOST_VIN_PIN;


	//Aciona clock do port onde esta localizado o A/D
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

	//Inicializa o pino de IO desejado:
	GPIO_Init(BOOST_VFB_PORT, &analogIo);
	GPIO_Init(BOOST_VFB_PORT, &vin);

	//Inicializa clock do ADC:
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);

	// Configura o A/D:
	ADC_InitTypeDef adcInit;
	ADC_CommonInitTypeDef adcCommon;

	ADC_StructInit(&adcInit);
	ADC_CommonStructInit(&adcCommon);

	//
	// o adc vai rodar no modo mais simples, single conversion + 1 regular channel:
	//
	adcCommon.ADC_Clock = ADC_Clock_SynClkModeDiv1;
	adcCommon.ADC_Mode = ADC_Mode_Independent;

	adcInit.ADC_ExternalTrigEventEdge = ADC_ExternalTrigInjecEventEdge_None;
	adcInit.ADC_AutoInjMode = ADC_AutoInjec_Disable;
	adcInit.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable;
	adcInit.ADC_DataAlign = ADC_DataAlign_Left;
	adcInit.ADC_Resolution = ADC_Resolution_12b;
	adcInit.ADC_NbrOfRegChannel = 1;

	// Prepara o sequencer:
	ADC_CommonInit(ADC1, &adcCommon);
	ADC_Init(ADC1, &adcInit);
	ADC_RegularChannelSequencerLengthConfig(ADC1,1);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1,ADC_SampleTime_1Cycles5 );
/*
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2,ADC_SampleTime_1Cycles5 );
 */
	// ADC Pronto para rodar.
	ADC_VoltageRegulatorCmd(ADC1, ENABLE);
	ADC_Cmd(ADC1, ENABLE);
}

//
// Boost_HW_SetPwm()
//
void Boost_HW_SetPwm(void)
{
	GPIO_InitTypeDef gpioL, gpioH, gpioIn;
	gpioL.GPIO_Pin  = BOOST_PWM_L_PIN;
	gpioL.GPIO_Mode  = GPIO_Mode_AF;
	gpioL.GPIO_OType = GPIO_OType_PP;
	gpioL.GPIO_Speed = GPIO_Speed_Level_3;

	gpioH.GPIO_Pin  = BOOST_PWM_H_PIN;
	gpioH.GPIO_Mode  = GPIO_Mode_AF;
	gpioH.GPIO_OType = GPIO_OType_PP;
	gpioH.GPIO_Speed = GPIO_Speed_Level_3;

	gpioIn.GPIO_Pin  = BOOST_IN_PIN;
	gpioIn.GPIO_Mode  = GPIO_Mode_OUT;
	gpioIn.GPIO_OType = GPIO_OType_PP;
	gpioIn.GPIO_Speed = GPIO_Speed_Level_3;


	//Aciona o clock do HRTIM:
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_HRTIM1, ENABLE);
	RCC_HRTIM1CLKConfig(RCC_HRTIM1CLK_PLLCLK);

	//Aciona o pino que queremos o HRTIM:
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
	GPIO_Init(BOOST_PWM_PORT, &gpioL);
	GPIO_PinAFConfig(BOOST_PWM_PORT, GPIO_PinSource10,GPIO_AF_13);
	GPIO_Init(BOOST_PWM_PORT, &gpioH);
	GPIO_PinAFConfig(BOOST_PWM_PORT, GPIO_PinSource11,GPIO_AF_13);

	GPIO_Init(BOOST_PWM_PORT, &gpioIn);
	GPIO_ResetBits(BOOST_PWM_PORT, BOOST_IN_PIN);

	//COnfigura o HRTIM para obter-se uma saida pushpull em pwmH e L:
	// OBS usamos o timer B
	HRTIM1->HRTIM_MASTER.MCR  = 0x00000000;
	HRTIM1->HRTIM_MASTER.MPER = BOOST_HRTIM_LOAD_VAL(BOOST_SW_FREQ);
	HRTIM1->HRTIM_TIMERx[1].TIMxCR = 0x00000000 | ( 1 << 3);
	HRTIM1->HRTIM_TIMERx[1].PERxR  = BOOST_HRTIM_LOAD_VAL(BOOST_SW_FREQ); //Acerta o periodo
	HRTIM1->HRTIM_TIMERx[1].CMP1xR = 0;
	HRTIM1->HRTIM_TIMERx[1].SETx1R = (1 << 2);
	HRTIM1->HRTIM_TIMERx[1].RSTx1R = (1 << 3);
	//HRTIM1->HRTIM_TIMERx[1].SETx2R = (1 << 2);
	//HRTIM1->HRTIM_TIMERx[1].RSTx2R = (1 << 3);
	HRTIM1->HRTIM_TIMERx[1].DTxR  =  (230 << 16) | (230 << 0);
	HRTIM1->HRTIM_TIMERx[1].OUTxR  = (1 << 8);
	HRTIM1->HRTIM_COMMON.OENR      = (1 << 2) | (1 << 3);//habilita as saidas PWM.

	HRTIM1->HRTIM_MASTER.MCR  = 0x003F0008; //Habilita o master timer
}

//
// Boost_HW_SetInterrupts()
//
void Boost_HW_SetInterrupts(void)
{
	//Desliga o HRTIM1 e ADC1 como fonte de interrupcao:
	NVIC_DisableIRQ(HRTIM1_TIMB_IRQn);
    NVIC_DisableIRQ(ADC1_2_IRQn);

	//Aciona interupcao por reset (ela que sera o trigger para disparar
	//a conversao A/D)
	HRTIM_ITConfig(HRTIM1, 0x01, HRTIM_TIM_IT_RST, ENABLE);

	//Aciona a interrupcao do ADC:
	ADC_ITConfig(ADC1, ADC_IT_EOC,ENABLE);


    NVIC_EnableIRQ(HRTIM1_TIMB_IRQn);
    NVIC_EnableIRQ(ADC1_2_IRQn);
}

//
// Boost_HW_SetDutyCicle()
//
void Boost_HW_SetDutyCicle(uint16_t dc)
{
	HRTIM1->HRTIM_TIMERx[1].CMP1xR = dc;
}

//
// BoostError()
//
void BoostError(errorcode err)
{
	//
	// Eh uma funcao interna mas util para debug
	// se cair aqui o programa pede um halt da fonte
	// e deixa o errorcode visivel para debug.
	if(err != knoError)
	{
		BoostHalt();
		while(err);
	}
}

//
// HTRIM ISR:
//
void HRTIM1_TIMB_IRQHandler(void)
{
	//Limpa o flag de interrupcao:
	HRTIM_ClearITPendingBit(HRTIM1, 0x01, HRTIM_TIM_IT_RST);

	//Dispara a leitura do conversor A/D:
	ADC_StartConversion(ADC1);

	//Atualiza novo DutyCicle calculado previamente:
	Boost_HW_SetDutyCicle(dutyCicle);
}


//
// ADC1 ISR:
//
void ADC1_2_IRQHandler(void)
{
	if(adcStep == 0)
	{
		//Limpa fonte de interupcao:
		ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);

		//Toma o resultado da conversao A/D
		vfbVal = vfbScale * (float)ADC_GetConversionValue(ADC1);
	}
/*
	else
	{
		ADC_ClearITPendingBit(ADC1, ADC_IT_EOC | ADC_IT_EOS);
		inVoltage = vfbScale * (float)ADC_GetConversionValue(ADC1);
		adcStep = 0;
	}
*/
#if BOOST_CTL_TYPE == 1

	if(adcStep == 0)
	{
		//Roda a malha de controle:
		DigitalPowerLoopFunc();

		//Prepara o dutycicle para correcao no proximo ciclo:
		dutyCicle += (uint16_t)( (int16_t)(0.5 * (float)BOOST_HRTIM_LOAD_VAL(BOOST_SW_FREQ)) +
								loopwork.pOut);
	}
#endif
}


//
// DigitalPowerLoopSetCoef()
//
#if BOOST_CTL_TYPE == 1
void DigitalPowerLoopSetCoef(float kp, float ki, float kd)
{
	//prepara o set de coeficienets ax:
	a_n[0] = -1.0f;
	a_n[1] =  0.0f;
	a_n[2] =  0.0f;

	//preparar o set de coeficientes bx:
	b_n[0] =  kp + ki + kd;
	b_n[1] = -ki + (2.0f * kd);
	b_n[2] =  kd;

	//liga a array de estados nos nodes da funcao de controle:
	loopwork.pAcoeff = &a_n[0];
	loopwork.pBCoeff = &b_n[0];
	loopwork.pOut    = &output;
	loopwork.perr    = &inVoltage;
	loopwork.pfeed   = &vfbVal;
	loopwork.pxn     = &x_n[0];
	loopwork.pyn     = &y_n[0];
}
#endif

//
// conversor boost, funcoes publicas:
//

//
// BoostInit()
//
void BoostInit(float inputVoltage, float outputVoltage)
{
	//
	// Checa se a relacao Vo/Vi eh valida:
	//
	if(inputVoltage > outputVoltage)
	{
		errorcode  err = koutVoltageTooLow;
		BoostError(err);
	}

	//
	// Checa se a tensao de saida desejada eh valida:
	//
	if(outputVoltage > BOOST_MAX_VOLTAGE)
	{
		errorcode err = koutVoltageTooHigh;
		BoostError(err);
	}



	//
	// Determina o duty cicle
	// nota, estamos trabalhando com um buck em mondo continuo
	// Vo/Vi = 1 / (1 - D)
	transferRatio = 1.0f - (inputVoltage / outputVoltage);
	dutyCicle = (uint16_t)(transferRatio * (float)BOOST_HRTIM_LOAD_VAL(BOOST_SW_FREQ));
	inVoltage = inputVoltage;
	outVoltage= outputVoltage;

	//calcula a escala de conversao:
	vfbScale = BOOST_MAX_VOLTAGE / 65536.0f;

	//
	// Inicializa o hw do boost converter mas sem operar:
	//
	Boost_HW_SetAnalog();
	Boost_HW_SetPwm();
	Boost_HW_SetInterrupts();

#if BOOST_CTL_TYPE == 1
	DigitalPowerLoopSetCoef(1.0, 0.0, 0.0);
#endif


	//
	// Sistema inicialmente em halt:
	//
	BoostHalt();
	boostFlags = BOOST_HALT;
}

//
// BoostStart()
//
void BoostStart(void)
{
	//
	// Com o dutycicle pre calculado da um trigger no pwm
	//

	HRTIM1->HRTIM_MASTER.MCR = 0x003F0008;
	Boost_HW_SetInterrupts();
	Boost_HW_SetDutyCicle(dutyCicle);

	//Libera VIN:
	GPIO_SetBits(BOOST_PWM_PORT, BOOST_IN_PIN);

	boostFlags = BOOST_RUN;
}

//
// BoostVoltageChange()
//
void BoostVoltageChange(float newVoltage)
{
	// Checa se a relacao Vo/Vi eh valida:
	//
	if(inVoltage > newVoltage)
	{
		errorcode  err = koutVoltageTooLow;
		BoostError(err);
	}

	//
	// Checa se a tensao de saida desejada eh valida:
	//
	if(newVoltage > BOOST_MAX_VOLTAGE)
	{
		errorcode err = koutVoltageTooHigh;
		BoostError(err);
	}

	//
	// Recalcula parametros do boost:
	//
	transferRatio = 1.0f - (inVoltage / newVoltage);
	dutyCicle = (uint16_t)(transferRatio * (float)BOOST_HRTIM_LOAD_VAL(BOOST_SW_FREQ));
	outVoltage = newVoltage;

	//
	// Modifica tensao de saida:
	//
	Boost_HW_SetDutyCicle(dutyCicle);

}

//
// BoostHalt()
//
void BoostHalt(void)
{
	if(boostFlags & BOOST_HALT)
	{
		//
		// Ja esta inoperante.
		//
		return;
	}

	//
	// derruba o master hrtim:
	//
	HRTIM1->HRTIM_MASTER.MCR = 0;

	//Derruba VIN
	GPIO_ResetBits(BOOST_PWM_PORT, BOOST_IN_PIN);

	//
	// derruba as interupcoes:
	//
	NVIC_DisableIRQ(HRTIM1_TIMB_IRQn);
	NVIC_DisableIRQ(ADC1_2_IRQn);

	boostFlags = BOOST_HALT;

}

Eis onde a “mágica ocorre”. Vejam que as funções internas nada mais são que escalas ou configurações específicas do processador STM32. O módulo HRTIM foi configurado sem utilizar a biblioteca de periféricos fornecida pela ST pois desejava um modo de operação mais específico. Explico, o conversor boost que vamos utilizar é o tipo síncrono certo? Logo um dos transistores (no caso T5) da placa discovery irá funcionar como o diodo de transferência de energia do indutor para a saída, logo o HRTIM precisa gerar dois sinais complementares. É aí onde temos mais um problema, vejam que a frequência de chaveamento é elevadíssima, de forma que deve ser considerado, no projeto de qualquer conversor síncrono, um “tempo morto” onde nenhuma das chaves é acionada de forma que uma só acione quando a outra trocar completamente de estado, evitando assim o famoso problema de cruzamento de MOSFET que poderia levar o sistema à destruição. Mais uma vez o HRTIM dá conta do recado oferecendo um preciso gerador de “tempo morto” configurável (8 bits). Experimentalmente, com ajuda do osciloscópio, o tempo de 200 ns se mostrou perfeitamente adequado.

As demais funções internas configuram os GPIOs, e conversor A/D em modo de conversão única, além disso sua interrupção será configurada e habilitada pois é dentro do seu vetor de interrupção onde será executada futuramente a malha de controle digital de tempo real. Além dessa, a interrupcão gerada pelo HRTIM é habilitada para auxiliar o disparo do A/D de forma a obtermos uma estratégia de controle futuro muito similar ao modo ciclo-a-ciclo, utilizado em demasia por circuitos integrados analógicos. Por último temos as funções de usuário que nada mais são a teoria boost do artigo anterior implementadas em software.

O arquivo principal da aplicação pode ser visto abaixo:

//
//		INTRODUCAO A DIGITAL POWER COM A STM32F334
//
//		@file  main.c
//      @brief implementa uma engine de controle de brilho de LED closed loop
//             sem usar a CPU.
//


#include "stm32f30x.h"
#include "stm32f3348_discovery.h"
#include "stm32f30x_rcc.h"
#include "boost.h"

//
// Macros e constantes uteis:
//

#define TICK_FREQ      1000   //frequencia de updade do tick.
#define SYSTICK_LOAD_VAL(x) (x == 0?0:(SystemCoreClock) /x)    //recarga do systick
#define BUTTON_SCAN_TIME 10   //periodo de scanning do botao em ms

#define DIMMING_MAX_VAL  15.0f
#define DIMMING_MIN_VAL  5.50f

//
// maquininha simples de estado do dimmer:
//
typedef enum
{
	kdimmingUp = 0,
	kdimmingDown,
}dim_state;

//
// Variaveis:
//
float bright = DIMMING_MIN_VAL;
uint32_t tickCounter = 0;
dim_state dimmingMchn = kdimmingUp;

//
// main()
// @brief funcao principal, captura o estado do botao e regula
//        o brilho do led.
//
int main(void)
{
	uint32_t scan = 0;

	//Inicializa boost converter:
	BoostInit(5.0f, 10.0f );


	//Configura o botao da discovery para ser usado como controle
	//de dimmer.
	//
	STM_EVAL_PBInit(BUTTON_USER,BUTTON_MODE_GPIO);

	//
	// Configura o systick counter para gerar uma
	// base tempo constante.
	//
	//
	SysTick->CTRL = 0x00;
	SysTick->LOAD = SYSTICK_LOAD_VAL(TICK_FREQ);
	SysTick->CTRL = 0x07;

	scan = tickCounter;


	//Aciona o boost controller :
	BoostStart();

	for(;;)
	{
		//Escaneia o botao da placa a cada 10ms
		if(tickCounter - scan >= BUTTON_SCAN_TIME)
		{
			//Checa se o botao foi pressionado:
			if(STM_EVAL_PBGetState(BUTTON_USER) != 0)
			{
				//Avalia a maquininha de estados:
				switch(dimmingMchn)
				{
					case kdimmingUp:

						bright += 0.5f;
						if(bright > DIMMING_MAX_VAL)
						{
							//Realiza wrap e troca de estado do dimmer
							dimmingMchn = kdimmingDown;
							bright = DIMMING_MAX_VAL;
						}
					break;


					case kdimmingDown:
						bright-= 0.5f;
						if(bright <= DIMMING_MIN_VAL)
						{
							//Realiza wrap e troca de estado do dimmer
							dimmingMchn = kdimmingUp;
							bright = DIMMING_MIN_VAL;
						}
					break;
				}

			//Atualiza valor de tensao no boost
			BoostVoltageChange(bright);

			}

		    scan = tickCounter;
		}
	}
}

//
// SysTick_Handler()
// @brief esta interrupcao atualiza o contador de
//        base de tempo.
void SysTick_Handler(void)
{
	tickCounter++;
}

E aqui temos a aplicação principal que, na verdade, foi baseada na mesma desenvolvida na segunda parte desta série. Logo utilizaremos o botão B1 localizado na placa, a constante BUTTON_SCAN_TIME determina de quantos em quantos milissegundos o botão será checado. Inicialmente o firmware irá configurar o Boost chamando as funcões especifícas contidas em Boost.h. Em seguida o contador Systick será configurado para gerar a base de tempo de escaneamento do botão B1. Após isso o conversor Boost síncrono é colocado em operação através da chamada da função de start e o programa entra no loop principal que é ao identificar o pressionamento do botão. Um incremento ou decremento de 0,5 V será feito na tensão de saída dependendo da direção desta, decodificado pelos estados kdimmingUp e kdimmingDown. Com isso, ao efetuar o pressionamento e segurar a tecla, poderemos ver a geração de uma onda triangular na saída do sistema entre 6,0 e 15 V teoricamente. Teoricamente? Sim veremos por quê.

Os resultados

E vamos à parte mais legal, os resultados, eis que vamos mostrar as formas de onda obtidas na saída do conversor. As primeiras são as geradas pelo HRTIM do processador:

Conversor Boost Síncrono: HRTIM waveform
Figura 2 : Formas de onda geradas pelo HRTIM

Vejam que as formas de onda do canal 1 são realmente complementares, observem a frequência de chaveamento medida pelo osciloscópio de 250 KHz. Além disso, se o leitor observar com mais atenção, na borda de cada um dos waveforms, verão o efeito do gerador de “tempo morto” em ação. Reparem que as formas de onda nunca se “cruzam”, uma só estará em nível alto quando a outra estiver em nível baixo completamente. Agora vejamos a tensão de saída e entrada comparadas. 

Conversor Boost Síncrono: input x output waveform
Figura 3: Tensão de saída x tensão de entrada

Caro leitor, aqui vem a foto que acho particularmente uma das mais legais, pegar uma fonte qualquer de 5,0 V e variar sua tensão para cima ou para baixo (usando um buck) e melhor ainda, de forma digital e super flexível. No canal 1 (em amarelo) temos o sinal de entrada derivada de uma das fontes da minha Analog Discovery. Em verde, no canal 2, temos a tensão de saída em CN7 na placa discovery. Veja que a partir de uma tensão mais baixa foi possível gerar a conhecida tensão de 13,8 V, perfeita para alimentar, por exemplo, um módulo de áudio pequeno. As medidas estão mostradas nos cantos inferiores da área do osciloscópio.

E como não poderia faltar, vamos ver um vídeo da aplicação rodando? Que tal? Então segue abaixo, vejam que interessante:

Conclusão

Chegamos aqui ao fim de mais um experimento, verificamos as formas de onda geradas pelo HRTIM, os recursos usados da placa e do processador alvo. Além disso vimos o sistema conversor boost síncrono operando como um todo e os resultados foram animadores, porém veja, caro leitor, que um problema pode ter passado batido na euforia de ver formas de onda. Por mais que o firmware eleve a tensão em 15,0 V máximos, esse valor no vídeo nunca foi atingido. Aliás, para quem pegar, compilar e gravar esse firmware na sua discovery vai perceber a mesma coisa, que o sistema em equilíbrio fica sempre com um valor de tensão diferente do desejado. É o fenômeno de erro de estado estacionário, além disso o que será que acontece com a tensão de saída se a de entrada elevar-se? Provavelmente o desvio será maior ainda. Isso acontece pois o processador consegue atuar sobre o sistema mas não consegue ver o que está ocorrendo na saída. No próximo artigo dessa série, vamos efetivamente fechar a malha de controle via firmware e verificar o que acontece com o desempenho do nosso conversor e realmente construir um completo sistema de digital power. Então é isso amigos, até a próxima.

Links úteis

Firmware conversor boost síncrono

Referências

Manual de hardware da placa discovery STM32F334

ERICKSON, W. Robert – Fundamentals of Power Electronics , 2001

Digital Power com STM32F334

Digital Power com STM32F334 – Conversor Boost Síncrono – Parte III Digital Power com STM32F334 – Firmware do Conversor Boost Síncrono Closed Loop – Parte final
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
1 Comentário
recentes
antigos mais votados
Inline Feedbacks
View all comments
Eder
Eder
04/12/2015 13:41

Show!

Home » Hardware » Microcontroladores » Digital Power com STM32F334 – Firmware do Conversor Boost Síncrono ‘Open Loop’ – Parte IV

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: