stm32 SPI NSS Signal Anfänger

Gast #2372771
Lesenswert?

Hallo, ich bin totaler Anfänger in Dingen SPI. Ich messe momentan direkt 
an den Ausgangspins des STM32F107VC und habe den unten stehenden Code am 
laufen. Die Clocks und die Daten werden soweit ich das sehen kann 
übermittelt, auch wenn das Signal ziemlich wackelig aussieht. Der NSS 
allerdings zuckt sich bis auf die Störungen die durch den Clock rein 
kommen überhaupt nicht. Ich hatte das jetzt so verstanden dass der Pegel 
nur bei Datenübermittlung auf Low geht und sonst immer ein High 
aufweist?! Vielleicht kann mir einer von euch sagen was ich falsch 
mache, bzw. woran ich nicht gedacht habe. Muss eventuell noch ein Pullup 
beschaltet werden?
Der Code sollte lauffähig sein, sofern jetzt beim kopieren nichts 
verloren gegangen ist.


1
/* Includes ------------------------------------------------------------------*/
2
#include "stm32f10x.h"
3

4

5

6
/* Private typedef -----------------------------------------------------------*/
7

8
/* Private define ------------------------------------------------------------*/
9
#define BufferSize       32
10

11
/* Private macro -------------------------------------------------------------*/
12
/* Private variables ---------------------------------------------------------*/
13
SPI_InitTypeDef  SPI_InitStructure;
14
DMA_InitTypeDef  DMA_InitStructure;
15
GPIO_InitTypeDef GPIO_InitStructure;
16

17

18
/* Private function prototypes -----------------------------------------------*/
19
void RCC_Configuration(void);
20
void GPIO_Configuration(void);
21

22
/* Private functions ---------------------------------------------------------*/
23

24
/**
25
  * @brief  Main program
26
  * @param  None
27
  * @retval None
28
  */
29
int main(void)
30
{
31

32

33
  /* System clocks configuration ---------------------------------------------*/
34
  RCC_Configuration();
35

36
  /* GPIO configuration ------------------------------------------------------*/
37
  GPIO_Configuration();
38

39

40

41
// SPI_MASTER configuration ------------------------------------------------------
42
  SPI_InitStructure.SPI_Direction              = SPI_Direction_1Line_Tx;
43
  SPI_InitStructure.SPI_Mode                   = SPI_Mode_Master;
44
  SPI_InitStructure.SPI_DataSize               = SPI_DataSize_8b;
45
  SPI_InitStructure.SPI_CPOL                   = SPI_CPOL_High;
46
  SPI_InitStructure.SPI_CPHA                   = SPI_CPHA_1Edge;
47
  SPI_InitStructure.SPI_NSS                     = SPI_NSS_Soft;    // NSS Software Controlled
48
  SPI_InitStructure.SPI_BaudRatePrescaler      = SPI_BaudRatePrescaler_4;
49
  SPI_InitStructure.SPI_FirstBit                 = SPI_FirstBit_MSB;
50
  SPI_InitStructure.SPI_CRCPolynomial       = 7;
51
  SPI_Init(SPI1, &SPI_InitStructure);
52

53
  // Take NSS line high by default
54
  GPIO_SetBits(GPIOA,  GPIO_Pin_4);
55

56

57
  /* Enable SPI_MASTER NSS output for master mode */
58
  SPI_SSOutputCmd(SPI1, ENABLE);
59

60

61

62
  /* Enable SPI_MASTER */
63
  SPI_Cmd(SPI1, ENABLE);
64

65

66
  while (1)
67
  {
68

69

70
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);
71

72
    SPI_I2S_SendData(SPI1, 150);
73

74
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
75
    {}
76

77
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
78

79

80
  }
81

82

83
}
84

85

