4

I'm trying to do the following: Storing a text file (7kB) in the flash memory of a STEVAL-MKI109V2 (running with freeRTOS) board and read this text file and doing some computation with it on the device itself. I have 2 problems regarding that:

1) Storing the text file Is it enough to just add the text file to my keil project? Can I access it after compiling?

2) Accessing the data That's where I failed until now. At first I tried using fopen() from stdio.h but I got some errors on compilation. I found out that my project compiles by using microLib which seems it doesn't include file I/O. After compiling with standard C - library it was successful but as soon as I reach the fopen part in my code the system crashes.

Now I don't know if the reason is that the text file is not found or if I cannot use fopen() on my embedded system. I didn't find further information inside the STM documents or forums except the FLASH_Unlock(); function but it seems it's used for writing.

Do I need to store my text file in another way and access by memory address instead of just filename? I'm confused and cannot find any information online.

Thanks in advance for any help!

Unfixable
  • 440
  • 1
  • 7
  • 20

2 Answers2

2

If you just want the contents of the file as a char-string, you can convert the file to C source code e.g. using a small Python program (or any other language, I just use Python for that as it is simple to do that in Python than in C or C++ for instance). Just create something like:

const char my_text[] = {

    ... here goes the text

};

Most simply, just embrace each line with ".

