Teensy 3 simultaneous analogWrite() possible?

Status
Not open for further replies.
Hi all. Is there a way to set new pwm values on 3 or more different pin's at the same time?
It's easy to do this for their digital states. But I need that for pwm ( modulating a TTL rgb laser).

Martin
 
Nobody has an idea? In pins_teensy.c PWM is generated with TPM or FTM. But to understand the FTM flowcharts and the application notes is really hard.
The use of FTM_SYNC_CNTMAX or FTM_SYNC_CNTMIN and FTM_SYNC_SWSYNC is not clear to me. They say that COMBINE has to be used but this is always
linking two channels.
Or should i try to use FTM_PWMLOAD? I would say no. Because i have to preload the CnV registers and then write all new values at one point to the
FTM.

To explain my problem:

analogWrite(redVal, redPin);
analogWrite(greenVal, greenPin);
analogWrite(blueVal, bluePin);

gives the following result:

line1.jpg

As you can see, the red part of the white laser is activated first. Then comes the green part in and the beam goes to yellow. The blue part comes
and the beam goes to white.
At the end the red part is switched off, the beam becomes cyan. Then the green part is switched off, the blue part is the last visible color before the laser
goes off.

This happens because the light source is just a point modulated over mirrors in his movement to get a line.
The Teensy is fast enough to generate an 8 bit resolution for each color (rgb) just with TTL modulation.
The problem is just to write the PWM values at the very same time to the pins.

May be that anybody had the same problem before?

Martin
 
First, you need to use pins which are controlled from the same FTM timer.

Details are on this page. Scroll down to the table after "PWM Frequency".

https://www.pjrc.com/teensy/td_pulse.html

When you call analogWrite(), the value is written to a register. The register is double buffered, so the PWM completes the current cycle with the old setting, then uses your new setting on the next cycle.

So to get all 3 to update together, you will need to add some code to cause all 3 writes to occur before the counter reaches its max value and a new PWM cycle begins. You could do this by a tight loop which reads the counter. It can also be done with the timer overflow interrupt.

Again, I want to emphasize the hardware is indeed double buffered. Perhaps you have see results that lead you to believe analogWrite() is somehow delaying and the speed of the code to execute 3 calls to analogWrite matters? That would be a WRONG assumption. Writing to the FTM channel register has no immediate effect. The PWM completes its current cycle with the original setting, then the last write you performed during the old cycle takes effect on the next cycle.
 
May be thats fine

Ok i cant test the code with the laser right now. But i have connected some LEDs to a Teensy 3.5 and it seems to be okay.
I will test it with the connected laser-modul in the next few days.

Code:
#define FTM0_CH0_PIN  22
#define FTM0_CH1_PIN  23
#define FTM0_CH2_PIN  9

#define FTM_PINCFG(pin) FTM_PINCFG2(pin)
#define FTM_PINCFG2(pin) CORE_PIN ## pin ## _CONFIG

#define TOF 7
#define TOIE 6


const int onBoardLedPin = 13;
volatile bool onBoardLedState = false;

int timerOverflowCnt = 0;
const int TIMER_OVERFLOW_CNT_MAX = 1000;

const uint32_t PWM_FREQUENCY = 96000;
int intensity = 0;

const int ANALOG_WRITE_RES = 10;
volatile uint32_t cval = 0;



/* EVERY FTM0-COUNTER OVERFLOW THIS WILL BE EXECUTED (DEPENDING ON THE PWM FREQUENCY) */
void ftm0_isr(void) {

  cli();
  FTM0_SC &= ~(1<<TOF);                                       /* WITHOUT CLEARING THE FLAG THE MCU STUCKS IN THE ISR */
  timerOverflowCnt++;
  if (timerOverflowCnt > TIMER_OVERFLOW_CNT_MAX) {            // REFRESH THE PWM VALUES ?
    timerOverflowCnt = 0;
    onBoardLedState = !onBoardLedState;                       // JUST FOR DEBUGGING
    FTM0_C0V = cval;                                          // LOAD NEW (NEXT) PWM VALUES
    FTM0_C1V = cval;
    FTM0_C2V = cval;
  } // if
  sei();

} // end



void setup() {
  
  pinMode(onBoardLedPin, OUTPUT);                                             // JUST FOR DEBUGGING

  analogWriteFrequency(FTM0_CH0_PIN, PWM_FREQUENCY);                          // SET PWM FREQUENCY

  FTM0_SC |= (1<<TOIE);                                                       // ENABLE OVERFLOW INTERRUPT ON FTM0
  NVIC_ENABLE_IRQ(IRQ_FTM0);                                                  // ENABLE INTERRUPTS FOR FTM0

  /* TEENSYS PIN CONFIGURATION */
  FTM_PINCFG(FTM0_CH0_PIN) = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;   // RED PIN
  FTM_PINCFG(FTM0_CH1_PIN) = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;   // GREEN PIN
  FTM_PINCFG(FTM0_CH2_PIN) = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;   // BLUE PIN
  
} // end




void loop() {
  
  intensity = analogRead(A14);                                                        // GET A VALUE
  cval = ((uint32_t)(intensity-1) * (uint32_t)(FTM0_MOD + 1)) >> ANALOG_WRITE_RES;    // COPIED FROM pins_teensy.c
  digitalWriteFast(onBoardLedPin, onBoardLedState);                                   // JUST FOR DEBUGGING
  
} // end

Martin :D
 
Last edited:
Status
Not open for further replies.
Back
Top