In voorbereidingATtiny Hardware Tips

Kant-en-klare bordjes met AVR processor? Kijk eens op de Arduino pages; is een uitgebreide gebruikers-community bij. Leuk bordje is bijvoorbeeld de Arduino Duemilanove (wel krachtiger dan de ATtiny).

Deze pagina is een vervolg op mijn Starten met de ATtiny2313 pagina... Het behandelt een aantal tips en trucks aan de hardwarekant voor mensen die met de 2313 willen werken (en dient eigenlijk voornamelijk als naslagwerk voor mezelf). Voor software/debuggen zie de ATtiny Software (en debugging) Tips.

Onderwerpen op deze pagina:

Geen garanties, maar hopelijk heeft naast mezelf nog iemand er iets aan.

Fuse programming vanuit je C source, of met AVRDUDE

Naast het programmageheugen heeft de tiny2313 nog meer programmeerbare delen; met name de fuses voor het instellen van de verschillende modes (zoals welke klok te gebruiken). Die fuses zijn vaak wat raadselachtig (zo is 'programmed' een 0, en 'cleared' een 1), maar gelukkig is er op het net wel wat uitleg verkrijgbaar; zo is er bijvoorbeeld de fuse calculator, welke de fuse waardes netjes uitrekent aan de hand van je keuzes. Als je de waardes berekend hebt kan je met avrdude deze programmeren. Pas op; een verkeerde waarde kan je chip onbruikbaar maken (zeker als je alleen een seriële programmer hebt)! Meer info ook op de AVR Fuses HOWTO Guide (en natuurlijk in de datasheet).

Het is nuttig eerst eens de huidige waardes uit te lezen, met het commando (serial programmer, windows resp. linux):

avrdude -p t2313 -c siprog -P com1 -U lfuse:r:-:h -U hfuse:r:-:h -U efuse:r:-:h
avrdude -p t2313 -P /dev/ttyS0 -i 40 -c siprog -U hfuse:r:-:h -U efuse:r:-:h

Enkele Fuse-settings

Default 8MHz / 8: Low=0x64, High=0xFD, Ext=0xFF

Extern 4 MHz Xtal: Low=0xFD

Internal 128 kHz clock (low power): Low=0xE6

Watchdog & brownout@2.7V: High=0xCB

Dit levert bij mij de waarden op (even zoeken in de output): low fuse 0x64, high fuse 0xdf, extended fuse 0xff. Dit zijn de standaard fabriekswaarden (interne RC oscillator, etc). Ik wil de processor op het kristal laten lopen (extern kristal, 4 MHz, geen deling door 8); dit levert een low fuse waarde op van 0xfd. De high fuse en extended fuse kunnen ongewijzigd blijven! Commando (hier met de usb programmer; -c usbasp):

avrdude -p t2313 -c usbasp -U lfuse:w:0xfd:m

En ja, programmer uitgebreid met een 4 MHz kristal en 2 stuks 22 pF condensatoren, en mijn ledje knippert nu 4x sneller (in plaats van de 1 MHz interne RC-klok, de 4 MHz kristalwaarde). Zoals gezegd: een verkeerde fuse waarde kan je chip onbruikbaar maken; altijd dubbel-checken!!!

Fuses in je C programma

Je kunt ook de waarde van fuses in je programma (en daarmee direct in je binary files) opnemen, zodat deze informatie in de bijhorende source en .elf file staat en niet verloren gaat als je je kladblaadje per ongeluk weg gooit, en ze bovendien automatisch op de goede manier meegeprogrammeerd worden. Dit gaat (op een wat primitieve manier, de fuse calculator blijft nodig om te checken of je het goed hebt) met behulp van de avr/fuses.h include file en een door jezelf in je C file op te geven configuratie, bijvoorbeeld:

#include <avr/io.h>
#include <avr/fuse.h>
FUSES =   // specified bits will be zeroed...
{         // select 128 kHz internal oscilator with slow start
    .low  = (FUSE_CKSEL0 & FUSE_CKSEL3 & FUSE_SUT0),   // 0xE6
    .high = HFUSE_DEFAULT,                             // 0xFD
    .extended = EFUSE_DEFAULT,                         // 0xFF
};

Je kunt de waarde van de fuses uitlezen uit de .elf file met behulp van het commando avr-objdump -s -j .fuse <filenaam>.elf. Helaas, de waardes worden nog niet automatisch door AVRDUDE geprogrammeerd (staan niet in de .hex file), dit moet je nog steeds 'handmatig' doen (zie hierboven)...

Low-cost zero-CPU-load analog-to-digital converter

AD constant currentDe ATtiny2313 heeft zelf geen A/D-converter. In de applicatienote AVR401: 8-bit precision A/D converter van Atmel staat wel hoe er met de analoge comparator er zelf een te maken is, maar deze was mij te complex (ook qua software). Ik heb zelf een gestripte versie gemaakt met de volgende voordelen:

  • Minimaal aantal onderdelen: een low-cost transistor, twee weerstanden en een condensator
  • Gebruikt slechts twee pinnen op de ATtiny2313 (pin 12 en 13)
  • Minimale software; slechts een extra instructie in de timer interrupt routine (plus enkele initialisatie-instrucies)
  • Bereik praktisch 0.1 .. 4.9 Volt (bij 5 Volt supply)
  • Minimaal energiegebruik

