Forum: Mikrocontroller und Digitale Elektronik STM32: SPI MISO Bug


von Tim R. (mugen)


Lesenswert?

Ich verstehe die Welt seit einigen Stunden nicht mehr. Ich habe Probleme 
mit einem simplen SPI Bus und finde einfach nicht die Ursache dafür.

Ich benutzte das stm32 discovery board als SPI Master um Daten zu senden 
und zu empfangen.

Folgendes geht:

- CLK ist da
- CS geht
- MOSI funktioniert einwandfrei und die Bits habe ich xmal schon geprüft 
und gezählt
- Daten kommen an MISO richtig an!

Ich benutze CooCox als IDE.
Ich habe bereits auch eine Lösung gefunden, allerdings geht die wirklich 
nur über CooCox. Nach der SPI Initialisierung setze CPOL und CPHA auf 
High über das JTAG-Interface und lasse SPI1 kurz falsch laufen (Nur ein 
Frame). Danach setze ich CPOL und CPHA wieder auf 0 und dann 
funktioniert alles. Leider finde ich nicht den Grund dafür und ich würde 
mich sehr darüber freuen, wenn ich den Controller ohne JTAG Anbindung zu 
laufen bekomme ;)


Hier meine GPIO Initialisierung:
1
    // GPIO_Pin_5 - SPI1_SCK      OUT
2
    // GPIO_Pin_6 - SPI1_MISO      IN
3
    // GPIO_Pin_7 - SPI1_MOSI      OUT
4
    // GPIO_Pin_10 -                              // BLOCK-TEST: SPI_CS
5
6
    /* Configure SPI1 pins: SCK, MISO and MOSI -------------------------------*/
7
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_7;//
8
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
9
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
10
    GPIO_Init(GPIOA, &GPIO_InitStruct);
11
12
13
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
14
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
15
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
16
    GPIO_Init(GPIOA, &GPIO_InitStruct);
17
18
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
19
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
20
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
21
    GPIO_Init(GPIOB, &GPIO_InitStruct);

Hier meine SPI Initialisierung:
1
void init_SPI1(void)
2
{
3
  SPI_InitTypeDef SPI_InitStructure;
4
5
  //=======================================================================
6
    /* 1st phase: SPI1 Master */
7
    /* SPI1 Configuration ----------------------------------------------------*/
8
9
    /* Deinitializes the SPIx peripheral registers to their default reset values */
10
  SPI_I2S_DeInit(SPI1);
11
12
  SPI_StructInit(&SPI_InitStructure);
13
14
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
15
    // SPI MODE Configuration:
16
    //
17
    //   Mode   CPOL   CPHA
18
    //   0      0      0
19
    //   1      0      1
20
    //   2      1      0
21
    //   3      1      1
22
    //
23
    //          0           SPI_CPOL_Low
24
    //          1           SPI_CPOL_High
25
    //                 0    SPI_CPHA_1Edge
26
    //                 1    SPI_CPHA_2Edge
27
28
    // SPI MODE 3:
29
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
30
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
31
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;          // SPI_DataSize_8b   or SPI_DataSize_16b
32
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;          // SPI_FirstBit_MSB or SPI_FirstBit_LSB
33
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;              // SPI_NSS_Soft   or SPI_NSS_Hard
34
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;            // SPI_Mode_Master  or SPI_Mode_Slave
35
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //SPI_Direction_1Line_Tx;//
36
    SPI_InitStructure.SPI_CRCPolynomial = 7;
37
38
    SPI_Init(SPI1, &SPI_InitStructure);      // SPI initialisieren
39
40
    SPI_CalculateCRC(SPI1, DISABLE);
41
42
    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, DISABLE);
43
44
    /* Enable SPI1 */
45
    SPI_Cmd(SPI1, ENABLE);
46
47
    /* Wait for SPI1 Tx buffer empty */
48
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
49
}

von (prx) A. K. (prx)


Lesenswert?

Eine Kleinigkeit fehlt leider: nämlich was genau nicht funktioniert. 
Also was du versuchst, was dabei deiner Ansicht nach passieren sollte 
und was tatsächlich passiert.

Und der Code dazu fehlt auch.

: Bearbeitet durch User
von Tim R. (mugen)


Lesenswert?

Okay...

Was genau nicht funktioniert ist, dass ich keine Daten im 
Empfangsregister vorfinde obwohl das richtige Byte an MISO anliegt. Der 
Slave funktioniert somit einwandfrei. Ich bekomme die JTAG Lösung auch 
nicht per Code nachgestellt. Achselzuck

von (prx) A. K. (prx)


Lesenswert?

Takte laufen?

von (prx) A. K. (prx)


Lesenswert?

Es bringt einen nicht immer weiter, nur den Code zu zeigen, in dem man 
selbst den Fehler vermutet. Manchmal hilft es, auch den Code zu zeigen, 
in dem man ihn nicht vermutet.

