Digital Power Starter Kit 3 Firmware  DM330017-3, Rev.3.0
dsPIC33C Buck Converter Peak Current Mode Control Example
dev_buck_substates.c
1 /*
2  * File: dev_buck_substates.c
3  * Author: M91406
4  * Comments: Buck converter operation sub-states header file
5  * Revision history:
6  * 10/28/20 1.0 initial version
7  */
8 
9 #include <xc.h> // include processor files - each processor file is guarded.
10 #include <stdint.h> // include standard integer data types
11 #include <stdbool.h> // include standard boolean data types
12 
13 #include "dev_buck_pconfig.h" // include buck converter
14 #include "dev_buck_typedef.h" // include buck converter data object declarations
15 
16 // Private function prototypes of sub-state functions
17 volatile uint16_t __attribute__((always_inline)) SubState_PowerOnDelay(volatile struct BUCK_CONVERTER_s *buckInstance);
18 volatile uint16_t __attribute__((always_inline)) SubState_PrepareVRampUp(volatile struct BUCK_CONVERTER_s *buckInstance);
19 volatile uint16_t __attribute__((always_inline)) SubState_VRampUp(volatile struct BUCK_CONVERTER_s *buckInstance);
20 volatile uint16_t __attribute__((always_inline)) SubState_IRampUp(volatile struct BUCK_CONVERTER_s *buckInstance);
21 volatile uint16_t __attribute__((always_inline)) SubState_PowerGoodDelay(volatile struct BUCK_CONVERTER_s *buckInstance);
22 
23 
24 // Declaration of function pointer array listing sub-state functions in order of execution
25 volatile uint16_t (*BuckConverterRampUpSubStateMachine[])(volatile struct BUCK_CONVERTER_s *buckInstance) =
26 {
32 };
33 
34 // Declaration variable capturing the size of the sub-state function pointer array
36 
37 
50 volatile uint16_t SubState_PowerOnDelay(volatile struct BUCK_CONVERTER_s *buckInstance)
51 {
52  volatile uint16_t retval=0;
53 
54  // Set BUSY bit until process is complete
55  buckInstance->status.bits.busy = true;
56 
57  // delay startup until POWER ON DELAY has expired
58  if(buckInstance->startup.power_on_delay.counter++ > buckInstance->startup.power_on_delay.period)
59  {
60  // Clamp POD counter to EXPIRED
61  buckInstance->startup.power_on_delay.counter =
62  (buckInstance->startup.power_on_delay.period + 1); // Saturate power on counter
63 
64  retval = BUCK_OPSRET_COMPLETE;
65  }
66  else
67  // When the period has not expired yet, return to this function
68  {
69  retval = BUCK_OPSRET_REPEAT;
70  }
71 
72  return(retval);
73 }
74 
75 
95 volatile uint16_t SubState_PrepareVRampUp(volatile struct BUCK_CONVERTER_s *buckInstance)
96 {
97  volatile uint16_t _i=0;
98  volatile uint32_t _vout=0;
99  volatile uint32_t _vin=0;
100  volatile uint32_t _start_dc=0;
101 
102  // Set BUSY bit until process is complete
103  buckInstance->status.bits.busy = true;
104 
105  // Copy user setting of voltage reference into loop reference
106  buckInstance->v_loop.reference = buckInstance->set_values.v_ref;
107 
108  // Hijack voltage loop controller reference
109  buckInstance->startup.v_ramp.reference = 0; // Reset Soft-Start Voltage Reference
110  buckInstance->startup.i_ramp.reference = 0; // Reset Soft-Start Current Reference
111  buckInstance->v_loop.controller->Ports.ptrControlReference =
112  &buckInstance->startup.v_ramp.reference; // Voltage loop is pointing to Soft-Start Reference
113 
114  // Pre-charge reference
115  // Never start above the pre-biased output voltage.
116  // Always start at or slightly below the pre-biased output voltage
117  buckInstance->startup.v_ramp.reference = buckInstance->data.v_out;
118 
119  // In peak current mode, set duty cycle to max to allow the comparator take control
120  if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_PCMC)
121  {
122  // If pointer to duty cycle register is invalid, return error
123  if (buckInstance->sw_node[_i].slope_compensation.ptr_duty_cycle == NULL)
124  { return(BUCK_OPSRET_ERROR); }
125 
126  // Set duty cycle limit to allow comparator control
127  for (_i=0; _i<buckInstance->set_values.no_of_phases; _i++) {
128  *buckInstance->sw_node[_i].slope_compensation.ptr_duty_cycle =
129  buckInstance->sw_node[_i].slope_compensation.duty_cycle_limit;
130  }
131  }
132  // In average current mode, set current reference limit to max startup current level
133  else if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_ACMC)
134  { // Disable all current control loops and reset control loop histories
135  buckInstance->v_loop.maximum = buckInstance->set_values.i_ref;
136  buckInstance->v_loop.controller->Limits.MaxOutput = buckInstance->v_loop.maximum;
137  }
138 
139  // Pre-charge PWM and control loop history
140  if(((buckInstance->data.v_in - buckInstance->feedback.ad_vin.scaling.offset) > 0) &&
141  ((buckInstance->data.v_out - buckInstance->feedback.ad_vout.scaling.offset) > 0) )
142  {
143  _vout = __builtin_muluu(
144  (buckInstance->data.v_out - buckInstance->feedback.ad_vout.scaling.offset),
145  buckInstance->feedback.ad_vout.scaling.factor);
146  _vout >>= (16 - buckInstance->feedback.ad_vout.scaling.scaler);
147 
148  _vin = __builtin_muluu(
149  (buckInstance->data.v_in - buckInstance->feedback.ad_vin.scaling.offset),
150  buckInstance->feedback.ad_vin.scaling.factor);
151  _vin >>= (16 - buckInstance->feedback.ad_vin.scaling.scaler);
152 
153  // Protect against negative duty cycle results
154  if (_vout > _vin) _vout = _vin;
155 
156  // CALCULATE BUCK CONVERTER STARTUP DUTY RATIO
157  // DC = VOUT / VIN, where DC = D * PERIOD
158 
159  if(_vin > 0)
160  {
161  _start_dc = __builtin_muluu((_vout), buckInstance->sw_node[0].period);
162  _start_dc = __builtin_divud(_start_dc, (uint16_t)_vin);
163  }
164  else
165  { _start_dc = (uint16_t)buckInstance->sw_node[_i].duty_ratio_min; }
166  }
167  else
168  // If there is no input voltage or no output voltage, start with minimum duty ratio
169  {
170  for (_i=0; _i<buckInstance->set_values.no_of_phases; _i++) {
171  _start_dc = (uint16_t)buckInstance->sw_node[_i].duty_ratio_min;
172  }
173  }
174 
175  // Program PWM module and pre-charge control loop
176  if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_VMC)
177  {
178  if(_start_dc < buckInstance->v_loop.minimum)
179  { _start_dc = buckInstance->v_loop.minimum; }
180  else if(_start_dc > buckInstance->v_loop.maximum)
181  { _start_dc = buckInstance->v_loop.maximum; }
182  else { /* continue */ }
183 
184  buckInstance->v_loop.ctrl_Precharge(buckInstance->v_loop.controller, 0, _start_dc);
185  *buckInstance->v_loop.controller->Ports.Target.ptrAddress = _start_dc; // set initial PWM duty ratio
186  if(buckInstance->v_loop.controller->Ports.AltTarget.ptrAddress != NULL)
187  *buckInstance->v_loop.controller->Ports.AltTarget.ptrAddress = _start_dc; // set initial PWM duty ratio
188  else { /* continue */ }
189 
190  }
191  else if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_ACMC)
192  {
193  // Limit startup duty cycle to largest minimum/smallest maximum
194  for (_i=0; _i<buckInstance->set_values.no_of_phases; _i++) {
195 
196  if(_start_dc < buckInstance->i_loop[_i].minimum)
197  { _start_dc = buckInstance->i_loop[_i].minimum; }
198  else if(_start_dc > buckInstance->i_loop[_i].maximum)
199  { _start_dc = buckInstance->i_loop[_i].maximum; }
200  else { /* continue */ }
201  }
202 
203  // Set initial duty cycle
204  for (_i=0; _i<buckInstance->set_values.no_of_phases; _i++)
205  {
206  // pre-charge current loop control histories with ideal duty cycle
207  buckInstance->i_loop[_i].ctrl_Precharge(
208  buckInstance->i_loop[_i].controller, 0, _start_dc
209  );
210 
211  // pre-charge PWM outputs with ideal duty cycle
212  *buckInstance->i_loop[_i].controller->Ports.Target.ptrAddress = _start_dc; // set initial PWM duty ratio
213  if(buckInstance->i_loop[_i].controller->Ports.AltTarget.ptrAddress != NULL)
214  *buckInstance->i_loop[_i].controller->Ports.AltTarget.ptrAddress = _start_dc; // set initial PWM duty ratio
215  else { /* continue */ }
216  }
217  }
218  else if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_PCMC)
219  {
220  /* do nothing */
221  Nop();
222  }
223  else
224  {
225  return(BUCK_OPSRET_ERROR);
226  }
227 
228  return(BUCK_OPSRET_COMPLETE);
229 
230 }
231 
232 
248 volatile uint16_t SubState_VRampUp(volatile struct BUCK_CONVERTER_s *buckInstance)
249 {
250  volatile uint16_t retval=1;
251  volatile uint16_t _i=0;
252 
253  // Set BUSY bit until process is complete
254  buckInstance->status.bits.busy = true;
255 
256  // ensure control loop is enabled
257  if(!buckInstance->v_loop.controller->status.bits.enabled) {
258 
259  // Enable all PWM channels
260  retval &= buckPWM_Resume(buckInstance); // Enable PWM outputs
261 
262  // In voltage mode control...
263  if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_VMC)
264  { // only enable voltage loop
265  buckInstance->v_loop.controller->status.bits.enabled = true; // enable voltage loop controller
266  }
267  // In average current mode control...
268  else if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_ACMC)
269  {
270  // enable voltage loop controller
271  buckInstance->v_loop.controller->status.bits.enabled = true;
272 
273  // enable all phase current loop controllers
274  for (_i=0; _i<buckInstance->set_values.no_of_phases; _i++) {
275  buckInstance->i_loop[_i].controller->status.bits.enabled = true;
276  }
277  }
278  // In peak current mode control...
279  else if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_PCMC)
280  {
281  // enable voltage loop controller
282  buckInstance->v_loop.controller->status.bits.enabled = true;
283  }
284  // IF control mode is set to unsupported control mode, return error
285  else
286  {
287  return(BUCK_OPSRET_ERROR);
288  }
289 
290  }
291 
292  // increment reference
293  buckInstance->startup.v_ramp.reference += buckInstance->startup.v_ramp.ref_inc_step;
294 
295  // check if ramp is complete
296  if (buckInstance->startup.v_ramp.reference > buckInstance->v_loop.reference)
297  {
298  // Set reference to the desired level
299  buckInstance->startup.v_ramp.reference = buckInstance->v_loop.reference;
300 
301  // Reconnect API reference to controller
302  buckInstance->v_loop.controller->Ports.ptrControlReference = &buckInstance->v_loop.reference;
303 
304  retval = BUCK_OPSRET_COMPLETE;
305 
306  }
307  else
308  // remain in this state until ramp is complete
309  {
310  retval = BUCK_OPSRET_REPEAT;
311  }
312 
313 
314  return(retval);
315 
316 }
317 
318 
337 volatile uint16_t SubState_IRampUp(volatile struct BUCK_CONVERTER_s *buckInstance)
338 {
339  volatile uint16_t retval=0;
340 
341  // Set BUSY bit until process is complete
342  buckInstance->status.bits.busy = true;
343 
344  // in average current mode if voltage limit is hit, increment
345  // voltage loop limit to ramp up current loop
346  if (buckInstance->set_values.control_mode == BUCK_CONTROL_MODE_ACMC)
347  {
348  // Increment maximum current limit
349  buckInstance->v_loop.controller->Limits.MaxOutput += buckInstance->startup.i_ramp.ref_inc_step;
350 
351  if (buckInstance->v_loop.controller->Limits.MaxOutput >= buckInstance->set_values.i_ref)
352  // check if ramp is complete
353  {
354  buckInstance->v_loop.maximum = buckInstance->set_values.i_ref;
355  buckInstance->v_loop.controller->Limits.MaxOutput = buckInstance->v_loop.maximum;
356  retval = BUCK_OPSRET_COMPLETE;
357  }
358  else
359  // if ramp is not complete yet, remain in this state
360  {
361  retval = BUCK_OPSRET_REPEAT;
362  }
363  }
364  else // In Non-Current Mode ramp-up ends up here and needs to be lifted to PG_DELAY
365  {
366  buckInstance->v_loop.controller->Limits.MaxOutput = buckInstance->v_loop.maximum;
367  retval = BUCK_OPSRET_COMPLETE;
368  }
369 
370  return(retval);
371 
372 }
373 
374 
387 volatile uint16_t SubState_PowerGoodDelay(volatile struct BUCK_CONVERTER_s *buckInstance)
388 {
389  volatile uint16_t retval=0;
390 
391  // Set BUSY bit until process is complete
392  buckInstance->status.bits.busy = true;
393 
394  // increment delay counter until the GOWER GOOD delay has expired
395  if(buckInstance->startup.power_good_delay.counter++ > buckInstance->startup.power_good_delay.period)
396  {
397  buckInstance->startup.power_good_delay.counter =
398  (buckInstance->startup.power_good_delay.period + 1); // Clamp to PERIOD_EXPIRED for future startups
399 
400  // If defined, set POWER_GOOD output
401  if(buckInstance->gpio.PowerGood.enabled)
402  {
403  retval = buckGPIO_Set(&buckInstance->gpio.PowerGood);
404  if(!retval)
405  return(BUCK_OPSTATE_ERROR);
406  }
407 
408  retval = BUCK_OPSRET_COMPLETE;
409  }
410  else
411  // if period has not expired yet, remain in this state
412  {
413  retval = BUCK_OPSRET_REPEAT;
414  }
415 
416  return(retval);
417 
418 }
419 
420 // end of file
volatile uint16_t SubState_IRampUp(volatile struct BUCK_CONVERTER_s *buckInstance)
This function is for the average current mode control where the output current is ramped up to nomina...
volatile uint16_t SubState_VRampUp(volatile struct BUCK_CONVERTER_s *buckInstance)
This function ramps up the output voltage to its nominal regulation point.
volatile uint16_t SubState_PrepareVRampUp(volatile struct BUCK_CONVERTER_s *buckInstance)
This function calculate and pre-charge PWM outputs with ideal duty cycle.
volatile uint16_t SubState_PowerOnDelay(volatile struct BUCK_CONVERTER_s *buckInstance)
This function delays the startup until the Power-on Delay has expired.
volatile uint16_t SubState_PowerGoodDelay(volatile struct BUCK_CONVERTER_s *buckInstance)
In this function, a counter is incremented until the power good delay has expired.
volatile uint16_t(* BuckConverterRampUpSubStateMachine[])(volatile struct BUCK_CONVERTER_s *buckInstance)
Function pointer array of buck converter startup sub-states.
volatile uint16_t BuckRampUpSubStateList_size
Buck converter sub-state machine function pointer array size.
volatile uint16_t buckPWM_Resume(volatile struct BUCK_CONVERTER_s *buckInstance)
This function resumes the buck PWM operation.
volatile uint16_t buckGPIO_Set(volatile struct BUCK_GPIO_INSTANCE_s *buckGPIOInstance)
This function sets the selected general purpose input/ouput pins.
volatile struct NPNZ16b_s v_loop
External reference to user-defined NPNZ16b controller data object 'v_loop'.
Definition: v_loop.c:86
struct BUCK_CONVERTER_STATUS_s::@126::@128 bits
data structure for single bit addressing operations
volatile uint16_t period
Soft-Start Period (POD, RAMP PERIOD, PGD, etc.)
volatile uint16_t ref_inc_step
Size/value of one reference increment/decrement or this period.
volatile uint16_t counter
Soft-Start Execution Counter (read only)
volatile uint16_t reference
Internal dummy reference used to increment/decrement controller reference.
volatile struct BUCK_STARTUP_PERIOD_HANDLER_s power_good_delay
volatile struct BUCK_STARTUP_PERIOD_HANDLER_s v_ramp
volatile struct BUCK_STARTUP_PERIOD_HANDLER_s power_on_delay
volatile struct BUCK_STARTUP_PERIOD_HANDLER_s i_ramp
volatile uint16_t v_out
BUCK output voltage.
volatile uint16_t v_in
BUCK input voltage.
volatile uint16_t i_ref
User reference setting used to control the power converter controller.
volatile uint16_t v_ref
User reference setting used to control the power converter controller.
enum BUCK_CONTROL_MODE_e control_mode
Fundamental control mode.
volatile uint16_t no_of_phases
number of converter phases
void(* ctrl_Precharge)(volatile struct NPNZ16b_s *, volatile fractional, volatile fractional)
Function pointer to PRECHARGE routine.
volatile uint16_t maximum
output clamping value (maximum)
volatile struct NPNZ16b_s * controller
pointer to control loop object data structure
volatile uint16_t reference
Control loop reference variable.
volatile uint16_t minimum
output clamping value (minimum)
volatile uint16_t duty_cycle_limit
Switch node duty cycle limit value.
volatile uint16_t * ptr_duty_cycle
Pointer to switch node duty cycle register.
volatile struct BUCK_SLOPE_COMP_SETTINGS_s slope_compensation
Peak current mode slope compensation settings.
volatile uint16_t period
Switching period.
volatile uint16_t duty_ratio_min
Absolute duty cycle minimum during normal operation.
volatile int16_t factor
Fractional scaling factor (range -1 ... 0.99969)
volatile int16_t offset
Signal offset as signed integer to be subtracted from ADC input.
volatile int16_t scaler
Feedback bit-shift scaler used for number normalization.
volatile struct BUCK_ADC_INPUT_SCALING_s scaling
normalization scaling settings
volatile struct BUCK_ADC_INPUT_SETTINGS_s ad_vin
ADC input sampling input voltage.
volatile struct BUCK_ADC_INPUT_SETTINGS_s ad_vout
ADC input sampling output voltage.
volatile bool enabled
Specifies, if this IO is used or not.
volatile struct BUCK_GPIO_INSTANCE_s PowerGood
Power Good Output.
BUCK control & monitoring data structure.
volatile struct BUCK_SWITCH_NODE_SETTINGS_s sw_node[BUCK_NO_OF_PHASES]
BUCK converter switch node settings.
volatile struct BUCK_LOOP_SETTINGS_s i_loop[BUCK_NO_OF_PHASES]
BUCK Current control loop objects.
volatile struct BUCK_CONVERTER_STATUS_s status
BUCK operation status bits.
volatile struct BUCK_FEEDBACK_SETTINGS_s feedback
BUCK converter feedback settings.
volatile struct BUCK_GPIO_SETTINGS_s gpio
BUCK converter additional GPIO specification.
volatile struct BUCK_LOOP_SETTINGS_s v_loop
BUCK voltage control loop object.
volatile struct BUCK_CONVERTER_DATA_s data
BUCK runtime data.
volatile struct BUCK_CONVERTER_SETTINGS_s set_values
Control field for global access to references.
volatile struct BUCK_CONVERTER_STARTUP_s startup
BUCK startup timing settings.
struct NPNZ_STATUS_s::@132::@134 bits
Controller status bit-field for direct bit access.
volatile uint16_t * ptrAddress
Pointer to register or variable where the value is read from (e.g. ADCBUFx) or written to (e....
Definition: npnz16b.h:228
volatile uint16_t * ptrControlReference
Pointer to global variable of input register holding the controller reference value (e....
Definition: npnz16b.h:265
volatile struct NPNZ_PORT_s AltTarget
Secondary data output port declaration.
Definition: npnz16b.h:264
volatile struct NPNZ_PORT_s Target
Primary data output port declaration.
Definition: npnz16b.h:263
volatile int16_t MaxOutput
Maximum output value used for clamping (R/W)
Definition: npnz16b.h:330
volatile struct NPNZ_STATUS_s status
Control Loop Status and Control flags.
Definition: npnz16b.h:504
volatile struct NPNZ_LIMITS_s Limits
Input and output clamping values.
Definition: npnz16b.h:508
volatile struct NPNZ_PORTS_s Ports
Controller input and output ports.
Definition: npnz16b.h:505