Forum: Compiler & IDEs SPI mit Attiny84


von Christian (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, habe ein Problem bei der Verwendung von SPI mit einem Attiny84.
Der Code stammt von Atmel aus der Application note AVR319: Using the USI 
module for SPI communication - 
http://www.atmel.com/dyn/resources/prod_documents/AVR319.zip.

Die einzigen Anpassungen die ich machen musste waren die Aufrufe für die 
ISR und die PORTS sowie PINS.

Mein Problem ist das ich SPI im Master Mode laufen lassen möchte, aber 
egal welches Zeichen ich versende, der MOSI Pin (PA6) bleibt permanent 
auf low wärend das CLK Pin 8 mal toggelt (mit dem Oszi gesehen).

Weiß nicht wo der Fehler liegt, da ich leider nicht debuggen kann und 
das AVR Studio kein USI bzw. SPI simulieren kann.

Vielen Dank

Christian

von Christian (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, ich weiß echt nicht mehr weiter, selbst dieser einfachere Code 
von
Eric Toering funktioniert nicht auf meinem Attiny84V (125kHz interner 
Takt).
Es ist genau das selbe Verhalten, wie schon im Post zuvor beschrieben, 
am Pin PA4 toggelt, wunderbar mit dem Oszi zu sehen, die Clock vor sich 
hin, PA5 (MISO) liegt auf high aber am PA6 (MOSI) rührt sich nix.

Bin dankbar für jede Hilfe

MfG Christian

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich habe gerade keine Zeit, mir im Datenblatt anzugucken, was du da
machst.  Hier eine Routine, mit der ich erfolgreich via USI/SPI auf
einem ATtiny44 mit einem AT86RF230 kommuniziere:
1
#include <stdint.h>
2
#include <util/atomic.h>
3
4
static uint8_t
5
SPITransfer(uint8_t d)
6
{
7
        USIDR = d;
8
        USISR = _BV(USIOIF);
9
        do {
10
                USICR = _BV(USIWM0) | _BV(USICS1) |
11
                        _BV(USICLK) | _BV(USITC);
12
        } while ((USISR & _BV(USIOIF)) == 0);
13
        return USIDR;
14
}
15
16
uint8_t
17
rf230_regrd(uint8_t regno)
18
{
19
        uint8_t rv;
20
21
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
22
        {
23
                PORTA &= ~_BV(7);
24
                (void)SPITransfer(0x80 | regno);
25
                rv = SPITransfer(0);
26
                PORTA |= _BV(7);
27
        }
28
        return rv;
29
}

(PORTA7 ist das chip select vom AT86RF230.)

von Christian M. (moetown)


Lesenswert?

Hallo Jörg, danke für den Code. Genau das habe ich auch vor, den 
AT86RF230 mit einem Attiny84 zu verbinden. Gab es bei deinem Projekt 
irgendwelche Schwierigkeiten?

MfG Christian

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Christian Moschner wrote:

> Hallo Jörg, danke für den Code. Genau das habe ich auch vor, den
> AT86RF230 mit einem Attiny84 zu verbinden.

OK, ich hänge dir mal mein komplettes radioif.[ch] mit dran.

Du kannst dir auch mal µracoli angucken:

https://savannah.nongnu.org/projects/uracoli/

Axel wollte demnächst meine kleine ATtinyX4-basierte Plattform
(die ich "tiny230" genannt habe) dort mit einbinden.

> Gab es bei deinem Projekt
> irgendwelche Schwierigkeiten?

Die einzige nennenswerte Schwierigkeit habe ich, mit ISP zu
programmieren, wenn die Firmware den AT86RF230 bereits aktiviert
hat.  Der blockiert dann das SPI-Interface.  Ich habe noch nicht
ganz rausgefunden, warum das so ist: ist habe am /SEL einen
Pullup von ca. 1 MΩ dran, damit der Transceiver beim RESET des
AVR (alle IOs hängen in der Luft) nicht selektiert wird.  Aus
irgendeinem mir noch nicht nachvollziehbaren Grund wird aber die
/SEL-Leitung direkt beim RESET (vom Programmer aktiviert) aktiv.
Der einzige Programmer, der es schafft, das ISP trotzdem noch zu
übernehmen, ist ein AVRISP mkII.  Ein JTAGICE mkII oder ein AVR
Dragon (für debugWIRE) schaffen es nicht.

Sinnvoller Weise sollte man also wohl in dieser Leitung eine
Lötbrücke vorsehen, damit der AT86RF230 im Zweifelsfalle zum
Schweigen gebracht werden kann.

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:

> übernehmen, ist ein AVRISP mkII.  Ein JTAGICE mkII oder ein AVR
> Dragon (für debugWIRE) schaffen es nicht.

Oder einfach nen Bootloader nehmen, der schafft es auch.

Für den Bootloader ist man nämlich nicht an bestimmte Pins gebunden, da 
geht jeder IO-Pin.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

> Oder einfach nen Bootloader nehmen, der schafft es auch.

Dafür verbraucht man halt noch mindestens einen IO-Pin extra.  Wenn
man nur noch 4 für die Applikation zur Verfügung hat, ist das schon
heftig.

von Andreas K. (a-k)


Lesenswert?

Je nach Anwendung bleiben von einem 8pinner mit Bootloader 5 oder 6 Pins 
für die Anwendung übrig. Reset wird dann ja meist nicht benötigt und den 
Bootloader-Pin kann man u.U. mit einem Anwendungspin teilen.

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:
> Peter Dannegger wrote:
>
>> Oder einfach nen Bootloader nehmen, der schafft es auch.
>
> Dafür verbraucht man halt noch mindestens einen IO-Pin extra.  Wenn
> man nur noch 4 für die Applikation zur Verfügung hat, ist das schon
> heftig.

Wie kommst Du auf nur 4?

Mit nem Bootloader hast Du natürlich alle 12 IOs zur Verfügung für die 
Applikation.

Reset und SPI werden ja zum Proggen nicht mehr gebraucht.
Und der Bootloaderpin lauscht nur ne Weile (~0,3s) nach dem Reset auf 
das Paßwort, danach ist er auch verfügbar.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

> Wie kommst Du auf nur 4?

Weil ich davon ausgehe, dass man /RESET nicht für die Applikation
hat -- sonst kann man kein debugWIRE mehr benutzen.  Außerdem braucht
der AT86RF230 eben auch seine Pins.  Bleiben 4 GPIOs für die
Applikation übrig.  Da der das SPI-Interface ohnehin schon benutzt,
kostet ISP nichts extra (es benutzt die gleichen Pins, auch wenn das
bei mir gerade aus irgendeinem Grund nicht richtig klappt), während
dein Bootloader ein Pin extra benötigen würde.  Ein Pin vom SPI kann
er sich nicht teilen, da der Bootloader (im Gegensatz zu ISP) nicht
während Reset arbeiten kann, und zur Laufzeit ist das SPI halt durch
den AT86RF230 belegt.

Ergo bringt der Bootloader hier gar keinen Gewinn, sondern nur
zusätzliche Umständlichkeit.  (ISP ist im Großen und Ganzen ja recht
einfach zu handhaben.)

Was ich allerdings in meiner derzeitigen Applikation wirklich nicht
verstehe ist, warum PORTA0 (was das /SEL für den AT86RF230 ist) zwar
die ganze Zeit inaktiv ist, aber just mit dem /RESET plötzlich aktiv
wird (sagt mein LA zumindest).  Damit belegt der AT86RF230 den SPI-
Bus genau in dem Moment, wo das ISP aktiv werden will, und es kommt
zur Kollision.

> Reset und SPI werden ja zum Proggen nicht mehr gebraucht.
> Und der Bootloaderpin lauscht nur ne Weile (~0,3s) nach dem Reset auf
> das Paßwort, danach ist er auch verfügbar.

Nach welchem Reset denn, wenn du dafür kein Pin mehr spendieren
willst...?

von Andreas K. (a-k)


Lesenswert?

Jörg Wunsch wrote:

> Nach welchem Reset denn, wenn du dafür kein Pin mehr spendieren
> willst...?

Dem Power-On-Reset.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas Kaiser wrote:

> Dem Power-On-Reset.

Ick, jedesmal ein power-cycle.  OK, mit debugWIRE isses natürlich
auch nicht besser.  Bye-bye, remote debugging.  (Ich bin es gewohnt,
den lieben langen Tag meine AVRs übers Netz zu debuggen, die im
200 m entfernten Labor werkeln, aber das sind alles ATmegas mit
JTAG.)

von Andreas K. (a-k)


Lesenswert?

Ich habe zwar debugWire und limitiertes JTAG rumliegen, aber JTAG habe 
ich bislang nur selten gebraucht und debugWire noch überhaupt nicht.

Meistens tut's ein serieller Ausgang und/oder ein paar Statuspins. Und 
wenn man tatsächlich mal einem 8pinner sowiel Programm ohne freien Pin 
unterjubelt, dass die Debugsession kompliziert wird - nun ja, man muss 
diese Schritte nicht unbedingt mit dem 8pinner anfangen, es langt wenn 
das Endprodukt den verwendet. Am Anfang darf es auch ein anderes Modell 
sein, wenn dem keine grundsätzlichen Hardwareabhängigkeiten im Weg 
stehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas Kaiser wrote:

> Meistens tut's ein serieller Ausgang und/oder ein paar Statuspins.

Naja, ist kein Vergleich zu richtigem Online-Debugging.

> Und
> wenn man tatsächlich mal einem 8pinner sowiel Programm ohne freien Pin
> unterjubelt, dass die Debugsession kompliziert wird - nun ja, man muss
> diese Schritte nicht unbedingt mit dem 8pinner anfangen, es langt wenn
> das Endprodukt den verwendet.

Hier ging's ja um 14-Pinner.

> Am Anfang darf es auch ein anderes Modell
> sein, wenn dem keine grundsätzlichen Hardwareabhängigkeiten im Weg
> stehen.

Das ist bei den HF-Teilen nicht ganz einfach.  Du müsstest eine separate
Platine für den größeren Controller entwerfen.  Da der große Controller
dann auch andere Hardware hat (z. B. richtiges SPI statt der USI), wird
die Portierung zusätzlich erschwert.

Es hat schon was für sich, wenn man die fertige Applikation auf der
fertigen Platine auch noch online debuggen kann.

von Andreas K. (a-k)


Lesenswert?

Jörg Wunsch wrote:

> müsstest eine separate Platine für den größeren Controller entwerfen.

Entwickelst du Software immer als homogenen quadratischen Block komplett 
neu, ohne Module? Ich pflege eher das Baukastenverfahren zu verwenden, 
und das kann auch mal heissen, dass ein solches Modul erst einmal mit 
einem Testaufbau an einem Mega32 im STK500 hängt bis es läuft.

Ein Gutteil des Debuggings verlegt sich so auf angenehmere Plattformen.

Ok, HF ist ein anderes Thema. Und nicht meines.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Den HF-Krempel kannst du nicht als freifliegenden Drahthaufen testen.
Dafür musst du schon irgendwas solides hinsetzen.

Das kann natürlich ein anderer Modul sein mit einem größeren Controller,
trotzdem bereitet die Portierung auf einen kleinen Controller danach
einigen Aufwand, sodass der Debugger dafür ziemlich hilfreich ist.
Ich habe nicht geschrieben, dass er unabdingbar sei, aber es spart eben
einfach Zeit.  Klar, wenn du ihn noch nie benutzt hast, ist dir diese
Erfahrung bislang erspart geblieben. ;-)

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:

> dein Bootloader ein Pin extra benötigen würde.  Ein Pin vom SPI kann
> er sich nicht teilen, da der Bootloader (im Gegensatz zu ISP) nicht
> während Reset arbeiten kann, und zur Laufzeit ist das SPI halt durch
> den AT86RF230 belegt.

Nö, wie schon gesagt, der Bootloader geht mit jedem Pin, also natürlich 
auch mit einem der SPI-Pins.

Z.B. der MOSI wäre geeignet und würde auch Peripherie nicht 
beeinflussen, da ja SCK nicht getaktet wird, kann der ruhig zappeln.


> (ISP ist im Großen und Ganzen ja recht
> einfach zu handhaben.)

Wenn man davon absieht, daß man extra Hardware oder nen echten 
LPT-Anschluß braucht.


> Was ich allerdings in meiner derzeitigen Applikation wirklich nicht
> verstehe ist, warum PORTA0 (was das /SEL für den AT86RF230 ist) zwar
> die ganze Zeit inaktiv ist, aber just mit dem /RESET plötzlich aktiv
> wird (sagt mein LA zumindest).  Damit belegt der AT86RF230 den SPI-
> Bus genau in dem Moment, wo das ISP aktiv werden will, und es kommt
> zur Kollision.

Ich würde mal den Pullup auf 10k verringern, 1M erscheint mir doch sehr 
hoch, da kann leicht eine Leitung übersprechen.

Ich hab zwar ewig keine SPI-Programmierung mehr selber gemacht, aber bei 
den classic-AVRs war mir aufgefallen, daß nach dem Reset noch die 
interne Resetzeit (16ms) abgewartet werden mußte, ehe das Program-Enable 
geschickt werden konnte.
Könnte gut sein, daß während dieser internen Resetzeit Pins zappeln.

Ein Programmieralgorithmus, der nach Reset = Low noch 16ms wartet, 
sollte es daher packen.


> Nach welchem Reset denn, wenn du dafür kein Pin mehr spendieren
> willst...?

Entweder Power-On oder Watchdog durch die Applikation.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

>> (ISP ist im Großen und Ganzen ja recht
>> einfach zu handhaben.)

> Wenn man davon absieht, daß man extra Hardware oder nen echten
> LPT-Anschluß braucht.

Ist aber erstens da und zweitens brauchst du für den Bootloader
ja auch nicht nur Luft -- und sei's ein RS-232-Levelshifter.

(Da wir über debugWIRE geredet haben, ist es eigentlich klar,
dass das Programmiergerät verfügbar ist.)


>> Was ich allerdings in meiner derzeitigen Applikation wirklich nicht
>> verstehe ist, warum PORTA0 ...

> Ich würde mal den Pullup auf 10k verringern, 1M erscheint mir doch sehr
> hoch, da kann leicht eine Leitung übersprechen.

Naja, die Applikation soll eigentlich sparsam mit Energie umgehen,
es handelt sich ja um IEEE 802.15.4. ;-)  Aber ich habe auch schon
mal einen 10-kΩ-Widerstand drauf gepappt, hat keine Änderung
ergeben: der Ausgang wird ganz offensichtlich im Moment des Reset
aktiv nach unten gezogen.

