Forum: Mikrocontroller und Digitale Elektronik STMF32, SPI, Master, Vollduplex


von G.F. (Gast)


Lesenswert?

Hallo,

ich kriege meine SPI Schnittstelle einfach nicht zum laufen. im unteren 
Quelltext ist auch der Senddata-Befehlm der ausgeführt wird. Der GPIOA3 
steuert eine LED an. Die leuchtet fleißig, hört dann aber irgendwann 
einfach auch. Ein clock oder irgendwas ist nicht sichtbar. Wo ist der 
Fehler?

Besten Dank für jede Hilfe

-> Ich verwende Keil, Bibliotheken sind ins Projekt eingefügt

#include "stm32f10x_conf.h"
#include <stm32f10x_lib.h>

ErrorStatus HSEStartUpStatus;

void RCC_Configuration(void);  //Configures Clock for all devices and 
GPIOs
void NVIC_Configuration(void);
void GPIO_init(void);
void SPI_init (void);        //Initializes all required GPIOs
void Delay(vu32 nCount);        //Creates a delay: nCount / Clock-Speed
          //Initializes the SPI-interface
//Init nested vector interrupt controller
#define BufferSize 32        //SPI's Buffersize

GPIO_InitTypeDef GPIO_Init_Struct;   //Struct für initializing GPIOs
SPI_InitTypeDef SPI_InitStructure; //Struct für initializing the 
SPI-interface

//Defining SPI's required Memory for write actions
u8 SPI1_Buffer_Tx[BufferSize] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
0x07, 0x08, 0x09,
                                 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
0x10, 0x11, 0x12,
                                 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
0x19, 0x1A, 0x1B,
                                 0x1C, 0x1D, 0x1E, 0x1F, 0x20};

u8 SPI1_Buffer_Rx[BufferSize];                 //for read actions
u8 TxIdx = 0, RxIdx = 0, k = 0;               //setting SPI's control 
variables and counter k


int main(void) {
  RCC_Configuration ();
  NVIC_Configuration();
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
  GPIO_init ();
  SPI_init();



  while (1){
    TxIdx = 0;
  RxIdx = 0;

  for (k = 0; k < BufferSize; k++)  SPI1_Buffer_Rx[k] = 0;
   while (TxIdx < BufferSize)
  {
    GPIO_SetBits(GPIOA,GPIO_Pin_3);
  Delay (0xAFFFF);
  GPIO_ResetBits(GPIOA,GPIO_Pin_3);
    /* Wait for SPI1 Tx buffer empty */
   //while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) ==RESET);
    /* Send SPI2 data */
    GPIO_SetBits(GPIOA,GPIO_Pin_3);
  Delay (0xAFFFF);
  GPIO_ResetBits(GPIOA,GPIO_Pin_3);

    SPI_I2S_SendData(SPI1, 0x55);
    /* Wait for SPI2 data reception */
    GPIO_SetBits(GPIOA,GPIO_Pin_3);
  Delay (0xAFFFF);
  GPIO_ResetBits(GPIOA,GPIO_Pin_3);
  Delay (0xAFFFF);


   //while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

    /* Read SPI1 received data */
    //SPI1_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI1);
   }
  }
}
void SPI_init(void)
{
  //-----Variablendeklaration-----
  GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef SPI_InitStructure;
  //DMA_InitTypeDef  DMA_InitStructure;

  //-----Pins Configurieren-----
  /* Config SPI1_NSS - Pin (PA.4) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* Config SPI1_SCK - Pin (PA.5) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* Config SPI1_MISO - Pin (PA.6) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* Config SPI1_MOSI - Pin (PA.7) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);


  //-----SPI-Schnittstelle Initialisierung-----
  /*Standartinitialisierung*/
  SPI_I2S_DeInit(SPI1);
  /*Spezielle Initialisierung*/
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = 
SPI_BaudRatePrescaler_8;//SPI_BaudRatePrescaler_256; //72MHz / 8 = 9MHz
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  //SPI_InitStructure.SPI_CRCPolynomial = 7;  //Std-Polynom

  SPI_Init(SPI1, &SPI_InitStructure);

  //-----SPI starten-----
  SPI_Cmd(SPI1, ENABLE);

  //-----DMA anschalten-----
  //SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);

  /* Standartinitialisierung - DMA1 Channel1 for ADC1 */
  //DMA_DeInit(DMA1_Channel1);

  /* Spezielle Initialisierung */
  //DMA_InitStructure.DMA_PeripheralBaseAddr = 0x4001244C; 
//Registeradresse von ADC-Ergebnis
  //DMA_InitStructure.DMA_MemoryBaseAddr = 
(u32)&ad_buffer[0];//0x40006100;
  //DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  //DMA_InitStructure.DMA_BufferSize = 32;  //es sind 32 16bit-Werte =^ 
64 8bit-Werte
  //DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  //DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  //DMA_InitStructure.DMA_PeripheralDataSize = 
DMA_PeripheralDataSize_HalfWord;
  //DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  //DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  //DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  /* DMA1 Channel 2 (SPI1 Rx) initialize */
  //DMA_Init(DMA1_Channel2, &DMA_InitStructure);

  /* DMA Interrupt anschalten bei End of Conversion*/
  //DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

  /* DMA1 Channel 1 enable bevor ADC sein request sendet */
  //DMA_Cmd(DMA1_Channel1, ENABLE);


  //-----Send Data via SPI-----
  //SPI_I2S_SendData(SPI1, u16 Data)

  //-----Send Data via SPI-----
  //SPI_I2S_ReceiveData(SPI1)

}