Het principe is eenvoudig (zie schema 1 en ook de app note): de te meten spanning wordt op pin 12 (AIN0) aangeboden. Op pin 13 (AIN1) wordt een lineair stijgende spanning gemaakt: met behulp van een constante stroom (als ingesteld door de transistor Q1 en weerstand R2) wordt een condensator C1 opgeladen. Op hetzelfde moment is een timer gestart. Op het moment dat de spanning op de condensator dezelfde is als de spanning op de meet-ingang wordt de waarde van de timer in het timer capture register ingeklokt; dit is de gemeten waarde.

AD input protectionNa een vaste tijd wordt de condensator leeggemaakt (in ongeveer 20 µs), door pin 13 van de ATtiny2313 tijdelijk als output met waarde 0 te configureren (met de weerstand R1 als stroombegrenzer), en kan de cyclus opnieuw beginnen. Het geheel loopt op Timer1 die ik toch al had lopen voor andere taken (met name de PWM outputs, klok op 4 MHz/8 dus ~2 kHz PWM); kost dus geen extra resources. Het enige extra is een instructie in de interrupt routine die pin 13 van input (meten) naar output met waarde 0 (ontladen) schakelt, en weer terug (toggle: DDRB ^= _BV(PB1);). OK, niet helemaal zero-CPU-load, maar enkele instructies elke 500 µs (2 kHz) is verwaarloosbaar.

Op de meet-ingang wel nog wat onderdelen om deze te beschermen tegen te hoge spanningen en zo; of dit nodig is hangt af van je toepassing (schema 2, zener is 5.1 Volts).

Voor de precieze waarde van de condensator moet je wat experimenteren, afhankelijk van je timing, en met name de kwaliteit van je condensator en van de gebruikte transistor, waarvan de versterkingsfactor (en daarmee de stroom) niet voor elke transistor dezelfde is...

De meetwaarde is uit te lezen uit het Timer/Counter 1 capture register, ICR1L. De waarde wordt elke milliseconde bijgewerkt (1 kHz sample frequency). De meting is gekoppeld aan de voedingsspanning, ideaal voor weerstand-gebaseerde sensoren; maar calibratie is eventueel ook mogelijk: schakel de AIN0 input van de comparator naar de interne referentiespanning (1.1V) en meet deze; dit geeft je een schaalfactor. De ondergrens is niet helemaal 0 Volt, omdat de condensator niet helemaal leeg raakt (blijft een kleine laadstroom lopen, ook tijdens het ontladen, geeft een ondergrens van ongeveer 1 mA x 100 Ohm = 100 mV).

Initialisatie voor A/D conversie (exclusief de PWM-initialisatie op 2 kHz fast mode):

// Timer initialisation for PWM not shown
// TIMER 1 ADconv: noise filter, neg edge
TCCR1B |= (1 << ICNC1) | (0 << ICES1);
// ACO: output of comparator; ACIC enable timer capture; ACIS:2 -> pos edge
ACSR = (1 << ACO) | (1 << ACIC) | (1 << ACIS1) | (0 << ACIS0);
// only use as analog input; disable digital input (power reduction)
DIDR = (1 << AIN1D) | (1 << AIN0D);

Simpel, niet?

HomeNode met simpel LCD display

Simpel display aan mijn HomeNodeOnderdeel van mijn home control system: een simpele ATtiny gebaseerde node die een aantal sensoren en schakelaars bestuurd. Het prototype hiernaast hangt met een flatcable aan de USBasp programmer (rechts, aangesloten op een USB hub), en aan een LCD display. Op de print daarnaast nog wat headers voor I2C en solid state relais; plus natuurlijk de blauwe 3-pin connector voor aansluiting aan het netwerk. Meeste passieve componenten zitten als SMD-onderdelen aan de onderkant van het printje.

De node heeft de mogelijkheid om een simpel LCD aan te sluiten; zie plaatje. Het gaat hier om een simpel 2x16 display (hier LCM-S01602DSR) dat in allerlei uitvoeringen vrij goedkoop te krijgen is (in allerlei maten, 2x16; 2x20, 4x20, etc). Aansluiting is mogelijk via slechts zes draadjes plus de 5 Volt voeding: 4 datalijnen, een command/data selectielijn en een write puls. Heb je meer pinnen beschikbaar dan kan het wat efficienter, bijvoorbeeld via een 8-bits databus en een read/write select (totaal 11 draadjes, plus voeding).

Al deze displays maken gebruik van dezelfde compatible controllers (vaak de HD44780U), dus de software is herbruikbaar voor allerlei types. Ik maak gebruik van de code van Donald Weiman, die verschillende uitvoeringen op zijn site heeft staan. Hiernaast op het scherm zijn testprogramma (aangepast voor de ATtiny HomeNode door de pinnummers te wijzigen; tekst aangevuld met "/KM" zodat ik kon zien dat het mijn aangepaste software was).

Let op: voor de Arduino zijn er vergelijkbare display te vinden, die echter via een ingebouwde converter met I2C aangestuurd worden (nog minder pinnen maar trager). Zijn niet compatible met de software van Donald!

Stroomgebruik in een werkelijke schakeling

In mijn vuurvlieg-project (een batterij- en zonnecel-gevoed ontwerp) heb ik eens de stroom gemeten. De details zijn verhuisd naar de vuurvlieg-pagina...