Forum: Mikrocontroller und Digitale Elektronik Probleme mit SPI - STM32F2


von EmbeddedUser (Gast)


Lesenswert?

Hallo,

ich habe folgendes Problem mit der SPI Kommunikation auf dem STM32F2.
Um von einem Flashspeicher die ID auszulesen führe ich folgende 
Funktionen aus.
1
    // Read ID
2
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
3
    SPI_I2S_SendData(SPIx, 0xAB);
4
5
    // Dummy byte
6
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
7
    SPI_I2S_SendData(SPIx, 0x0);
8
9
    // Dummy byte
10
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
11
    SPI_I2S_SendData(SPIx, 0x0);
12
13
    // Dummy byte
14
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
15
    SPI_I2S_SendData(SPIx, 0x0);
16
17
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
18
    SPI_I2S_SendData(SPIx, 0x0);
19
20
    // Read byte
21
    while ( SPI_I2S_GetFlagStatus( SPIx, SPI_I2S_FLAG_RXNE ) == RESET );
22
    ReadID = SPI_I2S_ReceiveData(SPIx);

Beim ersten mal erscheint nicht die gewünscht ID. Beim zweiten mal wird 
die korrekte ID in die Variable ReadID abgelegt.

Was müsste getan werden, damit beim ersten mal die ID in der Variable 
abgelegt wird ?

In der Initialisierungsroutine habe ich auch schon folgendes getestet.
1
    //Dummy-Read zum Entleeren des Rx-Buffers
2
    if(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == SET)
3
      SPI_I2S_ReceiveData(SPIx);

Der Fehler tritt nach wie vor auf.

von EmbeddedUser (Gast)


Lesenswert?

Hab schon alles ausprobiert. Es müsste doch dafür eine Lösung geben.

von wurst (Gast)


Lesenswert?

Was für einen Flashspeicher benutzt du denn genau?
Braucht der vielleicht eine gewisse Zeit oder bestimmte Anzahl an Takten 
auf dem CLK-Signal zum Initialisieren?

von EmbeddedUser (Gast)


Lesenswert?

Der STM32 Mikrocontroller soll mit dem EPCS Flash Controller via SPI 
kommunizieren.

von Tobias S. (tryan)


Lesenswert?

Hallo EmbeddedUser,

