• Garbage out without garbage in (ATTiny serial problems)

    Selali Adobor10/24/2016 at 00:49 0 comments

    After moving on from the flash issue I tried implementing a simple heartbeat check for the GSM module.

    When you send the text "AT" you should get the response, "OK" back*

    *The GSM module echos back everything you send, so the full string is really "AT <newline> OK"

    What I was getting from the debug port was this:

    Attempting to read from SIM800
    Read line from SIM800: ???K
    

    I'll start by saying the decision to keep the debug port already proved invaluable. When I tried having the ATTiny send the "AT" response while the GSM module was hooked up to my USB-to-Serial breakout, I was getting "AT <newline> OK" as expected.

    That meant the ATTiny was getting exactly the correct response, but something was wrong with the ATTiny's serial receiving routine.

    All I had to go on was the fact I was getting the correct number of characters, and the ATTiny was sending "AT" as it should.

    The fix turned out to be pretty straight forward though, simply adding the line:

    delay(500);
    before and after my sleep function gave me what I expected:
    Attempting to read from SIM800
    Read line from SIM800: AT <newline> OK
    

    ...kind of.


    There was supposed to be a debug statement that contained what I was sending to the sim module, and sometimes I was still getting garbage.

    But it was progress.


    TinyDebugSerial and SoftwareSerial are very sensitive to timing because they implement UART without the supporting hardware. Shortening my debug statements (thus having fewer statements overlapping between the two) produced reliable output without sleep statements:

    writeSim: AT
    readSim: AT <newline> OK

  • When I ran out of flash (and how avr-nm saved the day)

    Selali Adobor10/23/2016 at 16:16 0 comments

    I wanted to have a convenient debug port that I could use to see what was going on when my ATTiny talked to the GSM module.

    I went with TinySerialDebug, a transmit-only library and everything was working great.. until I added the SoftwareSerial library:

    I was out of flash on my ATTiny85.

    Meaning my firmware's code was taking too much space on the constrained ATTiny85.

    A flag that disabled all the debug port related code, brought me back under the space limit, but I definitely needed a way to talk to the GSM module (the ATTiny doesn't have hardware UART). And I really wanted a debug port because talking to the GSM module was going to be hard enough to debug without some way to tell what the ATTiny was saying. So I set about solving the space issue without cutting either library.

    My first instinct was that SoftwareSerial was too large, since it implements the entire Stream interface that Arduino provides, which has a ton of convenience functions.

    I looked up ways to optimize sketch size, but realized, while I did suspect SoftwareSerial was the culprit here, I hadn't actually proven it was what was eating up all my flash space.

    Some searching brought me to avr-nm. It's a utility that takes an "elf" file ( the firmware that gets uploaded to the AVR) and spits out something like this:

    avr-nm --size-sort -Crtd firmware.elf
    00000390 T realloc
    00000304 T malloc
    00000286 T free
    00000244 T __vector_2

    Those are functions defined in my code, and in the libraries that I imported sorted by the amount of space they were taking up.

    That screenshot is from after I fixed the issue. Here's one from before I fixed it:

    avr-nm --size-sort -Crtd firmware.elf       
    00000734 T dtoa_prf
    00000432 T __ftoa_engine
    00000390 T realloc
    00000304 T malloc
    I bolded the two functions that stuck out the most. They stuck out not only because they were taking the most space, but because if dtoa did what I thought it did, converted a double to a string (which is what it does), there was no mission-critical code that should be calling it.


    So if I knew that I didn't need to convert numbers to strings for anything related to the end goal of the project, where could I have been calling it?
    void watchdogSleep(const double seconds)
    ...
      debug.print("Entering sleep for ");
      debug.print(String(seconds));
                  ^
      debug.println(" seconds");
    ...
    Some background:

    The watchdogSleep function uses the ATTiny's watchdog timer to "fake" long term sleeping. The watchdog is set to 8 seconds (it's max value), the ATTiny goes to sleep, and the watchdog timer wakes it back up. It repeats this until enough seconds have passed in 8 seconds increments.

    That debug statement to let me know that it was going to sleep.

    But my debug statement had this line:

    debug.print(String(seconds));
    It was taking 'seconds', a 'double', and turning it into a 'String'. Doing so was bringing in the 'dtoa' function, which was massive compared to the the serial code (Neither serial library even came in the top 5 functions for memory usage)

    To put into perspective how large it was, even changing that line to:

    debug.print(String((int)seconds));

    (note the added cast to int), was enough to bring me back under the limit!

    I ended up adding an overload to the `print` method that took an integer, and changed the type of seconds to an unsigned int. A double never really made sense anyways, a negative value would have left the player sleeping forever, and the resolution was limited to 1 second increments at best.

    While going through space optimization guides I also realized how wasteful Arduino's String() could be, so I have one more task to take on before calling the flash issue completely solved, but won't have to worry about hitting the limits of the ATTiny85 just yet.