Vis indlæg

Denne sektion tillader dig at se alle indlæg oprettet af dette medlem. Bemærk at du kun kan se indlæg der er oprettet i områder du i øjeblikket har adgang til.


Emner - kjoller

Sider: [1]
1
Artikler / Introduktion til vUSB - USB fra en billig AVR
« Dato: Marts 05, 2015, 14:57:54 »


Standarden inden for hobby-segmentet er at vi kommunikerer fra microcontroller til computeren via en seriel forbindelse. I de fleste AVR development boards (fx Arduino) er der en USB-til-seriel adapter indbygget, og ellers kan man finde en billigt på ebay.

Nogle gange ville det dog være rart at kunne forbinde direkte fra microcontrolleren til pc’en. Min grund til at eksperimentere med USB var specifikt at bygge en USB game-controller til at spille arcade-spil. Selve dimsen blev jeg aldrig færdig med, men til gengæld blev jeg noget klogere i processen.

OBS: Software nævnt i denne artikel forudsætter at du ved hvordan du kompilerer avr-gcc, og indlæser dem på din microcontroller. Hvis ikke, så vil jeg gerne anbefale bogen “Make: AVR Programming” af Elliot Williams. Alternativt er der sikkert hjælp at finde på google.

Virtuel USB
USB er en relativt kompliceret måde at kommunikere på, og derfor vil man typisk anvende hardware-implementeret USB. Det kræver dog at ens microcontroller har det, og det betyder oftest en ret heftig stigning i pris. Et eksempel på en sådan microcontroller er Atmega32U4, som er at finde i en Arduino Leonardo. På Mouser.com koster denne kr. 42,91, hvor en Atmega168PB koster kr 9,54. (Og så kan man få en atmega328p til nærmeste ingenting, hvis man er villig til at gamble på AliExpress). Derfor kan man, hvis man er en nærigpind, og ikke er bleg for at rode med lidt semi-obskur kode, bruge en virtuel USB-stack til at ‘emulere’ hardwaren. Standarden for dette er V-USB.

Hvis du tilfældigvis har købt en billig AVR-programmer fra ebay, så er der en ret god chance for at du allerede har stiftet bekendtskab med V-USB. USBasp og vusbtiny er ret udbredte på markedet, og begge er bygget med V-USB

Hardware
V-USB kræver kun en lille smule mere end det man normalt sætter på en AVR. Nedenstående diagram er fra forsiden af V-USB-projektets hjemmeside, og viser en Attiny2313. Jeg har dog mest eksperimenteret med en Atmega238P, men forskellen burde være minimal. (Jeg forstå dog ikke hvorfor de ikke har en pull-up på reset, men nok om det).



På en Atmega328P skal der (som minimum) være:
  • En pull-up (10 kohm) på reset, evt en reset-knap til at hive den ned igen.
  • Afkoblingskondensatorer på VCC og AVCC

For at få V-USB til at køre, så skal følgende også være på plads:
  • En krystal (12MHz anbefalet) på XTAL1 og XTAL2 (inkl passende kondensatorer)
  • Forbindelse gennem en 68 ohm modstand fra INT0 til D+ på USB
  • Forbindelse gennem en 68 ohm modstand fra en GPIO til D- på USB
  • En måde at få enten VCC ned til 3.3V eller en måde at få D+/D- -signalerne ned til 3.3V
  • En 1.5 kohm pull-up til D-.