> Ich hab zwar ewig keine SPI-Programmierung mehr selber gemacht, aber bei
> den classic-AVRs war mir aufgefallen, daß nach dem Reset noch die
> interne Resetzeit (16ms) abgewartet werden mußte, ehe das Program-Enable
> geschickt werden konnte.

Das macht das JTAG ICE im ISP-Modus ohnehin.

> Könnte gut sein, daß während dieser internen Resetzeit Pins zappeln.

Nö, die sollten innerhalb weniger Takte normalerweise hochohmig
werden.  Ich habe mir die Abfolge bei einem Reset mal von Leuten
erklären lassen, die es wissen sollten...  Darum macht es mich ja
ziemlich stutzig.

von klk (Gast)


Lesenswert?

Christian schrieb:
> Hallo, habe ein Problem bei der Verwendung von SPI mit einem
> Attiny84.
> Der Code stammt von Atmel aus der Application note AVR319: Using the USI
> module for SPI communication -
> http://www.atmel.com/dyn/resources/prod_documents/AVR319.zip.
>
> Die einzigen Anpassungen die ich machen musste waren die Aufrufe für die
> ISR und die PORTS sowie PINS.

Ich weiß, dieser Thread ist über 10 Jahre alt, aber eine Lösung für die 
ursprüngliche Frage war leider nicht dabei.

Folgende Fehler sind mir aufgefallen:
* beim ATTiny84 ist im Datenblatt A5 mit MISO und A6 mit MOSI 
beschriftet. Das ist leider sehr irreführend - bei Verwendung von USI 
muss man nämlich auf "DO" (Data Out) und "DI" (Data In) achten. Und das 
ist blöderweise genau anders herum als MOSI/MISO.
DO (Data Out) liegt auf A5 und muss bei den Slaves an MOSI angeschlossen 
werden. DI liegt auf A6 und muss bei den Slaves an MISO angeschlossen 
werden:
1
#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
2
#define SPI_DDR_PORT DDRA
3
#define USCK_DD_PIN DDA4
4
#define DO_DD_PIN DDA5
5
#define DI_DD_PIN DDA6
6
#endif

* der Code zum Lesen vom Bus enthält einen Fehler. Wenn gelesen werden 
soll, muss man quasi irgendwas auf den Bus schreiben, die währenddessen 
gelesenen Daten stehen anschließend in einem Register bereit.
I.d.R. sendet man also zuerst eine Registeradresse auf den Bus, und 
anschließend z.B. ein 0x00, um dem Slave die Gelegenheit zu geben, 
währenddessen seine Daten zurück zu schicken.

Viele Grüße

-klk

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

klk schrieb:
> Das ist leider sehr irreführend

Es entspricht einfach deren Funktion beim ISP. Bei vielen AVRs ist die 
Funktion des SPI-Blocks dann gleichlautend wie bei ISP, aber bei den 
USIs ist das nicht der Fall.

> aber eine Lösung für die ursprüngliche Frage war leider nicht dabei.

Das stimmt so nicht. Ich habe meine Lösung ganz oben vorgestellt, und 
diese funktioniert seit genauso vielen Jahren, wie der Thread alt ist.

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.