Forum: Mikrocontroller und Digitale Elektronik SPI Kommunikation mit Target über USBasp


von Stefanie B. (sbs)


Lesenswert?

Hallo,

auf http://www.fischl.de/usbasp/ steht derzeit:
* Planned: serial interface to target (e.g. for debugging).
Genau das möchte ich umsetzen.


Dazu habe ich mir folgendes überlegt:
Da der ISP-Programmieradapter schon die SPI-Leitungen belegt, soll das 
Target über SPI mit dem USBasp reden, welches dann mit USB weiter mit 
dem Hostrechner redet.

Um die den Overhead im Target so gering wie möglich zu halten, möchte 
ich
das Target als SPI master und das USBasp als slave konfigurieren.
Denn dann kann man im Target komfortable aussuchen wann man die 
Debugging Informationen sendet, als Slave können die 
Lese/Schreibanfragen zu den unpassendsten Zeiten kommen.

Da das USBasp auch schon ein USB slave ist, also insgesamt 2 
Schnittstellen
als Slave bedient, benötigt es einen Puffer um die beiden Schnittstellen 
zu synchronisieren.

Der Puffer funktioniert, dieser kann auch schon per USB ausgelesen 
werden.
Immer wenn ich Bytes hineinschreibe, kann man sie am Hostrechner 
emfangen.

Die SPI Schnittstelle selber funktionert auch, ich kann also Daten von 
dem Target zu dem USBasp senden.

Das Problem ist die Synchronisation der beiden Schnittstellen:
Da das USBasp im SPI-slave modus arbeitet, nimmt es die Daten per 
Interrupt an.
Wenn aber so ein Interrupt in das usbPoll() an der unpassenden, da 
zeitkritischen Stelle einschlägt, gibt es Fehler im USB Stack.

Wie geht man jetzt am besten vor?
* Man könnte mit noch einer Leitung dem Target signalisieren, wann SPI 
erwünscht ist und wann nicht.

* Ignorieren der SPI Nachrichten während der aktiven USB Phase.

* Doch den USBasp als SPI-Master und das Target als slave konfigurieren?

Was ist aus Benutzersicht am einfachsten?
Die Kommunikation über einen Verlust-behafteten Kanal oder die ein 
bestimmtes Timing zum Senden der Debugnachrichten?

Ich habe schon Code geschrieben, dieser funktioniert allerdings nur
sehr begrenzt, da eben dieses Synchronisationsproblem auftaucht.
https://github.com/stefanbeller/USBasp
Der Code kann auf 2 USBasps getestet werden (eins als echtes USBasp, das
andere als Target, welches hin und wieder Daten per SPI verschickt.)

Gruß,
Stefan

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Hallo!
Zuerst mein Kompliment, ich finde es klasse, dass sich mal jemand an 
diese Baustelle herantraut!

Stefan B. schrieb:
> Die SPI Schnittstelle selber funktionert auch, ich kann also Daten von
> dem Target zu dem USBasp senden.

:-)

> Das Problem ist die Synchronisation der beiden Schnittstellen:
> Da das USBasp im SPI-slave modus arbeitet, nimmt es die Daten per
> Interrupt an.
> Wenn aber so ein Interrupt in das usbPoll() an der unpassenden, da
> zeitkritischen Stelle einschlägt, gibt es Fehler im USB Stack.

Klingt so, als bräuchtest du ein USIBR (USI Buffer Register), wie ich es 
vom ATtiny85 her kenne. Gibts aber wohl bei den ATmegas nicht... oder?

Was passiert, wenn du die Interrupts während dieser "zeitkritischen 
Stelle" sperrst?

> * Man könnte mit noch einer Leitung dem Target signalisieren, wann SPI
> erwünscht ist und wann nicht.

Fürs Target zu aufwändig auszuwerten, find ich.

> * Ignorieren der SPI Nachrichten während der aktiven USB Phase.

Du meinst, die Nachrichten, die das Target sendet? Ich hab nicht 
verstanden, was die "aktive USB-Phase" ist. Ist das nur dann, wenn der 
USBasp zum Programmieren genutzt wird? Dann wär das sicher kein Problem 
für den User.

> * Doch den USBasp als SPI-Master und das Target als slave konfigurieren?

Auch wieder zu aufwändig für das Ziel, denk ich...

von Stefanie B. (sbs)


Lesenswert?

Markus W. schrieb:
> Klingt so, als bräuchtest du ein USIBR (USI Buffer Register), wie ich es
> vom ATtiny85 her kenne. Gibts aber wohl bei den ATmegas nicht... oder?
>
> Was passiert, wenn du die Interrupts während dieser "zeitkritischen
> Stelle" sperrst?

Ein USIBR habe ich nicht in dem Datenblatt des Atmega8 finden können.

Bisher sah die Hauptschleife so aus:
1
for (;;) {
2
    usbPoll();
3
}

Wenn ich die Interrupts während des usbPoll() ausstelle, dann kommen in 
derzeit keine Nachrichten mehr an, es kann also maximal eine Nachricht 
(1Byte) geschickt werden. Jedes weitere Byte würde das bisherige in dem 
SPDR Register überschreiben.

Der USB Host pollt regelmäßig alle angeschlossenen Geräte, diese müssen 
innerhalb von 50ms antworten, sonst wird das Gerät abgemeldet.
Dieses Antworten passiert innerhalb des usbPoll(). die usbPoll Funktion 
hingegen, muss Zyklen-genau sein laut deren Dokumentation, um die Zeiten 
auf dem USB Bus zu einzuhalten.

Ich habe bisher die Hauptschleife so erweitert:
1
for (;;) {
2
  SPCR &= ~(1 << SPIE);
3
  usbPoll();
4
  SPCR |= (1 << SPIE);
5
  if (prog_state == PROG_STATE_SERIAL) {
6
    if (--blink_counter == 0) {
7
      toggleLedRed();
8
      blink_counter = (unsigned int)(1UL << 15);
9
    }
10
  }
11
}

Weiterhin könnte man noch soetwas wie pollSPI() einfügen in der Funktion 
wird dann auf die Nachrichten von dem Target gewartet.

Lange Rede, kurzer Sinn:
Falls der SPI Interrupt deaktiviert wird, kann man nie sicher sein, ob 
Nachrichten von dem Target bei dem USBasp ankommen. Man kann sogar 
ziemlich sicher sein, dass Packetverluste (heh, Byteverluste) auftreten 
und muss definitiv ein Data-Link-Layer Protokoll einsetzen, welches die
Übertragung sicherstellt.

Alternativ kann man versuchen die usbPoll() Funktion zu sezieren und nur 
an den wirklich zeitkritischen Stellen den SPI Interrupt deaktivieren.
Bisher habe ich die USB Schnittstelle nicht näher untersucht.

> Du meinst, die Nachrichten, die das Target sendet? Ich hab nicht
> verstanden, was die "aktive USB-Phase" ist. Ist das nur dann, wenn der
> USBasp zum Programmieren genutzt wird? Dann wär das sicher kein Problem
> für den User.

Mit der "aktiven USB-Phase" meinte ich die usbPoll() Funktion, die also 
nicht nur während des Flashen des Target, sondern die ganze Zeit 
regelmäßig ausgeführt wird.

Gruß,
Stefan

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

OK, danke, nun hab ichs begriffen. :-)

So ganz einfach wird die Sache vermutlich nicht sein, sonst hätten die 
Entwickler von damals es schnell erledigt. Kann also gut sein, dass ein 
gehöriger Schluck Aufwand drinsteckt und du deine Ergänzungen in die 
Funktion usbPoll() integrieren musst.

