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


von Sylvia H. (sandy)


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

von Klaus F. (kfalser)


Lesenswert?

Sylvia H. schrieb:
> gehen regelmäßig Bytes verloren.

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

von Sylvia H. (sandy)


Lesenswert?

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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


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.

von Sylvia H. (sandy)


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?

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


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?

von Sylvia H. (sandy)


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

von Sylvia H. (sandy)


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......

von Detlev T. (detlevt)


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.

von Jan-Henrik B. (vedaykin)


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.

von Falk B. (falk)


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.

von Gerhard G. (g_g)


Angehängte Dateien:

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.

von Jan-Henrik B. (vedaykin)


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

von Jan-Henrik B. (vedaykin)


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

von Jan-Henrik B. (vedaykin)


Angehängte Dateien:

Lesenswert?

jetzt aber...

von Falk B. (falk)


Lesenswert?

@  Jan-Henrik Bathelt (vedaykin)

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

>jetzt aber...

Eben, lies mal was über Bildformate!

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


Lesenswert?

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

von Jan-Henrik B. (vedaykin)


Lesenswert?

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

von Jan-Henrik B. (vedaykin)


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
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
}

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.