Forum: Mikrocontroller und Digitale Elektronik Frage: STM32F103 beide SPI benutzen


von asd (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe ein Bluepill Board und versuche gerade beide SPI Busse zu 
benutzen. Ich habe die Seiten von Stefan Frings und seine CMSIS Dateien 
als Start benutzt:
http://stefanfrings.de/stm32/stm32f1.html
Das gefällt mir ganz gut, das Setzen der Registerwerte funktioniert 
ähnlich wie ich das vom AVR mega gewohnt bin. Jetzt bin ich aber auf ein 
Problem gestoßen bei dem mir das Rference Manual und Beispiele im 
Internet nicht weiter helfen. Ich versuche beide SPI Busse zu benutzen, 
aber es gelingt mit nur beim SPI1. Der SPI2 schiebt keine Daten raus, 
und sein "TXE" (TX buffer empty) Bit geht nach dem ersten schreiben auf 
Null und wird nie wieder high.
SPI2 hängt auf dem APB1 Bus, währen die Peripherie die ich erfolgreich 
benutzt habe (SPI1 und USART1) am APB2 hängen. Vielleicht ist das ein 
Hinweis? In allen Beispielen im Internet hat auch bei APB1 Peripherie 
ein Aktivieren gereicht:
SET_BIT(RCC->APB1ENR, RCC_APB1ENR_SPI2EN); // Enable SPI2

Im Reference Manual habe ich keinen Hinweis gefunden dass mehr als das 
nötig ist. Am CPU Clock wird nichts verändert, es sollten also alle 
Clocks bei 8MHz liegen.

Ich hänge mal den kompletten Code hier rein. Am Anfang von main wird 
direkt in die Funktion "test_spi2" gesprungen, dort nur die beiden SPI 
initialisiert (nur "init_gpio();" wird angespungen, alle anderen 
Funktionen werden in diesem Beispiel nicht benutzt)

Vielleicht sieht einer der ARM-Freaks gleich das Register das ich noch 
setzen müsste...
1
void test_spi2()
2
{
3
  uint16_t data=0;
4
  int led_state=0;
5
6
    // Enable Port A, B, C and alternate functions
7
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);
8
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);
9
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);
10
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_AFIOEN);
11
12
13
  SET_BIT(RCC->APB2ENR, RCC_APB2ENR_SPI1EN); // Enable SPI1
14
  SET_BIT(RCC->APB1ENR, RCC_APB1ENR_SPI2EN); // Enable SPI2
15
16
  init_gpio();  // set all ports to GPIO and alternate functions  // ToDo: vor oder nach dem SPI setup?!??
17
18
  SET_BIT(SPI1->CR1, SPI_CR1_DFF);  // 16 bit per transfer
19
  SET_BIT(SPI1->CR1, SPI_CR1_MSTR);  // Master mode
20
  SET_BIT(SPI1->CR1, SPI_CR1_BR_2);  // clock div 32 / RM0008 p.743  ( bei 8MHz Takt sind das 250kHz)
21
  //SET_BIT(SPI1->CR1, SPI_CR1_BR_0);  // clock div 4  / RM0008 p.743
22
  SET_BIT(SPI1->CR1, SPI_CR1_SPE);  // SPI enable
23
24
  SET_BIT(SPI2->CR1, SPI_CR1_DFF);  // 16 bit per transfer
25
  SET_BIT(SPI2->CR1, SPI_CR1_MSTR);  // Master mode
26
  SET_BIT(SPI2->CR1, SPI_CR1_BR_2);  // clock div 32 / RM0008 p.743
27
  //SET_BIT(SPI2->CR1, SPI_CR1_BR_0);  // clock div 4  / RM0008 p.743
28
  SET_BIT(SPI2->CR1, SPI_CR1_SPE);  // SPI enable

und dann die Datenübertragung:
1
    // write 2x 16 bit on SPI2 and 2x 16bit on SPI1
2
    WRITE_REG(GPIOB->BSRR,GPIO_BSRR_BR12);  // PB12 low  ( Chip select for SPI)
3
    while (!(SPI1->SR & SPI_SR_TXE));   // busy wait for TX buffer ready to write
4
    //while (!(SPI2->SR & SPI_SR_TXE));   // busy wait for TX buffer ready to write  // bei SPI2 hängt der hier ewig (außer beim ersten Aufruf)
5
    SPI2->DR=0x55ff;    // send 16 bit word
6
    SPI1->DR=data;    // send 16 bit word
7
    while (!(SPI1->SR & SPI_SR_TXE));   // busy wait for TX buffer ready to write
8
    //while (!(SPI2->SR & SPI_SR_TXE));   // busy wait for TX buffer ready to write  // bei SPI2 hängt der hier ewig
9
    SPI2->DR=0x300f;    // send 16 bit word
10
    SPI1->DR=data;    // send 16 bit word
11
    while ( (SPI1->SR & SPI_SR_BSY));   // busy wait for SPI transfer to be finished
12
    while ( (SPI2->SR & SPI_SR_BSY));   // busy wait for SPI transfer to be finished  (SPI2 hängt hier nicht)
