Teensy 4.0 First Beta Test

Status
Not open for further replies.
I'm confused. "scope on pin 2" -- pin 2 of what? T4? T4 pin 2 uses eflexpwm, but on my scope i see 37.3mhz (jitter 37.9) with 40mhz on pin 8 (eflexpwm).
"hooked it up to the T4" -- what is "it"? adafruit generator?

FWIW, i changed my qtmr_count.ino sketch to use pin 8 PWM (eflexpwm) for testing. analogWriteFrequency(8,75000000) works for eflexpwm pins, doesn't for qtmr pwm pins. And i removed raw PWM 10 code, no longer needed.

Sorry for the confusion. Was testing a change that @defragster made to sketch where he was doing a the analogWriteFrequency using pin 2 with 40Mhz. Using your new sketch I am seeing it range from 37.13 to 37.87Mhz. At 75Mhz am seeing 74.07 to 76.75Mhz.

I just changed the freqCount test sketch and at 40Mhz getting 37.7Mhz, 75Mhz gives 75Mhz freqCount. Just about exact. With the clock generator was getting a bit different results. At 75Mhz was getting around 70.2Mhz with FreqCount.

Now for a couple of questions to show my ignorance:
1. Which pins would be QTMR pwm pins
2. Which pins are eFlexPWM pins
Reason I ask is that pin 8 is shown as QT4_1 and pin 9 QT4_2??? So I am really confused on the differences so back to the RM I guess.
 
Now for a couple of questions to show my ignorance:
1. Which pins would be QTMR pwm pins
2. Which pins are eFlexPWM pins
Reason I ask is that pin 8 is shown as QT4_1 and pin 9 QT4_2??? So I am really confused on the differences so back to the RM I guess.

The pin table in post #3 has a PWM column. The entries of the form PWMx... are eflexpwm. Entries of form QTx... are quad timer PWM. A couple of pins can be either based on ALT choice in MUX config register. For QT, there are 4 timers each with 4 "channels". QT4_2 is channel 2 of QT timer 4. Similarly for eflexpwm, 4x4 plus A or B output pins.

is FreqCount or my qtmr_count sketch showing 75000000 for 75mhz from a 2nd T4? The only time I see 75000000 is if i'm doing an androgynous test on a single T4 -- T4's PWM jumpered to pin 9 of same T4. As you've now measured with Adafruit generator, external PWM to a T4 is probably accurate only up to 68 mhz

you could measure Adafruit's 25mhz crystal accuracy with GPS PPS ...
 
@manitou
Thanks for explanation on PWM pins - never realized that before.

Just been checking and the answer to your question:
is FreqCount or my qtmr_count sketch showing 75000000 for 75mhz from a 2nd T4? The only time I see 75000000 is if i'm doing an androgynous test on a single T4 -- T4's PWM jumpered to pin 9 of same T4.
The only time I see exactly 75Mhz is when I am using your qtmr_count sketch on the same T4. If I go from T4 -- T4 I only see about 66Mhz, just tested.

Since I was using the Adafruit generator I am pretty sure that freqCount is working on pin 9 as it should be - are there any pins that are unusable like on the T3.x? Not 100% sure. Maybe pin 6?

If I could find my one and only GPS with a PPS signal broken out I can give it a try. :) Every time I clean up and put stuff away I can never find it again :).
 
Since I was using the Adafruit generator I am pretty sure that freqCount is working on pin 9 as it should be - are there any pins that are unusable like on the T3.x? Not 100% sure. Maybe pin 6?
:).

Using pin 9 (QT4_2 cascaded with QT4_3) I don't think there are any T4 pins unusable, at least, I don't see any pin in post #3 that uses QT4_3. When we were using pin 19 (QT3), the cascaded channel was making pin 18 unusable for PWM, hence the change to QT4 pin 9.
 
Using pin 9 (QT4_2 cascaded with QT4_3) I don't think there are any T4 pins unusable, at least, I don't see any pin in post #3 that uses QT4_3. When we were using pin 19 (QT3), the cascaded channel was making pin 18 unusable for PWM, hence the change to QT4 pin 9.

Cool. Guess its about ready for prime time. In middle of something else - will do the push to Paul in a little bit. Thanks. Mike
 
To try and fine tune the errors I added a 16us correction factor for the timer but may need some more testing. I did post that change up my GitHub page.
I don't think you want to make such a correction in the library. The small error in counts is not due to a fixed bias but in frequency inaccuracies of both the Adafruit generator's 25MHz crystal (± 30 ppm) and your T4's 24MHz crystal (± 10 ppm?). So another T4 and another Adafruit generator would likely exhibit slightly different frequency errors.
 
