Forum: Mikrocontroller und Digitale Elektronik STM32F205 cached Register obwohl er keine Caches hat


von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Ein interessantes Problem ist mir gestern aufgefallen.

Ab und zu bleibt der I2C hängen bei der while Schleife hier:
1
uint8_t i2c_rep_start(unsigned int i2c_base, uint8_t addr){
2
3
  volatile struct i2c * const i2c = (volatile struct i2c *)i2c_base;
4
  
5
  while(i2c->SR1 & SR1_BTF);
6
  return starting(i2c_base, addr);
7
}

Mit dem volatile stimmt eigentlich alles und es ist mit -O0 compiliert 
zum debuggen.

Im Debugger sehe ich, dass der CPU Kern SR1 als 0x84 ausließt und im 
Register vorhält.
0x80 für TX not empty und eben 0x04 für BTF.
Jetzt dacht ich, dass dann eben der I2C Bus klemmt, kann ja mal 
vorkommen.

ABER!

Wenn ich jetzt im Debugger den Registerwatch öffne, dann steht da 0x80 
beim SR1.
Jetzt kommts noch besser: wenn ich jetzt nochmal durchsteppe, dann ließt 
er auch 0x80 aus und macht weiter aufm I2C Bus.

Hat da jemand ne Idee?
In den Erratas stehen zwar andere gruselige Dinge, aber nicht dieses 
Problem.

Ich brauch nen Exorzisten!

von Gerd E. (robberknight)


Lesenswert?

Mw E. schrieb:
> Wenn ich jetzt im Debugger den Registerwatch öffne, dann steht da 0x80
> beim SR1.

Ich würde dem Debugger an der Stelle nicht unbedingt vertrauen. Wenn der 
Debugger Register auslesen will, kann es zu einigen lustigen Effekten 
kommen die Fehler vorspiegeln wo gar keine sind.

Lies die Register in Deinem Code aus und speichere sie in einem Puffer 
im RAM. Dann lass den Code mit normaler Geschwindigkeit ohne 
Unterbrechung durch den Debugger laufen. Setze Deinen Breakpoint auf 
eine spätere Stelle im Code und schau Dir dann den Inhalt von Deinem 
Puffer an.

von Jim M. (turboj)


Lesenswert?

Mw E. schrieb:
> Mit dem volatile stimmt eigentlich alles und es ist mit -O0 compiliert
> zum debuggen.

Zeig mir wie "struct i2c" definiert ist  und ich zeige Dir (vermutlich) 
Deinen Fehler.

Die metrische Tonne Casts bringt hier nix IMHO.

von (prx) A. K. (prx)


Lesenswert?

Der Asm-Code dieses Codes?

Was soll es eigentlich bringen, die Adresse als uint zu übergeben und 
überall zu casten? Statt den Parameter gleich richtig zu definieren. 
Ganz allgemein würde ich empfehlen, Casts möglichst sparsam einzusetzen.

: Bearbeitet durch User
von foobar (Gast)


Lesenswert?

Sicher, dass der Test (warten auf 0) richtig rum ist?

von M. Н. (Gast)


Lesenswert?

Kann auch ein Glitch in der Hardware sein. Hatte sowas beim SDIO Modul 
schon. Habe das Status Register in einer Dauerschleife gepollt.
Mit -O0 lief alles. Sobald man den Code auf -O3 gestellt hat, hat er 
immer nen CRC Fehler angezeigt, obwohl die Kommunikation aufm 
Logicanalyzer korrekt aussah...

Ich musste zuerst darauf warten, bis das Kommando fertig war, und dann 
die Status Flags lesen. Die Flags flackern wohl während des Sendens ab 
und zu hin und her. Das war eine Sucherei.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Vielen Dank für die Antworten, leider komme ich erst jetzt zum 
Antworten.

foobar schrieb:
> Sicher, dass der Test (warten auf 0) richtig rum ist?
Genau das wars, BTF soll ja nicht gesetzt sein.
Man sollt eben nicht 1 Uhr morgens noch Coden.