Du könntest aber auch mal bei fischl.de direkt anklopfen, vielleicht 
haben die noch eine Idee, wo man anpacken sollte.

Bitte meld dich wieder, es interessiert mich brennend, ob du mit dem 
Vorhaben weiterkommst. Vielleicht schau ich auch mal in den Quellcode, 
schadet ja nichts, auch wenn ich AVR-Assembler viel besser kann als 
AVR-C.

von Stefanie B. (sbs)


Lesenswert?

Markus W. schrieb:
> Bitte meld dich wieder, es interessiert mich brennend, ob du mit dem
> Vorhaben weiterkommst. Vielleicht schau ich auch mal in den Quellcode,
> schadet ja nichts, auch wenn ich AVR-Assembler viel besser kann als
> AVR-C.

Heh, bei mir ist es genau andersherum. Ich kann C viel besser als 
Assembler jeglicher Art.
Das usbPoll() scheint mir auch nur eine Wrapper Funktion für die 
Assembler Sachen zu sein.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Stefan B. schrieb:
> Heh, bei mir ist es genau andersherum. Ich kann C viel besser als
> Assembler jeglicher Art.

Du kriegst das bestimmt hin.

> Das usbPoll() scheint mir auch nur eine Wrapper Funktion für die
> Assembler Sachen zu sein.

Sieht nicht unbedingt so aus. Die Funktion ist in der Datei usbdrv.c 
definiert:
1
USB_PUBLIC void usbPoll(void)
2
{
3
schar   len;
4
uchar   i;
5
6
    len = usbRxLen - 3;
7
    if(len >= 0){
8
/* We could check CRC16 here -- but ACK has already been sent anyway. If you
9
 * need data integrity checks with this driver, check the CRC in your app
10
 * code and report errors back to the host. Since the ACK was already sent,
11
 * retries must be handled on application level.
12
 * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3);
13
 */
14
        usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len);
15
#if USB_CFG_HAVE_FLOWCONTROL
16
        if(usbRxLen > 0)    /* only mark as available if not inactivated */
17
            usbRxLen = 0;
18
#else
19
        usbRxLen = 0;       /* mark rx buffer as available */
20
#endif
21
    }
22
    if(usbTxLen & 0x10){    /* transmit system idle */
23
        if(usbMsgLen != USB_NO_MSG){    /* transmit data pending? */
24
            usbBuildTxBlock();
25
        }
26
    }
27
    for(i = 20; i > 0; i--){
28
        uchar usbLineStatus = USBIN & USBMASK;
29
        if(usbLineStatus != 0)  /* SE0 has ended */
30
            goto isNotReset;
31
    }
32
    /* RESET condition, called multiple times during reset */
33
    usbNewDeviceAddr = 0;
34
    usbDeviceAddr = 0;
35
    usbResetStall();
36
    DBG1(0xff, 0, 0);
37
isNotReset:
38
    usbHandleResetHook(i);
39
}

Wenn ich den Kommentar weglasse und die Konstante mit der Flusssteuerung 
auflöse, bleibt das hier übrig:
1
USB_PUBLIC void usbPoll(void)
2
{
3
schar   len;
4
uchar   i;
5
6
    len = usbRxLen - 3;
7
    if(len >= 0){
8
        usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len);
9
    usbRxLen = 0;       /* mark rx buffer as available */
10
    }
11
    if(usbTxLen & 0x10){    /* transmit system idle */
12
        if(usbMsgLen != USB_NO_MSG){    /* transmit data pending? */
13
            usbBuildTxBlock();
14
        }
15
    }
16
    for(i = 20; i > 0; i--){
17
        uchar usbLineStatus = USBIN & USBMASK;
18
        if(usbLineStatus != 0)  /* SE0 has ended */
19
            goto isNotReset;
20
    }
21
    /* RESET condition, called multiple times during reset */
22
    usbNewDeviceAddr = 0;
23
    usbDeviceAddr = 0;
24
    usbResetStall();
25
    DBG1(0xff, 0, 0);
26
isNotReset:
27
    usbHandleResetHook(i);
28
}

Auf den ersten Blick relativ übersichtlich.
In der Datei usbdrv.h ist einiges an Doku drin. Ich werd das mal 
durchsehen.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Noch ein Gedanke:
Du schreibst, dass es Probleme gibt, wenn über SPI ein Byte ankommt und 
damit ein Interrupt ausgelöst wird, während die oben genannte 
USB-Funktion läuft. Kann es sein, dass die betreffende Interrupt-Routine 
einfach zu lang ist, also zu viel Zeit braucht? Vielleicht kann man die 
verkürzen oder optimieren.
Magst du sie posten?

von Stefanie B. (sbs)


Lesenswert?

Die Interruptroutine für spi sieht so aus:
1
ISR(SPI_STC_vect )
2
{
3
    comBuffer[comStop] = SPDR;
4
    comStop ++;
5
}

Das dissassemblierte binary sieht dann so aus:
1
00000ba0 <__vector_10>:
2
     ba0:       1f 92           push    r1
3
     ba2:       0f 92           push    r0
4
     ba4:       0f b6           in      r0, 0x3f        ; 63
5
     ba6:       0f 92           push    r0
6
     ba8:       11 24           eor     r1, r1
7
     baa:       8f 93           push    r24
8
     bac:       9f 93           push    r25
9
     bae:       ef 93           push    r30
10
     bb0:       ff 93           push    r31
11
     bb2:       80 91 79 01     lds     r24, 0x0179
12
     bb6:       9f b1           in      r25, 0x0f       ; 15
13
     bb8:       e9 e7           ldi     r30, 0x79       ; 121
14
     bba:       f0 e0           ldi     r31, 0x00       ; 0
15
     bbc:       e8 0f           add     r30, r24
16
     bbe:       f1 1d           adc     r31, r1
17
     bc0:       90 83           st      Z, r25
18
     bc2:       8f 5f           subi    r24, 0xFF       ; 255
19
     bc4:       80 93 79 01     sts     0x0179, r24
20
     bc8:       ff 91           pop     r31
21
     bca:       ef 91           pop     r30
22
     bcc:       9f 91           pop     r25
23
     bce:       8f 91           pop     r24
24
     bd0:       0f 90           pop     r0
25
     bd2:       0f be           out     0x3f, r0        ; 63
26
     bd4:       0f 90           pop     r0
27
     bd6:       1f 90           pop     r1
28
     bd8:       18 95           reti

Zu den Zeitkritischen Sachen:
In der Datei usbdrvasm12.asm steht:
> Do not link this file! Link usbdrvasm.S instead, which includes the
> appropriate implementation!

> Since almost all of this code is timing critical, don't change unless you
> really know what you are doing! Many parts require not only a maximum number
> of CPU cycles, but even an exact number of cycles!

Jetzt müssen wir untersuchen, in welcher Datei die 
Interruptsperren/freigaben eingebaut werden müssen.
Die usbPoll() Funktion ist zu weit oben im USB STack angesetzt, die 
Assemblerdateien wohl zuweit unten.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Danke!

Ich hab mal durchgezählt, die ISR schluckt 52 Takte. Das ist ziemlich 
lang für zwei Zeilen Code. C arbeitet leider sehr viel über den Stack, 
jedes push braucht 2 Takte - jedes pop auch.

Gibt es bei C die Möglichkeit, den Compiler anzuweisen, bestimmte 
Register nicht zu benutzen? Falls ja, könnte man die ISR evtl. in 
Assembler schreiben, sie würde dann weniger als halb so lang laufen.

Zum C-Code:

