Uno formfit with more memory

I built a test system for a customer using an Uno. They have asked for some changes, when I compile the new sketch I get a warning that there is low memory and there may be some stability issues. So far the sketch works but I still have more changes to add.

I don't want to rebuild the hardware, shield and connectors all in place, but that may not be an option.

Is there a board that has the same form and pinouts as an Uno but with more memory?

Thanks
John

1 Like

You could get a Nano Every and an Uno PCB and make an adapter.


Then it would pair right up.

That's a good idea. I have an Every and have used it before for the same reason, needed more more memory. I'll give that a try.

Thanks

How to power up this board?

I found this board on Amazon. Your thoughts?

It doesn't expand memory of the Uno

No but it does take a Nano Every and I can connect the pins of the Every to the pins that match the Uno, So as far as I can tell, the Every would replace the Uno but the shield will plug into where the existing Uno is.

At least I think that's what it's doing, do you? or am I missing something?

Thanks

I am not quite sure is Nano Every pinout exactly the same as classic Nano. If so, all should be works fine
But note that MCU of Nano Every is not fully compatible with Atmega328 code

Well... you could also post your code and see if the savants around here have any suggestions for compaction. Sometimes, the obvious escapes... For example, have you explored the use of the F macro for print statements? We don't know, because we can't read your mind.

1 Like

I'll have to confirm the pins but I did just try compiling the sketch with a Every and no problems, big difference in the memory. For $11 it's worth a shot, otherwise I'll just get a bare shield and wire up as first suggested.

Let's see the message, so we know if you're hurting for code space or RAM

1 Like

It highly depends on how far you are over the (kind-of) arbitrarily chosen limit. If the IDE reports e.g. 76% I would not worry, if it is over 80% I will start worrying. The sketch itself will also have an affect how much RAM it uses at run time and if it's going to be a problem.

You don't seem to be willing to share your code; if it does not make use of the F macro for printing, that would be the first thing to do.

Define "same form" :wink: A shield designed for an Uno will fit on a Leonardo (500 bytes extra RAM) or a Mega (plenty of extra RAM but a lot bigger).

However, the shield needs to be properly designed meaning that:

  1. The 6-pin ICSP header needs to be used for SPI.
  2. I2C must be on the header that also has pins 8-13.

And if your sketch bypasses the hardware abstraction layer you have another problem.

Lastly note that not all libraries are compatible with the Nano Every (and the point of bypassing the hardware abstraction layer also stands). Before going that way I suggest that you compile for the Nano Every to find possible problems.

Your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advice on) your project :wink: See About the IDE 1.x category.

@sterretje not sure why you thought I was unwilling to share my code, I never said anything like that. I was asking more of a general hardware related question so I didn't think the sketch would matter, I have attached it below. I have also included the error I am getting. Keep in mind that the sketch is a work in progress I have not finished the changes, as well as I had to remove some of the functionality of the original code as some of that was interfering with getting the changes working. I'll add those back in later. There's also a lot of Serial.print statements but those are for debugging and will be removed. The system runs a pump with a stepper motor, originally the operator would enter how many steps for the motor, a dwell time and how many times to repeat the process. They now what to enter the speed of the pump, how long to run it and a pause time but instead of repeating the same parameters they can change the next phases settings. Currently I have it limited to 10 phases, if they need less they enter a 0 for the last phase number. While the pump is running it measure two pressure transmitters and stores the data on a SD card. Form fit to me means I can unplug the first component and plug a second one in the same place without making any changes and it works the same as the first. There is an extremal power supply, real time clock, 2 pushbuttons, two pressure transmitter, the SD card and the stepper motor controller. I don't want to have to rewire all of that. If I can plug the Every into this shield, solder female header pins on and plug all the connections in the same place I'll be happy. As mentioned earlier I was able to compile this sketch with a Every without making any changes so the libraries I'm using must be compatible.

Here is the sketch

[code]
//  stepper motor control code
// Enter cycle values, number of steps, dwell time between steps, and number of increments on serial monitor
// Comands to control test also entered on serial monitor, s = start, p = pause, r = resume, e = end, or use pushbutton to start cycle
// Added a purge cycle, when the purge pushbutton is pressed the pump will go 1 revolution in 1 minute
// Added 2 pressure sensors, RTC and SD card for data logging
// Rev 6 added an arrary to hold phase #, Speed, Time, Dwell
// Changed stepper libray to be able to control speed
// Copyright Process Services 2020

