Forum: Mikrocontroller und Digitale Elektronik Berechnung auf PC und auf Controller unterschiedlich


von H. F. (hafisch)


Lesenswert?

Hallo zusammen

Ich habe ein komisches Phänomen auf welches ich keine Antwort finde.

Es geht um eine Berechnung welche ich zur Ansteuerung eines 
PWM-Controllers mittels eine Interrupt-Timers mache.

Nun habe ich eine Berechnungszeile, welche mir die Anzahl Überläufe des 
Timers berechnet. Ist die Anzahl Überläufe erreicht, setze ich den 
PWM-Ausgang.

Dabei verwende ich folgende Variablen:
1
// general data
2
double dPwm_freq = 1975;                                // requested frequency
3
const unsigned long ulCycleTime = 125;                // cycle time in nano seconds
4
const unsigned long ulCpuFrequency = 8000000;         // Cpu freqnecy in Hz
5
6
//pwm data
7
const unsigned int iPrescaler = 1;                    // prescaler of timer0
8
const unsigned int nTimer = 256;                     // resolution of timer0
9
volatile unsigned long ulTimeOvfl;                   // Time for Overflow of timer0 in nano seconds
10
volatile unsigned long ulTmrOvflCntr = 0;            // counter for number of overflows
11
volatile unsigned long ulPwm_EndCntr = 0;            // end value until time of pwm-cycle has reached

Die Berechnung selbst im Code sieht dann folgendermassen aus:
1
// calculate pwm data
2
ulTimeOvfl = (ulCycleTime * 256 *iPrescaler);
3
ulPwm_EndCntr = ((1000000000)/(dPwm_freq*ulTimeOvfl*2));

Wenn ich dies nun in einem C-Projekt in Eclipse laufen lasse, dann 
funktioniert diese Berechnung tadellos. Ich kann danach den korrekten 
Wert in der Konsole ausgeben.

Sobald ich dies jedoch auf den Controller (Attiny85) lade, dann bleibt 
die Applikation an dieser Berechnung hängen.

An was kann das liegen? Was ist Unterschiedlich bei der Berechnung auf 
dem PC und auf dem Controller?

Liegt das daran, dass es sich beim Controller um eine 8bit CPU handelt, 
bei meinem PC jedoch um einen 32bit Prozessor?
Wie kann ich dies umgehen?

Danke für die Antworten und einen schönen Abend wünscht
hafisch

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

H. Fisch schrieb:
> Sobald ich dies jedoch auf den Controller (Attiny85) lade, dann bleibt
> die Applikation an dieser Berechnung hängen.

Wie kommst Du darauf?

H. Fisch schrieb:
> Was ist Unterschiedlich bei der Berechnung auf
> dem PC und auf dem Controller?

Die Größe des Stack.
Ich schätze, dein Stack ruscht in den Variablen-Bereich und wird 
überschrieben. Dass der Controller scheinbar genau an dieser Berechnung 
hängen bleibt, hat nichts mit der Berechnung selber zu tun, sondern ist 
eher Zufall.

Nur so eine Idee.

von Kaj (Gast)


Lesenswert?

H. Fisch schrieb:
> Liegt das daran, dass es sich beim Controller um eine 8bit CPU handelt,
> bei meinem PC jedoch um einen 32bit Prozessor?
> Wie kann ich dies umgehen?
Einen 32bit-controller nehmen, z.B. Atmel SAM3X8E (Arduino Due, 
Cortex-M3) oder einen STM32F4 (Cortex-M4), was aber nichts mit deinem 
Problem zu tun hat.

Bei mir kommt aber sowohl im Atmel Studio mit dem Simulator, als auch in 
Visual Studio jeweils 7 raus...

Ich werf mal noch die Begriffe "Wertebereiche" und "Overflow" in den 
raum.

