Skip to content

Commit db78876

Browse files
committed
Detect RAM usage and stop if full
This resolves issue arduino#1356 and add the ability for the Arduino IDE to detect the amount of RAM allocated to a sketch and compare that to the available RAM on each board. If RAM is more than 90% full, it will fail on building since there is not enough free RAM for the heap and stack to use.
1 parent c97a710 commit db78876

File tree

3 files changed

+82
-18
lines changed

3 files changed

+82
-18
lines changed

Diff for: app/src/processing/app/Sketch.java

+31-7
Original file line numberDiff line numberDiff line change
@@ -1637,24 +1637,48 @@ public void setCompilingProgress(int percent) {
16371637

16381638
protected void size(String buildPath, String suggestedClassName)
16391639
throws RunnerException {
1640-
long size = 0;
1641-
String maxsizeString = Base.getBoardPreferences().get("upload.maximum_size");
1642-
if (maxsizeString == null) return;
1643-
long maxsize = Integer.parseInt(maxsizeString);
1640+
long textSize = 0;
1641+
long dataSize = 0;
1642+
String maxTextSizeString = Base.getBoardPreferences().get("upload.maximum_size");
1643+
String maxDataSizeString = Base.getBoardPreferences().get("upload.maximum_data_size");
1644+
if (maxTextSizeString == null) return;
1645+
long maxTextSize = Integer.parseInt(maxTextSizeString);
1646+
long maxDataSize = -1;
1647+
if(maxDataSizeString != null)
1648+
maxDataSize = Integer.parseInt(maxDataSizeString);
16441649
Sizer sizer = new Sizer(buildPath, suggestedClassName);
16451650
try {
1646-
size = sizer.computeSize();
1651+
long[] sizes = sizer.computeSize();
1652+
textSize = sizes[0];
1653+
dataSize = sizes[1];
16471654
System.out.println(
16481655
I18n.format(
16491656
_("Binary sketch size: {0} bytes (of a {1} byte maximum)"),
1650-
size, maxsize
1657+
textSize, maxTextSize
16511658
)
16521659
);
1660+
if(maxDataSize > 0) {
1661+
System.out.println(
1662+
I18n.format(
1663+
_("Memory usage: {0} bytes (of a {1} byte maximum)"),
1664+
dataSize, maxDataSize
1665+
)
1666+
);
1667+
} else {
1668+
System.out.println(
1669+
I18n.format(
1670+
_("Memory usage: {0} bytes"),
1671+
dataSize
1672+
)
1673+
);
1674+
}
16531675
} catch (RunnerException e) {
16541676
System.err.println(I18n.format(_("Couldn't determine program size: {0}"), e.getMessage()));
16551677
}
16561678

1657-
if (size > maxsize)
1679+
/* At least 10% of RAM should be reserved for stack/heap usage */
1680+
if (textSize > maxTextSize ||
1681+
(maxDataSize > 0 && dataSize > maxDataSize*9/10))
16581682
throw new RunnerException(
16591683
_("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
16601684
}

Diff for: app/src/processing/app/debug/Sizer.java

+33-11
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,32 @@
3333
public class Sizer implements MessageConsumer {
3434
private String buildPath, sketchName;
3535
private String firstLine;
36-
private long size;
36+
private long textSize;
37+
private long dataSize;
38+
private long eepromSize;
3739
private RunnerException exception;
3840

3941
public Sizer(String buildPath, String sketchName) {
4042
this.buildPath = buildPath;
4143
this.sketchName = sketchName;
4244
}
4345

44-
public long computeSize() throws RunnerException {
46+
public long[] computeSize() throws RunnerException {
4547
String avrBasePath = Base.getAvrBasePath();
4648
String commandSize[] = new String[] {
4749
avrBasePath + "avr-size",
50+
"-A",
4851
" "
4952
};
5053

51-
commandSize[1] = buildPath + File.separator + sketchName + ".hex";
54+
commandSize[2] = buildPath + File.separator + sketchName + ".elf";
5255

5356
int r = 0;
5457
try {
5558
exception = null;
56-
size = -1;
59+
textSize = -1;
60+
dataSize = -1;
61+
eepromSize = -1;
5762
firstLine = null;
5863
Process process = Runtime.getRuntime().exec(commandSize);
5964
MessageSiphon in = new MessageSiphon(process.getInputStream(), this);
@@ -80,10 +85,10 @@ public long computeSize() throws RunnerException {
8085
if (exception != null)
8186
throw exception;
8287

83-
if (size == -1)
88+
if (textSize == -1)
8489
throw new RunnerException(firstLine);
8590

86-
return size;
91+
return new long[] { textSize, dataSize, eepromSize };
8792
}
8893

8994
public void message(String s) {
@@ -92,15 +97,32 @@ public void message(String s) {
9297
else {
9398
StringTokenizer st = new StringTokenizer(s, " ");
9499
try {
95-
st.nextToken();
96-
st.nextToken();
97-
st.nextToken();
98-
size = (new Integer(st.nextToken().trim())).longValue();
100+
String section = st.nextToken();
101+
if(!section.startsWith("."))
102+
return;
103+
long bytes = (new Integer(st.nextToken().trim())).longValue();
104+
//long addr = (new Integer(st.nextToken().trim())).longValue();
105+
//System.out.println("Section: " + section + " with " + bytes + " bytes at address " + addr);
106+
if(section.equals(".text") || section.equals(".data") || section.equals(".bootloader")) {
107+
if(textSize < 0)
108+
textSize = 0;
109+
textSize += bytes;
110+
}
111+
if(section.equals(".data") || section.equals(".bss") || section.equals(".noinit")) {
112+
if(dataSize < 0)
113+
dataSize = 0;
114+
dataSize += bytes;
115+
}
116+
if(section.equals(".eeprom")) {
117+
if(eepromSize < 0)
118+
eepromSize = 0;
119+
eepromSize += bytes;
120+
}
99121
} catch (NoSuchElementException e) {
100122
exception = new RunnerException(e.toString());
101123
} catch (NumberFormatException e) {
102124
exception = new RunnerException(e.toString());
103125
}
104126
}
105127
}
106-
}
128+
}

Diff for: hardware/arduino/boards.txt

+18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
uno.name=Arduino Uno
66
uno.upload.protocol=arduino
77
uno.upload.maximum_size=32256
8+
uno.upload.maximum_data_size=2048
89
uno.upload.speed=115200
910
uno.bootloader.low_fuses=0xff
1011
uno.bootloader.high_fuses=0xde
@@ -24,6 +25,7 @@ atmega328.name=Arduino Duemilanove w/ ATmega328
2425

2526
atmega328.upload.protocol=arduino
2627
atmega328.upload.maximum_size=30720
28+
atmega328.upload.maximum_data_size=2048
2729
atmega328.upload.speed=57600
2830

2931
atmega328.bootloader.low_fuses=0xFF
@@ -45,6 +47,7 @@ diecimila.name=Arduino Diecimila or Duemilanove w/ ATmega168
4547

4648
diecimila.upload.protocol=arduino
4749
diecimila.upload.maximum_size=14336
50+
diecimila.upload.maximum_data_size=1024
4851
diecimila.upload.speed=19200
4952

5053
diecimila.bootloader.low_fuses=0xff
@@ -66,6 +69,7 @@ nano328.name=Arduino Nano w/ ATmega328
6669

6770
nano328.upload.protocol=arduino
6871
nano328.upload.maximum_size=30720
72+
nano328.upload.maximum_data_size=2048
6973
nano328.upload.speed=57600
7074

7175
nano328.bootloader.low_fuses=0xFF
@@ -87,6 +91,7 @@ nano.name=Arduino Nano w/ ATmega168
8791

8892
nano.upload.protocol=arduino
8993
nano.upload.maximum_size=14336
94+
nano.upload.maximum_data_size=1024
9095
nano.upload.speed=19200
9196

9297
nano.bootloader.low_fuses=0xff
@@ -213,6 +218,7 @@ mini328.name=Arduino Mini w/ ATmega328
213218

214219
mini328.upload.protocol=arduino
215220
mini328.upload.maximum_size=28672
221+
mini328.upload.maximum_data_size=2048
216222
mini328.upload.speed=115200
217223

218224
mini328.bootloader.low_fuses=0xff
@@ -234,6 +240,7 @@ mini.name=Arduino Mini w/ ATmega168
234240

235241
mini.upload.protocol=arduino
236242
mini.upload.maximum_size=14336
243+
mini.upload.maximum_data_size=1024
237244
mini.upload.speed=19200
238245

239246
mini.bootloader.low_fuses=0xff
@@ -255,6 +262,7 @@ ethernet.name=Arduino Ethernet
255262

256263
ethernet.upload.protocol=arduino
257264
ethernet.upload.maximum_size=32256
265+
ethernet.upload.maximum_data_size=2048
258266
ethernet.upload.speed=115200
259267

260268
ethernet.bootloader.low_fuses=0xff
@@ -276,6 +284,7 @@ fio.name=Arduino Fio
276284

277285
fio.upload.protocol=arduino
278286
fio.upload.maximum_size=30720
287+
fio.upload.maximum_data_size=2048
279288
fio.upload.speed=57600
280289

281290
fio.bootloader.low_fuses=0xFF
@@ -297,6 +306,7 @@ bt328.name=Arduino BT w/ ATmega328
297306

298307
bt328.upload.protocol=arduino
299308
bt328.upload.maximum_size=28672
309+
bt328.upload.maximum_data_size=2048
300310
bt328.upload.speed=19200
301311
bt328.upload.disable_flushing=true
302312

@@ -319,6 +329,7 @@ bt.name=Arduino BT w/ ATmega168
319329

320330
bt.upload.protocol=arduino
321331
bt.upload.maximum_size=14336
332+
bt.upload.maximum_data_size=1024
322333
bt.upload.speed=19200
323334
bt.upload.disable_flushing=true
324335

@@ -362,6 +373,7 @@ lilypad328.name=LilyPad Arduino w/ ATmega328
362373

363374
lilypad328.upload.protocol=arduino
364375
lilypad328.upload.maximum_size=30720
376+
lilypad328.upload.maximum_data_size=2048
365377
lilypad328.upload.speed=57600
366378

367379
lilypad328.bootloader.low_fuses=0xFF
@@ -383,6 +395,7 @@ lilypad.name=LilyPad Arduino w/ ATmega168
383395

384396
lilypad.upload.protocol=arduino
385397
lilypad.upload.maximum_size=14336
398+
lilypad.upload.maximum_data_size=1024
386399
lilypad.upload.speed=19200
387400

388401
lilypad.bootloader.low_fuses=0xe2
@@ -404,6 +417,7 @@ pro5v328.name=Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega328
404417

405418
pro5v328.upload.protocol=arduino
406419
pro5v328.upload.maximum_size=30720
420+
pro5v328.upload.maximum_data_size=2048
407421
pro5v328.upload.speed=57600
408422

409423
pro5v328.bootloader.low_fuses=0xFF
@@ -425,6 +439,7 @@ pro5v.name=Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega168
425439

426440
pro5v.upload.protocol=arduino
427441
pro5v.upload.maximum_size=14336
442+
pro5v.upload.maximum_data_size=1024
428443
pro5v.upload.speed=19200
429444

430445
pro5v.bootloader.low_fuses=0xff
@@ -446,6 +461,7 @@ pro328.name=Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega328
446461

447462
pro328.upload.protocol=arduino
448463
pro328.upload.maximum_size=30720
464+
pro328.upload.maximum_data_size=2048
449465
pro328.upload.speed=57600
450466

451467
pro328.bootloader.low_fuses=0xFF
@@ -467,6 +483,7 @@ pro.name=Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega168
467483

468484
pro.upload.protocol=arduino
469485
pro.upload.maximum_size=14336
486+
pro.upload.maximum_data_size=1024
470487
pro.upload.speed=19200
471488

472489
pro.bootloader.low_fuses=0xc6
@@ -488,6 +505,7 @@ atmega168.name=Arduino NG or older w/ ATmega168
488505

489506
atmega168.upload.protocol=arduino
490507
atmega168.upload.maximum_size=14336
508+
atmega168.upload.maximum_data_size=1024
491509
atmega168.upload.speed=19200
492510

493511
atmega168.bootloader.low_fuses=0xff

0 commit comments

Comments
 (0)