PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AVR-USB (obdev.at) in Gang bringen



robocat
29.07.2008, 22:43
hallo ihr,

vorneweg: ein tutorial ist das hier nicht, da würde ich den mund etwas voll nehmen. nur findet man bei einer roboternetz suche herzlich wenig, was avr und usb betrifft. das kann doch so nicht bleiben.

ich wollte einen atmega8 mit usb ansteuern, wollte dazu aber nicht extra einen chip wie den FTDI FT232R verwenden. das ganze soll später dazu dienen, mit dem pc die werte eines luftdrucksensors auszulesen - vorerst war ich aber damit zufrieden, eine led ein- und auszuschalten.

ich stolperte über die seite von Objective Development (http://www.obdev.at/products/avrusb/index-de.html), die eine software für avr-controller entwickelt haben, die eine vielzahl von anwendungen zulässt, im grunde aber eine möglichkeit zur kommunikation zwischen pc und avr über usb bereitstellt, und das mit minimalem hardwareaufwand (nein, ich bekomme kein geld für schleichwerbung, bin nur begeistert, dass es sowas gibt ;)).

auf der suche nach einem passenden beispielprojekt fand ich das hier http://ast.m-faq.de/USB-LCD/USB-LCD_en.htm, wobei auf http://www.modding-faq.de/index.php?artid=615&page=1 eine beinahe idiotensichere aufbauanleitung beschrieben ist. damit wird ein lcd über usb angesteuert, das ich der einfachheit halber einfach mal weggelassen habe.

http://www.modding-faq.de/moddingfaq/lcd/usb-lcd/USB-LCD_tb.png

ich habe nur eine led (mit vorwiderstand) an PB1 angeschlossen. anstelle des LM317 habe ich einen 3,3V festspannungsregler verbastelt, und eben keinen tiny2313, sondern den atmega8 verwendet.

ausser dem controller und ein paar kleinen widerständen benötigt man eigentlich nur eine usb-buchse (verdammt, welcher pin ist da nun D+ und D-? ist aber in der aufbauanleitung gut erkennbar) und einen 12MHz quarz. einer der 68R widerstände (der von der D- leitung) wird mit PD0 (pin 2 am controller) verbunden, der andere (D+) mit PD1 und PD2 (pin 3 und 4). 1,5kOhm widerstand wie im schaltplan gezeichnet nach 3,3V.

das erste problem kommt beim flashen. der controller wird mit 3,3V versorgt, kann man trotzdem einen standard 74HC244 parallelport programmer verwenden? ich weiss es bis heute nicht, denn ich habe, um dieses problem zu umgehen, noch einen 7805 spannungsregler angelötet, und zum flashen immer über diesen versorgt. das usb kabel sollte man währenddem tunlichst abklemmen, sonst kommt sich da was in die quere. für hinweise, ob es auch mit 3,3V geht, wäre ich dankbar.

also frisch hinein mit dem code in den controller! welchem code? ich habe mir das projektpaket http://www.modding-faq.de/moddingfaq/lcd/usb-lcd/USB-LCD.zip heruntergeladen, und dann folgende änderungen daran vorgenommen:

1. im makefile wird aus dem attiny2313 ein atmega8 gemacht.
2. in der datei "main.c" wird in der funktion main folgendes geändert:

PORTB = 0;
DDRB = 0xFF;
PORTD = 0;
DDRD = 0b01111000;
damit ist die led an PB1 anfangs ausgeschalten.
3. ebenfalls in der datei main.c in der funktion usbFunctionSetup ändert man folgenden abschnitt:

case cmdLCD_BG:
if(data[2] != 0)
PORTB |= (1 << 1); // wir wollen PB1 schalten
else
PORTB &= ~(1 << 1);
len = 1;
break;
4. in meinem avr studio (mit gcc als c plugin) heisst der interrupt nicht SIG_INT0 sondern SIG_INTERRUPT0. das muss in der datei usbdrvasm.S geändert werden:

.global SIG_INTERRUPT0
.type SIG_INTERRUPT0, @function

SIG_INTERRUPT0:

die fusebits des atmega8 müssen auf externen takt mit dem 12MHz quarz umgestellt werden (SUT0, CKSEL0, BOOTSZ1, BOOTSZ0 kriegen ein häkchen in ponyprog so wie hier http://palmavr.sourceforge.net/cgi-bin/fc.cgi?P_PREV=ATmega8&P=ATmega8&V_LOW=C1&V_HIGH=99&M_LOW_0x3F=0x01&M_LOW_0x40=&M_LOW_0x80=0x80&M_HIGH_0x01=&M_HIGH_0x06=0x00&M_HIGH_0x08=&M_HIGH_0x10=&M_HIGH_0x20=0x00&M_HIGH_0x40=0x00&M_HIGH_0x80=&B_SPIEN=P&B_SUT0=P&B_BOOTSZ1=P&B_BOOTSZ0=P&B_CKSEL0=P&O_BITS=Apply+fuse+bits).

man beschreibt also den controller, setzt die fusebits (am besten letzteres zuerst, und dann eine led blinken lassen, um zu sehen ob er auch wirklich noch richtig tickt). danach kommt der grosse moment und nachdem man die schaltung ans usb angeschlossen hat (vorher den 7805 freimachen) macht es unter windoof xp "dingding" und ein usb gerät wird erkannt. man kann nun einen treiber dafür aussuchen, hierzu verwendet man die datei driver\USB-LCD.inf aus obengenanntem projektpaket.

bis hierher alles wie beschrieben? toll, dann braucht man nun eine pc software, um die led in gang zu kriegen. ich habe den borland bcc32 compiler verwendet, und mir folgenden code zusammengeschrieben (bzw. besser gesagt, zusammenkopiert, denn es sind weitgehend die inhalte wie in der usb-lcd-dll):

#define VENDORID 0x03eb
#define PRODUCTID 0x7a53

#define cmdEcho 0
#define cmdLCD_Init 1
#define cmdLCD_Command 2
#define cmdLCD_Data 3
#define cmdLCD_BG 4

#define msgOK 0
#define msgErr 1

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include "usb.h" // geaendert (gaensefuesschen)


struct usb_device *usb_dev;
struct usb_dev_handle *usb_handle;

struct usb_device *device_init( unsigned int vendorid, unsigned int productid )
{
struct usb_bus *usb_bus;
struct usb_device *dev;

/* Config USB trace debug, 0: None, 1-255: Trace depth */
usb_set_debug( 0 );

/* Initialize USB library */
usb_init( );

/* Generic USB library bus structure traversal */
usb_find_busses( );
usb_find_devices( );

/* Scan device tree for vendor ID/product ID match */
for ( usb_bus = usb_get_busses( ); usb_bus; usb_bus = usb_bus -> next )
{
for ( dev = usb_bus -> devices; dev; dev = dev -> next )
{
printf("vendor: %x product: %x\n",dev->descriptor.idVendor,dev->descriptor.idProduct);

if (( dev->descriptor.idVendor == vendorid ) &&
( dev->descriptor.idProduct == productid ) )
return dev;
}
}

return NULL;
}

short USB_SendBuffer(unsigned char request, short value, short index, char *buffer, short length){
//struct usb_device *usb_dev;
//struct usb_dev_handle *usb_handle;
short ret;

if ( usb_dev == NULL )
return -1;

/* Befehl ausführen */
usb_handle = usb_open( usb_dev );
if ( usb_handle != NULL ){
ret = usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | 0x00, request, value, index, buffer, length, 5000);
usb_close( usb_handle );
}else
return -1;
return ret;
}

short USB_ReceiveBuffer(unsigned char request, short value, short index, char *buffer, short length){
//struct usb_device *usb_dev;
//struct usb_dev_handle *usb_handle;
short ret;

/* Make initial connection
usb_dev = device_init( VENDORID, PRODUCTID );*/

if ( usb_dev == NULL )
return -1;

/* Befehl ausführen */
usb_handle = usb_open( usb_dev );
if ( usb_handle != NULL ){
ret = usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | 0x80, request, value, index, buffer, length, 5000);
usb_close( usb_handle );
}else
return -1;
return ret;
}