Die Übersetzung des Compilers find ich ok, lediglich das zweite "push 
r0" und das erste "pop r0" sind überflüssig. Aber darauf kommt es 
wahrscheinlich auch nicht mehr an.

In welchem Wertebereich bewegt sich comStop? Könntest du statt mit 
comBuffer[comStop] auch mit einem Zeiger arbeiten (z.B. *comPointer++ )? 
Falls ja, würde das eine 16-Bit-Addition in der ISR sparen. Außerdem 
könnte Post-Inkrement verwendet werden (statt "st Z,r25" dann "st 
Z+,r25"), das spart die zweite Addition ("subi r24,0xff") ein. Ob das 
alles das Problem löst, weiß ich natürlich nicht... :-(

von Oliver J. (skriptkiddy)


Lesenswert?

Wozu eigentlich die Kopfstände?

Quelle usbdrv.h (20120109):
1
Interrupt latency:
2
The application must ensure that the USB interrupt is not disabled for more
3
than 25 cycles (this is for 12 MHz, faster clocks allow longer latency).
4
This implies that all interrupt routines must either have the "ISR_NOBLOCK"
5
attribute set (see "avr/interrupt.h") or be written in assembler with "sei"
6
as the first instruction.

Mit ISR_NOBLOCK sollte also alles im grünen Bereich sein.

Gruß Oliver

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Oliver J. schrieb:
> Mit ISR_NOBLOCK sollte also alles im grünen Bereich sein.

Hm. Das bedingt, dass alles Zeitkritische des bisherigen Programms sich 
nur in Interrupt-Routinen befindet. Davon war ich nicht ausgegangen, 
aber du hast völlig Recht, das ist einen Versuch wert!

Ein Problem könnte es geben, wenn die ISR(SPI_STC_vect) aufgerufen wird, 
während sie noch läuft, aber das ist sehr unwahrscheinlich.

von proGit (Gast)


Lesenswert?

Markus W. schrieb:
>
> In welchem Wertebereich bewegt sich comStop? Könntest du statt mit
> comBuffer[comStop] auch mit einem Zeiger arbeiten (z.B. *comPointer++ )?
> Falls ja, würde das eine 16-Bit-Addition in der ISR sparen. Außerdem
> könnte Post-Inkrement verwendet werden (statt "st Z,r25" dann "st
> Z+,r25"), das spart die zweite Addition ("subi r24,0xff") ein. Ob das
> alles das Problem löst, weiß ich natürlich nicht... :-(

Im ersten Beitrag ist der bisherige Code verlinkt:
1
// choose size to 2^8, so comStart, comEnd can wrap around as ringbuffer
2
// indexes.
3
static uchar comBuffer[256];
4
static uchar comStart = 0;
5
static uchar comStop = 0;

von Oliver J. (skriptkiddy)


Lesenswert?

Markus W. schrieb:
> Hm. Das bedingt, dass alles Zeitkritische des bisherigen Programms sich
> nur in Interrupt-Routinen befindet.
In der usbPoll-Funktion steckt sicher nichts Zeitkritisches:

Quelle usbdrv.h (20120109):
1
USB_PUBLIC void usbPoll(void);
2
/* This function must be called at regular intervals from the main loop.
3
 * Maximum delay between calls is somewhat less than 50ms (USB timeout for
4
 * accepting a Setup message). Otherwise the device will not be recognized.
5
 * Please note that debug outputs through the UART take ~ 0.5ms per byte
6
 * at 19200 bps.
7
 */

Markus W. schrieb:
> Ein Problem könnte es geben, wenn die ISR(SPI_STC_vect) aufgerufen wird,
Das könnte man über ein Globales Flag abfangen:
1
volatile uint8_t X_Y_alredy_started = 0;
2
ISR(X_Y_vect, ISR_NOBLOCK)
3
{
4
   /* Flag setzen oder zurückkehren */
5
   if (X_Y_alredy_started == 1) {
6
      /* evenuell noch irgendwo vermerken */
7
      return;
8
   } else {
9
       X_Y_alredy_started = 1;
10
   }
11
    
12
   /* Hier Steht Code */
13
14
   /* Flag zurücksetzen */
15
   X_Y_alredy_started = 0;
16
}

Gruß Oliver

von Stefanie B. (sbs)


Lesenswert?

Oliver J. schrieb:
> Mit ISR_NOBLOCK sollte also alles im grünen Bereich sein.

Heh, Ich sollte die Doku besser lesen. Danke für den entscheidenen 
Hinweis.

Ich habe den SPI Interrupt auf ISR_NOBLOCK gesetzt und das Auslesen von 
Daten aus dem Target über das USBasp funktioniert jetzt.

Wenn zuviele Daten per SPI versandt werden, gibt es immer noch 
Packetverlust, aber das ist ja normal bei Überlast. Bei einer Last von 2 
Bytes in 10 ms (unregelmäßig aufgeteilt, dh. 9.6 ms lang nichts und dann 
2 Bytes kurz hintereinander) funktioniert es.

Als nächsten Schritt könnte Ich einen Treiber für die Hostseite 
bereitstellen, derzeit habe ich nur ein rudimentäres Python Skript 
welches die Daten entgegennimmt und in der Konsole ausgibt.
https://github.com/stefanbeller/USBasp/blob/master/host/testcommunication.py

Was erwartet ein Benutzer von einem Hostseitigen Treiber für so eine 
Kommunikation? Vielleicht einfach nur ein Programm, welches die Daten 
auf stdout ausgibt, sodass man diese in anderen Programmen 
wieterverarbeiten kann?

Andere Detailfrage:
Soll die rote LED, die sonst den Programmiervorgang anzeigt, während der
SPI Kommunikation auch konstant an sein? Derzeit habe ich sie auf 
Blinken eingestellt, sodass man das Programmieren und die SPI 
Kommunikation voneinander unterscheiden kann.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Stefan B. schrieb:
> Danke für den entscheidenen Hinweis.

Dem Dank an Oliver schließ ich mich an!

> Ich habe den SPI Interrupt auf ISR_NOBLOCK gesetzt und das Auslesen von
> Daten aus dem Target über das USBasp funktioniert jetzt.

Schööön!

Wie liest du eigentlich? So ähnlich wie mit dem Befehl hier?
  cat /dev/irgendwas

> Wenn zuviele Daten per SPI versandt werden, gibt es immer noch
> Packetverlust, aber das ist ja normal bei Überlast. Bei einer Last von 2
> Bytes in 10 ms (unregelmäßig aufgeteilt, dh. 9.6 ms lang nichts und dann
> 2 Bytes kurz hintereinander) funktioniert es.

Hmmm... der Puffer müsste mit 256 Bytes auf jeden Fall groß genug sein. 
Woran liegt das? Eventuell noch ein Bug?
Viele werden später Daten zeilenweise mit printf() versenden wollen, da 
gäbs dann schon ein kleines Problem...

> Als nächsten Schritt könnte Ich einen Treiber für die Hostseite
> bereitstellen, derzeit habe ich nur ein rudimentäres Python Skript
> welches die Daten entgegennimmt und in der Konsole ausgibt.
> https://github.com/stefanbeller/USBasp/blob/master/host/testcommunication.py

"Treiber" klingt so nach Windows – da halte ich mich mal raus. :-)

> Andere Detailfrage:
> Soll die rote LED, die sonst den Programmiervorgang anzeigt, während der
> SPI Kommunikation auch konstant an sein? Derzeit habe ich sie auf
> Blinken eingestellt, sodass man das Programmieren und die SPI
> Kommunikation voneinander unterscheiden kann.

Mir würde das Blinken gefallen, dann sieht man, dass Daten kommen. Sie 
blinkt nur, wenn der angeschlossene Mikrocontroller Daten sendet oder 
zumindest einen Takt anlegt, oder? Wenn sie IMMER blinken würde, wärs 
vielleicht doch zu nervig. :-)

Mit welchem USBasp experimetierst du eigentlich? Ich hab zwei 
verschiedene China-USBasps hier rumliegen, wär natürlich toll, wenn 
deine Software dann auf beiden laufen würde. :-)

von Stefanie B. (sbs)


Lesenswert?

Markus W. schrieb:
> Hmmm... der Puffer müsste mit 256 Bytes auf jeden Fall groß genug sein.
> Woran liegt das? Eventuell noch ein Bug?
> Viele werden später Daten zeilenweise mit printf() versenden wollen, da
> gäbs dann schon ein kleines Problem...

Da nun die SPI isr unterbrochen werden kann und ich nicht weiß wie lange 
die USB isr braucht, können Bytes verloren gehen, wenn man die zu 
schnell hintereinander sendet.
Ich habe nicht ausgemessen, wie klein der minimale zeitliche Abstand 
zwischen zwei Bytes sein muss, um definitiv 'Packetverlust' zu 
vermeiden,
320µs als Wartezeit waren halt einfach zu bekommen. ;)

