schnelles SPI für ATXMEGA 256

OP #2094157
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
OP
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
OP
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......
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.
@  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.
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
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
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
1
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
Variablendeklaration
3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
4

5
uint16_t gintI; //Testvariable
6

7
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8
ADC-Auslesen
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
10

11
uint16_t read_MCP3204(void)
12
{
13
  uint8_t lintISPConfByte = 0b00000110;;
14
  uint8_t lintByte_high;
15
  uint8_t lintByte_low;
16
  uint8_t lintChannel = 0;
17
  
18
  PORTC.OUTCLR = PIN4_bm; //Übertragung starten, SS auf high
19
  
20
  SPIC_DATA = lintISPConfByte; //ADC-Initialisieren, Byte 1, siehe Datenblatt
21
  while(!(SPIC.STATUS & (1<<SPI_IF_bp)))
22
  
23
  lintISPConfByte =lintChannel<<6;
24
  
25
  SPIC_DATA = lintISPConfByte; //ADC-Initialisieren, Byte 2, siehe Datenblatt
26
  while(!(SPIC.STATUS & (1<<SPI_IF_bp)))
27
  
28
  lintByte_high = SPIC_DATA; //ADC-Auslesen
29
   lintByte_high &= 0b00001111; // Nur die ersten 4 Bit in Byte 2 sind interessant bei einem 12Bit-Wandler
30
  
31
  SPIC_DATA = 0x00; //Ein Dummy-Byte durchschieben
32
  while(!(SPIC.STATUS & (1<<SPI_IF_bp))) 
33
   
34
  lintByte_low = SPIC_DATA; // Byte 3 ist ein reines Datenbyte des ADCs
35
  
36
  PORTC.OUTSET = PIN4_bm;  //Übertragung stoppen, SS auf high 
37
  
38
  return ((lintByte_high<<8)|lintByte_low); //Zusammenbau des 12Bit Messwertes und Rückgabe
39
}
40

41
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42
Hauptprogramm/Main
43
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
44

45
int main( void ){
46
  
47
  ClockSystemIni();
48
  SPIInit();
49
  sei();
50
  
51
  while (true)
52
  {  
53
    gintI = read_MCP3204();
54
  }
55
}
56

57
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58
Initialisierungsfunktionen
59
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60

61
//Configure XMega Clock, clock system @ 32Mhz , PERCLK is 16 Mhz
62
void ClockSystemIni( void )
63
{
64
  OSC.CTRL = OSC_RC32MEN_bm;                      //Start internal 32MHz RC oscillator
65
  do {
66
  } while ( ( OSC.STATUS & OSC_RC2MRDY_bm ) == 0 );          //Wait while oscillator stabilizes
67
  CCP = CCP_IOREG_gc;
68
  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
69
  CCP = CCP_IOREG_gc;
70
  CLK.CTRL = CLK_SCLKSEL_RC32M_gc;                  //Select 32 MHz as master clock
71
}
72
//Configure SPI-BUS
73
void SPIInit()
74
{
75
  SPICPort_Init();   //max Spi-Takt F_CPU/2 = 16 Mhz. Pinkonfiguration für SPI-Master
76
  SPIC.CTRL =  SPI_MODE_0_gc | SPI_PRESCALER_DIV4_gc  | (1<< SPI_CLK2X_bp) | (1<< SPI_ENABLE_bp) | (1<< SPI_MASTER_bp);
77
    SPIC.STATUS = 0;
78
  SPIC.INTCTRL = SPI_INTLVL_MED_gc;
79
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 15 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.