2008-11-17

Jednoduchý programátor pro Atmel AVR ...

Pokud nemáme paralelní port pro jednoduchý programátor typu DAPA, pak programátor na sériový port může být tím co nám vytrhne trn z paty. O tom jak jsem takový programátor stavěl je tento článek. Bylo to dobrodružství s elektronikou na celý den.

Hledání

Hledal jsem dlouho, než jsem našel konstrukci která se mi zamlouvala, byl to AVR In-Circuit Serial Programmer. Maje většinu součástek, chybí mi jen konektor na plochý kabel (WSL06G, podle katalogu GES), jsem se pustil do práce, překreslil si schémata do sešitu a popsal.

[FIXME: img:schéma]

Pilka a pilníky

Dalším rozhodnutím bylo mechanické provedení konstrukce. Inspirován přístupem v článku jsem se rozhodl že použiji zkušební plošňák a že jej položím nikoliv kolmo ale na plocho do konektoru. Vzal jsem tedy jeden plošňák, konektor a šel do dílny. Doma by z toho bylo moc nepořádku. Chvíle hraní s pilkou na železo a pilníky, a odnášel jsem si plošňáček který naprosto přesně zapadal do konektoru.


Hlavolam na stole

Doma na stole jsem začal řešit jak připevním konektor k plošňáku. Přesněji otázkou nebylo jak, ale kde přesně jej připájím. Původně jsem myslel že plošňák zasunu mezi vývody z konektoru a na jedné straně připájím. Neměl jsem ovšem jistotu že se vše zase vejde do konektoru. Proto jsem začal tím, že jsem příslušnou silou zasunul a zatlačil transistor do plošňáku až na doraz, aby byl co nejníže. Konektor šel zavřít, a tak jsem věděl že by to mohlo jít. Ještě jsem chvíli přemýšlel jestli by nebylo vhodnější připájet plošňák nikoli mezi vývody ale úplně vespod. Tuto variantu možná ještě budu zvažovat, kdybych stavěl druhý stejný programátor.

V této chvíli začalo skládání hlavolamu, přemýšlel jsem jak to celé dát dohromady, kam umístit jednotlivé součástky. To byla nejnáročnější část. Na papíře se toho moc nedalo, a tak jsem přemýšlel, představoval si, a občas zkoušel nějakou součástku zasunout. Opravdu to trvalo dlouho, nakonec jsem dospěl k názoru že místa je dost a že mi nezbude nic jiného než složit celý hlavolam po částech. Připájel jsem tedy konektor, a začal se třemi na něj připojenými odpory. Tedy chtělo by to menší odpory, vím že takové existují a dokonce jsou dva na původním obrázku. Ale já je neměl. Musel jsem si vystačit s tím co jsem měl. Po odporech přišly na řadu Zenerovy diody. Po nějakém přemýšlení jsem z nich nakonec udělal můstky jdoucí přes odpory. Tohle na tom celém bylo to nejtěžší, nesestavoval jsem vše v dvourozměrné rovině, ale v třírozměrném prostoru. Zkrátka hlavolam.

Pak jsem hledal tu správnou pozici pro transistor, to mi zabralo dost času. Musel jsem si do bloku nakreslit vývody transistoru z různých pohledů a popsat který je který. Zkrátka protože jeho zapojení nenosím v hlavě, musel jsem se neustále dívat do bloku. Nakonec jsem dospěl k pozici se kterou jsem byl spokojený. V tu chvíli jsem už měl představu jak zapojím zbylé odpory a poslední diodu. Takže transistor zapájený, začal jsem přemýšlet jak do toho zapojím celý kabel. Došlo mi, že jestli zapájím zbylé součástky, zapájet kabel se mi už nepodaří. Vzal jsem tedy připravený 6-ti žilový plochý vodič a začal tím že jsem na jeden konec začal připevňovat malinký plošňáček pro zapájení nožiček až je koupím, nebo drátků jenž se zavedou do nepájivého pole. Plochý vodič je totiž z pletených lanek a ty prostě do nepájivého pole zapojit nikdy nepůjdou, protože jsou měkká a jsou to lanka. Poté jsem začal studovat zapojení 6-ti vývodové hlavy, abych si mohl v bloku poznamenat, který vodič patří kam.


