Forum: Mikrocontroller und Digitale Elektronik stm32f103 generelles Problem


von grundschüler (Gast)


Lesenswert?

1
....
2
3
  init_vs1053();
4
  vs_zl_buffer=0;
5
  vs_hellotest();
6
  wait;//1000ms
7
8
/**/
9
10
  SPI1->CR1 &=~(0b111<<3);//fast spi
11
  SPI1->CR1 |=  (3<<3);//fast spi
12
  
13
...

vs1053 wird initialisiert und spielt anschließend den vs1053-hello-code 
hörbar ab. Anschließend werden mp3-Dateien abgespielt.

Dann soll der spi-prescaler reduziert werden. Jetzt sind nicht nur die 
mp3s weg, auch der hellocode - obwohl zeitlich früher - wird nicht mehr 
abgespielt.

Wie kann das sein?

bei SPi2 geht es korrekt/presc==2, bei spi1 obiges Phänomen. Warum?

von Jim M. (turboj)


Lesenswert?

1
  SPI1->CR1 &=~(0b111<<3);//fast spi
2
  SPI1->CR1 |=  (3<<3);//fast spi

Das sind zwei Schreibzugriffe. Vermutlich knallt der erste, fass die 
doch mal zu einem Zugriff zusammen.

Achtung: Taktumschaltung während einer SPI Transaktion kann auch aus 
anderen Gründen knallen, z.B. weil interne Teiler/Zähler überlaufen. So 
könnten auch unschöne Glitches entstehen.

: Bearbeitet durch User
von grundschüler (Gast)


Lesenswert?

Jim M. schrieb:
> Das sind zwei Schreibzugriffe.

Erstmal Danke für den Hinweis.

???
- vorhandener Wert in Bit-Folge soll geändert werden:
1. Bit-Folge auf Null setzen
2. Bit-Folge auf gewünschten Wert setzen

Wie schaffst du das in einem Schreibzugriff?

Das oben beeschriebene Problem ist geklärt. Lag daran dass die #defines 
zur Umstellung spi1/2 fehlerhaft waren.
 Spi2 läuft mit presc=clk/2 Spi1 nur mit clk/16. Da anderer Bus wäre 
logisch mindestens mit clk/4.

Ich werde das ganze jetzt mit dem la untersuchen.

von Jim M. (turboj)


Lesenswert?

grundschüler schrieb:
> - vorhandener Wert in Bit-Folge soll geändert werden:
> 1. Bit-Folge auf Null setzen
> 2. Bit-Folge auf gewünschten Wert setzen
>
> Wie schaffst du das in einem Schreibzugriff?

Trivialste Grundlagen der Programmierung:
1
 
2
SPI1->CR1 = (SPI1->CR1 & ~(7<<3)) | (3<<3);

Ein einzelner Read-Modify-Write Zyklus.

von grundschüler (Gast)


Lesenswert?

Jim M. schrieb:


guter Hinweis, danke

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Jim M. schrieb:
> Trivialste Grundlagen der Programmierung:
>
> SPI1->CR1 = (SPI1->CR1 & ~(7<<3)) | (3<<3);
>
> Ein einzelner Read-Modify-Write Zyklus.

Das das als einzelner Zyklus implementiert wird, ist durch nichts 
garantiert. Ebenso werden die meisten Compiler die Formulierung in zwei 
Zeilen auch nichts anderes implementieren.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

grundschüler schrieb:
> 0b111

Binaerziffern sind nicht im C Sprachumfang enthalten...

von grundschüler (Gast)


Lesenswert?

Uwe B. schrieb:
> 0b111
> Binaerziffern sind nicht im C Sprachumfang enthalten...

sicher?
da meckert nichts und es funktioniert auch...

von Uwe (Gast)


Lesenswert?

Uwe B. schrieb:
> Das das als einzelner Zyklus implementiert wird, ist durch nichts
> garantiert.

Doch, das ist dadurch garantiert, dass die gelesene/geschriebene 
Speicheradresse als volatile deklariert ist. Der Compiler muss hier 
genau einen Lese- und genau einen Schreib-Zugriff erzeugen.

von Holger (Gast)


Lesenswert?

grundschüler schrieb:
> sicher?
> da meckert nichts und es funktioniert auch...

Meine Lieblingsargumentation... Gleich dahinter kommen noch folgende:

- "gestern ging es aber noch!"
- "ich habe daran NICHTS gemacht/verändert"
- "so hat es aber bisher IMMER funktioniert"
- "wer braucht Abblockkondensatoren? Geht doch auch ohne!"
- "EAGLE ist MINDESTENS so gut wie Altium. Wenn nicht sogar besser!"
- usw., gibt noch eine ganze Menge

Übrigens:

Was du meinst ist folgendes: "Mein Compiler schluckt das weil GCC auch 
Binärzahlen versteht. Da ich aber ein guter Programmierer bin, schreibe 
ich meinen Code so, dass compilerspezifische Besonderheiten darin nicht 
unnötig vorkommen" :-)

--> in C verwendet man HEX. Ist ja eigentlich auch nichts anderes als 
Binär wenn man jeweils 4 Stellen zusammenfasst.

wenn man UNBEDINGT binär haben möchte (ich programmiere seit über 20 
Jahren C, habe es noch nie wirklich gebraucht):
1
#define B(x) ( \
2
  0##x >>  0 & 0001 | \
3
  0##x >>  2 & 0002 | \
4
  0##x >>  4 & 0004 | \
5
  0##x >>  6 & 0010 | \
6
  0##x >>  8 & 0020 | \
7
  0##x >> 10 & 0040 | \
8
  0##x >> 12 & 0100 | \
9
  0##x >> 14 & 0200 )

Uwe schrieb:
> Doch, das ist dadurch garantiert, dass die gelesene/geschriebene
> Speicheradresse als volatile deklariert ist. Der Compiler muss hier
> genau einen Lese- und genau einen Schreib-Zugriff erzeugen.

Sehe ich genauso.

von grundschüler (Gast)


Lesenswert?

wieder was gelernt.mein #define:
1
#define spi2_presc_0_to_7(x) do{SPI2->CR1=(SPI2->CR1 & ~(0x07<<3))|(x<<3);}while(0)

Holger schrieb:
> #define B(x) ( \
>   0##x >>  0 & 0001 | \

das ist dann vermutlich als

> #define 0b(x) ( \
...

irgenwo im Programm vorhanden

von Jim M. (turboj)


Lesenswert?

Uwe B. schrieb:
> Das das als einzelner Zyklus implementiert wird, ist durch nichts
> garantiert. Ebenso werden die meisten Compiler die Formulierung in zwei
> Zeilen auch nichts anderes implementieren.

Das sind Register und die sind volatile. Damit macht der Compiler 
jeden Lese- und Schreibzugriff ganz genau so wie Du ihn hinschreibst. 
Dies wird spätestens durch den GCC garantiert.

Deshalb wird der GCC bei der Zwei-Zeilen-Version immer zwei 
Schreibzugriffe machen, was bei Hardware Registern unerwünschte 
Nebenwirkungen haben kann.

Schau Dir selbst mal das Disassembly an.

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.