86
void RCC_Configuration(void)
87
{
88
  /* PCLK2 = HCLK/2 */
89
  RCC_PCLK2Config(RCC_HCLK_Div2);
90

91
  /* Enable peripheral clocks --------------------------------------------------*/
92

93

94
  /* Enable SPI_MASTER clock and GPIO clock for SPI_MASTER and SPI_SLAVE */
95

96
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 ,ENABLE);
97
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);
98

99
}
100

101
void GPIO_Configuration(void)
102
{
103
  GPIO_InitTypeDef GPIO_InitStructure;
104

105

106

107
  /* Configure SPI_MASTER pins: NSS, SCK and MOSI */
108
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7  | GPIO_Pin_5 | GPIO_Pin_4  ;
109
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
110
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
111
  GPIO_Init(GPIOA, &GPIO_InitStructure);
#2372785
Lesenswert?

NSS ist bei den STM32 etwas verwirrend. Es gibt letztlich keinen 
vollautomatischen Hardware-Support für die SS-Leitung(en) eines Masters, 
d.h. die Aktivierung vor und Deaktivierung nach Ende des Transfers ist 
Sache der Software. Die dann natürlich auch dran denken muss, diese 
Leitung erst zu deaktivieren, wenn alle Bits wirklich raus sind.
Gast #2372795
Lesenswert?

Ich war der Meinung genau das zu machen mit der Schleife:

  while (1)
  {


    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    SPI_I2S_SendData(SPI1, 150);

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
    {}

    GPIO_SetBits(GPIOA, GPIO_Pin_4);


  }
Gast #2372811
Lesenswert?

>Ich habe die Doku der Library nicht vorliegen (die sowieso nicht mein
>Ding ist), war aber über deinen Kommentar gestolpert:

Ah ja, jetzt weiß ich was du meinst AK. das ganze rührt daher, dass ich 
zuerst die Hardwareaktivierung drinn hatte, das hat nicht funktioniert, 
also bin ich auf Software umgestiegen. Den müsste ich noch mal raus 
nehmen. Danke.
Gast #2372838
Lesenswert?

Also als "GPIO_Mode_Out_PP" sieht es so aus als würde er endlich das tun 
was ich möchte, ich fines es nur verwirrend dass sogar die STM Beispiele 
bringen wie:

  /* Configure SPI_MASTER NSS pin */
  GPIO_InitStructure.GPIO_Pin = SPI_MASTER_PIN_NSS;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(SPI_MASTER_GPIO_NSS, &GPIO_InitStructure);
#2372906
Lesenswert?

Seb schrieb:
> Also als "GPIO_Mode_Out_PP" sieht es so aus als würde er endlich das tun
> was ich möchte, ich fines es nur verwirrend dass sogar die STM Beispiele
> bringen wie:
>
>   /* Configure SPI_MASTER NSS pin */
>   GPIO_InitStructure.GPIO_Pin = SPI_MASTER_PIN_NSS;
>   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
>   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
>   GPIO_Init(SPI_MASTER_GPIO_NSS, &GPIO_InitStructure);

Wenn Du "SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;"
definierst, weiß der Pin, welchen Du für NSS verwenden willst, nichts 
von seiner SPI-Funktion. Ist ein ganz normaler Output. Das Beispiel, 
welches Du hier zitierst, ist nicht für NSS Soft!
Gast #2373010
Lesenswert?

Ja, kann sein dass ich da was durcheinander gebracht habe, ich habe 
leider immer noch nicht herausgefunden wie man das ganze in der Hardware 
Variante realisieren soll und werde wohl bei der Software bleiben. Das 
Beispiel hatte ich ursprünglich aus diesem STM Example (DMA). Ich hatte 
mich nicht sehr um die DMA gekümmert und nur das nötigste behalten, mag 
sein dass es im Zusammenspiel mit dieser Sinn ergibt:
1
/**
2
  ******************************************************************************
3
  * @file    SPI/DMA/main.c 
4
  * @author  MCD Application Team
5
  * @version V3.5.0
6
  * @date    08-April-2011
7
  * @brief   Main program body
8
  ******************************************************************************
9
  * @attention
10
  *
11
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
12
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
13
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
14
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
15
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
16
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
17
  *
18
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
19
  ******************************************************************************
20
  */ 
21

22
/* Includes ------------------------------------------------------------------*/
23
#include "stm32f10x.h"
24
#include "platform_config.h"
25

26

27
/** @addtogroup STM32F10x_StdPeriph_Examples
28
  * @{
29
  */
30

31
/** @addtogroup SPI_DMA
32
  * @{
33
  */ 
34

35
/* Private typedef -----------------------------------------------------------*/
36
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
37

38
/* Private define ------------------------------------------------------------*/
39
#define BufferSize       32
40

41
/* Private macro -------------------------------------------------------------*/
42
/* Private variables ---------------------------------------------------------*/
43
SPI_InitTypeDef  SPI_InitStructure;
44
DMA_InitTypeDef  DMA_InitStructure;
45
GPIO_InitTypeDef GPIO_InitStructure;
46

47
uint8_t SPI_MASTER_Buffer_Tx[BufferSize] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
48
                                            0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
49
                                            0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
50
                                            0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
51
                                            0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
52
                                            0x1F, 0x20};
