Forum: Mikrocontroller und Digitale Elektronik SPI MISO erkennt falsche Werte bei höherer Geschwindigkeit


von spi (Gast)



Lesenswert?

Hallo,

ich kommuniziere per SPI zwischen einem STM und einem Atmel. Der Atmel 
ist hier der Master und würde laut Datenblatt einen SPI-Takt bis zu 
66MHz schaffen. Die Daten werden bei steigender Flanke am clock 
übernommen.

STM: STM32F105RC; core-clock = 72MHz

Atmel: AT32UC3A0512
www.atmel.com/Images/doc32058.pdf
core-clock = 66MHz


Nun ist es in meinem Fall so, dass meine Kommunikation nur bis ca. 20MHz 
funktioniert. Bei höheren Frequenzen „empfängt“ der Atmel nur noch 
falsche Werte. In die andere Richtung ist es allerdings so, dass der STM 
(=slave) immer das richtige empfängt.

Ich konnte mal ein Screenshot vom Oszi machen. Hier legt der Slave den 
Wert 0x34 bei einem Takt von 22MHz auf die MISO-Leitung. Der Atmel 
glaubt in diesem Fall jedoch ein 0x1E erkenne zu müssen. So wie ich das 
sehe, sollten die MISO-Werte aber zur richtigen Zeit anliegen und ich 
verstehe gar nicht, wie der Atmel hier auf 0x1E kommt.

Hat jemand einen Tipp wie ich bei der Fehlersuche weiter vorgehen 
sollte?

Zum Oszi: Es hat eine Auflösung von 500MHz bzw. 2,5GS/s

von spi (Gast)



Lesenswert?

Nochmal das Bild im Anhang...

von Blitzbirne (Gast)


Lesenswert?

Was soll das denn für ein Dateutyp im Anhang sein?

von Blitzbirne (Gast)


Lesenswert?

Deine Hilfslinien sind aber alle bei einem unterschiedlichen 
Spannungspegel auf CLK eingezeichnet.
Wenn ich die roten Linien alle etwas nach links verschiebe komme ich auf 
0x1E.

von spi (Gast)


Lesenswert?

natürlich noch der Code (ich verwende Atmels Framework ASF und 
freeRTOS):
1
void spiInit(void)
2
{
3
    spiInitPins();
4
    spiInitModule();
5
    spiDmaInit();
6
}
7
8
9
void spiInitModule(void)
10
{
11
    struct spi_device spi_dev_conf_cam1 = {
12
        .id = SPI_CS_CAM1 };
13
14
    spi_master_init(&AVR32_SPI1);
15
    spi_master_setup_device(&AVR32_SPI1, &spi_dev_conf_cam1, SPI_MODE_0, \
16
            22000000, 1);
17
    spi_enable(&AVR32_SPI1);
18
}
19
20
void spiDmaInit(void)
21
{
22
    /* PDCA channel options */
23
    static const pdca_channel_options_t PDCA_OPTIONS_FOR_TRANSFER =
24
    {
25
        .addr   = NULL,                     // memory address
26
        .pid    = AVR32_PDCA_PID_SPI1_TX,   // select peripheral/SPI tx channel
27
        .size   = 0,                        // transfer counter
28
        .r_addr = NULL,                     // next memory address
29
        .r_size = 0,                        // next transfer counter
30
        .transfer_size = PDCA_TRANSFER_SIZE_BYTE// select size of the transfer
31
    };
32
    static const pdca_channel_options_t PDCA_OPTIONS_FOR_RECIEVE =
33
    {
34
        .addr   = NULL,                     // memory address
35
        .pid    = AVR32_PDCA_PID_SPI1_RX,   // select peripheral/SPI rx channel
36
        .size   = 0,                        // transfer counter
37
        .r_addr = NULL,                     // next memory address
38
        .r_size = 0,                        // next transfer counter
39
        .transfer_size = PDCA_TRANSFER_SIZE_BYTE// select size of the transfer
40
    };
41
42
    /* Disable all interrupts */
43
    Disable_global_interrupt();
44
45
    INTC_register_interrupt( (__int_handler) &pdca_int_handler, \
46
            AVR32_PDCA_IRQ_0, AVR32_INTC_INT0);
47
    INTC_register_interrupt( (__int_handler) &pdca_int_handler, \
48
            AVR32_PDCA_IRQ_1, AVR32_INTC_INT1);
49
50
    /* First disable all interrupts */
51
    SENSOR_SPI->idr = 0xFFFF;
52
53
    /* Enable SPI interrupt */
54
    SENSOR_SPI->IER.nssr = 1;
55
56
    /* Init PDCA channel with the pdca_options */
57
    pdca_init_channel(SPI1_PDCA_CHANNEL_TX, &PDCA_OPTIONS_FOR_TRANSFER);
58
    pdca_init_channel(SPI1_PDCA_CHANNEL_RX, &PDCA_OPTIONS_FOR_RECIEVE);
59
60
    /* Enable all interrupts */
61
    Enable_global_interrupt();
62
63
    /* Enable now the transfer */
64
    pdca_enable(SPI1_PDCA_CHANNEL_RX);
65
    pdca_enable(SPI1_PDCA_CHANNEL_TX);
66
}
67
68
uint8_t spiRWCam1(uint8_t dataTx)
69
{
70
    uint16_t dataRx = 0;
71
    // select SPI chip.
72
    spi_selectChip(SENSOR_SPI, SPI_CS_CAM1);
73
    // Send the Status Register Read command.
74
    spi_write(SENSOR_SPI, (uint16_t)dataTx);
75
    // Unselect SPI chip.
76
    spi_unselectChip(SENSOR_SPI, SPI_CS_CAM1);
77
78
    spi_read(SENSOR_SPI, &dataRx);
79
    return (uint8_t)dataRx;
80
}