Ein Stück Code mit dem es auf jedenfall gehen sollte:
1
#include <stdint.h>
2
3
int main(void)
4
{
5
  uint16_t dPwm_freq = 1975;
6
  uint8_t ulCycleTime = 125;
7
8
  uint8_t iPrescaler = 1;
9
  uint16_t ulTimeOvfl;
10
  uint16_t ulPwm_EndCntr = 0;
11
  
12
  
13
  ulTimeOvfl = ulCycleTime * 256 * iPrescaler;
14
  ulPwm_EndCntr = 1000000000 / ( (uint32_t)dPwm_freq * ulTimeOvfl * 2 );
15
                                  ^^^^^^^^
16
}
Ungenutze Variablen hab ich mal entfernt, Compiler Optimierung ist 
ausgeschaltet.
Der Cast ist genaugenommen unnötig, da in deiner Version die Variable 
dPwm_freq vom Typ double und damit mind. 4Byte groß ist.
1
#include <stdint.h>
2
3
int main(void)
4
{
5
  double dPwm_freq = 1975;
6
  uint8_t ulCycleTime = 125;
7
8
  uint8_t iPrescaler = 1;
9
  uint16_t ulTimeOvfl;
10
  uint16_t ulPwm_EndCntr = 0;
11
  
12
  
13
  ulTimeOvfl = ulCycleTime * 256 * iPrescaler;
14
  ulPwm_EndCntr = 1000000000 / ( dPwm_freq * ulTimeOvfl * 2 );
15
16
}
Funktionier im AVR-Simulator genau so gut, kommt auch 7 raus.

von Karl H. (kbuchegg)


Lesenswert?

H. Fisch schrieb:

Warum versuchst du nicht, dem Compiler die Berechnung anzuhängen?
Oder musst du die Frequenz zur Laufzeit ändern können?

> double dPwm_freq = 1975;                                // requested
> frequency

double ist zwar nett, ist aber auf einem AVR effektiv nur ein float. Mit 
allen Problemen, wie etwa dem, dass du nur 5 bis 6 signifikante Stellen 
hast. Im Gegensatz zu den 15 bei echten double auf einem PC.

von H. F. (hafisch)


Lesenswert?

Hallo danke für die schnelle Antwort

Ich habe nun herausgefunden dass es am Datentyp des Divisors lag, 
welcher als double definiert war.
Definiere ich diesen als float funktioniert alles.

Nun habe ich jedoch noch ein kleines Problem.

Ich habe ein Array mit einigen Elementen welche ich in einer Schleife 
abfrage.

Nun habe ich einen Zugriff auf das Array innerhalb der Schleife mit 
folgendem Effekt.

Ist die Arrayindexvariable innerhalb der SChleife definiert, 
funktioniert der Zugriff. Verwende ich jedoch den Schleifenindex oder 
eine ausserhalb definierte Variable, so funktioniert der Zugriff nicht.

folgendes Beispiel funktioniert
1
for (iAtBeat=0; iAtBeat<uiNumOfBeats; iAtBeat++){
2
3
  int iTemp=0;
4
  fPwm_freq = aMySongNotes[iTemp];
5
6
}

folgendes Beispiel funktioniert nicht
1
int iTemp=0;
2
for (iAtBeat=0; iAtBeat<uiNumOfBeats; iAtBeat++){
3
4
  fPwm_freq = aMySongNotes[iTemp];
5
6
}

auch dieses Beispiel funktioniert nicht
1
for (iAtBeat=0; iAtBeat<uiNumOfBeats; iAtBeat++){
2
3
  fPwm_freq = aMySongNotes[iAtBeat];
4
5
}

Ist dies erklärbar? Wenn ja, wie?

Danke und Gruss
hafisch

von Karl H. (kbuchegg)


Lesenswert?

H. Fisch schrieb:

> Ist dies erklärbar?

nein.


Iregendwas ist in deinem Code anscheinend mächtig faul. Und dieses 
'irgendwas' muss mit dieser Berechnung noch nicht mal in Zusammenhang 
stehen.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

H. Fisch schrieb:
> folgendes Beispiel funktioniert
>
1
for (iAtBeat=0; iAtBeat<uiNumOfBeats; iAtBeat++){
2
> 
3
>   int iTemp=0;
4
>   fPwm_freq = aMySongNotes[iTemp];
5
> 
6
> }
 Was soll da funktionieren ?
 Ändert sich ja nichts.

H. Fisch schrieb:
> folgendes Beispiel funktioniert nicht
>
1
int iTemp=0;
2
> for (iAtBeat=0; iAtBeat<uiNumOfBeats; iAtBeat++){
3
> 
4
>   fPwm_freq = aMySongNotes[iTemp];
5
> 
6
> }
 Was soll hier nicht funktionieren ?
 Ändert sich genauso wenig.

H. Fisch schrieb:
> auch dieses Beispiel funktioniert nicht
>
1
for (iAtBeat=0; iAtBeat<uiNumOfBeats; iAtBeat++){
2
> 
3
>   fPwm_freq = aMySongNotes[iAtBeat];
4
> 
5
> }

 Wo ist uiNumOfBeats definiert ?
 Einen Wert zugewiesen ?