//#include <AccelStepper.h>
#include <Stepper.h>
#include <SPI.h>
#include <SdFat.h>                // SD card & FAT filesystem library
#include <Wire.h>
#include "RTClib.h"


// RTC variables
RTC_DS3231 realClock; // Establishes the chipset of the Real Time Clock
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// SD Variables
SdFat  SD;         // SD card filesystem


unsigned int SDyear = 2019;
byte SDmonth = 11;
byte SDday = 15;
byte SDhour = 6;
byte SDminute = 11;
byte SDsecond = 00;
char logFileName[20] = " "; // current log file name
File logfile; // the logging file
DateTime now ;

int errorNumb = 0; // system error number to display message
const int chipSelect = 10;

// Motor pin definitions
// Blue   - 28BYJ48 pin 1
// Pink   - 28BYJ48 pin 2
// Yellow - 28BYJ48 pin 3
// Orange - 28BYJ48 pin 4
// Red    - 28BYJ48 pin 5 (VCC)

#define motorPin1 3    // IN1 on the ULN2003 driver 1
#define motorPin2 4   // IN2 on the ULN2003 driver 1
#define motorPin3 5   // IN3 on the ULN2003 driver 1
#define motorPin4 6   // IN4 on the ULN2003 driver 1

const int stepsPerRevolution = 200; // number of steps per a revolution of motor
// initialize the stepper library on pins 3 through 11:
Stepper EF_Stepper(stepsPerRevolution, 3, 4, 5, 6);

#define repeatPb 8   // Repeat cycle pushbutton
#define purgePb  9   // purge cycle pushbutton

int led = 13; // set led to pin 13
String dataIn; // string from operator
char d1;        // character from string
String x;     // String from operator

// Pressure Sensors
int InPrssPin = A0; // Inlet pressure to A0
int OutPrssPin = A1; // Outlet pressure to A1
int InPrssRaw = 0;  // Inlet Pressure raw value
int OutPrssRaw = 0;  // Outlet Pressure raw value
float InPrssScld = 0.0; // Inlet pressure scaled
float OutPrssScld = 0.0; // Outlet pressure scaled
float InPrssPeak = 0.0; // Inlet Pressure Peak
float OutPrssPeak = 0.0; // Outlet Pressure Peak
int InatPeak = 0;


// temporary array for use when parsing
const byte numChars = 64;
char receivedChars[numChars];
char tempChars[numChars];
char dataInChars[numChars];
boolean newData = false;
char startMarker = '<';
char endMarker = '>';
char comma = ',';

// variables for test cycle
long incr = 0;  // number of poles per increment
int poles = 0;  // total poles incremented
int dwell = 0;  // dwell time between steps
int totSteps = 0; // total number of steps
int runCycle = 0; // run cycle enable
long stepCount = 0; // current step counts
int i = 0;
int purgeMode = 0; // purge mode run bit
int purgeSteps = 0;
float purgeDwell = 0.014; // Purge dwell time between steps
int purgeIncr = 0; // purge step counter
int totalPurgeSteps = 4096; // number of steps in purge cycle 1 revolution
long PmpStartTm; // time pump started
long PmpStopTm; // time pump stopped
int phaseNum ;  // entered phase number
int phaseCount = 0; // count the number of phase entered
int pmpEnb = 0; // pump is enabled
int pmpStpd = 0; // pump stopped

// Purge variables
int purgeDist = 4096; // distance pump goes during Purge, 4096 = 1 revolution
int purgeSpd = 70; // speed of pump during purge, 75 = 1 minute for a revolution

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
//AccelStepper stepMotor(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); // AccelStepper::FULL4WIRE

// declare phase parameter array
long phase[11] [4];

void setup() {
  Serial.begin(9600);
  //  stepper.setSpeed(64); // 1 min//64 1rpm //128 2rpm //ENTER 4100 FOR 1 rev OF THE ROLLER
  // Set some constraints on the stepper motor
  //stepMotor.setMaxSpeed(500.0);
  //stepMotor.setAcceleration(100.0);
  //  stepMotor.setSpeed(50);

  pinMode(led, OUTPUT); // set led pin to an output
  pinMode(repeatPb, INPUT_PULLUP); // input for repeat pushbutton
  pinMode(purgePb, INPUT_PULLUP); // input for purge pushbutton

  // Start realClock
  Wire.begin(); // Starts the Wire library allows I2C communication to the Real Time Clock
  realClock.begin(); // Starts communications to the RTC

  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    errorNumb = 1;
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");

  // call function to enter test parameters
  phase_setup();

  for (int i = 0; i <= 10; i++) {
    Serial.print(phase[i][0]);
    Serial.print("\t");
    Serial.print(phase[i][1]);
    Serial.print("\t");
    Serial.print(phase[i][2]);
    Serial.print("\t");
    Serial.print(phase[i][3]);
    Serial.println("\t");
  } // end for

} // end Setup

