Forum: Mikrocontroller und Digitale Elektronik STM32+SPI, Senden ja, aber kein Empfangen


von Hans (Gast)


Lesenswert?

Hey,
ich baue gerade eine Ansteuerung für zwei LCDs aus, die über SPI 
angesprochen werden. Irgendwie wollte das aber nicht so richtig 
funktionieren, weshalb ich erstmal eine SPI Dummyschaltung aufgebaut 
habe zum Testen.
Ich benutze das STM32Discovery Board und habe SPI1 und SPI2 direkt 
miteinander verbunden. Jetzt schicke ich aus beiden SPI Daten raus und 
schaue nach, ob die auch angekommen sind. Eigentlich ganz simpel, dazu 
gibt es schließlich auch ein Beispielprogramm in der Firmware Lib.

Leider ist es dann doch nicht so einfach, es will bei mir schlichtweg 
nicht klappen. Beide SPI senden die Daten raus, aber empfangen wird iwie 
gar nichts. Zig Codevariationen später habe ich mal das Beispiel aus der 
FW Lib draufgespielt, das läuft natürlich...
Kann mir bitte jemand sagen, wo der Fehler liegt? Im Prinzip ist alles 
genau gleich wie in dem Beispielprogramm, nur das Resultat leider nicht 
:(



Programmablauf: Clock wird auf 24MHz gestellt, alle möglichen IOs 
initalisiert, dann wird meine SPI_Test() aufgerufen:


void SPI_Test(void)
{
  /* 1. SPI1 als Master, SPI2 als Slave initialisieren
   * 2. Daten von SPI1 zu SPI2 schicken
   */

  /* Schritt 1 */
  SPI_InitTypeDef    SPIInit1;
  GPIO_InitTypeDef   GPIOInit1;

  RCC_APB2PeriphClockCmd(LCD_SPI_CLK_GPIO_CLK | LCD_SPI_MISO_GPIO_CLK | 
LCD_SPI_MOSI_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB2PeriphClockCmd(LCD_SPI_CLK, ENABLE);

  GPIOInit1.GPIO_Pin = LCD_SPI_CLK_PIN;
  GPIOInit1.GPIO_Speed = GPIO_Speed_50MHz;
  GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(LCD_SPI2_CLK_GPIO_PORT, &GPIOInit1);

  GPIOInit1.GPIO_Pin = LCD_SPI_MISO_PIN;
  GPIOInit1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  //GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(LCD_SPI2_MISO_GPIO_PORT, &GPIOInit1);

  GPIOInit1.GPIO_Pin = LCD_SPI_MOSI_PIN;
  GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(LCD_SPI_MOSI_GPIO_PORT, &GPIOInit1);

  SPI_I2S_DeInit(SPI1);
  SPIInit1.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPIInit1.SPI_Mode = SPI_Mode_Master;
  SPIInit1.SPI_DataSize = SPI_DataSize_16b;
  SPIInit1.SPI_CPOL = SPI_CPOL_Low;
  SPIInit1.SPI_CPHA = SPI_CPHA_2Edge;
  SPIInit1.SPI_NSS = SPI_NSS_Soft;
  SPIInit1.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; /* 
gegebenenfalls anpassen an 72MHz Connectivity Line */
  SPIInit1.SPI_FirstBit = SPI_FirstBit_LSB;
    SPIInit1.SPI_CRCPolynomial = 7;
  SPI_Init(LCD_SPI, &SPIInit1);

  /* SPI1 starten */
  SPI_Cmd(LCD_SPI, ENABLE);



  SPI_InitTypeDef    SPIInit2;
  GPIO_InitTypeDef   GPIOInit2;

  RCC_APB2PeriphClockCmd(LCD_SPI2_CLK_GPIO_CLK | LCD_SPI2_MISO_GPIO_CLK 
| LCD_SPI2_MOSI_GPIO_CLK, ENABLE);
  RCC_APB1PeriphClockCmd(LCD_SPI2_CLK, ENABLE);

  GPIOInit2.GPIO_Pin = LCD_SPI2_CLK_PIN;
  GPIOInit2.GPIO_Speed = GPIO_Speed_50MHz;
  GPIOInit2.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  //GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(LCD_SPI2_CLK_GPIO_PORT, &GPIOInit2);

    GPIOInit2.GPIO_Pin = LCD_SPI2_MISO_PIN;
  GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(LCD_SPI2_MISO_GPIO_PORT, &GPIOInit2);

    GPIOInit2.GPIO_Pin = LCD_SPI2_MOSI_PIN;
  GPIOInit2.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    //GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(LCD_SPI2_MOSI_GPIO_PORT, &GPIOInit2);

    SPI_I2S_DeInit(SPI2);
    SPIInit2.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPIInit2.SPI_Mode = SPI_Mode_Slave;
    SPIInit2.SPI_DataSize = SPI_DataSize_16b;
    SPIInit2.SPI_CPOL = SPI_CPOL_Low;
    SPIInit2.SPI_CPHA = SPI_CPHA_2Edge;
    SPIInit2.SPI_NSS = SPI_NSS_Soft;
    SPIInit2.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; /* 
gegebenenfalls anpassen an 72MHz Connectivity Line */
    SPIInit2.SPI_FirstBit = SPI_FirstBit_LSB;
    SPIInit2.SPI_CRCPolynomial = 7;
    SPI_Init(LCD_SPI2, &SPIInit2);

    /* SPI2 starten */
    SPI_Cmd(LCD_SPI2, ENABLE);



    /* Schritt 2*/

    uint16_t test=0;
    uint16_t test2=0;
    /* SPI senden 0x1111 */
    SPI_I2S_SendData(SPI1, 0x1111);
    SPI_I2S_SendData(SPI2, 0x1111);
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET)
  {
  }
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET)
  {
  }


  /* Beide LED aus, wenn Daten empfangen */
  test = SPI_I2S_ReceiveData(SPI1);
  if(test==0)
  {
    LED_On(LED1);
  }
  else
  {
    LED_Off(LED1);
  }
  test2 = SPI_I2S_ReceiveData(SPI2);
  if(test2==0)
  {
    LED_On(LED2);
  }
  else
  {
    LED_Off(LED2);
  }

}