PWMServo library

Just tested 3 5v servos - a GWS, a old Futaba and a HiTex 645MG. All three worked fine with the 3.3v PWM signal from the T4. However, if you are going to use several servos would probably power them from a different source than the T4 5v pin. Just remember gnd to gnd :)
 
using USB1 and USB2 design question

I started to use simultaneously USB1 _and_ USB2 in device mode.
(It is really on T3.6 but I used code from T4, so I post here)

I got it working with both ports defined for usb_serial.
For this I added a set of usb2_* files and use a seperate #define USB2_SERIAL.

Now, I really wanted to use USB_SERIAL on USB1 and USB2_MTPDISK on USB2 (USBHS in T3.6)
So, I run into design questions

usb_serial uses a timer and different endpoint definitions
should one use a single for multiple devices (here seremu, mtp) ?
What is the best way to eliminate visibility of device specific defines in usb dispatcher (say usb2.c) ?
I can undefine all symbols in new code or use new symbols.

I know Paul will be working on T4 usb, but everything (T4 and SW) seems to be delayed somewhat and my schedule conflicts with unknown release of T4, so I need to work on T3.6 to obtain HS MTP disk access.
 
DMAMEM and malloc() how to use with DMA?

I know I have been over some/most of this before, but it keeps coming up and I am not really sure of what approaches people are expecting to do with these types of memory allocations on the T4...

So far I believe DMAMEM stands for: make it a pain in the a.. to use with DMA ;)

a) DMA out of memory (example to MOSI), will not see any data that changed in the cache so it gets stale information
b) DMA into memory (example MISO to mem) will go directly into RAM, but memory reads will go to cache again old data...

Example suppose you have a display: example ST7789 240x320 pixel display. So you have a frame buffer of 240*240*2 bytes = 153600 bytes. And you setup your frame class to go into continuous update mode using DMA. This will require lets say 3 DMASettings to be chained to each other with lets say 51200 bytes output each... Sort of besides the point, but is the state of st7789_t3 code in my fork/branch

Now I sort of make the assumption that you turned on continuous updates as you are actually wanting to update it... Note: currently when you write to memory in this memory range, it goes through a cache, which great for speeding things up, BUT DMA goes through always reading from the real memory, which may be stale and show the old stuff...

So currently my display driver, when it finishes a frame it tries to force the cache to flush into real memory.
Hack for address range: if ((uint32_t)_pfbtft >= 0x20200000u) arm_dcache_flush(_pfbtft, _width*_height*2);

Which sort of works.

Note: that same DMA ISR also increments a frame count... Now suppose my mainline program has:
Code:
void testContinuousUpdate() {
  elapsedMillis emu = 0;
  Serial.println("Start Continuous update test");
  tft.fillScreen(ST7735_RED);
  tft.updateScreenAsync(true);
  Serial.println("After updateScreenAsync");
  while(tft.frameCount() < 10) {
   if (emu > 500) {
    emu = 0;
    Serial.printf("Frame count: %d\n", tft.frameCount());
   }
  }
  tft.fillScreen(ST7735_GREEN);
  while(tft.frameCount() < 20) ;
  tft.fillScreen(ST7735_BLUE);
  while(tft.frameCount() < 30) ;
  tft.fillScreen(ST7735_RED);
  tft.drawRect(0,0, tft.width(), tft.height(), ST7735_BLUE);
  tft.setCursor(10, tft.height() / 2 - 4);
  tft.printf("R:%d W:%d H:%d", rotation, tft.width(), tft.height());
  while(tft.frameCount() < 35) ;
  Serial.println("Finished all frames");
  tft.endUpdateAsync();
  Serial.println("After call to endUpdateAsync");
  while (tft.asyncUpdateActive());  
  Serial.println("Test completed");
}

Now suppose we get to frame 10 and we are fill the screen with GREEN (was RED)

Note the fillScreen will simply iterate and write the color green to all of the memory locations....

OK so far, except: You will likely see some splotchy output, as some of the writes stay in the cache and some make it through RAM which shows up in that screen update.

The interesting questions include, what should I do about this?

I could in cases like this, maybe have all three of my DMASettings fire an interrupt, could also have them fire interrupt at mid point... Could then in cases like this or maybe showing simple movie frames, then have the code synchronize itself to wait until lets say the top third of a frame displays and fill in that third, then when second third completes update that third....