53
uint8_t SPI_SLAVE_Buffer_Rx[BufferSize];
54
__IO uint8_t TxIdx = 0;
55
volatile TestStatus TransferStatus = FAILED;
56

57

58
/* Private function prototypes -----------------------------------------------*/
59
void RCC_Configuration(void);
60
void GPIO_Configuration(void);
61
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
62

63
/* Private functions ---------------------------------------------------------*/
64

65
/**
66
  * @brief  Main program
67
  * @param  None
68
  * @retval None
69
  */
70
int main(void)
71
{
72
  /*!< At this stage the microcontroller clock setting is already configured, 
73
       this is done through SystemInit() function which is called from startup
74
       file (startup_stm32f10x_xx.s) before to branch to application main.
75
       To reconfigure the default setting of SystemInit() function, refer to
76
       system_stm32f10x.c file
77
     */     
78
       
79
  /* System clocks configuration ---------------------------------------------*/
80
  RCC_Configuration();
81

82
  /* GPIO configuration ------------------------------------------------------*/
83
  GPIO_Configuration();
84

85
  /* SPI_SLAVE_Rx_DMA_Channel configuration ---------------------------------------------*/
86
  DMA_DeInit(SPI_SLAVE_Rx_DMA_Channel);
87
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SPI_SLAVE_DR_Base;
88
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI_SLAVE_Buffer_Rx;
89
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
90
  DMA_InitStructure.DMA_BufferSize = BufferSize;
91
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
92
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
93
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
94
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
95
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
96
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
97
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
98
  DMA_Init(SPI_SLAVE_Rx_DMA_Channel, &DMA_InitStructure);
99

100
  /* SPI_MASTER configuration ------------------------------------------------------*/
101
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
102
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
103
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
104
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
105
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
106
  SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
107
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
108
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
109
  SPI_InitStructure.SPI_CRCPolynomial = 7;
110
  SPI_Init(SPI_MASTER, &SPI_InitStructure);
111

112
  /* SPI_SLAVE configuration ------------------------------------------------------*/
113
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Rx;
114
  SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
115
  SPI_Init(SPI_SLAVE, &SPI_InitStructure);
116

117
  /* Enable SPI_MASTER NSS output for master mode */
118
  SPI_SSOutputCmd(SPI_MASTER, ENABLE);
119

120
  /* Enable SPI_SLAVE Rx request */
121
  SPI_I2S_DMACmd(SPI_SLAVE, SPI_I2S_DMAReq_Rx, ENABLE);
122

123
  /* Enable SPI_SLAVE */
124
  SPI_Cmd(SPI_SLAVE, ENABLE);
125
  /* Enable SPI_MASTER */
126
  SPI_Cmd(SPI_MASTER, ENABLE);
127

128
  /* Enable DMA1 Channel4 */
129
  DMA_Cmd(SPI_SLAVE_Rx_DMA_Channel, ENABLE);
130

131
  /* Transfer procedure */
132
  while (TxIdx < BufferSize)
133
  {
134
    /* Wait for SPI_MASTER Tx buffer empty */
135
    while (SPI_I2S_GetFlagStatus(SPI_MASTER, SPI_I2S_FLAG_TXE) == RESET);
136
    /* Send SPI_MASTER data */
137
    SPI_I2S_SendData(SPI_MASTER, SPI_MASTER_Buffer_Tx[TxIdx++]);
138
  }
139

140
  /* Wait for DMA1 channel4 transfer complete */
141
  while (!DMA_GetFlagStatus(SPI_SLAVE_Rx_DMA_FLAG));
142

143
  /* Check the correctness of written data */
144
  TransferStatus = Buffercmp(SPI_SLAVE_Buffer_Rx, SPI_MASTER_Buffer_Tx, BufferSize);
145
  /* TransferStatus = PASSED, if the transmitted and received data
146
     are equal */
147
  /* TransferStatus = FAILED, if the transmitted and received data
148
     are different */
149

150
  while (1)
151
  {}
152
}
153

