PWM driving of a DC/DC Converter with Arduino nano

Hi everybody,

I would like to drive a MOSFET halfbridge with arduino nano. The thing is, I'm brand new to Arduino, and obviously I'm missing something.

I wrote a program using Timer1, see below.
What it is suppose to do is:
either drive the Highside mosfet with pin 9 in buck converter mode, or to drive the low side Mosfet with pin 10 in boost converter mode.
The mode is selected through switch.

At this point, it should get in buck converter mode when the programm begins, because of the initial values of TimerSet and IsCharging. But nothing happens at either output 9 or 10. (I checked with an osco)

If I put the ISR as comment, then both output pins are high, so I think I missed something about the timer, but I cannot figure out what exactly. I have looked at tutorials and read the AtMega168 datasheet part about timers but I've become quite confused, so I am turning to you.

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


const int ModeSwitchHigh = 2;
const int ModeSwitchLow = 3;
const int HighSideMos = 9;
const int LowSideMos = 10;
volatile boolean IsCharging = true;  //True -> Buck converter mode, using only High-side Mosfet. False -> Boost converter mode, using only Low-Side Mosfet
volatile boolean TimerSet = false;

void setup() {
 pinMode(ModeSwitchHigh,INPUT_PULLUP);
 pinMode(ModeSwitchLow,INPUT_PULLUP);
 pinMode(HighSideMos, OUTPUT);
 pinMode(LowSideMos, OUTPUT);
 digitalWrite(HighSideMos, HIGH);
 digitalWrite(LowSideMos, HIGH); //Vielleicht nicht nötig wegen main Loop

attachInterrupt(digitalPinToInterrupt(ModeSwitchHigh), Buckmode, FALLING);    //Buckconverter mode, Battery loading, High-Side Mosfet
attachInterrupt(digitalPinToInterrupt(ModeSwitchLow), Boostmode, FALLING);    //Boostconverter mode, Battery unloading, Low-Side Mosfet 


  //InitTimer1
  TCCR1A = 0; 
  TCCR1B = 0; 
  TCNT1  = 0; 
  ICR1 = 159;   //Set Top Value, -> frequenz 100 kHz 16 MHz/100kHz-1, 16 MHz internal clock
  OCR1A = 80; // init Wert 5 mikro sek
  TCCR1B |= (1 << CS10); // no prescaling, internal clock
  TCCR1B |= (1 << WGM13); // turn on fast PWM mode
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  TCCR1A |= (1 << COM1A1);  //nötig zum nichtinvertiertes PWM-Signal setzen
 }

void loop() {
  //Buckmode
  if ((IsCharging == true)&&(TimerSet==false)) {
  OCR1A = 71;  //44,44% of 160.  4V output with 9V input
  TimerSet=true;
  digitalWrite(HighSideMos, HIGH);
  digitalWrite(LowSideMos, LOW);
}
  //Boostmode
  else if ((IsCharging == false)&&(TimerSet==false)){
    OCR1A = 96; //T_E = 96, 60 % Period. 
    TimerSet = true;
    digitalWrite(HighSideMos, LOW);
    digitalWrite(LowSideMos, HIGH);
  }
}

ISR(TIMER1_COMPA_vect){

  if (IsCharging == true) //TSS, PWM Aus High-Side Mosfet, Pin 9
  {
   digitalWrite(HighSideMos,LOW);
  }
  else if (IsCharging == false) {
    digitalWrite(LowSideMos,LOW);
  }
}


void Buckmode(){
  IsCharging = true;
  TimerSet = false;
}

void Boostmode(){
  IsCharging = false;
  TimerSet = false;
}

Thanks in advance for your time

Murmeltier

Provide a wiring diagram of your setup.

Hi, well here it is.

I drafted it from memory alone because everything is still at my workplace, but it should be right.

The switch is manual and it's positions, determining wether the battery loads or unloads, are given to the arduino through pins 2 and 3. Anyway, it's really the PWM i'm having a problem with, and (I suppose) the timer routine.

All right, somebody else helped me.

My error was that I schould have worked with PINB |= (1 << PINB1); //toggle pin9 and PINB |= (1 << PINB2); //toggle pin10 inside the ISR so that the pins go back to their normal state at the end of the cycle.

I tried to access pin 9 and pin 10 directly with digitalWrite, which, obviously, did not work.

I tried to access pin 9 and pin 10 directly with digitalWrite, which, obviously, did not work.

Why obviously ?

Well, because there was no PWM at either pin 9 or 10, which was the problem I exposed in my first post.

Murmeltier:
Well, because there was no PWM at either pin 9 or 10, which was the problem I exposed in my first post.

Now I am really confused.

The Nano pins 9 and 10 are PWM capable but they can also be used as digital pins. As you were using digitalWrite() I am not really surprised that there was no PWM at either pin 9 or 10