short _stdcall USB_LCD_BL (short value)
{
char buffer[8];
if (USB_ReceiveBuffer(cmdLCD_BG, value, 0, buffer, sizeof(buffer)) > 0)
return (buffer[0] == msgOK);
return 0;
}

int main()
{
usb_dev=device_init(VENDORID,PRODUCTID);
if(usb_dev)printf("init sucessful!\n");
else printf("error 1\n");
getch();

if(USB_LCD_BL(1))printf("led is on!\n");
else printf("error 2\n");
getch();

if(USB_LCD_BL(0))printf("led is off!\n");
else printf("error 3\n");
getch();

return 0;
}

kompilieren kann man das mit

path E:\bcc32\bin <--- der pfad zum bin verzeichnis eures borland compilers
bcc32 usbled.c libusb.lib <--- kompilieren der quelldatei usbled.c mit der libusb.lib library
del *.obj *.tds <--- muss nicht sein, löscht nur den compilermüll
usbled.c heisst die quelldatei, und libusb.lib muss also gelinkt werden. libusb.lib?! ja, man benötigt libusb-win32, das gibt es hier http://libusb-win32.sourceforge.net bzw genau hier http://sourceforge.net/project/showfiles.php?group_id=78138. ist ein windoof installer, den man in seinen programme-ordner (oder sonstwohin) entpackt. dort, unter
"C:\Programme\LibUSB-Win32\lib\bcc\libusb.lib" findet sich die besagte library.