Meine USBasps sind aus dem Shop von Ullrich Radig, die Schaltpläne 
findet man hier 
http://www.ulrichradig.de/home/index.php/avr/usb-avr-prog

Um die Erweiterung schnell testen zu können, habe ich einfach die 
Hauptschleife umgebaut, siehe 
https://github.com/stefanbeller/USBasp/blob/master/firmware/main.c#L371
(clockWait wartet 320µs und war schon da)

Zu dem Treiber... Naja ich benutze derzeit in python die python-usb lib 
version 0.4.3-1 (Standard in Ubuntu 12.04)

Da USB Kommunikation über sogenannte Setup Packete erfolgt, können pro 
USB Packet nur 8 Byte Nutzdaten an den Hostpc gesendet werden.
(Es gibt noch sogenannte Bulk Transfers oder Interrupt Transfers, aber 
da USB Neuland für mich ist, benutze ich die Packete die auch alle 
anderen Befehle des USBasps benutzen.)

Und in python habe ich jetzt die Funktionen
1
def getHandle() # return the correct USB handle for the USBasp programmer
2
def enableSerialMode(USBaspHandle) # enables Serial listening
3
def disableSerialMode(USBaspHandle) # basically turns off red LED blinking
4
def getData(USBaspHandle) # returns 0 up to 8 bytes of data depending on buffer size in USBasp
Die Funktion getData müsste noch so umgebaut werden, sodass man einen 
kontinuierlichen Bytestrom bekommt.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Stefan B. schrieb:
> Ich habe nicht ausgemessen, wie klein der minimale zeitliche Abstand
> zwischen zwei Bytes sein muss, um definitiv 'Packetverlust' zu
> vermeiden,
> 320µs als Wartezeit waren halt einfach zu bekommen. ;)

Kann man dem Anwender sowas wie eine maximale Taktfrequenz fürs SPI als 
Richtwert geben? Ich nehm an, dass es kein Problem ist, wenn es keine 
Wartezeit zwischen den Bytes gibt, wenn die SPI-Frequenz entsprechend 
gering ist. Das wär für den User am einfachsten zu verstehen und 
umzusetzen. Auch printf() und andere Routinen halten sich dann daran.

> Meine USBasps sind aus dem Shop von Ullrich Radig, die Schaltpläne
> findet man hier
> http://www.ulrichradig.de/home/index.php/avr/usb-avr-prog

Werd ich mir anschauen, danke! Ich nehm an, du setzt mit deiner Software 
auf dem letzten Entwicklungsstand von fischl.de auf (Mail 2011)?

> Um die Erweiterung schnell testen zu können, habe ich einfach die
> Hauptschleife umgebaut, siehe
> https://github.com/stefanbeller/USBasp/blob/master/firmware/main.c#L371
> (clockWait wartet 320µs und war schon da)

Ich schau morgen mal rein. Danke.

> Zu dem Treiber... Naja ich benutze derzeit in python die python-usb lib
> version 0.4.3-1 (Standard in Ubuntu 12.04)

Schon drauf, wenn man Ubuntu neu installiert? Ich denk jetzt einfach mal 
an die Neulinge...

> (Es gibt noch sogenannte Bulk Transfers oder Interrupt Transfers, aber
> da USB Neuland für mich ist, benutze ich die Packete die auch alle
> anderen Befehle des USBasps benutzen.)

Mach da bloß keinen Aufwand, es geht erst einmal darum, Textausgaben auf 
den Schirm zu bringen. Je einfacher, desto leichter lässt sich die 
Software hinterher pflegen.

> Und in python habe ich jetzt die Funktionen
> (...)
> Die Funktion getData müsste noch so umgebaut werden, sodass man einen
> kontinuierlichen Bytestrom bekommt.

Als einfacher Anwender stelle ich es mir ideal vor, wenn man ein Binary 
hat, das Linux-mäßig auf stdout schreibt. Dann kann man es beliebig in 
Pipes einbauen usw.
Vielleicht kann avrdude schon von Haus aus sowas? Ich hab keine Ahnung.

von Oliver J. (skriptkiddy)


Lesenswert?

Stefan B. schrieb:
> Da nun die SPI isr unterbrochen werden kann und ich nicht weiß wie lange
> die USB isr braucht, können Bytes verloren gehen, wenn man die zu
> schnell hintereinander sendet.

Wenn Daten verloren gehen, dann muss man die Geschichte irgendwie 
synchronisieren. Ich hätte dazu folgende Idee:

Beide Geräte sind abwechselnd Master oder Slave. Also: Ein 
Multimaster-Bus.

Target-AVR  |  Datenrichtung  |   usbasp    | Aktion
------------+-----------------+-------------+--------------------------- 
---
Master      |      -->        |    Slave    | Byte wird versendet
Slave       |      <--        |    Master   | usbasp schickt ACK

Zuerst wartet der usbasp auf die Daten und danach wartet der Target-AVR 
auf das Acklowledge-byte. Und das immer im Wechsel. Dabei sendet niemand 
zu viel und man hat immer Zeit die Bytes abzuholen, ohne dass ein 
Overrun auftritt.

Könnte das nicht so funktionieren?


Gruß Oliver

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Oliver J. schrieb:
> Target-AVR  |  Datenrichtung  |   usbasp    | Aktion
> ------------+-----------------+-------------+--------------------------- ---
> Master      |      -->        |    Slave    | Byte wird versendet
> Slave       |      <--        |    Master   | usbasp schickt ACK

Das ist eine gute Idee für eine Flusssteuerung. Würde bestimmt prima 
funktionieren.
Das schränkt aber die Einsatzmöglichkeiten von Stefans Projekt ein. Ziel 
sollte es sein – so denke ich – Testausgaben und andere Ausgaben per 
printf() zu ermöglichen.

von Stefanie B. (sbs)


Lesenswert?

Oliver J. schrieb:
> Wenn Daten verloren gehen, dann muss man die Geschichte irgendwie
> synchronisieren. Ich hätte dazu folgende Idee:
>
> Beide Geräte sind abwechselnd Master oder Slave. Also: Ein
> Multimaster-Bus.