von Tim R. (mugen)


Lesenswert?

Ja die Takte laufen, die Bits in den RCC Registern habe ich auch bereits 
geprüft. Ansonsten würde kein SPI Frame nach außen gesendet werden.

Gerne kann ich den Test-Code posten, aber dort vermutlich keine 
Probleme. Der Code ist nicht fertig und auch der Stil gefällt mir noch 
nicht:
1
#include "stm32f10x.h"
2
#include "system.h"
3
4
/***************************************************************************//**
5
 @brief Double_Pulse_Main
6
 ******************************************************************************/
7
8
uint16_t SPI1_TX(uint16_t DATA_TX);
9
uint16_t SPI1_RX();
10
11
uint16_t ARRAY_TEST[3] = { 0x01, 0x02, 0x03 };
12
13
void Double_Pulse_Main_TEST_BLOCKRAM(uint32_t l_pulse_t1, uint32_t l_pulse_t2, uint32_t l_pulse_t3)
14
{
15
    static int i=0;
16
    static int l_j=0;
17
18
    static uint16_t l_pulse[3];
19
20
    //*LESEN getestet mit SPI_CPOL_Low & SPI_CPHA_1Edge ********************************************************************************************
21
      ARRAY_TEST[0] = 0;
22
        ARRAY_TEST[1] = 0;
23
        ARRAY_TEST[2] = 0;
24
25
        if(i == 1)
26
        {
27
          GPIOA->BSRR = GPIO_Pin_1;  // RAM: WE auf 1
28
          i = 0;
29
          l_j += 1;
30
31
          if(l_j >= 200)
32
            l_j = 0;
33
        }
34
        else
35
        {
36
          GPIOA->BRR = GPIO_Pin_1;    // RAM: WE auf 0
37
          i = 1;
38
        }
39
40
      GPIOA->BRR   = GPIO_Pin_10;  // SPI_!CS auf 0
41
    Delay(1);//10 µs
42
43
    if(i == 1)
44
    {
45
      ARRAY_TEST[0] = SPI1_TX(l_j);      // 23-16 bit
46
47
      ARRAY_TEST[1] = SPI1_TX(l_j);    // 15-08 bit
48
49
      ARRAY_TEST[2] = SPI1_TX(l_j);    // 07-00 bit
50
51
      GPIOA->BRR   = GPIO_Pin_2;    // ADD0 auf 0
52
      GPIOA->BRR   = GPIO_Pin_3;    // ADD1 auf 0
53
      Delay(1);//10 µs
54
55
      GPIOA->BSRR  = GPIO_Pin_9;    // CLK zunächst auf 1
56
      Delay(1);//10 µs
57
      GPIOA->BRR   = GPIO_Pin_9;    // CLK zunächst auf 0
58
      Delay(1);//10 µs
59
    }
60
    else
61
    {
62
      GPIOA->BSRR  = GPIO_Pin_9;    // CLK zunächst auf 1
63
      Delay(1);//10 µs
64
      GPIOA->BRR   = GPIO_Pin_9;    // CLK zunächst auf 0
65
      Delay(1);//10 µs
66
67
      ARRAY_TEST[0] = SPI1_RX();    // 23-16 bit
68
69
      ARRAY_TEST[1] = SPI1_RX();    // 15-08 bit
70
71
      ARRAY_TEST[2] = SPI1_RX();    // 07-00 bit
72
    }
73
74
     Delay(1);//10 µs
75
     GPIOA->BSRR   = GPIO_Pin_10;  // SPI_!CS auf 1
76
     Delay(100);//1000 µs
77
}
78
79
uint16_t SPI1_TX(uint16_t DATA_TX)
80
{
81
  uint16_t l_value = 0;
82
83
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); // Wait for SPI1 Tx buffer empty
84
  SPI_I2S_SendData(SPI1,DATA_TX);
85
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1);
86
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
87
  l_value = SPI_I2S_ReceiveData(SPI1);  /* Clear pending RXNE*/
88
89
  return l_value;
90
}
91
92
uint16_t SPI1_RX()
93
{
94
  uint16_t l_DATA_RX=0;
95
96
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); // Wait for SPI1 Tx buffer empty
97
  SPI_I2S_SendData(SPI1,0x00);
98
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1);
99
100
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);
101
  l_DATA_RX=SPI_I2S_ReceiveData(SPI1); /* Clear pending RXNE*/
102
103
  return l_DATA_RX;
104
}

Initialisierung:
1
  SystemInit();
2
3
4
  /* System clocks configuration -------------------------------------------*/
5
  init_RCC();
6
7
    /* GPIO configuration ----------------------------------------------------*/
8
    init_GPIO();
9
10
11
12
    /* TIMER configuration ---------------------------------------------------*/