But that is more problematic if you wish to more general graphics.

Could maybe try to setup to double buffer. and maybe have the system copy current buffer code is using into secondary memory that the DMA actually outputs from...

BUT I keep wondering how many hoops code like this should jump through?

Maybe again DMAMEM - should be defined to be - Good to use for DMA?
Maybe a new define FASTMEM or CACHEDMEM or ... that has the cache enabled?

Wondering if when linking sections in upper memory could be setup, that if the user did define DMAMEM, that section would be created and use up the sizes requested of the upper memory and then the rest could be allocated to cached?

Thoughts? What am I missing?
 
Problems with memcpy() and the T4

I have a problem with memcpy() that I think was addressed in this thread, but I can't seem to find it, MAYBE I'm wrong:)
I have a version of the KILO editor that I modified to work with the T36 and was working with the T36.

Using the latest TD 1.47b4 and Arduino 1.8.9 for T4.

Tried it on the T4 and got the following results.
This is the function that works with the sprintf():
Code:
void editorSave(void) {
  int j, len = 0;
  char tempFilename[256];
  char buf[256];

  for (j = 0; j < E.numrows; j++)
    len += E.row[j].size + 1;

  if (E.filename == NULL) {
    E.filename = editorPrompt("Save as: %s (ESC to cancel)", NULL);
    if (E.filename == NULL) {
      editorSetStatusMessage("Save aborted");
      return;
    }
    editorSelectSyntaxHighlight();
  }
  sprintf(tempFilename, "%s", E.filename);
  result = f_open(&fp,tempFilename, FA_WRITE | FA_CREATE_ALWAYS);
  if (result == FR_OK) {
	for (j = 0; j <= E.numrows; j++) {
[COLOR="#FF0000"]                sprintf(buf,"%s\n",E.row[j].chars);[/COLOR]
//		memcpy(buf, (char *)E.row[j].chars, E.row[j].size);
//		buf[E.row[j].size] = '\n';
		result = f_puts(buf,&fp);
	}
	f_close(&fp);
	E.dirty = 0;
	editorSetStatusMessage("%d bytes written to disk", len);
	return;
  }
  f_close(&fp);
  editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
}

This is the lising that comes up in the KILO editor after a save using sprintf():
Code:
' def.bas
cls 
slcls 11
key$ = ""
fontsize 2
print "getkey() function test"
fontsize 1
while key$ <> chr$(27)
  key$ = getkey()
  if key$ <> chr$(27) then 
    print key$;
    if key$ = chr$(13) then 
      print 
    endif
  endif
wend
end
function getkey()
  local kp$
  kp$ = ""
  repeat
    kp$ = inkey$
  until kp$ <> ""
return kp$
Works.

Now, using memcpy() instead of sprintf():
Code:
void editorSave(void) {
  int j, len = 0;
  char tempFilename[256];
  char buf[256];

  for (j = 0; j < E.numrows; j++)
    len += E.row[j].size + 1;

  if (E.filename == NULL) {
    E.filename = editorPrompt("Save as: %s (ESC to cancel)", NULL);
    if (E.filename == NULL) {
      editorSetStatusMessage("Save aborted");
      return;
    }
    editorSelectSyntaxHighlight();
  }
  sprintf(tempFilename, "%s", E.filename);
  result = f_open(&fp,tempFilename, FA_WRITE | FA_CREATE_ALWAYS);
  if (result == FR_OK) {
	for (j = 0; j <= E.numrows; j++) {
//		sprintf(buf,"%s\n",E.row[j].chars);
[COLOR="#FF0000"]                memcpy(buf, (char *)E.row[j].chars, E.row[j].size);
		buf[E.row[j].size] = '\n';[/COLOR]	
		result = f_puts(buf,&fp);
	}
	f_close(&fp);
	E.dirty = 0;
	editorSetStatusMessage("%d bytes written to disk", len);
	return;
  }
  f_close(&fp);
  editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
}

I get this:

Code:
' def.bas
cls 
.bas
slcls 11

key$ = ""
fontsize 2
 print "getkey() function test"
fontsize 1
ey() function test"
while key$ <> chr$(27)
n test"
  key$ = getkey()
(27)
n test"
  if key$ <> chr$(27) then 
t"
    print key$;
$(27) then 
t"
    if key$ = chr$(13) then 
"
      print 
 chr$(13) then 
"
    endif
t 
 chr$(13) then 
"
  endif
f
t 
 chr$(13) then 
"
wend
if
f
t 
 chr$(13) then 
"
end