ich habe das so gemacht:
1
uint8_t spi2_putc(uint16_t data) {
2
  FPGA_DESELECT();
3
  // make sure the transmit buffer is free
4
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
5
  SPI_I2S_SendData(SPI2, data);
6
  // and then be sure it has been sent over the wire
7
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
8
  data=SPI_I2S_ReceiveData(SPI2);
9
10
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
11
  SPI_I2S_SendData(SPI2, 0);
12
  // and then be sure it has been sent over the wire
13
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
14
  data=SPI_I2S_ReceiveData(SPI2);
15
16
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
17
  SPI_I2S_SendData(SPI2, 0);
18
  // and then be sure it has been sent over the wire
19
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
20
  data=SPI_I2S_ReceiveData(SPI2);
21
22
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
23
  SPI_I2S_SendData(SPI2, 0);
24
  // and then be sure it has been sent over the wire
25
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
26
  data=SPI_I2S_ReceiveData(SPI2);
27
28
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
29
  SPI_I2S_SendData(SPI2, 0);
30
  // and then be sure it has been sent over the wire
31
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
32
  data=SPI_I2S_ReceiveData(SPI2);
33
34
35
  FPGA_SELECT();
36
  return data;

vielleicht hilft es dir weiter...

viele grüße Tobias

von Tobias S. (tryan)


Lesenswert?

So... hab es nochmal ein wenig "hübscher" gestaltet.
1
uint8_t spi_Read_ID(uint8_t data) {
2
  EPCS_SELECT();
3
4
  // Send Operation Code
5
  // make sure the transmit buffer is free
6
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
7
  SPI_I2S_SendData(SPI2, data);
8
  // and then be sure it has been sent over the wire
9
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
10
  data=SPI_I2S_ReceiveData(SPI2);
11
12
  // Send 3 Dummy bytes and 1 to Read the ID
13
  for (uint8_t i=0; i!=4; i++){
14
  // make sure the transmit buffer is free
15
  while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
16
  SPI_I2S_SendData(SPI2, 0);
17
  // and then be sure it has been sent over the wire
18
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
19
  data=SPI_I2S_ReceiveData(SPI2);
20
  }
21
22
  EPCS_DESELECT();
23
  return data;
24
}

viele grüße

von EmbeddedUser (Gast)


Lesenswert?

Guten Morgen Tobias S.,

vielen Dank für deine Beiträge.

Mit welcher Datei von Quartus || wird der EPCS Flash Controller 
beschrieben ? Ist es womöglich die Datei mit der Endung jic ?
Ab welcher Adresse soll der EPCS Flash Controller beschrieben werden ?

von Tobias S. (tryan)


Lesenswert?

Hallo EmbeddedUser,

hmm... wenn du das EPCS wirklich seriell mit einen µC beschreiben 
möchtest. bleibt eigentlich "nur" das "Raw binare File". Dieses File 
muss 1:1 ab der Adresse 0x000000 in das EPCS geladen werden.

Das "jic"-File wäre JTag.

Viele Grüße Tobias

von EmbeddedUser (Gast)


Lesenswert?

Hallo Tobias S.,

ich kann in dem Projekt kein Bin-File sehen. Muss ich dieses File mit 
einem zusätzlichen Tool erzeugen ?

Ich habe bezüglich dem EPCS Flash Controller noch eine weiteres Problem.
Wie beschreibst du die Sectoren ? Das seitenweise (256 Bytes) 
beschreiben des EPCS Flash Controller funktioniert soweit.

von EmbeddedUser (Gast)


Lesenswert?

Ich muss in Quartus || das *.rbf File erzeugen. Der komplette Inhalt 
dieser Datei muss ab der Adresse 0 im EPCS Flash kopiert werden.

von EmbeddedUser (Gast)


Lesenswert?

Oder muss vielleicht doch das *.rpd File benutzt werden ?

von Tobias S. (tryan)


Lesenswert?

Ja genau das *.rpb meine ich...

von EmbeddedUser (Gast)


Lesenswert?

Die Write_Page Funktion sieht bei mir so aus:
1
int Write_Page(char *data, int len, unsigned long addr)
2
{
3
    ChipSEL();
4
5
    SendOpCode(0x02); // Operation Code = 0x02
6
7
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
8
    SPI_I2S_SendData(SPIx, (unsigned char)(addr>>16));
9
10
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
11
    SPI_I2S_SendData(SPIx, (unsigned char)(addr>>8));
12
13
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
14
    SPI_I2S_SendData(SPIx, (unsigned char)(addr));
15
16
    // Data
17
    for(int i=0; i<Length; i++)
18
    {
19
      while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
20
      SPI_I2S_SendData(SPIx, *Data);
21
      Data++;
22
    }
23
24
    Sleep(7); // delay time = 7 ms
25
26
    ChipDESEL();
27
28
    return 1;
29
}

Bevor ich diese Funktion ausführe wird ein Write_Enable ausgeführt. Nach 
Write_Page wird ein Write_Disable durchgeführt. Sobald ich einen Sektor 
beschreiben möchte (256 Pages) wird das Debugging automatisch 
unterbrochen. Ich kann den Fehler nicht finden.

von EmbeddedUser (Gast)


Lesenswert?

Ja meinst du nun das *.rpd oder das *.rbf File. Das *.rpd File kann so 
wie es aussieht nur mit dem Tool SRunner benutzt werden. Also ich meine 
es müsste das *.rbf (Raw binary file) File sein

von Tobias S. (tryan)


Lesenswert?

hmm... was genau meinst du mit "Debugging automatisch
unterbrochen"

Hast du es schon geschafft ein beschriebenes EPCS auszulesen?

von Tobias S. (tryan)


Lesenswert?

Ja sorry zu lange her. Ich meine das *.rbf

von Tobias S. (tryan)


Lesenswert?

Du darfst max.256 Bytes pro Schreibzyklus schreiben. Danach muss die 
Adresse erhöht werden. Und dann darf ein neuer Schreibzyklus beginnen. 
Siehe Seite 25 im EPCS datasheet

von EmbeddedUser (Gast)


Lesenswert?

Ja das mache ich ja bereits. Am Anfang lösche ich den ganzen Speicher 
mit Erase_Bulk.

von Tobias S. (tryan)


Lesenswert?

Okay, aber er schreibt nur die ersten 256 Bytes?

von EmbeddedUser (Gast)


Lesenswert?

Wie müsste der genauere Ablauf aussehen, wenn ein Sektor beschrieben 
werden soll ? Irgendwas stimmt ja bei mir nicht ganz. Der Debugger bzw. 
Mikrocontroller hängt sich bei mir auf.

von Tobias S. (tryan)


Lesenswert?

Wenn sich der µC aufhängt klingt es eher, dass er in eine while scheife 
springt und nicht mehr raus kommt... Wartest du vielleicht auf einen 
bestimmten zustand von dem EPCS?

von EmbeddedUser (Gast)


Lesenswert?

Ich warte bevor ich ein Byte versende ob das Flag "SPI_I2S_FLAG_TXE" 
wieder zurückgesetzt wird.
1
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);

