Section type conflict and other memory error

Lesept

Well-known member
Hi
I have a Teensy 4.1 with 8MB PSRAM and 256 MB Flash.
I have a large code that uses large arrays declared in .h files. I try to manage the storage between RAM1 & 2, PSRAM and Flash, depending on their size.

For example, the file classifier_2_weight.h contains:
Code:
#include <stdint.h>
PROGMEM const float classifier_2_weight_output_0[128000] =
    {
        -0.0524069182574749, -0.03734472393989563, -0.04629778116941452, -0.0400727204978466, -0.02280816249549389,
        -0.02316550724208355, 0.002435319824144244, 0.0019113686867058277, -0.015797318890690804, -0.04310063645243645,
        -0.011440770700573921, 0.03244912996888161, -0.008675714023411274, -0.022800328209996223, -0.010684050619602203,
...
};

I use this array in a function called model_forward, in a forward.cpp file, which declares and includes some arrays as well:
Code:
// Memory block
#include "..\include\parameters\onnx__Conv_95.h"
#include "..\include\parameters\onnx__Conv_98.h"
#include "..\include\parameters\onnx__Conv_101.h"
#include "..\include\parameters\onnx__Conv_104.h"
#include "..\include\parameters\onnx__Conv_107.h"
#include "..\include\parameters\onnx__Conv_110.h"
#include "..\include\parameters\onnx__Conv_113.h"
#include "..\include\parameters\classifier_2_weight.h" // <--- Here
EXTMEM float input[131072];
DMAMEM float input2[32768];
EXTMEM float output[131072];
DMAMEM float weightsRAM2[73728];
EXTMEM float weightsPSRAM[921600];
PROGMEM float weightsFlash[921600];

When I compile the code I get this error message:
Code:
In file included from C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:54:
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\include\parameters\classifier_2_weight.h: In function 'void model_forward(float**)':
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\include\parameters\classifier_2_weight.h:3:21: error: 'classifier_2_weight_output_0' causes a section type conflict with 'weightsFlash'
    3 | PROGMEM const float classifier_2_weight_output_0[128000] =
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:60:15: note: 'weightsFlash' was declared here
   60 | PROGMEM float weightsFlash[921600];
      |               ^~~~~~~~~~~~

exit status 1
Compilation error: 'classifier_2_weight_output_0' causes a section type conflict with 'weightsFlash'

These 2 arrays seem to have coliving problems. They interact here:
Code:
memcpy(weightsFlash, classifier_2_weight_output_0, 512000);

If I remove the PROGMEM statement in the .H file, keeping only:
Code:
#include <stdint.h>
const float classifier_2_weight_output_0[128000] =
then the compilation continues and I get another error:
Code:
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\fa125436\AppData\Local\arduino\sketches\EE9AC2D007C02D446B7F6F7B98C17DC1/Aidge_Teensy_ResNet.ino.elf section `.data' will not fit in region `DTCM'
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\fa125436\AppData\Local\arduino\sketches\EE9AC2D007C02D446B7F6F7B98C17DC1/Aidge_Teensy_ResNet.ino.elf section `.data' will not fit in region `FLASH'
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: address 0x20cf3de0 of C:\Users\fa125436\AppData\Local\arduino\sketches\EE9AC2D007C02D446B7F6F7B98C17DC1/Aidge_Teensy_ResNet.ino.elf section `.bss' is not within region `DTCM'
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: address 0x20cf3de0 of C:\Users\fa125436\AppData\Local\arduino\sketches\EE9AC2D007C02D446B7F6F7B98C17DC1/Aidge_Teensy_ResNet.ino.elf section `.bss' is not within region `DTCM'
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: section .bss.dma VMA [20200000,2026b07f] overlaps section .data VMA [20000000,20cf1ebf]
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: region `DTCM' overflowed by 13057504 bytes
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: region `FLASH' overflowed by 9455616 bytes
collect2.exe: error: ld returned 1 exit status

