Hardware/software allocation

Hi All. I want to build an interleaved, 3-phase (square wave rather than sine) PWM where duty cycle remains the same over hundreds of cycles. Duty cycles will occasionally be varied via command through SPI. __--------____________--------________ __________--------____________--------_ ----_______________--------_______________---

Can I allocate particular pieces of hardware (timers etc), or does the compiler handle that, as long as I allocate appropriate data sizes. Has anyone any idea what the maximum PWM frequency would be with various chips/boards ? I want to be able to run to 300kHz as well as 2 ADCs and SPI communication. I only need 3 o/p pins, 2 ADC, SPI and 5 GPIO.

Thanks in advance

The Arduino UNO has three timers. The Arduino core manages one timer to provide millisecond and microsecond timers and ~900 Hz PWM on two pins . Each of the other two timers are used by your code or various libraries. I think you will need three separate timers to get interleaved PWM. The Arduino Mega 2560 has more timers so that might be a better choice.

Most Arduino boards run on a 16 MHz clock so you can get 8 MHz PWM, if you only need three values (0%, 50% and 100%). At 300 kHz you would have 53 levels of PWM using Fast PWM but using Phase Correct PWM you only get half the frequency so you would have 26 levels of PWM at that speed.

You say you want 300khz PWM but what is the time (or frequency) between cycles?

     |---------  time ? ---------|
_____|--------|__________________|--------|___________
______________|--------|__________________|--------|____
-----|_________________|---------|_________________|---

I'm just curious if it can all be done in software.

The DUE has a PWM controller which gives you the ability to synchro several PWM channels and update duty cycles (and/or frequency) on the fly, 13 ADC channels and an SPI interface. The PWM frequency goes up to 84 MHz.

One timer should be enough. One pin goes high on the first pulse, the second pin goes high on the second pulse, the third on the third pulse, and then start counting again.

This should work:

void ISR() { // The ISR called by the timer
  // Reset timer (too lazy to look this one up).
  pulse++;
  switch (pulse) {
    case 1:
      digitalWrite(1, HIGH);
      digitalWrite(3, LOW;
      break;
    case 2:
      digitalWrite(1, HIGH);
      digitalWrite(3, LOW;
      break;
    case 3:
      digitalWrite(1, HIGH);
      digitalWrite(3, LOW;
      pulse = 0; // reset the pulse counter
  }
}

You may want to replace the digitalWrite() with direct port writes, as that's a lot faster. Overall ISR should be short enough to qualify as ISR, especially with direct port writes it can be finished within a couple dozen clock ticks.

wvmarle: One timer should be enough. One pin goes high on the first pulse, the second pin goes high on the second pulse, the third on the third pulse, and then start counting again.

I don't see how you vary the duty cycle. It looks like you can only vary the frequency. I think the OP wants a fixed frequency (300 kHz) and variable duty cycle.

Oh, missed the duty cycle part. OK then two timers - one for starting the pulses, one for ending the pulses (I assume duty cycle is the same for all the phases, and that the timers will not diverge from one another, as they're linked to the same clock speed).

wvmarle: OK then two timers - one for starting the pulses, one for ending the pulses (I assume duty cycle is the same for all the phases, and that the timers will not diverge from one another, as they're linked to the same clock speed).

How would that work when the duty cycle exceeds 33% and the pulses start to overlap?

Should be no problem with the ISR as I suggested above. One for setting HIGH, another for setting them LOW, in order. Then the overlap is handled automatically, as one ISR only looks at which signal is due to be switched HIGH, and the other for which signal has to be set LOW, regardless of what the other signals may be at the time of switching.

The only problem I see is at the limits of 0% and 100%, then this doesn't work any more.

wvmarle: The only problem I see is at the limits of 0% and 100%, then this doesn't work any more.

At 0% just set all three pins LOW and stop the timers. At 100% just set all three pins HIGH and disable the timer interrupts. That's what analogWrite() does. :)

I know, that's the obvious workaround.

Hi, What is the application?

3phase usually means the three pulses are interleaved, not separate individual ON times like you have shown.

Thanks.. Tom.. :)