Wenn ich eine Page beschreibe dann habe ich keine Probleme.

von EmbeddedUser (Gast)


Lesenswert?

Wie hast du das gelöst ?

von Tobias S. (tryan)


Lesenswert?

Poste bitte den Code in dem du die Adresse hoch zählst

Viele Grüße Tobias

von EmbeddedUser (Gast)


Lesenswert?

Hier ist ein Auszug aus meiner Applikation:

1
void main(void)
2
{  
3
  Time = Get_Time();
4
5
  id = ReadID();
6
  _delay();
7
8
  for(int i=0; i<256; i++)
9
  {
10
    EpcsData[i] = 0xAA;
11
  }
12
  
13
  Write_Enable();
14
  _delay();
15
  Erase_Bulk();
16
  _delay();
17
  Write_Disable();
18
  _delay();
19
20
  while (1)
21
  {
22
    if ( Time_Passed(&Time) )
23
    {
24
      for(int i = 256; i<256; i++)
25
      {
26
        Write_Enable();
27
        Sleep(5); // 5 ms
28
        Write_Page(EpcsData,256,i*0x00100); // 1. Paramter=Daten, 2. Paramter=Länge der Daten, 3. Parameter= Adresse
29
        Sleep(5); // 5 ms
30
        WriteDisable();
31
        _delay();
32
      }
33
      // 1. Paramter=Daten und 2. Parameter=Länge (werden noch nicht an die Applikation weitergereicht), 3. Parameter= Adresse
34
      Read_Page(0,0,0x00500);  
35
      _delay();
36
      
37
      Time = Get_Ahead_Time(1000); // 1 sec  
38
    }
39
  }
40
}

von EmbeddedUser (Gast)


Angehängte Dateien:

Lesenswert?

Folgendes habe ich festellen können. Wenn ich in der "Write_Page" 
Funktion die komplette for Schleife entferne, dann hängt sich der 
Mikrocontroller nicht auf.

Im Anhang befindet sich einen Auszug von der IAR JLink Debugger 
Fehlermeldung.

von Tobias S. (tryan)


Lesenswert?

hmm die länge darf max. 255 sein. Das "0" Byte nicht vergessen mit zu 
zählen...

Warum fängst du erst an der Adresse 0x500 an auszulesen?

Wie groß ist deine "EpcsData"?

Viele grüße Tobias

von EmbeddedUser (Gast)


Lesenswert?

Guten Morgen Tobias S.,

EpcsData ist 256 Byte groß. Die for Schleife ist natürlich falsch.
Die for Schleife sieht natürlich so aus:
1
for(int i = 0; i<256; i++)
2
{
3
 ....
4
}

von EmbeddedUser (Gast)


Lesenswert?

Und mit der Funktion Read_Page möchte ich nur die Page ab der Adresse 
0x00500 auslesen.
1
Read_Page(0,0,0x00500);

von EmbeddedUser (Gast)


Lesenswert?

