Boost regulator with ATtiny

When Microchip bought Atmel I was afraid that they would discontinue further development of the AVR MCUs and instead only promote their PIC-devices. But it seems this worry was unjustified. New series of ATtinies and ATmegas have been released and these new devices are packed with very useful periferals. At the same time the price of the newer devices are substantially lower than the older ones.

Of particular interest to me is the Event System and the Configurable Custom Logic (CCL) block that makes it possible to route signals between peripherals and pins without having to go through any CPU processing.
This opens up for applications like software configurable switch-mode regulators for voltage translation (step-up/boost, step-down/buck, flyback etc.).

To evaluate this, a boost regulator to deliver +12V from a +5V supply was designed, built and tested.

The schematic is simple:

What is realised in the AVR can be seen from this block diagram:

The blocks drawn are all configured, but then afterwards fully independent, from the CPU. Two timers are utilized. The first, to the upper left, is configured to run continuously and overflows after 30 µs, i.e. at a fixed frequency at around 33 kHz, when set up as in the code below. The overflow signal is logically AND:ed with the state of the analog comparator. This AND gate is implemented by one of the two Look-Up-Tables in the CCL block. The comparator takes its inputs from a pin and the internal DAC. If the voltage detected at the output of the regulator is lower than the DAC set point, the comparator output is high. The signal from the AND gate then starts the second timer in one-shot mode. It is configured such that its comparison output, which is fed to a pin, is high from start to around 15 µs later. If the comparator would be continuously in its high state this all together creates a signal that repeatedly is high 15 µs and low 15 µs (total period time 30 µs).
This signal is intended to drive a transistor to first “charge” an inductor and then give the inductor time to release its energy at a higher voltage.
The voltage at the output is scaled down and compared with the one from the DAC. This ensures regulation to a fixed output voltage. Thanks to the DAC, the regulator output voltage can be tuned digitally without having to change any resistor values.

The test prototype was built in “dead bug style” above a proto board:

The waveform at the switch node (drain of the transistor) looks like this:

At first we see the 5V supply, then, for 15 µs the transistor pulls low and the current rises in the inductor (a current probe would be nice to have). With component values as in the schematic, the current reached will be 5V/33µH*15µs = 2.3 A.
When the driving waveform goes low, the transistor turns off and the inductor releases its energy. This happens at a voltage (assuming steady-state) that is the difference between the output voltage (plus diode drop, some 0.5V) and the supply voltage. The time it takes for this is 15 µs * 5V/(12.5V-5V) = 10 µs. With 30µs period time we thus have some margin left. It is important that there is enough time for the inductor to discharge, otherwise the current will raise higher and higher at situation of high loading and eventually something will be damaged.
When the energy is released some ringing is observed around the 5V level due to stray capacitance in the circuit (e.g. drain-source capacitance) which resonates with the inductance. This ringing is damped by the RC-snubber circuit across the diode. Without the snubber it looks like this:

The maximum current that can be delivered at 12V can be calculated from the fact that the mean current at 5V is 1.15 A during 15µs and zero at the remaining 15 µs, which gives 0.575A on average if the regulator is working continuously. This is 5V*0.575A = 2.9W. Assuming 85% efficiency leaves around 2.5W at 12V, or a little more than 200 mA. If we want more than this we could e.g. increase the switch current by decreasing the inductance value.

A feature that is nice to have in all switch regulators is overload protection. If we, with this design, can know that the analog comparator hasn’t seen a level above its threshold for a certain time, this can be interpreted as overload and the CPU core can turn off switching. This is implemented by configuring The Periodic Interrupt Timer (PIT) to trig a routine that checks whether the comparator in its turn has trigged an interrupt since the last PIT interrupt. The details are in the code.

This all together demonstrates how money and PCB space can be saved by using blocks in a modern MCU for voltage conversion instead of using separate chips.