S obrázkem v bloku jsem začal oddělovat jednotlivá lanka a postupně je pájet. A tady jsem udělal postupně dvě nepříjemné chyby. Stačilo jedno lanko omylem zapájet na jinou pozici. Protože jsem při pájení byl až moc poctivý, a lanko otočil kolem vývodu odporu, nešlo to ven. V tak malém prostoru, kdy transformátorová páječka je jako slon v porcelánu a není co čím chytit je jakákoliv chyba příliš drahá. Nakonec se mi podařilo lanko napůl od-cvaknout a napůl utrhnout. Si musím pořídit lepší štípací kleště s velmi malou špičkou, protože těmi mými jsem se nemohl dostat tam kam jsem potřeboval. Chvilka strachování, jestli zbývající délka lanka bude stačit, a různé pokusy jak zapájenou dírku očistit od cínu. O chvíli později jsem udělal jinou chybu, lanko jsem špatně odizoloval a když jsem jej protáhl dírkou, několik vláken neprošlo. Všiml jsem si toho až bylo zapájené. Opravu jsem to tak nemohl nechat, ty vlákna se blížily k vývodu transistoru a zkrat byl otázkou času či otřesů. A zase, lanko dobře zapájené, skoro ukázkově, bohužel obtočené okolo vývodu odporu. Nešlo ven a nešlo. Nakonec jsem je taky pinzetou utrhl. A zase čištění otvoru, vytáhnout zbytky vláken a zase znova. Ale toto byla poslední velká chyba.

Po zapájení zbývajících vývodů a součástek jsem se jal obvod přeměřovat. V té změti jsem si nebyl jist jestli se tam neschovává ještě nějaká další chyba. Navíc už nebylo řádné světlo a pájel jsem tak někdy až na slepo. Transformátorová páječka jako slon, neviděl jsem jestli je někde něco zapájené špatně. Při proměřování se mi nelíbila jedna hodnota a tak jsem odpor který byl připojený k vývodu 6 a 7 konektoru DB9 znovu přepájel. Žádné další podivnosti jsem se nedoměřil. Ale ono měření samotné bylo podivnost. Velmi špatně jsem chytal hrotem kontakt.

Poté jsem vše zavřelo do plastového krytu konektoru, připájel k nouzové hlavě ještě 6 drátků a sbíral odvahu to celé vyzkoušet. Už bylo dost hodin, a představa že to nebude fungovat nebyla zrovna příjemná. Uvažoval jsem že to všechno sbalím a pro dnešek toho nechám. Nakonec jsem se to rozhodl programátor vyzkoušet, a dotáhnout to do konce.

Test

Na volném nepájivém poli sestavil jednoduchý obvod se dvěma LED na PB3 a PB4 a zasunul do něj naprogramovanou ATtiny15L z předchozích pokusů s paralelním programátorem. Nejdříve jsem přivedl napětí na obvod a po krátkém hledání chyby mi došlo že opravdu musím přitáhnout RESET MCU k napájecímu napětí malým odporem. Pak se diody rozblikaly. Poté jsem zasunul vývody z hlavy plochého kabelu a po zapnutí opět diody blikaly. Když už nic jiného, programátor neovlivňoval negativně MCU v obvodu.

Vše jsem vzal a přesunul se o dva metry dozadu k serveru a ... a nic. Program sice fungoval ale programátor ne. Chvilka experimentování s avrdude a uisp, a chvilka studování /etc/avrdude.conf. Poté jsem dospěl k poznání, že programátor který jsem vyrobil není podle zapojení DASA ale serial ponyprog (ponyser) nebo Lancos SI-Prog (siprog). A konečně úspěch, programátor detekoval připojený MCU
# avrdude -c ponyser -p t15 -P /dev/ttyS0

avrdude: AVR device initialized and ready to accept instructions
...
Nakonec ještě nahrát do MCU program
# avrdude -c ponyser -p t15 -P /dev/ttyS0 \
-U flash:w:/tmp/morse15a.hex

...
avrdude done. Thank you.

Závěr

Strávil jsem nad programátorem celý den, a zhodnotil bych jej jako úspěšný. Předsi jen jsem zase vzal do ruky pájku a dokázal něco spájet. Ten moment kdy programátor detekoval MCU mi spadl kámen ze srdce. Do poslední chvíle jsem si nebyl jist že jsem vše udělal správně. Z celé práce my vyplynulo několik poučení:

  • Sestavování obvodu tímto způsobem je neskutečný hlavolam (omezené místo a velké součástky). Ke všemu jsem neznal zpaměti zapojení vývodů diod a transistoru. Musel jsem si je poznamenat do bloku a neustále se kontrolovat.
  • Jestli v tom chci pokračovat, musím si pořídit mikropájku. Opravdu to s transformátorovou páječkou není ono, ještě že ty diody a transistor nemají ručičky, určitě bych dostal pár facek.
  • Třetí ručička, ten kovový stojánek s lupou a dvěma krokodýlky je geniální vynález. Ostatně další jeden až dva krokodýlky jsem při pájení požíval téměř pořád.
  • Chce to nekonečnou trpělivost a neskutečnou pečlivost, v tak malém prostoru a bez mikropájky je každá chyba obrovským utrpením. Je nutné se opravdu pořád kontrolovat, a dělat si přestávky na oddech.
  • V takové miniaturizaci potřebuji taky lepší štípací kleště (štípačky), potřebuji takové které mají velmi malý konec kterým se dostanu skoro všude.
  • Univerzální PCB jsou velmi zajímavý materiál, který má specifické vlastnosti. Dá se například lámat podél dírek. Rovněž jeho opracování není nikterak obtížné, pilka na železo upnutí do svěráku, a sada pilníčků mi dovolí dosáhnout přijatelného tvaru.

