minimalistic mode for smaller memory

I wrote a simple sketch to be run with the ArduinoTiny project. The target is an ATTiny2313. The simple sketch came out to be 4200Bytes. When written in C code, its only 800.

I’d like to suggest a checkbox that will compile a sketch in minimalistic mode.

Here is the code which I am talking about.

/*
Barnes and Nobel Nook Tablet Mod Chip
 Copyright 2011 Adam Outler - hkvc
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -Adam Outler  adamoutler, gmail.com
 
 */

boolean Position[3]={true,true,true};//Place holders for operation
int inByte; //current byte
String Message=""; //current string of bytes
//begin sketch

void setup() {
  Serial.begin(115200); //Initialize UART and set baud for serial
  Serial.println("I are your god now");
  }
void loop() {
  if (Serial.available()) {
    inByte = Serial.read();
    if ( inByte == 10 ){
      Message="";
    } 
    else {
      Message=Message +(char)inByte; //dump char into string
      if (Message == "OMAP44XX SDP # "){
        if ( Position[1]){
          Serial.println("O hai Nook Im in ur memory");
          Serial.println("mmcinit 0; fatload mmc 0:1 0x81000000 new.flashing_boot.img;");
          Serial.println("Mai kernel is ur kernel");
          Position[1]=(!Position[1]);
          return;

        } else if ( Position[2]){
          Serial.println("Ur Security is my target");
          Serial.println("mw.l 80e84794 e1a00000; mw.l 80e847fc e1a00000; mw.l 80e84808 e1a00000; mw.l 80e847a0 e1a00000;");
          Serial.println("Ur Security is neutralized");
          Position[2]=(!Position[2]);
          return;
        } 
        else if ( Position[3]){
          Serial.println("boot mai kernel now");
          Serial.print("booti 0x81000000");
          Serial.println("k thx bai");
          Position[3]=(!Position[3]);
          return;
        }
      }  
    }
  }
  if (millis()>=60000){
    lockup;
  }
}
void lockup(){
  while(true){
    delay(50000);//program cannot end, only sleep
  }
}

The basic gist of this program is to monitor for a string, then respond with one of 3 strings. I added some extra stuff into it as well.

The problem is that this compiles over 4K and it does not need to be more than 1K. Here’s a similar program written in all C.

#include <avr/io.h>
#include <avr/pgmspace.h>

// Use a 3.6864MHz clock
#define F_CPU   3686400UL
#define BAUD   115200UL

// Must be loaded after defines above
#include <util/setbaud.h>

// These strings won't fit in RAM
char LOADMMC[] PROGMEM = "mmcinit 0; fatload mmc 0:1 0x81000000 new.flashing_boot.img;";
char OPCODES[] PROGMEM = "mw.l 80e84794 e1a00000; mw.l 80e847fc e1a00000; mw.l 80e84808 e1a00000; mw.l 80e847a0 e1a00000;";
char BOOTCMD[] PROGMEM = "booti 0x81000000";

void uart_putchar(char c) {
   // Wait until transmitter ready
   loop_until_bit_is_set(UCSRA, UDRE);
   UDR = c;
}

void uart_puts_progmem(char *s) {
   char b;
   // While the byte read from flash isn't a null byte, keep sending
   while ('\0' != (b = pgm_read_byte(s++))) {
      uart_putchar(b);
   }
}

void init_uart() {
   // Set baud rate using setbaud macros
   UBRRH = UBRRH_VALUE;
   UBRRL = UBRRL_VALUE;
   #if USE_2X
   UCSRA |= _BV(U2X);
   #else
   UCSRA &= ~_BV(U2X);
   #endif
   
   // Enable receiver/transmitter
   UCSRB = _BV(RXEN) | _BV(TXEN);
   
   // TxD pin PD1 set to output
   DDRD |= _BV(PD1);
   // RxD pin PD0 set to input
   DDRD &= ~_BV(PD0);
}

void send_string(int i) {
   switch (i) {
      case 0:
         uart_puts_progmem(BOOTCMD);
         break;
      case 1:
         uart_puts_progmem(OPCODES);
         break;
      case 2:
         uart_puts_progmem(LOADMMC);

         // Disable interrupts and put the micro to sleep - it will never wake up ( :( )
         asm("CLI");
         MCUCR |= _BV(SM1) | _BV(SM0) | _BV(SE);
         asm("SLEEP");
         break;
   }
}

int main(void)
{
   char c;
   int state, i;
   
   // Turn off peripherals we aren't using
   PRR |= _BV(PRTIM1) | _BV(PRTIM0) | _BV(PRUSI);

   init_uart();
   
    while(1)
    {
      // Use a state machine to detect the prompt
        if (UCSRA & _BV(RXC)) {
         c = UDR;
         switch (state) {
            case 0:
               if (c == 'S') state++;
               break;
            case 1:
               if (c == 'D') state++;
               else state = 0;
               break;
            case 2:
               if (c == 'P') state++;
               else state = 0;
               break;
            case 3:
               if (c == ' ') state++;
               else state = 0;
               break;
            case 4:
               if (c == '#') state++;
               else state = 0;
               break;
            case 5:
               if (c == ' ') send_string(i++);
               state = 0;
               break;
         }
      }
    }
}

It seems to me that size would be a concern when prototyping.

Thanks for reading and considering this proposal for a minimalistic compilation option.

I wrote a simple sketch to be run with the ArduinoTiny project. The target is an ATTiny2313. The simple sketch came out to be 4200Bytes. When written in C code, its only 800.

I’d like to suggest a checkbox that will compile a sketch in minimalistic mode.

That would preclude this:

String Message=""; //current string of bytes

No wonder the sketch was smaller in C.

What are you pointing out there?

I didn't bother troubleshooting past removing all lines of code. serial.begin makes the sketch take up around 1K of the available memory. It does not seem like it should be that large. UART is a very simple protocol.

What are you pointing out there?

That you are comparing apples and water buffaloes. The String class is horribly inefficient, compared to char arrays.

I didn't bother troubleshooting past removing all lines of code. serial.begin makes the sketch take up around 1K of the available memory.

Flash or SRAM?

UART is a very simple protocol.

Sure. But there are input and output buffers, and interrupts to minimize the impact of the input and output of data on the rest of the sketch. They take up SRAM memory.

AdamOutler: What are you pointing out there?

I didn't bother troubleshooting past removing all lines of code. serial.begin makes the sketch take up around 1K of the available memory. It does not seem like it should be that large. UART is a very simple protocol.

Using Arduino APIs is more about convenience than code size. Don't forget the primary audience of the arduino platform. This doesn't mean the devs should carelessly produce bloated code, nor that the current core libs are unimprovable, but saying "it doesn't seem like it should be that large" is like implying they're putting useless fancy routines into Serial for no reason. Instead of accusing the Arduino team of being incompetent, you should probably take a look at the source code of Serial and discuss here how it could be improved.

UART is a very simple protocol.

I thought UART was a device, not a protocol.

http://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter

Ok that was enough for a useless polemical comment :-)

Back IT, I think there can be no "minimalistic" mode. How can a compiler or even a more complex piece of software convert the first of the two examples you wrote into the second ?

One could probably identify some convenience functions that Arduino core classes provide and that can be selectively "turned off" to save space if one is willing to loose some functionality or ease of use (IIRC there is a recurring argument like this one about digitalWrite vs. direct port manipulation). Provided this makes sense, it can probably be implemented via conditional compilation (#ifdefs in the libraries, #defines in the sketch).