Teensy 4.0 analogwrite minor bug?

kingforger

Active member
I'm using analogWrite to use the PWM functionality on a Teensy 4.0. I'm using 10 bits resolution. When I do analogWrite(PIN, 1023) I would expect the pin to be on 100% of the time without any dips or 'blips'.

However, there's a little 'blip' where the voltage goes down to zero for a very short time at the frequency that I specified earlier via analogWriteFrequency. My 350MHz BW scope sees this clearly. If I tell it to limit BW to 20MHz, you cannot see this any more. So for example, if I do:

analogWriteFrequency(PIN, 50000);
analogWrite(PIN, 1023);

then you will see a little 'blip' or dip down to 0V (and then ringing back up) every 20 microseconds (50kHz rate). As shown below:
blip.png

HOWEVER, if I instead change the order and do:
analogWrite(PIN, 1023);
analogWriteFrequency(PIN, 50000);

Then there are no blips at all even at 350MHz BW! It's perfectly on all the time as I expect. As shown below:
blip gone.png

This seems to be a bug to me. FYI you see 5V above because it's gone through a digital isolator with 5V output to interface to other things.
 
Last edited:
which pin are you using?

The reason I ask, is there are two different timer subsystems (eFlexPWM, or QuadTimer) used depending on which pin.
which is controlled by the table in PWM.c
Code:
const struct pwm_pin_info_struct pwm_pin_info[] = {
	{1, M(1, 1), 0, 4},  // FlexPWM1_1_X   0  // AD_B0_03
	{1, M(1, 0), 0, 4},  // FlexPWM1_0_X   1  // AD_B0_02
	{1, M(4, 2), 1, 1},  // FlexPWM4_2_A   2  // EMC_04
	{1, M(4, 2), 2, 1},  // FlexPWM4_2_B   3  // EMC_05
	{1, M(2, 0), 1, 1},  // FlexPWM2_0_A   4  // EMC_06
	{1, M(2, 1), 1, 1},  // FlexPWM2_1_A   5  // EMC_08
	{1, M(2, 2), 1, 2},  // FlexPWM2_2_A   6  // B0_10
	{1, M(1, 3), 2, 6},  // FlexPWM1_3_B   7  // B1_01
	{1, M(1, 3), 1, 6},  // FlexPWM1_3_A   8  // B1_00
	{1, M(2, 2), 2, 2},  // FlexPWM2_2_B   9  // B0_11
	{2, M(1, 0), 0, 1},  // QuadTimer1_0  10  // B0_00
	{2, M(1, 2), 0, 1},  // QuadTimer1_2  11  // B0_02
	{2, M(1, 1), 0, 1},  // QuadTimer1_1  12  // B0_01
	{2, M(2, 0), 0, 1},  // QuadTimer2_0  13  // B0_03
	{2, M(3, 2), 0, 1},  // QuadTimer3_2  14  // AD_B1_02
	{2, M(3, 3), 0, 1},  // QuadTimer3_3  15  // AD_B1_03
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{2, M(3, 1), 0, 1},  // QuadTimer3_1  18  // AD_B1_01
	{2, M(3, 0), 0, 1},  // QuadTimer3_0  19  // AD_B1_00
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{1, M(4, 0), 1, 1},  // FlexPWM4_0_A  22  // AD_B1_08
	{1, M(4, 1), 1, 1},  // FlexPWM4_1_A  23  // AD_B1_09
	{1, M(1, 2), 0, 4},  // FlexPWM1_2_X  24  // AD_B0_12
	{1, M(1, 3), 0, 4},  // FlexPWM1_3_X  25  // AD_B0_13
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{1, M(3, 1), 2, 1},  // FlexPWM3_1_B  28  // EMC_32
	{1, M(3, 1), 1, 1},  // FlexPWM3_1_A  29  // EMC_31
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{1, M(2, 0), 2, 1},  // FlexPWM2_0_B  33  // EMC_07
#ifdef ARDUINO_TEENSY40
	{1, M(1, 1), 2, 1},  // FlexPWM1_1_B  34  // SD_B0_03
	{1, M(1, 1), 1, 1},  // FlexPWM1_1_A  35  // SD_B0_02
	{1, M(1, 0), 2, 1},  // FlexPWM1_0_B  36  // SD_B0_01
	{1, M(1, 0), 1, 1},  // FlexPWM1_0_A  37  // SD_B0_00
	{1, M(1, 2), 2, 1},  // FlexPWM1_2_B  38  // SD_B0_05
	{1, M(1, 2), 1, 1},  // FlexPWM1_2_A  39  // SD_B0_04
#endif
#ifdef ARDUINO_TEENSY41
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{1, M(2, 3), 1, 6},  // FlexPWM2_3_A  36  // B1_00
	{1, M(2, 3), 2, 6},  // FlexPWM2_3_B  37  // B1_01
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{0, M(1, 0), 0, 0},
	{1, M(1, 1), 2, 1},  // FlexPWM1_1_B  42  // SD_B0_03
	{1, M(1, 1), 1, 1},  // FlexPWM1_1_A  43  // SD_B0_02
	{1, M(1, 0), 2, 1},  // FlexPWM1_0_B  44  // SD_B0_01
	{1, M(1, 0), 1, 1},  // FlexPWM1_0_A  45  // SD_B0_00
	{1, M(1, 2), 2, 1},  // FlexPWM1_2_B  46  // SD_B0_05
	{1, M(1, 2), 1, 1},  // FlexPWM1_2_A  47  // SD_B0_04
	{0, M(1, 0), 0, 0},  // duplicate FlexPWM1_0_B
	{0, M(1, 0), 0, 0},  // duplicate FlexPWM1_2_A
	{0, M(1, 0), 0, 0},  // duplicate FlexPWM1_2_B
	{1, M(3, 3), 2, 1},  // FlexPWM3_3_B  51  // EMC_22
	{0, M(1, 0), 0, 0},  // duplicate FlexPWM1_1_B
	{0, M(1, 0), 0, 0},  // duplicate FlexPWM1_1_A
	{1, M(3, 0), 1, 1},  // FlexPWM3_0_A  53  // EMC_29
#endif
};
 