Then either add that file to the project (you'll require an extern declaration from where you use it) or #include it and make the declaration static (thanks @clifford).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • Thank you, that simple idea helped my problem :) – Unfixable Jun 03 '15 at 09:37
  • In my experience (though it may be specific to C++) in ARM RealView (the compiler used in Keil's ARM-MDK, which I assume is the toolchain in question since MicroLib was mentioned), `my_text[]` will be located in RAM with a const initialiser in ROM, thus wasting a significant amount of RAM. I have edited your answer to declare it `static` which has the effect of locating it in flash directly. I hope you do not object. – Clifford Jun 03 '15 at 19:21
  • @Clifford: Thank you, I forgot to mention `static`. However, I rolled back and edited the last sentence, as I actually describe both ways: external struct with global scope and #included (where I forgot the `static` actually). – too honest for this site Jun 03 '15 at 19:39
  • @Clifford: I would call a compiler handling const similar to `.data` broken at best. For the Cortex-M that would even add reliability issues, as protection the area would require at least another MPU region. Sure that was no bug in the linker script and startup code? For gcc, I can tell you it works. But there are some problems with compound literals assigne to `* const`. As I use special sections for the outer struct, I suspect a problem with this and did not follw that trace (I just us a seperate const struct instead of the literal and assign its address to the pointer in the second struct). – too honest for this site Jun 03 '15 at 19:44
  • ... Could it be the compiler tries to be "conservatice" with const, as many embedded developers tend to use it a bit - well - careless. I still know some thinking a string literal is read/write. Gcc is much less forgiving with such "flaws". And I like that. – too honest for this site Jun 03 '15 at 19:48
  • @Olaf : It depends where you declare the constant. In C and C++ const within a function may be assigned from parameters and in C++ const class members may be assigned by the constructor so must be in r/w memory. The use of `static` prevents that, so teh data can be locate in r/o; Outside of a function or class (file or namspace scope, it may make no difference - it is already implicitly `static`, but it is easier to habitually use `static` in case you change a variables scope. – Clifford Jun 04 '15 at 09:58
  • @Olaf : http://stackoverflow.com/questions/3709207/c-semantics-of-static-const-vs-const is relevant here. – Clifford Jun 04 '15 at 10:00
  • Making the declaration static in a header may create duplicate instances if included in multiple translation units without linker optimisations being applied. – Clifford Jun 04 '15 at 10:06
  • Okay I got some problems again and it's related to the available stack I think. So I got a header file with my array static const char foo[] = {"1,2,3" "4,5,6}; and so on. What is the difference between {"1,2,3" "4,5,6} and {"1,2,3", "4,5,6"}? I planned to access my array with strcpy(line, &foo[i]);, can I access my array like that? The problem is that my system falls into the stack overflow routine before crashing so I'm wondering: If I access one part of my array, is the whole array loaded on the stack? I constrained by 4kB stack size for my task so I need to access it line by line. – Unfixable Jun 05 '15 at 05:13
  • @Unfixable: That's why I only wrote to embrace in `"`, not add a comma. The first way the strings are concatenated by the compiler, the second would be for an array of `char *`, of course. If you want that, plan for the additional pointers and update your declaration of the array. I just answered your question, that will allow the same as a file does. If you want the text pre-processed, you have to think further yourselfs. That is part of your job after all. – too honest for this site Jun 05 '15 at 11:20
  • 1
    @Unfixable: After all, the array is just an array. As being const initialized to exactly the size of chars you stored, you can get its size. As the code is automatically generated, you can also create more complex structures, or add an index-array to the start of each line (the array of `char *` would serve the same purpose, but hinders if you want to transfer more lines at once - e.g. sending through a block-interface like Ethernet. Note that C does **not** add NUL to each string when concatenationg strings. YOu **first** have to make clear **what** you actually want to do, **then how**. – too honest for this site Jun 05 '15 at 11:34
  • Yes I didn't add the comma I just wondered about it. The problem is that it doesn't seem to act in the same way as a file system access does. If I access a file through fopen it seems that only as much data as the buffer size is allocated on the stack but if I access the array, it seems at the time of the access the whole array gets allocated which exceeds the stack size I can use for this specific task. I need to think about it more. Anyway, thanks for your input! – Unfixable Jun 07 '15 at 14:41
  • @Unfixable: that is a normal char array! Of course it has not the same semantic as a file. However,it does include tha same contents - if you did not leave out chars when creating the source code. Have you actually ever accessed any other array? Ok, first verify your toolchain really packs 'const' into Flash. The array itself does definitively not allocate memory on the stack (neither does the toolchain, even _if_ it would pack `const` vars into RAM, it would not pack it onto the stack. – too honest for this site Jun 07 '15 at 14:57
  • WAIT a second: Do you have the array definition inside a function and without the `static` before that?? That would explain why it is copied to the stack. This is plain wrong. Just have this array at file-level **and** use `static`. Please read about local vs. global variables and scope then. – too honest for this site Jun 07 '15 at 15:00
  • Okay to clarify I have my array in the format: static const char data[] = { "content"}; inside a header file which I include in the function that is accessing this array. I did experimentation and some short string works while a very long string like I have to use crashed the system that's what brought me to the assumption that the system is running out of memory. Okay, I will report back once I checked if its really stored into flash. Thanks for the advice! – Unfixable Jun 08 '15 at 00:46
  • Although `static const` should be safe in a function, you should better have it a file scope (mostly bad style to have `#include` in a function). You should open a new question about your function (that has nothing to do with the current question). There is apparently a problem with _that_. I'll look out (the `embedded` tag is not that busy) and answer if I can. – too honest for this site Jun 08 '15 at 00:57
  • Sorry for my bad explanation (English is not my first language). It's actually at file scope. I think I know how to resolve it now because I had some small bug in my code, it wasn't actually a memory problem. Now I only need to traverse the array and copy each line and getting the values inside the line using strtok. I will just add some special character to the end of each line when creating my data. Thanks for all the help, the remaining part I should be able to solve on my own. I will make a new question if I'm stuck again, like you said, it's getting unrelated to the original question :) – Unfixable Jun 08 '15 at 01:18
2

If you simply want to embed a resource in your application the implementing a filesystem would be overkill and you should use @Olaf's method.

If however you want data that you can program independently of your application; then you could simply reserve the necessary number of on-chip flash pages and either program those separately via JTAG or add support for loading and programming the flash pages to your application. Or for greater flexibility, you could add a file-system that uses a reserved number of flash pages - that would also require you to add to your application a means to download and write the data.

All flash pages on the STM32F1xx are of equal size, so it does not matter whether you use low or high memory pages, but using the upper pages is simpler because the reset vector where your code starts is in the low memory. To reserve the pages (prevent the compiler placing code in them), you simply reduce the default upper address in the project's memory map options (I am assuming you are using Keil ARM-MDK/uVision since you mentioned MicroLib).

The both Keil's MicroLib or the its full featured library have support for I/O streams, but because the I/O capability of the target cannot be known in advance it requires what is known as retargetting. At it's simplest this is often implemented only for stdout/stdin streams, but you can implement file descriptors for any I/O device - however to perform file I/O you need a file-systems such as ELM FatFs or Yaffs for which you will still need to implement the low-level drivers for accessing the flash. If you use a file-system library; you do not actually have to hook in stdio via retargetting; you can access the library directly - I mentioned retargetting because you seem to have a somewhat loose grasp of how a stdio works.

The details of flash programming on the STM32F1xx are in a separate manual from the main reference, while the STM32 standard peripheral library includes low-level functions to support programming. Here you will find a serious gotcha not made clear elsewhere in ST's documentation; when you program or erase flash, it locks-out the address and data bus to the entire flash memory - since that is normally where the processor is also fetching instructions from, the entire core stalls for the duration of the operation, which can be as much as 40ms (it is worse on STM32F2xx at 800ms!); consequently writing to a flash page may mess up time critical operations.

If you want to use a filesystem on such a device; you may be better off using an SPI port to communicate with an SD card, or otherwise using off-chip non-volatile memory.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Wow thank you for your thorough explanation. As somebody who only started working with embedded systems 3 weeks ago I appreciate any information like that! Still many things to learn. – Unfixable Jun 04 '15 at 01:26
  • 1
    @Unfixable : OK; the critial thing to remember is that flash memory is word programmable/page erasable; to *change* data you have to read-modify-erase-write an entire page. You obviously need to ensure that such pages are not used for code that may be executing. And dealing with the potential for power-failure during a write is a more complex issue. – Clifford Jun 04 '15 at 10:32
  • @Unfixable: Note that the sepearately erasable units are often called "sectors". Also, some Flash architectures further split each sector into "pages" as unit of programming. You'll have to read the reference manual and corrseponding app-notes. – too honest for this site Jun 05 '15 at 11:28