2008-11-09

Použití časovačů k běhu úloh

Protože pro vážnější práci nemohu mít založený program na čekacích smyčkách, zkoušel jsem dnes rozblikat LED diodu s použitím časovače. Časovač generuje přerušení a obslužná rutina pak počítá tato přerušení a po určitém počtu změní stav LED diody. Tento přístup mi fungoval. Program jsem ale přepracoval a uvádím jeho poslední verzi.

Diodou na PB3 bliká starý kód s použitím čekacích smyček.
Kód s použitím časovače blikal diodou na PB4 ale je neaktivní.
Na PB4 jsem připojil sluchátko a s pomocí druhého časovače generuji zvuk.


;; Tabulka vektorů přerušení
.ORG 0
RESET: RJMP MAIN ; Reset Handle
V_INT0: RJMP RESET ; External IRQ0 handler
V_IOPCH:RJMP RESET ; Pin Change Interrupt
RJMP T1CMA ; Timer1 Compare Match A
V_T1OVF:RJMP RESET ; Timer1 Overflow
V_T0OVF:RJMP T0OVF ; Timer/Counter0 Overflow
V_EERDY:RJMP RESET ; EEPROM Ready
V_ANAC: RJMP RESET ; Analog Comparator
V_ADCCC:RJMP RESET ; ADC Conversion Complete
.ORG 9

;;; Initialize the MCU
INIT:
;;; Initialize T0 as interrupt source delivering ticks.
;LDI W,CS0CK1024 ; 1562.5Hz (6.1Hz)
;LDI W,CS0CK256 ; 6250.0 Hz (24.4Hz)
LDI W,CS0CK64 ; 25kHz (97.66Hz)
;LDI W,CS0CK8 ; 200kHz (782.25Hz)
OUT TCCR0,W

;;; Initialize T1 as the source for the beep frequency.
;; Set CTC1 to Reset Counter to $00 on Compare Match A
;; Set COM1A to Timer/Counter disconnected from output pin OC1A
;; Set source to CK (cca 1.6MHz)
;; Set Prescaler to CK/1024 (cca 1562.5Hz, 0.64ms)
; LDI W,(CTC1 | CS1CK1024)
; LDI W,(CTC1 | CS1CK512) ; 3125Hz
; LDI W,(CTC1 | CS1CK256) ; 6250Hz
LDI W,(CTC1 | CS1CK128) ; 12500Hz
OUT TCCR1,W
;; Set the divide factor, the compared value.
LDI W,3 ; 12500Hz/3 = 4166.6 Hz
OUT OCR1A,W


;; Reset all counters and prescalers.
LDI W,0
OUT TCNT0,W
OUT TCNT1,W
LDI W,(FOC1A | PSR1 | PSR0)
OUT SFIOR,W

;; Clear Interrupt Flags for all counters.
LDI W,(OCF1A | TOV1 | TOV0)
OUT TIFR,W

;; Allow Interrupt from Counter 1 Compare Match and Counter 0 Overflow
LDI W,(OCIE1A | TOIE0)
OUT TIMSK,W

RET


;;; Main code executed after power on and/or reset.
MAIN:

; We don't initialize stack (SPL,SPH) because ATtiny15
; contains hardware stack 3 level deep.

;; Initialize
LDI W,$18 ; PB3,PB4 out, only
OUT DDRB,W

RCALL INIT
SEI
;; All peripherals are initialized, now the main program.


;; Before main loop and flashing led we do a reset blinking.
LDI RA,16
RSTFL:
RCALL BLINK_RB3
LDI R22,1
RCALL DLY100MS
DEC RA
BRNE RSTFL

SBI PORTB,3 ; LED on
LDI R22,6
RCALL DLY3
CBI PORTB,3 ; LED off
RCALL DLY100MS

CBI PORTB,3
;;; Main Program Loop, the old code running in prallel.
LOOP:
RCALL BLINK_RB3

LDI R22,1
RCALL DLY3