De bedste, mest stabile signaler fås ved at regulere spændingen ned til 3.3V. Ovenfor gøres det ved at sætte to dioder i serie, men en lille linær regulator ville nok være bedre. På min første udgave af mit eksperiment gjorde jeg det ved hjælp af to zener-dioder på D+ og D-. Det er en billig løsning, og den virker, men Ralph Doncaster (http://nerdralph.blogspot.dk/2015/01/usb-interfacing-for-avr-microcontrollers.html) har vist at det ikke nødvendigvis er den gode løsning.

Mit projekt
Jeg satte mig for at bygge en mere generel løsning, som kunne bruges til lidt af hvert. Sådan en slags development board. Hulbræt-udgaven så sådan ud med et gamepad-’shield’ ovenpå:


(Jeg mangler et billede af den uden shield på, det kommer lige så snart jeg kan grave den op af projektkassen)

Efter at det var begyndt at virke finpudsede jeg lidt på diagrammet og kom frem til dette:


Det endte med at jeg fik lavet en PCB hos http://dirtypcbs.com, der så sådan ud:


Flere billeder, beskrivelse og link til github-side findes her: http://lab.kjlr.dk/p/handystick

Software
Med hardwaredelen vel overstået er vi ved sagens kerne: Software. Jeg indrømmer blankt at noget af dette er semi-sort snak for mig, men man kommer langt med lidt copy-paste.

Konfiguration - usbconfig.h
V-USB sættes op i usbconfig.h. Der er en masse indstillinger man kan fifle med; jeg vil gennemgå de vigtigste her - men det er nok en god idé selv at undersøge hvad de gør, og om der er andre der gør noget vigtigt.

Den første sektion er hardware-opsætning, altså clock-hastighed og hvilken port og pins USB-data-linjerne er forbundet til:
Kode:
#define USB_CFG_CLOCK_KHZ (F_CPU/1000) // Hardware-klokken i kHz. 
#define USB_CFG_IOPORTNAME D // Hvilken port. Jeg bruger D
#define USB_CFG_DMINUS_BIT 7 // Hvilken pin bruger D- - jeg har sat den på PD7
#define USB_CFG_DPLUS_BIT 2 //Hvilken pin bruger D+ - jeg har sat den på PD2

Hvis du bare gerne vil implementere allerede skrevet software, men på din egen hardware, så er dette muligvis det eneste du behøver at rette til. Hvis du gerne vil modificere lidt på det, eller skrive dit eget, så skal du også definere USB-klasse, samt det et vendor- og product-id, og du kan lave en tekst-beskrivelse af hvad produktet er.

Hvis du vil lave et HID (Human Interface Device, fx keyboard, mus eller joystick), så skal du også kigge på noget med længden af HID-description. HID devices er et specifikt og relativt omfattende emne, så jeg vil ikke gå dybere ind i det. Men du kan jo vælge at kigge på eksempel-softwaren til mit eksperiment ovenfor.

Vendor og Product ID
Hvis man skal lave et decideret produkt, og vil skrive på æsken at det er USB-kompatibelt, så skal man skaffe sig et vendor id, og man kan herefter bruge alle de product id’s. Vendor-id kræver et medlemskab hos USB.org (http://www.usb.org/developers/vendor/). Det koster dog USD 4.000 per år, så det er uden for mit hobby-budget. Så længe man arbejder med det på hobby-plan, så er der dog intet forgjort i at låne fra eksemplerne, eller endda tilfældigt finde på et - så længe man rammer et ikke-eksisterende produkt. Ellers kan det give rod med drivers.

Main-funktionen
Som i de fleste c-programmer er det main-funktionen der kører først, og det er dens opgave at kalde alle andre. Når al initialisering er overstået, er der typisk en uendeligt kørende løkke som denne:

Kode:
while(1) {
    usbPoll()
}

Dette er faktisk det eneste krav for en løkke; Man skal køre usbPoll-funktionen jævnligt for at sikre at det ‘administrative’ i USB-protokollen bliver overholdt. Man kan så sørge for at alt andet sker i interrupts. Jeg bruger i mit gamepad-eksempel følgende kode:
Kode:
while(1) {
    wdt_reset(); // Hold watchdog’en glad.
    _delay_ms(20); // Vent lidt for ikke at overdrive. Potentielt et problem for hardcore gamere.
    usbPoll(); // Administrativt USB-kald
    if ((reportBuffer.buttonMask!=readMask)&(usbInterruptIsReady())){ // Tjek om der er sket noget
      reportBuffer.buttonMask = readMask; // skriv ny buttonMask
      usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer)); // Send data afsted
    }
}

