Pages: [1] 2   Go Down
Author Topic: Lack of SRAM memory  (Read 1526 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello, I've finished to write and compile my program, but when it start running the arduino runs out of memory and it gives strange characters to serial.
I need some help to optimize my code... to make more SRAM available (Flash memory is good: 31.030 bytes).

Code:
#include <SPI.h>
#include <Ethernet.h>
#include <VirtualWire.h>
#include <Wire.h>
#include "SdFatUtil.h"

//VARIÁVEIS PARA O RTC (DS1307)
//SCL      <--> Analog Input 5
//SDA      <--> Analog Input 4
#define DS1307_I2C_Endereco 0x68  // This is the I2C address
#define I2C_Write Wire.write
#define I2C_Read Wire.read
byte segundo, minuto, hora, diaSemana, dia, mes, ano;

//CONVERSÃO DE BCD PARA DECIMAL
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

char* noMes[] = {
  "","Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"};

//DECLARAÇÃO DOS PINOS
const byte ledInfo = 2;
const byte ledRececao = 3;
const byte pinoRececao = 8;
const byte BUFSIZ = 128;

//DECLARAÇÃO DAS VARIÁVEIS GLOBAIS
char mensagem[6];
unsigned int dadosAgua = 0;
float dadosBat = 0.0;
float percentagem = 0;
unsigned long litros = 0;
boolean Log = false;
int altAgua = 0;

//CONFIG ETHERNET SHIELD
byte mac[] = {
  0x80, 0xA2, 0xDA, 0x00, 0xEA, 0x8C };
byte ip[] = {
  10, 50, 196, 80 };
char ficheiroIndex[] = "i.htm";
char ficheiroTanque[] = "t.jpg";
char ficheiroBorder[] = "b.jpg";
char ficheiroFavicon[] = "f.ico";
char ficheiroLog[8];
char* ficheiroLer;
EthernetServer server = EthernetServer(80);
EthernetClient client;

//PROGRAMAÇÃO DO CARTÃO SD
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

//ARMAZENA SEQUÊNCIAS DE ERRO NA MEMÓRIA FLASH PARA ECONOMIZAR RAM
#define error(s) error_P(PSTR(s))
void error_P(const char* str) {
  PgmPrint("Erro: ");
  SerialPrintln_P(str);
  if (card.errorCode()) {
    PgmPrint("Erro cart.SD: ");
    Serial.print(card.errorCode(), HEX);
    Serial.print(',');
    Serial.println(card.errorData(), HEX);
  }
  digitalWrite(ledInfo, HIGH);
  while(1);
}

void setup() {

  Serial.begin(9600);
  delay(100);

  pinMode(ledInfo, OUTPUT);
  pinMode(ledRececao, OUTPUT);
  pinMode(10, OUTPUT);

  //INICIA A COMUNICAÇÃO I2C
  Wire.begin();

  //LIGA E DESLIGA OS 2 LEDS PARA INDICAR QUE ESTÃO OPERACIONAIS
  digitalWrite(ledInfo, HIGH);
  digitalWrite(ledRececao, HIGH);
  digitalWrite(10, HIGH);
  delay(1000);
  digitalWrite(ledInfo, LOW);
  digitalWrite(ledRececao, LOW);

  PgmPrint("RAM: ");
  Serial.println(FreeRam());

  //INICIALIZA O CARTÃO SD EM "FULL SPEED", MÁXIMO DESEMPENHO. (PARA EVITAR ERROS COM LIGAÇÃO À BREADBOARD DEVE ESTAR EM "HALF SPEED")
  if (!card.init(SPI_FULL_SPEED, 4)) error("Erro Init cart.SD!");

  //INICIALIZA O VOLUME FAT
  if (!volume.init(&card)) error("Erro vol cart.SD!");

  //LISTA NA SÉRIE OS FICHEIROS QUE ESTÃO NA RAIZ DO CARTÃO SD, COM DATA E TAMANHO
  if (!root.openRoot(&volume)) error("Erro root cart.SD!");

  //INICIA O SERVIDOR
  Ethernet.begin(mac, ip);
  server.begin();
  delay(100);

  //CONFIGURA E INICIA O RECEPTOR
  vw_set_rx_pin(pinoRececao);
  vw_setup(2000);
  vw_rx_start();

  //LED PISCA 3 VEZES A INDICAR TODA A CONFIGURAÇÂO CONCLUÍDA COM SUCESSO
  for (int i = 0; i<3; i++) {
    digitalWrite(ledInfo, HIGH);
    delay(250);
    digitalWrite(ledInfo, LOW);
    delay(250);
  }
  Serial.println(F("Config concl"));
}

void loop() {

  altAgua++;
  rececaoRF();
  clienteLigado();
  delay(500);
}

//RECEPÇÃO DOS DADOS POR RF 433MHz
void rececaoRF() {

  byte buf[VW_MAX_MESSAGE_LEN];
  byte buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) {
    digitalWrite(ledRececao, HIGH);
    for (int j = 0; j<buflen; j++) {
      mensagem[j] = buf[j];
    }
    if (mensagem[0] == 'R') {
      dadosAgua = atoi(&mensagem[1]);
    }
    else if (mensagem[0] == 'B') {
      dadosBat = atof(&mensagem[1]);
      Serial.print(F("Volt Bat: "));
      Serial.println(dadosBat);
    }
    Serial.print(F("Msg Receb: "));
    Serial.println(mensagem);
    memset(&buf, 0, sizeof(buf));
    memset(&mensagem, 0, sizeof(mensagem));
    calcAgua();
    gravarDados();
    digitalWrite(ledRececao, LOW);
  }
}
CONTINUES...
« Last Edit: April 22, 2013, 09:56:26 am by blastboot » Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
void calcAgua() {
  percentagem = ((465-dadosAgua)*100)/465;
  litros = ((465-dadosAgua)*600000)/465;
}

