/*
* a boost/ step-up or buck/ step-down converter controler algorithm
*
* principle is shown in https://www.we-online.com/en/components/applicationguide/boost_converter
*
* arduino used to provide a PWM signal to control the switch (FET) and to read
* the output voltage serving as a feedback signal. feedback signal is compared with desired setpoint.
* a deviation in output value and setpoint leads to a correction of the PWM => closed loop control.
* for the time being, setpoint will be a fixed value - could be substituted by a potentiometer
*
* as the HW simulator does not provide the ability to build up a complete HW loop, the following
* simplification is applied:
* - the feedback value is provided by pot1 - this pot is not to be confused with a possible pot for providing setpoint value
* - a closed loop is not realised => open loop simulation only
* - a FET is not shown, the control signal is fed into a "resistor".
*
* The logic analyser allows to record the PWM signal - be aware, that one million samples are taken at max
* therefore, play around with the pot within some 10 seconds to observe, how the PWM is interrupted
* once the setpoint is "virtually" exceeded by the feedback signal (simulated by the pot1!)
* the logic analyser file can be view in PulseView as documented in https://docs.wokwi.com/guides/logic-analyzer#viewing-the-data-in-pulseview
*
*/
#define FET_PWM_CTRL_PIN 9 // a pwm capable pin, do not use timer 0 as it is used for delay() and likewise
// - hence, use timer 1, where OC1A/B are on 9 resp 10
#define FEEDBACK_PIN A5 // an ADC pin to read the feedback
#define FILTER_COEFF 4 // a coefficient for a simple filter when reading ADC value
uint16_t feedback_val = 0, setpoint_val = 600; // ADC provides 0 ... 1023 which has to be mapped to the desired
// physical quantiy in volts; for simplifcation a fixed setpoint is used
void setup() {
// put your setup code here, to run once:
pinMode(FET_PWM_CTRL_PIN, OUTPUT);
// the PWM is created "manually" not using the analogue write function due to its low output frequency
// a low output frequency lead to a big inductor in the boost circuit - we want to use small components ;-)
// ensure to enable timer 1 (disable power safe, if any)
PRR &= ~(1 << PRTIM1);
// config "fast PWM" with TOP defined by OCR1A and select no clock prescaler, fast PWM will create a fixed 50% duty cycle
// frequncy calculates as f_pwm = 16 MHz / (2 * 1 * (1 + OCR1A)) or solving for a required f_pwm: OCR1A = 16 MHz / (2 * 1 * f_pwm) - 1
TCCR1B |= (1 << WGM13); // undocumented issue with ATmega 328 16-bit register write access - wihtout this the high byte register value OCR1AH wont be written
// update the buck frequency - 16-bit register access in non-atomic, so protect against IRQ interrupting
noInterrupts(); // disable IRQ
// OCR1AH = 342 >> 8; // yields 19.6 kHz;
// OCR1AL = 342; // yields 19.6 kHz;
OCR1AH = 31 >> 8; // set to 246.3 kHz
OCR1AL = 31;
interrupts(); // enable IRQ
TCCR1A = (1 << WGM11) | (1 << WGM10) | (1 << COM1A0); // COM1A0 = toggle OC1A on compare match
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); // CS10 = no clock prescaling
}
void loop() {
// put your main code here, to run repeatedly:
uint32_t lastCall = 0; // used for quantisation of operations - read ADC, inhibit PWM etc.
if (millis() - lastCall > 3) {
// every x milliseconds do ...
lastCall = millis(); // update the event compare timepoint
feedback_val = (uint16_t) ((FILTER_COEFF * feedback_val + analogRead(FEEDBACK_PIN)) / (FILTER_COEFF + 1));
if (feedback_val <= setpoint_val) {
// the PWM signal needs to be enabled, output signal is too low
// turn the clock source on again (see for details in following else-clause)
TCCR1B |= (1 << CS10);
}
else {
// the PWM signal needs to be disabled, output signal is too high
// one might think to turn revert the configuration of the pin and turn to an input - probably bad idea
// because this will leave the gate of the FET floating - an input pin is typically high impedant
// so, better disable the timer - removing the clock source will do so - hence clear all clock source bits
TCCR1B &= ~( (1 << CS12) | (1 << CS11) | (1 << CS10) );
}
}
}