Forum: Mikrocontroller und Digitale Elektronik STM32f030C - seltsame Verschiebung beim DMA und SPI2


von Jens (Gast)


Lesenswert?

Hallo,

ich rätsel gerade an einen Phänomän auf dem Stm32F030C herum und komme 
irgendwie nicht weiter. Ich habe 2 uCs mittels SPI2 und DMA auf dem 
STM32 miteinander verbunden und versuche zwischen beiden zu 
kommunizeren. Dei sendet der zweite uc alle 10ms eine Nachricht in 
Richtung STM (Mein Problem geht aber auch bei langsameren Zeiten nicht - 
nur mal so vorweg - hab das auch mit 1s probiert).

In Richtung des anderen uC geht das auch Prächtig - allerdings ist der 
zurück kommenede Frame merkwürdig verschoben. Und zwar verschiebt sich 
das Ding von Nachricht zu Nachricht jeweils um 1 Byte nach vorne und 
wird hinten wieder aufgefüllt.

Ankommmen sollte zum Beispiel:
0xF1 - 0xAA - 0x03 - 0xFF - 0xF2
das kommt beim erstem Mal dann auch.

Dann kommt beim zweitem Durchlauf 0xAA - 0x03 - 0xFF - 0xF2 - 0xF1
in der nächsten Runde verschiebt sich das ganze wieder um ein Byte
0x03 - 0xFF - 0xF2 - 0xF1 - 0xAA

SPI2 ist dabei als Master configuriert:
1
void SPI2_Init_Master (void)
2
{
3
/* init SPI 2 as master for nordic commincation */
4
  
5
    GPIO_InitTypeDef GPIO_InitStructure;
6
    SPI_InitTypeDef  SPI_InitStructure;
7
  
8
    /* enable GPIO clock */
9
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
10
11
    /*enable SPI1 clock*/
12
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
13
14
    /* Configure SPI2 IO Pin's */
15
    GPIO_InitStructure.GPIO_Pin   = SPI2_SCK | SPI2_MOSI | SPI2_MISO;
16
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
17
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
18
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
19
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
20
    GPIO_Init(GPIOB, &GPIO_InitStructure);
21
22
    GPIO_StructInit (&GPIO_InitStructure);
23
24
    GPIO_PinAFConfig(GPIOB, SPI2_SCK_AF,  GPIO_AF_0);
25
    GPIO_PinAFConfig(GPIOB, SPI2_MISO_AF, GPIO_AF_0);
26
    GPIO_PinAFConfig(GPIOB, SPI2_MOSI_AF, GPIO_AF_0);
27
28
     /*Configure SPI2*/
29
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
30
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
31
32
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; 
33
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; 
34
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
35
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
36
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
37
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
38
    SPI_InitStructure.SPI_CRCPolynomial = 8;
39
40
    SPI_Init(SPI2, &SPI_InitStructure);
41
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
42
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
43
}

dazu gehört dann natürlich noch DMA4/5:
1
void SPI2_DMA_init (unsigned char* rx_buff,unsigned char* tx_buff)
2
{
3
  
4
  DMA_InitTypeDef DMA_InitStructure;
5
  NVIC_InitTypeDef NVIC_InitStructure;
6
7
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  // enable DMA clock
8
  
9
  
10
    /*Configure DMA channel 4 to SPI2 -> memory -> Rx*/
11
    DMA_DeInit(DMA1_Channel4);
12
    DMA_InitStructure.DMA_PeripheralBaseAddr = SPI2_DR_Address;
13
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) rx_buff;
14
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
15
    DMA_InitStructure.DMA_BufferSize = SPI2_BUFFER_SIZE_RX+2;
16
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
17
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
18
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
19
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
20
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
21
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
22
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
23
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
24
25
    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);    // enable DMA interrupt
26
    DMA_Cmd(DMA1_Channel4, DISABLE);                  // disenable DMA
27
28
    /*Configure NVIC for DMA interrupt*/
29
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_5_IRQn;
30
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
31
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
32
    NVIC_Init(&NVIC_InitStructure);
33
34
    DMA_SetCurrDataCounter(DMA1_Channel4, 0);
35
    DMA_Cmd(DMA1_Channel4, ENABLE);
36
37
    /*Configure DMA channel 5 to memory -> SPI2 -> Tx*/
38
    DMA_DeInit(DMA1_Channel5);
39
    DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)SPI2_DR_Address;
40
    DMA_InitStructure.DMA_MemoryBaseAddr =  (uint32_t)tx_buff;
41
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
42
    DMA_InitStructure.DMA_BufferSize = SPI2_BUFFER_SIZE_TX+2;
43
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
44
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
45
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
46
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
47
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
48
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
49
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
50
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);
51
52
    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
53
    DMA_Cmd(DMA1_Channel5, DISABLE);
54
55
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_5_IRQn;
56
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
57
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
58
    NVIC_Init(&NVIC_InitStructure);
