I'm building this for an ATTiny2313A which has 2K of flash and 128 Bytes of RAM. It produced a 3.8K HEX file and the output below. This is my first real project in AVR studio other than just blinking an LED.
So if I understand this correctly the output should fit? 1.3K for the program and 44Bytes of RAM in use?
I noticed also it said debug, but since I'll be flashing the hex with a third party device I don't need any debug support, so that should be something I can turn off to save space, right? Is 44Bytes of RAM all it needs total, or is that just an estimate?
The code I'm using below won't be the final version. I just found a similar project and am basing mine off of it. I may need more space because I'll be adding more custom characters/symbols. So I may need a little more RAM.
Also I need to make sure I don't mess up and make it so I can't reprogram the chip if I need to. I prefer to use MOSI,MISO,SCK which is easy to do from an Arduino as a programmer. I've also got a cheap chinese USB programmer that I have managed to get working with AVRDude in the past, it also programs using MOSI,MISO,SCK.
------ Build started: Project: Scroll, Configuration: Debug AVR ------
Build started.
Project "Scroll.cproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files\Atmel\Atmel Studio 6.1\Vs\Compiler.targets" from project "C:\Users\stonent\Documents\Atmel Studio\6.1\Scroll\Scroll\Scroll.cproj" (target "Build" depends on it):
Task "RunCompilerTask"
C:\Program Files\Atmel\Atmel Studio 6.1\shellUtils\make.exe all
Building file: .././Scroll.c
Invoking: AVR/GNU C Compiler : 3.4.2
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-gcc.exe" -funsigned-char -funsigned-bitfields -DDEBUG -O1 -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -g2 -Wall -mmcu=attiny2313a -c -std=gnu99 -MD -MP -MF "Scroll.d" -MT"Scroll.d" -MT"Scroll.o" -o "Scroll.o" ".././Scroll.c"
Finished building: .././Scroll.c
Building target: Scroll.elf
Invoking: AVR/GNU Linker : 3.4.2
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-gcc.exe" -o Scroll.elf Scroll.o -Wl,-Map="Scroll.map" -Wl,--start-group -Wl,-lm -Wl,--end-group -Wl,--gc-sections -mmcu=attiny2313a
Finished building target: Scroll.elf
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature "Scroll.elf" "Scroll.hex"
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-objcopy.exe" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex "Scroll.elf" "Scroll.eep" || exit 0
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-objdump.exe" -h -S "Scroll.elf" > "Scroll.lss"
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-objcopy.exe" -O srec -R .eeprom -R .fuse -R .lock -R .signature "Scroll.elf" "Scroll.srec"
"C:\Program Files\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.2.1002\avr8-gnu-toolchain\bin\avr-size.exe" "Scroll.elf"
text data bss dec hex filename
1320 30 14 1364 554 Scroll.elf
Done executing task "RunCompilerTask".
Task "RunOutputFileVerifyTask"
Program Memory Usage : 1350 bytes 65.9 % Full
Data Memory Usage : 44 bytes 34.4 % Full
Done executing task "RunOutputFileVerifyTask".
Done building target "CoreBuild" in project "Scroll.cproj".
Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != '').
Target "Build" in file "C:\Program Files\Atmel\Atmel Studio 6.1\Vs\Avr.common.targets" from project "C:\Users\stonent\Documents\Atmel Studio\6.1\Scroll\Scroll\Scroll.cproj" (entry point):
Done building target "Build" in project "Scroll.cproj".
Done building project "Scroll.cproj".
Build succeeded.
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
//-----------------------------------------------------------------------------
// BMATRIX: NECKLACE with LED-MATRIX that displays text messages
//
// Based on Nuts&Volts Jul 2013 article: "Smart Necklace", p. 40
//
// Author : Bruce E. Hall bhall66@gmail.com
// Website : http://w8bh.net
// Version : 1.0
// Date : 27 Jul 2013
// Target : ATTINY4313 or ATTINY2313 microcontroller
// Language : C, using AVR studio 6
//
// ---------------------------------------------------------------------------
//
// Uses LITE-ON LTP-757G 5x7 LED MATRIX (Column Cathode) Display
//
// LED to ATTINY4313 b PORTA PORTB PORTD
// ---------------------------------- ------------------------
// LED FUNCTION to PORT (PIN) 7 - - -
// ---------------------------------- 6 - row0 -
// Col 0 - PD1 // Row 0 - PB6 5 - row1 -
// Col 1 - PA0 // Row 1 - PB5 4 - col2 row6
// Col 2 - PB4 // Row 2 - PA1 3 - row3 row5
// Col 3 - PB1 // Row 3 - PB3 2 - col4 row4
// Col 4 - PB2 // Row 4 - PD2 1 row2 col3 col0
// // Row 5 - PD3 0 col1 - -
// // Row 6 - PD4
//
// Since this a column cathode display,
// Columns are active LOW; to set a col, PORTx &= ~(1<<bit)
// Rows are active HIGH; to set a row, PORTx ~= (1<<bit)
//
// Fuse settings: 4 MHz osc with 65 ms Delay, SPI enable; *NO* clock/8
// ---------------------------------------------------------------------------
// DEFINES
#define F_CPU 4000000L // run CPU at 4 MHz
#define ROWS 7 // LED matrix has 7 rows, 5 columns
#define COLS 5
#define SCROLLDELAY 15 // delay in cs between column shifts
#define FLASHDELAY 17 // delay in cs between symbol flashes
#define BEATDELAY 30 // delay in cs between heartbeats
#define HEARTCHAR 99
#define TEXT1 "I Love You! "
#define TEXT2 "Ich Liebe Dich! "
// ---------------------------------------------------------------------------
// INCLUDES
#include <avr/io.h> // deal with port registers
#include <avr/interrupt.h> // deal with interrupt calls
#include <avr/pgmspace.h> // put character data into progmem
#include <util/delay.h> // used for _delay_ms function
#include <string.h> // string manipulation routines
#include <avr/sleep.h> // used for sleep functions
// ---------------------------------------------------------------------------
// GLOBAL VARIABLES
char buf[12]; // display buffer; each byte = 1 column
// buf[0] is the left-most column (col0)
// buf[4] is the right-most column (col4)
// buf[5] is a blank column between chars
// buf[6]..buf[10] are scrolled onto display
int curCol; // current column; values 0-4
const unsigned char FONT_CHARS[107][5] PROGMEM =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // (space)
{ 0x00, 0x00, 0x5F, 0x00, 0x00 }, // !
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
{ 0x14, 0x7F, 0x14, 0x7F, 0x14 }, // #
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12 }, // $
{ 0x23, 0x13, 0x08, 0x64, 0x62 }, // %
{ 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
{ 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
{ 0x00, 0x1C, 0x22, 0x41, 0x00 }, // (
{ 0x00, 0x41, 0x22, 0x1C, 0x00 }, // )
{ 0x08, 0x2A, 0x1C, 0x2A, 0x08 }, // *
{ 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
{ 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,
{ 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
{ 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
{ 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
{ 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
{ 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
{ 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
{ 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
{ 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
{ 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
{ 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
{ 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
{ 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
{ 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
{ 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
{ 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
{ 0x00, 0x08, 0x14, 0x22, 0x41 }, // <
{ 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
{ 0x41, 0x22, 0x14, 0x08, 0x00 }, // >
{ 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
{ 0x32, 0x49, 0x79, 0x41, 0x3E }, // @
{ 0x7E, 0x11, 0x11, 0x11, 0x7E }, // A
{ 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
{ 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
{ 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
{ 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
{ 0x7F, 0x09, 0x09, 0x01, 0x01 }, // F
{ 0x3E, 0x41, 0x41, 0x51, 0x32 }, // G
{ 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
{ 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
{ 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
{ 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
{ 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
{ 0x7F, 0x02, 0x04, 0x02, 0x7F }, // M
{ 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
{ 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
{ 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
{ 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
{ 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
{ 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
{ 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
{ 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
{ 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
{ 0x7F, 0x20, 0x18, 0x20, 0x7F }, // W
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
{ 0x03, 0x04, 0x78, 0x04, 0x03 }, // Y
{ 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
{ 0x00, 0x00, 0x7F, 0x41, 0x41 }, // [
{ 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"
{ 0x41, 0x41, 0x7F, 0x00, 0x00 }, // ]
{ 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
{ 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
{ 0x00, 0x01, 0x02, 0x04, 0x00 }, // `
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
{ 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
{ 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
{ 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
{ 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
{ 0x08, 0x14, 0x54, 0x54, 0x3C }, // g
{ 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
{ 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
{ 0x20, 0x40, 0x44, 0x3D, 0x00 }, // j
{ 0x00, 0x7F, 0x10, 0x28, 0x44 }, // k
{ 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
{ 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
{ 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
{ 0x7C, 0x14, 0x14, 0x14, 0x08 }, // p
{ 0x08, 0x14, 0x14, 0x18, 0x7C }, // q
{ 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
{ 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
{ 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
{ 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
{ 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
{ 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
{ 0x0C, 0x50, 0x50, 0x50, 0x3C }, // y
{ 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
{ 0x00, 0x08, 0x36, 0x41, 0x00 }, // {
{ 0x00, 0x00, 0x7F, 0x00, 0x00 }, // |
{ 0x00, 0x41, 0x36, 0x08, 0x00 }, // }
{ 0x08, 0x08, 0x2A, 0x1C, 0x08 }, // ->
{ 0x08, 0x1C, 0x2A, 0x08, 0x08 }, // <-
{ 0xFF, 0x41, 0x5D, 0x41, 0xFF }, // 096: psycho 2
{ 0x00, 0x3E, 0x22, 0x3E, 0x00 }, // 097: psycho 1
{ 0x06, 0x15, 0x69, 0x15, 0x06 }, // 098: nuke
{ 0x0C, 0x1E, 0x3C, 0x1E, 0x0C }, // 099: solid heart
{ 0x0C, 0x12, 0x24, 0x12, 0x0C }, // 100: outline heart
{ 0x0A, 0x00, 0x55, 0x00, 0x0A }, // 101: flower
{ 0x08, 0x14, 0x2A, 0x14, 0x08 }, // 102: diamond
{ 0x07, 0x49, 0x71, 0x49, 0x07 }, // 103: cup
{ 0x22, 0x14, 0x6B, 0x14, 0x22 }, // 104: star2
{ 0x36, 0x36, 0x08, 0x36, 0x36 }, // 105: star3
{ 0x0F, 0x1A, 0x3E, 0x1A, 0x0F } // 106: fox
};
// ---------------------------------------------------------------------------
// INTERRUPT SERVICE ROUTINE
//
// Function: Light a column on the LED matrix display, according to contents
// of display buffer. buf[0] = leftmost column; buf[4] = rightmost
//
// This routine is called about 390 times per second, yielding a refresh
// rate for the whole display of 390/5 = 78 frames per second.
ISR (TIMER0_COMPA_vect)
{
if (++curCol >= COLS) // advance column counter
curCol = 0;
// turn off all LEDS, by taking cathode (column) pins high
PORTA = 0x01;
PORTB = 0x16;
PORTD = 0x02;
// turn on individual row bits in this column
char i = buf[curCol];
if (i & _BV(0)) PORTB |= _BV(6);
if (i & _BV(1)) PORTB |= _BV(5);
if (i & _BV(2)) PORTA |= _BV(1);
if (i & _BV(3)) PORTB |= _BV(3);
if (i & _BV(4)) PORTD |= _BV(2);
if (i & _BV(5)) PORTD |= _BV(3);
if (i & _BV(6)) PORTD |= _BV(4);
// turn selected column on
switch(curCol)
{
case 0: PORTD &= ~_BV(1); break;
case 1: PORTA &= ~_BV(0); break;
case 2: PORTB &= ~_BV(4); break;
case 3: PORTB &= ~_BV(1); break;
case 4: PORTB &= ~_BV(2); break;
}
}
// ---------------------------------------------------------------------------
// PROGRAM INITIALIZATION CODE
void init ()
{ // set output pins
DDRA = 0x03; // 0000.0011
DDRB = 0x7E; // 0111.1110
DDRD = 0x1E; // 0001.1110
// setup Timer/Counter0 for LED refresh
TCCR0A = _BV(WGM01); // Set CTC mode
TCCR0B = _BV(CS02); // Set prescaler clk/256 = 15625 Hz
OCR0A = 40; // 15625/40 = 390 interrupts/sec (5 cols = ~78fps)
TIMSK = _BV(OCIE0A); // Enable T/C 0A interrupt
MCUCR = 0x30; // 0011.0000 (sleep enabled, power down)
WDTCR = 0x18; // 0001.1000 set WD turn-off and WD enable bits
WDTCR = 0x10; // 0001.0000 reset WD enable to complete WD turnoff
sei(); // enable global interrupts
}
void DelayCS(int cs)
// Delays CPU for specified time, in centiseconds (1/100 sec)
// Calling _delay_ms in a routine prevents inlining, reducing code size,
// at the expense of slight timing inaccuracies.
{
for (int i=0; i<cs; i++)
_delay_ms(10);
}
void DelaySecond()
{
DelayCS(100);
}
// -------------------------------------------------------------------------
// CHARACTER SCROLLING ROUTINES
void ShiftLeft()
// shifts the entire display buffer one column to the left
{
for (int i=0; i<11; i++)
{
buf[i] = buf[i+1]; // buf[0] on left; buf[11] on right
} // each element represents a column
} // buf[0..4] are only elements visible
void Scroll()
// scrolls a character onto the display
{
for (int i=0; i<COLS+1; i++)
{
ShiftLeft(); // shift display 1 column to left
DelayCS(SCROLLDELAY); // and wait a while
} // repeat 5x for whole character
}
void LoadSymbol(int index)
// loads a font symbol into the non-visible part of display buffer
{
for (int y = 0; y < COLS; y++)
{
buf[y+5] = pgm_read_byte(&(FONT_CHARS[index][y]));
}
buf[11] = 0x00; // add character spacing
}
void MakeVisible()
// copies char from non-visible to visible part of buffer
{
for (int i=0; i<COLS; i++)
{
buf[i] = buf[i+5];
}
}
void DisplaySymbol(int index)
// loads a font symbol into the visible display buffer
{
LoadSymbol(index);
MakeVisible();
}
void ScrollText(const char *text)
// scrolls given text across matrix, right to left
{
for (int i=0; i<strlen(text); i++)
{
LoadSymbol(text[i]-' '); // get char
Scroll(); // and scroll it
} // repeat for all chars
}
void DisplayText(const char *text)
// displays given text, one character at a time
{
for (int i=0; i<strlen(text); i++)
{
DisplaySymbol(text[i]-' '); // display char
DelaySecond(); // wait a while
} // repeat for all chars
}
// -------------------------------------------------------------------------
// ANIMATION ROUTINES
void FlashHeart()
{
DisplaySymbol(HEARTCHAR); // flash heart on
DelayCS(FLASHDELAY); // wait
DisplaySymbol(0); // flash heart off
DelayCS(FLASHDELAY); // wait
}
void HeartBeat()
{
FlashHeart(); // heart on/off
FlashHeart(); // heart on/off
DelayCS(BEATDELAY); // wait
FlashHeart(); // do it again!
FlashHeart();
DelayCS(BEATDELAY);
}
// -------------------------------------------------------------------------
// MAIN PROGRAM LOOP
void main_loop ()
{
while(1)
{
for (int i=100; i<107; i++)
{
DisplaySymbol(i); // display a fun symbol
DelaySecond();
DelaySecond();
HeartBeat(); // heartbeats
HeartBeat();
DisplayText(TEXT1); // display text1
DelaySecond();
HeartBeat(); // more heartbeats
ScrollText(TEXT2); // scroll text2
DelaySecond();
} // repeat 7 times
sleep_cpu(); // turn off display
}
}
// ---------------------------------------------------------------------------
// MAIN
int main (void)
{
init(); // set up ports, CPU registers
main_loop(); // do the display, then sleep
return (0); // that's all, folks!
}