void GPIO_init () {

  GPIO_DeInit(GPIOA);                  //Reset GPIOs
  GPIO_StructInit(&GPIO_Init_Struct);   //Connecting GPIO_StructInit 
with GPIO_Init_Struct


  GPIO_Init_Struct.GPIO_Pin  = GPIO_Pin_3;    //Defining which pin is to 
be initialized
  GPIO_Init_Struct.GPIO_Speed  = GPIO_Speed_50MHz;  //Defining the 
previous selected pin's speed
  GPIO_Init_Struct.GPIO_Mode  = GPIO_Mode_Out_PP;  //Defining the 
previous selected pin's mode as push/pull
    GPIO_Init(GPIOA,&GPIO_Init_Struct);            //Initialization of 
the previous selected pin
}

/*********************************************************************** 
********
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
************************************************************************ 
*******/
void RCC_Configuration(void)
{

  /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if (HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    /* PCLK2 = HCLK/2 */
    RCC_PCLK2Config(RCC_HCLK_Div2);

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
                         RCC_APB2Periph_SPI1, ENABLE);
  /* SPI2 Periph clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

    /* PLLCLK = 8MHz * 9 = 72 MHz */
  //  RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

    /* Enable PLL */
   // RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
//    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  //  {}

    /* Select PLL as system clock source */
   // RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
  //  while (RCC_GetSYSCLKSource() != 0x08)
  //  {}
  }

}

void Delay(vu32 nCount)
{
  for(; nCount != 0; nCount--);
}

void NVIC_Configuration(void)
{
#ifdef  VECT_TAB_RAM
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}

von G.F. (Gast)


Lesenswert?

Edit: Ein clock ist nicht sichtbar soll heißen: Ein sck clock ist nicht 
messbar , sry

von G.F. (Gast)


Lesenswert?

Hilfe

von Lasse S. (cowz) Benutzerseite


Lesenswert?

1.) Ein Push so schnell tut absolut nicht not.

2.) Räum deinen Code mal auf, da ist ja ziemlich viel (Mist) 
auskommentiert.


Du wirst da nichts messen können, weil der Clock ja nur während des 
Sendens anliegt. Darum herum hast du ziemlich viele Delays und Pausen.


Gruß
Lasse
PS: Code-Beispiele bitte erstmal hübscher machen (unnötige eh 
auskommentierte Zeilen raus) und dann in nen Code-Block.

von Steffen (Gast)


Lesenswert?

1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);

fehlt schonmal, vielleicht auch noch mehr, aber als text lässt sich 
Quellcode schlecht lesen.

von G.F. (Gast)


Lesenswert?

Ja sry,

ich wollte eigentlich auch was rausschmeißen, aber dann fehlt was und 
die Frage kommt auf: Haste auch wikrlich dieses und jenes gemacht. Beim 
nächsten mal mach ichs besser, ich poste das evt. gleich nochmal, 
probier aber erstmal eure tips aus.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

die SPI-Clock aktivierst du.
1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
2
                         RCC_APB2Periph_SPI1, ENABLE);

Das passt also. Aber: Du hast da prinzipiell ziemlich viel aus dem 
Beispiel noch drin, was überhaupt nicht mehr passt (du aktivierst u.a. 
auch SPI2), dann sind Kommentare falsch...

Also: Versteh erstmal, was du mit den einzelnen Schritten im Beispiel 
überhaupt tust, dann klappt das auch besser.

von G.F. (Gast)


Lesenswert?

Also danke schon mal für die Hilfe, ich poste gleich einen 
ordentlicheren Code. Also hier die SPI_init Routine:

void SPI_init(void)
{
  //-----Variablendeklaration-----
  GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef SPI_InitStructure;
  //DMA_InitTypeDef  DMA_InitStructure;

  //-----Pins Configurieren-----
  /* Config SPI1_NSS - Pin (PA.4) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Config SPI1_SCK - Pin (PA.5) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Config SPI1_MISO - Pin (PA.6) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Config SPI1_MOSI - Pin (PA.7) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);


  //-----SPI-Schnittstelle Initialisierung-----
  /*Standartinitialisierung*/
  SPI_I2S_DeInit(SPI1);
  /*Spezielle Initialisierung*/
  SPI_InitStructure.SPI_Direction = 
SPI_Direction_2Lines_FullDuplex;

  SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = 
SPI_BaudRatePrescaler_8;//SPI_BaudRatePrescaler_256; //72MHz / 8 = 9MHz

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  //SPI_InitStructure.SPI_CRCPolynomial = 7;  //Std-Polynom

  SPI_Init(SPI1, &SPI_InitStructure);

  //-----SPI starten-----
  SPI_Cmd(SPI1, ENABLE);
}

