Forum: Mikrocontroller und Digitale Elektronik SPI mit STM32


von Torsten A. (torsten_a)


Angehängte Dateien:

Lesenswert?

Hi,
ich versuche mit einem STM32F103 einen SPI FRAM „FM25H20“ anzusprechen. 
Meine Versuche blieben bisher erfolglos.
Ich habe leider keine Ahnung was fehlt bzw. falsch ist.  Meine erste 
Vermutung ist, dass der Takt bzw. die Frequenz für den SPI2 Bus nicht 
richtig initialisiert wurde. Oder aber dass die SPI Initialisierung 
unvollständig ist. Vielleicht aber auch eine fehlerhafte Verwendung der 
„SPI-Routinen“.
Der FRAM verlangt den SPI Mode 0 oder 3 (CPOL=0, CPHA=0 oder 
CPOL=1,CPHA=1).
Mit einem Atmega 2560 kann ich diesen FRAM-Typ erfolgreich via SPI 
ansprechen - nur leider kann der C-Code nicht 1zu1 importiert werden…:(
Vielleicht  kann mir jemand weiter helfen und sieht wo es klemmt. Ich 
muss noch dazu sagen, dass ich erst seit 1er Woche mit einem STM32F103 
zu tun habe und keine Erfahrung habe.

meine main() mit RCC_Configuration():
1
int main (void) {
2
3
    // System Clocks Configuration 
4
    RCC_Configuration();        
5
6
    // I2C is using for test/debugging
7
    I2C_Addr_configuration();
8
    I2C1_Configuration();         
9
10
    spi2_init();                // initialize SPI
11
    test_fram();                // Test Routine
12
   
13
    NVIC_Configuration();       
14
    init_control_unit();
15
16
    while(1) {
17
        //....
18
    }
19
}
20
21
void RCC_Configuration (void) {              
22
23
        /* RCC system reset(for debug purpose) */
24
        RCC_DeInit();
25
26
        /* Enable HSE */
27
        RCC_HSEConfig(RCC_HSE_ON);
28
29
        /* Wait till HSE is ready */
30
        HSEStartUpStatus = RCC_WaitForHSEStartUp();
31
32
        if(HSEStartUpStatus == SUCCESS)
33
        {
34
            /* HCLK = SYSCLK */
35
            RCC_HCLKConfig(RCC_SYSCLK_Div1); 
36
37
            /* PCLK2 = HCLK */
38
            RCC_PCLK2Config(RCC_HCLK_Div1); 
39
40
            /* PCLK1 = HCLK/2 */
41
            RCC_PCLK1Config(RCC_HCLK_Div2);
42
43
            /* Flash 2 wait state: required at operation of 72MHz */
44
            FLASH_SetLatency(FLASH_Latency_2);
45
            /* Enable Prefetch Buffer */
46
            FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
47
48
            /* PLLCLK = 8MHz * 9 = 72 MHz */
49
            RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
50
51
            /* Enable PLL */ 
52
            RCC_PLLCmd(ENABLE);
53
54
            /* Wait till PLL is ready */
55
            while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
56
            {
57
            }
58
            /* Select PLL as system clock source */
59
            RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
60
61
            /* Wait till PLL is used as system clock source */
62
            while(RCC_GetSYSCLKSource() != 0x08)
63
            {
64
            }
65
        }
66
        
67
        // Enable peripheral Clocks
68
        /* Enable GPIO clock */
69
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
70
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
71
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
72
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
73
    
74
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
75
        /* Enable SPI clock  */
76
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
77
  
78
        
79
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
80
       
81
}


SPI2 Initialisierung:
1
void spi2_init (void) {
2
3
 // RCC 
4
 // already done --> in RCC_Configuration();
5
 /* Enable GPIO clock */
6
 //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
7
 /* Enable SPI clock  */
8
 //RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
9
10
 // GPIO 
11
 GPIO_InitTypeDef GPIO_InitStructure_NSS;
12
 // SPI2 NSS @ PB12 
13
 GPIO_InitStructure_NSS.GPIO_Pin   = GPIO_Pin_12;
14
 GPIO_InitStructure_NSS.GPIO_Mode  = GPIO_Mode_Out_PP;
15
 GPIO_InitStructure_NSS.GPIO_Speed = GPIO_Speed_50MHz;
16
 GPIO_Init(GPIOB, &GPIO_InitStructure_NSS);
17
18
 // set slave select to high  
19
 GPIO_WriteBit(GPIOB, GPIO_Pin_12, 1);
20
21
 // GPIO 
22
 GPIO_InitTypeDef GPIO_InitStructure;
23
 // SPI2 SCK/MISO/MOSI @ PB13/PB14/PB15 
24
 GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
25
 GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
26
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
27
 GPIO_Init(GPIOB, &GPIO_InitStructure);
28
29
 // SPI 
30
 SPI_InitTypeDef SPI_InitStructure;
31
32
 SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
33
 SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
34
 SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
35
 SPI_InitStructure.SPI_CPOL              = SPI_CPOL_High;  // SPI_Mode 0
36
 SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge; // SPI_Mode 0
37
 SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
38
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;    //SPI_BaudRatePrescaler_256; // 36MHz/256=140kHz < 400kHz
39
 SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
40
 SPI_InitStructure.SPI_CRCPolynomial     = 7;
41
 SPI_Init(SPI2, &SPI_InitStructure);
42
43
 SPI_CalculateCRC(SPI2, DISABLE);
44
45
 SPI_Cmd(SPI2, ENABLE);
46
47
}

Und die Funktionen fram_spi_write_byte() , fram_spi_read_byte() und 
test_fram():
1
/**************************************************************************
2
*               FRAM_SPI_WRITE_BYTE FUNCTION
3
*
4
* Description : This function writes one byte into FRAM.
5
* Arguments   : 16 bit address, 8 bit data
6
* Returns     :  None
7
* Note        : Internal Function
8
**************************************************************************/
9
void fram_spi_write_byte(unsigned int addr, unsigned char data_byte)
10
{
11
    //SPI start
12
    //SPI_SSOutputCmd(SPI2, ENABLE);
13
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 0);
14
  
15
    //Sets WEL bit. WREN must precede WRITE opcode.   
16
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
17
    SPI_I2S_SendData(SPI2, 0x06);
18
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
19
    
20
21
    //SPI end
22
    //SPI_SSOutputCmd(SPI2, DISABLE);
23
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 1);
24
25
    //delay(1);
