Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Laderegler Test Tueftler Seite

(Lösung B: Anpassen der Spannung an D+ und D-)
(Quellen)
Zeile 250: Zeile 250:
  
 
== Quellen ==
 
== Quellen ==
[http://www.obdev.at/products/vusb/index.html V-USB Homepage by Objective Development]
+
* [http://www.obdev.at/products/vusb/index.html V-USB Homepage by Objective Development]
[http://vusb.wikidot.com/ V-USB Wiki]  
+
* [http://vusb.wikidot.com/ V-USB Wiki]  
[[Kategorie:Microcontroller]]
+
* Alle drei Schaltpläne wurden aus der Wiki von V-USB entnommen.
 +
[[Kategorie:Microcontroller]]

Version vom 10. Mai 2010, 15:54 Uhr

Mit V-USB von Objective Development ist es ohne weitere Hardware möglich, mit einem AVR Mikrocontroller ein USB-Gerät aufzubauen.


Hardware Voraussetzungen des AVRs

Spannungspegel-Problem

Da der AVR mit anderen Spannungen als die des USB-Standards arbeitet, müssen diese Angepasst werden. Der Computer und der AVR-Mikrocontroller haben beide bestimmte Anforderungen an die Spannung für einen High- bzw. Low-Pegel. Da wir die Computerseite nicht verändern können, müssen die Anpassungen am AVR stattfinden. Vom PC wird ein Low-Pegel als 0V, ein High-Pegel als 3,3V übertragen. Jedoch ist die kein Problem, da die AVR-Mikrocontroller selbst bei 5V diesen Pegel sicher als High erkennen. Die andere Richtung ist ein größeres Problem. Der Computer erwartet als Low-Pegel eine Spannung von 0V - 0,8V und 2V - 3,6V als High. Um diese Voraussetzungen zu erfüllen, muss entweder der AVR mit einer Spannung von 2V - 3,6V betreiben werden oder die Pegel müssen an D+ und D- des AVRs angepasst werden.

Lösung A: Verringern der Betriebspannung des AVRs

Für diese Lösung wird die Betriebsspannung des AVRs auf 3,3V - 3,6V herunter gesetzt. Dies ist mit einem 3,3V-Spannungsregler (LE33CZ) möglich.

Spannungsanpassung mit Dioden


Vorteile

  • Saubere Lösung. Schnelle Übergänge auf D+ und D-
  • Gute Störfestigkeit am Signaleingang

Nachteile

  • 3,3V-Spannungsregler sind oft teuer und schwer zu beschaffen
  • Viele AVRs funktionieren nicht sicher bei den Angeforderten Taktraten
  • Hohe Stromaufnahme durch den Spannungsregler (überschreiten maximale Stromaufnahme von 500mA)

Ebenso ist es möglich, die Spannung mit Gleichrichterdioden zu reduzieren. Hierfür werden einfach zwei oder drei Gleichrichterdioden in Reihe vor VCC des AVRs geschaltet.

Pegelanpassung mit Zenerdioden

Zusätzliche Vorteile

  • Niedrige kosten / Bauteile sind leicht zu bekommen.
  • kein Ruhestrom --> USB-Konformer Standby-Modus

Zusätzliche Nachteile

  • Keine Spannungsregelung --> Spannung kann bei hoher Last einbrechen
  • Die unregulierte Spannung ist problematisch für Analoge Schaltungen (ADC,...)

Lösung B: Anpassen der Spannung an D+ und D-

Ebenso kann man die Spannung an den Datenleitungen (D+ und D-) mit Zenerdioden verringern. Es werden 3,6V Low-Power Zenerdioden (wie 1N4148, 500mW oder weniger) empfohlen, da diese eine geringe Kapazität haben und somit weniger Störungen auf den Datenleitungen verursachen.

Pegelanpassung mit Zenerdioden

Wenn diese Lösung verwendet wird, stellen sie vor Benutzung sicher, dass die Spannungspegel mit den geforderten Pegeln(LOW:0V-0,8V HIGH:2V-3,6V) übereinstimmen.

Vorteile

  • Niedrige kosten
  • Leicht zu bekommen
  • Ganze Schaltung kann mit 5V betrieben werden --> Hohe Taktraten möglich

Nachteile

  • Keine saubere Lösung: Es muss ein Kompromiss zwischen allen Möglichkeiten gefunden werden.
  • Zener-Dioden kommen mit einem breiten Spektrum an Merkmalen. Deshalb könnten die Ergebnisse nicht reproduzierbar sein.
  • Hohe Ströme beim Senden von High-Leveln

Allgemeine Anmerkungen zur Hardware

Es wird bei jeder der oben genannten Schaltungen ein PullUp-Widerstand (1,5k - 10k) von D- nach Vcc benötigt. Ebenso muss zwischen AVR und Die Datenleitungen ein Widerstand von je 68 Ohm.


Welche Taktraten können verwendet werden?

Momentan unterstützt V-USB Taktraten von 12 MHz, 12.8 MHz, 15 MHz, 16 MHz, 16.5 MHz, 18 MHz und 20 MHz. Diese Taktraten sind präzise, dies bedeutet, dass ein Quarz mit 11.9 MHz nicht funktionieren würde. Nur bei den 16.5 und 12.8 MHz Varianten ist eine Toleranz von 1%.16.5 MHz kann z.B. mit dem internen RC Oszillator von AVRs wie dem ATTiny25/45/85 oder dem ATTiny26 erreicht werden. Entscheidungshilfe

  • Möchten sie den internen RC Oszillator benutzen? Dann nehmen sie die 16.5MHz-Variante.
  • Ist sehr wenig Speicher vorhanden? Verwenden sie am besten die 16MHz oder 20Mhz Variante.
  • Wird der AVR mit einer niedrigen Spannung betrieben? Dann verwenden sie die 12MHz-Variante.
  • Wollen sie CRC-Prüfsummen verwenden? Benutzen sie die 18Mhz-Variante.


Anschluss an den AVR

Die Datenleitung D+ muss über den 68 Ohm-Widerstand mit dem Port INT0 des AVRs verbunden werden. D- kann an einen beliebigen Port. Diese Ports müssen dann in der "usbconfig.h" angepasst werden.

Software des AVR: Die Firmware

Als erstes muss man sich die neueste Version von V-USB von folgender Seite herunterladen: [1] Nachdem sie das Archiv heruntergeladen haben, entpacken sie es und kopieren sie den Ordner "usbdrv" in ihr Projektverzeichnis. Kopieren bzw. erstellen das Makefile und passen darin die Taktrate und den verwendeten Controller an. Ebenso wird eine "usbconfig.h" benötigt, diese kann z.B. aus dem tests-Ordner kopiert werden. In dieser müssen nun die Punkte USB_CFG_IOPORTNAME, USB_CFG_DMINUS_BIT und USB_CFG_DPLUS_BIT angepasst werden.

In der main.c müssen immer als erstes folgende Dateien importiert werden:

#include <avr/io.h> //IO-Zugriff: Braucht man immer
#include <avr/interrupt.h> // V-USB braucht interrupts
#include <avr/pgmspace.h>
#include <avr/wdt.h> //Watchdog: Sollte immer aktiv sein.

#include "usbdrv.h" //Der USB-Treiber
#include <util/delay.h> //Wird später für Timing etc. benötigt

Gerät mit selbst geschriebenem PC-Treiber (kein HID)

Der Code für ein eigenes Gerät wird hier am Beispiel eines Gerätes veranschaulicht, bei dem sich über USB der PWM-Kanal steuern lässt. Damit kann man zum Beispiel eine LED dimmen.

Nach den Includes komm nun die Funktion zum Verarbeiten eingehender Daten. Das erste Empfangene Byte, also der Befehl wird mit rq->bRequest abgefragt. In diesem Fall ist dieser entweder 0 oder 1. 0 bedeutet den PWM-Wert zu setzen, 1 bedeutet den Status (PWM-Wert) zurückzusenden. Die einzelnen Parameter des Aufrufs können mit rq->wValue.bytes[id] abgefragt werden. Bei Befehl 0 wird in rq->wValue.bytes[0] der neue PWM-Wert übertragen. Durch setzen von replyBuf kann festgelegt werden, welche Daten zurückgesendet werden sollen. Dabei muss immer replyBuf[id] verwedet werden. Bei Befehl 1 wird mit replyBuf[0] = OCR1A der aktuelle PWM-Wert zurückgesendet. Mit return 2 wird dann noch mitgeteilt, dass überhaupt was zurückgesendet werden soll. Mit return 0 wird nichts zurückgesendet. Das ist in diesem Fall der Fall, wenn ein ungültiger Befehl übermittelt wurde.

USB_PUBLIC uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;
static uchar    replyBuf[2];

    usbMsgPtr = replyBuf;
    if(rq->bRequest == 0){
	replyBuf[0] = rq->wValue.bytes[0];
        replyBuf[1] = 0x0;

	OCR1A=rq->wValue.bytes[0];
	eeprom_write_byte(0,OCR1A);
	return 2;
    }
    else if (rq->bRequest == 1) {
	replyBuf[0] = OCR1A;
        replyBuf[1] = 0x0;
	return 2;
    }
    return 0;
}


Als nächstes komm void main: Hier schalten wir als erstes den Watchdog-Timer ein. Danach setzen wir alle Ports und DDR so wie wir sie brauchen. Es ist nur darauf zu achten, dass INT0 ein Eingang ist. Bei einem Atmega8 ist dies PORTD.2. Für unser Beispiel setzen wir TCCR1A als 8_bit PWM-Timer. Danach laden wir den letzten PWM-Wert aus dem EEPROM (Wird immer beim Ändern gespeichert). Nun trennen wir die Verbindung für > 500ms, dies wird benötigt, um nach einen Neustart des Mikrocontrollers (z.B. durch Watchdog) dem PC mitzuteilen, dass er neugestartet ist. Danach Verbinden wir uns wieder mit usbDeviceConnect(). Nun muss die Verbindung mit usbInit() initialisiert werden ud die Interrupts mit sei() eingeschaltet werden. Nun muss nur noch im Mainloop der Watchdog zurückgesetzt werden und usbPoll() aufgerufen werden.

int main(void)
{
uchar   i;

    wdt_enable(WDTO_1S);
    DDRD = ~(1 << 2);   /* all outputs except PD2 = INT0 */
    DDRB = 0xff;    /* output pins setzen */
    PORTD = 0;     /* USB-Verbindung */
    PORTB = 0;     /* output pins aus*/

	TCCR1A = (1<<WGM10)|(1<<COM1A1); // PWM, phase correct, 8 bit.
	OCR1A=eeprom_read_byte(0);


/* We fake an USB disconnect by pulling D+ and D- to 0 during reset. This is
 * necessary if we had a watchdog reset or brownout reset to notify the host
 * that it should re-enumerate the device. Otherwise the host's and device's
 * concept of the device-ID would be out of sync.
 */

    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
    i = 0;
    while(--i){         /* fake USB disconnect for > 500 ms */
        wdt_reset();
        _delay_ms(2);
    }
    usbDeviceConnect();
    usbInit();
    sei();
    for(;;){    /* main event loop */
        wdt_reset();
        usbPoll();
    }
    return 0;
}

Damit ist die Firmware fertig. Hier noch ein Makefile für avr-gcc: (Chip: Mega8, Clock: 12MHz, Programmer: Ponyser)

# Name: Makefile
# Project: edited PowerSwitch
# Author: 
# Creation Date: 
# Tabsize: 4
# Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
# This Revision: $Id: Makefile 277 2007-03-20 10:53:33Z cs $

DEVICE = atmega8
AVRDUDE = avrdude -c ponyser -P /dev/ttyS0 -p $(DEVICE)
# Choose your favorite programmer and interface above.

COMPILE = avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=$(DEVICE) #-DDEBUG_LEVEL=2
# NEVER compile the final product with debugging! Any debug output will
# distort timing so that the specs can't be met.

OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o

# symbolic targets:
all:	main.hex

.c.o:
	$(COMPILE) -c $< -o $@

.S.o:
	$(COMPILE) -x assembler-with-cpp -c $< -o $@
# "-x assembler-with-cpp" should not be necessary since this is the default
# file type for the .S (with capital S) extension. However, upper case
# characters are not always preserved on Windows. To ensure WinAVR
# compatibility define the file type manually.

.c.s:
	$(COMPILE) -S $< -o $@

flash:	all
	$(AVRDUDE) -U flash:w:main.hex:i


# Fuse low byte:
# 0xef = 1 1 1 0   1 1 1 1
#        ^ ^ \+/   \--+--/
#        | |  |       +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz)
#        | |  +--------------- SUT 1..0 (BOD enabled, fast rising power)
#        | +------------------ CKOUT (clock output on CKOUT pin -> disabled)
#        +-------------------- CKDIV8 (divide clock by 8 -> don't divide)
#
# Fuse high byte:
# 0xdb = 1 1 0 1   1 0 1 1
#        ^ ^ ^ ^   \-+-/ ^
#        | | | |     |   +---- RSTDISBL (disable external reset -> enabled)
#        | | | |     +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V)
#        | | | +-------------- WDTON (watchdog timer always on -> disable)
#        | | +---------------- SPIEN (enable serial programming -> enabled)
#        | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved)
#        +-------------------- DWEN (debug wire enable)
#fuse_tiny2313:	# only needed for attiny2313
	# $(AVRDUDE) -U hfuse:w:0xdb:m -U lfuse:w:0xef:m


clean:
	rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s

# file targets:
main.bin:	$(OBJECTS)
	$(COMPILE) -o main.bin $(OBJECTS)

main.hex:	main.bin
	rm -f main.hex main.eep.hex
	avr-objcopy -j .text -j .data -O ihex main.bin main.hex
	./checksize main.bin
# do the checksize script as our last action to allow successful compilation
# on Windows with WinAVR where the Unix commands will fail.

disasm:	main.bin
	avr-objdump -d main.bin

cpp:
	$(COMPILE) -E main.c

D+ ist in diesem Beispiel mit PD2 verbunden, D- mit PD0. Die LED hängt an PB1. (Schaltplan noch in Arbeit.)

Die PC-Software zu diesem Beispiel wird bald verfügbar sein.

HID-Gerät (Tastatur/Maus/...)

[noch in Arbeit]

PC-Software bei nicht HID-Projekten (Treiber)

[noch in Arbeit]

Quellen


LiFePO4 Speicher Test