Does the Teensy 3.5 have 256K of RAM?

The existing information is confusing (to say the least), but I think the Teensy 3.5 actually has 256K of RAM, not 192K as is listed most places. Has anybody else looked at this? This seems really weird that nobody's noticed for this long, so I've done a fair amount of searching, and am listing what I turned up here. If it actually has 256K, only using 192K seems like a bug.

First, documentation saying 256K: A thread on the Freescale forums titled MK64FX512VLQ12 : Does it have 256KB of SRAM or 192KB of SRAM has what looks like an official Freescale response saying the version with 1M of flash has 256K. The datasheet (I'm looking at "Rev. 7, 10/2016") says it has 256K in many places, and doesn't mention 192 anywhere ctrl+F finds. The reference manual (I'm looking at "Rev. 3, July 2017") also says there's 256K in "3.5.3.1 SRAM sizes" and "2.3 Orderable part numbers". SIM_SOPT1.RAMSIZE does not have an option for 192K. "A.4 Chip Configuration chapter changes" mentions "Updated SRAM to 256 KB and SRAM_U to 192 in SRAM sizes".

Some documentation pointing to 192K: "3.5.3.1 SRAM sizes" lists a 192K-sized address range for some of the K64 chips, but not others. The previously-linked Freescale forum post implies there used to be a lot more places saying 192K (I don't see much point in trying to verify by digging up old revisions of the documentation). Also, every single piece of Teensy-related documentation I've found says the 3.5 has 192K of SRAM, and many of them contrast that with 256K in the 3.6. The mk64fx512.ld that comes with Teensyduino also uses LENGTH=192K for the RAM region.

Empirically, all 256K seem to work. I tested with this (after moving the stack out of the way in the linker script):
Code:
  printf("starting\n");
  volatile uint32_t *const test_pointer = (volatile uint32_t *)0x20000000;
  static constexpr size_t kRestOfSize = 0x30000 / sizeof(uint32_t);
  for (size_t i = 0; i < kRestOfSize; ++i) {
    test_pointer[i] = i % 293;
  }
  for (size_t i = 0; i < kRestOfSize; ++i) {
    if (test_pointer[i] != i % 293) {
      printf("compare fail\n");
      while (true) {}
    }
  }
  if (test_pointer[0] == test_pointer[kRestOfSize / 3]) {
    printf("prime didn't work\n");
    while (true) {}
  }
  if (test_pointer[kRestOfSize / 3] == test_pointer[kRestOfSize / 3 * 2]) {
    printf("prime didn't work\n");
    while (true) {}
  }
  if (test_pointer[0] == test_pointer[kRestOfSize / 3 * 2]) {
    printf("prime didn't work\n");
    while (true) {}
  }
  if (test_pointer[0] == test_pointer[kRestOfSize / 2]) {
    printf("prime didn't work\n");
    while (true) {}
  }
  printf("finished\n");

Even after all of that evidence for having 256K, I still have doubts about this. It just seems like too big of a thing for everybody else to have missed for this long. Did I miss something obvious here?
 
it may be possible its a mistake, or it may be possible part of that RAM is used by the system itself and not given to the user...
 
Interesting. I confirmed I could write/read above the stack on T3.5 with
Code:
void setup() {
  int i, errs = 0;
  Serial.begin(9600);
  while (!Serial);
  char *p = (char *) 0x20020004;
  Serial.print("stack variable address "); Serial.println((uint32_t)&i,HEX);
  Serial.println("set");
  for (i = 0; i < 60000; i++) p[i] = i;
  Serial.println("test");
  for (i = 0; i < 60000; i++) if (p[i] != i % 256) errs++;
  Serial.print("errs "); Serial.println(errs);
}

void loop() {}
I was able to access RAM above 192K with all three of my T3.5s.

I tried changing mk64fx512.ld to use
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K

but the teensy loader is not to be fooled and complains i compiled for the wrong architecture

EDIT: The ref manual 3.5.3.1 has a table indicating SRAM_L and SRAM_U, MK64FX512VMD12 has smaller address range, and there is a note about misaligned accesses across the boundary.
 
Last edited:
As a quick workaround, just delete the ELF file. Teensy Loader can’t tell how you compiled the code without the ELF file.
 
As a quick workaround, just delete the ELF file. Teensy Loader can’t tell how you compiled the code without the ELF file.

OK, i edited mk64fx512.ld and boards.txt (teensy35.upload.maximum_data_size=262144) and deleted the ELF and manually forced the upload, and the stack is now starting around 0x2002FF4C. So that seems to get 256K for the T3.5, but begs the question as to why you have configured the IDE to use only 192K for the T3.5??
 
I see a great PJRC marketing opportunity :eek:

PJRC announces 33% increase in Teensy 3.5 RAM with release of Teensyduino 1.42 ....
 
Last edited:
I registered to get in that and comment was 'Unauthorized This place or content does not exist or access to it is restricted. ...'

I did a search there and found this : https://community.nxp.com/message/804198?commentID=804198#comment-804198

Krithivasan Suryanarayanan
Jun 21, 2016 4:39 PM
...
I'm not sure how much memory you would need for a 10 sec low res video on an MCU but we have K64_120 MCU that you can consider with 256 KB RAM and 1024 KB flash for $5.45 (10K quanitity pricing).
 
Last edited:
Any thoughts on what part of the system might be using it?

Based on Paul's remark in post #6, I don't think the upper RAM is being used at all as a result of ambiguous documentation. The Teensyduino IDE will need to be updated to properly support 256K on the T3.5. Hacking the .ld file and boards.txt I have tested a number of sketches on a number of T3.5s, and all seem to run fine with 256K RAM. I used the command line loader to bypass the teensyloader checks.

teensy_loader_cli -mmcu=mk64fx512 -w tst.ino.hex

I ran a 250x250 float array Linpack benchmark which requires 250KBytes +, and it ran fine at 22.9 megaflops.
Code:
Sketch uses 19708 bytes (3%) of program storage space. Maximum is 524288 bytes.
Global variables use 259924 bytes (99%) of dynamic memory, leaving 2220 bytes for local variables. Maximum is 262144 bytes.

After hacking FastCRC lib to support buffers larger than 64KB (uint16_t to uint32_t), I ran FastCRC benchmark on 240KB buffer and got same CRC value on both T3.5 and T3.6.
 
Last edited:
Update from the NXP thread: the documentation has a confirmed error about the address range. The Teensy 3.5 definitely has 256K of RAM.

I'm happy to help with updating Teensyduino, but I don't have any experience working with it. I do all my development with a custom toolchain (it's the latest snapshot http://frc971.org/content/2017-software if anybody wants to take a look). The linker script is the only place I'd think to update, but it seems that boards.txt at least also needs to be updated, and I don't have any idea if there's anywhere else.

Based on Paul's remark in post #6, I don't think the upper RAM is being used at all as a result of ambiguous documentation.

SRAM_L is only 64K according to all the documentation I've seen. The question was whether SRAM_U is 128K or 192K. The linker script I grabbed from Teensyduino uses all of SRAM_L and 128K of SRAM_U as a single region.
 
I’ll probably leave 4 bytes unused. Teensy Loader currently looks at the stack symbol inside the ELF for the double check. Someday I’ll come up with a better way, but that’s not going to happen quickly. Right now all my dev cycles are going into the ports menu redesign. Still, this memory increase should be doable for the next beta, with that tiny caveat of 4 bytes unused so the existing code can still tell them apart based on the stack symbol.
 
Sounds good. Thanks for looking at this!

Have you considered using some other symbol than the one marking the end of the stack to identify the target? Seems to me like it has lots of advantages, although I could definitely be missing something. It avoids that 4-byte thing for starters. Also, `teensyduino_id = 35` vs `teensyduino_id = 36` seems like it should be accessible the same way you're currently getting the value of _estack. You could even keep _estack pointing at the current locations for each version and use a differently-named symbol for the actual stack to preserve binary compatibility for board identification if that's at all useful.
 
Have you considered using some other symbol than the one marking the end of the stack to identify the target? Seems to me like it has lots of advantages

Yup, that's definitely what I meant by "someday I’ll come up with a better way, but that’s not going to happen quickly".

Also, `teensyduino_id = 35` vs `teensyduino_id = 36` seems like it should be accessible the same way you're currently getting the value of _estack.

Please feel free to pursue this, both how you'd reliably get it into the ELF file, and how you'd parse it...
 
FYI: when someday comes - Koromix parses the 'compiled for' Teensy from the HEX file during his sanity checks for valid HEX.
 
Please feel free to pursue this, both how you'd reliably get it into the ELF file, and how you'd parse it...

maybe conditionally (based on __MK... symbols) create a location/symbol for the ELF (like is done for __rtc_localtime) __MCU_T35

or a special RAM section name in the .ld file, e.g.
Code:
    .mcut35 (NOLOAD) : {
        . = ALIGN(4);
        *(.mcut35*)
    } > RAM

i'm not sure how easy those are to parse/find. The section names are C strings all together in a "section name string table" (the index of the table itself is defined in the ELF header by the field e_shstrndx). ref https://wiki.osdev.org/ELF_Tutorial

Code:
 296048: 73720075  73625f6d  616c6c6f  63006932    |sr?usb_malloc?i2|
 296064: 73305f69  7372005f  65737461  636b0065    |s0_isr?_estack?e|
 296080: 6e65745f  74696d65  725f6973  72005f65    |net_timer_isr?_e|
...
 406272: 63726970  746f7274  61626c65  002e646d    |criptortable?.dm|
 406288: 61627566  66657273  002e7573  62627566    |abuffers?.usbbuf|
 406304: 66657273  002e6d63  75743335  002e6461    |fers?.mcut35?.da|
 406320: 7461002e  62737300  2e41524d  2e617474    |ta?.bss?.ARM.att|
_estack is in that table, too. so maybe in mk64fx512.ld just _mcut35 = 1; In T3.6 .ld you'd have _mcut36 = 1;

Code:
 405520: 7472696e  675f7072  6f647563  745f6e61    |tring_product_na|
 405536: 6d65005f  6d637574  33350064  656c6179    |me?_mcut35?delay|
 405552: 0074706d  305f6973  72006932  73305f72    |?tpm0_isr?i2s0_r|

Rather than searching through the C string table, it may be faster to walk the section headers looking for 0 size sections then checking the name (C string) for that section, though we're only dealing with milliseconds ...
Code:
readelf -S *elf
There are 22 section headers, starting at offset 0x633b8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 010000 001e44 00  AX  0   0  4
  [ 2] .fini             PROGBITS        00001e44 011e44 000004 00  AX  0   0  4
  [ 3] .usbdescriptortab NOBITS          1fff0000 030000 0000a0 00  WA  0   0  4
  [ 4] .dmabuffers       NOBITS          1fff0200 030000 000198 00  WA  0   0 512
  [ 5] .usbbuffers       NOBITS          1fff0398 030000 000360 00  WA  0   0  4
  [ 6] .mcut35           PROGBITS        1fff06f8 020bd0 000000 00   W  0   0  1
  [ 7] .data             PROGBITS        1fff06f8 0206f8 0004d8 00  WA  0   0  8

Or as bsilver8192 suggested just an assignment in the .ld files _TeensyMCU = 35; and then the teensyloader could search the elf symbol table for name and value
Code:
readelf -s *elf | grep yMCU
   580: 00000023     0 NOTYPE  GLOBAL DEFAULT  ABS _TeensyMCU

For older HEX files, if the symbol was not found, the MCU identification would have to fall back to RAM size.
 
Last edited:
I'm willing to take a look at this. Where's the source for teensy_post_compile? That seems to be the thing which needs to learn how to parse this, and I can't figure out which project it's in.
 
I've put this change into the core library, boards file and Teensy Loader. It will appear in 1.42-beta4, likely next week.
 
Great - Looks like I will need to try out my ili9341_t3n library with frame buffer support on it :D Hopefully it will just work, but I do know that the DMA stuff can work differently!
 
I've put this change into the core library, boards file and Teensy Loader. It will appear in 1.42-beta4, likely next week.

Found this again and see I mismarked my 'calendar' - thought it was imminent ... not 'likely next week' ... been waiting to see beta4 to divert back to 4 Teensy's on my computer. Though 30 MHz SPI_MSTransfer test has T_3.6 Master still blinking the T_3.1 slave LED 10x/sec and sending over 500 '96 byte' messages each second for last 3 days - 130 M messages? One required resend.

KurtE: will be nice if the T_3.5 RAM extension allows it to usably DMA/Buffer the ILI9341.
 
I was able to access RAM above 192K with all three of my T3.5s.

I tried changing mk64fx512.ld to use
RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K

but the teensy loader is not to be fooled and complains i compiled for the wrong architecture
 
OK, Teensyduino 1.42 Beta #4 enables all 256KB of T3.5 RAM!! :D
I re-ran tests (see earlier posts) successfully. Linpack with 250x250 arrays used 259924 bytes (99%) of dynamic memory, leaving 2216 bytes for local variables. Maximum is 262140 bytes. And FastCRC benchmark with 240KB buffer works and uses 250660 bytes of RAM.

secret encoding: 256K is 262144 bytes, so 262140 is used by loader to distinguish between T3.5 and T3.6
 
Last edited:
Back
Top