void gravarDados() {

  //FAZ O STACK POINTER IR PARA O INÍCIO
  Wire.beginTransmission(DS1307_I2C_Endereco);
  I2C_Write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_Endereco, 7);

  segundo = bcdToDec(I2C_Read() & 0x7f); //MASCARA PQ É BIT DE CONTROLE
  minuto  = bcdToDec(I2C_Read());
  hora    = bcdToDec(I2C_Read() & 0x3f); //MÁSCARA PQ É BIT DE CONTROLE
  dia     = bcdToDec(I2C_Read());
  mes     = bcdToDec(I2C_Read());
  ano     = bcdToDec(I2C_Read());

  sprintf(ficheiroLog,"%s%s", noMes[mes], ".csv");

  Log = file.open(&root, ficheiroLog, O_WRITE | O_APPEND);
  if (Log){
    //HORA
    file.print(dia, DEC);
    file.print(" ");
    file.print(noMes[mes]);
    file.print(" ");
    file.print("20");
    if (ano < 10) {
      file.print("0");
    }
    file.print(ano, DEC);
    file.print(" , ");
    if (hora < 10) {
      file.print("0");
    }
    file.print(hora, DEC);
    file.print(":");
    if (minuto < 10) {
      file.print("0");
    }
    file.print(minuto, DEC);
    file.print(":");
    if (segundo < 10) {
      file.print("0");
    }
    file.print(segundo, DEC);
    //DADOS    
    file.print(" , ");
    file.print(percentagem, 1);
    file.print(" , ");
    file.println(litros);
    file.close();
    Log = false;
  }
  else {
    Serial.println(F("ERRO grav LOG!"));
  }
}