Gerd E. schrieb:
> Mw E. schrieb:
>> Wenn ich jetzt im Debugger den Registerwatch öffne, dann steht da 0x80
>> beim SR1.
>
> Ich würde dem Debugger an der Stelle nicht unbedingt vertrauen. Wenn der
> Debugger Register auslesen will, kann es zu einigen lustigen Effekten
> kommen die Fehler vorspiegeln wo gar keine sind.

Registerlesen beim I2C kann ja durchaus an der Statemachine rumspielen 
(zB SR2 lesen resetet das ADDR Bit).
An der Stelle ist da zwar nichts im DaBla Dokumentiert, aber wer weis 
was ST da ins Silizium gegossen hat.
Jedenfalls wird das auslesen der Register an der Statemachine gespielt 
haben zB durch das DataRegister lesen und schon hats das BTF geflippt.
Wieso hat der PeripheralBus eigentlich keine Leitung für "das ist jetzt 
eine Registerwatch Debugauslesung, bitte behalte die internen States der 
Statemachine bei" ?! Wär doch mal ne gute Neuerung.

Jim M. schrieb:
> Die metrische Tonne Casts bringt hier nix IMHO.
Verzweiflungstat ;)
Ein volatile cast würde reichen.

Jim M. schrieb:
> Zeig mir wie "struct i2c" definiert ist  und ich zeige Dir (vermutlich)
> Deinen Fehler.
Bittesehr:
1
struct i2c {
2
  unsigned int CR1;
3
  unsigned int CR2;
4
  unsigned int OAR1;
5
  unsigned int OAR2;
6
  unsigned int DR;
7
  unsigned int SR1;
8
  unsigned int SR2;
9
  unsigned int CCR;
10
  unsigned int TRISE;
11
};
es bringt übrigens nichts dort volatile vor das struct zu schreiben, 
dann meckert der Compiler zurecht mit:
"periph/i2c_regdefs.h:14:1: warning: useless type qualifier in empty 
declaration"
Erst durch das Casten wird das volatile, ist das struct volatile, so 
auch seine Inhalte.

A. K. schrieb:
> Was soll es eigentlich bringen, die Adresse als uint zu übergeben und
> überall zu casten? Statt den Parameter gleich richtig zu definieren.
> Ganz allgemein würde ich empfehlen, Casts möglichst sparsam einzusetzen.

Es gibt ja nicht nur den einen I2C, also übergeb ich die Basisadresse 
des I2C und lege dann das struct über die Register.
Da könnt man jetzt nochn enum nehmen.
Direkt nen Pointer aufn struct übergeben könnt man auch, aber dann muss 
ich eben beim anlegen auch schon rumcasten.
Oder wie würdest du das machen?

Jedenfalls tut das jetzt, ab und zu gibts maln NACK nachm write, aber 
das kann ja immermal vorkommen beim I2C wenn der Slave grade kein Bock 
hat zu Antworten.

von Jim M. (turboj)


Lesenswert?

Mw E. schrieb:
> Erst durch das Casten wird das volatile, ist das struct volatile, so
> auch seine Inhalte.

Zuviele Casts. Kann man weglassen, wenn man das volatile in das Struct 
packt:
1
struct i2c {
2
  volatile unsigned int CR1;
3
  volatile unsigned int CR2;
4
  volatile unsigned int OAR1;
5
  volatile unsigned int OAR2;
6
  volatile unsigned int DR;
7
  volatile unsigned int SR1;
8
  volatile unsigned int SR2;
9
  volatile unsigned int CCR;
10
  volatile unsigned int TRISE;
11
};

Erst dann macht der Compiler bei "normalen" Zugriffen alles richtig. So 
machen das alle OEM Header die ich hier finde.

Ich würde die "unsigned int" dann noch durch uint32_t ersetzen.

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.