154
/**
155
  * @brief  Configures the different system clocks.
156
  * @param  None
157
  * @retval None
158
  */
159
void RCC_Configuration(void)
160
{
161
  /* PCLK2 = HCLK/2 */
162
  RCC_PCLK2Config(RCC_HCLK_Div2); 
163

164
  /* Enable peripheral clocks --------------------------------------------------*/
165
  /* Enable SPI_SLAVE DMA clock */
166
  RCC_AHBPeriphClockCmd(SPI_SLAVE_DMA_CLK, ENABLE);
167

168
#ifdef USE_STM3210C_EVAL
169
  /* Enable GPIO clock for SPI_MASTER and SPI_SLAVE */
170
  RCC_APB2PeriphClockCmd(SPI_MASTER_GPIO_CLK | SPI_SLAVE_GPIO_CLK |
171
                         RCC_APB2Periph_AFIO, ENABLE);
172

173
  /* Enable SPI_MASTER Periph clock */
174
  RCC_APB1PeriphClockCmd(SPI_MASTER_CLK, ENABLE);
175
                           
176
#else
177
  /* Enable SPI_MASTER clock and GPIO clock for SPI_MASTER and SPI_SLAVE */
178
  RCC_APB2PeriphClockCmd(SPI_MASTER_GPIO_CLK | SPI_SLAVE_GPIO_CLK |
179
                         SPI_MASTER_CLK, ENABLE);
180
#endif
181
  /* Enable SPI_SLAVE Periph clock */
182
  RCC_APB1PeriphClockCmd(SPI_SLAVE_CLK, ENABLE);
183
}
184

185
/**
186
  * @brief  Configures the different GPIO ports.
187
  * @param  None
188
  * @retval None
189
  */