Hier der quellcode zum Senden der Daten:

int main(void) {
  RCC_Configuration ();
  NVIC_Configuration();
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
 // GPIO_init ();
  SPI_init();



  while (1){ //laufe für immer
  TxIdx = 0;
  RxIdx = 0;

  for (k = 0; k < BufferSize; k++)  SPI1_Buffer_Rx[k] = 0;
   while (TxIdx < BufferSize)
  {
    GPIO_SetBits(GPIOA,GPIO_Pin_3); //LED an
  Delay (0xAFFFF);//Delay,damit man von der LED was sieht
  GPIO_ResetBits(GPIOA,GPIO_Pin_3); //LED aus

         //While draußen, weil er hier sonst ewig hängt
         //while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) 
==RESET);

         //Led blinkt einmal
         GPIO_SetBits(GPIOA,GPIO_Pin_3);
  Delay (0xAFFFF);
  GPIO_ResetBits(GPIOA,GPIO_Pin_3);

         //Hier passiert nix
         SPI_I2S_SendData(SPI1, 0x55);


         GPIO_SetBits(GPIOA,GPIO_Pin_3);

         //LED blinkt
  Delay (0xAFFFF);
  GPIO_ResetBits(GPIOA,GPIO_Pin_3);
  Delay (0xAFFFF);

   //Anweisung auskommentiert, da er hier sonst hängt, glaube ich
   //while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

    /* Read SPI1 received data, auch mal rausgeschmissen, hat net 
geholfen */
    //SPI1_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI1);
   }
  }
}



Besten Dank für eure Hilfe

von Steffen (Gast)


Angehängte Dateien:

Lesenswert?

im Anhang mal ein paar Zeilen Code die funktionieren.

von G.F. (Gast)


Lesenswert?

Also mein Problem ist, dass ich leider nur noch heute Zeit habe, das 
feritg zu kriegen. Wer gut, wenn jemand den Fehler sieht. Grundsätzlich 
verstanden was da läuft habe ich schon. das mit den 50 Mhz war ein 
Fehler im Eifer des Gefechts. Ich weiß, dass die SPI Schnittstelle max. 
18 MHz schafft. Ich finde den Fehler aber trotzdem nicht.

kopiert sind einige Quellcodes aus dem STM Beispiel für Vollduplex 
>Datenübertragung mit Soft_NSS. Laufen tut es trotzdem net.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Also, wenn du nochmal Code als Text postest, antworte ich dir nicht 
mehr. Dafür gibt es Code-Tags, mit denen sich dann der Code gut lesen 
lässt.

Trotzdem zu dem Code:
1.) Wieso hast du das GPIO_init weggeklammert?
2.) Im Firmware-Beispiel wird auch MISO mit AF_PP initialisiert, ob das 
sinnvoll ist, kann ich aber mangels Erfahrung nicht sagen.

3.) Mach deine Testroutine mal einfacher. Statt dem ganzen Zeugs mit dem 
Buffer reicht zum testen doch ein
1
while(1) SPI_I2S_SendData(0xFF);

Gruß
Lasse

von G.F. (Gast)


Lesenswert?

Also diese GPIO Sache hab ich brausgenommen, da meine LED an Pin A3 
liegt. Meine SPI Schnittstelle liegt aber auch an IO Bank A, nälich A4 
bis A7. Ich dachte, das wäre eventuell das Problem. Wars aber net. Und 
Danke für das Codebeispiel. Habs reinprogrammiert, muss es aber nich zum 
laufen kriegen. Irgendwo hab ich noch was übersehen...

von Steffen (Gast)


Lesenswert?

Ich glaube du musst einmal den Empfangsbuffer(SPI_DR)lesen bevor du 
wieder senden kannst, siehe ReferenceManual Seite 600(Full-duplex 
transmit and receive procedure in master or slave mode)

von G.F. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Steffen,

habe deinen Code eingefügt. Es läuft aber trotzdem nicht:

Ich konfiguriere zunächst die Clock,
mache deine SPI init
und dann führe ich deine Funktion spi1_tx aus.

Keine Ahnung warum.Im Quellcode rufe ich auch deine Funktionen auf.

von Steffen (Gast)


Lesenswert?

Hast du die RCC_Configuration bewusst geändert? Da fehlt nämlich 
einiges.

von G.F. (Gast)


Lesenswert?

Ja, habe ich. Ich verwende keine PLL oder externen Oszillator. Ich 
verwende nur die internen Oszillatoren.

von Steffen (Gast)


Lesenswert?

Ok, mit der Clock Control kenne ich mich nicht so gut aus, fehlt dann 
nicht trotzdem ein RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); . Achne lese 
gerade, dass nach einem Reset der HSI oszillator die system clock ist. 
Ist denn dann
1
* Enable HSE */
2
  RCC_HSEConfig(RCC_HSE_ON);
 richtig?

von G.F. (Gast)


Lesenswert?

@Steffen: Hmm, also meine LED kann ich schalten. Und aus dem HSE wird ja 
alles andere abgeleitet, auch der Clock für IOs .Sollte also nicht daran 
liegen.

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.