Read Voltage at PWM off time, and Current at PWM on time

Hello,

For a battery charging project, i am using an ARDUINO UNO which is driving a buck converter to provide the battery with the charging current. I am using external ADCs to measure the battery's charging voltage and current. The test setup is working fine, but right now i am just measuring the voltage and current at random time instants. However to measure it correctly, battery voltage reading should be done at an instant when the controller's PWM output is LOW (OFF duty cycle), and battery current reading should be done when PWM output is HIGH (ON duty cycle). So i was thinking how i can do that, since i am using analogueWrite() function to give PWM output, i thought if i could access analogueWrite() fucntion, may be i could there insert the function of read_ADC_Voltage() during the LOW time, and read_ADC_Current() during the HIGH time.

Is my approach right ? If yes then can please anyone tell me how can i access and use this analogueWrite() function ? And if someone has any other idea to do the readings correctly, please suggest. I shall be grateful.

You could turn PWM off when you want to read the voltage and current. Set the pin appropriately using digitalWrite(). Take your readings, and turn PWM back on.

PWM is driven by hardware. All analogWrite does is set up that hardware and exits. Modifying that wouldn't help.

If you study the datasheet, you can get interrupts at compare match and overflow of the timer which would be where the pin is changing states.

I looked into interrupts and learned about them that there are 2 types of interrupts in Arduino namely "external”, and “pin change”. So i downloaded the "PinChangeInt Library" to test it. I wrote a small program where a PWM of 62.5kHz is being generated on pin3, and i am calling rising and falling edge triggered interrupts on this pin, i.e to display one value when rising edge occurs, and other value when falling edge occurs. My code looks like following:

#include <PinChangeInt.h>
#define pw 3
int pwm;


void setup() {
  // put your setup code here, to run once:
  pinMode(pw, OUTPUT) ;
  pwm_setup();             // Set PWM to a frequency of 62.5kHz
  
  PCintPort::attachInterrupt(pw,rise,RISING);    // call void rise() when PWM is HIGH
  PCintPort::attachInterrupt(pw,fall,FALLING);   // call void fall() when PWM is LOW


  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  pwm = 127;                                                // 50% duty cycle
  pwm_on(pwm);
 
}
void pwm_setup()
{
  
  TCCR2A = 0x23 ;
  TCCR2B = 0x09 ; // mode 7, clock prescale by 1
  OCR2A = 256-1 ;  // 256 clock periods = 16us per cycle
  OCR2B =0 ;
  TCNT2 =0 ;

}
void pwm_on(double)
 {
    OCR2B = pwm ;
 }

void rise()
{
  Serial.println("RISE");
}

void fall()
{
  Serial.println("fall");
}

But it is not working the way i think it should. It keeps on displaying "fall" every time, whereas according to me it should display "RISE" and "fall" alternatively, right ? However if i remove the "PCintPort::attachInterrupt(pw,fall,FALLING); " line, it starts to display "RISE" as it is supposed to.

Since its my first time programming with Arduino, and i am just a beginning level programmer, i might be making some stupid mistake here. So can you point it out please ?

But it is not working the way i think it should.

You can't attach two handlers to the same pin. There is a clue in the name of the library. CHANGE means that YOU have to determine, in the interrupt handle, why you were called.

PaulS:
You can't attach two handlers to the same pin.

So that means i can only use one handler, for e.g

PCintPort::attachInterrupt(pw,rise,RISING);

and i have to sort some way out to tell my controller to do the other task (which it is supposed to do when PWM is LOW) without the help of interrupt. May be some kind of "if, else" condition.

I have yet to figure out why you want to use pin change interrupts on an external interrupt pin. Use the regular attachInterrupt() function to attach a CHANGE handler, and in the interrupt service routine, read the state of the pin to determine if the change was from HIGH to LOW or from LOW to HIGH.

Use direct port manipulation if needed to get the speed required.

On the other hand, turning off PWM for the time needed to read the voltage and current seems a far simpler process to implement.

PaulS:
I have yet to figure out why you want to use pin change interrupts on an external interrupt pin. Use the regular attachInterrupt() function to attach.....