; SBI PORTB,4
LDI R22,2
RCALL DLY3

RCALL BLINK_RB3
; CBI PORTB,4
RCALL DLY
RCALL DLY
RCALL DLY
RCALL DLY
RCALL DLY

RJMP LOOP

;; Zpožďovací procedura

DLY:
LDI R22,2
DLY3: LDI R21,255
DLY2: LDI R20,255
DLY1: DEC R20
BRNE DLY1
DEC R21
BRNE DLY2
DEC R22
BRNE DLY3
RET
;;; Timer0 is used in creation of tick for software. This interupt
;;; should be generate with 25kHz frequency.
T0OVF:
;; Because owerflow, we need to set the value.
LDI WI,7 ; With CK8 this should generate 100Hz overflow
OUT TCNT0,WI

;; Now we generate slower signal
DEC T0L
BRNE NOSLOW
;; Counter is zero. Initialize for next cycle and generate SLOW TICK
LDI T0L,100-1
;; SLOW TICK
; The RB4 is for earphone.
;RCALL BLINK_RB4
NOSLOW:
RETI
;;; Blink the LED on RB4 pin. We do this by inverting the value on the pin.
BLINK_RB4:
;; Read the RB4 and negate it to genereate tone.
SBIC PORTB,4
RJMP RB4CLR
RB4SET: SBI PORTB,4
RJMP RB4Done0
RB4CLR: CBI PORTB,4
RB4Done0:
RET

;;; Blink the LED on RB3 pin. We do this by inverting the value on the pin.
BLINK_RB3:
;; Read the RB3 and negate it to genereate tone.
SBIC PORTB,3
RJMP RB3CLR
RB3SET: SBI PORTB,3
SBR BITF,0b00000001 ; Enable beep
RJMP RB3Done0
RB3CLR: CBI PORTB,3
CBR BITF,0b00000001 ; Stop beep
RB3Done0:
RET

;;; Timer/Counter 1 Compare Match A Interrupt Routine. This generate tone.
;;; Because this interrupt is caled often it should be as short as possible.
T1CMA:
SBRC BITF,0
RCALL BLINK_RB4
RETI

2008-11-08

První experimenty s ATtiny15L

Tak jsem se konečně přiměl k tomu, sestavit si jednoduchý programátor a skusit naprogramovat ATtiny15L. Programátor je to nejjednodušší co jsem našel, programátor na pralelní port. Takže vzal jsem konektor na parallení port, napájel 5 drátků a toť vše.



Na nepájivém poli jsem pak zapojil drátky i ATtiny15L.

From ATtiny15 Parallel Port Programmer


V počítači sice nemám paralelní port, ale je v jednom malém servříku za mnou, tak jsem na ten srvřík nainstaloval programátor uisp a avrdude.

From ATtiny15 Parallel Port Programmer


S uisp mi to funguje příkazy:

# uisp -dlpt=/dev/.static/dev/parport0 -dprog=dapa --download
# uisp -dlpt=/dev/.static/dev/parport0 -dprog=dapa --erase --upload --verify if=/tmp/blik15.hex -v=3

A s avrdude pak příkazy:
# avrdude -c dapa -p t15
# avrdude -c dapa -p t15 -U flash:w:/tmp/blik15.hex

Program který na to maličkém obvodu právě běží je následující. Jen sem z něj vystříhl definice periferií aby byl kratší.

.... definice periferií
.def w=r16

;; Tabulka vektorů přerušení
.ORG 0
RESET: RJMP MAIN ; Reset Handle
V_INT0: rjmp RESET ; External Interrupt Request 0
V_IOPCH:rjmp RESET ; Pin Change Interrupt
V_T1CM: rjmp RESET ; Timer/Counter1 Compare Match A
V_T1OVF:rjmp RESET ; Timer/Counter1 Overflow
V_T0OVF:rjmp RESET ; Timer/Counter0 Overflow
V_EERDY:rjmp RESET ; EEPROM Ready
V_ANAC: rjmp RESET ; Analog Comparator
V_ADCCC:rjmp RESET ; ADC Conversion Complete


; Main code executed after power on and/or reset.
.ORG $009
MAIN:

; We don't initialize stack (SPL,SPH) because ATtiny15
; contains hardware stack 3 level deep.

;; Initialize
LDI W,$18 ; PB3,PB4 out, only
OUT DDRB,W

;; Main Program Loop
LOOP:
SBI PORTB,3

LDI R22,1
RCALL DLY3

SBI PORTB,4
LDI R22,2
RCALL DLY3

CBI PORTB,3
CBI PORTB,4
RCALL DLY
RCALL DLY
RCALL DLY
RCALL DLY
RCALL DLY

RJMP LOOP