von spi (Gast)


Lesenswert?

Blitzbirne schrieb:
> Deine Hilfslinien sind aber alle bei einem unterschiedlichen
> Spannungspegel auf CLK eingezeichnet.
> Wenn ich die roten Linien alle etwas nach links verschiebe komme ich auf
> 0x1E.

Hmmm... ich fand es auch schwierig die tatsächlich richtige Position der 
Linien zu bestimmen, da ich ja nicht weiß wann der Master der Meinung 
ist die Daten übernehmen zu müssen. Ich finde auch, dass die Flanken 
recht unregelmäßig ausschauen.

Das mit dem nach links verschieben ist schon mal ein super Hinweis. 
Danke schön (auch wenn ich noch nicht weiß was ich nun ändern könnte).

von spi (Gast)


Lesenswert?

Die Funktion mit der ich die Daten per DMA in einen Puffer einlese habe 
ich noch vergessen:
1
void spiRBuffCam(volatile uint8_t *buffAddr, uint32_t sizeOfBuff)
2
{
3
    spi_selectChip(&AVR32_SPI1, SPI_CS_CAM1);
4
5
    portENTER_CRITICAL();
6
    {
7
        pdca_enable_interrupt_transfer_complete(SPI1_PDCA_CHANNEL_RX);
8
        /* load PDCA */
9
        pdca_load_channel( SPI1_PDCA_CHANNEL_RX, (void *)buffAddr, sizeOfBuff);
10
        /* enable the PDCA Rx channel first then the Tx channel */
11
        pdca_enable(SPI1_PDCA_CHANNEL_RX);
12
        /* send dummy data from the user page in flash */
13
        pdca_load_channel(SPI1_PDCA_CHANNEL_TX, (void *)dummy_0xff_filledBlockAtFlash, sizeOfBuff);
14
        //pdca_enable(SPI1_PDCA_CHANNEL_TX);    //already enabled at init
15
   }
16
   portEXIT_CRITICAL();
17
}


Ich stelle allerdings gerade (leider erst jetzt) fest, dass ich mit der 
Funktion spiRWCam1() die Daten sogar bei 30MHz auslesen kann. Mein 
Problem ist dann also nur dann, wenn ich per DMA auslesen möchte. (also 
mit der Funktion: spiRBuffCam())

von (prx) A. K. (prx)


Lesenswert?

STM32 Reference: SPI Slave Frequency <= PCLK/2. Mehr als 36MHz sind also 
sowieso nicht drin. Bei den SPIs am APB1 mit halbem PCLK <= 18MHz.

Wie sieht die Kabelei aus? Versorgungsspannung? SPI Pinmode vom STM32?

von (prx) A. K. (prx)


Lesenswert?

spi schrieb:
> Nochmal das Bild im Anhang...

Bei Frequenzen in diesem Bereich solltest du auf die Massekabel der 
Tastköpfe verzichten und mit Massefeder an der Tastkopfspitze arbeiten:
https://www.mikrocontroller.net/attachment/27280/groundspring.png

Mit Massekabel kann ein steilflankiges 20MHz Rechteck auf dem Oszi 
nämlich auch so aussehen: 
https://www.mikrocontroller.net/attachment/27258/74AC-Ausgang.PNG
wobei man da nicht das Signal misst, sondern Artefakte im Tastkopf.

von spi (Gast)


Angehängte Dateien:

Lesenswert?

A. K. schrieb:
> Massefeder an der Tastkopfspitze

Was es alles gibt... Hardware und Messtechnik sind leider nicht meine 
Stärke. Habe auch ein wenig gebraucht um zu kapieren wo/wie die 
Massefeder an den Tastkopf angeschlossen werden soll. Hier mal ein Bild, 
falls sich jemand anderes mal die gleiche Frage stellen sollte:
http://images.vogel.de/vogelonline/bdb/464000/464042/25.jpg

Neue Messungen sind zur Zeit leider nicht möglich, da ich kein eigenes 
Oszi besitze.


A. K. schrieb:
> Mehr als 36MHz sind also sowieso nicht drin.