Jeg har en 2-sekunders Watchdog timer kørende, der genstarter softwaren, hvis noget låser, men ellers er det nye if-sætningen, og den heri indeholdte kode.

“reportBuffer” er den struktur, der bliver sendt over USB’en. Den indeholder en 8-bits størrelse ved navn buttonMask. Fra anden runde af løkken vil den indeholde det, der sidst er blevet sendt afsted.

Jeg har interrupts defineret på GPIO’erne til at finde ud af om der er blevet trykket på en knap. Hvis der er sket noget, så bliver resultaterne indlæst i readMask, der er af samme type som buttonMask. If-sætningen sammenligner reportBuffer.buttonMask med readMask for at se om der er sket noget med readMask siden sidst der blev sendt data. Hvis dette er tilfældet, så bliver reportBuffer.buttonMask opdateret, og resultatet bliver sendt til usbSetInterrupt-funktionen.

På den måde vil der, hver eneste gang man trykker eller slipper en knap, blive sendt data til computeren, og man kan hoppe, kravle og skyde i et eller andet spil :-)

Videre eksperimenter
Jeg ville rigtigt gerne forstå USB-protokollen og V-usb software-driveren mere i dybden, og det tror jeg sker bedst ved at eksperimentere med de forskellige eksempler man kan finde på http://www.obdev.at/products/vusb/. Jeg kunne f.eks godt tænke mig at se lidt på hvordan man kunne styre et standard 16x2 LCD gennem USB, eller måske en LED-cube. Jeg håber på at komme videre, og så vil jeg prøve at opdatere med dybere artikler.

Jeg håber at denne artikel har givet dig en lille smule indblik i hvordan V-USB virker, og at du har fået mod på at eksperimentere. Jeg kunne godt bruge lidt erfaringsudveksling.

PS:
Faktisk kom der en bonus med mit eksperiment ovenfor. Man kan installere USBAspLoader på den, en bootloader, der ved at holde en knap nede under reset emulerer en USBasp AVR-programmer, som kan programmere sig selv. Det gør at man kan lave en absurd billig arduino-klon, dog uden serial.  Det er derfor at der er to knapper på PCB'en; én til reset og én til at starte USBasp.

2
Andet lyd relateret / Lav en AUX-indgang på en gammel rør-radio
« Dato: September 18, 2014, 11:11:55 »
Halløj.

Min oprindelige plan var at skaffe en gammel busted radio, fjerne indmaden og derefter bygge en moderne forstærker og noget raspberry pi ind som lydkilde.

Men nu fik jeg tilfældigvis fingre i en radio i god stand, og som efter sigende skulle virke fortrinligt:


Og nu synes jeg egentligt at det er synd at strippe den. Derfor tænkte jeg om man kunne bruge én af kanalerne (den har FM, 4xAM og en grammofon-indgang) til en aux-kanal, fx til RPi'en.

Min første tanke var at bruge grammofon-indgangen. Men så vidt jeg husker, så er det typisk et meget svagt signal, der skal heri? Er det bedre at bruge fx en AM-indgang, og kan man 'bare' det? Hvilken slags lydsignal kommer der ud af sådan en fætter? Hvis man kunne bruge en AM-indgang, så er der flere (kort- mellem- og lang-bølge (og en FB?)), og så kunne man måske også have to aux-indgange?

Hvis I ikke på nuværende tidspunkt havde luret det, så er lyd ikke min stærke side :-)

3
Køb og Salg / Bortgives: Atmega development board til vUSB
« Dato: September 10, 2014, 17:32:13 »
Hej Elektronik'ere

Jeg blev aldrig færdig med min blog-serie om at bygge en billig arduino-klon. Det var mest fordi jeg fandt ud af at det var sjovere at nørkle med kredsløb, pcb-design og kode, end at skrive blog-indlæg.

Nu er jeg til gengæld færdig med mit næste projekt: Et lille Atmega board, det er lidt ala en arduino nano i størrelsen. Den har dog ikke noget USB<->Seriel-interface, men er i stedet beregnet til brug med vUSB. Hvis man bruger USBasploader, kan man få den til at fungere som sin egen programmer, men man kan også programmere den via ISP'en og bare bruge den til at lave en USB gamepad eller lignende.