Code läuft bis zum Ende durch, nur die LEDs bleiben aus. Findet jemand 
den Fehler?
Achso, die ganzen Defines LCD_SPI_PIN_abc sollten stimmen. DEr 
Übersichtlichkeit halber hier:

#define LCD_SPI2           SPI2
#define LCD_SPI2_CLK           RCC_APB1Periph_SPI2
#define LCD_SPI2_CLK_PIN         GPIO_Pin_13
#define LCD_SPI2_CLK_GPIO_PORT   GPIOB
#define LCD_SPI2_CLK_GPIO_CLK    RCC_APB2Periph_GPIOB
#define LCD_SPI2_MISO_PIN        GPIO_Pin_14
#define LCD_SPI2_MISO_GPIO_PORT  GPIOB
#define LCD_SPI2_MISO_GPIO_CLK   RCC_APB2Periph_GPIOB
#define LCD_SPI2_MOSI_PIN        GPIO_Pin_15
#define LCD_SPI2_MOSI_GPIO_PORT  GPIOB
#define LCD_SPI2_MOSI_GPIO_CLK   RCC_APB2Periph_GPIOB
#define LCD_SPI              SPI1
#define LCD_SPI_CLK            RCC_APB2Periph_SPI1
#define LCD_SPI_CLK_PIN         GPIO_Pin_5
#define LCD_SPI_CLK_GPIO_PORT   GPIOA
#define LCD_SPI_CLK_GPIO_CLK    RCC_APB2Periph_GPIOA
#define LCD_SPI_MISO_PIN        GPIO_Pin_6
#define LCD_SPI_MISO_GPIO_PORT  GPIOA
#define LCD_SPI_MISO_GPIO_CLK   RCC_APB2Periph_GPIOA
#define LCD_SPI_MOSI_PIN        GPIO_Pin_7
#define LCD_SPI_MOSI_GPIO_PORT  GPIOA
#define LCD_SPI_MOSI_GPIO_CLK   RCC_APB2Periph_GPIOA


Danke schonmal!

von Martin (Gast)


Lesenswert?

Wenn du zuerst über SPI1 sendest, dann hat der Slave noch nichts im 
Datenregister. Dann sendest du über SPI2, welcher jedoch auf den Master 
warten muss.
Eventuell spielt die Reihenfolge hier mit.

