Forum: Mikrocontroller und Digitale Elektronik Probleme mit STM32F103 und SPI1 remapping


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Henning S. (henning_s)


Lesenswert?

Hallo allerseits,
ich habe mich mal nach längerer Pause wieder an die STM's rangewagt und 
habe mir ein kleines Board zum Spielen designed und gebaut.

Dabei handelt es sich um ein Board mit dem STM32F103, der auch auf dem 
BluePill-Board verbaut ist.
Ich habe am SPI1 ein kleines ILI9341 Display laufen, aber nicht an den 
default Pins für SPI1 (PA5-PA7) sondern an den alternativen Pins für den 
SPI1 (PB3-PB5).
Dafür muss der SPI1 anders gemappt werden, sowie der JTAG deaktiviert 
werden, um diese Pins dafür nutzen zu können. Zudem soll es noch ein 
Errata geben, was besagt, dass bei gemapptem SPI1 der Clock vom I2C1 
nicht aktiviert sein darf. Ich habe jetzt schon Stunden rumprobiert, 
aber ich krieg den SPI1 einfach ums verrecken nicht zum laufen. In der 
Init hängt er sich zwar nicht auf, aber dann in der while()-Schleife in 
spi_send(). Zudem hab ich mal mit dem LogicAnalyzer geguckt, was da so 
lost ist. Auf PB3-PB5 absolut GAR nix. Der SPI ist komplett tot.
Vielleicht hat ja jemand das schonmal gemacht und könnte mir 
weiterhelfen. Hier mal der Code dazu:
1
//Pseudo-Functions
2
#define CS_low()      GPIOC->ODR &= ~(1<<14);
3
#define CS_high()      GPIOC->ODR |= (1<<14);
4
5
6
void spi_init(void)//set spi speed and settings 
7
{
8
  SPI_InitTypeDef SPI_InitStruct;
9
  GPIO_InitTypeDef GPIO_InitStruct;
10
11
  RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
12
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE); //Errata -> Don't use Remapped SPI1 with activated I2C1-Clock
13
14
  // GPIO pins for MISO, MOSI and SCK
15
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3;
16
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
17
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
18
  GPIO_Init(GPIOB, &GPIO_InitStruct);
19
20
  //GPIO PortC 14 ->CS
21
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
22
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
23
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
24
  GPIO_Init(GPIOC, &GPIO_InitStruct);
25
26
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
27
  GPIO_PinRemapConfig(GPIO_Remap_SPI1, ENABLE);
28
29
  SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
30
  SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
31
  SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
32
  SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
33
  SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI_Direction_1Line_Tx;
34
  SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
35
  SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
36
  SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
37
  SPI_Init(SPI1, &SPI_InitStruct); 
38
  SPI_Cmd(SPI1, ENABLE);
39
40
  CS_high();
41
}
42
43
void spi_send(uint8_t spi_data)//send spi data to display
44
{
45
  SPI1->DR = spi_data;                // Write data to be transmitted to the SPI data register
46
  while (!(SPI1->SR & (SPI_I2S_FLAG_TXE)));      // Wait until transmit complete
47
  while (SPI1->SR & (SPI_I2S_FLAG_BSY));        // Wait until SPI is not busy anymore
48
}
49
50
uint8_t spi_read(void)
51
{
52
  SPI1->DR = 0x00;                // Write data to be transmitted to the SPI data register
53
  while (!(SPI1->SR & (SPI_I2S_FLAG_TXE)));      // Wait until transmit complete
54
  while (SPI1->SR & (SPI_I2S_FLAG_BSY));        // Wait until SPI is not busy anymore
55
  while (!(SPI1->SR & (SPI_I2S_FLAG_RXNE)));      // Wait until receive complete
56
  return SPI1->DR;                  // Return received data from SPI data register
57
}


Viele Grüße

Henning

von Monk (roehrmond)


Lesenswert?

Bist du sicher, dass es ein originaler STM32F103C8 ist?

von Henning S. (henning_s)


Angehängte Dateien:

Lesenswert?

Moin Monk,

ja, da bin ich mir eigentlich sicher. Habe anbei mal ein Foto von dem 
Controller angehängt.

Viele Grüße

: Bearbeitet durch User
von Wastl (hartundweichware)


Angehängte Dateien:

Lesenswert?

Henning S. schrieb:
> Vielleicht hat ja jemand das schonmal gemacht und könnte mir
> weiterhelfen.