There are several things wrong with your timer setup.

  1. For fast PWM to ICR1, you need mode 14, with bits set in WGM13,WGM12, and WGM11. With top value ICR1 set to 159 you will get 100 KHz.

  2. You need to enable the pwm hardware outputs for both output pins A and B. Set bits in COM1A1 and COM1B1
    to clear on compare match and set at top (non inverted output i.e higher compare match values give longer duty cycle on). OCR1A and OCR1B will be the compare match values.

  3. The processor will generate hardware outputs, and you do not need to enable any compare match interrupts or use compare match ISR's to manipulate the outputs. If fact, one of the problems with the current code is that you were using a dual sloped timer mode, and have the compare match interrupt turn off the pin at the same time as it was being turned on.

Thank you very much for this advice, I'll do it now :slight_smile:

Thank you very much!

I corrected my code thanks to your help. It looks like this, now, and seems to work properly (I haven't tested very extensively yet)

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


const int ModeSwitchHigh = 2;
const int ModeSwitchLow = 3;
const int HighSideMos = 9;
const int LowSideMos = 10;
volatile boolean IsCharging = true;  //True -> Buck converter mode, using only High-side Mosfet. False -> Boost converter mode, using only Low-Side Mosfet
volatile boolean TimerSet = false;
volatile int CompareValueHigh = 40;
volatile int CompareValueLow = 40;


void setup() {
 pinMode(ModeSwitchHigh,INPUT_PULLUP);
 pinMode(ModeSwitchLow,INPUT_PULLUP);
 pinMode(HighSideMos, OUTPUT);
 pinMode(LowSideMos, OUTPUT);

attachInterrupt(digitalPinToInterrupt(ModeSwitchHigh), Buckmode, FALLING);    //Buckconverter mode, Battery loading, High-Side Mosfet
attachInterrupt(digitalPinToInterrupt(ModeSwitchLow), Boostmode, FALLING);    //Boostconverter mode, Battery unloading, Low-Side Mosfet 


  //InitTimer1
  TCNT1  = 0;
  TCCR1A = 0; 
  TCCR1B = 0; 
  
  // set to mode 14 fast pwm.
  // TCCR1B
 // Bit                 7      6      5       4     3      2      1      0
 // Bit Name          COM1A1 COM1A0 COM1B1 COM1B0 -----  ----- WGM11  WGM10
 // Initial Value       0      0      0       0     0      0      0      0
 // changed to          1      0      1       0     0      0      1      0

 TCCR1A = B10100010;      
   
 // TCCR1B
 // Bit             7     6      5       4       3      2        1       0
 // Bit Name      ICNC1  ICES1 ----   WGM13    WGM12    CS12    CS11     CS10
 // Initial Value    0     0     0        0       0      0        0       0
 // changed to       0     0     0       1       1      0        0       1
 
 TCCR1B = B00011001;
  
  ICR1 = 159;   //Set Top Value, -> frequenz 100 kHz 16 MHz/100kHz-1, 16 MHz internal clock
  OCR1A = 50; // init Wert 5 mikro sek
  OCR1B = 50;  
 }

void loop() {
//Buckmode  
  if ((IsCharging == true)&&(TimerSet==false)) {
    // Here Pin 10 stoppen, Pin 9 enable   
   TCCR1A &= ~(1 << COM1B1);
  TCCR1A |= (1 << COM1A1);
  OCR1A = 20; 
  TimerSet=true;
}
  //Boostmode
  else if ((IsCharging == false)&&(TimerSet==false)){
   TCCR1A &= ~(1 << COM1A1);
     TCCR1A |= (1 << COM1B1);
    OCR1B = 20; 
    TimerSet = true;
  }
}

void Buckmode(){
  IsCharging = true;
  TimerSet = false;
 // PINB = (1 << PINB1); //toggle pin9
  
}

void Boostmode(){
  IsCharging = false;
  TimerSet = false;
}

Nice job getting this sorted out. I like the presentation of your comments as well. +1

One thing I am not certain about is the correct way to handle the disconnected output in each of the two modes. I think that digitalWrite HIGH or LOW may be appropriate, but I don't really understand the circuit.

The nice presentation of comments about TCCR1A and TCCR1B is from somebody on the internet, but I did like it too. It helped me quite a lot.

I tried with digitalWrite first, but it didn't have any effect, that's why i ended up setting the PWM off and on for each mode.

I tried with digitalWrite first, but it didn't have any effect, that's why i ended up setting the PWM off and on for each mode.

Yes, setting the PWM off and on for each mode is correct. My question is about the desired state of the pin/FET which is not putting out the PWM. (i.e. the output which is turned off).

Mmh, yes, I probably should set them on LOW when I disable the PWM, is what you mean? (I know I want them on LOW when not working)

Mmh, yes, I probably should set them on LOW when I disable the PWM, is what you mean? (I know I want them on LOW when not working)

Yes. Use, whatever state of the output places the FET in the condition you want it. I have seen different buck/boost circuits where the non pwm'd FET was conducting, and others where it was not.