Woher weiß das Gerät (beide), wann es den Status umschalten soll?
Wenn das Target zufällig ziemlich lange keine Daten verschickt und dann
viele Daten in kurzer Zeit?
Ich denke so ein Multimasterbus verkompliziert die ganze Sache nur.
(Das wäre auf dem USBasp kein Problem, obwohl auch da wegen des 
zeitkritischen USB Stacks die Umschaltung getimed werden muss.

SPI ist ein voll Duplex Bus, das bedeutet, das immer wenn A ein Byte 
nach B sendet, auch automatisch ein Byte von B nach A gesendet wird.
Man könnte also im SPI-Slave (USBasp) ein ACK als nächstes zu sendendes 
Byte in die SPI Register schreiben sobald das Byte gesichert ist.
Bisher sieht der Interrupt so aus
1
ISR(SPI_STC_vect, ISR_NOBLOCK)
2
{
3
    comBuffer[comStop] = SPDR;
4
    comStop ++;
5
}
Als Erweiterung wird jedes Byte invertiert und im nächsten 
Nachrichtenaustausch als ACK zurückgesendet:
1
ISR(SPI_STC_vect, ISR_NOBLOCK)
2
{
3
    const uchar recv = SPDR;
4
    comBuffer[comStop] = recv;
5
    comStop ++;
6
    SPDR = ~recv;
7
}
Nun kann das Target selber feststellen ob die SPI-Nachrichten zu schnell
in dem USBasp auflaufen

> Dabei sendet niemand
> zu viel und man hat immer Zeit die Bytes abzuholen, ohne dass ein
> Overrun auftritt.
>
> Könnte das nicht so funktionieren?

Heh, "niemand sendet zuviel", das ist meiner Meinung nach einfacher 
umsetzbar mit der Idee von Markus, nämlich eine maximale Taktfrequenz 
anzugeben, mit der Daten gesendet werden dürfen.


> Als einfacher Anwender stelle ich es mir ideal vor, wenn man ein Binary
> hat, das Linux-mäßig auf stdout schreibt. Dann kann man es beliebig in
> Pipes einbauen usw.
> Vielleicht kann avrdude schon von Haus aus sowas? Ich hab keine Ahnung.
Wahrscheinlich müsste man dann avrdude erweitern, mal schauen was sich 
da machen lässt :)

Das Problem auf dem PC ist auch folgendes:
Wir können keine Annahmen über die Anzahl der gesndeten Nachrichten von 
dem Target machen, außer die maximale Taktfrequenz als obere Schranke.
Daher muss man auf der PC Seite eigentlich ununterbrochen USB-Control 
Nachrichten verschicken, mit der Bitte die Daten aus dem Puffer des 
USBasps zum Host zu senden.
Meine Pythonlösung (ist übrigens nicht standardmäßig installiert) hat 
daher eine CPU Auslastung von 100%  :(
Mit avrdude wäre das nicht anders.

>
>
> Gruß Oliver

Gruß Stefan

von Oliver J. (skriptkiddy)


Lesenswert?

Stefan B. schrieb:
> SPI ist ein voll Duplex Bus, das bedeutet, das immer wenn A ein Byte
> nach B sendet, auch automatisch ein Byte von B nach A gesendet wird.
Wie stellst du dir das genau vor?


> Woher weiß das Gerät (beide), wann es den Status umschalten soll?
> Wenn das Target zufällig ziemlich lange keine Daten verschickt und dann
> viele Daten in kurzer Zeit?
Ich dachte mir das so:
Der usbasp ist quasi immer Slave. Er wird nur kurz zum Master wenn er 
das Ack verschickt. Das würde ich vom Hauptprogramm aus machen, um auch 
gleich danach wieder umschalten zu können.
Der Target-AVR sendet ein Byte und schaltet um auf Slave. Wenn er das 
ACK bekommt, dann schaltet er wieder auf Master und sendet das nächste 
Byte, wenn vorhanden.

Hmm das wird aber nichts, wenn der USB-Interrupt feuert, bevor der 
USB-asp wieder auf Slave geschalten hat. Dann würde nämlich wenn der 
Target-AVR der Meinung ist, dass er wieder senden darf, der usbasp immer 
noch ein Master sein. Das kann so nicht funktionieren.

Gruß Oliver

von Oliver J. (skriptkiddy)


Lesenswert?

Ich glaube ich habe die Handshake Lösung gefunden:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=107060&start=0

Der Master setzt in seinem Telegramm das Busyflag, sendet es heraus und 
pollt dann solange die MISO-Leitung, bis der Slave sein Byte in das SPDR 
herein geschrieben hat und damit das Busyflag toggelt. Dann kann der 
Master das nächste Byte senden. Kommt einem Handshake über die 
MISO-Leitung gleich.

Man könnte einfach gestalten indem man nur 7 Datenbit verwendet und das 
höchste dann als Busyflag nutzt. Da könnte man dann immer 7 Bit in beide 
Richtungen übertragen. Null wird als kein Zeichen gewertet. Da müsste 
man aber vom Target-AVR aus den USBasp dann ständig pollen, wenn in 
beide Richtungen übertragen werden soll. Für ASCII reichen 7 Bit denke 
ich.



Gruß Oliver

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Denkt bitte dran, dass es hinterher für den Anwender möglichst einfach 
sein soll. printf() auf dem Mikrocontroller soll möglichst ohne 
Änderungen oder Rücksichtnahme auf ein Flusssteuerungsprotokoll 
fehlerfrei funktionieren.

Wahrscheinlich geht das wirklich nur mit der Vorgabe einer maximalen 
Taktfrequenz.

Was mir vorhin auch durch den Kopf ging: Wenn der USBasp Master ist, 
kann die Übertragung trotzdem in Gegenrichtung stattfinden, ja, es stört 
auch nicht, wenn sie nur in Gegenrichtung läuft. Der USBasp schickt 
dann nur den Takt, mehr nicht.

Beim regelmäßigen Wechsel zwischen Master uns Slave muss auch immer der 
Takt-Master wechseln, das heißt, man braucht Sicherheitsvorkehrungen auf 
der Taktleitung – z.B. nach dem Open-Kollektor-Prinzip. Das 
verkompliziert die Sache.

Trotzdem wär es am einfachsten, wenn der Mikrocontroller der Master 
bleiben darf – eben mit langsamem Takt.

von Oliver J. (skriptkiddy)


Lesenswert?

Markus W. schrieb:
> Denkt bitte dran, dass es hinterher für den Anwender möglichst einfach
> sein soll.
Wenn man dem Anwender eine Lib oder eine fertige putc-Funktion gibt, ist 
dem das sicher zum Schluss egal, wie die Kommunikation intern 
funktioniert.

> printf() auf dem Mikrocontroller soll möglichst ohne
> Änderungen oder Rücksichtnahme auf ein Flusssteuerungsprotokoll
> fehlerfrei funktionieren.
Warum sollte das kompliziert sein. Einfach ein spi_putc gemäß der 
avr-libc bauen und stdout darauf umleiten. Die putc Funktion blockiert 
halt solange bis der Slave nicht mehr busy ist.


> Trotzdem wär es am einfachsten, wenn der Mikrocontroller der Master
> bleiben darf – eben mit langsamem Takt.
Das kann er bei dem MISO-Polling definitiv.


Ich denke, dass man das tatsächlich so machen kann/sollte, wie ich es 
bereits vorhin beschreiben habe (MISO-Busy-Polling). Für eine Richtung 
ist das fast schon trivial. Damit hätte man den maximal möglichen 
Durchsatz und kann auch noch buffer-overflows verhindern, wenn der Slave 
seinen Zustand erst auf nicht busy setzt, wenn Platz im Ringpuffer ist. 
Wenn ich heute Abend etwas Zeit habe, dann probiere ich das mal aus.

PS. Wäre das denn nicht schön, wenn man den maximal möglichen Durchsatz 
erreichen kann und nicht um ein einziges Byte bangen müsste?


Gruß Oliver

von Oliver J. (skriptkiddy)


Lesenswert?

Man könnte auch 8 Bit versenden und nutzt ein Toggeln des MSB im usbasp 
für den Handshake. Da müsste man nur den Kommunikationsstart irgendwie 
synchronisieren. Vielleicht reicht es aus, wenn man das erste Byte nach 
dem Reset des Target-AVR einfach heraus schreibt und danach erst 
Handshake betreibt.

Gruß Oliver

von Hubi (Gast)


Lesenswert?

Oliver J. schrieb:
> Warum sollte das kompliziert sein. Einfach ein spi_putc gemäß der
> avr-libc bauen und stdout darauf umleiten. Die putc Funktion blockiert
> halt solange bis der Slave nicht mehr busy ist.

Hallo!
Denke doch bitte auch an die Leute, die z.B. einen ATtiny13 in Assembler 
programmieren. Gerade für die ist das USB-SPI sehr wertvoll, weil sie 
nur schwer auf andere Wege umsteigen können (die kleinen Tinys haben 
keinen UART). Hier kostet jedes Byte wertvollen Platz, und eine Lib 
lässt sich da kaum "einbinden".

Ich seh es deswegen genauso wie Markus: maximale SPI-Geschwindigkeit 
vorsehen

von Oliver J. (skriptkiddy)


Lesenswert?

Hubi schrieb:
> Hier kostet jedes Byte wertvollen Platz, und eine Lib
> lässt sich da kaum "einbinden".
Wenn man das Handshake nicht verwenden will, dann schreibt man halt 
einfach Zeichen raus und gut ist.


> Ich seh es deswegen genauso wie Markus: maximale SPI-Geschwindigkeit
> vorsehen
Ich bin eher für die sichere Variante.


Gruß Oliver

von Stefanie B. (sbs)


Lesenswert?

Die Hostseite ist soweit fertig.
Es werden exakt die empfangenen Bytes auf stdout ausgegeben.

Derzeit bin ich dabei auszumessen, mit welcher maximalen Taktrate
das SPI des USBasp befeuert werden kann.

Dabei stelle ich fest, dass hin und wieder manche USB Packete 
anscheinend doppelt ankommen.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Stefan B. schrieb:
> Die Hostseite ist soweit fertig.
> Es werden exakt die empfangenen Bytes auf stdout ausgegeben.

Gratuliere! :-)

