Digistump Forums
The Digispark => Digispark (Original) Support => Topic started by: ElectronicWar on March 01, 2013, 03:41:50 pm
-
So right now I assembled my LCD shield kit and the demos are working fine.
Next up, I wanted to write a simple program where I hard-code a bunch of strings which then get displayed on one line and get scrolled if too long (16 chars).
My code's working fine, but I can only manage to save like 3-4 messages without getting weird currupted memory problems (broken messages on the LCD included).
I'm new to embedded programming and have no real clue how to keep the messages out of the RAM.
Here's my code. It doesn't matter if I "save" the messages like this or if I loop through a char* list[] {...} array.
The following code is working fine and the 3 messages scroll endlessy (messages from slipsum.com for testing).
/* ATtiny85 as an I2C Master Ex2 BroHogan 1/21/11
* Modified for Digistump - Digispark LCD Shield by Erik Kettenburg 11/2012
* SETUP:
* ATtiny Pin 1 = (RESET) N/U ATtiny Pin 2 = (D3) N/U
* ATtiny Pin 3 = (D4) to LED1 ATtiny Pin 4 = GND
* ATtiny Pin 5 = SDA on DS1621 & GPIO ATtiny Pin 6 = (D1) to LED2
* ATtiny Pin 7 = SCK on DS1621 & GPIO ATtiny Pin 8 = VCC (2.7-5.5V)
* NOTE! - It's very important to use pullups on the SDA & SCL lines!
* PCA8574A GPIO was used wired per instructions in "info" folder in the LiquidCrystal_I2C lib.
* This ex assumes A0-A2 are set HIGH for an addeess of 0x3F
* LiquidCrystal_I2C lib was modified for ATtiny - on Playground with TinyWireM lib.
* TinyWireM USAGE & CREDITS: - see TinyWireM.h
*/
//#define DEBUG
#include <TinyWireM.h> // I2C Master lib for ATTinys which use USI - comment this out to use with standard arduinos
#include <LiquidCrystal_I2C.h> // for LCD w/ GPIO MODIFIED for the ATtiny85
#define GPIO_ADDR 0x27 // (PCA8574A A0-A2 @5V) typ. A0-A3 Gnd 0x20 / 0x38 for A - 0x27 is the address of the Digispark LCD modules.
#define LCD_CHARS 16
#define LCD_LINES 2
LiquidCrystal_I2C lcd(GPIO_ADDR, LCD_CHARS, LCD_LINES); // set address & 16 chars / 2 lines
void setup(){
TinyWireM.begin(); // initialize I2C lib - comment this out to use with standard arduinos
lcd.init(); // initialize the lcd
lcd.backlight(); // Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("Setup OK. Start.");
}
int currentMessageNumber = 0;
void blankDisplay()
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
}
void displayMessage(char* message)
{
int msgLen = strlen(message);
blankDisplay();
currentMessageNumber++;
lcd.print("Message ");
lcd.print(currentMessageNumber, DEC);
lcd.print(":");
lcd.setCursor(0, 1);
// Display message (and scroll it if too long)
char curItem[16];
for (int i = 0; i < (msgLen - LCD_CHARS + 1); i++)
{
for (int k = 0; k < LCD_CHARS; k++)
{
if (i + k < msgLen) {
curItem[k] = message[i+k];
} else {
curItem[k] = ' ';
}
}
lcd.setCursor(0, 1);
lcd.print(curItem);
if (i == 0) { delay(1000); } // To be able to read start of message
delay(350);
}
delay(2000);
}
void loop(){
currentMessageNumber = 0;
delay(1500);
displayMessage("Your bones don't break, mine do. That's clear.");
displayMessage("Your cells react to bacteria and viruses differently than mine. You don't get sick, I do.");
displayMessage("That's also clear. But for some reason, you and I react the exact same way to water.");
}
Now add the following lines and get weird results:
displayMessage("We swallow it too fast, we choke. We get some in our lungs, we drown.");
displayMessage("However unreal it may seem, we are connected, you and I. We're on the same curve, just on opposite ends.");
displayMessage("The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men.");
I'm pretty sure it's a problem with the 512K RAM, but how can I work around this problem?
My C++ knowledge is very basic unfortunately.
The binary size could hold like ~80 messages like this.
-
Also playing with the lcd right now, will test this out. Do you think it would be worthwhile to stack the I2C EEPROM board on at the same time? I think the two devices are at different addresses...
-
Crazy... screenshot attached. Compiler only reports 3,248 bytes used.
(http://emc2innovation.com/IMG_00000012.jpg)
-
Have you taken a look inside LiquidCrystal_I2C.cpp? There's a couple functions that look interesting:
// These commands scroll the display without changing the RAM
void LiquidCrystal_I2C::scrollDisplayLeft(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystal_I2C::scrollDisplayRight(void) {
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
I wonder if the scrolling messages are overflowing a char buffer somewhere.
-
Kinda wish the Arduino environment had a debugger. Might give this guy (http://www.visualmicro.com/post/2012/05/05/Debug-Arduino-Overview.aspx) a shot later.
-
I ran into the same thing with an overly large sketch on Arduino.
I'm not the expert but the Print command gets executed, the same string is held as the original and again when sent to the print, and it overflows the ram space.
I used this .. printf_P(PSTR("This string will be stored in flash memory")); ..to overcome it in ver 023.
Have a look at "Using Flash Memory for string storage" at
http://playground.arduino.cc/Main/Printf (http://playground.arduino.cc/Main/Printf)
Mark
-
Okay, quick primer on how modern computers (digispark included) work:
You have two kinds of memory - the stack and the heap. We'll be ignoring the heap for now. The stack is just like a stack of paper. You add bits to the top, and remove bits from the top, but that's all. Each time your program enters a new function it adds all it's variables to the top of the stack, then when you return it removes those variables freeing up that memory. This means that deeper you nest your functions, the taller the stack grows and the more memory you are using. Another implication is that as soon as you enter a function (even loop or setup) every variable you use in that function immediately consumes all of it's space in RAM, even if you haven't set it to anything yet! The Digispark only has 512 bytes of RAM and some of that is used by parts of the arduino environment. Your corruption is happening because you're allocating so much memory in the stack that it slams in to the heap (which also exists in RAM), where some objects like your LCD library maybe stored. Different parts of your program end up writing over the same sections of RAM, so you get corruption.
How can you work around this? The usual solutions people offer are to write in special PROGMEM keywords and things which store your strings in the flash, then have only one string variable you copy those strings in to just before you use them. This is complicated and annoying to explain to beginners, and still annoying to deal with even for advanced users, and it isn't even that efficient! But there's another way you can get exactly the same thing without having to write any weird code:
Break it up in to functions. For each string you want to write out to your LCD, make a function which just has that string, and sends it to your LCD. When you call this function from your main program it will automatically copy the string in to the stack, send it to your LCD, then because it returns after that, it will clear up that section of the stack making it available to the next part of your program.
void displayBonesBreak() { displayMessage("Your bones don't break, mine do. That's clear."); }
void displayCellsReact() { displayMessage("Your cells react to bacteria and viruses differently than mine. You don't get sick, I do."); }
void displayAlsoClear() { displayMessage("That's also clear. But for some reason, you and I react the exact same way to water."); }
Simple yeah? If you need to add some dynamic bits to your messages you can give those functions some arguments and process all that in the function. A nice side effect of this is that you can write in all your strings at the top of your program, then if people need to come in and change some bits later (translations and typos) it's easy for them to see all the messages in one place.
— <3 Bluebie
-
Thanks Bluebie, great info there!
That's the bane of using high-level programming languages only, you just don't care about such stuff ::)
Thanks Mark as well, gonna look into it, seems promising.
I also found the autoScroll() function in the LCD lib, gonna play around with it a bit, maybe my scrolling code is not needed anymore.
Cheers!
-
Hello Bluebie,
it seems, that I have a similar problem, which I reported in thread http://digistump.com/board/index.php/topic,752.0.html
However, when rewriting the program like you describe, i still run into crashes. Do you have any further ideas?
Are there tools available, to monitor heap and stack pointers and how much is free?
Regards
Gogol
-
I think it'd be better to use PROGMEM to have the data stored in flash and then use pgm_read_byte_near or pgm_read_word_near to get it.
a few more functions are ok but gogol pushed it to 30+ and it starts to look like a mess.
-
You can also use the F() macro, which also stores in flash and is a bit easier to deal with (in my experience anyways).. it's supported as of Arduino 1.0.
Example:
Serial.print(F("This is a really long string so we better store it in the flash so we don't run out of memory!"));
-
You can use the included avr tools.. I do this to check the usage on my regular arduinos.. (you don't have to use the --mcu argument either)..
Example:
/Applications/DigisparkArduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-size -C /var/folders/mm/d0mf5n6x0h1_mth8czb6hfkr0000gn/T/build4358590708087556964.tmp/Infrared.cpp.elf
AVR Memory Usage
----------------
Device: Unknown
Program: 1222 bytes
(.text + .data + .bootloader)
Data: 11 bytes
(.data + .bss + .noinit)
Hello Bluebie,
it seems, that I have a similar problem, which I reported in thread http://digistump.com/board/index.php/topic,752.0.html (http://digistump.com/board/index.php/topic,752.0.html)
However, when rewriting the program like you describe, i still run into crashes. Do you have any further ideas?
Are there tools available, to monitor heap and stack pointers and how much is free?
Regards
Gogol
-
Hi sorphin,
thanks for that tip, that is exactly, what I have expected!
regards
Gogol