This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430 optimize RAM usage

Other Parts Discussed in Thread: MSP430F449

Hi.

I'm having trouble developing an application for the MSP430F449. My device has 60 kB of Flash memory and 2kB of RAM and apparently it's not enough for my application or at least in the way I'm doing it.

I'm using IAR embedded workbench and at the end of the *.map file I have this:

17 136 bytes of CODE memory
700 bytes of DATA memory (+ 84 absolute )
1 816 bytes of CONST memory

I'm still a little clueless as to which of these parameters represents the RAM usage, even after reading through the forums. If you would provide me with a quick explanation I'd really appreciate it.
Up to  this point the application runs just fine, but when I introduce the chunk of code that implements the complex calculations my system must do, it pops up the following error:

Error[e16]: Segment INFO (size: 0x112 align: 0x1) is too long for segment definition. At least 0x12 more bytes needed. The problem occurred while processing the segment placement command "-Z(CONST)INFO=1000-10FF", where at the moment of placement the available memory ranges were "CODE:1000-10ff"
Reserved ranges relevant to this placement:
1000-10ff INFO

My first approach to this error is to decrease the RAM usage, so I took another look at my first *.map file and there is a source file listed in the module summary table using 633 bytes in the CONST entry. I think reducing this number could solve my problem. This file is the implementation of a simple menu using an LCD display and 2 switches.

So my question to you is: What techniques are appropriate to optimize the program in order to use less RAM and perhaps use a bigger percentage of the Flash memory which I have plenty?