Ich hab mal schnell CubeMX angeworfen und den Code für deine
Konfiguration generieren lassen. Dabei fällt auf dass MISO als
Input deklariert wird, also keine alternate Function hat.

Vielleicht kannst du dir aus den restlichen Zeilen einen Reim
machen ob bei dir alles stimmig ist. Siehe Anhang.

von Wastl (hartundweichware)


Lesenswert?

Wastl schrieb:
> Dabei fällt auf dass MISO als Input deklariert wird

Also genauer genommen als floating Pin, das wird offensichtlich
gebraucht damit die alternate Function erfüllt werden kann.

Beim Setzen der GPIO_InitStruct für MISO werden die Daten von den
Output-Pins übernommen, speziell die alternate Function bleibt
bestehen.

von Henning S. (henning_s)


Lesenswert?

Moin Wastl,
danke schonmal für deine Hilfe. Ich hab es jetzt mal genauso gemacht und 
hab den Miso als Floating Input. Zudem hab ich noch die Interrupt-Config 
aus dem CubeMX Code übernommen. Beides bringt aber leider keine 
Änderung.
1
void spi_init(void)//set spi speed and settings 
2
{
3
  SPI_InitTypeDef SPI_InitStruct;
4
  GPIO_InitTypeDef GPIO_InitStruct;
5
6
  RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
7
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE); //Errata -> Don't use Remapped SPI1 with activated I2C1-Clock
8
9
  // GPIO pins for MOSI and SCK
10
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
11
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
12
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
13
  GPIO_Init(GPIOB, &GPIO_InitStruct);
14
15
  // GPIO pins for MISO
16
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
17
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
18
  GPIO_Init(GPIOB, &GPIO_InitStruct);
19
20
  //GPIO PortC 14 ->CS
21
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
22
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
23
  GPIO_Init(GPIOC, &GPIO_InitStruct);
24
25
  //Remapping SPI1 to PB3-5 & Disable JTAG
26
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
27
  GPIO_PinRemapConfig(GPIO_Remap_SPI1, ENABLE);
28
29
  NVIC_SetPriority(SPI1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
30
  NVIC_EnableIRQ(SPI1_IRQn);
31
32
  SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
33
  SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
34
  SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
35
  SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
36
  SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI_Direction_1Line_Tx;
37
  SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
38
  SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
39
  SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
40
  SPI_Init(SPI1, &SPI_InitStruct); 
41
  SPI_Cmd(SPI1, ENABLE);
42
43
  CS_high();
44
}


Grüße

: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Henning S. schrieb:
> Beides bringt aber leider keine Änderung.

Ist diese Zeile
1
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

gleichlautend zu deiner Initialisierung?

Ich würde die Clock-Initialisierung immer separat für jedes
Peripherie-Element aufrufen, es ist mir sonst zu unübersichtlich ...

von Wastl (hartundweichware)


Lesenswert?

Henning S. schrieb:
> Zudem hab ich noch die Interrupt-Config
> aus dem CubeMX Code übernommen.

Das Interrupt-Handling hat sicherlich nichts mit der prinzipiellen
Hardware-Funktionalität des SPI zu tun.

von Henning S. (henning_s)


Lesenswert?

Wastl schrieb:
> Henning S. schrieb:
>> Beides bringt aber leider keine Änderung.
>
> Ist diese Zeile
>
1
>   LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
2
>
>
> gleichlautend zu deiner Initialisierung?
>
> Ich würde die Clock-Initialisierung immer separat für jedes
> Peripherie-Element aufrufen, es ist mir sonst zu unübersichtlich ...


Hallo Wastl,
DANKE! Das war entscheidende Hinweis auf den Tippfehler, den ich drin 
hatte. Da hast du mich auf die richtige Spur gebracht

Falsch:
1
  RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
2
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE); //Errata -> Don't use Remapped SPI1 with activated I2C1-Clock

Richtig
1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
2
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE); //Errata -> Don't use Remapped SPI1 with activated I2C1-Clock

Jetzt kann ich endlich schlafen gehen :-D

Viele Grüße

: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Henning S. schrieb:
> DANKE! Das war entscheidende Hinweis auf den Tippfehler, den ich drin
> hatte. Da hast du mich auf die richtige Spur gebracht

Danke. Mit den Clock-Bezeichnungen stehe ich auch auf Kriegsfuss,
zum Glück nimmt einem da CubeMX die Arbeit ab.

Würde dir auch empfehlen mit CubeMX zu arbeiten. Die HAL-
Geschichten kann man ja getrost unbeachtet lassen.

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.