exit status 1
Compilation error: exit status 1
This is more complex to understand.
I have read somewhere that if I don't declare arrays as PROGMEM, they are first stored in RAM1 then put in Flash. But if their size is larger than the RAM1 size, maybe this results in section `.bss' is not within region `DTCM' ?

Can anyone explain these error messages and help me fix them?
Thanks for your help.
 
PROGMEM float weightsFlash[921600];

You need const when using PROGMEM.

If your weightsFlash[] array is actually initialized by a different .cpp or .ino file, but you want to give access to it without creating a duplicate (and conflicting) copy, use "extern const float weightsFlash[921600];" (without PROGMEM). But it must be created somewhere, and in that place it must have PROGMEM and const.
 
Thanks Paul.
You need const when using PROGMEM.
Should I do the same for EXTMEM and DMAMEM?

Code:
EXTMEM const float input[131072];
DMAMEM const float input2[32768];
EXTMEM const float output[131072];
DMAMEM const float weightsRAM2[73728];
EXTMEM const float weightsPSRAM[921600];
PROGMEM const float weightsFlash[921600];

When I do this, I get a warning, such as:
Code:
In file included from c:\users\fa125436\appdata\local\arduino15\packages\teensy\tools\teensy-compile\11.3.1\arm\arm-none-eabi\include\c++\11.3.1\cstring:42,
                 from C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:1:
c:\users\fa125436\appdata\local\arduino15\packages\teensy\tools\teensy-compile\11.3.1\arm\arm-none-eabi\include\string.h:31:18: note:   initializing argument 1 of 'void* memcpy(void*, const void*, size_t)'
   31 | void *   memcpy (void *__restrict, const void *__restrict, size_t);
      |                  ^~~~~~
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:123:24: warning: invalid conversion from 'const void*' to 'void*' [-fpermissive]
  123 |                 memcpy(weightsRAM2, onnx__Conv_95_output_0, 294912);
      |                        ^~~~~~~~~~~
      |                        |
      |                        const void*
 
Actually, input and output cannot be const as they are changed during the execution.
I changed my code like this:
Code:
// Memory block
#include "..\include\parameters\onnx__Conv_95.h"
#include "..\include\parameters\onnx__Conv_98.h"
#include "..\include\parameters\onnx__Conv_101.h"
#include "..\include\parameters\onnx__Conv_104.h"
#include "..\include\parameters\onnx__Conv_107.h"
#include "..\include\parameters\onnx__Conv_110.h"
#include "..\include\parameters\onnx__Conv_113.h"
#include "..\include\parameters\classifier_2_weight.h"
#include "..\..\inputs.h"
EXTMEM float input[131072];               // PSRAM
DMAMEM const float input2[32768];         // RAM2
EXTMEM float output[131072];              // PSRAM
DMAMEM const float weightsRAM2[73728];    // RAM2
EXTMEM const float weightsPSRAM[921600];  // PSRAM
PROGMEM const float weightsFlash[921600]; // Flash
FASTRUN void model_forward(float **net_output)
{
    /*
    Input  stored in PSRAM
    Output stored in PSRAM
    */
    memcpy(input, inputs, 12288);
...
with the inputs.h file as follows:
Code:
#include <stdint.h>
PROGMEM const float inputs[3072] =
    {
        1.4285330772399902,
        2.087620258331299,
...
};

But I still get an error message:
Code:
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:60:20: error: 'weightsPSRAM' causes a section type conflict with 'input'
   60 | EXTMEM const float weightsPSRAM[921600];  // PSRAM
      |                    ^~~~~~~~~~~~
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:56:14: note: 'input' was declared here
   56 | EXTMEM float input[131072];                               // PSRAM
      |              ^~~~~

What is wrong?

Edit: maybe the sum of the arrays does not fit into my PSRAM...?
 
Last edited:
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:60:20: error: 'weightsPSRAM' causes a section type conflict with 'input' 60 | EXTMEM const float weightsPSRAM[921600]; // PSRAM | ^~~~~~~~~~~~
EXTMEM won't work with const? It is not initialized and that is the area to be written from FLASH after startup correct?
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_ResNet\src\dnn\src\forward.cpp:56:14: note: 'input' was declared here 56 | EXTMEM float input[131072]; // PSRAM
This may be a problem that 'input' is a name conflict defined elsewhere? try :: inputPSRAM or other
 
I did my best to reduce the size and complexity of the code while keeping the error. You can find a smaller program here.
Please tell me if you can donwload it and if it gives the same error I get:
Code:
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_test\src\dnn\src\forward.cpp:14:14: error: 'input' causes a section type conflict with 'weightsFlash'
   14 | EXTMEM float input[131072];                        // PSRAM
      |              ^~~~~
C:\Users\fa125436\Documents\Arduino\Aidge_Teensy_test\src\dnn\src\forward.cpp:19:20: note: 'weightsFlash' was declared here
   19 | EXTMEM const float weightsFlash[921600]; // PSRAM
      |                    ^~~~~~~~~~~~


exit status 1


Compilation error: 'input' causes a section type conflict with 'weightsFlash'

One additionnal information: if I comment out line 104 of the file convolution.hpp, I do not get the error.
 
Looked at your code. Took some time because you have many Windows-only style pathnames. Please use forward slash, so we non-Windows users can help you without this time-consuming step!

The fix for your problem is exactly as Defragster said. Just delete the "const" from the arrays in EXTMEM and DMAMEM.

In forward.cpp, change this:

Code:
#include "../include/parameters/onnx__Conv_101.h"
EXTMEM float input[131072];                        // PSRAM
DMAMEM const float input2[32768];          // RAM2
EXTMEM float output[131072];               // PSRAM
DMAMEM const float weightsRAM2[73728]; // RAM2
// EXTMEM const float weightsPSRAM[921600];  // PSRAM
EXTMEM const float weightsFlash[921600]; // PSRAM

to this:

Code:
#include "../include/parameters/onnx__Conv_101.h"
EXTMEM float input[131072];                        // PSRAM
DMAMEM float input2[32768];        // RAM2
EXTMEM float output[131072];               // PSRAM
DMAMEM float weightsRAM2[73728]; // RAM2
// EXTMEM const float weightsPSRAM[921600];  // PSRAM
EXTMEM float weightsFlash[921600]; // PSRAM
 
Sorry about that, and thanks for your help. It fixes the problem indeed, but there is still another error message:

Code:
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\fa125436\AppData\Local\arduino\sketches\EE9AC2D007C02D446B7F6F7B98C17DC1/Aidge_Teensy_ResNet.ino.elf section `.text.progmem' will not fit in region `FLASH'
c:/users/fa125436/appdata/local/arduino15/packages/teensy/tools/teensy-compile/11.3.1/arm/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: region `FLASH' overflowed by 5769216 bytes
collect2.exe: error: ld returned 1 exit status

exit status 1
Compilation error: exit status 1

My board has 256MB Flash, how is it supposed to be overflowed? Should I declare this size somewhere?
Of course, this is with the entire program, not the smaller one I provided earlier.
 
Yes, but I bought it at Protosupplies:

DEV-26-2G (8MB PSRAM/256MB Flash) has an 8MB (64M-bit) volatile PSRAM installed along with a 256MB (2G-bit) non-volatile NAND Flash memory as shown below for those that need an even larger amount of non-volatile storage such as for data logging, image files or audio files. The NAND Flash is the 8-pad WSON 8x6mm package.

The Flash chip will be a Winbond W25N02KVZEIR. The PSRAM will be the AP 6404L-3SQR or equivalent.

Edit:
After double thinking about what you said, I went back to the prosupplies site and read this:

Optional Flash Memory​

The optional Flash memory is also QSPI like the Teensy 4.1 built-in Flash with similar performance. Both smaller NOR and larger NAND Flash chips are supported in sizes as large as 256MB/2Gb using the built-in LittleFS library.

The main thing to know about the optional Flash memory is that it cannot be used to simply increase the built-in 8MB program space. While the optional Flash memory cannot be used to directly increase program space on the Teensy 4.1, it can sometimes be used to stretch the program space by off-loading large data structures and the like from program space and putting it into the optional Flash chip.

If I understand well, I have to use LittleFS to address this memory. That's not what I was expecting at the beginning, so I need further reading...
 
Last edited:
That OPTIONAL FLASH is on QSPI underside for ADDED storage of 256MB. Available for use with LittleFS.

The PJRC installed Primary Boot FLASH "PROGMEM" storage is a fixed 8MB on the T_4.1.
 
Last edited:
That OPTIONAL FLASH is on QSPI underside for ADDED storage of 256MB. Available for use with LittleFS.
Sorry, I don't understand. Does it mean I have 8 or 16MB PSRAM?
This piece of code:
Code:
// Check for PSRAM chip(s) installed
  uint8_t size = external_psram_size;
  Serial.printf("PSRAM Memory Size = %d Mbyte\n", size);
prints 8 MB.
 
You have 8MB PSRAM and 256MB of NAND Flash that have been added to the bottom of the Teensy which sit on a QSPI bus. To have 16MB PSRAM, a 2nd 8MB PSRAM chip would be installed instead of the 256MB Flash chip. The Teensy 4.1 by itself does not have any PSRAM.

The main Teensy 4.1 Flash used for program memory is fixed at 8MB and is a separate small part that sits on the top side of the Teensy on a different QSPI bus.

As you have discovered, the 256MB Flash that has been added cannot be used as additional program space. It must be accessed via the LittleFS library. The usage of it basically parallels that of using something like an SD card.
 
Hi
I am now trying to use the LittleFS library, to copy very large arrays to the NAND Flash memory.
My understanding is that I create a "file" in the NAND Flash and write the array in it. I wrote a small test code but I can't read the float values I put in this file.
What is wrong?

Here is the code:
Code:
/*
  Test LittleFS write, read
 */
#include <LittleFS.h>
LittleFS_QPINAND myfs;  //Specifies to use an QSPI NAND Flash attached to SPI
#include "onnx__Conv_110.h"

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    // wait for serial port to connect.
  }
  Serial.print("Initializing SPI FLASH...");
  // see if the Flash is present and can be initialized:
  if (!myfs.begin()) {
    Serial.printf("Error starting %s\n", "SPI FLASH");
    while (1)
      ;
  }
  Serial.printf("NAND Flash Memory Size =  %d bytes / ", myfs.totalSize());
  Serial.printf("%d Mbyte / ", myfs.totalSize() / 1048576);
  Serial.printf("%d Gbit\n", myfs.totalSize() * 8 / 1000000000);
  Serial.println("Flash initialized.");
 
 int N = 10;  // 921600
  // open the file.
  File dataFile = myfs.open("onnx__Conv_110.h", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    for (uint16_t j = 0; j < N; j++) {
      dataFile.println(onnx__Conv_110_output_0[j]);
      Serial.printf("i = %d data = %f\n", j, onnx__Conv_110_output_0[j]);
    }
    dataFile.close();
  } else {
    // if the file isn't open, pop up an error:
    Serial.println("error opening onnx__Conv_110.h");
  }
  delay(100);  // run at a reasonable not-too-fast speed
  Serial.println("Data written, now reading...");

  File file2 = myfs.open("onnx__Conv_110.h", FILE_READ);
  if (file2) {
    float data[N] = { 0 };
    int index = 0;
    while (file2.available() && (index < N)) {
      float x = file2.parseFloat(SKIP_ALL);
      Serial.printf("i = %d data = %f\n", index, x);
      data[index++] = x;
    }
    file2.close();
  }
}
void loop() {
  //
}
and the output:
Code:
Initializing SPI FLASH...NAND Flash Memory Size =  265289728 bytes / 253 Mbyte / 2 Gbit
Flash initialized.
i = 0 data = 0.029072
i = 1 data = -0.010079
i = 2 data = -0.014119
i = 3 data = 0.010565
i = 4 data = -0.005434
i = 5 data = -0.001253
i = 6 data = 0.036922
i = 7 data = 0.043040
i = 8 data = -0.020667
i = 9 data = -0.053442
Data written, now reading...
i = 0 data = 0.000000
i = 1 data = 0.000000
i = 2 data = 0.000000
i = 3 data = 0.000000
i = 4 data = 0.000000
i = 5 data = 0.000000
i = 6 data = 0.000000
i = 7 data = 0.000000
i = 8 data = 0.000000
i = 9 data = 0.000000
The values in the first part (0.029072, -0.010079, etc) are correct, but obviously I can't read them again from the file.

I would prefer to write 4 bytes for each float number in my array, then read again 4 bytes and convert them to float. I think this would be faster.
 
@joepasquariello is correct but besides that the sketch does not compile as shown.

However with that said I modified the sketch and saw the same thing as you. Issue is probably with parseFloat, never had luck with that. With that said I played around a bit and used atof after reading in data as a string:

Code:
Initializing SPI FLASH...QSPI flash begin
NAND Flash Memory Size =  16777216 bytes / 16 Mbyte / 0 Gbit
Flash initialized.
i = 0 data = 1.000000
i = 1 data = 1.100000
i = 2 data = 1.200000
i = 3 data = 1.300000
i = 4 data = 1.400000
i = 5 data = 1.500000
i = 6 data = 1.600000
i = 7 data = 1.700000
i = 8 data = 1.800000
i = 9 data = 1.900000
Data written, now reading...


Dumping Log!!!
1.00
1.10
1.20
1.30
1.40
1.50
1.60
1.70
1.80

here is the sketch that I used:
C++:
/*
  Test LittleFS write, read
 */
#include <LittleFS.h>
LittleFS_QSPI myfs;  //Specifies to use an QSPI NAND Flash attached to SPI
float onnx__Conv_110_output_0[10] = {1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9};
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    // wait for serial port to connect.
  }
  Serial.print("Initializing SPI FLASH...");
  // see if the Flash is present and can be initialized:
  if (!myfs.begin()) {
    Serial.printf("Error starting %s\n", "SPI FLASH");
    while (1)
      ;
  }
  Serial.printf("NAND Flash Memory Size =  %d bytes / ", myfs.totalSize());
  Serial.printf("%d Mbyte / ", myfs.totalSize() / 1048576);
  Serial.printf("%d Gbit\n", myfs.totalSize() * 8 / 1000000000);
  Serial.println("Flash initialized.");
  myfs.remove("onnx__Conv_110.h");
 
 int N = 10;  // 921600
  // open the file.
  File dataFile = myfs.open("onnx__Conv_110.h", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    for (uint16_t j = 0; j < N; j++) {
      dataFile.println(onnx__Conv_110_output_0[j]);
      Serial.printf("i = %d data = %f\n", j, onnx__Conv_110_output_0[j]);
    }
    dataFile.close();
  } else {
    // if the file isn't open, pop up an error:
    Serial.println("error opening onnx__Conv_110.h");
  }
  delay(100);  // run at a reasonable not-too-fast speed
  Serial.println("Data written, now reading...");
  dataFile.close();
/*
  File file2 = myfs.open("onnx__Conv_110.h", FILE_READ);
  if (file2) {
    float data[N] = { 0 };
    int index = 0;
    while (file2.available() && index < N) {
      float x = file2.parseFloat();
      Serial.printf("i = %d data = %f\n", index, x);
      data[index++] = x;
    }
    file2.close();
  }
*/
  File file2 = myfs.open("onnx__Conv_110.h", FILE_READ);
  Serial.println("\nDumping Log!!!");
  // open the file.
  char fileContents[40]; // Probably can be smaller
  uint8_t index2 = 0;
  float data[20];
  N = 0;
  if (file2) {
    while (file2.available()) {
      fileContents[index2++] = file2.read();
      fileContents[index2] = '\0'; // NULL terminate the array
      if(fileContents[index2-1] == '\r'){
        //Serial.println(atof(fileContents));
        data[N] = atof(fileContents);
        N += 1;
        index2 = 0;
      }
    }
    file2.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening file");
  }
  for(uint8_t i = 0; i < (N-1); i++)
      Serial.println(data);
}
void loop() {
  //
}


cheers.
 
Thanks to both of you for your answers.
@mjs513 : I'll try this when I'm back at work.

However, it seems to me that reading a float number as an list of ascii values then transforming it to float (if I understand well atof) is a waste of time and computing power. But if there is no other solution...
 
I tried the code, and it works. I have changed it a bit:
Code:
/*
  Test LittleFS write, read
 */
#include <LittleFS.h>
LittleFS_QPINAND myfs;  //Specifies to use an QSPI NAND Flash attached to SPI
// const int chipSelect = 4;
#include "onnx__Conv_110.h"
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    // wait for serial port to connect.
  }
  Serial.print("Initializing SPI FLASH...");
  // see if the Flash is present and can be initialized:
  if (!myfs.begin()) {
    Serial.printf("Error starting %s\n", "SPI FLASH");
    while (1)
      ;
  }
  Serial.printf("NAND Flash Memory Size =  %d bytes / ", myfs.totalSize());
  Serial.printf("%d Mbyte / ", myfs.totalSize() / 1048576);
  Serial.printf("%d Gbit\n", myfs.totalSize() * 8 / 1000000000);
  Serial.println("Flash initialized.");
  int N = 100000;  // 921600
  myfs.remove("onnx__Conv_110.h");
  Serial.println("File erased in Flash");
  Serial.printf("There are %d data\n", N);
  elapsedMicros chrono = 0;
  File dataFile = myfs.open("onnx__Conv_110.h", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    for (int j = 0; j < N; j++) {
      dataFile.println(onnx__Conv_110_output_0[j], 8);
      // Serial.printf("i = %d data = %f\n", j, onnx__Conv_110_output_0[j]);
    }
    dataFile.close();
    Serial.printf("Execution time: %.3f ms\n", (float)chrono / 1000.0);
  } else Serial.println("error opening onnx__Conv_110.h");

  Serial.println("Now reading data...");
  chrono = 0;
  File file2 = myfs.open("onnx__Conv_110.h", FILE_READ);
  // open the file.
  char fileContents[15];  // 8 digits after .
  uint8_t index2 = 0;
  float data[N] = { 0 };
  int i = 0;
  if (file2) {
    while (file2.available()) {
      fileContents[index2++] = file2.read();
      fileContents[index2] = '\0';  // NULL terminate the array
      if (fileContents[index2 - 1] == '\r') {
        data[i++] = atof(fileContents);
        index2 = 0;
      }
    }
    file2.close();
    Serial.printf("Execution time: %.3f ms\n", (float)chrono / 1000.0);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening file");
  }
  // for (int i = 0; i < N; i++)
  //   Serial.printf("i = %d data = %f\n", i, data[i]);
}
void loop() {
  // nope
}
I have commented out the lines that print the values because I verified for N=10 that they are correct.
Now, I'm trying to increase the number of data, because it may reach 1 million...

First test: 10 000 float data:
Code:
Initializing SPI FLASH...NAND Flash Memory Size =  265289728 bytes / 253 Mbyte / 2 Gbit
Flash initialized.
File erased in Flash
There are 10000 data
Execution time: 82.270 ms
Now reading data...
Execution time: 61.637 ms
82 ms to write the array, 62 ms to read it back.

When I increase the number to 100 000, the code stops at:
Code:
Initializing SPI FLASH...NAND Flash Memory Size =  265289728 bytes / 253 Mbyte / 2 Gbit
Flash initialized.
File erased in Flash
There are 100000 data
probably because the RAM is saturated. I need to declare the array in PSRAM (DMAMEM).

EDIT: actually no. I needed an int variable (not uint16_t or uint8_t) as array index.

I feel that if I want to process 1 million floating point values or more, I need to divide the array in several smaller arrays, each in a .h file, that I will read in sequence and transfer to the QSPI Flash one after the other.
 
Last edited:
Now I have a new problem, I really don't understand what is going on...
Here is the code:
Code:
/*
  Test LittleFS write, read
 */
#include <LittleFS.h>
LittleFS_QPINAND myfs;  //Specifies to use an QSPI NAND Flash attached to SPI
#include "onnx__Conv_110.h"
const int N = 82;  // 921600
DMAMEM float data[N] = { 0 };
float last = 0;
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    // wait for serial port to connect.
  }
  Serial.print("Initializing SPI FLASH...");
  // see if the Flash is present and can be initialized:
  if (!myfs.begin()) {
    Serial.printf("Error starting %s\n", "SPI FLASH");
    while (1)
      ;
  }
  Serial.printf("NAND Flash Memory Size =  %d bytes / ", myfs.totalSize());
  Serial.printf("%d Mbyte / ", myfs.totalSize() / 1048576);
  Serial.printf("%d Gbit\n", myfs.totalSize() * 8 / 1000000000);
  Serial.println("Flash initialized.");
  myfs.remove("onnx__Conv_110.h");
  Serial.println("File erased in Flash");
  Serial.printf("There are %d data\n", N);
  elapsedMicros chrono = 0;
  File dataFile = myfs.open("onnx__Conv_110.h", FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    for (int j = 0; j < N; j++) {
      dataFile.println(onnx__Conv_110_output_0[j], 8);
      // Serial.printf("i = %d data = %f\n", j, onnx__Conv_110_output_0[j]);
    }
    dataFile.close();
    last = onnx__Conv_110_output_0[N - 1];
    Serial.printf("Execution time: %.3f ms\n", (float)chrono / 1000.0);
  } else Serial.println("error opening onnx__Conv_110.h");

  Serial.println("Now reading data...");
  chrono = 0;
  File file2 = myfs.open("onnx__Conv_110.h", FILE_READ);
  char buffer[15];  // 8 digits after .
  int index = 0;
  int i = 0;
  if (file2) {
    while (file2.available()) {
      buffer[index++] = file2.read();
      // Serial.printf("index= %d, buf= %c\n", index - 1, buffer[index - 1]);
      if (buffer[index - 1] == '\r') {
        buffer[index - 1] = '\0';  // NULL terminate the array
        data[i++] = atof(buffer);
        index = 0;
        file2.read();
        if (i % 10 == 0) Serial.println(i);
        // Serial.printf("i= %d data= %f\n", i - 1, data[i - 1]);
      }
    }
    file2.close();
    Serial.printf("Execution time: %.3f ms\n", (float)chrono / 1000.0);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening file");
  }
  // for (int i = 0; i < N; i++)
  //   Serial.printf("i = %d data = %f\n", i, data[i]);
  Serial.printf("Checking...\nLast data written: %f\n", last);
  Serial.printf("Last data read   : %f\n", data[N - 1]);
}
void loop() {
  // put your main code here, to run repeatedly:
}

If at line 8, I set N=81, I get this output:
Code:
Initializing SPI FLASH...NAND Flash Memory Size =  265289728 bytes / 253 Mbyte / 2 Gbit
Flash initialized.
File erased in Flash
There are 81 data
Execution time: 18.609 ms
Now reading data...
10
20
30
40
50
60
70
80
Execution time: 9.815 ms
Checking...
Last data written: 0.010245
Last data read   : 0.010245

Everything works as expected. But if I set N=82, here is the output:
Code:
Initializing SPI FLASH...NAND Flash Memory Size =  265289728 bytes / 253 Mbyte / 2 Gbit
Flash initialized.
File erased in Flash
There are 82 data
Execution time: 7465.198 ms
Now reading data...
Execution time: 10.384 ms
Checking...
Last data written: 0.026714
Last data read   : 0.000000

Now it takes 7 seconds to write 82 values in the file, and nothing is read anymore.
I'm litterally tearing my hair out trying to figure out what's going on...
 
It seems that the problem comes from
Code:
dataFile.close();
when writing the file. This instruction alone takes almost 7 seconds.

I don't think I ever wrote 256 MB in the Flash memory, to saturate it somehow. But it's as if the multiple tests I did have caused a memory problem. The code of message 20 with 10 000 data doesn't work anymore.
 
it's as if the multiple tests I did have caused a memory problem.

Have you tried running the example datalogger program for the LittleFS library? I ask this again because it seems like it does more or less what you want, and if you read the code you might get a better understanding of how LittleFS works and how to use it. In particular, it shows how to erase files. Your code calls the remove() function, then prints "File erased in flash", and I'm pretty sure that remove() simply updates the directory. If you have been running the test program over and over, you may now have a large directory structure that needs to be traversed to do something like close a file. I don't know, but you may also have used up lots of the available flash space. The example shows how to erase files and restore the file system to its original state via the format functions.
 
I haven't looked at the code here or the LittleFS code for a long time.
That LittleFS code is more concerned with data integrity than speed - especially on FLASH. It will run as it does leaving a trail of abandoned dirty flash blocks behind it and only format them as needed. FLASH format can take painfully long. Looking at the Test_Integrity - it seems PROGmem is in use? "...\hardware\teensy\avr\libraries\LittleFS\examples\Test_Integrity\PROG\PROG.ino"
You will see a TRIM like feature that can pre format all unused blocks.
:: 'f' LittleFS::formatUnused( ALL ) : DATA PRESERVED, empty blocks preformatted
Doing this on startup might show a difference? : myfs.formatUnused( 0, 0 );

But any .close() will update the dir entry and commit the needed blocks. Any change to that might cause a duplication of the data to new blocks in some fashion leaving many dirty blocks behind and using new blocks for the data and creating directory entry updates on yet more blocks.
 
Back
Top