Saturday, December 7, 2013

Shrinkify Arduino using Cheap ATtiny13A Microcontroller

You can shrinkify your simple Arduino project into ultra tiny ATtiny13A microcontroller as long as your project code size doesn't exceed 1 Kb limit of ATtiny13A, and it doesn't use RAM / EEPROM over 64 bytes . Why would you do that? Because two important reason: it's cheap (vcc2gnd.com sell this microcontroller for as low as $1.5 / Rp17.000,- for Indonesian customer, even tinier and cheaper for SOIC version), and it certainly has much smaller form than your ordinary Arduino, even compared with Arduino smallest form (Arduino Micro).

If you need more power (bigger program code space, bigger RAM), you should consider using bigger version of ATtiny such ATtiny2313, but that's another story. For now let's focus with ATtiny13A (note that "A" suffix means newer version of ATtiny13 series, older version has no such suffix). Also note that for serious design / commercial product, you really should consider using newer series such ATtiny45 or ATtiny85 (same form factor with bunch of new capabilities).

To program any AVR tiny microcontrollers you can use SPI-based programmer such usbASP, or use your existing SPI-enabled board such Arduino (using ArduinoISP sketch, see following picture to see how simple it is to connect ATtiny13A to your Arduino)...


Friday, December 6, 2013

Character LCD I2C Library for Arduino

With I²C Display Module, you can easily connect character LCD (Liquid Crystal Display) to your Arduino via I²C protocol, thus saving a lot of valuable pins usually used for parallel connection (at least 6 pins: 2 control pins - RS and EN - and 4 data pins D7, D6, D5, and D4 for 4-bit mode). With I²C (a.k.a. TWI /  Two Wires Interface), you need only two pins. Even better, those two pins can also be shared with other I2C-based peripherals.

Note: in Arduino Uno, SDA is pin A4, SCL is pin A5. For other models, please check corresponding pin diagram.

The only drawback of using these modules is (beside a little additional cost for purchasing I²C display module) is speed reduction, but it's negligible since you don't need to update lot of data at high speed with such character-based display device (might be different story with graphics LCD, they do need to fetch a lot of bitmap data).

You might want to use new LiquidCrystal_I2C library, please download most recent version (v1.2.1) in zipped file (485 Kb), generously contributed by F. Malpartida. Extract it to your Arduino working folder under library sub-folder (i.e., My Document\Arduino\libraries).

There are several Character LCD I²C modules on the market, you should use correct initialization code which might be slightly different for each device.

Include required library at beginning of your sketch as follow:
#include 'Wire.h'
#include 'LiquidCrystal_I2C.h'

Next step is to instantiate the LCD object by calling LiquidCrystal_I²C class constructor. This constructor accepts parameter in following order: addr, en, rw, rs, d4, d5, d6, d7, bl, blpol
  • addr is I²C address of the module. It's unique for each device, check with your I²C module supplier to get the correct address. Usually, they are set to 0x20, 0x27, or 0x38
  • en is bit index for Enable (EN) pin.
  • rw is bit index for Read/Write Selector (RW) pin.
  • rs is bit index for Register Selector (RS) pin.
  • d4d5d6d7 are bit indexes for upper 4-bit of data pins
  • bl is bit index for backlight pin.
  • blpol polarity of backlight pin, might be differs according to the LCD being used. Value is either POSITIVE or NEGATIVE (enum declared in LCD.h).
The first argument (addr) is mandatory, that means you have to manually specify the address of your I²C device. Other arguments are optional, if not specified they will be set to default values (bit#6 for en, bit#5 for rw, bit#4 for rs, bit#0 for d4, bit#1 for d5, bit#2 for d6, bit#3 for d7). If bl is omitted, backlight state won't be modified (default to value set by the I²C module). Default value for blpol is POSITIVE.

Those bit indexes are required for the library to send correct signal to appropriate pins since different I²C modules has different pin mapping.

Some example of initialization codes (try them to find one that suitable for your device), instantiated on object lcd:
  • LiquidCrystal_I2C lcd (0x20,2,1,0,4,5,6,7,3,POSITIVE);
  • LiquidCrystal_I2C lcd (0x27,2,1,0,4,5,6,7,3,POSITIVE);
  • LiquidCrystal_I2C lcd (0x20,4,5,6,0,1,2,3,7,NEGATIVE);
Finally, initialize the LCD by invoking begin() method which accepts two arguments: column count and row count. Example: for 16x2 display, invoke lcd.begin(16,2); For 20x4 display, invoke lcd.begin(20,4);

I2C LCD Display 20x4 Sample Sketch

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Instantiate lcd object
LiquidCrystal_I2C lcd( 0x20, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE );

// Custom character patterns
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
};

void setup() {
  // initialize the lcd
  lcd.begin( 20, 4 ); 
  
  // create custom chars
  for( uint8_t i = 0; i < 8; i++ ) {
    lcd.createChar ( i, (uint8_t *)charBitmap[ i ] );
  }

  lcd.setCursor( 3, 2 );                  
  lcd.print( "LCD 20x4 DEMO" );
  lcd.setCursor( 0, 3 );
  lcd.print( "azTech @ vcc2gnd.com" );

}

void loop() {
   register uint8_t i;
   // Animate
   lcd.home();   
   for( i = 20; i--; ) lcd.write( random( 8 ) );
   lcd.setCursor( 0, 1 );
   for( i = 20; i--; ) lcd.write( random( 8 ) );   
   delay( 200 );
}
Watch the result on demo video below...

Wednesday, December 4, 2013

Prevent GCC from auto-inline a function

Sometimes GCC goes too "smart" by inlining a function (put entire block of it's code directly in place) rather than assembling it as normal subroutine (block of code invoked by RCALL/CALL instruction and returns with RET instruction).

You can tell GCC not to automatically inline a specific function by declaring noinline attribute modifier before function type declaration. For example:
__attribute__((noinline)) int myStrictFunction() { }