The full source code is posted here below. After compilation with avr-gcc it can be programmed to the chip through the one-pin UPDI-interface with a standard UART-cable and pyUPDI.

// Targets an ATtiny214

#define F_CPU 3333333
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define OVERLOAD_LED PIN4_bm // PA4

volatile uint8_t overload_flag;

ISR(RTC_PIT_vect) { // 16 Hz

  RTC.PITINTFLAGS = 0x01; // clear flag
  if (overload_flag) {
    PORTA.OUT |= OVERLOAD_LED;
    TCA0.SINGLE.CTRLA = 0b00000000; // DISABLE switching.
  }
  else {
    PORTA.OUT &= ~OVERLOAD_LED;
    overload_flag = 0x01;
    AC0.INTCTRL = 0x01; // enable interrupt
  }
}

ISR(AC0_AC_vect) {
  AC0.STATUS = 0x01; // clear flag
  AC0.INTCTRL = 0x00; // disable interrupt
  overload_flag = 0x00;
}

void main () {
  
  PORTA.DIR = OVERLOAD_LED | PIN2_bm | PIN5_bm; // outputs
  PORTA.PIN7CTRL = 0x04; // digital input disable for AINP0/PA7
  PORTA.OUT = 0x00;

  PORTMUX.CTRLA = 0x01; // Enable EVOUT0
  
  _delay_ms(500);

  //TCA0.SINGLE.PER = 65; // 19.5us period, for 12V->26V and 120uH
  TCA0.SINGLE.PER = 100; // 30us period, for 5V->12V and 120uH
  TCA0.SINGLE.CTRLA = 0b00000001; // DIV1 -> 0.3us/tick, ENABLE
    
  TCB0.CTRLB = 0x16; // Single shot, output enable
  TCB0.EVCTRL = 0x01; // Enable input capture, start counter at pos edge
  //TCB0.CCMP = 27; // 8us for 12V in and 0.8A current in 120uH
  TCB0.CCMP = 50; // 15us for 5V in and 2.3A current in 33uH
  TCB0.CTRLA = 0x01; // ENABLE

  AC0.MUXCTRLA = 0b10000011; // Inverted output, DAC to neg in
  VREF.CTRLA = 0x03; // 4.3V
  //DAC0.DATA = 140; // 2.36V *(100+10)/10 = 26V
  DAC0.DATA = 65; // 2.36V *(100+10)/10 = 12V
  
  DAC0.CTRLA = 0x01; // ENABLE

  AC0.CTRLA = 0b00100001; // Interrupt at neg edge, ENABLE
  
  EVSYS.SYNCCH0 = 0x02; // TCA0_OVF
  EVSYS.ASYNCCH0 = 0x01; // CCL_LUT0
  EVSYS.ASYNCUSER8 = 0x01; // SYNCCH0 -> EVOUT0/PA2 to see max switch freq 
  EVSYS.ASYNCUSER2 = 0x01; // SYNCCH0 -> LUT0
  EVSYS.ASYNCUSER0 = 0x03; // ASYNCCH0 -> TCB0
  
  CCL.LUT0CTRLB = 0x63; // AC0 + EVENT0
  CCL.TRUTH0 = 0b10001000; // AND
  CCL.LUT0CTRLA = 0x01; // ENABLE
  CCL.CTRLA = 0x01; // ENABLE

  _delay_ms(200); // wait 200ms after start before enabling overload detection
  
  overload_flag = 0x00;
  
  while(RTC.STATUS);
  RTC.CLKSEL = 0x00; // Use 32 kHz from OSC32K
  while(RTC.PITSTATUS);
  RTC.PITINTCTRL = 0x01; // enable interrupt
  while(RTC.PITSTATUS);
  RTC.PITCTRLA = 0b01011001; // Enable, interrupt after 2048 cycles => 16Hz

  sei();
  
  while(1) {
  }
}

There is a thread at AVRFreaks for discussion.

3 thoughts on “Boost regulator with ATtiny

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s