I am just a beginner, so i thought pin change interrupt is the way to go. But if it is not needed in your opinion, then i wont go for it. Ill try searching how to use the regular attachInterrupt() function, and make use of it in my program.

As far as your idea of turning PWM off for the period of voltage reading goes, i am not sure about it. I mean it could be right, but im afraid that ill mess up the process by manually turning the PWM on and off, may be it could disturb my control implementation, or whatsoever.

Ill first try looking into the attachInterrupt() function on how to make it work for my case as you stated, and if i am not successful, then ill go for turning off the PWM and take the voltage reading at that time.

What is the PWM controlling? How long does it take to read the voltage, using whatever sensor you have? How long does it take to read the current, using whatever sensor you are using?

Why would you use a pin change interrupt or external interrupt for this? The PWM hardware switches the pin when the timer hits a compare match and again when the timer overflows. Use the compare match interrupt and the timer overflow interrupt.

You don't say which pins you are using for the PWM, so I'm not sure which timer to point you to. But they all work in basically the same way with subtle differences. Please refer to sections 15, 16, and 18 of the holy datasheet for more information.

PWM is controlling the switching of buck converter, which is controlling the current being provided to the battery. I dont know about the sensor timings, for current sensing i am using a shunt resistor ( to measure the current) , with an amplifier (to adjust the voltage level) and an ADC. For voltage measurement i am just using an amplifier (to adjust the voltage level) and an ADC. So i think that the time requirement would be just that of ADC's. And maximum conversion time in the ADS8319 ADC's data sheet is 1.4us. I have implemented a PI control on my micro-controller, whose sampling time is 16us.

Delta_G:
You don't say which pins you are using for the PWM,

Im sorry if i havent mentioned the pin number. I am generating the PWM on pin 3 which uses the Timer2.

yiipmann:
Im sorry if i havent mentioned the pin number. I am generating the PWM on pin 3 which uses the Timer2.

Then the section you want is section 18. Time to do some reading.

PaulS:
On the other hand, turning off PWM for the time needed to read the voltage and current seems a far simpler process to implement.

What if i do this way

void loop() 
{
  pwm_on(pwm);           //sets PWM at a particular duty cycle calculated by PID function
  pwm_off();                //turn PWM off for voltage reading
  read_ADC_voltage();     // read the voltage
  pwm_on(pwm);          // turn the PWM back on
  read_ADC_current();      // read the current 
  calc_voltage(adcvalue);   // calculate the actual voltage by doing some manipulations
  calc_current(adcvalue2);   // calculate the actual current by doing some manipulations
  Input = amps;               // calc_current(adcvalue2) return "amps" i,e the value of current
  myPID.Compute();      // compute the PWM duty cycle with the help of amps, (a current controller)
  pwm = Output;           // assign PWM the Output of PID fucntion, which is the new PWM value

(In the above function i am trying to keep the current constant by using a PI control implementation, which would be used in Constant Current charging cycle of the battery)

Do you think this will work fine ? Although may be the first two lines may be un-necessary i.e turning the PWM ON and then off, but i guess theres no harm to do that.

Any suggestions ?

As far as interrupt and timers goes, i will look into that too, but i am looking for a simpler solution here, rather than making my code complex by adding interrupts (as interrupts are very sensitive and must be handled very carefully ive heared, so me being a newbie, im just afraid to use them as they might produce some results which i cant detect).

What if i do this way

You said that you needed to read current when the pin was on. With PWM happening, you have no idea whether the pin is HIGH or LOW when you read the current.

PaulS:
With PWM happening, you have no idea whether the pin is HIGH or LOW when you read the current.

Yes you are right about that, but the main thing is that it should be OFF during the voltage reading. Secondly when i started to search a bit more about it over the internet i came to find out that current is approximately same over the pwm cycle, so it can be read any time (as i am getting a dc current at the ouput because of my buck converter LCL filter, so the current would be the same throughout), the only thing to consider is to measure the voltage when there is no signal ( or no HIGH PWM signal ) applied accross the battery cell. So i think this would work considering that.

Delta_G:
Use the compare match interrupt and the timer overflow interrupt.

Agreed. I used this to measure the back emf of a small motor.

...R