Thank you
André Gomes

  • The linker's error msg says that you code generated 274 (hex 112) bytes for Info-Flash, which is limited to 256 (hex 100).

    Why are you using Info-Flash?

  • I didn't mean to use info-flash. But I guess since big parts of my application are based on existing application reports I might be using it.

    How should I proceed to find where the info-flash is used?

  • Search your source code for the word "INFO", "INFOA", or "INFOB". If you are lucky, you may find out who's done it.But there are other way to use them without spelling out the symbolic name. In that case, you may have to use other tricks to find them.

  • Andre Gomes said:
    there is a source file listed in the module summary table using 633 bytes in the CONST entry. I think reducing this number could solve my problem.

    No. CONST data usually goes directly into main flash and doesn't use ram. CODE memory is also lcated in main flash, along with the interrupt vectors.

    DATA goes into both, main memory and ram. Thso variables with init values require a copy of these init value in main flash to initialize ram after power-up. These are IMHO the "84 absolute".

    Not listed but also located in ram are the heap (if you use malloc) and the stack, whcih not only contains retrun addresses for function calls, but also all locally defined variables. This ram usage is not checked by the linker. (the 'stack size' setting is jsut a placeholder to trigger a linker error when less memory is left by the DATA, but does not affect the runtime by any means)

    It's indeed strange that there are 274 bytes located in INFO memory, which isn't used at all by default and (as OCY pointed out) is only 256 bytes size.

  • Thank you very much for your answers, old_cow_yellow and  Jens-Michael Gross. It seems I had misunderstood the problem.

    I went through the source files and found the following definition inside a header:

    #define __infomem__ _Pragma("location=\"INFO\"")

    this infomem macro is used only once:

    __infomem__ const struct info_mem_s nv_parms =
    { ... }

    this is a structure containing two unions with constant data for scaling measured values. I don't know why it's placed in the info flash, but when I remove the __infomem__ macro from the code, it compiles fine but my system stops working.

     Any ideas?


  • When I asked you: "Why are you using info-flash?" I did not mean to imply that you should not use it. Nor to imply that stop using info-flash will cure your problem.

    Now the question is, why is nv_parms longer than 256 bytes? Please be forewarn that arbitrarily cutting it down to 256 bytes will not cure your problem either.

  • The size of the variable nv_parms is defined by the following definition:

    struct info_mem_s
    {
    union
    {
    struct nv_parms_s s;
    int8_t x[128];
    } seg_a;
    union
    {
    int8_t x[128];
    } seg_b;
    };

    The structure nv_parms_s is the "image" of the parameters to be placed in the info memory, and its size depends on the functionalities of the application that I use. Since I need to use most of these functionalities the size of  nv_parms_s is greater than 128 bytes which makes the size of info_mem_s bigger than 256 thus leading to a linker error.
    The union seg_b is never used, removing it from struct info_mem_s allows me to compile with no errors but does not solve my problem.

    Could there be some conflict in the way data is stored in the info flash?

  • This struct looks weird. Why is seg_b a union if it has only one member?

    To spread s over both segments, things must look different:

    strunct info_mem_s
    {
      union
      {
        struct nv_parms_s s;
        struct {
          int8_t seg_a[128];
          int8_t seg_b[128];
       }
    }

    The 'nameless struct maybe won't work (it works on (MSP)GCC). If not, the second struct needs a name like 'segs'.
    However, this general structure ensures that info_mem_s is laid across seg_a and seg_b (if needed)

  • Is int8-t 8-bit or t6-bit wide integer type?

    Does nv_parms_s imply non-volatile-parameters-structure? Is it being erased and re-written? If so, does the size of the sector of Flash matters?

    Using code without knowing what it does is very risky. Passing through the compiler and linker is the easy part.

  • old_cow_yellow said:

    Is int8-t 8-bit or t6-bit wide integer type?

    It's 8-bit wide.

    old_cow_yellow said:

    Does nv_parms_s imply non-volatile-parameters-structure?


    Yes.

    old_cow_yellow said:

    Is it being erased and re-written?

    Neither, after initialization it's only read.

    old_cow_yellow said:

    If so, does the size of the sector of Flash matters?


    Yes, because the entire non-volatile structure needs to be stored in the flash.

    The problem comes up only when the size of nv_parms_s is bigger than the size of one segment. I tried redefining the structure info_mem_s according to the suggestion of Jens_Michael Gross and it ended up like this:

    struct info_mem_s
    {
        union
        {
           struct nv_parms_s s;
           struct segs{
                 int8_t x_a[128];
                 int8_t x_b[128];
           };
        }seg_a;
    };

    I think this guarantees the structure is spread over both segments correctly. Compiling like this passes through the compiler and linker but the system still doesn't work.
    I did study the code before starting to use it but I didn't go deep enough and now it backfired.

  • old_cow_yellow said:
    Is int8-t 8-bit or t6-bit wide integer type?

    The name int8_t implies an 8 bit-wide type. I'd expect it to be an alias for signed char.

  • Indeed it is

    typedef signed char int8_t;

  • Andre Gomes said:
    struct info_mem_s
    {
        union
        {
           struct nv_parms_s s;
           struct segs{
                 int8_t x_a[128];
                 int8_t x_b[128];
           };
        }seg_a;
    };

    Well, the wrapping struct is superfluous,a s it only contains one member, the union. Also, teh namign is misleadign since seg_a contains INFOA and INFOB segment (x_a, x_b)

    typedef union
    {
      struct nv_parms_s s;
      struct segs{
        int8_t a[128];
        int8_t b[128];
      };
    } info_mem_s;

    const info_mem_s infomem;

    allows access to

    infomem.s.[...] as well as infomem.a[y] or infomem.b[z]

    This declaration and definition can be directly placed to INFO area using the compiler specific mechanisms. It may even include an initialization.

  • Jens-Michael Gross said:

    Well, the wrapping struct is superfluous,  as it only contains one member, the union. Also, the naming is misleadign since seg_a contains INFOA and INFOB segment (x_a, x_b)

    typedef union
    {
      struct nv_parms_s s;
      struct segs{
        int8_t a[128];
        int8_t b[128];
      };
    } info_mem_s;

    const info_mem_s infomem;


    Even if the wrapping structure is not needed, I have to include it, because otherwise it won't be compatible with the original structure that contained two unions. If I am to change that I will have to change the accesses to the structure (which is fairly easy) but I also have to change the initialization of the structure, not only is this a complex task but it could lead to more errors or inconsistencies in the code.
    I'm starting to think the problem might be elsewhere, so I'll go into further detail and maybe you can provide me with more debugging techniques.

    I'm using the application report slaa391:
    http://www.ti.com/mcu/docs/litabsmultiplefilelist.tsp?sectionId=96&tabId=1502&literatureNumber=slaa391&docCategoryId=1&familyId=914

    The purpose of my system is to monitor energy (using slaa391) and it has a few extra peripherals.
    The raw application works only if nv_parms_s is smaller than 128, this is without the energy measurement functionalities. Once I switch these on the error in the info flash pops up. By using all different structure definitions already discussed in this post the program compiles and runs correctly, except some functionalities stop working, the Basic timer ISR used to implement an RTC runs only once at the beginning instead of every second. If I stop the program I can see it is running correctly all the Timer and ADC interrupts as well as energy accumulation.
    The system goes into Low power mode shortly after it starts, and I noticed it doesn't wake up from it when it should. 

    There is little I can conclude from this, what steps do you think I should take to find the problem? 

  • Andre Gomes said:
    By using all different structure definitions already discussed in this post the program compiles and runs correctly, except some functionalities stop working, the Basic timer ISR used to implement an RTC runs only once at the beginning instead of every second. If I stop the program I can see it is running correctly all the Timer and ADC interrupts as well as energy accumulation.

    I don't know how your program works. But effects like this are often observed if time-consuming things are done inside an ISR. When an ISR is entered, no other interrupt can interrupt it until it exits. Also, if two interrupts are pending, the one with the higher priority is exeuted first.

    If a program spends too much time inside an iSR, it may happen that when it finally exits the ISR, several othe rinterrupts are pending, so the one with the highest priority is executed first. This may well be the on whose ISR just exited. Worst case, an interrupt with a lower priority is never served at all.

    The priorities are fixed (see the device datasheet for priority order).

    So check your ISRs. And code them to be fast-in and fast out. Don't spend any timne inside an ISR, don't wait for data being sent or received, for conversion being done. All these events have their own interrupt, so just start the process in one ISR (e.g. start a conversion in a timer ISR) and end it in its own ISR (the ADC ISR) instead of waiting for the conversion to complete in the timer ISR while all other interrupts are blocked.

  • Jens-Michael Gross said:

    If a program spends too much time inside an iSR, it may happen that when it finally exits the ISR, several othe rinterrupts are pending, so the one with the highest priority is executed first. This may well be the on whose ISR just exited. Worst case, an interrupt with a lower priority is never served at all.

    You were right.

    My Timer_A ISR needs to be a long time consuming routine, on top of that it was running too frequently. Since the other ISR had a lower priority it was never attended.
    Also, I checked my device's datasheet for ISR priority, but I couldn't figure out the priority of the main().

    Anyway,  the problem is solved.
    It's been enlightening, shall any other problem arise I'll start a different thread.

    Thank you very much.

  • Andre Gomes said:
    Also, I checked my device's datasheet for ISR priority, but I couldn't figure out the priority of the main().

    Well, main is no interrupt, so it has no priority. Main is, what runs if no interrupt is pending and no ISR is being executed. Or in other words: main is, what is interrupted by an interrupt. :)

**Attention** This is a public forum