Jeg har masser af PCB'er til overs (fik lavet 20), så hvis du betaler en 10'er for porto og kuvert, så sender jeg dig gerne én.

Læs mere her: http://lab.kjlr.dk/p/handystick

PS: Det kræver dog at du har mod på at lodde små SMD-dele (0603, 0805 og TQFP).

4
Hej folkens

Jeg er for sjov begyndt at rode med assembler til AVR. Det er selvfølgelig smartest når man ikke har så meget plads at gøre godt med og/eller har applikationer hvor timing er kritisk, men lige nu prøver jeg bare at knække nøden.

Jeg har prøvet at implementere et program hvor jeg blinker med LED'en på pin Arduino pin 13 (Svarende til PB5 - Port B, bit 5). Målet var at LED skulle skifte status hvert sekund. Så vidt jeg kan lure, så skulle det gerne være perfekt timet på 1.000.000 mikrosekunder (såfremt krystallen er tunet på præcis 16MHz). Det fylder 44 bytes, set i forhold til 1.084 bytes hvis man compiler det basale blink-eksempel fra Arduino - så kan man altid diskutere læsbarheden :)

Er der en assembler-haj, der kan fortælle om jeg er helt i skoven? Jeg er som sagt helt ny i assembler-verdenen. (Hvis ikke jeg kan få hjælp, så er det ren blær - jeg er sgu ret stolt over at reducere et programs størrelse med faktor 25  ;D )

Kode:
Kode:
; My first piece of assembler code. It is made to mimic the blink
; example from the Arduino environment. The arduino example compiles
; to around 1Kb - this is 44 bytes. And should be very
; precise in the timing.
.nolist;
.include "m88def.inc";
.list;


; SETTING CLOCK SPEED - currently at 16 MHz
.equ clockCyclesPerMilliSecond = 16*1000
; The delay to put between blinks in milliseconds
.equ delayMilliseconds = 1000
; The direction register, the port and the bit to set the pin of the
; LED to flash
; Currently at PB5 (Arduino pin 13)
.equ DDR = DDRB
.equ PORT = PORTB
.equ BIT = 5

; SETTING UP REGISTERS
.DEF my_register = R16

; Not sure if this is needed... It works without it.
rjmp setup

; setup
setup:
    SBI     DDR,BIT         ; Set pin to output

loop:
    sbi     PORT,BIT        ; 2 cycles - set pin HIGH
    rcall   Delay           ; 3 cycles (the call itself)
    cbi     PORT,BIT        ; 2 cycles - set pin LOW
    rcall   Delay           ; 3 cycles (the call itself)
    rjmp    loop            ; 2 cycles (the jump itself) - repeat
   
Delay:
    nop
    ; Delay consists of two loops - the inner loop loops for a
    ; millisecond, the outer counts the number of milliseconds-
    ; From every inner loop, there is subtracted the number of
    ; cycles to complete the outer loop (8). From the first time, there
    ; is also subtracted the number of cycles to call, setup and return
    ; from the subroutine as well as the cycles for switching the pin,
    ; half of the rjmp command and the nop in the start of this function
   
    ; inner loop : 4 cycles
    ; outer loop : 8 cycles
    ; pin switching, calling, returning and looping : 16 cycles
   
    ; Since precision is made by cutting the number of times the
    ; inner loop runs, it is important that the number of cycles
    ; in the outer loop and the one-time-fluff is divisble by 4.
   
    ldi     ZH,HIGH((clockCyclesPerMilliSecond-8-16)/4)
    ldi     ZL,LOW((clockCyclesPerMilliSecond-8-16)/4)
    ; A lot of nops and grief could be saved by only supporting a
    ; maximum of 255 millisecond delay.
    ldi     YL,LOW(delayMilliseconds)
    ldi     YH,HIGH(delayMilliseconds)
   
    delayloop:
            sbiw    ZL, 1       ; 2 cycles
            brne    delayloop   ; 2 cycles
       
        sbiw    YL,1                                     ; 2 cycles
        ldi     ZH,HIGH((clockCyclesPerMilliSecond-8)/4) ; 1 cycle
        ldi     ZL,LOW((clockCyclesPerMilliSecond-8)/4)  ; 1 cycle
        nop ; added to make a number of cycles divisible by 4 1 cycle 
        nop ; added to make a number of cycles divisble by 4  1 cycle
        brne    delayloop                                ; 2 cycles
   
    nop ; added to make a number of cycles divisible by 4 ; 1 cycle
    ret ;                                                   3 cycles