26
27
    //SPI start
28
    //SPI_SSOutputCmd(SPI2, ENABLE);
29
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 0);
30
31
    //0x02 is WRITE opcode      
32
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
33
    SPI_I2S_SendData(SPI2, 0x02);    
34
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
35
36
    /* set address */
37
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
38
    SPI_I2S_SendData(SPI2, 0x00);    
39
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
40
    SPI_I2S_SendData(SPI2, (unsigned char)((addr & 0xFF00) >> 8));    
41
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
42
    SPI_I2S_SendData(SPI2, (unsigned char)(addr & 0x00FF));    
43
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
44
45
    //write data
46
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
47
    SPI_I2S_SendData(SPI2, data_byte);    
48
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
49
50
    /* terminate spi data transfer */
51
    //SPI_SSOutputCmd(SPI2, DISABLE);
52
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 1);  
53
}
54
55
56
/**************************************************************************
57
*               FRAM_SPI_READ_BYTE FUNCTION
58
*
59
* Description : This function reads one byte from FRAM.
60
* Arguments   : 16 bit address
61
* Returns     :  8 bit data
62
* Note        : Internal Function
63
**************************************************************************/
64
unsigned char fram_spi_read_byte(unsigned int addr)
65
{
66
    unsigned char data_byte = 0;
67
  
68
    //SPI start
69
    //SPI_SSOutputCmd(SPI2, ENABLE);
70
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 0);
71
72
    //0x03 is READ opcode
73
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
74
    SPI_I2S_SendData(SPI2, 0x03);    
75
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
76
77
    /* set address */
78
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
79
    SPI_I2S_SendData(SPI2, 0x00);    
80
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
81
    SPI_I2S_SendData(SPI2, (unsigned char)((addr & 0xFF00) >> 8));    
82
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
83
    SPI_I2S_SendData(SPI2, (unsigned char)(addr & 0x00FF));    
84
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
85
86
     
87
    //read data    
88
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
89
    data_byte = SPI_I2S_ReceiveData(SPI2); 
90
    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET);
91
92
    /* terminate spi data transfer */
93
    //SPI_SSOutputCmd(SPI2, DISABLE);
94
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 1);
95
  
96
    return data_byte;  
97
}
98
99
100
void test_fram(void) {
101
  unsigned char i;
102
103
  fram_spi_write_byte(0, 0x01);
104
  fram_spi_write_byte(1, 0x02);
105
  fram_spi_write_byte(2, 0x03);
106
  fram_spi_write_byte(3, 0x04);
107
  fram_spi_write_byte(4, 0x05);
108
109
  for(i=0;i<5;i++){
110
    global_rd_ram_buff[i] = fram_spi_read_byte(i);
111
  }
112
113
}

von holger (Gast)


Lesenswert?

> GPIO_InitTypeDef GPIO_InitStructure;
> // SPI2 SCK/MISO/MOSI @ PB13/PB14/PB15
> GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
> GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
> GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
> GPIO_Init(GPIOB, &GPIO_InitStructure);

MISO muss ein Input sein.

von Torsten A. (torsten_a)


Lesenswert?

Das habe ich auch schon geändert.
1
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_14; //MISO
2
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;

Es gibt ja einige Beispielprojekte in denen SPI verwendet wird - mal 
findet man MISO als Input und mal als GPIO_Mode_AF_PP. Scheint ja beides 
zu funktionieren??!


in der Funktion fram_spi_read_byte() habe ich jetzt auch das richtige 
Register-Flag "RXNE" eingesetzt
1
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET);
2
data_byte = SPI_I2S_ReceiveData(SPI2);