Es muss an dieser for Schleife liegen. Wie kann mit dem STM32 256 Bytes 
per SPI versendet werden, ohne dass der Mikrocontroller sich aufhängt ? 
Es muss doch möglich sein. Ich habe soeben auch die Interrupt Variante 
ausprobiert. Da passiert es auch.

1
for(int i=0; i<256; i++)
2
{
3
  while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE)==RESET);
4
  SPI_I2S_SendData(SPIx, DATEN_BYTE);
5
}

von Tobias S. (tryan)


Lesenswert?

Anbei mein Code, aber ich bin auch noch am Programmieren... Also keine 
Garantie ;)
1
void spi_Write_Page(char *data, uint32_t adr){
2
  char  Write_in_Prog = 3;
3
4
  spi_Write(1);
5
  EPCS_SELECT();
6
  spi_send_Bytes(0x02,0,0);
7
  spi_send_Bytes(adr>>16,0,0);
8
  spi_send_Bytes(adr>>8,0,0);
9
  spi_send_Bytes(adr,0,0);
10
11
  for(int i=0; i!=0x100; i++){
12
    // make sure the transmit buffer is free
13
       while (SPI_I2S_GetFlagStatus(SPI2_PORT, SPI_I2S_FLAG_TXE) == RESET);
14
       SPI_I2S_SendData(SPI2, *data);
15
       // and then be sure it has been sent over the wire
16
       while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
17
       data++;
18
    }
19
  EPCS_DESELECT();
20
21
  while (Write_in_Prog==3){
22
    Write_in_Prog=spi_Read_Status();
23
    }
24
}
25
26
void spi_Write_Sektor(char *data, char len){
27
  for (uint16_t i=0; i!=len; i++){
28
    spi_Write_Page(data,i*0x00100);
29
    data=data+0x100;
30
    }
31
}

von Klaus (Gast)


Lesenswert?

@EmbeddedUser

In deiner WritePage Funktion fehlt die Abfrage, ob das Flash ready ist. 
Dazu das Status-Register auslesen und das entsprechende Bit auswerten. 
Am einfachsten ist es, diese Abfrage vor jedem Löschen, Schreiben und 
Lesen zu machen, kostet nur so eine µs. Und die ganzen delays raus aus 
dem Programm.

MfG Klaus

von EmbeddedUser (Gast)


Lesenswert?

Wo müsste genau müsste in der for Schleife die Abfrage erfolgen und 
welches Bit ? Damit auf den Speciher geschrieben werden kann, müsste 
laut Datenblatt das Bit 0 vom Status Register 0 sein.

von EmbeddedUser (Gast)


Lesenswert?

Es hängt definitiv an dieser blöden for Schleife.

von Klaus (Gast)


Lesenswert?

EmbeddedUser schrieb:
> Damit auf den Speciher geschrieben werden kann, müsste
> laut Datenblatt das Bit 0 vom Status Register 0 sein.

Ich benutze eine andere CPU, die Bedeutung deiner SPI Register kenne ich 
nicht.

Ich mache die Abläufe so:

Vor jedem Löschen, Schreiben oder Lesen warte ich, bis Bit 0 vom Status 
Register des Flashs 0 ist.

Das kann man so machen: READ STATUS Kommando senden und ein Byte 
zurücklesen. Dann CS wieder auf 1. Bit 0 von dem Byte auswerten und 
nochmal von vorne, wenn nicht 0;

Oder CS auf low, READ STATUS senden und solage Bytes lesen, bis Bit 0 
nicht mehr gesetzt ist. Dann CS wieder auf high.

Feiglinge setzen noch einen Loopcounter als Timeout darüber ;-) kann 
aber beim Löschen ganz schön lange dauern (500ms pro Sektor wenn ich 
mich recht erinnere)

Danach kann man alles machen, z.B. READ und Startadresse ausgeben (4 
Byte) und lesen bis der Flash zuende ist. Delays sind nirgenwo 
erforderlich, die Bits bekommt man auch mit 25 MHz ohne Pause.

So macht das das FPGA, 0x03 0x00 0x00 0x00 ausgeben und Bytes eintakten 
bis fertig.

MfG Klaus

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.