if
f
t 
 chr$(13) then 
"
function getkey()
(13) then 
"
  local kp$
key()
(13) then 
"
  kp$ = ""

key()
(13) then 
"
  repeat
"

key()
(13) then 
"
    kp$ = inkey$

(13) then 
"
  until kp$ <> ""
(13) then 
"
return kp$
 <> ""
(13) then 
"
*|
urn kp$
 <> ""
(13) then 
"

Any ideas, am I missing something obvious?
(This happens to me a lot);)
 
@KutrE,

There is no trailing null after \n that I can see in the hex dump just 0x0A. But I see a lot of repeating code through out the rest of the file.
I guess I need to do some basic tests with memcpy().
Thanks
 
I believe the fputs will output to file until it find null char. My guess is your \n is overwriting it and so fputs might continue to write more, repeating what was in buffer from previous writes
 
FWIW, NXP SDK examples OFTEN disabled DCACHE with SCB_DisableDCache(). See earlier thread
https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=197430&viewfull=1#post197430

Thanks, As I mentioned, I thought we had discussed some of this before.

But still wonder, is this what any random library should do? That is if you use the library it disables the cache for the rest of the system?

Or should I put this in the examples code for the library, that if you are going to use DMA updates, call this...

Or should library code find ways around it? Example I just pushed up a version of the DMA support for st7735/89 displays, that instead of doing dma directly from the frame buffer (which could be malloc), it instead has two smaller buffers as part of the object, which during the DMA frame updates, it copies sections of frame buffer into it's internal buffers as it updates the display...

With this change it removed the bleed through and splotchy updates my test scratch was showing for continuous update. But it added the overhead of processing more dma interrupts, which memcpy memory.

And this change took me a lot longer to get working, as again ran into interrupts being called multiple times... Needed: asm("dsb");
 
Or should I put this in the examples code for the library, that if you are going to use DMA updates, call this...

Yes, this. Libraries using DMA should call the cache flush or delete functions. Cache maintenance really should be done within libraries, not usually exposed to developers who simply wish to use the library.

Examples for those libs should use DMAMEM or malloc() to allocate the memory. Currently this is not done in many of them, but really should be. DMA does not get "fair" access (bus arbitration) to buffers allocated in DTCM or ITCM. The CPU takes precedence. Tight loops or other memory-heavy code can delay or stall DMA if the buffers are located in those memory ranges.


FWIW, NXP SDK examples OFTEN disabled DCACHE with SCB_DisableDCache().

Like so many vendor code samples, this is a terrible practice when you try to build a software ecosystem on top of that sort of code.


That is if you use the library it disables the cache for the rest of the system?

Yup, that's the huge problem with disabling the cache. It makes writing some library easier and (maybe) more efficient. But the terrible cost is wrecking performance for everything else.

Don't disable the cache.
 
@PaulStoffregen and others...

As a few of us have been playing with the ST7735/89_t3 library to support DMA updates, we ran into issues of trying to do continuous updates and make changes to the stuff in the frame buffer (i.e. the reason you are having it do continuous updates)... I have a version of the ST... library where I use secondary buffers, that I copy data into out of main FB while doing the update... More in the thread: https://forum.pjrc.com/threads/5701...r-displays-without-CS-pin?p=211286#post211286

To demonstrate this on probably a setup you have (ILI9341 display), I earlier updated my ili9341_t3n library (github.com/kurte/ili9341_t3n) which still requires my SPIN library also up in my github...

I made a copy of the test program I was using for ST... that runs on ILI9341... Nothing special. It was mainly done to test out different rotations of different ST77xx displays that have different memory layouts...

View attachment ili9341_t3n_simpletest_FB-190730a.zip

If you type just: <cr>
in the Serial Monitor it will change the rotation and draw test screen.

if you type: a <cr>
It will draw it using DMA (Async) different background color

