Starten met de ATtiny2313

Ledlamp in werking

Opgelet: deze pagina is van rond 2011. Tegenwoordig zou ik niet meer met een loste ATtiny starten, maar met bijvoorbeeld de Arduino Nano. Goedkoper (kristal etc zit er al op, en klonen zijn al vanaf zo'n €2.50 uit China te krijgen), en met de Arduino-omgeving heel makkelijk te programmeren. Ook geen aparte programmer nodig, gewoon via USB.

Zie ook mijn pagina's: AVR Butterfly demo board met de ATmega, vuurvliegjes als een toepassing van de ATtiny, en verder de ATtiny software en hardware pagina's.

Probleem: een I²C-chip (PCA9634) die ik graag als RGB powerLED-controller wilde gebruiken (als uitbreiding voor mijn Rabbit, en om te spelen met I²C op mijn omgebouwde NSLU2) is als hobbyist haast niet betaalbaar verkrijgbaar, in ieder geval niet in een behuizing die soldeerbaar is; pootjes minder als 1 mm apart ga ik niet zelf zitten hobbyen... Wat te doen? Kan ik dit probleem op een andere manier oplossen (in 2011, zoals gezegd: nu beter met de Arduino Nano...)?

Als ik nu eens een goedkope microcontroller neem, en zelf de functionaliteit daarin programmeer? Flexibel, ook voor andere zaken inzetbaar, en effectief nog goedkoper ook. Zo gezegd, zo gedaan? Wel, er komt natuurlijk wel een aantal extra stappen bij kijken:

  • De chip moet goed verkrijgbaar (en betaalbaar) en hanteerbaar zijn
  • De chip moet voldoende mogelijkheden hebben; hier I²C slave en PWM (Pulse Width Modulation) uitgangen
  • Je hebt een 'programmer' nodig
  • Je hebt ontwikkeltools nodig, liefst C/C++

Voor de huidige tijd: nog makkelijker zijn de Arduino-bordjes; kant-en-klare modules met veel beschikbare software. Ben zelf aan het kijken naar de Arduino Nano, een kleine module die toch goed hanteerbaar is. Ook verkrijgbaar als goedkope Chinese kloon (al rond de €2.50), al raad ik aan eerst een originele te kopen (minder kans op verrassingen).

Al met al is de keuze gevallen op de Atmel ATtiny2313. Een goed verkrijgbare microcontroller met FLASH geheugen, in een eenvoudig verwerkbare 20-pins DIL behuizing. Online in 2011 gekocht bij Conrad €2.14 (#154166-89). Veel informatie op internet. Past zo op de standaard gaatjesprint die ik gebruik voor prototypen. Een AVR-programmer is te koop onder de €10, en de tiny2313 is 'in-circuit'-programmeerbaar, dus je hoeft de chip niet eens uit je schakeling te halen om de functionaliteit te veranderen.

De Atmel ATtiny2313

De ATtiny2313 is (als opvolger/vervanger van de AT90S2313) een prima AVR microcontroller voor beginners. Een overzichtje van de eigenschappen en functies van de ATtiny2313; zie ook de uitgebreide documentatie in de datasheet (PDF 2MB):ATtiny2313 pinout

  • 8-bit AVR architectuur (1..2 cycles/instructie; Harvard memory arch)
  • 2kB flash programmageheugen, 10.000x schrijfbaar
  • 128 bytes ram geheugen
  • 128 bytes eeprom geheugen, 100.000x schrijfbaar
  • Seriële poorten, timers, counters, etc
  • 4 PWM kanalen (pulsbreedte modulatie)
  • I²C (TWI) slave en master mogelijkheid
  • 20 pins, waarvan 18 als I/O te gebruiken
  • maximaal 20 miljoen instructies per seconde bij een 20MHz klok
  • interne oscillator, geen extern kristal noodzakelijk (maar kan wel)
  • Voeding 2.7 (1.8 voor V versie) tot 5.5V, dus werkt ook op twee batterijen

De Tools

Ik wil de tools kunnen draaien op zowel Ubuntu Linux als op Windows. Daar ik liever niet meer in assembler programmeer (weer een andere assembly-taal...) ga ik voor C: de GCC compiler suite is ook verkrijgbaar voor de 2313. Minimaal is nodig de WinAVR GCC omgeving, dit is de Windows GCC C/C++ compiler voor de AVR processoren, met alle bijhorende tools. Een belangrijk onderdeel hiervan is de runtime library AVR-libc, met uitgebreide AVR-libc documentatie en voorbeelden (ook over bijvoorbeeld interrupts, mixen met assembler code, etc). Voor Linux/Ubuntu 12.04: installeer de tools gewoon vanuit de software Center, of met: sudo apt-get install gcc-avr avr-libc avrdude (voor oudere Ubuntu's zie: AVR-GCC .deb packages).

AVR met Linux: aanpassen

De Code::Blocks configuratie was niet optimaal, voeg -R .fuse -R .lock -R .signature toe in de build options: pre/post build steps, eerste avr-objcopy commando.

Verder heb ik standaard de volgende compiler-opties toegevoegd: -gdwarf-2 -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums

Wil je een .lss file, voeg dan aan de pre/post build steps toe: avr-objdump -h -S $(TARGET_OUTPUT_FILE) > $(TARGET_OUTPUT_FILE).lss

De hele AVR GCC suite is command-line gebaseerd (dus zo'n ouderwets DOS boxje). Gebruik je liever een complete grafische IDE, kijk dan naar de Atmel AVR Studio 4 (Windows). Dit programma is gratis te downloaden (eerst het programma, en dan de twee service packs, en in de goede volgorde installeren: programma, dan SP1, dan pas SP2). Werkt samen met de GCC compiler, maar je kan ook in assembler werken.

Als alternatief (dat ik zelf gebruik), en óók beschikbaar voor Linux, kan je de Code::Blocks IDE gebruiken. Deze heeft standaard ook de AVR configuratie in zijn templates (al linkt'ie iets anders, waardoor de binary niet exact hetzelfde is als bij AVR Studio).

Meer info over de C compiler: zie de software tips pagina

De programmer

Als je een programma gecompileerd hebt, moet je het ook in de 2313 zien te krijgen, oftewel je hebt een programmer nodig en software om met de programmer te kunnen praten. Het eenvoudigst qua omgeving vind ik om hiervoor avrdude te gebruiken; meegeleverd in WinAVR. Wil je echter dit niet vanaf de command line hoeven te doen, dan kan je in Windows ook PonyProg gebruiken, deze heeft een vriendelijker grafische gebruikersomgeving. Ik heb het zelf overigens niet gebruikt, gebruik alleen avrdude.

USBasp AVR programmerTegenwoordig gebruik ik een usb-programmer gebaseerd op de USBasp Versie 2 van Thomas Fischl, die goed samenwerkt met recente versies van avrdude. Deze USBasp's zijn op veel plaatsen verkrijgbaar, heb zelf via marktplaats gewoon in Nederland besteld (€5,95 inclusief verzendkosten). Makkelijker daar nu veel nieuwe computers geen seriele poort meer hebben... En levert gelijk 5 of 3.3 Volt aan je bordje (jumper JP1). Voorbeeld gebruik in Linux, voor de ATtiny2313, eerst de oude inhoud lezen (laatste letter h=hex, r=raw binary), dan de nieuwe schrijven:

avrdude -P usb -c usbasp -p t2313 -U flash:r:original.hex:h
avrdude -P usb -c usbasp -p t2313 -U flash:w:knipper.hex

De serial programmer- componenten

1x Sub-D connector, 9-polig
3x weerstand 4K7
1x weerstand 10K
1x weerstand 33K
1x transistor BC549C
1x diode 1N4148
2x zener 5V1
1x 20-polig IC voetje
1x condensator 0.1 uF
1x condensator 33 uF/16V
1x 3-polige header
1x 2x5-polige header
gaatjesprint met eilandjes

Voor avrdude is -c siprog de identificatie voor de seriële programmer. Om deze programmer onder Linux werkend te maken was even tricky. avrdude in combinatie met een trage (128 kHz low power) clock van de ATtiny draaide voor mij te snel onder Linux (Windows was OK), en ik moest de -i 40 parameter toevoegen. O ja, en -P /dev/ttyS0 in plaats van -P com1

Wel eenmalig aan je systeem vertellen dat je die poort mag gebruiken (anders moet je steeds sudo voor avrdude zetten: voeg in de folder /etc/udev/rules.d een file 99-USBasp.rules toe met als inhoud onderstaande tekst, en herstart udev met sudo /etc/init.d/udev restart

# Enable usbasp in udev rules, file /etc/udev/rules.d/99-USBasp.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE="0666"

Ik ben ooit begonnen met een zelfbouw seriële programmer (2010), een low-cost programmer voor gebruik met een seriële poort (denk minder dan € 10, en geen IC's nodig). Mijn versie is gebaseerd op het schema van de seriële programmer AVR programmer Olimex AVR-PG1, en de vergelijkbare AVR programmer van electronics-diy. Paar kleine modificaties, met name haal ik de 5 Volt uit de USB-poort van mijn laptop, dus een USB-kabeltje gehalveerd en hiervan de ground en +5V aangesloten op de 3-polige header, zodat de tiny2313 voeding heeft en ook zonder seriële kabel programma'tjes kan uitvoeren. En ik heb naast de 2x5-pins ISP (In-System Programming) header een 20-polig IC-voetje geplaatst (Vcc op pin 20, GND op pin 10, reset pin 1, etc), kan dus zowel losse 2313's als bordjes met ISP (in-system programming) programmeren. Zie de foto hieronder, met al een ATtiny in het 20-pins voetje (opmerking: enkele SMD-weerstanden zitten aan de onderkant).

Seriële programmer

Deze programmer is zowel compatible met de avrdude software als met de PonyProg software (zie bij 'De Tools'). De programmer is ook gelijk een mini-applicatiebordje, in de zin dat programma's er ook gelijk kunnen draaien; zie bijvoorbeeld 'Het eerste programma'tje' verderop. Let op: werkt niet altijd goed samen met een USB-to-serial converter, heeft ook de handshake signalen nodig. Heb je alleen usb, gebruik dan de bovengenoemde USBasp.

Het eerste programma'tje

De 'hello world' voor embedded systems is het laten knipperen van een LEDje... Ik ben hiervoor uitgegaan van de Nederlandstalige intro 'Knipperende LED', waar op de site behoorlijk wat over de tiny2313 wordt uitgelegd. Zeker lezen! Op de programmer twee extra onderdelen geplaatst: weerstand 470 Ohm plus een rode LED, en in serie aangesloten tussen Vcc en pin PD2 (pin 6 op het voetje): dus anders dan in de tutorial! Dit omdat ik ook een extern kristal wil kunnen gebruiken: deze wordt op pin 4 en 5 aangesloten, waar in de tutorial de LED zit. Ook de source (bij mij knipper.c) dus even hierop aanpassen...

Ik gebruikte hier nog AVR Studio om te compileren; met 'F7' vertaal je de hele boel. In de directory 'default' vind je de gegenereerde files; de .hex file bevat de binary om in de chip te branden. de .lss file bevat een uitgebreide listing, inclusief startup code. AVR Studio doet een aantal stappen; de meest belangrijke is het aanroepen van de compiler; hieronder (verkort) weergegeven om te laten zien met welke opties vertaald wordt:

avr-gcc -mmcu=attiny2313 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums knipper.c

De -Os optimaliseerd voor grootte. Let op: na dit commando volgt er nog een aantal commando's om de uiteindelijke hex file te maken; hier niet weergegeven (doet AVR Studio voor je, maar wel van belang als je zelf een .bat of een makefile wilt maken). Downloaden naar de chip gaat met avrdude, hier voor de zelfgemaakte seriële programmer:

avrdude -p t2313 -c siprog -P com1 -U flash:w:knipper.hex

En ja, het LEDje gaat na het downloaden vanzelf knipperen. Het hele programma is 116 bytes (de grootte van de te downloaden binary, dus inclusief libraries en opstartcode), niet slecht voor een heel C programma!

Losgekoppeld van de computer, en op een regelbare voeding aangesloten. Eens kijken hoe ver ik de voeding kan laten dalen... Zelfs bij 1.33 Volt (de laagste stand die ik haal) blijft de uitgang keurig op en neer gaan, al is door de te lage spanning de LED al niet meer zichtbaar. Netjes, formeel is'ie maar vanaf 2.7 Volt gegarandeerd (en de V-versie vanaf 1.8V). Houdt in dat'ie ook op twee oplaadbare batterijen werkt, handig voor een volgens project dat ik in gedachten heb (soort vuurvliegjes gebaseerd op de zonnecel van zo'n oude LED-tuinlamp).

Fuse programming met AVRDUDE

Dit stukje is verhuisd naar de hardware tips pagina...

Interrupts

Altijd handig om een gevoel van tijd te hebben, dus een interrupt-routine om ticks te tellen is plezierig. De timers lopen toch al (vanwege de PWM), dus ik gebruik timer 0 overflow om elke periode een interrupt te genereren. Met een 4 MHz kristal; prescaler op 8, en 256 ticks voor een PWM-ronde kom ik zo op een PWM- en interrupt-frequentie van haast 2 kHz (4MHz / 8 / 256). In de interrupt-routine gebruik ik dit (om te testen) om een LEDje te laten knipperen; ziet er op de scope goed uit. Timer 0 instellen als pwm en in TIMSK timer overflow interrupt aanzetten, en de globale enable flag aanzetten met de sei() functie:

#include <avr/interrupt.h>
volatile int pwm_counter;

ISR(TIMER0_OVF_vect)    // T0 interrupt service routine
{
  PORTD ^= (1 << PD2);  // toggle LED output at 1 kHz
}
...
// in main: timer0 as fast PWM, clear pwm output on match
TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS01);   // timer0 prescale by factor 8
TIMSK |= (1 << TOIE0);  // enable timer0 overflow interrupt
sei();                  // global enable interrupts
...

De timer interrupt wordt uiteindelijk gebruikt voor onder andere het geleidelijk aan- en uit-zetten van de leds, en het bijhouden van de real-time klok.

De I²C (of TWI)

Atmel noemt I²C "TWI", Two-Wire Interface, om trade-mark issues te voorkomen. Ik had gehoopt code van het Arduino project te kunnen gebruiken, maar helaas: hardware is anders. De ATtiny2313 heeft een USI poort (Universal Serial Interface), die meerdere standaarden — waaronder I²C — aankan, maar is net weer wat anders dan op de AVR's gebruikt op de Arduino. Met I2C heb je overigens twee kanten:

  • De I²C master; deze is de baas en leest I2C devices (of schrijft er waarden heen). Dit is typisch de microcontroller of computer die de zaak aanstuurt, en er is er maar een op de bus.
  • De I²C slave; dit is een 'device' zoals bijvoorbeeld een EEEPROM, een temperatuursensor of een A/D converter. Hiervan kunnen er meerdere tegelijkertijd aan de bus hangen.

I2C Slave (device)

Normaal werkt de AT2313 als master, maar ik had de code voor een slave nodig. Gelukkig was er ook voor de tiny op internet wel wat te vinden; twee projecten waarbij de AT2313 als device gebruikt wordt vond ik met name van belang (de Atmel eigen code uit de app-notes werkt volgens fora niet altijd betrouwbaar, deze links hebben bijgewerkte versies):

  • Deze I²C dimmer applicatie, waar een circulaire buffer voor communicatie gebruikt wordt: handig als je een message-based protocol wilt. Overigens is deze app ook een slimme manier om een 8-kanaals PWM te implementeren op de ATtiny.
  • Deze I²C eeprom simulatie, die zich gedraagt als een seriële eeprom, dus meer een memory-mapped manier van communicatie

Ben met de eprom-simulatie aan de slag gegaan; was het eenvoudigst hier een register-gebaseerde interface á la PCA9634 mee op te bouwen. De code deed niet helemaal wat er gezegd werd, heb wat kleine wijzigingen doorgevoerd, zoals het samenvoegen van de send- en receive-buffer in een geheugenbuffer. De hele code is minder dan 500 bytes, dus ik heb nog meer dan 3/4 over voor de eigenlijke applicatie. Alle i2c-communicatie wordt in de interrupt afgehandeld; het main program is een lege eindeloze loop.

Ook gezorgd dat de LED en een switch (met een weerstand van 1K, van PD3/pin 7 naar aarde) ergens in het "eprom"-geheugengebied zijn gemapped door in de eindeloze loop van het 'main'-programma deze waarden heen en weer te kopiëren van de I/O naar de geheugenbuffer waar de eeprom gesimuleerd wordt. Ja, ik kan nu (vanuit de NSLU2) de LED aan en uitzetten, en de schakelaar uitlezen (via de i2cset en i2cget commando's)! I²C werkt. Ongeveer een week nadat ik de onderdelen van de programmer binnenkreeg, toch netjes.

Ik ga overigens niet een 8-kanaals PCA9634 exact nabouwen (waarvoor de dimmer-app een goed startpunt zou zijn); maar de extra intelligentie van de tiny gebruiken voor een besturing op hoger niveau (commando's als ga in zoveel seconden naar die helderheid); misschien dat dan een message-based protocol als in de dimmer dan toch meer toepasselijk is. Bovendien (in verband met de gevoeligheid van het menselijk oog) wil ik meer een logaritmische curve, en daarvoor heb ik meer dan 8 (lineaire) bits nodig, zit aan 12 te denken... Maar, dat wordt misschien nog wel eens een andere pagina.

I2C Master (Host)

Overigens kan je de ATtiny natuurlijk ook als I2C master gebruiken, om zo I²C devices uit te kunnen lezen. Ik gebruik bijvoorbeeld de LM75BD voor het meten van de warmwateraanvoer en koudwaterafvoer voor een slimme CV pomp voor de vloerverwarming. De regeling zelf draait op een ATtiny2313 (als deel van een groter huisnetwerk). De code voor de master-functinaliteit is gebaseerd op de Atmel application note AVR310, en is zo'n 270 bytes. Zie ook Peter Fleury met zijn I2C master library, compact (in assembly geschreven) maar nog niet door mij getest (ben eerst met de Atmel app note aan de slag gegaan voor ik deze tegen kwam).

HEXFET power LED driverEen krachtiger LED

Bij Conrad enkele power LEDs besteld, rood/groen/blauw, per kleur ongeveer 1 Watt. Deze LEDs (181159-89; €14,14) mogen per stuk 350 mA hebben (mits goed gekoeld, 188052-89), en dat is wat veel voor de ATtiny. Met enkele low-cost HEXFETs IRL510 (162789-89; € 0,60) is het echter wel goed te doen.

RGB power LED lampEen simpel schema'tje geeft ook een stroom­begrenzing, zodat ongeacht de voedings­spanning de stroom binnen de veilige grenzen blijft: als de spanning over R2 te hoog gaat, gaat T1 geleiden, en knijpt T2 dicht --> stroom wordt minder en de spanning over R2 daalt, evenwicht bij ongeveer 0.63V. Let op, als de FET in stroombegrenzingsmode werkt, valt er wel spanning over (gaat als weerstand werken), en dissipeert hij dus ook vermogen: een bescheiden koelplaatje is nodig! Bij de gegeven waardes, en de blauwe LED (3.5V spanning, x2) op 350 mA staat er 2.9V over R3, en dus 1.45V over de FET --> 0.5W (en 1W over R3), bij de rode LED (2.5V, x2) meer: 3.45V resp. 1.2W over de FET.

De ingang is compatibel met de ATtiny op 5 Volt, en aangesloten op de PWM-uitgangen op pin 14..16 (3 FETs in totaal, dus). Dit geeft een lamp met behoorlijke lichtopbrengst, en instelbare kleur en helderheid.

Ledlamp in werkingEen eerste testprogramma'tje is gebaseerd op een RGB-LED tutorial, hierin wordt gedemonstreerd hoe je de pulsbreedte modulatie (PWM) gebruikt. Er zijn voor mij enkele kleine aanpassingen nodig: de driver-trap zoals geschreven gedraagt zich als een inverter, dus uit → aan, en omgedraaid. De 2313 heeft in zijn configuratie­registers bits om de uitgang om te draaien (zie b.v. COM0A1), daarmee gedraagt het programma zich zoals gewenst.

En verder...

Ben nog met wat extra zaken bezig, zoals een low-cost AD conversie op de ATtiny; zie meer op mijn ATtiny Hardware Tips pagina... En tips over de software/debug kant op de software tips pagina.

Plus: Een ongesorteerde dump van mijn bookmarks over de AVR:

Algemeen:

Programmers:

Onderdelen nodig?