> Dabei stelle ich fest, dass hin und wieder manche USB Packete
> anscheinend doppelt ankommen.

Verschwinden im Subraum? ;-)
Das heißt, manche Zeichenfolgen erscheinen dann doppelt am Bildschirm?

Ich mach mir grad Gedanken, ob sich dein Host-Script später vielleicht 
auch auf Bash oder C portieren lässt. Vielleicht wage ich mich an einen 
Versuch – aber das dauert noch.

von Oliver J. (skriptkiddy)


Lesenswert?

Wie stellt ihr euch eigentlich den Betrieb dieses Projektes vor? Damit 
diese Geschichte überhaupt funktionieren kann, darf nicht die 
Resetleitung des Target-AVR auf /SS des usbasp gehen. Bei allen 
AVR-Schaltungen, die ich kenne (Ausnahme: usbasp), ist aber Reset auf 
den Programmierstecker geführt. Reset ist aber normalerweise kein 
GPIO.


Gruß Oliver

von Hannes L. (hannes)


Lesenswert?

Soweit ich den USBASP verstanden habe, soll die Erweiterung eine echte 
UART zum Target bereitstellen. Dies wäre ein nettes Feature, aber nicht 
unbedingt erforderlich, da es ein billiger USB-UART-Adapter (gibt es 
auch mit TTL-Pegel) auch tut.

SPI zwischen Target und Umsetzer (ASP), noch dazu mit Flusssteuerung, da 
AVR-SPI mangels Empfangspuffer nicht so richtig Slave-fähig ist, halte 
ich für nicht unbedingt erstrebenswert.

Ein kleines Platinchen mit MAX232 und 4 Pins zum AVR (Vcc, GND, RXD, 
TXD) habe ich sowiso immer an einem RS232-Verlängerungskabel hängen, da 
ich dieses Interface regelmäßig zum Parametrieren verschiedener 
AVR-Schaltungen nutze. Dies ermöglicht in Verbindung mit HTERM 
problemloses Debuggen über UART sowie mittels spezieller kleiner 
VB6-Programme komfortables Parametrieren des Targets.

...

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Oliver:

Soweit ich mich an den Schaltplan erinnere, wird die Resetleitung des 
Targets vom USBasp immer dann (und nur solange) auf GND gezogen, wenn 
programmiert wird. Danach ist die Leitung wieder auf VCC, und man kann 
die Zielschaltung mit den 5 Volt aus USB betreiben. Manche USBasps 
lassen sich sogar auf 3,3 Volt umschalten, so dass man auch 
Zielschaltungen programmieren und versorgen kann, die mit 3,3 Volt 
arbeiten, weil sie z.B. ein LCD oder eine SD-Karte ansteuern.
Also: alles im grünen Bereich. :-)

Hannes Lux schrieb:
> Dies wäre ein nettes Feature, aber nicht
> unbedingt erforderlich, da es ein billiger USB-UART-Adapter (gibt es
> auch mit TTL-Pegel) auch tut.

Klar, mit einem eigenen RS232-Umsetzer gehts auch. Das bedingt aber
1. dass der Mikrocontroller einen UART hat (einige haben das nicht),
2. dass du (wie du auch schreibst) einen MAX232 brauchst, also 
zusätzliche Hardware, und
3. dass dein PC eine serielle Schnittstelle bzw. einen Adapter dafür 
braucht.

Das von Stefan angestoßene Projekt kommt ohne 1., 2. und 3. aus. 
Deswegen ist es ja so genial. :-)

von Oliver J. (skriptkiddy)


Lesenswert?

Markus W. schrieb:
> Also: alles im grünen Bereich. :-)
Muss denn der Target-AVR nicht am usbasp den SS-Pin gegen Masse ziehen, 
um ein Byte übertragen zu können? Wie soll er das mit seinem Reset-PIN 
tun?

Oder soll das Ganze nur für usbasps und Spezialschaltungen sein?


Gruß Oliver

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Der usbasp wird sich eben einfach immer angesprochen fühlen, so viel 
Leitungen gibt der ISP nunmal nicht her.

von Oliver J. (skriptkiddy)


Lesenswert?

Martin Wende schrieb:
> Der usbasp wird sich eben einfach immer angesprochen fühlen, so viel
> Leitungen gibt der ISP nunmal nicht her.

Wie soll das funktionieren, wenn die Resetleitung des Targets auf 5V 
liegt und diese Leitung mit dem SS vom usbasp verbunden ist. Um als 
Slave Daten empfangen zu können, muss SS auf low-Pegel liegen.

Gruß Oliver

von Matthias K. (bartimaeus)


Lesenswert?

Das ist ein super interesantes Thema! Bin grad darauf gestoßen als ich 
nach etwas gesucht habe, wie ich mit dem USBasp Adapter Signale von 
meinem µC ablesen kann.
Gibt es schon irgendwelche Updates?
So wie ich es verstanden habe wurde am originalen Layout des Adapters 
nichts geändert, oder? Nur die Firmware wird neu geschrieben.
Bin jedenfalls sehr gespannt wie das hier weitergeht!

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Matthias Kesenheimer schrieb:
> Gibt es schon irgendwelche Updates?