Ja, 36MHz wären mein Ziel.

Mittlerweile habe ich herausgefunden, dass schon ein delay von einem 
einzigen Takt zwischen den einzelnen Bytes ausreicht um die Übertragung 
mit 32MHz laufen zu lassen. Atmel bietet diese Möglichkeit netter weise 
per Konfiguration der Schnittstelle an:
1
//! Default Config Spi Master Delay BCT ( delay between consecutive transfers)
2
#define CONFIG_SPI_MASTER_DELAY_BCT            1


A. K. schrieb:
> Wie sieht die Kabelei aus? Versorgungsspannung? SPI Pinmode vom STM32?
1
/* ___ SPI1 configuration ________________________________________________*/
2
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
3
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
4
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
5
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
6
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
7
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
8
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
9
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
10
SPI_InitStructure.SPI_CRCPolynomial = 7;
11
SPI_Init(SPI1, &SPI_InitStructure);

Das mit der Kabelei könnte vielleicht wirklich der Grund sein, warum ich 
noch nicht ganz auf die 36MHz komme. Ich habe mal versucht den Aufbau 
meiner beiden Platinen/MCU's auf einer Skizze darzustellen.

von Mike (Gast)


Lesenswert?

spi schrieb:
> Nochmal das Bild im Anhang...

Bei solchen Signale kann man die Fehler gut verstehen. Grundsätzlich ist 
SPI eine digitale Signalübertragung und so sollten die Signale dann auch 
aussehen, bevor man erwarten kann, dass die Gegenstelle die richtig 
empfangen kann. Entweder liegt das an der Messtechnik oder die Signale 
sind tatsächlich so unsauber. Bevor die nicht ordentlich sind, ist da 
ohne Signalregenerierung nicht mehr zu erwarten.

von Wolfgang (Gast)


Lesenswert?

spi schrieb:
> Zum Oszi: Es hat eine Auflösung von 500MHz bzw. 2,5GS/s

Was du da angibst, ist vermutlich die Analogbandbreite und die 
Abtastfrequenz.

Hast du einen 1:10 Tastkopf verwendet?

Welche Impedanz und Länge hat dein Kabel?
Wie sehen Treiberimpedanz und Empfängerimpedanz/Leitungsabschluß aus?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

spi schrieb:
> Ich konnte mal ein Screenshot vom Oszi machen.
Da sieht es für mich so aus, wie wenn sich die Daten annähernd 
gleichzeitig mit den steigenden Taktflanken, die an sich auch nur 
rudimentär und nach Erklärung sichtbar sind! Das wäre dann aber der 
falsche Zeitpunkt zur Abtastung. Besser wäre hier die fallende Flanke. 
Verwendest du den falschen SPI Modus?

BTW: Wenn das Signal am uC-Pin wirklich so aussieht, dann gibt das nie 
eine sichere Übertragung.

von Schreiberling (Gast)


Lesenswert?

Hallo,


Bedenke auch, dass die Kabellaufzeit eine Rolle spielt. Bei 50MHz sind 
deine Zeitreserven sehr gering (10ns): die Taktflanke muss zum ST hin 
und die Datenflanke zum ATMEL zurück - bei 6ns/m geht das schon 
theoretisch nur bis weniger als 1m.
Praktisch eher noch weniger, weil der ST auch noch Zeit braucht, seine 
Daten zu setzen. Probleme können also schon früher auftreten, z.B. bei 
20cm.
Schau dir mal die Setup und Holdzeiten im Datenblatt an und rechne dein 
Timing mal durch - mit Kabellaufzeit.

Der ST hat dagegen nie ein Problem: der bekommt Takt und Daten 
gleichzeitig.

Abhilfe: Frequenz runter, Kabel kürzer oder asynchrone Kommunikation.

von (prx) A. K. (prx)


Lesenswert?

spi schrieb:
> Das mit der Kabelei könnte vielleicht wirklich der Grund sein,

Die Länge der Kabel ist extrem wichtig, wenn du sie nicht passend mit 
Treiber versehen und abgeschlossen hast. Jenseitig einiger zig cm ist 
das nötig und angesichts RJ45 gehe ich davon aus, dass du weit jenseits 
davon liegst. Siehe Wellenwiderstand.

Auf die Laufzeitfrage wurde ja schon hingewiesen. Mögliche Lösung wären 
2 SPI-Master. Einer für AVR32=>STM32 und einer andersrum, jeweils 
unidirektional betrieben. Dann treten keine Laufzeiteffekte auf. 
Blöderweise gibts beim STM32 wohl nur ein SPI mit 36MHz, die anderen nur 
mit 18MHz.

Oder Ethernet.

> [c]/* _ SPI1 configuration

Sorry, ich meinte die GPIO Pinkonfiguration der SPI-Pins. Die 
Grenzfrequenz der STM32 Pins hängt davon ab - und von der Höhe der 
Versorgungsspannung. Daher die Frage.

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.