13
    WRITE_REG(GPIOB->BSRR,GPIO_BSRR_BS12);  // PB12 high  ( Chip select for SPI)

von NichtWichtig (Gast)


Lesenswert?

Mach das mal mit der CubeIDE.

von HALVerweigerer (Gast)


Lesenswert?

NichtWichtig schrieb:
> Mach das mal mit der CubeIDE.

Ja denn auch mit CubeMX kann man (praktisch gänzlich) ohne
HAL arbeiten ....

von HALVerweigerer (Gast)


Lesenswert?

Wenn man das so macht kann eigentlich nicht viel schiefgehen.
1
/* FUNCTION ************************************/
2
void SPI_Init (SPI1_Mode_t mode)
3
/*
4
 * SPECIFICATION:  Init SPI1  STM32F103
5
 ***********************************************/
6
{
7
  GPIO_InitTypeDef    GPIO_InitStruct;
8
  SPI_InitTypeDef     SPI_InitStruct;
9
10
  //  Initialize SPI
11
  RCC_APB2PeriphClockCmd (RCC_APB2Periph_SPI1, ENABLE);
12
13
  RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA, ENABLE);
14
  RCC_APB2PeriphClockCmd (RCC_APB2Periph_AFIO, ENABLE);
15
16
  SPI_InitStruct.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
17
  SPI_InitStruct.SPI_Mode              = SPI_Mode_Master;
18
  SPI_InitStruct.SPI_DataSize          = SPI_DataSize_8b;
19
  SPI_InitStruct.SPI_NSS               = SPI_NSS_Soft;
20
  SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
21
  SPI_InitStruct.SPI_FirstBit          = SPI_FirstBit_MSB;
22
  SPI_InitStruct.SPI_CRCPolynomial     = 7;
23
24
  if (mode == SPI_MODE_0)
25
  {
26
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
27
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
28
  }
29
  else if (mode == SPI_MODE_1)
30
  {
31
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
32
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
33
  }
34
  else if (mode == SPI_MODE_2)
35
  {
36
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
37
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
38
  }
39
  else if (mode == SPI_MODE_3)
40
  {
41
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
42
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
43
  }
44
  else
45
  {
46
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
47
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
48
  }
49
50
  SPI_Init (SPI1, &SPI_InitStruct);
51
52
  /* Configure SPI1 pins: SCK and MOSI with default alternate
53
  function (not remapped) push-pull */
54
  GPIO_InitStruct.GPIO_Pin   = SPI_MOSI_PIN | SPI_SCLK_PIN;
55
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
56
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
57
  GPIO_Init (GPIOA, &GPIO_InitStruct);
58
59
  /* Configure MISO as Input with internal pull-up */
60
  GPIO_InitStruct.GPIO_Pin   = SPI_MISO_PIN;
61
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPU;
62
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
63
  GPIO_Init (GPIOA, &GPIO_InitStruct);
64
65
  SPI_Cmd (SPI1, ENABLE);
66
67
} /* --- SPI_Init --- */

Für das andere SPI muss man halt darauf achten das richtige
RCC_APBxPeriphClockCmd und RCC_APB2Periph_SPIx zu verwenden,
das gilt auch für die entsprechenden Ports und Alternate
Functions.

Meiner Meinung nach sehr übersichtlich, und es gibt kein
Gefrickel mit Bits im Register setzen oder clearen ....

von HALVerweigerer (Gast)


Lesenswert?

Der Vollständigkeit halber:
1
//----------------------------
2
// Includes
3
//----------------------------
4
#include "stm32f10x.h"
5
#include "stm32f10x_gpio.h"
6
#include "stm32f10x_rcc.h"
7
#include "stm32f10x_spi.h"
8
9
// Peripherie Defines - alle Pins liegen auf Port A
10
11
#define  SPI_MOSI_PIN     GPIO_Pin_7  /*    */
12
#define  SPI_MISO_PIN     GPIO_Pin_6  /*    */
13
#define  SPI_SCLK_PIN     GPIO_Pin_5  /*    */
14
15
//----------------------------
16
// SPI Mode
17
//----------------------------
18
typedef enum
19
{
20
  SPI_MODE_0 = 0,  // CPOL=0, CPHA=0
21
  SPI_MODE_1,      // CPOL=0, CPHA=1
22
  SPI_MODE_2,      // CPOL=1, CPHA=0
23
  SPI_MODE_3       // CPOL=1, CPHA=1
24
} SPI1_Mode_t;

von Monk (roehrmond)


Lesenswert?

asd schrieb:
> Der SPI2 schiebt keine Daten raus,
> und sein "TXE" (TX buffer empty) Bit geht nach dem ersten schreiben auf
> Null und wird nie wieder high.

Mit dem Problem bist du offenbar nicht alleine, schau:
Beitrag "Stm32f103 Problem mit Spi2"

Leider habe ich keine Lösung. Hast du den MISO Pin als Eingang 
konfiguriert? Das ist im Master Modus wichtig.

Dort gibt's noch ein anderes Beispiel mir ausführlicher Erklärung:
https://learnbuildshare.wordpress.com/about/stm32/using-spi-as-master/

: Bearbeitet durch User
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.