void clienteLigado() {
  char clientline[BUFSIZ];
  int index = 0;
  client = server.available();
  if (client) {
    digitalWrite(ledInfo, HIGH);
    delay(1);
    digitalWrite(ledInfo, LOW);
    index = 0;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          if (index >= BUFSIZ)
            index = BUFSIZ - 1;
          continue;

        }
        clientline[index] = 0;
        Serial.println(clientline);
        digitalWrite(ledInfo, HIGH);
        delay(1);
        digitalWrite(ledInfo, LOW);        

        if (strstr(clientline, "GET / ") != 0) {
          headerRespostaHttp();
          conTypeTxt();
          ficheiroLer = ficheiroIndex;
          lerFicheiroCartao();

        }
        else if (strstr(clientline, "GET /tqe") != 0) {
          headerRespostaHttp();
          conTypeImg();
          ficheiroLer = ficheiroTanque;
          lerFicheiroCartao();
        }
        else if (strstr(clientline, "GET /bdr") != 0) {
          headerRespostaHttp();
          conTypeImg();
          ficheiroLer = ficheiroBorder;
          lerFicheiroCartao();
        }
        else if (strstr(clientline, "GET /fin") != 0) {
          headerRespostaHttp();
          client.println(F("Content-Type: image/x-icon"));
          client.println();
          ficheiroLer = ficheiroFavicon;
          lerFicheiroCartao();
        }
        else if (strstr(clientline, "GET /&dadosagua") != 0) {
          headerRespostaHttp();
          conTypeTxt();
          client.print(altAgua);
          client.println(F("px"));
          Serial.println(altAgua);
        }
        else if (strstr(clientline, "GET /&logg") != 0) {
          headerRespostaHttp();
          char carMes = clientline[10];
          switch (carMes) {
          case '1':
            sprintf(ficheiroLer,"%s%s", noMes[1], ".csv");
            //ficheiroLer = "Jan.csv";
            break;
          case '2':
            sprintf(ficheiroLer,"%s%s", noMes[2], ".csv");
            //ficheiroLer = "Fev.csv";
            break;
          case '3':
            sprintf(ficheiroLer,"%s%s", noMes[3], ".csv");
            //ficheiroLer = "Mar.csv";
            break;
          case '4':
            sprintf(ficheiroLer,"%s%s", noMes[4], ".csv");
            //ficheiroLer = "Abr.csv";
            break;
          case '5':
            sprintf(ficheiroLer,"%s%s", noMes[5], ".csv");
            //ficheiroLer = "Mai.csv";
            break;
          case '6':
            sprintf(ficheiroLer,"%s%s", noMes[6], ".csv");
            //ficheiroLer = "Jun.csv";
            break;
          case '7':
            sprintf(ficheiroLer,"%s%s", noMes[7], ".csv");
            //ficheiroLer = "Jul.csv";
            break;
          case '8':
            sprintf(ficheiroLer,"%s%s", noMes[8], ".csv");
            //ficheiroLer = "Ago.csv";
            break;
          case '9':
            sprintf(ficheiroLer,"%s%s", noMes[9], ".csv");
            //ficheiroLer = "Set.csv";
            break;
          case 'o':
            sprintf(ficheiroLer,"%s%s", noMes[10], ".csv");
            //ficheiroLer = "Out.csv";
            break;
          case 'n':
            sprintf(ficheiroLer,"%s%s", noMes[11], ".csv");
            //ficheiroLer = "Nov.csv";
            break;
          case 'd':
            sprintf(ficheiroLer,"%s%s", noMes[12], ".csv");
            //ficheiroLer = "Dez.csv";
            break;
          }
          client.print(F("Content-Disposition: attachment; filename=\"LOG_"));
          client.print(ficheiroLer);
          client.println(F("\""));
          client.println();
          lerFicheiroCartao();
        }
        else {
          client.println(F("HTTP/1.1 404 Not Found"));
          conTypeTxt();
          client.println(F("<h2>Erro 404</h2>"));
          client.println(F("<s2>Caminho/ficheiro nao existe.<s2>"));
          client.println(F(""));
        }
        break;
      }
    }
    delay(1);
    client.stop();
  }
}

void headerRespostaHttp() {
  client.println(F("HTTP/1.1 200 OK"));
}

void conTypeTxt() {
  client.println(F("Content-Type: text/html"));
  client.println();
}

void conTypeImg() {
  client.println(F("Content-Type: image/jpeg"));
  client.println();
}