: Bearbeitet durch User
von H. F. (hafisch)


Lesenswert?

Hallo zusammen

alse erstmal herzlichen Dank für die Antworten.
Ich habe nun erst einmal einen anderen Controller genommen, jedoch mit 
dem gleichen Effekt.

Danach habe ich das Projekt auf das minimalste reduziert um den Fehler 
genau definieren zu können.
Das Projekt besteht eigentlich nur aus einer for-Schleife welche 10 mal 
durchlaufen wird, und einen Ausgang mit einer LED steuert.

Nun ist es so, dass wenn ich in dieser Schleife einen Array-Wert mit 
einem Konstanten Arrayindex abfrage, funtioniert dies einwandfrei und 
die LED blinkt 5 mal.
Sobald ich jedoch den Schleifenindex verwende um den Arrayinhalt 
abzufragen, bleibt mir der Controller hängen.
Dies äussert dich so, dass nach dem Start die LED auf etwa 5% leicht 
leuchtet ohne zu blinken.
Die entsprechenden Zeilen sind unten im Code beschrieben.

Hier das entsprechende Programm
1
#include <avr/io.h>
2
#include <stdio.h>
3
4
// --- main routine ---
5
int main(){
6
7
  // --- local declarations ---
8
  const unsigned int uiNumOfLoops = 10;
9
  volatile unsigned long i;
10
  volatile unsigned long j;
11
  volatile unsigned int myVal;
12
13
  unsigned long aMyArray[75] = {0,1,2,3,4,5,6,7,8,9};
14
15
  // --- define IO's ---
16
  DDRB = (1<<PB4);
17
18
    // --- main loop ---
19
    for (i=0; i<uiNumOfLoops; i++){
20
21
      // get array variable
22
      myVal = aMyArray[0];   // <--- works
23
      //myVal = aMyArray[i];   // <-- controller stops, does not work
24
25
      // blink output
26
      if ((PORTB & (1<<PB4)) == 0){
27
        PORTB |= (1<<PB4);  // set output
28
      }else{
29
      PORTB &= ~(1<<PB4); // reset output
30
      }
31
32
      // delay loop
33
      for (j=0; j<10000; j++){
34
35
      }
36
      
37
    }
38
39
  return 1;
40
}

Was mache ich noch falsch? Es muss an der Applikation liegen da dies bei 
verschiedenen Controllern gleich auftritt.

Gibt es irgendwelche Compilereinstellungen welche dies verursachen 
könnten?
Ich arbeite unter Ubuntu mit Eclipse und dem AvrDude.

Danke für die Hilfe und einen schönen Samstag wünscht
hafisch

von Wolfgang (Gast)


Lesenswert?

H. Fisch schrieb:
> volatile unsigned long i;
> volatile unsigned long j;

Gibt es irgendeinen Grund, dein Array über eine 32-Bit Variable zu 
indizieren?

Gleiches gilt für den Variablentyp deine Array-Elemente. Spätestens wenn 
du dir die Frequenz deines PWM-Signals anguckst, wird sich rausstellen, 
dass es selten sinnvoll ist, hier mehr als 16 Bit zu verwenden.

H. Fisch schrieb:
> double dPwm_freq = 1975;          // requested frequency
Welche Dynamik erwartest du, dass du zu Gunsten der Dynamik ein 
float-Variable verwendest und damit auf Auflösung verzichtest. 
Frequenzen im Millihertz-Bereich sind für PWM selten sinnvoll. Nimm 
lieber eine solide Festkommaarithmetik und achte auf die Größe der 
Zwischenergebnisse, i.e. auf die Reihenfolge der Operationen.

von H. F. (hafisch)


Lesenswert?

Hallo Wolfgang

Zu diesen beiden Punkten gebe ich dir absolut recht.
Die Variablengössen sind nicht optimiert und zu gross oder noch falsch 
gewählt.
Den float Datentyp habe ich erst einmal so gewählt, da ich nicht sicher 
bin, wie genau die Frequenzen sein müssen so dass Fehler nicht hörbar 
sind. Dies werde ich jedoch erst anpassen, wenn ich dies mit dem Buzzer 
und der ganzen Melodie getestet habe.