void loop() {

  if (digitalRead(repeatPb) == LOW) {
    runCycle = 1;
    phaseNum = 1;
    Serial.println("PB pressed");
  } // end if (digitalRead(repeatPb) == LOW)


  //      for(int x = 1; x <= phaseCount; x++){
  //        Serial.println("in for");


  // *******************  Phase Start ***************************************************
  if (runCycle == 1 && purgeMode == 0) {

    if (pmpEnb == 0) {
      PmpStartTm = millis(); // capture pump start time
      pmpEnb = 1;
    } // end if(pmpEnb == 0){

    if (pmpEnb) {

      // start motor at phase speed
      EF_Stepper.setSpeed(phase[phaseNum][0]);
      Serial.println(phase[phaseNum][0]);
      // EF_Stepper.setSpeed(phase[1][0]);
      // step 1/100 of a revolution:
      EF_Stepper.step(stepsPerRevolution / 100);
      Serial.println("runCycle");
      Serial.println(phase[phaseNum][1]);

      if (millis() > (PmpStartTm + phase[phaseNum][1])) {
        runCycle = 0;
        pmpEnb = 0;
        pmpStpd = 1;
        PmpStopTm = millis();
        Serial.println("Pump Stopped");
      } // end  if(millis() > (PmpStartTm + phase[phaseNum][1]))

    } // end if(pmpEnb)

  } // end if(runCycle == 1)

  if (pmpStpd && (millis() > (PmpStopTm + phase[phaseNum][2]))) {
    pmpStpd = 0;
    phaseNum++; // increment phase number
    runCycle = 1;
    Serial.println("Phase end");
  } // end  if(millis() > (PmpStartTm + phase[phaseNum][2]))

  //*************************   Phase Stop   ********************************************************************

  //    } // end for(int x; x <= phaseCount; x++)

} // end loop

void recvWithStartEndMarkers() { // reads variables from controller
  static boolean recvInProgress = false;
  static byte ndx = 0;
  //  char startMarker = '<';
  //  char endMarker = '>';
  char rc;

  // while (Serial1.available() > 0 && newData == false) {
  //  rc = Serial1.read();

  dataIn.toCharArray(dataInChars, 64);
  // rc = Serial.read();

  if (recvInProgress == true) {
    if (dataInChars != endMarker) {
      receivedChars[ndx] = dataInChars;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      recvInProgress = false;
      ndx = 0;
      newData = true;
    }
  }

  else if (dataInChars == startMarker) {
    recvInProgress = true;
  }
  // } // end while (Serial1.available()

} // end void recvWithStartEndMarkers()

//============

void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
  poles = atoi(strtokIndx);     // step value

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  dwell = atoi(strtokIndx);     // dwell time

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  totSteps = atoi(strtokIndx);     // total number of steps

} // end void parseData()

void dateTime(uint16_t* date, uint16_t* time)
{

  SDyear = now.year();
  SDmonth = now.month();
  SDday = now.day();
  SDhour = now.hour();
  SDminute = now.minute();
  SDsecond = now.second();
  *date = FAT_DATE(SDyear, SDmonth, SDday);
  *time = FAT_TIME(SDhour, SDminute, SDsecond);

} // end void datetime


void error(char *str)
{
  Serial.print("error: ");
  Serial.println(str);
  Serial.println(errorNumb);

  // red LED indicates error
  //  digitalWrite(redLEDpin, HIGH);

  // display fault on screen

  if (errorNumb == 1) {
    Serial.println("Insert SD Card");
  }
  else if (errorNumb == 2) {
    Serial.println("Failed to Create File");
    Serial.println("Insert SD Card");
  }

  while (1);
} // end void error