void lerFicheiroCartao() {
  boolean ficheiro = false;
  ficheiro = file.open(&root, ficheiroLer, O_READ);
  if (ficheiro) {
    byte clientBuf[64];
    int clientCount = 0;

    while(file.available()) {
      clientBuf[clientCount] = file.read();
      clientCount++;
      if (clientCount > 63) {
        client.write(clientBuf, 64);
        clientCount = 0;
      }
    }
    if (clientCount > 0) {
      client.write(clientBuf, clientCount);
    }
    file.close();
    memset(&ficheiroLer, 0, sizeof(ficheiroLer));
  }
}

Thanks in advance!
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26345
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
case '1':
            sprintf(ficheiroLer,"%s%s", noMes[1], ".csv");
            //ficheiroLer = "Jan.csv";
            break;
          case '2':
            sprintf(ficheiroLer,"%s%s", noMes[2], ".csv");
            //ficheiroLer = "Fev.csv";
            break;

Code:
            sprintf(ficheiroLer,"%s%s", noMes[carmes - '0' + 1], ".csv");
or similar.
Looks like a few of your GETs could live in PROGMEM too.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for answering!
Quote
sprintf(ficheiroLer,"%s%s", noMes[carmes - '0' + 1], ".csv");
I couldn't understand what does this do in this format. Can you give me a simple explanation?