Die grossen Datentypen habe ich allerdings hauptsächlich aus dem Grund 
so gewählt, dass ich aufgrund des oben genannten Problems ziemlich viel 
schon versucht habe um die Ursache zu finden. Entsprechend habe ich 
alles auf sehr grosse Datentypen gestellt habe, um irgendwelche 
Überläufe ausschliessen zu können.

Sobald ich das Schleifen-Problem gefunden habe und das Programm so läuft 
werde ich den Rest optimieren.

Danke für die Hilfe und Gruss
hafisch

von H. F. (hafisch)


Lesenswert?

Hallo zusammen

Ich habe noch eine weitere Erkenntnis bezüglich des Zugriffs auf das 
Array mit einer Variable.

Ich habe das gleiche Problem, wenn ich eine Variable ausserhalb der 
Schleife definiere, und diese in der Schleife inkrementiere.

Das heisst das Programm bleibt bei folgendem Code ebenfalls hängen:
1
// --- main loop ---
2
volatile int arrayIdx = 0;
3
4
for (i=0; i<uiNumOfLoops; i++){
5
6
  // get array variable
7
  arrayIdx ++;
8
  myVal = aMyArray[arrayIdx];    // <-- controller stops, does not work
9
  //myVal = aMyArray[i];         // <-- controller stops, does not work

Es funktioniert nur, wenn ich die Variable innerhalb der Schleife 
definiere, oder einen konstanten Wert eintrage.

Hat noch jemand eine Idee?

Danke und Gruss
hafisch

von Daniel A. (daniel-a)


Lesenswert?

Ich denke der fehler ist nicht im code. Es gibt keine Rekursionen oder 
zu grosse locale Arrays, welche einen Stackoverflow auslösen könnten, 
zudem gibt es auch keine bufferoverflows oder änliches.
Compilierst du für den richtigen uc, hat dieser eine zuverlässige 
stromversorgung?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

H. Fisch schrieb:
> volatile unsigned int myVal;
>
>   unsigned long aMyArray[75] = {0,1,2,3,4,5,6,7,8,9};

 Warum liest du die ganze Zeit einen integer aus einem long Array
 heraus ?

H. Fisch schrieb:
> Das heisst das Programm bleibt bei folgendem Code ebenfalls hängen:
> // --- main loop ---
> volatile int arrayIdx = 0;
>
> for (i=0; i<uiNumOfLoops; i++){
>
>   // get array variable
>   arrayIdx ++;
>   myVal = aMyArray[arrayIdx];    // <-- controller stops, does not work
>   //myVal = aMyArray[i];         // <-- controller stops, does not work
>
> Es funktioniert nur, wenn ich die Variable innerhalb der Schleife
> definiere, oder einen konstanten Wert eintrage.
>
> Hat noch jemand eine Idee?

 Ja.
 Überprüfe deine Einstellungen, wähle richtigen uC.
 Es gibt absolut keinen Grund warum das nicht funktionieren sollte.

von H. F. (hafisch)


Lesenswert?

Hallo

Ich denke auch dass es Applikativ stimmt, da ich dasselbe auf dem 
Rechner in einer lokalen C-Applikation problemlos ausführen konnte.

Es muss also entweder an einer Compilereinstellung, einen applikativen 
Fehler zu dieser speziellen HW oder an der HW selbst liegen.

Das auslesen des Integers aus einem long-Array kommt daher, dass ich 
meine Applikation zu Beispielzwecken reduziert habe. Dies ist jedoch 
kein Problem da es sich um eine impliziten konvertierung handelt.

Muss HW-mässig etwas beachtet werden?
Muss im AvrDude ausser dem Typ den Fuses, den Lockbits noch etwas 
anderes eingestellt werden was hardwareabhängig ist?
Könnte es an bestimmten Compilereinstellungen liegen?

Werde dies noch mit einem Atmega und im Win Avr versuchen.

Gruss
hafisch

von Stefan E. (sternst)


Lesenswert?

H. Fisch schrieb:
> Nun ist es so, dass wenn ich in dieser Schleife einen Array-Wert mit
> einem Konstanten Arrayindex abfrage, funtioniert dies einwandfrei und
> die LED blinkt 5 mal.
> Sobald ich jedoch den Schleifenindex verwende um den Arrayinhalt
> abzufragen, bleibt mir der Controller hängen.

Wie erzeugst du das HEX-File?
Vermutlich hast du die data-Section nicht mit in dieses exportiert.

von H. F. (hafisch)


Lesenswert?

Hallo

Das tönt mal nach einer möglichen Ursache.
Was ist denn die Data section? Was ist darin enthalten, so dass es einen 
Einfluss auf den Arrayzugriff haben kann?

Weiss jemand wie dies im Eclipse mit AvrDude konfiguriert werden kann.

vielen herzlichen Dank und einen schönen Abend wünscht
hafisch

von Stefan E. (sternst)


Lesenswert?

H. Fisch schrieb:
> Was ist darin enthalten, so dass es einen
> Einfluss auf den Arrayzugriff haben kann?

Die Initialisierungsdaten deines Arrays.

H. Fisch schrieb:
> Weiss jemand wie dies im Eclipse mit AvrDude konfiguriert werden kann.

AvrDude hat damit schon mal überhaupt nichts zu tun. Was man in Eclipse 
einstellen kann/muss, kann ich dir nicht sagen. Aber wenn du ein 
automatisch generiertes Makefile verwendest, dann würde ich erwarten, 
dass das nicht das Problem ist.

Es wäre hilfreich, wenn du mal den kompletten Output eines Builds posten 
würdest.

von H. F. (hafisch)


Lesenswert?

Hallo zusammen

Hier der Output des build-log.
Könnt ihr darin sehen ob es sich um eine Fehleinstellung handelt?
1
**** Build of configuration Release for project AvrMelodyBeeper ****
2
3
make all 
4
Building target: AvrMelodyBeeper.elf
5
Invoking: AVR C Linker
6
avr-gcc -Wl,-Map,AvrMelodyBeeper.map -mmcu=attiny25 -o "AvrMelodyBeeper.elf"  ./MelodyBeeper.o   
7
Finished building target: AvrMelodyBeeper.elf
8
 
9
Invoking: AVR Create Extended Listing
10
avr-objdump -h -S AvrMelodyBeeper.elf  >"AvrMelodyBeeper.lss"
11
Finished building: AvrMelodyBeeper.lss
12
 
13
Create Flash image (ihex format)
14
avr-objcopy -R .eeprom -O ihex AvrMelodyBeeper.elf  "AvrMelodyBeeper.hex"
15
Finished building: AvrMelodyBeeper.hex
16
 
17
Create eeprom image (ihex format)
18
avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex AvrMelodyBeeper.elf  "AvrMelodyBeeper.eep"
19
Finished building: AvrMelodyBeeper.eep
20
 
21
Invoking: Print Size
22
avr-size --format=avr --mcu=attiny25 AvrMelodyBeeper.elf
23
AVR Memory Usage
24
----------------
25
Device: attiny25
26
27
Program:     400 bytes (19.5% Full)
28
(.text + .data + .bootloader)
29
30
Data:          0 bytes (0.0% Full)
31
(.data + .bss + .noinit)
32
33
34
Finished building: sizedummy
35
 
36
37
**** Build Finished ****

Ich verwende im Eclipse den "internal build".

Danke und Gruss
hafisch

von Stefan E. (sternst)


Lesenswert?

H. Fisch schrieb:
> Sobald ich dies jedoch auf den Controller (Attiny85) lade

> avr-gcc ... -mmcu=attiny25 ...

Was denn nun?

von H. F. (hafisch)


Lesenswert?

Hallo

Ich habe zu Testzwecken, um einen defekten Controller ausschliessen zu 
können, auf einen attiny25 gewechselt.

Doch inzwischen habe ich einmal auf einen Atmega8515 gewechselt.
Bei diesem scheint dies ohne Probleme zu funktionieren.
Ist es möglich, dass mir bei einem tiny der Speicher ausgeeht sobald 
dies mit einem Schleifenindex abgerufen wird?
Hat diese einen Einfluss auf den zu verwendenen Speicher?

Danke und Gruss
hafisch

von Stefan E. (sternst)


Lesenswert?

H. Fisch schrieb:
> Ist es möglich, dass mir bei einem tiny der Speicher ausgeeht sobald
> dies mit einem Schleifenindex abgerufen wird?

Dir geht auf einen Tiny25 in jedem Fall der Speicher aus.
(Wie viel Bytes braucht das Array und wie viel hast du auf einem 
Tiny25?)

Bei Zugriffen mit konstantem Index fällt das nur nicht auf, weil dann in 
Wirklichkeit gar kein Zugriff auf das Array stattfindet.

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.