Pins 3 and 4. EMC_05 and EMC-06. Both on the Flex timer, from the look of it. Though I'm not sure how that would affect this problem.
 
Thanks,

As to how it affects the problem:
The code base is completely different under the seams depending on what type of timer.
Just helps to deduce which code to look at...
Example AnalogWrite:
Code:
void analogWrite(uint8_t pin, int val)
{
	const struct pwm_pin_info_struct *info;

	if (pin >= CORE_NUM_DIGITAL) return;
	//printf("analogWrite, pin %d, val %d\n", pin, val);
	info = pwm_pin_info + pin;
	if (info->type == 1) {
		// FlexPWM pin
		IMXRT_FLEXPWM_t *flexpwm;
		switch ((info->module >> 4) & 3) {
		  case 0: flexpwm = &IMXRT_FLEXPWM1; break;
		  case 1: flexpwm = &IMXRT_FLEXPWM2; break;
		  case 2: flexpwm = &IMXRT_FLEXPWM3; break;
		  default: flexpwm = &IMXRT_FLEXPWM4;
		}
		[COLOR="#FF0000"]flexpwmWrite(flexpwm, info->module & 0x03, info->channel, val);[/COLOR]
	} else if (info->type == 2) {
		// QuadTimer pin
		IMXRT_TMR_t *qtimer;
		switch ((info->module >> 4) & 3) {
		  case 0: qtimer = &IMXRT_TMR1; break;
		  case 1: qtimer = &IMXRT_TMR2; break;
		  case 2: qtimer = &IMXRT_TMR3; break;
		  default: qtimer = &IMXRT_TMR4;
		}
		quadtimerWrite(qtimer, info->module & 0x03, val);
	} else {
		return;
	}
	*(portConfigRegister(pin)) = info->muxval;
	// TODO: pad config register
}
The set of code that you are hitting on is handled by the Red branch versus some of the other timers which go down the other rabbit hole (quadTimerWrite).
Or another way to look at it, someone needs to verify how the registers are set as to the Reference manual chapter 54 versus chapter 53...
 
I'm using 10 bits resolution. When I do analogWrite(PIN, 1023) I would expect the pin to be on 100% of the time without any dips or 'blips'.

10 bits means the cycle is divided into 1024 time slots. Writing 0 means none of them have the waveform high. Writing 1023 means 1023 of those 1024 have the waveform high.

The analogWrite() function, at least as implemented on Teensy, does indeed try to give you 100% high when you write 1024 or more. But the hardware can't do perfect 100% high. If you scope is fast enough, you'll see about 6ns low.

For a quick confirmation, I ran this code:

Code:
void setup() {
  analogWriteResolution(10);
  analogWrite(4, 1023);
}
void loop() {
}

and here is the resulting waveform:

file.png

As you can see on the screen, the pulse width is 220ns. The 4.4823 kHz cycle has a period of 223.1 us. 1/1024th of that cycle is 217.9ns. The hardware really giving you 1 of the 1024 time slots with the waveform low when you write 1023.

I also tested 1024, with this:

Code:
void setup() {
  analogWriteResolution(10);
  analogWrite(4, 1024);
}
void loop() {
}

Here is the resulting waveform:

file2.png

Ideally there should be no pulse. The signal should be 100% high. But sadly, the hardware can't seem to do it (or maybe we have a software limitation?) But compared to the waveform with 1023, you can see it is attempting 100% (all 104 time slots) high.

file2.png
 
"Ideally there should be no pulse. The signal should be 100% high. But sadly, the hardware can't seem to do it (or maybe we have a software limitation?) But compared to the waveform with 1023, you can see it is attempting 100% (all 104 time slots) high."

Yes, this is what I'm getting at. I was simplifying my code but I really meant to write 1024 instead of 1023. I did measure a pulse, as you saw. However, when I changed the order of my two lines of code, the pulse would completely go away. That's the interesting thing.
 
Back
Top