The progmem is a good idea. I will look for it to know how to use it.
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26345
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Assume "carmes" is an ASCII decimal digit.
Subtracting '0' turns it into its actual decimal value.
Use that to form your array subscript.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, so let's say that carMes is char '1'...  the function as you said, subtracts '0' to '1' which gives '1' and then adds '1' which gives '2', so it will look at position 2 of char array, is this?
If yes, and to free SRAM a little bit memory i should use it as the way i'm using it , like:
Code:
switch (carMes) {
          case '1':
            sprintf(ficheiroLer,"%s%s", noMes[carmes - '0' + 1], ".csv");
            //ficheiroLer = "Jan.csv";
            break;
          case '2':
            sprintf(ficheiroLer,"%s%s", noMes[carmes - '0' + 1], ".csv");
            //ficheiroLer = "Fev.csv";
            break;

Or another form?
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6619
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

1. You have a number of variables such as mensagem, segundo etc. that are used in only one function, and whose values do not (as far as i can see) need to be preserved between calls to that function. Declare those as local variables inside the function, so that they do not occupy storage all the time.

2. You have a number of instances where you are passing a literal string as a parameter (not the format parameter) to sprintf, for example:

Code:
sprintf(ficheiroLer,"%s%s", noMes[2], ".csv");

If you use this instead:

Code:
sprintf(ficheiroLer,"%s.csv", noMes[2]);

then you will save one of the string literals, and hence a few bytes.

3. You use the same string literal several times, for example ".csv", "%s%s" and " , ". Depending on whether gcc is performing string pooling or not, you might save memory by naming string literals that you use more than once.

4. Other than those, it's mostly a case of moving string literals into progmem. There are versions of some of the string handling functions that use progmem directly, for example strstr_P.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26345
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
switch (carMes) {
          case '1':
            sprintf(ficheiroLer,"%s%s", noMes[carmes - '0' + 1], ".csv");
            //ficheiroLer = "Jan.csv";
            break;
          case '2':
            sprintf(ficheiroLer,"%s%s", noMes[carmes - '0' + 1], ".csv");
            //ficheiroLer = "Fev.csv";
            break;
No, the switch is now unnecessary, because you're doing the subscript calculation the same for every case.
You may want to use the switch for your non-consecutive months at the end of the year.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

dc42 thank you very much, i will look to do what you have recommended.
Quote
3. You use the same string literal several times, for example ".csv", "%s%s" and " , ". Depending on whether gcc is performing string pooling or not, you might save memory by naming string literals that you use more than once.
You're telling to use like
Code:
char name[]=".csv"
and everytime i need to "write" that i point to "name" char. Is this?


AWOL ok i've understanding it now. So... looking to dc42 comment i suppose that i can put your ideas in the function, and it will look like:
Code:
sprintf(ficheiroLer,"%s.csv", noMes[carmes - '0' + 1]);
It's good like that?

(sorry for my english but it is not my native language)

Thanks for helping me!
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I realize that i have a problem using
Quote
sprintf(ficheiroLer,"%s.csv", noMes[carmes - '0' + 1]);
because i have 12 log files -> one for each month <- and i'm expecting to receive &logg1 (for Jan), &logg2 (for Feb) ... until &logg9 (for Sep) and because i'm looking only to position 10:
Quote
char carMes = clientline[10];
  i've put &loggo (for Oct), &loggn (for Nov) and &loggd (for December). So that function will not work for the last 3 months.
It's possible to do something like char carMes be equal to position 10 and 11 of clientline and then naming &logg from 01 to 12 for this function to work?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26345
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think I already pointed that out.
Lots of ways to handle it - look-up table, multiple ternary operators, switch/case for the last three months.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wich is the best way to save RAM? I've putted the month char array to progmem already
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7198
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

To save SRAM you can save the entire month string as one string in the PROGMEM and extract only 3 characters at time (could be hard on syntax).
You can also use F() on these:
Code:
char ficheiroIndex[] = "i.htm";
char ficheiroTanque[] = "t.jpg";
char ficheiroBorder[] = "b.jpg";
char ficheiroFavicon[] = "f.ico";
Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 106
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've done this:
Code:
prog_char ficheiroIndex[] PROGMEM = "i.htm";
prog_char ficheiroTanque[] PROGMEM = "t.jpg";
prog_char ficheiroBorder[] PROGMEM = "b.jpg";
prog_char ficheiroFavicon[] PROGMEM = "f.ico";
PROGMEM const char* fichPag[] = {
  ficheiroIndex, ficheiroTanque, ficheiroBorder, ficheiroFavicon};
char* ficheiroLer;
So the char array will be stored in progmem.


And for log file i've done this:
Code:
else if (strstr(clientline, "GET /&logg") != 0) {
          
          char carMes = clientline[10];
          byte num = atoi(&carMes);
          if (num > 0 && num<10) {
            strcpy_P(nomeMes, (char*)pgm_read_word(&(noMes[carMes - '0'])));
            sprintf(ficheiroLer,"%s.csv", nomeMes);  <------- printing nomeMes before this line returns Jan as expected
            Serial.println(ficheiroLer);  <-------- This isn't printed and arduino restarts...
          }
          else {
          switch (carMes) {
          case 'o':
            strcpy_P(nomeMes, (char*)pgm_read_word(&(noMes[10])));
            sprintf(ficheiroLer,"%s.csv", nomeMes);
            break;
          case 'n':
            strcpy_P(nomeMes, (char*)pgm_read_word(&(noMes[11])));
            sprintf(ficheiroLer,"%s.csv", nomeMes);
            break;
          case 'd':
            strcpy_P(nomeMes, (char*)pgm_read_word(&(noMes[12])));
            sprintf(ficheiroLer,"%s.csv", nomeMes);
            break;
          }
          }
          headerRespostaHttp();
          client.print(F("Content-Disposition: attachment; filename=\"LOG_\""));
          //client.print(ficheiroLer);
          //client.println(F("\""));
          client.println();
          lerFicheiroCartao();
        }

But when it receives GET /&logg1  (for example) arduino restarts. FreeRam() tells me that it has 925 bytes of memory, because i've comment almost the entire program to see if this part works, but it restarts...
« Last Edit: April 23, 2013, 06:30:23 pm by blastboot » Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 98
Posts: 4808
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, so let's say that carMes is char '1'...  the function as you said, subtracts '0' to '1' which gives '1' and then adds '1' which gives '2', so it will look at position 2 of char array, is this?


Arrays start with
  • as the first element.
  • , [1], [2] ... [2] is the 3rd, not 2nd.
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Pages: [1] 2   Go Up
Jump to: