mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik schnelles SPI für ATXMEGA 256


Autor: Sylvia H. (sandy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich möchte mit meinem ATXMEGA 256 D3 so schnell wie möglich Datenpakete 
über SPI schicken. Dazu habe ich ihn wie folgt konfiguriert:

Interner Oszillator auf 32 Mhz hoch multipliziert,
SS als Ausgang mit wired And pullups,
SPI Mode 0,
Interrupts aus.

Ich schicke ein Datenarray mit 8 Bytes Inhalt zu meinem Slave.

Nun kommt mein Problem:

Wenn ich die SPI Geschwindigkeit so konfiguriere, das es schneller geht 
als 2 Mhz gehen regelmäßig Bytes verloren.
Dies beobachte ich mit Hilfe des AARDVARK(Beagle) SPI/I2C Protocol 
Analyzer von Totalphase.com .
Hat jemand eine Idee, wie ich SPI Datenpakete schneller als 2 Mhz 
verschicken kann, ohne das Bytes verloren gehen?
Ich würde gerne mit 8 oder mehr Mhz senden können.
Vielen Dank

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sylvia H. schrieb:
> gehen regelmäßig Bytes verloren.

Was meinst Du?
Werden sie nicht gesendet oder werden sie nicht korrekt empfangen?

Autor: Sylvia H. (sandy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
laut meinem "Spion" (der Protokol Analysator) werden sie nicht gesendet, 
sie tauchen überhaupt nicht auf dem Bus auf

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ein programmtechnisches Problem. Der XMega kann SPI-Daten mit 
Fcpu/2 als SPI-Clock versenden. Allerdings ist die Nettorate etwas 
niedriger, da der XMega jedes Byte nachladen muss. Oder Du nimmst DMA, 
dann geht´s schneller.

Autor: Sylvia H. (sandy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok,
Fcpu/2 ist in meinem Fall 16 Mhz
warum kann nun der ATXMEGA aber wenn ich höher als 2 Mhz sende mit den 
Datenpaketen auf SPI nicht mehr mithalten?

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sylvia H. schrieb:
> warum kann nun der ATXMEGA aber wenn ich höher als 2 Mhz sende mit den
> Datenpaketen auf SPI nicht mehr mithalten?

Der XMega kann, glaub mir. Wartest Du auf das Interrupt-Flag des SPI und 
löschst Du dieses auch (oder Deine ISR)? Wenn nicht, überscheibst Du 
vielleicht das Datenregister, während noch gesendet wird?

Autor: Sylvia H. (sandy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich benutze den von ATMEL zur verfügung gestellten spi_driver

mein code ist:

for(uint8_t i = 0; i < =8; i++) {
/*  Transmit data from master to slave. */
SPI_MasterTransceiveByte(&spiMasterC, masterSendData[i]);
}
damit sende ich 8 Byte

die Methode SPI_MasterTransceiveByte(bla)
sieht fogendermaßen aus:

uint8_t SPI_MasterTransceiveByte(SPI_Master_t *spi, uint8_t TXdata)
{
  /* Send pattern. */
  spi->module->DATA = TXdata;

  /* Wait for transmission complete. */
  while(!(spi->module->STATUS & SPI_IF_bm)) {

  }
  /* Read received data. */
  uint8_t result = spi->module->DATA;

  return(result);
}

Dort müsste meiner Meinung nach alles stimmen

Autor: Sylvia H. (sandy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habe mal versucht alle Leitungen zu kürzen,
(SPI möchte ja keine langen Leitungen)
und trotzdem:
bei 2Mhz werden alle 8 Byte ordendlich verschickt,
bei 4Mhz werden die letzten 2 Byte "verschluckt" und erscheinen erst gar 
nicht auf dem Bus......

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kenne mich (noch ;-) ) mit den ATXMEGAs nicht so gut aus, aber muss 
man das Interrupt-Flag nicht explizit löschen, wenn man keine 
ISR-Routine ausführt?

update: Hm. Laut AVR1309 muss man das offenbar nicht. Mein Irrtum.

Autor: Jan-Henrik Bathelt (vedaykin)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit welcher maximalen Rate habt ihr die 8 Byte übertragen können? Also 
gemessen von SS/CS auf Null bis SS/Cs auf High. Ich komme bei einer 
Übertragung von 3 Byte mit den oben aufgeführten Befehlen auf ca. 7kHz 
und würde gerne wissen, ob das schon am Limit ist, bzw. ob Ihr da 
wesentlich schneller seit.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Jan-Henrik Bathelt (vedaykin)

>Mit welcher maximalen Rate habt ihr die 8 Byte übertragen können?

Lesen? F_CPU/2, hier also 16 MHz.

>Also
>gemessen von SS/CS auf Null bis SS/Cs auf High. Ich komme bei einer
>Übertragung von 3 Byte mit den oben aufgeführten Befehlen auf ca. 7kHz

Rechnen?

8 byte x 8 Bit x 1/16 Mhz = 4µs.

Mit ner Handvoll Takte für CS LOW/High vielleicht 5µs, macht 200kHz.

Wenn man diese maximale Geschwindigkeit erreichen will, muss man aber 
das alles in EINER Funktion zusammenfassen oder SPI_MasterTransceiveByte 
als inline deklarieren. Sonst wird sinnlos zeit mit Funktionsaufrufen 
verplempert.

Autor: Gerhard G. (g_g)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Sylvia H. schrieb:
> Ich würde gerne mit 8 oder mehr Mhz senden können.

teste es mal mit einen herkömmlichen Spi-Treiber.

Der ist zwar jetzt auf SPID eingestellt, läßt sich aber leicht auf SPIC 
usw. umstellen. Interrupt wäre auch möglich.

spidTransferByte(xx) oder spidTransferWord(xxxx)

Gruß G.G.

Autor: Jan-Henrik Bathelt (vedaykin)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@Frank Brunner: Genau das mit den einzelnen Funktionsaufrufen ist auch 
mein aktuelles Problem, da ich mit dem ATXMega bisher immer nur 1 Byte 
übertragen kann. Zwischen den Aufrufen vergeht unglaublich viel Zeit, 
nicht ganz unverständlich mit den ganzen Fehlerroutinen, aber noch nicht 
völlig verstanden auf meiner Seite. Ich habe es noch nicht 
geschafft/angefangen alles in EINER Funktion zu verpacken. Danke für die 
Abschätzung was möglich wäre, wenn nicht auf die vordefinierten 
Funktionen zurückgegriffen würde.

@G.G.: Danke für den Beispiel-Code.

Grüße,

Jan

Autor: Jan-Henrik Bathelt (vedaykin)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@ G.G.: Also die Übertragung der Bytes funktioniert noch einen Tick 
schneller, jedoch wird 80% der Zeit bei mir mit Pausen verschwendet. Du 
überträgst 2 x 1 Byte in der Funktion spidTransferWord(xxxx) unter 
verwendung der Funktion spidTransferByte(xx). Es dauert die Übertragung 
der 3 Bytes aufsummiert ca. 30us, topp!! ;). Allerdings habe ich 
insgesamt über 100us Pausen zwischendrin. Also eine Pause zwischen der 
Übertragung zweier Bytes ist größer, als die Übertragung des 
eigentlichen.

Ich habe das Problem bzw. werde gezwungen, dass ich Daten in SPIC_DATA 
schreiben muss. Was in der iox256a3.h als "#define SPIC_DATA 
_SFR_MEM8(0x08C3)" steht. Hier kann ich ja nur ein Byte reinschreiben. 
Also ist mir die Übertragung von z.B. einem Wort in einem Schritt mit 
dem Hardware SPI nicht möglich?

Im Anhang ein Screenshot. Gelb: Die 3 Bytes, Lila: CS-Kanal.

Grüße,

Jan

Autor: Jan-Henrik Bathelt (vedaykin)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
jetzt aber...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Jan-Henrik Bathelt (vedaykin)

>      IMG_0294.JPG
>      2,2 MB, 13 Downloads

>jetzt aber...

Eben, lies mal was über Bildformate!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab's verkleinert.  Der Fokuspunkt ist zu nah gewählt, man kann
das Gesicht des Fotografen nicht erkennen. ;-)

Autor: Jan-Henrik Bathelt (vedaykin)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daraus ein biometrisches Passfoto zu berechnen ist wahrscheinlich 
einfacher, als die Pausen wegzukriegen ;). Sorry für die 2MB.

Autor: Jan-Henrik Bathelt (vedaykin)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, laut Oszi läuft das ganze korrekt mit 20kHz, jedoch scheint es, als 
ob die Daten noch nicht in "SPIC_DATA" abholbereit sind. Die Werte die 
ich jetzt auslese haben nichts mit der anliegenden analogen Spannung am 
ADC zu tun. Wenn ich den Prescaler von 4 auf 16 hochsetze, dann werden 
wieder die korrekten analogen Werte gelesen. Ich warte doch schon auf 
die Statusmeldung des SPI, ob auch alle Daten übertragen worden sind. 
Hat jemand eine Ahnung, warum die Daten anscheinend doch noch nicht 
richtig in "SPIC_DATA" angekommen sind, bzw. mache ich einen Fehler beim 
Auslesen?

An MISO liegt ein richtiges Signal an. Der ADC wandelt korrekt. Alle 
Signale sind sauber.

Grüße,

Jan
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Variablendeklaration
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

uint16_t gintI; //Testvariable

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ADC-Auslesen
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

uint16_t read_MCP3204(void)
{
  uint8_t lintISPConfByte = 0b00000110;;
  uint8_t lintByte_high;
  uint8_t lintByte_low;
  uint8_t lintChannel = 0;
  
  PORTC.OUTCLR = PIN4_bm; //Übertragung starten, SS auf high
  
  SPIC_DATA = lintISPConfByte; //ADC-Initialisieren, Byte 1, siehe Datenblatt
  while(!(SPIC.STATUS & (1<<SPI_IF_bp)))
  
  lintISPConfByte =lintChannel<<6;
  
  SPIC_DATA = lintISPConfByte; //ADC-Initialisieren, Byte 2, siehe Datenblatt
  while(!(SPIC.STATUS & (1<<SPI_IF_bp)))
  
  lintByte_high = SPIC_DATA; //ADC-Auslesen
   lintByte_high &= 0b00001111; // Nur die ersten 4 Bit in Byte 2 sind interessant bei einem 12Bit-Wandler
  
  SPIC_DATA = 0x00; //Ein Dummy-Byte durchschieben
  while(!(SPIC.STATUS & (1<<SPI_IF_bp))) 
   
  lintByte_low = SPIC_DATA; // Byte 3 ist ein reines Datenbyte des ADCs
  
  PORTC.OUTSET = PIN4_bm;  //Übertragung stoppen, SS auf high 
  
  return ((lintByte_high<<8)|lintByte_low); //Zusammenbau des 12Bit Messwertes und Rückgabe
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Hauptprogramm/Main
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

int main( void ){
  
  ClockSystemIni();
  SPIInit();
  sei();
  
  while (true)
  {  
    gintI = read_MCP3204();
  }
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Initialisierungsfunktionen
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

//Configure XMega Clock, clock system @ 32Mhz , PERCLK is 16 Mhz
void ClockSystemIni( void )
{
  OSC.CTRL = OSC_RC32MEN_bm;                      //Start internal 32MHz RC oscillator
  do {
  } while ( ( OSC.STATUS & OSC_RC2MRDY_bm ) == 0 );          //Wait while oscillator stabilizes
  CCP = CCP_IOREG_gc;
  CLK.PSCTRL = (CLK_PSADIV_1_gc | CLK_PSBCDIV_1_1_gc);        //Enable prescaler A div by 1 and B and C to div by 2
  CCP = CCP_IOREG_gc;
  CLK.CTRL = CLK_SCLKSEL_RC32M_gc;                  //Select 32 MHz as master clock
}
//Configure SPI-BUS
void SPIInit()
{
  SPICPort_Init();   //max Spi-Takt F_CPU/2 = 16 Mhz. Pinkonfiguration für SPI-Master
  SPIC.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV4_gc  | (1<< SPI_CLK2X_bp) | (1<< SPI_ENABLE_bp) | (1<< SPI_MASTER_bp);
    SPIC.STATUS = 0;
  SPIC.INTCTRL = SPI_INTLVL_MED_gc;
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.