von Hans (Gast)


Lesenswert?

Ok, ich habe die Reihenfolge gedreht, aber es läuft immer noch nicht :( 
Das Receive Buffer Flag zeigt immer an, dass der Buffer leer ist von 
SPI2 (Slave). Wenn ich aber SPI1 als Slave und SPI2 als Master 
programmiere, dann funktioniert es. Wie kann man das verstehen? Das FW 
Beispiel läuft einwandfrei in beide Richtungen mit beiden Master/Slave 
Einstellungen.

von holger (Gast)


Lesenswert?

>Das FW Beispiel läuft einwandfrei in beide Richtungen mit beiden
>Master/Slave Einstellungen.

Überprüf mal deine SlaveSelect Einstellungen.

von holger (Gast)


Lesenswert?

Und zieh auch mal die SlaveSelect Leitung runter
bevor der Master was sendet.

von holger (Gast)


Lesenswert?

>Und zieh auch mal die SlaveSelect Leitung runter
>bevor der Master was sendet.

Hmm, braucht man bei den Dingern wohl nicht.

>Das FW Beispiel läuft einwandfrei in beide Richtungen mit beiden
>Master/Slave Einstellungen.

Dort werden die SPI Pins aber auch fleissig von Input auf Output, oder
Output auf Input umgeschaltet wenn Master und Slave wechseln.
Vermutlich machst du da einen Fehler.

von Hans (Gast)


Lesenswert?

Ja, die NSS Pins sind gar nicht miteinander verbunden. Beim 
Initialisieren des SPI setze ich das SSM Bit für den NSS Software Mode.

Das fleißige Umsetzen von Input auf Output habe (jetzt) ich auch mit 
drin. Ich bin ungefähr einen halben Schritt weiter gekommen:


Konfiguriere ich SPI2 als Master, SPI1 als Slave, dann funktioniert die 
Datenübertragung manchmal. SPI1 empfängt immer meine 0x11, SPI2 hat aber 
fast immer ein 0xFF im Empfangsregister stehen. Einmal hat es aber schon 
geklappt.

Drehe ich den Code um und lasse SPI1 als Master senden, SPI2 als Slave 
agieren, dann funktioniert die Kommunikation gar nicht mehr. SPI1 
empfängt angeblich einmal 0x00. SPI2 empfängt gar nichts, scheint 
nichtmal zu senden. Das Sendeflag ist dauerhaft low, als ob noch Daten 
im Sendebuffer drin wären, die eigentlich mit SPI1 raus gehen sollten. 
Ich würde fast sagen, dass SPI2 kaputt ist, aber das FW Beispiel geht 
immer noch.

Hier ist mein Code. Am Anfang das #define SPI1_MASTER konfiguriert SPI1 
als Master und SPI2 als SLave oder andersrum. Die Reihenfolge beim 
Senden beachte ich jetzt auch. Auch die Konfiguration der SPIs und des 
Taktes ist jetzt identisch wie im FW Lib. Hilfe!
1
void SPI_Test(void)
2
{
3
  /* 1. SPI1 als Master, SPI2 als Slave initialisieren
4
   * 2. Daten von SPI1 zu SPI2 schicken
5
   * 3. Daten von SPI2 zu SPI1 schicken
6
   */
7
8
#define SPI1_MASTER
9
10
  /* Schritt 1 */
11
  SPI_InitTypeDef    SPIInit1;
12
  GPIO_InitTypeDef   GPIOInit1;
13
14
  RCC_APB2PeriphClockCmd(LCD_SPI_CLK_GPIO_CLK | LCD_SPI_MISO_GPIO_CLK | LCD_SPI_MOSI_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);
15
  RCC_APB2PeriphClockCmd(LCD_SPI_CLK, ENABLE);
16
17
  GPIOInit1.GPIO_Pin = LCD_SPI_CLK_PIN;
18
  GPIOInit1.GPIO_Speed = GPIO_Speed_50MHz;
19
#ifdef SPI1_MASTER
20
  GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
21
#endif
22
#ifndef SPI1_MASTER
23
  GPIOInit1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
24
#endif
25
  GPIO_Init(LCD_SPI2_CLK_GPIO_PORT, &GPIOInit1);
26
27
  GPIOInit1.GPIO_Pin = LCD_SPI_MISO_PIN;
28
#ifdef SPI1_MASTER
29
  GPIOInit1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
30
#endif
31
#ifndef SPI1_MASTER
32
  GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
33
#endif
34
  GPIO_Init(LCD_SPI2_MISO_GPIO_PORT, &GPIOInit1);
35
/*
36
    GPIOInit1.GPIO_Pin = LCD_SPI_NSS_PIN;
37
#ifdef SPI1_MASTER
38
  GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
39
#endif
40
#ifndef SPI1_MASTER
41
  GPIOInit1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
42
#endif
43
    GPIO_Init(LCD_SPI_NSS_GPIO_PORT, &GPIOInit1);
44
*/
45
  GPIOInit1.GPIO_Pin = LCD_SPI_MOSI_PIN;
46
#ifdef SPI1_MASTER
47
  GPIOInit1.GPIO_Mode = GPIO_Mode_AF_PP;
48
#endif
49
#ifndef SPI1_MASTER
50
  GPIOInit1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
51
#endif
52
  GPIO_Init(LCD_SPI_MOSI_GPIO_PORT, &GPIOInit1);
53
54
  SPI_I2S_DeInit(SPI1);
55
  SPIInit1.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
56
#ifdef SPI1_MASTER
57
  SPIInit1.SPI_Mode = SPI_Mode_Master;
58
#endif
59
#ifndef SPI1_MASTER
60
  SPIInit1.SPI_Mode = SPI_Mode_Slave;
61
#endif
62
  SPIInit1.SPI_DataSize = SPI_DataSize_8b;
63
  SPIInit1.SPI_CPOL = SPI_CPOL_Low;
64
  SPIInit1.SPI_CPHA = SPI_CPHA_2Edge;
65
  SPIInit1.SPI_NSS = SPI_NSS_Soft;
66
  SPIInit1.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; /* gegebenenfalls anpassen an 72MHz Connectivity Line */
67
  SPIInit1.SPI_FirstBit = SPI_FirstBit_LSB;
68
    SPIInit1.SPI_CRCPolynomial = 7;
69
  SPI_Init(LCD_SPI, &SPIInit1);
70
71
  /* SPI1 starten */
72
  SPI_Cmd(LCD_SPI, ENABLE);
73
74
75
76
  SPI_InitTypeDef    SPIInit2;
77
  GPIO_InitTypeDef   GPIOInit2;
78
79
  RCC_APB2PeriphClockCmd(LCD_SPI2_CLK_GPIO_CLK | LCD_SPI2_MISO_GPIO_CLK | LCD_SPI2_MOSI_GPIO_CLK, ENABLE);
80
  RCC_APB1PeriphClockCmd(LCD_SPI2_CLK, ENABLE);
81
82
  GPIOInit2.GPIO_Pin = LCD_SPI2_CLK_PIN;
83
  GPIOInit2.GPIO_Speed = GPIO_Speed_50MHz;
84
#ifdef SPI1_MASTER
85
  GPIOInit2.GPIO_Mode = GPIO_Mode_IN_FLOATING;
86
#endif
87
#ifndef SPI1_MASTER
88
  GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
89
#endif
90
    GPIO_Init(LCD_SPI2_CLK_GPIO_PORT, &GPIOInit2);
91
92
    GPIOInit2.GPIO_Pin = LCD_SPI2_MISO_PIN;
93
#ifdef SPI1_MASTER
94
  GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
95
#endif
96
#ifndef SPI1_MASTER
97
  GPIOInit2.GPIO_Mode = GPIO_Mode_IN_FLOATING;
98
#endif
99
    GPIO_Init(LCD_SPI2_MISO_GPIO_PORT, &GPIOInit2);
100
/*
101
    GPIOInit2.GPIO_Pin = LCD_SPI2_NSS_PIN;
102
#ifdef SPI1_MASTER
103
  GPIOInit2.GPIO_Mode = GPIO_Mode_IN_FLOATING;
104
#endif
105
#ifndef SPI1_MASTER
106
  GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
107
#endif
108
    GPIO_Init(LCD_SPI2_NSS_GPIO_PORT, &GPIOInit2);
109
*/
110
    GPIOInit2.GPIO_Pin = LCD_SPI2_MOSI_PIN;
111
#ifdef SPI1_MASTER
112
  GPIOInit2.GPIO_Mode = GPIO_Mode_IN_FLOATING;
113
#endif
114
#ifndef SPI1_MASTER
115
    GPIOInit2.GPIO_Mode = GPIO_Mode_AF_PP;
116
#endif
117
    GPIO_Init(LCD_SPI2_MOSI_GPIO_PORT, &GPIOInit2);
118
119
    SPI_I2S_DeInit(SPI2);
120
    SPIInit2.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
121
#ifdef SPI1_MASTER
122
  SPIInit2.SPI_Mode = SPI_Mode_Slave;
123
#endif
124
#ifndef SPI1_MASTER
125
  SPIInit2.SPI_Mode = SPI_Mode_Master;
126
#endif
127
    SPIInit2.SPI_DataSize = SPI_DataSize_8b;
128
    SPIInit2.SPI_CPOL = SPI_CPOL_Low;
129
    SPIInit2.SPI_CPHA = SPI_CPHA_2Edge;
130
    SPIInit2.SPI_NSS = SPI_NSS_Soft;
131
    SPIInit2.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; /* gegebenenfalls anpassen an 72MHz Connectivity Line */
132
    SPIInit2.SPI_FirstBit = SPI_FirstBit_LSB;
133
    SPIInit2.SPI_CRCPolynomial = 7;
134
    SPI_Init(LCD_SPI2, &SPIInit2);
135
136
    /* SPI2 starten */
137
    SPI_Cmd(LCD_SPI2, ENABLE);
138
139
140
    /* Schritt 2*/
141
142
143
    uint16_t test=0;
144
    uint16_t test2=0;
145
    /* SPI senden 0x1111 */
146
147
#ifdef SPI1_MASTER
148
    //GPIO_WriteBit(LCD_SPI_NSS_GPIO_PORT, LCD_SPI_NSS_PIN, Bit_RESET);
149
    SPI_I2S_SendData(SPI2, 0x11);
150
    SPI_I2S_SendData(SPI1, 0x11);
151
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
152
  {
153
  }
154
  test2 = SPI_I2S_ReceiveData(SPI2);
155
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
156
  {
157
  }
158
  test = SPI_I2S_ReceiveData(SPI1);
159
    //GPIO_WriteBit(LCD_SPI_NSS_GPIO_PORT, LCD_SPI_NSS_PIN, Bit_SET);
160
#endif
161
#ifndef SPI1_MASTER
162
    //GPIO_WriteBit(LCD_SPI2_NSS_GPIO_PORT, LCD_SPI2_NSS_PIN, Bit_RESET);
163
    SPI_I2S_SendData(SPI1, 0x11);
164
    SPI_I2S_SendData(SPI2, 0x11);
165
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
166
  {
167
  }
168
  test2 = SPI_I2S_ReceiveData(SPI1);
169
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
170
  {
171
  }
172
  test = SPI_I2S_ReceiveData(SPI2);
173
    //GPIO_WriteBit(LCD_SPI2_NSS_GPIO_PORT, LCD_SPI2_NSS_PIN, Bit_SET);
174
#endif
175
176
  /* Beide LED aus, wenn Daten empfangen */
177
178
  if(test==0)
179
  {
180
    LED_On(LED1);
181
  }
182
  else
183
  {
184
    LED_Off(LED1);
185
  }
186
187
  if(test2==0)
188
  {
189
    LED_On(LED2);
190
  }
191
  else
192
  {
193
    LED_Off(LED2);
194
  }
195
196
197
}

von Hans (Gast)


Lesenswert?

Omg, zweimal der selbe Typo:

GPIO_Init(LCD_SPI2_CLK_GPIO_PORT, &GPIOInit1);
GPIO_Init(LCD_SPI2_MISO_GPIO_PORT, &GPIOInit1);

heißt natürlich

GPIO_Init(LCD_SPI_CLK_GPIO_PORT, &GPIOInit1);
GPIO_Init(LCD_SPI_MISO_GPIO_PORT, &GPIOInit1);

...

Nur komisch, dass es mit falscher Konfiguration ungefähr jedes 10. Mal 
funktioniert hat, in einer der 4 Kommunikationsrichtungen.

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.