Hallo Matthias,
auch ich hoffe noch auf Updates. Fürchte aber, der Thread-Ersteller ist 
im wohlverdienten Pfingsturlaub.

von Stefanie B. (sbs)


Lesenswert?

Matthias Kesenheimer schrieb:
> So wie ich es verstanden habe wurde am originalen Layout des Adapters
> nichts geändert, oder? Nur die Firmware wird neu geschrieben.
> Bin jedenfalls sehr gespannt wie das hier weitergeht!

Genau, es gab keine Hardware Änderung.
(Ich benutze die USBasp Hardware aus dem Shop von Ulrich Radig.)
Die Firmware wurde nur minimal verändert.
Stand der Dinge:

Vom dem Targetavr kann man per SPI Daten verschicken.
Dieser Bytestream wird genauso auf dem Hostrechner auf stdout 
ausgegeben.

Für meinen Anwendungszweck ist das genug, was würdet ihr da noch 
erweitern?

von Matthias Kesenheimer (Gast)


Lesenswert?

Ist das dann die aktuelle Firmware, mit der das funktioniert?

https://github.com/stefanbeller/USBasp

von Stefanie B. (sbs)


Lesenswert?

Matthias Kesenheimer schrieb:
> Ist das dann die aktuelle Firmware, mit der das funktioniert?

genau das ist es.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Stefan B. schrieb:
> Matthias Kesenheimer schrieb:
>> Ist das dann die aktuelle Firmware, mit der das funktioniert?
>
> genau das ist es.

Super!

Ist die Firmware-Basis von Mai 2011? Will heißen, funktioniert damit 
auch das "-B"-Kommando, oder hast du eine ältere Firmware als Basis 
verwendet?

Gibt es noch irgendwelche Probleme mit Bytes, die verloren gehen?

von Stefanie B. (sbs)


Lesenswert?

https://github.com/stefanbeller/USBasp/commit/da7b6e47c7cc78b40077c343c33c931cb090424c

> Initial commit.

> This includes the files as of
> wget http://www.fischl.de/usbasp/usbasp.2011-05-28.tar.gz
> tar -xf usbasp.2011.05-28.tar.gz

Markus W. schrieb:
> Ist die Firmware-Basis von Mai 2011? Will heißen, funktioniert damit
> auch das "-B"-Kommando, oder hast du eine ältere Firmware als Basis
> verwendet?

Ich habe die anderen Kommandos nicht explizit getestet, zumindest das 
flashen eines weiteren usbasps mit dieser Firmware funktioniert. ;)

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Stefan B. schrieb:
> Ich habe die anderen Kommandos nicht explizit getestet, zumindest das
> flashen eines weiteren usbasps mit dieser Firmware funktioniert. ;)

Guuut! :-)

Magst du bei fischl.de anfragen, ob sie deine Verbesserungen übernehmen?
Die meisten User suchen ja direkt bei fischl, wenn sie ein 
Firmware-Update brauchen.

Die Hex-Dateien in USBasp/bin/firmware müsste man dann auch noch 
entsprechend updaten.

Langfristig findet sich sicher jemand, der dein Host-Script in C 
übersetzt und nach Windows portiert. Aber ok, ich persönlich brauch kein 
Windows. :-)

von Stefanie B. (sbs)


Lesenswert?

Markus W. schrieb:
> Magst du bei fischl.de anfragen, ob sie deine Verbesserungen übernehmen?
> Die meisten User suchen ja direkt bei fischl, wenn sie ein
> Firmware-Update brauchen.

Vor 11 Tagen (also als ich gefühlt fertig war), habe ich fischl eine 
mail geschrieben, er wolle sich das mal ansehen, habe aber 2 Wochen lang 
keine Zeit. Die Zeit ist fast vorbei, mal sehen ob was kommt.

Ulrich Radig habe ich auch auf diesen Thread hingewiesen, habe aber noch 
keine Antwort bekommen.

Zusätzlich habe ich die Firmware kompiliert und gepushed.
https://github.com/stefanbeller/USBasp/tree/master/bin/firmware

Ich persönlich würde so vorkompilierte Software für den PC nicht einfach 
so aus dem Web nutzen. Auf Mikrocontrollern macht man nicht viel falsch, 
aber generell für meinen Computer möchte ich es entweder selbst 
kompilieren, oder aus einer vertrauenswürdigen Quelle herunterladen.
(zb. Repositories einer großen Distribution.)

Das selberkompilieren bringt nochmal einen gewisses Vertrauen in den 
Code,
da man es ja reviewen kann. ;) (Das tue ich nur manchmal, zumindest ein 
Überfliegen, ob offensichtliche Probleme bestehen.)

Gruß,
Stefan

von Matthias Kesenheimer (Gast)


Lesenswert?

Tja, was nun?


1
name:firmware name$ sudo make main.hex
2
Password:
3
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c usbdrv/usbdrv.c -o usbdrv/usbdrv.o
4
In file included from usbdrv/usbdrv.c:12:0:
5
usbdrv/usbdrv.h:455:6: Fehler: Variable »usbDescriptorDevice« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
6
usbdrv/usbdrv.h:461:6: Fehler: Variable »usbDescriptorConfiguration« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
7
usbdrv/usbdrv.h:467:6: Fehler: Variable »usbDescriptorHidReport« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
8
usbdrv/usbdrv.h:473:6: Fehler: Variable »usbDescriptorString0« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
9
usbdrv/usbdrv.h:479:5: Fehler: Variable »usbDescriptorStringVendor« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
10
usbdrv/usbdrv.h:485:5: Fehler: Variable »usbDescriptorStringDevice« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
11
usbdrv/usbdrv.h:491:5: Fehler: Variable »usbDescriptorStringSerialNumber« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
12
usbdrv/usbdrv.c:70:14: Fehler: Variable »usbDescriptorString0« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
13
usbdrv/usbdrv.c:80:14: Fehler: Variable »usbDescriptorStringVendor« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
14
usbdrv/usbdrv.c:89:14: Fehler: Variable »usbDescriptorStringDevice« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
15
usbdrv/usbdrv.c:111:14: Fehler: Variable »usbDescriptorDevice« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
16
usbdrv/usbdrv.c:142:14: Fehler: Variable »usbDescriptorConfiguration« muss konstant sein, um mit »__attribute__((progmem))« in Nur-Lese-Abschnitt gelegt zu werden
17
make: *** [usbdrv/usbdrv.o] Error 1

von Stefanie B. (sbs)


Lesenswert?

Hm, gute  Frage, genau die aktuelle Version aus dem repository ergibt 
hier folgendes:
1
$ make main.hex
2
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c usbdrv/usbdrv.c -o usbdrv/usbdrv.o
3
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -x assembler-with-cpp -c usbdrv/usbdrvasm.S -o usbdrv/usbdrvasm.o
4
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c usbdrv/oddebug.c -o usbdrv/oddebug.o
5
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c isp.c -o isp.o
6
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c clock.c -o clock.o
7
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -x assembler-with-cpp -c tpi.S -o tpi.o
8
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c main.c -o main.o
9
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -o main.bin usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o isp.o clock.o tpi.o main.o -Wl,-Map,main.map
10
rm -f main.hex main.eep.hex
11
avr-objcopy -j .text -j .data -O ihex main.bin main.hex
Mit
1
avr-gcc --version
2
avr-gcc (GCC) 4.5.3

Welche Version des avr-gcc hast benutzt du?

von Stefanie B. (sbs)


Lesenswert?

Ich glaube hier
Beitrag "Re: Fiese Zeiger Hacks und PROGMEM"
wird dieser Fehler diskutiert.

