eerimoq / simba

Simba Embedded Programming Platform.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Reduce Memory Usage

softov opened this issue · comments

Hi, I am a C programmer, but I am new with Arduino, AtMega328 and this stuff.
I am stating a new project using a NANO (ATMega328p) to be a slave of a FreeBSD in a RS485 network.
Since in FreeBSD I don't have problem with memory there is no problem in design the structs, but sometimes I need to transmit packets, and lower size is better to transmit.

Using Arduino Framework I get ~40%, most of then are logs, sprintf to Serial (UART).
But I don't like C++, and all my reference codes are in c (framework of the company I work).

Today, searching for replacement, I see that I can use Simba, so, why not try?

I made a small code, to test some of resources I was using on Arduino, replace my Serial parser, to shell, and got little things working.
A terminal to receive command and read/write to my RS485 module, using uart_soft_driver.
More code I put, more the memory increase, until I get 109% of DATA memory utilization.

After read the code to find some ways to reduce the memory utilization, I think that I have found a way.

Take by example struct shell_t in ../src/oam/shell.h

   ...
    int carriage_return_received;
    int newline_received;
    int authorized;
   ...
    // DATA:    [==========]  99.2% (used 2032 bytes from 2048 bytes)
    // PROGRAM: [========  ]  75.3% (used 23118 bytes from 30720 bytes)

Changed to:

   ...
    unsigned int carriage_return_received:1; //  byte allocated
    unsigned int newline_received:1;  // will get accomodated in the 1 byte
    unsigned int authorized:1;  //  will get accomodated in the 1 byte
   ...
    // DATA:    [==========]  99.0% (used 2027 bytes from 2048 bytes)
    // PROGRAM: [========  ]  75.1% (used 23080 bytes from 30720 bytes)

I have made a example in C to reduce the memory use of a struct, take a look

#include <stdio.h>

typedef struct _StrA {
    char data[64];
    int flag_d; /* is a flag */
    int var_s_a; /* can be short */
    int var_i_a;
    int flag_c; /* is a flag */
    int var_s_b; /* can be short */
    int var_s_c; /* can be short */
    int flag_a; /* is a flag */
    long var_long;
    int flag_b; /* is a flag */
} StrA;

typedef struct _StrB {
    char data[64];
    unsigned int flag_d:1;
    short var_s_a;
    int var_i_a;
    unsigned int flag_c:1;
    short var_s_b;
    short var_s_c;
    unsigned int flag_a:1;
    long var_long;
    unsigned int flag_b:1;
} StrB;

typedef struct _StrC {
    char data[64];
    long var_long;
    int var_i_a;
    short var_s_a;
    short var_s_b;
    short var_s_c;
    unsigned int flag_a:1;
    unsigned int flag_b:1;
    unsigned int flag_c:1;
    unsigned int flag_d:1;
} StrC;

int main()
{
    /* SIZES [4] [112] [96] [88] in a 64 bits machine */
    printf("SIZES [%d] [%d] [%d] [%d]", sizeof(int), sizeof(StrA), sizeof(StrB), sizeof(StrC));
    
    /* SIZES [4] [28] [24] [22] in Bytes */
    printf("SIZES [%d] [%d] [%d] [%d]", sizeof(int), sizeof(StrA)/sizeof(int), sizeof(StrB)/sizeof(int), sizeof(StrC)/sizeof(int));

    return 0;
}

As you can see, this can reduce the memory utilization.
Ps, structs need to be allocated in sequence, take my example a INT = 1BYTE

    char data[64];
    long var_long;
    int var_i_a;

    short var_s_a; // 1 byte allocated (8 bits - 4 = 4)
    short var_s_b; // will use the 1 byte (1 bits - 1 = no remain after)

    short var_s_c; // 1 byte allocated (8 bits - 4 = 4)
    unsigned int flag_a; // will use 1 byte (4 bits - 1 = 3)
    unsigned int flag_b; // will use 1 byte (3 bits - 1 = 2)
    unsigned int flag_c; // will use 1 byte (2 bits - 1 = 1)
    unsigned int flag_d; // will use 1 byte (1 bits - 1 = no remain after)

This will reduce the size of memory needed to this structure.
Since it will use only one bit, this can be done in a lot of places using flags 1/0 to check enable/disable.

I have a made in some places to test off course, but since the source is large, I think it's better to put in base, because this will benefit everyone, and, of course, I can let my source updated, without need to patch every time.

At, softov

Hello,

I think I like the idea of using 1 bit per boolean in structs. Would save some precious RAM indeed. Feel free to create a PR introducing them in a few structs (those relevant to you), and it will probably be merged. The only drawback is that flash usage may increase slightly, but flash usage is not as critical as RAM.

PS. I this the UART soft driver cannot handle simultaneous TX and RX. I strongly recommend you to use the non-soft driver, often automatically started as the console which uses stdin and stdout. DS.

Oh man, I live in a cave, programming day and night.
I will edit/test some codes tomorrow and learn how to create a PR to this.

In time, I will create another issue about the UART.