Forum: Mikrocontroller und Digitale Elektronik SPI Kommunikation zwei STM32 mit DMA


von Willem B. (mr_willem)


Lesenswert?

Hi Leute,

ich habe eine Frage bezüglich der Kommunikation zweier STM32 mit DMA 
SPI.

Ich möchte mittels SPI 7 16 Bit variablen von Slave zu Master und 
dementsprechend umgekehrt schicken.
Hardwaremäßig habe ich
Ich habe MOSI mit MOSI, CLK mit CLK, NSS mit NSS und MISO mit MISO 
verbunden (PORT A4 bis A7).
In meiner Software habe ich für den SPI1 den DMA Channel 2 als RX und 
den DMA Channel 3 als TX Buffer definiert.

Der Aufbau der Software besteht aus einem endlosen loop der u.a. abfragt 
ob der SPI Bus frei ist (Ich setzte beim senden der Daten vom Master 
eine Variable auf 0 und setze sie in der ISR des RX DMA Kanals wieder 
auf 1) Daher sollten niemals zwei Transfers gleichzeitig stattfinden.

Ich habe für den Transfer drei Puffer definiert, einen RX Puffer und 
einen TX Puffer und einen Puffer mit dem das Programm arbeitet.

In der ISR (void spi_handleDMA1Ch2Interrupt(void), s.u.)des RX DMA warte 
ich bis der Transfer komplett ist, schalte den DMA Kanal ab, kopiere den 
Inhalt des RX Puffers in den Programm Puffer.
Dann setze ich noch das FLAG für den SPI Bus auf 1.

Der DMA wird dann aus dem Programmcode neu gestartet sobald Daten 
gesendet werden sollen (void SPI2_send(void), s.u.)

Auf Slave Seite ist der Code ähnlich, bis auf das natürlich nicht die 
NSS Leitung gezogen wird und der DMA unmittelbar nach dem Austausch der 
Puffer gestartet wird, damit auch Daten anliegen wenn der Master erneut 
eine Transaktion einleitet.

Mein Problem ist nun das folgende.
Es werden anscheinend Daten übermittelt, ich übertrage mit den Daten 
immer noch eine vier bittige Message Nummer von 0 bis 14, 15 ist für den 
Start des Programmes reserviert, damit ich im RX auch sehe auf welche 
anfrage der Slave antwortet.
Diese übertrage ich im letzten byte also in Puffer[6]
Der Master sendet erst eine neue Nachricht insofern er als Bestätigung 
eine Antwort mit der gleichen ID empfangen hat, sonst sendet er die 
vorherige Nachricht noch einmal.
Nach dem übertragen finde ich die Zahl manchmal in Puffer[4], manchmal 
in Puffer[5] und so weiter. Es scheint als ob sie immer eine Stelle 
weiter im Array shiftet.
Zudem habe ich das Programm gerade testweise so geschrieben, das in den 
ersten drei übertragenen Wörtern der gleiche Wert stehen soll.
Steht aber meistens nur in den ersten beiden oder im ersten.

Meine Frage daher,
Kann es sein, das es den SPI stört wenn man mit einem Debugger 
gleichzeitig im Programm unterwegs ist?

Ich nutze den JLink im SWD Modus mit eclipse IDE und gdb.
Die Breakpoints habe ich auch schon nur ausserhalb der ISR gesetzt.

Ist meine überlegung das ein RX und ein TX Puffer benutzt wird falsch, 
ich habe auch schon Code Beispiele mit nur einem Puffer gesehen.

Hat jemand eine Idee woran so ein verhalten liegen kann?? ich habe den 
Clock Prescaler auch schon auf 256 gesetzt damit die Kommunikation etwas 
verlangsamt wird.

Vielen Dank,
Willem


1
void spi_handleDMA1Ch2Interrupt(void){
2
   uint8_t i;
3
   //Test on DMA1 Channel2 Transfer Complete interrupt
4
   if(DMA_GetITStatus(DMA1_IT_TC2)) 
5
   {
6
      //Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits
7
      DMA_ClearITPendingBit(DMA1_IT_GL2);
8
      while (DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET) {}
9
      // wait for tx to complete - page 692
10
      while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {}
11
      while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET) {}
12
      DMA_ClearFlag(DMA1_FLAG_GL3); // Clear the global flag
13
14
      // Disable DMA
15
      DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, DISABLE);