59
60
    DMA_SetCurrDataCounter(DMA1_Channel5, 0);
61
    DMA_Cmd(DMA1_Channel5, ENABLE);
62
}

Die auszlesenden Werte werden in den Übergabepointer geschrieben, der 
auf ein array von der Größe Buffer + 2 zeigt.

Sobald der DMA Interrupt TC4 auslösst schreibe ich die Werte dann weg - 
fahre ein Deinit auf DMA4/5 und SPI2 und initalisere alles neu. Aber das 
Problem bleibt das selbe.

Hat jemand eine Idee woran das liegen könnte? In die andere Richtung 
läuft alle sauber und die Daten die der andere Controller ausgibt sehen 
auf dem Osziloskop klasse aus - alles da wo es hin gehört.

Grüße

Jens

von STM32 Experte (Gast)


Lesenswert?

STM32 und SPI-Slave. Ich habe schon Stunden, wenn nicht Tage damit 
zugebracht, das vernünftig zum laufen zu brigen. Der Master ist ja ganz 
in Ordnung, aber wenn man den SPI als Slave konfigurieren will, kämpft 
man nur gegen diesen unsinnigen FIFO an, den man nicht per Befehl 
löschen kann. Dabei spielt es keine Rolle, ob man DMA benutzt oder 
nicht, diese Verschiebung tritt immer wieder auf, wenn Du eine Datenmege 
ungleich Fifo-Größe (4 Bytes) übertragen willst. Auch wenn ich absoluter 
Fan von STM32-Controllern aller Größen bin, die SPI-Peripherie hat mich 
sehr enttäuscht, vor allem auch wegen der nur 8 einstellbaren 
Geschwindigkeiten.

Alternative? Versuche es mit dem USART im synchronen Modus (SPI 
kompatibel), der hat keinen störenden FIFO aber dafür auch leider keinen 
Chip-Select.

von Jens (Gast)


Lesenswert?

Hallo,

danke für die Antwort - ich werde in die Richtung mal schauen. 
Allerdings verwende ich den STM als Master. Aber das Problem hört sich 
verdammt ähnlich an.

Grüße

Jens

von Ludwig (Gast)


Lesenswert?

Auf welchem µC läuft der Slave?

von Jens (Gast)


Lesenswert?

Der Slave läuft auf einem Nordic NRF51822 - wie gesagt die Daten kommen 
laut Ozsiloskop ziemlich sauber zum STM rüber so das ich im Moment davon 
ausgehe, dass der STM Probleme hat diese vernüftig zu zuordnen.

Grüße

Jens

von Ludwig (Gast)


Lesenswert?

> Dabei spielt es keine Rolle, ob man DMA benutzt oder nicht, diese
> Verschiebung tritt immer wieder auf, wenn Du eine Datenmege ungleich
> Fifo-Größe (4 Bytes) übertragen willst.

Was meinst du mit deiner Aussage genau? Bei mir (STMF32F103, SD-Card) 
tritt keine Verschiebung auf.

von Fabian D. (fabi06)


Lesenswert?

Hallo,

ich hab neulich auch ein paar Tage an diesem Problem rumgefummelt. 
Letztendlich hab ich mir so beholfen, dass ich nach jeder 
8-Bit-Übertragung den gesamten Rx-Fifo ausgelesen habe. Somit ist das 
zuletzt ausgelesene Byte das zuletzt empfangene (was ich ja auslesen 
möchte). Ohne diese Schleife würde man das älteste Byte im Fifo lesen, 
welches schon 3 Übertragungen zuvor empfangen wurde.
Anscheinend gibts beim STM32F030 einen Bug bzgl. des RXNE-Flags im 
8-Bit-Modus.

/* gucken ob nochwas im FIFO ist (FRLVL-Bits) */
while ( 0x00 != (0x0600 & SPI2->SR) )
{
    returnValue = (unsigned char) SPI2->DR;
}

Gruß
Fabian

von Jens (Gast)


Lesenswert?

Ahh... ich habs. Der Tipp mit dem Fifo ist Goldrichtig gewesen.

Man muss den Fifo einfach auf "voll nach Quarter" setzen. Dann tritt 
auch keine Verschiebung mehr im Eintreffenden Array auf.
1
SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF);

Danke für Euere Hilfe.

Grüße

Jens

von Fabian D. (fabi06)


Lesenswert?

FRXTH hatte ich bei mir auch auf 1/4 Fifo eingestellt und trotzdem hatte 
er mir den ganzen Fifo vollgeschoben und beim Auslesen hab ich das Byte 
bekommen, welches ich 3 Übertragungen vorher empfangen habe, also an 
"tiefster" Stelle im Fifo...
Deswegen hab ich dann jeweils den ganzen Fifo ausgelesen bis ich dann 
endlich das richtige Byte gelesen habe.

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.