13
    //init_TIM2_PWM();
14
    init_TIM1_Pulse();
15
    init_TIM2_Pulse();
16
    init_TIM3_Pulse();
17
    //init_TIM1M_TIM3S_PULSE();
18
    init_TIM3M_TIM2S_PULSE();
19
    init_TIM4_ENC();
20
    init_TIM7_SW();
21
22
    init_SysTick_1msec();
23
24
    init_SPI1(); // INIT SPI1

von Daniel (Gast)


Lesenswert?

Hallo,
nur ne Vermutung, sollte der GPIO6 also der MISO nicht auch als 
GPIO_Mode_AF konfiguriert werden?

Gruß Daniel

von RayOfLight (Gast)


Lesenswert?

Problem ist genau hier:

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

von Tim R. (mugen)


Lesenswert?

RayOfLight schrieb:
> Problem ist genau hier:
>
> GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Mode habe ich bereits mehrmals gewechselt und dies funktioniert 
auch nicht:
1
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
2
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //GPIO_Mode_IN_FLOATING;
3
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
4
    GPIO_Init(GPIOA, &GPIO_InitStruct);

Im Internet habe ich bereits unterschiedlichste Meinungen über die 
richtige Konfigurationen von MISO gefunden und gefühlt habe ich alles 
ausprobiert. Aber ich lasse mich sehr gerne belehren, so ist es ja 
nicht.

von Tim R. (mugen)


Lesenswert?

Bitte beachtet den sehr wichtigen Hinweis, dass die Kummunikation 
funktioniert wenn SPI_CPOL und SPI_CPHA über JTAG kurzzeitig auf High 
gezogen wird. Warum auch immer ?!?

von (prx) A. K. (prx)


Lesenswert?

Die SS Steuerung rund um NSS hat wohl alle irritiert, die je mit STM32 
und SPI zu tun hatten. CR1:NSS=1 heisst, dass der interne SS-Pin des SPI 
Moduls von CR1:SSI gesteuert wird, an Stelle des externen Pins SS. Und 
wenn man einem Master extern SS=0 anlegt, dann nimmt er an, dass ein 
anderer Master schneller war als er und schaltet ab. Folglich 
funktioniert NSS=1 nur bei SSI=1.

von Tim R. (mugen)


Lesenswert?

@ A.K.

Diese Aussage habe ich auch öfters im Internet gelesen, dass es wegen 
NSS nur Verwirrungen kommt. Ich benutze GPOIA PIN10 als CS und steuere 
ihn auch über SW an. Für mich auch kein Problem, da mir die 
Geschwindigkeit in dieser Applikation recht egal ist. Andererseits frag 
ich mich wirklich was ST sich dabei gedacht hat, aber da scheinen wohl 
die alten Thomson Zeiten durch. In Verbindung mit DMA ist die ganze NSS 
Steuerung total sinnfrei.

Im übrigen habe ich sogar den neuesten GNU complire installiert, mir 
gehen langsam die Ideen aus ;-)

von (prx) A. K. (prx)


Lesenswert?

Tim R. schrieb:
> Ich benutze GPOIA PIN10 als CS und steuere
> ihn auch über SW an.

Ist mir klar. Es geht bei NSS=1 allerdings um das interne SS Signal des 
SPI-Moduls. Also das SS Signal, das bei NSS=1 aussen auf dem Pin nicht 
aufkreuzt, intern aber dennoch existiert. Wenn diese interne Signal auf 
0 steht, dann ist Essig. Und dieses interne Signal ist SSI, bei NSS=1.

Ich mag die STM32 Lib nicht so, also darfst du selber suchen. ;-)

> In Verbindung mit DMA ist die ganze NSS Steuerung total sinnfrei.

Yep.

: Bearbeitet durch User
von holger (Gast)


Lesenswert?

>    // SPI MODE 3:
>    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
>    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;


Vieleicht möchte das was du da angeschlossen hast
tatsächlich Mode3 haben? Eingestellt ist jedenfalls Mode0.

von Jannis C. (kabelwurm)


Lesenswert?

Was mir noch einfällt, den gesamten Code ohne die Libs zu schreiben. 
Damit kannst du einen Softwarefehler besser finden und möglicherweise 
den Fehler finden, wenn du im Datenblatt ließt. Mir geht es inzwischen 
so, dass ich die Libs garnicht mehr benutze und die Register direkt 
beschreibe. Zudem ist der Code damit maximal schnell und mit etwas 
Einarbeitung auch übersichtlicher, da man nach verfolgen kann, wann 
welches Bit gesetzt/gelöscht wird.
Gruß Jannis

von RayOfLight (Gast)


Lesenswert?

Versuche mal GPIO_PinAFConfig fur den MISO pin

von Tim R. (mugen)


Lesenswert?

