Teensy 4.0 First Beta Test

Status
Not open for further replies.
PWMServo Again
Again testing has been on pins 0, 1, 2, 3. I finally attached a servo to pins 1 and 2 (2 being the problem with the inverted signal and direction that I mentioned in previous post). Testing with the servo was done with the T3.5 for comparison to the same servo on the T4. Here are the results:
  1. On the T3.5 when moving in the 1 degree increments with 15ms between going from 0 to 180 took 2.70151 to complete the loop. Also measure the time from start of write(pos) to finish as between 2-3 us.
  2. Using the same sketch on the T4 (pin1) when moving in the 1 degree increments with 15ms between going from 0 to 180 took 2.70318 to complete the loop, a bit longer. Also measured the time from start of write(pos) to finish as 0 us (don't understand this unless it is returning immediately but then why would I get a signal that looks like a PWM signal on the scope?
  3. Looking at the waveforms on the scope while both are pwm signals there are differences between them which is next on the list
  4. The T4 wave seems to be much wider when it reaches the 180deg point than the T3.5. Maybe on the T4 it winds up as twice the size hard to tell on my scope which might be the reason for the added time to go from 0 to 180 degrees.

The only thing I can think of is that analogwrite is misbehaving?

From my previous post:
PWMServo Library

Tested the sweep example with the scope on pins 0, 1, 2, and 3.
On pins 0 and 1 the signal starts low goes when the sweep starts and the pulse widens from right to left as the sweep angle increases and then decreases as the angle decrease.
On pins 2 and 3 this is reversed. The signal starts high goes low as the pulse starts and as the sweep angle increases the pulse width increases from right to left and decrease left to right as the angel decreases
With sketch not running pins 0,1 are low while 2,3 are high.
The frequency is 50khz with a period of 20ms


Is this the way it should be?

EDIT: Just repeated the sweep test on a T3.5 and looks 1 and 3 match.
 
posted some simple baseline sketches used to see stuff github.com/Defragster/T4_demo

A simple delay free blink that should work for manitou?
Show startup timing and print a bit and a LOT and a call to delayMicroseconds() to know the CyCCntEnb is good upfront.
 
Hardware Serial: Currently trying to debug Serial.read(). Currently not getting an interrupt when data should arrive on data pin.
...
Or wondering if we should simply have the hardware definition here say it is pin 0, and then look up both: IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_03 and IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_03

Especially if we have s setTX and setRX for multiple pins... I think I am leaning that way...

Thoughts?

Do any pins have ALT use for UARTs? Table doesn't show any - FlexIO pins may alter that?

Anyhow - will watch for progress/changes - got the 11hr old github …

KurtE - swapped in your (2) files - it compiles. But posted BlinkMin - with no changes HALTS quietly the first time the LED blinks OFF?


Forgot to back up the HardwareSerial's … had to reinstall.


Prepped to test I have a T_3.6 catching debug from T4 Pin#17 and changed that to echo to Serial and also Serial3 to feed T_3.6 pin 8 and into T4 Pin 0 for Serial1 - so any debug spew should get back to T4 USB.

Added ::
Code:
#define KE_SERIAL Serial1

void setup() {
  KE_SERIAL.begin( 115200 );
...

void loop() {
  int incomingByte;
  ii++;
  while (KE_SERIAL.available() > 0) {
    incomingByte = KE_SERIAL.read();
    Serial.print((char)incomingByte);
  }
...
 
Last edited:
The only thing I can think of is that analogwrite is misbehaving?

Yup, we're missing analogWriteResolution, which PWMServo needs. Will work on this soon.

I've ported the regular Servo library. Please give this a try. Does it work with regular servo motors? So far I've only verified the waveforms with my oscilloscope.
 

Attachments

  • Servo.cpp
    24.3 KB · Views: 98
...

I've ported the regular Servo library. Please give this a try. Does it work with regular servo motors? So far I've only verified the waveforms with my oscilloscope.

It Works - same Sweep pin 9 on T_3.6 runs on T4b

Some generic Mini Analog Servo with 5V from USB

I have another larger Continuous servo that spins up - slows down - and repeats in changed direction … and repeats
 
Paul - as noted the Serial start time added 100+ms with 1.45b5? As well as the entry into setup()? I suppose you expect that but just noting because my ' while ( !Serial && millis() < 600 ); ' failed now to be ready to catch first print as it is generally over 600ms and not under.

Also - as my one posted sketch BlinkMin showed - a huge amount of Serial.print immediately on setup() entry - before Serial==true is ignored and partially buffered - huge can be 1,311,696 copies of Serial.println( millis() ); in the waiting while.

Problem is that once Serial goes true - if lost it blocks on .print until SerMon returns - leaving my Servo running for instance.

This can be prevented by stopping print if (!Serial) - but T_3x's don't do that.

BTW: First time I hooked a Servo to a Teensy - I knew I had them for a reason.
 
It Works - same Sweep pin 9 on T_3.6 runs on T4b
Some generic Mini Analog Servo with 5V from USB
...

<EDIT UPDATE> Obvious question does T_3.6 do the same thing with this servo on SWEEP, yes it does with the T4_update Servo.cpp and the saved installed copy. It goes into and out of 0° smoothly and jumps to the finish at 180 - not smooth

Moved Servo into Blink with Interval timer ( 498K/sec ) and the 1.5MB/sec Serial print - seems okay except on the 180° end - I limited to 160 - and it jumps to 180 and grumbles funny there before resuming?


Doing one update per second when I toggle the LED Blink.

Just re-ran SWEEP and paying attention it does the same thing there at 180°.

BTW: My cat came to investigate … the sounds from the Servo I think, I won't leave it running.
 
Last edited:
Problem is that once Serial goes true - if lost it blocks on .print until SerMon returns - leaving my Servo running for instance.

Maybe this is related to almost all interrupts currently using the default priority? Servo needs a fairly high NVIC priority level. I built this one on top of IntervalTimer, and currently IntervalTimer's priority setting isn't implemented.

Later (probably in a couple weeks) I'm planning to put more work into IntervalTimer to implement different priority levels for each timer, like we have with Teensy 3.x. But it's not simple, because NXP put all 4 timers on the same interrupt. We can't just assign each its own priority in the NVIC. All 4 need to use the highest priority, which is really unfortunate when a library like Servo needing high priority will get combined together in a project with other libs using IntervalTimer for non-urgent background stuff. I'm probably going to add code so up to 3 other unused/reserved interrupts can be commandeered and we can use the set pending like the audio library does. This might end up being quite tricky, since all the IntervalTimer APIs are meant to be callable from interrupts at all priority levels.... so I'm putting this off for a couple weeks while bringing up most of the other libraries.
 
Yup, we're missing analogWriteResolution, which PWMServo needs. Will work on this soon.

I've ported the regular Servo library. Please give this a try. Does it work with regular servo motors? So far I've only verified the waveforms with my oscilloscope.
Got it on the analogwriteresolution/analogres() being missing. Saw it in the imxrt.h and forgot to check if it was defined in pwm.c.

I downloaded the updated servo.cpp file and tested the servo on pins 1,2,3, and 4 just as a check. Tim covered pin 9. Worked exactly like it was working on a T3.5. So would say its ready for prime time.
 
Morning Tim.
Moved Servo into Blink with Interval timer ( 498K/sec ) and the 1.5MB/sec Serial print - seems okay except on the 180° end - I limited to 160 - and it jumps to 180 and grumbles funny there before resuming?

Doing one update per second when I toggle the LED Blink.

Just re-ran SWEEP and paying attention it does the same thing there at 180°.
I ran your sketch with my servo and didn't have grumbling at the extremes (0 or 180degs). When I tested sweep the range was 0-180 deg without grumbling. I am using a GWS servo btw

One of the things I experienced with different servos is that you may have to adjust the usecs limits for the low and/or high to get rid of the grumbling. Usually when that happens you hit the stop in the servo that it wants to go past.
 
pin tests
I ran various pin tests on edge pins, digital out, in,INPUT_PULLUP, analog in, pwm out, attachinterrupt . Most things are OK, but i had two anomalies.

1) nothing on pin 9 for PWM ??
2) A3 sees 3v3 ok, but to GND, reads 1021 and not 0 ???? EDIT A3 is pin 17 which is used by core printf, ok.

Most MCU's with floating input to analog input read "random" values, T4 floating analog are pretty steady... FWIW

Measured internal INPUT_PULLUP resistors at about 23K ohms.
Pin 13 in INPUT_PULLUP mode measures 1.68v as a result of resistor-LED on pin 13.

EDIT: pin 9, me thinks definition is wrong in hardware/teensy/avr/cores/teensy4/pwm.c, pins 8 and 9 have same config??
Code:
    {1, M(2, 2), 1, 2},  // FlexPWM2_2_A   8  // B0_10
    {1, M(2, 2), 1, 2},  // FlexPWM2_2_B   9  // B0_11

FIX: change to {1, M(2, 2), 2, 2}, // FlexPWM2_2_B 9 // B0_11
and pin 9 PWM works

EDIT: 2nd beta unit, all edge pin tests OK 1/10/19

With T4 breakout board (1/15/19) confirmed backside pins worked, digitalIO worked, PWM worked (no waveform inversion), and Serial 1-8 worked Rx-to_Tx
 
Last edited:
I've fixed bugs with missing I/O defs, and ported libraries OneWire, Encoder and CapacitiveSensor.

If anyone *really* wants an installer now for these, just say the word. Otherwise I'm going to hold off packaging up beta6 until tomorrow. Should have a few more libs ported by then...
 
I was just looking at the encoder library and was giving me headache with all that avr stuff. Put it aside and went for coffee.
 
General question: Wondering about how you are handling setting/clearing bits in registers without bit banding?

As M7 chips do not have bit banding. It does appear they have setup some registers to handle this, by having register, set, clear and toggle access to some registers, but not all.
Example:
Code:
#define HW_OCOTP_CTRL			(IMXRT_OCOTP.offset000)
#define HW_OCOTP_CTRL_SET		(IMXRT_OCOTP.offset004)
#define HW_OCOTP_CTRL_CLR		(IMXRT_OCOTP.offset008)
#define HW_OCOTP_CTRL_TOG		(IMXRT_OCOTP.offset00C)

But for LPUART I see:
Code:
// 39.3.1.1: page 2466
typedef struct {
	const uint32_t VERID;
	const uint32_t PARAM;
	volatile uint32_t GLOBAL;
	volatile uint32_t PINCFG;
	volatile uint32_t BAUD;
	volatile uint32_t STAT;
	volatile uint32_t CTRL;
	volatile uint32_t DATA;
	volatile uint32_t MATCH;
	volatile uint32_t MODIR;
	volatile uint32_t FIFO;
	volatile uint32_t WATER;
} IMXRT_LPUART_t;
And suppose in the CTRL register I want the main write function to set the CTRL bit: LPUART_CTRL_TIE
But the associated ISR could potentially update the CTRL register as well (could clear this bit, or maybe set LPUART_CTRL_TCIE

Just wondering best approach for these...
 
Code:
#define CCM_CCGR0_CAN2_SERIAL(n)		((uint32_t)(((n) & 0x03) << 20))
#define CCM_CCGR0_CAN2(n)			((uint32_t)(((n) & 0x03) << 18))
#define CCM_CCGR0_CAN1_SERIA[COLOR="#FF0000"]l[/COLOR](n)		((uint32_t)(((n) & 0x03) << 16))

typo, small character
 
Just wondering best approach for these...

A somewhat related question,
in the imxrt.h file I see sometimes the device registers grouped together as structures allowing different devices of same time be accessed via index into an array of devices (e.g. IMXRT_DMA_TCD_t)

there are then also explicit defines for all registers and all devices
#define DMA_TCD0_SADDR (IMXRT_DMA_TCD[0].SADDR)

and then there are declarations with pseudo structures
#define I2S1_TCSR (IMXRT_I2S1.offset008)

Is there a need for a unified approach?
 
As M7 chips do not have bit banding. It does appear they have setup some registers to handle this, by having register, set, clear and toggle access to some registers, but not all.
For my temp monitor stuff I just changed the register contents directly in the setup. Never used set, clr or toggle. At least for my application
 
General question: Wondering about how you are handling setting/clearing bits in registers without bit banding?
.....
Just wondering best approach for these...

I really miss the bitband. :(

There isn't any comprehensive answer. In many places, it's going to mean temporarily disabling the peripheral's interrupt, or all interrupts. I really wish ARM & NXP would have thought more about atomic bit set & clear, but sadly what we have to work with in this hardware is a rather piecemeal approach, where some the most critical peripherals like GPIO are sorely lacking. At least they did put in those 3 extra GPIO registers in the 2nd rev silicon (notice other parts still say 8 registers, not 11), but we're still left without atomic access to change pin direction or mask/unmask each pin's interrupt.

I don't imagine anyone from NXP involved in the specs of these chips will ever read this, but if they do.... please please please give us firmware developers atomic bit set & clear on *ALL* peripheral registers. Doesn't matter if it takes an extra clock cycle, like the bitband or bit manipulation engine (on Kinetis M0+ chips), as long as it's truly an atomic bus access (including DMA's view). Lacking atomic bit access means we programmers have to navigate a possible minefield of thorny race conditions just to talk to the hardware.


in the imxrt.h file I see sometimes the device registers grouped together as structures allowing different devices of same time be accessed via index into an array of devices (e.g. IMXRT_DMA_TCD_t)

there are then also explicit defines for all registers and all devices
#define DMA_TCD0_SADDR (IMXRT_DMA_TCD[0].SADDR)

and then there are declarations with pseudo structures
#define I2S1_TCSR (IMXRT_I2S1.offset008)

Is there a need for a unified approach?

With Teensy 3.x, many of the defines are still individual addresses. Some have been converted to structs. The trouble with individual addresses is the compiler doesn't optimize well, treating each as its own pointer.

So for the new chip, I wanted to start out with all using structs for efficient code. But defining those structs is a huge amount of work. It's also rather error prone when working from the reference manual, where everything is documented as offsets. So as a "solution" I recreated those 3 generic structs with everything named as offset. The 3 goals were, 1: cut down the hours needed, 2: improve the accuracy by having a close match to the docs, and 3: reap the compiler optimization benefits.

Since then I've started slowly converting some of them to device specific structs. Unless someone with a *lot* of free time wants to spend it on something that has no real benefit, seems unlikely most will get converted. I've only been doing the ones where we have several of something identical and C++ classes have a constexpr pointer. I do care if the actual code as the register names, so were not going to write something like HardwareSerial.cpp with names like "port->offset00C" all over the code. But for all cases you would just write "LPUART1_PINCFG" in the code, I really don't see any reason to pour hours of work into editing the defines.
 
Unless someone with a *lot* of free time wants to spend it on something that has no real benefit, seems unlikely most will get converted.

OK,
not everything has to be like the following
Code:
typedef struct
{
  uint32_t CSR;
  uint32_t CR1,CR2,CR3,CR4,CR5;
  uint32_t DR[8];
  uint32_t FR[8];
  uint32_t MR;
} I2S_PORT;

typedef struct
{
  uint32_t VERID;
  uint32_t PARAM;
  I2S_PORT TX;
  uint32_t unused[9];
  I2S_PORT RX;
} I2S_STRUCT;

I2S_STRUCT *I2S1 = ((I2S_STRUCT *)0x40384000);
I2S_STRUCT *I2S2 = ((I2S_STRUCT *)0x40388000);
I2S_STRUCT *I2S3 = ((I2S_STRUCT *)0x4038C000);
Note I realize the inconsistency in CR1 equiv. to CR[0] (replaced array with explicit list)
Not sure it is clearer or compiles better, but code seems to run OK
 
Last edited:
While working over the CAN registers, both CAN controllers consume 166 defines, I was able to cross verify and match the addresses between T4 & T3.x with new defines, the addresses are basically same except for the extended mailbox filtering and 2-3 more registers. This brought the 166 defines down to 19 which will work on both CAN1 & CAN2 controllers
Interested or not, just throwing it out there :)
Also with the T3.x series and the T4, the kinetis.h/imxrt.h lack the bit definitions for the config registers. With the 147 defines we can clear, I'm sure we have room to add a few :)

Code:
#define IMXRT_FLEXCAN1		(*(IMXRT_REGISTER32_t *)0x401D0000)
#define IMXRT_FLEXCAN2		(*(IMXRT_REGISTER32_t *)0x401D4000)
#define FLEXCANb_MCR(b)           (*(vuint32_t*)(b))
#define FLEXCANb_CTRL1(b)         (*(vuint32_t*)(b+4))
#define FLEXCANb_TIMER(b)         (*(vuint32_t*)(b+8))
#define FLEXCANb_RXMGMASK(b)      (*(vuint32_t*)(b+0x10))
#define FLEXCANb_RX14MASK(b)      (*(vuint32_t*)(b+0x14))
#define FLEXCANb_RX15MASK(b)      (*(vuint32_t*)(b+0x18))
#define FLEXCANb_ECR(b)           (*(vuint32_t*)(b+0x1C))
#define FLEXCANb_ESR1(b)          (*(vuint32_t*)(b+0x20))
#define FLEXCANb_IMASK2(b)        (*(vuint32_t*)(b+0x24))
#define FLEXCANb_IMASK1(b)        (*(vuint32_t*)(b+0x28))
#define FLEXCANb_IFLAG2(b)        (*(vuint32_t*)(b+0x2C))
#define FLEXCANb_IFLAG1(b)        (*(vuint32_t*)(b+0x30))
#define FLEXCANb_CTRL2(b)         (*(vuint32_t*)(b+0x34))
#define FLEXCANb_ESR2(b)          (*(vuint32_t*)(b+0x38))
#define FLEXCANb_CRCR(b)          (*(vuint32_t*)(b+0x44))
#define FLEXCANb_RXFGMASK(b)      (*(vuint32_t*)(b+0x48))
#define FLEXCANb_RXFIR(b)         (*(vuint32_t*)(b+0x4C))
#define FLEXCANb_RXIMR(b, n)      (*(vuint32_t*)(b+0x880+(n*4)))
#define FLEXCANb_GFWR(b, n)       (*(vuint32_t*)(b+0x1E0))
 
Status
Not open for further replies.
Back
Top