Now the interesting one, if you type: c<cr>
It will run a short continuous screen update test, which is nothing special:
Code:
void testContinuousUpdate() {
  elapsedMillis emu = 0;
  Serial.println("Start Continuous update test");
  tft.fillScreen(ILI9341_RED);
  tft.updateScreenAsync(true);
  Serial.println("After updateScreenAsync");
  while(tft.frameCount() < 10) {
   if (emu > 500) {
    emu = 0;
    Serial.printf("Frame count: %d\n", tft.frameCount());
   }
  }
  tft.fillScreen(ILI9341_GREEN);
  while(tft.frameCount() < 20) ;
  tft.fillScreen(ILI9341_BLUE);
  while(tft.frameCount() < 30) ;
  tft.fillScreen(ILI9341_RED);
  tft.drawRect(0,0, tft.width(), tft.height(), ILI9341_BLUE);
  tft.setCursor(10, tft.height() / 2 - 4);
  tft.printf("R:%d W:%d H:%d", rotation, tft.width(), tft.height());
  while(tft.frameCount() < 35) ;
  Serial.println("Finished all frames");
  tft.endUpdateAsync();
  Serial.println("After call to endUpdateAsync");
  while (tft.asyncUpdateActive());  
  Serial.println("Test completed");
}
But with current code, you will see blotches of new and old colors coming through. This is because some of the memory writes make it through to the real memory and are picked up and others wait until the next logical frame, as the ISR does a flush of all of the ram at that time...

Hope that makes sense... To make it work right I will probably need to do the same type update to my DMA support code, that have a couple smaller buffers I copy portions of frame buffer into and have the DMA operations work off of that memory...
 
Working with the ST7789 on this thread : ST7735-library)-support-for-displays-without-CS-pin

Also works on T_3.6 and others - but I just have an active T4 hooked up to twin TFT's.

As noted in linked post KurtE's latest this morning is running a pair of these non_CS devices - one each on SPI and SPI1 using POGO from pin #26/27 from breakout bottom on latest T4.

Been running some hours - I took out the wait 250ms and it is toggling the screens as fast as the ASYNC update on one screen completes or 1 ms - didn't actually add time tracking - but the 240x240 displays are both cycling faster than a single complete image can be seen - with lots of flash from out of sync bulk updates.

Oh - and of course I set SPI speed up from 24M ( probably the spec?) to 48 MHz and no issues.
 
@PaullStoffregen and others interested in DMA output on ILI9341_t3n..

I created a new branch: https://github.com/KurtE/ILI9341_t3n/tree/T4_DMA_buffer
Where I did the work I mentioned in the previous post #3894...

Where I did copy of Frame buffer into local memory which DMA uses to update the display. I used two smaller buffers round robin, and when a buffer completes, it switches to the other DMASettings with the other buffer, and triggers DMA interrupt, which then copies in the next portion of the frame buffer into it....

If you had run the same program in the previous post, with the simple continuous update test, you should have seen some color bleed through, which if you then switch to this new branch should hopefully have gone away. (fingers crossed)
 
I believe the fputs will output to file until it find null char. My guess is your \n is overwriting it and so fputs might continue to write more, repeating what was in buffer from previous writes
@KurtE - That took care of the problem. Another lesson learned. I understand string termination with '\0'. But I did not totally understand how fputs() works.
Commented out this line:
Code:
buf[E.row[j].size] = '\n';

I guess I cannot figure out why the code worked with the T36 and not the T4.
Anyway thanks for the help. You are the man :)
 
ILI9341_t3n: Now allow for multiple devices that can have frame buffers. And with the Asynch, that implies you can have more than one display being updated at the same time.

This is still in new branch mentioned a couple posts up, to fix dma buffer issues: https://github.com/KurtE/ILI9341_t3n/tree/T4_DMA_buffer

Note: while working on this and trying to setup multiple displays on different spi busses, I found out that I had not fully updated the SPIN library to have SPIN1 and SPIN2 objects on T4s... So now updated...

Now have a version of the multiple ST77xx display test using frame buffers converted back to ILI9341...

If anyone wishes to try it out,

View attachment ILI9341_t3n_multiple-190731a.zip

One I do a few quick tests, I will probably do a PR into my main branch soon.
 
NewPing Library

Just pushed my changes to the NewPing library to work with the T4 to GitHub: https://github.com/mjs513/NewPing_t4. As I mentioned I have the SRF-05 gong through a Adafruit level shifter to the T4 so it can operate at 5v without damaging the T4. Using a graph function I found for the ILI9341 was able to use @KurtE's ILI9341_t3n lib to plot the distance data as a function of degs. The servo is controlled with the PWMServo library.

20190731_190924.jpg

Can't show much more with showing the T4 so that's about it for now.
 
Hi all,

I'm curious about ADC library usage for T4. I see that pedvide's ADC library hasn't received T4 updates. My requirements are pretty basic (I hope): DC coupled, non-blocking if at all possible, high performance and averaging is not really needed. I'm using the audio library, so perhaps the best path forward is to hack up the ADC input from the audio library?

Or perhaps pedvide's lib will be updated sometime before T4 is available? Thanks for any ideas.
 
Status
Not open for further replies.
Back
Top