von Stefanie B. (sbs)


Lesenswert?

Trippelpost, yay!

@Matthias Kesenheimer
Ich habe die relevanten Stellen mal mit dem const keyword versehen, bei 
mir kompiliert das immer noch ohne Fehler. Vielleicht kannst du den 
jetzigen Stand mal ausprobieren?

von Matthias Kesenheimer (Gast)


Lesenswert?

Stefan B. schrieb:
> Welche Version des avr-gcc hast benutzt du?

Ich habs mit der Version 3 und mit 4 probiert.
1
avr-gcc --version
2
avr-gcc (GCC) 4.7.0


Stefan B. schrieb:
> Ich glaube hier
> Beitrag "Re: Fiese Zeiger Hacks und PROGMEM"
> wird dieser Fehler diskutiert.

Ok, das kann sein, ich kann leider nicht so arg viel damit anfangen :)



Stefan B. schrieb:
> Trippelpost, yay!
>
> @Matthias Kesenheimer
> Ich habe die relevanten Stellen mal mit dem const keyword versehen, bei
> mir kompiliert das immer noch ohne Fehler. Vielleicht kannst du den
> jetzigen Stand mal ausprobieren?

Versuch ich gleich, moment...

von Matthias Kesenheimer (Gast)


Lesenswert?

scheint zu funktionieren, danke!
1
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c usbdrv/usbdrv.c -o usbdrv/usbdrv.o
2
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -x assembler-with-cpp -c usbdrv/usbdrvasm.S -o usbdrv/usbdrvasm.o
3
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c usbdrv/oddebug.c -o usbdrv/oddebug.o
4
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c isp.c -o isp.o
5
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c clock.c -o clock.o
6
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -x assembler-with-cpp -c tpi.S -o tpi.o
7
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -c main.c -o main.o
8
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega8  -o main.bin usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o isp.o clock.o tpi.o main.o -Wl,-Map,main.map
9
rm -f main.hex main.eep.hex
10
avr-objcopy -j .text -j .data -O ihex main.bin main.hex

Gut, wenn ich dann  die Firmware geflasht habe, wie lese ich dann die 
Daten von meinem µC ab? Was muss ich also avrdude mitteilen, dass mein 
µC die Daten an stdout sendet?

von Stefanie B. (sbs)


Lesenswert?

Auf dem Hostrechner startest du das Ausgabeskript
1
cd ./host/
2
python pipeout.py

Dann werden die Ausgaben auf den Bildschirm angezeigt.
Alternativ kannst du die Daten anstelle auf den Bildschirm auch in eine 
Datei (hier daten.bin) leiten:
1
cd ./host/
2
python pipeout.py > daten.bin

Auf dem Mikrocontroller versendest du die Daten per SPI, also zum 
Beispiel so etwas (ungetestet):
1
#include <avr/io.h>
2
#include <util/delay.h> 
3
4
int main(void) 
5
{
6
  SPCR = (1 << SPE | 1 << MSTR); // aktiviere SPI als Master.
7
8
  SPDR = 'H';
9
  delay_us(10);
10
  SPDR = 'a';
11
  delay_us(10);
12
  SPDR = 'l';
13
  delay_us(10);
14
  SPDR = 'l';
15
  delay_us(10);
16
  SPDR = 'o';
17
  delay_us(10);
18
  SPDR = ' ';
19
  delay_us(10);
20
  SPDR = 'W';
21
  delay_us(10);
22
  SPDR = 'e';
23
  delay_us(10);
24
  SPDR = 'l';
25
  delay_us(10);
26
  SPDR = 't';
27
  delay_us(10);
28
  SPDR = '.';
29
30
  while (1);
31
}

von Andreas B. (andreasb)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen

Sorry das ich mich kurz einmische, ohne alles gelesen zu haben, ich bin 
gleich wider weg;-)

Vor einem halben Jahr habe ich selbst USBAsp erweitert um eine Serielle 
Kommunikation über UART zu erhalten. Ich habe dazu auch noch ein kleines 
"Terminal" geschrieben, um das ganze unter Linux anzusprechen.

Für mich reichts, ich habe den Code auch wider zurück an Fischl 
gesendet, der hat gesagt beim nächsten Release wird dieser eingebaut.

Da dies offenbar noch nicht geschehen ist veröffentliche ich hiermit den 
Code unter der GPL.

Die Kommunikation hat funktioniert. Die Konsole ist eher dürftig.


Ich arbeite momentan nicht mehr daran. Falls jemand diesen Code 
weiterverwendet, bitte schreibt mir doch kurz ein Mail oder eine 
Nachricht im Forum. Ich werde ggf. irgendwann auch mal wieder an dem 
Code weiterentwickeln.


mfg Andreas

von Bartimaeus (Gast)


Lesenswert?

@Stefan:
Danke für die ausführliche Anleitung! Ich hab es bis jetzt noch nicht an 
Hardware ausprobieren können, sondern nur mal das Pythonscript gestartet 
und geschaut was dabei rauskommt. Es treten ein paar Fehler auf, aber 
ich denke mal, das kommt daher, dass mein USBasp adapter noch nicht 
richtig geflasht wurde. Würde nur mal gerne wissen ob ich bis jetzt 
alles richtig gemacht habe :)

Das ist das was beim starten des Skriptes ausgegeben wird:
1
Traceback (most recent call last):
2
  File "pipeout.py", line 28, in <module>
3
    handle = getHandle()
4
  File "pipeout.py", line 9, in getHandle
5
    busses = usb.busses()
6
  File "/Library/Python/2.6/site-packages/usb/legacy.py", line 333, in busses
7
    return (Bus(),)
8
  File "/Library/Python/2.6/site-packages/usb/legacy.py", line 329, in __init__
9
    self.devices = [Device(d) for d in core.find(find_all=True)]
10
  File "/Library/Python/2.6/site-packages/usb/core.py", line 846, in find
11
    raise ValueError('No backend available')
12
ValueError: No backend available

Treten die Fehler wegen dem noch nicht geflashten USBasp auf?

von bartimaeus (Gast)


Lesenswert?

der obige Post ist von mir (Matthias Kesenheimer)

von Stefanie B. (sbs)


Lesenswert?

Ich habe kurz in die Lösung von Andreas B. geschaut und gebe zu die 
sieht technisch eleganter aus. Ich werde Sie auf jeden Fall mal 
ausprobieren.
(Wahrscheinlich erst nächstes Wochenende.)

@bartimaeus
Heh, das ist das Problem mit 'mal eben zusammengehacktem Code'.
Keine Doku und nix ;)

Ich habe folgende Packete installiert (Ubuntu 12.04)
1
$ dpkg -l |grep libusb
2
ii  libusb-0.1-4                           2:0.1.12-20                             userspace USB programming library
3
ii  libusb-1.0-0                           2:1.0.9~rc3-2ubuntu1                    userspace USB programming library
4
ii  libusb-1.0-0-dev                       2:1.0.9~rc3-2ubuntu1                    userspace USB programming library development files
5
ii  libusb-dev                             2:0.1.12-20                             userspace USB programming library development files
6
ii  libusbmuxd1                            1.0.7-2                                 USB multiplexor daemon for iPhone and iPod Touch devices - library
7
$ dpkg -l |grep usb |grep python
8
ii  python-usb                             0.4.3-1                                 USB interface for Python

Ich nehme an du brauchst ähnliche Packete insbesondere python-usb in der 
Version 0.4.3 (Die Autoren behaupten die Version 1.0, welche komplett 
neu geschrieben ist, sei kompatibel. Also sollte es auch mit der 
neueren Version gehen.)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.