190
void GPIO_Configuration(void)
191
{
192
  GPIO_InitTypeDef GPIO_InitStructure;
193

194
#ifdef USE_STM3210C_EVAL
195
  /* Enable SPI3 Pins Software Remapping */
196
  GPIO_PinRemapConfig(GPIO_Remap_SPI3, ENABLE);
197

198
  /* Configure SPI_MASTER pins: SCK and MOSI */
199
  GPIO_InitStructure.GPIO_Pin = SPI_MASTER_PIN_SCK | SPI_MASTER_PIN_MOSI;
200
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
201
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
202
  GPIO_Init(SPI_MASTER_GPIO, &GPIO_InitStructure);
203

204
  /* Configure SPI_MASTER NSS pin */
205
  GPIO_InitStructure.GPIO_Pin = SPI_MASTER_PIN_NSS;
206
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
207
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
208
  GPIO_Init(SPI_MASTER_GPIO_NSS, &GPIO_InitStructure);
209

210
#else
211
  /* Configure SPI_MASTER pins: NSS, SCK and MOSI */
212
  GPIO_InitStructure.GPIO_Pin = SPI_MASTER_PIN_NSS | SPI_MASTER_PIN_SCK | SPI_MASTER_PIN_MOSI;
213
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
214
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
215
  GPIO_Init(SPI_MASTER_GPIO, &GPIO_InitStructure);
216
#endif
217

218
  /* Configure SPI_SLAVE pins: NSS, SCK and MISO*/
219
  GPIO_InitStructure.GPIO_Pin = SPI_SLAVE_PIN_NSS | SPI_SLAVE_PIN_SCK;
220
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
221
  GPIO_Init(SPI_SLAVE_GPIO, &GPIO_InitStructure);
222

223
  GPIO_InitStructure.GPIO_Pin =  SPI_SLAVE_PIN_MISO;
224
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
225
  GPIO_Init(SPI_SLAVE_GPIO, &GPIO_InitStructure);
226
  
227
}
228

229
/**
230
  * @brief  Compares two buffers.
231
  * @param  pBuffer1, pBuffer2: buffers to be compared.
232
  * @param  BufferLength: buffer's length
233
  * @retval PASSED: pBuffer1 identical to pBuffer2
234
  *         FAILED: pBuffer1 differs from pBuffer2
235
  */
236
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
237
{
238
  while (BufferLength--)
239
  {
240
    if (*pBuffer1 != *pBuffer2)
241
    {
242
      return FAILED;
243
    }
244

245
    pBuffer1++;
246
    pBuffer2++;
247
  }
248

249
  return PASSED;
250
}
251

252
#ifdef  USE_FULL_ASSERT
253

254
/**
255
  * @brief  Reports the name of the source file and the source line number
256
  *         where the assert_param error has occurred.
257
  * @param  file: pointer to the source file name
258
  * @param  line: assert_param error line source number
259
  * @retval None
260
  */
261
void assert_failed(uint8_t* file, uint32_t line)
262
{
263
  /* User can add his own implementation to report the file name and line number,
264
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
265

266
  /* Infinite loop */
267
  while (1)
268
  {}
269
}
270

271
#endif
272

273
/**
274
  * @}
275
  */ 
276

277
/**
278
  * @}
279
  */ 
280

281
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
#2373012
Lesenswert?

Seb schrieb:

> leider immer noch nicht herausgefunden wie man das ganze in der Hardware
> Variante realisieren soll

Soweit mir bekannt überhaupt nicht. Darüber sind schon viele gestolpert 
und haben beispielsweise ihr Leid im Forum von ST beklagt (hier aber 
auch schon).

Besonders perfide ist das bei DMA, weil man bei nur sendendem Transfer 
keinen Interrupt für das Ende der Datenübertragung hat, der sich im 
Timing für die Deaktivierung eignen würde. Der Abschluss-Interrupt vom 
Transmit-DMA kommt zu früh. Man kann gezwungen sein, die Daten völlig 
unnötig wieder per DMA rückzulesen, um dessen Abschluss-Interrupt dafür 
einspannen zu können, wenn man keine Timer oder Zeitverzögerungen 
einsetzen will.

Beitrag "STM32 SPI2 mit DMA Problem (DMA TC-Flag kommt zu früh)"
Beitrag "STM32 SPI - Wozu dieses NSS?"
#2373028
Lesenswert?

Seb schrieb:
> a, kann sein dass ich da was durcheinander gebracht habe, ich habe
> leider immer noch nicht herausgefunden wie man das ganze in der Hardware
> Variante realisieren soll und werde wohl bei der Software bleiben.

Lass es bei der Software-Variante. Damit hast Du das Timing am CS Pin 
selber unter Kontrolle. Der Aufwand für den Pin setzen/rücksetzen ist 
doch vertretbar.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren