Teensy 4.0 and PWM

Status
Not open for further replies.

drother

Member
Hello,

I am having an issue with a T4 and setting a PWM pin to 256. Instead of being high all the time, it actually turns the port low. From searching around (on previous teensy boards), it seems you have to set 256 to be fully on. Any ideas?
 
try 1024 for full on? AFAIK the default resolution is 10 bit.

For use of 8 bit max 256 try :: analogWriteResolution(8)
 
Yeah I had it set to 8 bit resolution for that test. It is driving power electronics for a brushed DC motor. When the PID loop hit 256 it shut off!
 
An unsigned 8-bit integer can have a value of 0 to 255
An unsigned 10-bit integer can have a value of 0 to 1023

I would expect writing 256 to a PWM output set for 8-bit resolution would output 0.

This is a perfect example of why it says:

Forum Rule: Always post complete source code & details to reproduce any issue!
 
At least on Teensy 3.x when a PWM write of a value larger than allowed by resolution is passed - the indicated pin is just set HIGH like in cores\teensy3\pins_teensy.c:
Code:
	max = 1 << analog_write_res;
	if (val <= 0) {
		digitalWrite(pin, LOW);
		pinMode(pin, OUTPUT);	// TODO: implement OUTPUT_LOW
		return;
	} else if (val >= max) {
		digitalWrite(pin, HIGH);
		pinMode(pin, OUTPUT);	// TODO: implement OUTPUT_HIGH
		return;
	}

I'm not sure I see the same behavior coded in the \cores\teensy4\pwm.c source:
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;
		}
		flexpwmWrite(flexpwm, info->module & 0x03, info->channel, val);
	} 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
}
 
Confirmed it happens at 256 on 8 bit, 1024 on 10 bit, and 4096 on 12 bit.

I came up with the pretty simple sketch:

Code:
const int ledPin = 13;
const int pwm_freq = 3000; //pwm hz
const int pwm_res = 8; //pwm resolution, also pid output bits
int PWM = 0;
int PWM_max = 0;

void setup() {
  Serial.begin(9600);
  analogWriteFrequency(ledPin, pwm_freq);
  analogWriteResolution(pwm_res);
  PWM_max = 1 << pwm_res;
  //--PWM_max;
}

void loop() {
  Serial.print("PWM: ");
  Serial.println(PWM);
  analogWrite(ledPin, PWM);
  ++PWM;
  if (PWM > PWM_max) {
  --PWM;
  }
  delay(20);
}

un-comment out line 12 and the LED doesn't turn off.
 
Thanks, nice sketch - some mods to work with edits combining code in p#8 above - I wired pin #14 to LED #13:
Code:
const int ledPin = 13;
const int pwm_freq = 3000; //pwm hz
const int pwm_res = 12; //pwm resolution, also pid output bits
int PWM = (1 << pwm_res) - 30;
int PWM_max = 0;

void setup() {
  Serial.begin(9600);
  analogWriteFrequency(ledPin, pwm_freq);
  analogWriteResolution(pwm_res);
  analogReadResolution(pwm_res);
  PWM_max = 1 << pwm_res;
  //--PWM_max;
}

int aList[] = { 1,5,9,13,15,19,23,25,255 };
void loop() {
  Serial.print("PWM: ");
  Serial.print(PWM);
  int ii=0;
  while( aList[ii] < 200 ) {
    analogWrite(aList[ii], PWM);
    ii++;
  }
  ++PWM;
  if (PWM > PWM_max+2) {
    PWM-=4;
  }
  delay(2);
  Serial.print( "\tanalog Read: ");
  Serial.println( analogRead( 14 ) );
  delay(100);
}

It seems to work for pin #13. As you can see in p#8 2nd code there are two types of 'Analog PWM pins' - without looking I'm not sure where the breaks are? I tested the aList above {1,5,9,13,15,19,23,25} against pin #14 to work.

Not sure if you want to swap out your files: {Arduino}\hardware\teensy\avr\cores\teensy4\pwm.c with this file and test?

I'll put in a Pull Request then for review/inclusion.
 
Thanks, nice sketch - some mods to work with edits combining code in p#8 above - I wired pin #14 to LED #13:
Code:
const int ledPin = 13;
const int pwm_freq = 3000; //pwm hz
const int pwm_res = 12; //pwm resolution, also pid output bits
int PWM = (1 << pwm_res) - 30;
int PWM_max = 0;

void setup() {
  Serial.begin(9600);
  analogWriteFrequency(ledPin, pwm_freq);
  analogWriteResolution(pwm_res);
  analogReadResolution(pwm_res);
  PWM_max = 1 << pwm_res;
  //--PWM_max;
}

int aList[] = { 1,5,9,13,15,19,23,25,255 };
void loop() {
  Serial.print("PWM: ");
  Serial.print(PWM);
  int ii=0;
  while( aList[ii] < 200 ) {
    analogWrite(aList[ii], PWM);
    ii++;
  }
  ++PWM;
  if (PWM > PWM_max+2) {
    PWM-=4;
  }
  delay(2);
  Serial.print( "\tanalog Read: ");
  Serial.println( analogRead( 14 ) );
  delay(100);
}

It seems to work for pin #13. As you can see in p#8 2nd code there are two types of 'Analog PWM pins' - without looking I'm not sure where the breaks are? I tested the aList above {1,5,9,13,15,19,23,25} against pin #14 to work.

Not sure if you want to swap out your files: {Arduino}\hardware\teensy\avr\cores\teensy4\pwm.c with this file and test?


I'll put in a Pull Request then for review/inclusion.

Thanks.

My original test with the dc motor was on pin 12.
 
The teensy4 code is different.
I notice this line in cores/teensy4/pwm.c :

if (cval > modulo) cval = modulo; // TODO: is this check correct?

Without studying this too closely, I'm thinking this might be relevant.

edit: I should have just stayed out - @defragster is on top of this.
 
Last edited:
The teensy4 code is different.
I notice this line in cores/teensy4/pwm.c :

if (cval > modulo) cval = modulo; // TODO: is this check correct?

Without studying this too closely, I'm thinking this might be relevant.

I have no idea what that is about … I saw the Teensy3 code for overt set to HIGH or LOW is missing … attachment p#11 should work on pin 12 or any other - goes digital HIGH > res or LOW <= ZERO. Then should return to analog function between those values.

Edit - that is only under one of the two types of 'flexpwmWrite' and not the 'quadtimerWrite' case - it is making sure the val in cval is properly constrained in some fashion - it doesn't ASSERT HIGH and LOW beyond the resolution range.
 
I have no idea what that is about … I saw the Teensy3 code for overt set to HIGH or LOW is missing … attachment p#11 should work on pin 12 or any other - goes digital HIGH > res or LOW <= ZERO. Then should return to analog function between those values.

Yup! I confirmed it works for both pin 13 and pin 12!
Thanks defragster!
 
Status
Not open for further replies.
Back
Top