und die "usb.h" ? die gibt es auch dort, unter "C:\Programme\LibUSB-Win32\include\usb.h". beides kopiert man am besten in sein jeweiliges projektverzeichnis. dann kompilieren, und fertig ist das konsolen-executable, das die led ein- und dann ausschaltet (taste drücken dazu).

perfekt, die led geht an und aus, alles ist prima, die welt ist ein stückchen besser (oder naja, aber zumindest auch nicht schlechter) geworden.

was aber, wenn man im obigen schritt das usb-dings einsteckt, und nur ein leises plop zu hören ist.. und ein unbekanntes gerät erkannt wird? dann funktioniert etwas nicht (genau dieses ungeschick ward auch mir zuteil).

man prüft dann, ob D+ und D- nicht vertauscht sind. man misst auch mal die spannung dran. an D+ sollten etwa 3V anliegen, an D- etwa 0V. wenn das soweit passt, kann man eine 2te SIG_INTERRUPT0 funktion in der usbdrvasm.S schreiben:

SIG_INTERRUPT0:

ldi r16,2
out PORTB,r16
reti
die originale funktion benennt man irgendwie um. wenn man jetzt einen HIGH-pegel an PD2 (pin 4) bringt, sollte die led angehen. dann funktioniert der interrupt. an den usb port drangehängt, sollte dieser interrupt auch ausgelöst werden und die led aufleuchten. klappt immer noch nicht? dann in der main funktion in main.c:

//usbInit(); // das hier auskommentieren
// das hier einfügen:
MCUCR=((1<<ISC00)|(1<<ISC01)); // externer interrupt bei steigender flanke
GICR=(1<<INT0); // externer interrupt aktiviert
wenn auch dann die led nicht zu leuchten beginnt (nachdem man verschiedene pegel an INT0 (PD2, pin 4) angelegt hat).. dann ist etwas oberfaul, und ich kann nur empfehlen, die komplette schaltung nochmal stück für stück auf funktion zu überprüfen (blink programm zB). halt stop, man kann in der not auch in dem forum von obdev um rat fragen http://forums.obdev.at/viewforum.php?f=8 wobei man (glaube ich) auch auf deutsch fragen stellen kann, ist ja ein austria-projekt *anerkennend zu den ösis rüberguck*

uff, doch ziemlich viel zu schreiben, dafür dass es eigentlich nichts zu sagen gab. vielleicht hilft dieses möchtegerntutorial ja jemandem weiter, oder verleitet sogar jemanden, sein glück auch mal mit usb zu versuchen. fragen, anregungen und kritik sind natürlich auch gerne gesehen.

gruesse von eurer katz