void phase_setup() {

  // initialize start of phase parameters


  for (phaseNum = 0; phaseNum <= 10; phaseNum++) {
    Serial.println("Enter Phase Number");
    while (Serial.available() == 0) {} // wait for number of steps to be entered
    // poles = Serial.parseInt(); // set steps to entered value
    phaseNum = Serial.parseInt(); // set steps to entered value
    incr = poles; // set for first step
    Serial.read(); // clear serial buffer
    // Serial.println(poles);
    Serial.println(phaseNum);
    phaseCount = phaseCount = 1;

    if (phaseNum == 0) {
      return;
    } // end if(phaseNum == 0)
    /*
      Serial.println("Enter number of steps");
      while (Serial.available() == 0) {} // wait for number of steps to be entered
      // poles = Serial.parseInt(); // set steps to entered value
      phase[phaseNum][0] = Serial.parseInt(); // set steps to entered value
      incr = poles; // set for first step
      Serial.read(); // clear serial buffer
      // Serial.println(poles);
      Serial.println(phase[phaseNum][0]);
    */

    Serial.println("Enter Speed (0 to 100%)");
    while (Serial.available() == 0) {} // wait for Dwell Time to be entered
    //dwell = Serial.parseInt(); // set steps to entered value
    phase[phaseNum][0] = Serial.parseInt(); // set steps to entered value
    Serial.read(); // clear serial buffer
    //Serial.println(dwell);
    Serial.println(phase[phaseNum][0]);

    Serial.println("Enter Phase Time in milliseconds");
    while (Serial.available() == 0) {} // wait for Dwell Time to be entered
    // totSteps = Serial.parseInt(); // set total number of steps to entered value
    phase[phaseNum][1] = Serial.parseInt(); // set steps to entered value
    Serial.read(); // clear serial buffer
    //Serial.println(totSteps);
    Serial.println(phase[phaseNum][1]);

    Serial.println("Enter Pause Time in milliseconds");
    while (Serial.available() == 0) {} // wait for Dwell Time to be entered
    //dwell = Serial.parseInt(); // set steps to entered value
    phase[phaseNum][2] = Serial.parseInt(); // set steps to entered value
    Serial.read(); // clear serial buffer
    //Serial.println(dwell);
    Serial.println(phase[phaseNum][2]);


  } // for (phaseNum

} // end phase_setup
[/code]

And here is the error











C:\Users\EOFLOW\Documents\Arduino\Stepper_Control_6\Stepper_Control_6.ino: In function 'void setup()':
C:\Users\EOFLOW\Documents\Arduino\Stepper_Control_6\Stepper_Control_6.ino:140:40: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     error("Card failed, or not present");
                                        ^
C:\Users\EOFLOW\Documents\Arduino\Stepper_Control_6\Stepper_Control_6.ino: In function 'void recvWithStartEndMarkers()':
C:\Users\EOFLOW\Documents\Arduino\Stepper_Control_6\Stepper_Control_6.ino:231:24: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]
     if (dataInChars != endMarker) {
                        ^~~~~~~~~
C:\Users\EOFLOW\Documents\Arduino\Stepper_Control_6\Stepper_Control_6.ino:232:28: warning: invalid conversion from 'char*' to 'char' [-fpermissive]
       receivedChars[ndx] = dataInChars;
                            ^~~~~~~~~~~
C:\Users\EOFLOW\Documents\Arduino\Stepper_Control_6\Stepper_Control_6.ino:246:27: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]
   else if (dataInChars == startMarker) {
                           ^~~~~~~~~~~
Sketch uses 14030 bytes (43%) of program storage space. Maximum is 32256 bytes.
Global variables use 1592 bytes (77%) of dynamic memory, leaving 456 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Thanks for your help and let me know if you need any more info.

Post #9 asked for it and you did not honour the request.

But now we can have a look, thanks.

I saw both of your replies at the same time, not when they came in.

Thanks for looking it over for me

char daysOfTheWeek[7][10] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; // Saves 14 bytes

Move that to PROGMEM is the first advise.

1 Like
`Serial.print(F("Initializing SD card..."));` // Use program memory instead of RAM for many strings

The hidden Arduino Macro F() fixes random lock ups - Bald Engineer

If you currently judge the memory usage with those in the code, you are fooling yourself a bit at this stage; life might not be as bad as you think :wink:

So follow the advise on the F macro for all printing of fixed text and see how that goes.

Great, I'll make those changes and go from there.

Thanks again for your help