holger schrieb:
>>    // SPI MODE 3:
>>    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
>>    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
>
>
> Vieleicht möchte das was du da angeschlossen hast
> tatsächlich Mode3 haben? Eingestellt ist jedenfalls Mode0.

Soll 0 sein, mein Kommentar habe ich noch nicht zurück geändert.

von (prx) A. K. (prx)


Lesenswert?

SETZ DAS VERDAMMTE SSI BIT!

Falls meine Erklärung oben zu umständlich gewesen sein sollte. ;-)

von Tim R. (mugen)


Angehängte Dateien:

Lesenswert?

> Ich mag die STM32 Lib nicht so, also darfst du selber suchen. ;-)

Also das bit SSM und SSI sind bei mir beide auf High.

Zu STM32 Lib: Ich stimme da sehr gerne zu, da vieles kryptisch und als 
großes Monster gelöst wurde. Was ich aber mag ist die struct Lösung. Hex 
Files noch zur Parametrierung zu nutzen finde ich persönlich als lästig.

von holger (Gast)


Lesenswert?

>> Vieleicht möchte das was du da angeschlossen hast
>> tatsächlich Mode3 haben? Eingestellt ist jedenfalls Mode0.
>
>Soll 0 sein, mein Kommentar habe ich noch nicht zurück geändert.

Dann muss das wohl ein anderes Problem sein.
Deine Config für Mode0 ist jedenfalls in Ordnung.
Vieleicht liegts auch an der Schaltung.

von (prx) A. K. (prx)


Lesenswert?

Tim R. schrieb:
> Also das bit SSM und SSI sind bei mir beide auf High.

Vor oder nach dem Hack?

von Tim R. (mugen)


Lesenswert?

A. K. schrieb:
> SETZ DAS VERDAMMTE SSI BIT!
>
> Falls meine Erklärung oben zu umständlich gewesen sein sollte. ;-)

In der Tat habe ich das SSi bit wirklich suchen müssen und es wurde 
elegant in der Datei stm32f10x_spi.h in diese Zeile versteckt:
1
 #define SPI_Mode_Master                 ((uint16_t)0x0104)

Man beachte 0x100 (SSI bit)

Ach wie ich diese define Programmierung hasse.

von Tim R. (mugen)


Lesenswert?

A. K. schrieb:
> Tim R. schrieb:
>> Also das bit SSM und SSI sind bei mir beide auf High.
>
> Vor oder nach dem Hack?

Vor und wie auch nach dem Hack. Ich habe mal das Register direkt 
angesprochen und die Initialisierung ein wenig aufgeräumt. Leider kein 
Unterschied:

1
void init_SPI1(void)
2
{
3
  struct STRUCT_INIT_CR1_SPI{
4
    uint16_t CPHA:1;
5
    uint16_t CPOL:1;
6
    uint16_t MSTR:1;
7
    uint16_t BR:3;
8
    uint16_t SPE:1;
9
    uint16_t LSBFIRST:1;
10
    uint16_t SSI:1;
11
    uint16_t SSM:1;
12
    uint16_t RXONLY:1;
13
    uint16_t DFF:1;
14
    uint16_t CRCNEXT:1;
15
    uint16_t CRCEN:1;
16
    uint16_t BIDIOE:1;
17
    uint16_t BIDIMODE:1;
18
  };
19
20
  union STRUCT_SPI_CR1{
21
    uint16_t          all;
22
    struct  STRUCT_INIT_CR1_SPI  bit;
23
  };
24
25
  union STRUCT_SPI_CR1 SPI_CR1;
26
27
    // SPI MODE Configuration:
28
    //
29
    //   Mode   CPOL   CPHA
30
    //   0      0      0
31
    //   1      0      1
32
    //   2      1      0
33
    //   3      1      1
34
    //
35
    //          0           SPI_CPOL_Low
36
    //          1           SPI_CPOL_High
37
    //                 0    SPI_CPHA_1Edge
38
    //                 1    SPI_CPHA_2Edge
39
40
    // SPI MODE 0:
41
42
    SPI_CR1.all       = 0;
43
    SPI_CR1.bit.CPOL     = 0;
44
    SPI_CR1.bit.CPHA     = 0;
45
    SPI_CR1.bit.DFF     = 0;  //  8-bit data frame format is selected for transmission/reception
46
    SPI_CR1.bit.LSBFIRST   = 0;  //  MSB transmitted first
47
    SPI_CR1.bit.SSI      = 1;
48
    SPI_CR1.bit.SSM      = 1;
49
    SPI_CR1.bit.MSTR    = 1;  // Master configuration
50
    SPI_CR1.bit.SPE      = 1;  // Peripheral enable
51
    SPI_CR1.bit.BR      = 7;
52
53
    SPI1->CR1 = SPI_CR1.all;
54
}

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.