5
Generel Elektronik / Huller eller ej?
« Dato: Februar 18, 2014, 10:33:19 »
Jeg havde oprindeligt tænkt at 1206 var det mindste jeg kunne lave, men efter at have prøvet mig frem med 0805, så har jeg fundet på at jeg også lige skulle prøve 0603 - der er på vej til mig, og jeg glæder mig til at se om det alligevel bliver for småt.

Hvad bruger I? Er ting gennem huller stadig det foretrukne valg?

6
Arduino & Lign. / Endnu en arduino-klon
« Dato: Februar 03, 2014, 20:29:22 »
Hej folkens.

Jeg er i gang med min første egentlige produktudvikling, en arduino-klon. Jeg ved godt at det er gjort før, og det er mest for min egen skyld - men planen er at få et ordentligt, brugbart produkt ud af det i sidste ende.

Et af målene er at man i modsætning til den 'rigtige' arduino skal kunne bruge helt almindelige 5x7cm hulprint som shields. Og så skal den være pissebillig i produktion og dele.

Jeg er ved at lave en længere blog-serie på min nystartede blog (engelsk) http://kjoller.github.io/

Jeg tænker at når jeg var færdig, så ville jeg lave en sammenskrivning på dansk om hvordan en arduino var bygget op til Elektronik-Forum. Ind til videre må man følge med på bloggen, og hvis det er ok med boardets regler, så vil jeg løbende poste kortfattede, danske opdateringer i denne tråd.

Her er et sneak-peak på den prototype jeg fik samlet her i lørdags:

7
Andet digital relateret / Debounce af knapper og andet
« Dato: Januar 31, 2014, 07:57:23 »
Hej folkens

Hermed min første post på Dansk Elektronik Forum :-)

Jeg ville høre hvad folk normalt gør ift. at undgå støj på knapper, primært ifb. microcontrollere. Ind til videre har jeg brugt software debounce (sådan noget med et delay, og tjek om den virkeligt mener det).

Den længere historie:
Jeg ville se på rotary encoders, som i virkeligheden er to knapper/kontakter, der skifter som man drejer på håndtaget. I datasheet på en tilfældig sådan én er der beskrevet et kredsløb ala dette:



Altså, hvor der per kontakt er 2x10k modstand og 1x10nF kondensator. Den éne modstand er en almindelig pull-up, men hvad er den anden til? Jeg har set andre kredsløb hvor man bare bruger én pull-up-modstand og en kondensator. Tilfældigt google-resultat:



Hvis jeg skulle gætte, så handler det om at man bruger modstanden til at give mere mere tid til kondesatoren, så man kan nøjes med en mindre dims? Hvis jeg estimerer tidskonstanten for en 10k-modstand + 10nF-kondensator (R*C=T), så giver det 10.000ohm*0,00001F ~= 0,1s, hvilket vel lyder meget rimeligt for en debounce?

Men kan jeg spare en modstand væk? Jeg tænker at lave en mini-printkort, hvor jeg kan sætte en Rotary Encoder på, og så har jeg et anvendeligt standard-modul jeg kan bruge.

Som en advarsel, så bruger jeg hvad jeg husker fra elektronik i ungdomsskolen (15 år siden), fysik i gymnasiet (12 år siden) og hvad jeg har kunnet læse mig til i diverse elektronik-bøger fra biblioteket. Så bær venligst over med mig :-)


Sider: [1]