16
      SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx |  SPI_I2S_DMAReq_Tx, DISABLE);
17
      DMA_Cmd(DMA1_Channel2, DISABLE);
18
      DMA_Cmd(DMA1_Channel3, DISABLE);
19
      // wait until DMA is actually off
20
      while (DMA1_Channel2->CCR & DMA_CCR2_EN); 
21
      while (DMA1_Channel3->CCR & DMA_CCR3_EN);
22
#ifdef SPI2_MASTER      
23
      // Set NSS High
24
      GPIO_WriteBit(GPIOA, GPIO_Pin_4, SET);
25
#endif
26
      // Copy RX buffer
27
      for(i=0;i<7;i++)
28
      {
29
#ifdef SPI2_SLAVE
30
         SPI2Buffer[i]=SPI2CommandBuffer[i];
31
#endif
32
         SPI2CommandBuffer[i]=SPI2RecBuffer[i];
33
      }
34
#ifdef SPI2_MASTER
35
      // Set the SPI Bus free
36
      SPI2_FREE=1;
37
#endif
38
#ifdef SPI2_SLAVE
39
   // Set the number of transfers
40
   DMA_SetCurrDataCounter(DMA1_Channel2, 7);           
41
   DMA_SetCurrDataCounter(DMA1_Channel3, 7);
42
   DMA_ClearITPendingBit(DMA1_IT_GL2);     // clear again
43
   DMA_ClearFlag(DMA1_FLAG_GL3);           // Clear the global flag
44
45
   // Start DMA controller again
46
   DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
47
   SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
48
   
49
   // Initiate Transfer
50
   DMA_Cmd(DMA1_Channel2, ENABLE);
51
   DMA_Cmd(DMA1_Channel3, ENABLE);
52
#endif
53
   }
54
} 
55
56
void SPI2_send(void)
57
{
58
   uint8_t i;
59
   // Lock SPI Bus
60
   SPI2_FREE=0;
61
   // Write Commands into TX Buffer
62
   for(i=0; i<7; i++)
63
   {
64
      SPI2Buffer[i]=CommandBuffer[i];
65
   }
66
   // Set the number of transfers
67
   DMA_SetCurrDataCounter(DMA1_Channel2, 7);           
68
   DMA_SetCurrDataCounter(DMA1_Channel3, 7);
69
   DMA_ClearITPendingBit(DMA1_IT_GL2);     // clear again
70
   DMA_ClearFlag(DMA1_FLAG_GL3);           // Clear the global flag
71
72
   // Start DMA controller again
73
   DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
74
   SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
75
   
76
   // Pull NSS Low
77
   GPIO_WriteBit(GPIOA, GPIO_Pin_4, RESET);
78
   // Initiate Transfer
79
   DMA_Cmd(DMA1_Channel2, ENABLE);
80
   DMA_Cmd(DMA1_Channel3, ENABLE);
81
}

von Willem B. (mr_willem)


Lesenswert?

Nun habe ich es raus.
Es war am Ende ein übersehenes Puffer Problem.
Man sollte halt immer aufpassen ob die Pufferzugriffe auch nicht von 
zwei Stellen der Software erfolgen können.
Generell funktioniert der oben gezeigte Code ganz gut.

von newbies (Gast)


Lesenswert?

eine Frage von Anfänger:

was bedeutet NSS eigentlich.
SS = Slave Select
N = ?
Negativ bzw. NOT ? oder andere Bedeutung.

von Mike R. (thesealion)


Lesenswert?

Willem B. schrieb:
> Ich habe MOSI mit MOSI, CLK mit CLK, NSS mit NSS und MISO mit MISO
> verbunden (PORT A4 bis A7).

Ich denke mal hier meinst du MISO mit MOSI und MOSI mit MISO, oder?


newbies schrieb:
> was bedeutet NSS eigentlich.
> SS = Slave Select
> N = ?
> Negativ bzw. NOT ? oder andere Bedeutung.

Mit NOT SLAVE SELECT kommst du schon sehr gut hin. (die Leitung is low 
aktiv, daher not)

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.