die NVIC_Configuration() lautet:
1
void NVIC_Configuration (void) {  
2
    
3
    NVIC_InitTypeDef NVIC_InitStructure;
4
5
    #ifdef  VECT_TAB_RAM  
6
      /* Set the Vector Table base location at 0x20000000 */ 
7
      NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
8
    #else  /* VECT_TAB_FLASH  */
9
      /* Set the Vector Table base location at 0x08000000 */ 
10
      NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
11
    #endif
12
13
      /* 1 bit for pre-emption priority, 3 bits for subpriority */
14
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
15
      
16
      // Configure and enable I2C2 interrupt -------------------------------------
17
      NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQChannel;
18
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
19
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
20
      NVIC_Init(&NVIC_InitStructure);
21
 /*         
22
      // Enable the USART3 Interrupt 
23
      NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQChannel;
24
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
25
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
26
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
27
      NVIC_Init(&NVIC_InitStructure);
28
  */
29
}
also auch kein USART3 kann hier Einfluss nehmen....


Hat jemand eine Idee was noch fehlerhaft ist? Die Funktionen 
fram_spi_write_byte() , fram_spi_read_byte() und
test_fram() habe ich so auch beim ATMEGA umgesetzt, bis auf die 
Anpassungen auf den STM MC:

while (SPI_I2S_GetFlagStatus(SPI2, xxxx)==RESET);
SPI_I2S_SendData(SPI2, xxx);

und da läuft es...  --aber ausschließen kann ich das natürlich auch 
nicht.



Gibt es einen Unterschied bzw. wo liegt der Unterschied bei der 
Verwendung von
1
//SPI start
2
SPI_SSOutputCmd(SPI2, ENABLE);
statt
1
//SPI start
2
GPIO_WriteBit(GPIOB, GPIO_Pin_12, 0);
????

von Torsten A. (torsten_a)


Lesenswert?

1
SPI_SSOutputCmd(SPI2, ENABLE);
is using by hardware NSS management

dazu muss SPI_NSS_Hard aktiviert werden:
1
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

von torsten_a (Gast)


Lesenswert?

Ich habe jetzt versucht das Statusregister vom FRAM auszulesen und das 
hat auch nicht funktioniert.

Bei allen Lese-Versuchen bekomme ich immer 255 zurück.

Habe auch schon testweise CPOL und CHPA geändert?

Hat jemand SPI Beispiele oder kann mir bei meinen Code weiterhelfen?

von fliflop (Gast)


Angehängte Dateien:

Lesenswert?

hallo,

bei mir funktioniert der folgende code einwandfrei.

von torsten_a (Gast)


Lesenswert?

Muss beim "STM32" beim Lesen auch ein DummyByte austakten???
1
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);SPI_I2S_SendData(SPI1,0xFF);

habe die Veränderungen übernommen geht aber nicht :(

Trotzdem Danke!!!

von fliflop (Gast)


Lesenswert?

hi,
ob das dummyread wirklich sein muss, weiß ich nicht, dass müsste man mal 
nachlesen falls es stört. werden überhaupt die richtigen pins 
konfiguriert, sind die spi pins nicht pa4-pa7 ?
gruß steffen

von holger (Gast)


Lesenswert?

>Muss beim "STM32" beim Lesen auch ein DummyByte austakten???

Wie soll das Datenbyte sonst vom Slave zum Master kommen?
Der Master gibt den Takt vor. Das kann er nur wenn er
Dummybytes sendet.

Bevor man den ARM verstanden hat kommentiert man natürlich
erst mal alles wichtige weg was man nicht versteht.

    SPI_I2S_SendData(SPI2, data_byte);
>>>>    //while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);

    /* terminate spi data transfer */
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 1);

CS wieder hochziehen bevor das Byte raus ist, ist keine
gute Idee.

von Stephan V. (Firma: FH Gelsenkirchen) (devilx)


Lesenswert?

Hallo

Bist du mittlerweile weiter gekommen?

von Tim R. (mugen)


Lesenswert?

Moin Moin,

auch wenn dieser Thread alt ist, dann schreibe ich doch hier einen 
kleinen Hinweis. Die Code-Zeile von fliflop beinhaltet einen Fehler in 
der TX Funktion:
1
  int tmp=0;
2
  SPI_I2S_SendData(SPI1,tx);
3
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);
4
  tmp=SPI_I2S_ReceiveData(SPI1);
5
  return tmp;

In den obigen Code wird zwar das byte/word richtig gesendet, allerdings 
wird nicht auf die Empfangsdaten gewartet. Bei einer sequentiellen SPI 
Übermittlung hat man dann immer einen zu alten Wert.

Richtig müsste sein:
1
  int tmp=0;
2
  SPI_I2S_SendData(SPI1,tx);
3
  while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);
4
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1);
5
  tmp=SPI_I2S_ReceiveData(SPI1);
6
  return tmp;

Diese Lösung beansprucht allerdings eine längere Verarbeitungszeit, da 
erst nach Aussendung die while-schleife verlassen wird.

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.