Forum: Mikrocontroller und Digitale Elektronik Bitte um Hilfe bei der Programmierung von AVR8-Mikrocontrollern in C


von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Da kann doch nur die Arduino-IDE einen Bug haben oder ?

C kann doch direkt ein 16-Bit-Register, wie es dass OCR3A ist 
beschreiben.
Auch der Versuch OCR3AL & OCR3AH einzeln zu beschreiben funktioniert 
nicht.
1
#include <Arduino.h>
2
#include <stdint.h>
3
#include <avr/io.h>
4
5
#define MAX  500
6
#define MIN  200
7
8
9
////////////////////////////////////////////////////////////////////////////////
10
// SETUP
11
// 
12
void setup() {
13
  Serial.begin( 9600 );
14
  
15
Serial.println();
16
Serial.print  ( "MAX = "  );
17
Serial.println(  MAX      );
18
  
19
  OCR3A = MAX;
20
  //OCR3AH = MAX / 256;               // Mit niedriger Frequenz anfangen
21
  //OCR3AL = MAX % 256;
22
23
Serial.println();
24
Serial.print  ( "OCR3A = MAX = " );
25
Serial.println(  OCR3A          );
26
  
27
  
28
Serial.println();
29
Serial.print  ( "OCR3AH = MAX / 256 = "  );
30
Serial.println(  OCR3AH                  );
31
Serial.print  ( "OCR3AL = MAX % 256 = "  );
32
Serial.println(  OCR3AL          );
33
  
34
}

Bernd_Stein

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Hatten wir das nicht letztens schon?


Arduino bereitet alle Timer Für eine 8 Bit PWM vor.
Hatten wir das nicht letztens schon?

Setze, bevor du irgendwas anderes mit dem Timer tust, die 
Controllregister auf Null.
Hatten wir das nicht letztens schon?

Bernd S. schrieb:
>  Programmierung von AVR8-Mikrocontrollern in C
Das ist C++, mein Lieber!
C++! Nix C!
Mein Lieber.

Bernd S. schrieb:
> Da kann doch nur die Arduino-IDE einen Bug haben oder ?
Was soll die denn Schuld sein, wenn du unmögliches versucht....

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Bernd S. schrieb:
> Da kann doch nur die Arduino-IDE einen Bug haben oder ?

Tja, das muss es wohl sein.
Da kannste leider nix machen.

scnr,
WK

von N. M. (mani)


Lesenswert?

Bernd S. schrieb:
> Da kann doch nur die Arduino-IDE einen Bug haben oder ?

Auch wenn man das ab und zu denkt. Meist ist es nicht so und das Problem 
sitzt vor dem Bildschirm.

von Alexander (alecxs)


Lesenswert?

Habe zwar keine Ahnung aber selbst mir ist sofort aufgefallen AVR8 und 
16 Bit

von Rahul D. (rahul)


Lesenswert?

Alexander schrieb:
> Habe zwar keine Ahnung aber selbst mir ist sofort aufgefallen AVR8 und
> 16 Bit

auch ein Achtbitter darf 16-Bit-Register haben...

von Christian S. (roehrenvorheizer)


Lesenswert?

Rahul D. schrieb:
> auch ein Achtbitter darf 16-Bit-Register haben...

Stimmt, das hatte schon der AT90S2313.

mfg

von Georg M. (g_m)


Lesenswert?

Bernd S. schrieb:
> C kann doch direkt ein 16-Bit-Register, wie es dass OCR3A ist
> beschreiben.

C ist C, und Arduino ist Arduino.

von Rahul D. (rahul)


Lesenswert?

Georg M. schrieb:
> C ist C, und Arduino ist Arduino.

Falsch.
Arduino ist C++ (und ein bißchen drumrum).

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Gabs da nicht mal was, dass man erst L und dann H beschreiben muss, 
damit das mit dem Beschreiben von H dann als 16Bit Wert aktiv wird?

von Rahul D. (rahul)


Lesenswert?

Mampf F. schrieb:
> Gabs da nicht mal was, dass man erst L und dann H beschreiben muss,
> damit das mit dem Beschreiben von H dann als 16Bit Wert aktiv wird?

ja. Auch beim Auslesen (z.B. des ADC-Werteregisters).

von Wastl (hartundweichware)


Lesenswert?

Arduino F. schrieb:
> Arduino bereitet alle Timer Für eine 8 Bit PWM vor.

Ich dachte immer das Arduino-Framwork lässt alle Hardware
in Ruhe bis auf die die es wirklich braucht. Im Fall der
Timer wäre das beim Arduino Timer0 und sonst nichts. Also
nicht alle Timer.

von Rainer W. (rawi)


Lesenswert?

Georg M. schrieb:
> C ist C, und Arduino ist Arduino.

Arduino verwendet einen GCC Compiler.
https://gcc.gnu.org/
Durch welche IDE der aufgerufen wird, ist doch egal.

von Rainer W. (rawi)


Lesenswert?

Bernd S. schrieb:
> Auch der Versuch OCR3AL & OCR3AH einzeln zu beschreiben funktioniert
> nicht.

Um welchen Controller geht es dir überhaupt?

> Serial.println();
> Serial.print  ( "OCR3AH = MAX / 256 = "  );
> Serial.println(  OCR3AH                  );
> Serial.print  ( "OCR3AL = MAX % 256 = "  );
> Serial.println(  OCR3AL          );

Du kannst nicht erst das H-Byte und dann das L-Byte lesen. Dann holst du 
einen alten Wert aus dem TEMP-Register, der nicht zu deinem L-Byte 
gehört.
https://onlinedocs.microchip.com/pr/GUID-EC8D3BAB-0B5E-454F-AB6E-6A7C91C6F103-en-US-3/index.html?GUID-A7CE312E-676A-4DC2-B0C1-0A78575A1F85

: Bearbeitet durch User
von 900ss (900ss)


Lesenswert?

Alexander schrieb:
> Habe zwar keine Ahnung aber selbst mir ist sofort aufgefallen AVR8 und
> 16 Bit

Autsch......

von 900ss (900ss)


Lesenswert?

Rainer W. schrieb:
> Du kannst nicht erst das H-Byte und dann das L-Byte lesen. Dann holst du
> einen alten Wert aus dem TEMP-Register, der nicht zu deinem L-Byte
> gehört.

Richtig, genau anders herum funktioniert es.

von Rolf (rolf22)


Lesenswert?

N. M. schrieb:
> Bernd S. schrieb:
>> Da kann doch nur die Arduino-IDE einen Bug haben oder ?
>
> Auch wenn man das ab und zu denkt. Meist ist es nicht so und das Problem
> sitzt vor dem Bildschirm.

Im Studium habe ich mal mit Betreuern des Uni-RZ gesprochen. Die haben 
mir erzählt, sie hätten bei der Nutzerbetreuung mal Erbsen gezählt und 
dabei herausgefunden, dass von 1000 Reklamationen der Art "Der Compiler 
X arbeitet falsch" nur eine einzige berechtigt gewesen war.

Später dann, in meiner ersten Arbeitsstelle fing ich zusammen mit einem 
Computer-Anfänger an (Mathematik-Studium abgebrochen) an, der manchmal 
nervlich fast zusammengebrochen ist, weil seine FORTRAN-Programme nicht 
liefen. Waren aber immer seine Fehler, die ich oder jemand anders ihm 
zeigen musste.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Arduino F. schrieb:
> Arduino bereitet alle Timer Für eine 8 Bit PWM vor.
> Hatten wir das nicht letztens schon?
>
Jo das wars, danke. Habe wohl ein schlechtes Gedächnis, es kommt mir 
aber bekannt vor. Habe TCCR3A bis C auf null gesetzt.

von Rolf (rolf22)


Lesenswert?

Rahul D. schrieb:

> auch ein Achtbitter darf 16-Bit-Register haben...

Ja, hatte schon der 8-Bitter Z80 vor fast 50 Jahren.

Wenn man aber Hardware-Komponenten programmiert, dann studiert man IMMER 
das Datenblatt des Prozessors. Ganz gleich, was die Programmiersprache 
kann/könnte.

von Sebastian W. (wangnick)


Lesenswert?

Bernd S. schrieb:
> kann doch direkt ein 16-Bit-Register, wie es dass OCR3A ist beschreiben

Du hast da einen sehr interessanten Fall konstruiert. Die 
OCR-Doppelregister des AVR müssen byteweise in einer bestimmten 
Reihenfolge geschrieben und auch gelesen werden. Der gcc-Compiler tut 
das bei direkten 16-Bit-Zugriffen auf solche Doppelregister auch schön. 
Allerdings übergibst du in deinem Code das OCR3A-Doppelregister an 
println(). Und ich vermute stark, dass innerhalb von println() das 
Wissen über diese Spezialbehandlung verloren gegangen ist. Ich werde mal 
versuchen, das nachzuvollziehen.

LG, Sebastian

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Wastl schrieb:
> Ich dachte immer das Arduino-Framwork lässt alle Hardware
> in Ruhe bis auf die die es wirklich braucht. Im Fall der
> Timer wäre das beim Arduino Timer0 und sonst nichts. Also
> nicht alle Timer.

ALLE Timer.

Sebastian W. schrieb:
> Und ich vermute stark, dass innerhalb von println() das
> Wissen über diese Spezialbehandlung verloren gegangen ist.
Nein!

println() bekommt nur den Wert zu sehen, das Makro wird vorher 
ausgewertet, bevor Print überhaupt was tut.

Sebastian W. schrieb:
> Du hast da einen sehr interessanten Fall konstruiert.
Das hat ihm wirklich!
Arduino macht den Timer zu einem 8 Bit PWM Timer und ihm versucht dort 
16 Bit in ein Register zu schreiben, welches aufgrund der vorher 
erfolgten Konfiguration nur 8 Bit aufnehmen kann.

Bernd S. schrieb:
> Jo das wars, danke.
Fein!

von Falk B. (falk)


Lesenswert?

Der Drachenlord von uC.net ist mal wieder aktiv ;-)
Immer schön den Troll füttern . . .

von Sebastian W. (wangnick)


Lesenswert?

Arduino F. schrieb:
> Sebastian W. schrieb:
>> Und ich vermute stark, dass innerhalb von println() das
>> Wissen über diese Spezialbehandlung verloren gegangen ist.
> Nein!
>
> println() bekommt nur den Wert zu sehen, das Makro wird vorher
> ausgewertet, bevor Print überhaupt was tut.

Ok, ich hab mit das Datenblatt des Atmega2560P und den Arduino-Code noch 
einmal vorgenommen:
1. "Reading the OCRnA/B/C 16-bit registers does not involve using the 
Temporary Register." und "The Timer/Counter does not update this 
register automatically"
2. wiring.c::init():
1
  sbi(TCCR3B, CS31);    // set timer 3 prescale factor to 64
2
  sbi(TCCR3B, CS30);
3
  sbi(TCCR3A, WGM30);    // put timer 3 in 8-bit phase correct pwm mode
3. WGMn3:0=1, PWM, Phase Correct, 8-bit, TOP=0x00FF
4. "Note that when using fixed TOP values the unused bits are
masked to zero when any of the OCRnx Registers are written."
5. OCR3A ist definiert als _SFR_MEM16(0xnn). _SFR_MEM16 ist definiert 
als _MMIO_WORD. _MMIO_WORD ist definiert als * (volatile uint16_t * ).

@arduinof, du hast also recht. An println wird keine Referenz auf eine 
Variable übergeben, sondern ein Wert. Und in OCR3A steht tatsächlich 
nach der Zuweisung von 500 der Wert 244, weil die oberen 8 Bit durch den 
in init() eingestellten PWM-Modus schon bei der Zuweisung maskiert 
werden.

Wieder was gelernt.

LG, Sebastian

von Axel S. (a-za-z0-9)


Lesenswert?

Mampf F. schrieb:
> Gabs da nicht mal was, dass man erst L und dann H beschreiben
> muss,
> damit das mit dem Beschreiben von H dann als 16Bit Wert aktiv wird?

Ja. Der gcc weiß das aber und macht es bei 16-Bit Zugiffen automatisch.


Sebastian W. schrieb:
> 1. "Reading the OCRnA/B/C 16-bit registers does not involve using the
> Temporary Register." und "The Timer/Counter does not update this
> register automatically"

Eben. Wegen letzterem ist ersteres nicht notwendig. ATMEL hat das 
temp-Register nur dort implementiert, wo es notwendig ist.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Sebastian W. schrieb:
> @arduinof, du hast also recht.
Nicht immer, aber in Sachen Arduino und drum rum doch schon recht 
häufig.
Und: Danke für die Überprüfung/Klärung.

Interessant, dass du der Erste bist, der das in diesem Thread öffentlich 
getan hat. Eigentlich erwarte ich das von einem Threadersteller, bevor 
die Frage gestellt wird.
Denn die nötige Information liegt ja öffentlich aus.

Sebastian W. schrieb:
> Wieder was gelernt.
Einer der Gründe, warum auch ich hier bin. Man muss nur ein wenig 
aufpassen, dass man hier das richtige lernt.

Schlussendlich:
Man kann von der Arduino IDE halten, was man will....
Aber hier, in diesem konkreten Fall, ist sie vollständig von jeder 
Schuld freizusprechen.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Jetzt was Anderes.
Hat jemand eine elegantere bzw. in der Programmabarbeitung schnellere 
Idee ?

Es soll immer zwischen den MIN,- und MAX-Wert mit der SCHRITTWEITE hin 
und hergependelt werden ( siehe Anhang ).


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Es soll immer zwischen den MIN,- und MAX-Wert mit der SCHRITTWEITE hin
> und hergependelt werden ( siehe Anhang ).

Schon mal was von einer for() Schleife gehört? Nicht zu verwechseln mit 
der imaginären if()-Schleife.

http://www.if-schleife.de/

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Arduino F. schrieb:

> Schlussendlich:
> Man kann von der Arduino IDE halten, was man will....
> Aber hier, in diesem konkreten Fall, ist sie vollständig von jeder
> Schuld freizusprechen.

Ähem, nö. Erstens ging es nicht um die IDE (die ist vergleichsweise 
sowieso ziemlich grottig), sondern eher um das Framework.

Und auch das ist grottig. Und das zeigt sich sogar am konkreten Fall 
besonders deutlich. Es kann doch nicht sein, dass es ungefragt einen 
Timer aquiriert, dessen Funktionalität in der gebotenen Form dann aber 
garnicht genutzt wird und damit letztlich den Programmierer dabei 
behindert, den Timer für das zu nutzen, was er tatsächlich tun will.

Ja OK, dieses Fehlverhalten ist wenigstens dokumentiert. Wäre ja auch 
noch viel schlimmer, wenn nichtmal das der Fall wäre. Das wäre dann 
vorsätzliche Sabotage. Aber auch der gegenwärtige Sachverhalt ist meiner 
Meinung nach nicht sehr weit weg davon.

Denn technisch gäbe es durchaus die Möglichkeit, bereits zur Compilezeit 
(!) festzustellen, ob die vom Framework gebotene Timer-Funktionalität 
vom Anwenderprogramm überhaupt genutzt wird und, wenn das nicht der Fall 
ist, den Timer einfach mal in Ruhe zu lassen.

von Falk B. (falk)


Lesenswert?

Ob S. schrieb:
> Denn technisch gäbe es durchaus die Möglichkeit, bereits zur Compilezeit
> (!) festzustellen, ob die vom Framework gebotene Timer-Funktionalität
> vom Anwenderprogramm überhaupt genutzt wird und, wenn das nicht der Fall
> ist, den Timer einfach mal in Ruhe zu lassen.

Man könnte auch einfach aufhören zu plappern und zu heulen und den Timer 
VOLLSTÄNDIG und RICHTIG initialisieren. Dann klappt das auch.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Falk B. schrieb:
> Ob S. schrieb:
>> Denn technisch gäbe es durchaus die Möglichkeit, bereits zur Compilezeit
>> (!) festzustellen, ob die vom Framework gebotene Timer-Funktionalität
>> vom Anwenderprogramm überhaupt genutzt wird und, wenn das nicht der Fall
>> ist, den Timer einfach mal in Ruhe zu lassen.
>
> Man könnte auch einfach aufhören zu plappern und zu heulen und den Timer
> VOLLSTÄNDIG und RICHTIG initialisieren. Dann klappt das auch.

Vollständig heißt aber in jeder anderen Umgebung: ausgehend vom im DB 
dokumentierten Reset-State.

Bei der Arduino-Gülle aber eben nicht. Und das, obwohl es technisch 
möglich wäre, die unnütze Doppelinitialisierung, auf die es ansonsten 
hinausläuft, einfach mal einzusparen. Das wäre im Minimum gut für die 
Codegröße. Aber natürlich auch gut zur Vermeidung derartiger 
Überraschungen.

von Rainer W. (rawi)


Lesenswert?

Bernd S. schrieb:
> Jetzt was Anderes.

Dann wäre es jetzt auch an der Zeit, für etwas anderes einen neuen 
Thread zu eröffnen - nur um die Dinge ein bisschen sortiert zu halten.

von Falk B. (falk)


Lesenswert?

Ob S. schrieb:
> Vollständig heißt aber in jeder anderen Umgebung: ausgehend vom im DB
> dokumentierten Reset-State.

Ja und? Im ZWEIFELSFALL muss man halt ALLE Register setzen. So what!

> Bei der Arduino-Gülle aber eben nicht. Und das, obwohl es technisch
> möglich wäre, die unnütze Doppelinitialisierung, auf die es ansonsten
> hinausläuft, einfach mal einzusparen.

Ach du Ärmster, die Doppelinitialisierung! Das ist so wie Doppel-Wums! 
Oder Doppelpass!

> Das wäre im Minimum gut für die
> Codegröße.

Schon wieder Weltrettungsphantasien? Musst du deinen Flash-Verbrauch 
minimieren, so wie auch deine CO2 Erzeugung? Wie Klimaschädlich ist 
Flash-Speicher in CO2 Äquivalenten? ;-)

von Vax W. (Gast)


Lesenswert?

Ob S. schrieb:

> Vollständig heißt aber in jeder anderen Umgebung: ausgehend vom im DB
> dokumentierten Reset-State.
>
> Bei der Arduino-Gülle aber eben nicht. Und das, obwohl es technisch
> möglich wäre, die unnütze Doppelinitialisierung,

Da Du ja offensichtlich der Programmiergott bist, koenntest Du Dich 
bei Arduino einbringen und die Issues (die es gibt) zum Teil loesen.

si tacuisses, philosophus mansisses. Oder Machen: Das ist naemlich wie 
wollen, nur krasser.

von Stefan F. (Gast)


Lesenswert?

Manche Leute können sich halt nur mit ihrem eigenen Framework zufrieden 
geben. Dir anderen sind Teamfähig.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Vax W. schrieb:

> Da Du ja offensichtlich der Programmiergott bist, koenntest Du Dich
> bei Arduino einbringen und die Issues (die es gibt) zum Teil loesen.

1) Das sind keine "issues", jedenfalls nicht in dem Sinne, wie man das 
üblicherweise versteht. Das sind grundlegende Fehler im Konzept des 
Frameworks.

2) Ich habe mit meiner verbleibenden Lebenszeit sicher Besseres vor, als 
dieses grottige Framework nochmals von Grund auf neu zu schreiben.

von Some O. (some_one)


Lesenswert?

Falk B. schrieb:
> Ob S. schrieb:
>> Vollständig heißt aber in jeder anderen Umgebung: ausgehend vom im DB
>> dokumentierten Reset-State.
>
> Wie Klimaschädlich ist
> Flash-Speicher in CO2 Äquivalenten? ;-)

Bitte nehmt Euch ein Separée.

von Falk B. (falk)


Lesenswert?

Some O. schrieb:
>> Wie Klimaschädlich ist
>> Flash-Speicher in CO2 Äquivalenten? ;-)
>
> Bitte nehmt Euch ein Separée.

Un Separée, si vou plait! ;-)

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ob S. schrieb:
> 1) Das sind keine "issues", jedenfalls nicht in dem Sinne, wie man das
> üblicherweise versteht. Das sind grundlegende Fehler im Konzept des
> Frameworks.

Das ist deine Beurteilung!

Wenn du nicht willst, dass das Framework die Dinge initialisiert, dann 
solltest du auf die Initialisierung verzichten. Arduino Jünger wissen 
meist wie das geht. Du offensichtlich nicht.

Tipp:
Eine eigene main() anlegen, dann werden die Timer (und einiges andere) 
nicht angefasst.

: Bearbeitet durch User
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Arduino F. schrieb:

> Wenn du nicht willst, dass das Framework die Dinge initialisiert, dann
> solltest
> du auf die Initialisierung verzichten. Arduino Jünger wissen meist wie
> das geht. Du offensichtlich nicht.

Ich löse das Problem viel einfacher: Ich benutze das Framework (und auch 
die IDE) generell nicht.

Funktioniert nämlich alles wunderbar auch ohne diesen Mist!

von Wastl (hartundweichware)


Lesenswert?

Falk B. schrieb:
> Un Separée, si vou plait!

---> un séparé s'il vous plaît

von Falk B. (falk)


Lesenswert?

Je ne parle pas français!

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Bernd S. schrieb:
> SCHRITTWEITE

Ohne deine Schrittweite... bzw. mit fester 1
1
template<typename T>
2
class Pendel : public Printable
3
{
4
  private:
5
  const T min;
6
  const T max;
7
  T value;
8
  bool up;
9
  
10
  public:
11
  Pendel(T min, T max):min(min),max(max),value(min),up(true){}
12
  operator T() {return value;}
13
  T next()
14
  {
15
    if(min>=value) up=true;
16
    if(max<=value) up=false;
17
    return value += up?+1:-1;
18
  }
19
  virtual size_t printTo(Print &p)  const
20
  {
21
    size_t len = 0;
22
    len += p.print("  min: ")   + p.println(min);
23
    len += p.print("  max: ")   + p.println(max);
24
    len += p.print("  value: ") + p.println(value);
25
    len += p.print("  up: ")    + p.println(up?"true":"false");
26
    return len + p.println("----------------");
27
  }
28
};
29
30
Pendel<unsigned char> pendel{200,210};
31
32
33
void setup() 
34
{
35
  Serial.begin(9600);
36
}
37
38
void loop() 
39
{
40
  pendel.next();
41
  // analogWrite(pin,pendel); 
42
  Serial.println(pendel); // Status ausgeben
43
  delay(1000); // nur, damit es nicht zu schnell durchhuscht
44
}

Ob S. schrieb:
> Erstens ging es nicht um die IDE
Doch um genau die ging es im Eröffnungsposting.
Hast du scheinbar auch übersehen...
Sicherlich wegen zuviel Schaum vorm Mund.

von Wastl (hartundweichware)


Lesenswert?

Falk B. schrieb:
> Je ne parle pas français!

But ei cän good inglisch

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Falk B. schrieb:

> Je ne parle pas français!

Dann unterlass' doch einfach den Versuch. Von dir angedeutete oder 
behauptete Kompetenz (in irgendeiner Hinsicht) nimmt dir eh' niemand ab, 
der wirklich weiß, wie der Laden läuft...

von Wastl (hartundweichware)


Lesenswert?

Ob S. schrieb:
> Funktioniert nämlich alles wunderbar auch ohne diesen Mist!

Unglaublich, aber das habe ich auch schon herausgefunden.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ob S. schrieb:
> Ich löse das Problem viel einfacher: Ich benutze das Framework (und auch
> die IDE) generell nicht.

Darf ich dich als "Windbeutel" bezeichnen?
Warum buddelst du auf Baustellen, die dich nix angehen?

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Arduino F. schrieb:

> Ob S. schrieb:
>> Erstens ging es nicht um die IDE

> Doch um genau die ging es im Eröffnungsposting.

Nicht wirklich.

Das war nur das, wo Bernd S. das Problem lokalisiert zu haben glaubte...

Aber der Typ kann nach >10 Jahren Praxis immer noch nicht kompetent mit 
AVR8-Assembler umgehen. Ist also eher nicht dazu geeignet, 
einzuschätzen, wo ein Problem beheimatet ist.

von Falk B. (falk)


Lesenswert?

Ob S. schrieb:
> Dann unterlass' doch einfach den Versuch. Von dir angedeutete oder
> behauptete Kompetenz (in irgendeiner Hinsicht) nimmt dir eh' niemand ab,
> der wirklich weiß, wie der Laden läuft...

Geh mal besser hier hin

-> Humorbefreite Zone!

Gehe sofort dort hin.
Ziehe keine 4000 Euro ein!

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Arduino F. schrieb:

> Darf ich dich als "Windbeutel" bezeichnen?

Nein. Das würde ich als Beleidigung auffassen.

> Warum buddelst du auf Baustellen, die dich nix angehen?

Man muss immer auch mal über den Tellerrand schauen. Genau dies kannst 
du und deinesgleichen scheinbar nicht.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Ob S. schrieb:
> Genau dies kannst
> du und deinesgleichen scheinbar nicht.

Wirst wohl recht haben, wie auch sonst immer.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Na ihr Streithammel, könnt ihr auch mal wieder produktiv sein und mir 
erklären, warum ich das Output Compare A3 Match-Flag nicht löschen kann.
Das niederwertige Nibble bleibt immer gleich ( alles Einsen ).
1
 // Flag auswerten um guenstigen Moment zu erwischen
2
  if( TIFR3 & OCF3A ) { 
3
4
Serial.print  ( "TIFR3 = "  );
5
Serial.print  (  TIFR3, BIN );
6
Serial.println();
7
     
8
    OCR3A = rampeArray[ rampeArrayZeiger ];
9
    TIFR3 = 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen
10
11
Serial.print  ( "TIFR3 = "  );
12
Serial.println(  TIFR3, BIN );
13
    
14
  }

von Thomas Z. (usbman)


Lesenswert?

Bernd S. schrieb:
> TIFR3 = 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen

vielleicht weil du nicht das machst was im Kommentar steht...

TIFR3 |= 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen

von Hugo H. (hugo_hu)


Lesenswert?


von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Thomas Z. schrieb:
> vielleicht weil du nicht das machst was im Kommentar steht...
>
> TIFR3 |= 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen
>
Mit deiner Schreibweise, lasse ich ja nur die anderen Bits in dem 
Register unberührt. Ich habe das Register komplett neu beschrieben, d.h. 
die anderen Bits bleiben trotzem unberührt, da sie ja nur durch 
Schreiben einer 1 gelöscht werden können.

Da bin ja wiedermal gespannt, was nun die Ursache für das Phänomen ist.


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Thomas Z. schrieb:
> Bernd S. schrieb:
>> TIFR3 = 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen
>
> vielleicht weil du nicht das machst was im Kommentar steht...

Ausnahmsweise doch. Denn die Bits in DEM Register verhalten sich anders 
als normale Speicherzellen. Siehe Datenblatt.

> TIFR3 |= 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen

Nein.

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Da bin ja wiedermal gespannt, was nun die Ursache für das Phänomen ist.

Vermutlich die Verzögerung vom Löschen zur Ausgabe durch die 
print-Anweisung. Denn deine PWM läuft vermutlich mit sehr hoher Frequenz 
und print ist bei 9600 Baud schnarchlangsam. Eher so.
1
    OCR3A = rampeArray[ rampeArrayZeiger ];
2
    TIFR3 = 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen
3
    uint8_t tmp = TIFR3;
4
    Serial.print  ( "TIFR3 = "  );
5
    Serial.println(  tmp, BIN );

von Hugo H. (hugo_hu)


Lesenswert?

Falk B. schrieb:
> Siehe Datenblatt.

OCFnA can be cleared by writing a logic one to its bit location.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Falk B. schrieb:
> Vermutlich die Verzögerung vom Löschen zur Ausgabe durch die
> print-Anweisung. Denn deine PWM läuft vermutlich mit sehr hoher Frequenz
> und print ist bei 9600 Baud schnarchlangsam.
>
Wiedermal Danke, genau das war es.


Bernd_Stein

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:

> Ausnahmsweise doch. Denn die Bits in DEM Register verhalten sich anders
> als normale Speicherzellen. Siehe Datenblatt.

Nicht nur in dem Register: man achte auf den Namen: Flag-Register. Davon 
gibt es viele. Da man an einem schnellen (atomaren) Löschen der Flags 
interessiert ist, hilft uns hier die HW.

Leider sind die Datenblätter von Atmel/MicroChip sehr schlecht. In 
dieser Hinsicht sind bspw. die DB von STM besser: hier steht es ganz 
klar bei jedem Flag dabei, ob es rc_w0, rc_w1 oder rc_w, rc_r, rs_r ist.

von Falk B. (falk)


Lesenswert?

Wilhelm M. schrieb:
> Leider sind die Datenblätter von Atmel/MicroChip sehr schlecht.

So ein Unsinn! Nur weil die hier vielleicht nicht ganz so gut wie andere 
sind, sind sie nicht generall schlecht!

von Georg M. (g_m)


Angehängte Dateien:

Lesenswert?

Wilhelm M. schrieb:
> Leider sind die Datenblätter von Atmel/MicroChip sehr schlecht.

Was genau ist unverständlich?

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Wilhelm M. schrieb:
>> Leider sind die Datenblätter von Atmel/MicroChip sehr schlecht.
>
> So ein Unsinn! Nur weil die hier vielleicht nicht ganz so gut wie andere
> sind, sind sie nicht generall schlecht!

Das stimmt. Sie sind nicht generell schlecht!

In meinem obigen Satz fehlte ein "in dieser Hinsicht". Sorry, das habe 
ich zu später Stunde falsch formuliert. Und es hätte eigentlich Atmel 
heißen müssen, denn die der neuen AVRs (DA, DB, DD, EA, ... tiny1, 
tiny2, ...) sind nicht nur in dieser Hinsicht viel besser geworden.

Georg M. schrieb:
> Wilhelm M. schrieb:
>> Leider sind die Datenblätter von Atmel/MicroChip sehr schlecht.
>
> Was genau ist unverständlich?

Ich spreche nicht von unverständlich: es geht mir um Übersichtlichkeit 
und einfaches Erkennen.

Wie gesagt: der obiger Satz sollte heißen: " ... sind in dieser Hinsicht 
schlecht".

Die DB von MicroChip/Atmel (eigentlich Atmel) für die alten AVRs 
verwenden (mindestens) drei verschiedene Formulierungen:

- writing a '1'
- writing a logic one
- writing a one

Das ist schlecht für die Suche im Dokument.

Bei STM gibt es in der Registerübersicht unter den Bits noch die Zusätze 
wie rc_w0, ...

Natürlich könnte man auch sagen, dass das Problem an der Definition der 
Register in C liegt. In C++ (ja, ihr wisst schon) kann man das viel 
besser machen. Aber um eine sinnvolle C++-Schnittstelle zu den Registern 
zu liefern, sind die Hersteller zu faul, obwohl man das aus ihren 
eigenen XML-Beschreibungen recht einfach erzeugen könnte.

von Rahul D. (rahul)


Lesenswert?

Wilhelm M. schrieb:
> Natürlich könnte man auch sagen, dass das Problem an der Definition der
> Register in C liegt. In C++ (ja, ihr wisst schon) kann man das viel
> besser machen. Aber um eine sinnvolle C++-Schnittstelle zu den Registern
> zu liefern, sind die Hersteller zu faul, obwohl man das aus ihren
> eigenen XML-Beschreibungen recht einfach erzeugen könnte.

Hast du dazu bitte ein Beispiel?!

von Stefan F. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Aber um eine sinnvolle C++-Schnittstelle zu den Registern
> zu liefern, sind die Hersteller zu faul

Wohl auch, weil jeder C++ Entwickler eine eigene Vorstellung davon hat, 
was sinnvoll ist. Viele Möglichkeiten bringen viele unterschiedliche 
Lösungsansätze. Und in OOP kann man wunderbar akademisch aufgeblasene 
Gebäude konstruieren, die nur wenige Menschen durchblicken, aber 
akademisch super elegant aussehen.

von Fenton G. (fenton_g)


Lesenswert?

Bernd S. schrieb:
> if( TIFR3 & OCF3A ) {

Die Zeile kommt mir verdächtig vor. Soll die das OCF3A Bit (Bit 1 im 
TIFR3, Atmega2560) abfragen oder das TOV3 im Bit 0?

von Falk B. (falk)


Lesenswert?

Stefan F. schrieb:
> Und in OOP kann man wunderbar akademisch aufgeblasene
> Gebäude konstruieren, die nur wenige Menschen durchblicken, aber
> akademisch super elegant aussehen.

In der Tat. Das sind dann die Chuck Norris der Softwareentwicklung!

https://youtu.be/YRccr0Wmwtk?si=Bh4dhtjyp5FGRW2-

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan F. schrieb:
> Wilhelm M. schrieb:
>> Aber um eine sinnvolle C++-Schnittstelle zu den Registern
>> zu liefern, sind die Hersteller zu faul
>
> Wohl auch, weil jeder C++ Entwickler eine eigene Vorstellung davon hat,
> was sinnvoll ist.

Wenn es gut gemacht ist, so denke ich, dass das schon konvergiert.

> Viele Möglichkeiten bringen viele unterschiedliche
> Lösungsansätze.

Klar, und das ist auch gut ... und hoffentlich ist dann mindestens eine 
guter Ansatz dabei ;-)

> Und in OOP kann man wunderbar akademisch aufgeblasene
> Gebäude konstruieren, die nur wenige Menschen durchblicken, aber
> akademisch super elegant aussehen.

Was ich meine, hat so gar nichts mit OOP im klassischen Sinn zu tun.

Es geht darum, dass ich einfach
1
TIFR3 = 1<< OCF3A;

oder
1
TIFR3 |= 1<< OCF3A;

gar nicht erst schreiben kann. Eine der Möglichkeiten von C++ ist es 
eben, eigene DT zu definieren, die nur die sinnvollen Operationen 
enthalten. Und ein "|=" ist bei den Flag-Registern nicht sinnvoll.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Es geht schon wieder los...
Unser Wilhelm kapert mal wieder einen Thread um zu zeigen was für ein 
toller Hecht er doch ist.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Unser Wilhelm kapert mal wieder einen Thread um zu zeigen was für ein
> toller Hecht er doch ist.

Der einzige, der hier "abenteuerlichen" Code präsentiert hat, bis Du! 
Wahrscheinlich um zu zeigen, dass Du templates in C++ verstanden hast.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Wilhelm M. schrieb:
> dass Du templates in C++ verstanden hast

Ich danke dir herzlich für die Blumen.
Deine Anerkennung und Lobpreisungen, gehen mir runter wie Öl.

von Falk B. (falk)


Lesenswert?

Arduino F. schrieb:
> Deine Anerkennung und Lobpreisungen, gehen mir runter wie Öl.

Altöl? Frittenöl nach 3 Monaten bei 250°C? ;-)

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Falk B. schrieb:
> ...
Im nörgeln ist ist er ganz prächtig!
Im "zeigen" hapert es ganz derbe. Da kommt wenig und wenn, dann meist 
unvollständiges Zeugs.
In diesem Thread bisher noch gar nix.
Und eine verständliche, gut strukturierte Doku, habe ich noch nie von 
ihm gesehen.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Falk B. schrieb:
>> ...
> Im nörgeln ist ist er ganz prächtig!

Na, das hatten wir schon mal: wenn man darauf hinweist, das wie hier 
z.B. die DBer der Hersteller in einigen Punkten verbesserungsfähig sind, 
ist das für Dich "nörgeln". Gut: dazu stehe ich.

> Im "zeigen" hapert es ganz derbe. Da kommt wenig und wenn, dann meist
> unvollständiges Zeugs.

Ich habe sogar ein Beispiel gebracht, wie es besser geht.

> In diesem Thread bisher noch gar nix.
> Und eine verständliche, gut strukturierte Doku, habe ich noch nie von
> ihm gesehen.

Wie sieht denn Deine aus?

von Harald K. (kirnbichler)


Lesenswert?

Wilhelm M. schrieb:
> Ich habe sogar ein Beispiel gebracht, wie es besser geht.

Besser? Einigen wir uns auf anders.

von Wilhelm M. (wimalopaan)


Lesenswert?

Harald K. schrieb:
> Wilhelm M. schrieb:
>> Ich habe sogar ein Beispiel gebracht, wie es besser geht.
>
> Besser? Einigen wir uns auf anders.

Nö: wenn man es schafft, die Operation |= unmöglich zu machen in Fällen, 
in den sie definitv falsch ist, ist das in meinen Augen eine starke 
Verbesserung.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Wilhelm M. schrieb:
> Ich habe sogar ein Beispiel gebracht, wie es besser geht.
1. Wo?
2. Das würde ich mal als klassische Lüge bezeichnen.

Und ja, ich weiß schon was jetzt folgt!
Wie so häufig, wenn es dir mal wieder gelungen ist einen Thread zu 
kapern.
Das übliche für blöd erklären.
Da scheinst du ja irgendwie drauf angewiesen zu sein.

Bitte erfülle meine Erwartungen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Wie so häufig, wenn es dir mal wieder gelungen ist einen Thread zu
> kapern.

Der TO hat sein Thread selbst gekapert:

Beitrag "Bitte um Hilfe bei der Programmierung von AVR8-Mikrocontrollern in C : Interrupt Flag löschen"

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Wilhelm M. schrieb:
> Der TO hat sein Thread selbst gekapert

Hmmm.....
So wie du eine eigene Bedeutung von "Beispiel" zu haben scheinst, willst 
du auch "kapern" mit einer eigenen versehen.

Hier mal die Bedeutung von "kapern":
> übertragen: etwas übernehmen, sich in Besitz eines (fremden) Guts setzen

Wilhelm M. schrieb:
> Der TO
Dem TO gehört der Thread schon, seit er ihn angelegt hat.
TO == Thread Owner
Owner == Eigentümer/Besitzer

Dass man dir sowas erklären muss, ist ganz schön verblüffend für mich.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Dem TO gehört der Thread schon, seit er ihn angelegt hat.
> TO == Thread Owner
> Owner == Eigentümer/Besitzer
>
> Dass man dir sowas erklären muss, ist ganz schön verblüffend für mich.

Ach, das Leben hält auch für Dich einige Überraschungen bereit.

An welcher Stelle hat denn die Übernahme statt gefunden?

von Georg M. (g_m)


Lesenswert?


Beitrag #7516343 wurde von einem Moderator gelöscht.
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Fenton G. schrieb:
> Bernd S. schrieb:
>> if( TIFR3 & OCF3A ) {
>
> Die Zeile kommt mir verdächtig vor. Soll die das OCF3A Bit (Bit 1 im
> TIFR3, Atmega2560) abfragen oder das TOV3 im Bit 0?
>
Bei dem von mir gewähltem CTC-Mode 4, wird kein Overflow Flag gesetzt, 
da ich nicht bis MAX ( 0xFFFF ) hochzähle. Bzw. dieses Flag wird 
wahrscheinlich einmalig gesetzt.


Bernd_Stein

von Spess53 .. (hardygroeger)


Lesenswert?

Hi

>Bei dem von mir gewähltem CTC-Mode 4, wird kein Overflow Flag gesetzt,

Wie kommst du auf das schmale Brett?

Lies dir mal (S.145-!46)  "17.9.2 Clear Timer on Compare Match (CTC) 
Mode" durch.

Da steht genau drin wann der Overflow-Flag gesetzt wird.

Kleiner Tip: OCRnA (mit n= 1, 3, 4, oder 5)  bestimmt den MAX-Wert und 
damit die CTC-Frequenz.

MfG Spess

von Fenton G. (fenton_g)


Lesenswert?

Bernd S. schrieb:
> Fenton G. schrieb:
>> Bernd S. schrieb:
>>> if( TIFR3 & OCF3A ) {
Bernd S. schrieb:
> Bei dem von mir gewähltem CTC-Mode 4, wird kein Overflow Flag gesetzt,


Ich wollte eher darauf hinaus, ob es nicht statt:
if( TIFR3 & OCF3A ) {
besser
if( TIFR3 & (1<<OCF3A) ) {
heißen sollte?

von Falk B. (falk)


Lesenswert?

Fenton G. schrieb:
> Ich wollte eher darauf hinaus, ob es nicht statt:
> if( TIFR3 & OCF3A ) {
> besser
> if( TIFR3 & (1<<OCF3A) ) {
> heißen sollte?

Mit Sicherheit, denn die Bitmanipulation funktioniert nur so beim 
avr gcc / Arduino.

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Fenton G. schrieb:
>> Ich wollte eher darauf hinaus, ob es nicht statt:
>> if( TIFR3 & OCF3A ) {
>> besser
>> if( TIFR3 & (1<<OCF3A) ) {
>> heißen sollte?
>
> Mit Sicherheit, denn die Bitmanipulation funktioniert nur so beim
> avr gcc / Arduino.

Und so hat er tatsächlich TOV3 getestet ;-)

Und schon wieder ein Argument aus der Praxis, dass man die Operationen 
"&" oder auch "&=" bzw. "|" und "|=" für (solche) Register nicht möglich 
sein sollten.

S.a. 
Beitrag "Re: Bitte um Hilfe bei der Programmierung von AVR8-Mikrocontrollern in C"

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Wilhelm M. schrieb:
> Und so hat er tatsächlich TOV3 getestet ;-)
>
> Und schon wieder ein Argument aus der Praxis, dass man die Operationen
> "&" oder auch "&=" bzw. "|" und "|=" für (solche) Register nicht möglich
> sein sollten.

Gute Idee! Noch eine gute Idee: Mit Besteck kann man auch jede Menge 
gefaehrliche Operationen vollführen: Messer sind toedliche Stichwaffen, 
mit Gabeln kann man sehr schmerzhaft pieksen, sogar mit Loeffeln kann 
man sich die Augen ausloeffeln.
Also mal wieder ein Argument dafuer, Nahrung nur aus einem Trog, ohne 
weitere Hilfsmittel, zu sich zu nehmen und Besteck abzuschaffen.

Ich weiss schon, warum ich im 3. Post schrub, dass der TO da nix machen 
kann...

Gruss
WK

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Und schon wieder ein Argument aus der Praxis, dass man die Operationen
> "&" oder auch "&=" bzw. "|" und "|=" für (solche) Register nicht möglich
> sein sollten.

Deinen Gedankengang kann ich nicht nachvollziehen. Ich halte es eher für 
einen strategischen Fehler, dass Atmel (bzw. Microchip) diese Flags wie 
OCF3A als Bitnummer statt als Bitmaske definiert. Dann könnte man sich 
diese Shifterei wie (1 << OCF3A) von vornherein sparen.

Beim STM32 ist das anders. Die hier vorzufindenden Konstanten (CMSIS, 
StdLib, HAL) für die Register sind in der Regel Bitmasken und nicht 
Bitnummern. Da zieht Dein Argument erst gar nicht bzw. wirkt es eher 
deplaziert.

: Bearbeitet durch Moderator
von Roland F. (rhf)


Lesenswert?

Hall,
Wilhelm M. schrieb:
> Und schon wieder ein Argument aus der Praxis, dass man die Operationen
> "&" oder auch "&=" bzw. "|" und "|=" für (solche) Register nicht möglich
> sein sollten.

Es ist eher ein Argument dafür, das sich Bernd endlich mal ein 
C-Lehrbuch kauft und es von vorn bis hinten durcharbeitet. So lange er 
nicht weiß was er eigentlich tut, ist jede zusätzliche Abstraktion von 
letztlich grundlegenden Befehlen völlig sinnlos.

rhf

von Harald K. (kirnbichler)


Lesenswert?

Frank M. schrieb:
> Ich halte es eher für
> einen strategischen Fehler, dass Atmel (bzw. Microchip) diese Flags wie
> OCF3A als Bitnummer statt als Bitmaske definiert.

Das Argument, warum das gemacht wird, ist eine aus der vorderen 
Altsteinzeit. So kann man nämlich in Assembler die gleichen 
Definitionsdateien wie in C verwenden, wenn man die Bitoperationen SBI 
und CBI benutzt, die es nur für die ersten 32 Adressen im Adressraum 
gibt.

Deswegen werden ewiglange Shiftketten hingeschrieben. Überall. Nur 
deswegen.

(Und gerne wird auch eine 0 geshiftet, weil das ja "übersichtlicher" 
ist)

/semirant

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Deinen Gedankengang kann ich nicht nachvollziehen. Ich halte es eher für
> einen strategischen Fehler, dass Atmel (bzw. Microchip) diese Flags wie
> OCF3A als Bitnummer statt als Bitmaske definiert. Dann könnte man sich
> diese Shifterei wie (1 << OCF3A) von vornherein sparen.

Ist halt Konvention bei Atmel.

Wenn man es nicht weiß, muss man es halt lernen.

von Falk B. (falk)


Lesenswert?

Wilhelm M. schrieb:
> Und schon wieder ein Argument aus der Praxis, dass man die Operationen
> "&" oder auch "&=" bzw. "|" und "|=" für (solche) Register nicht möglich
> sein sollten.

Stimmt. Aber C war schon immer ein Rasiermesser, das in fähige Hände 
gehört.

von Falk B. (falk)


Lesenswert?

Frank M. schrieb:
> Deinen Gedankengang kann ich nicht nachvollziehen. Ich halte es eher für
> einen strategischen Fehler, dass Atmel (bzw. Microchip) diese Flags wie
> OCF3A als Bitnummer statt als Bitmaske definiert.

Ist historisch so gewachsen, weil die Header auch für Assembler nutzbar 
sind bzw. waren. Und der AVR Assembler braucht für seine Bitoperationen 
halt die Nummer.

> Dann könnte man sich
> diese Shifterei wie (1 << OCF3A) von vornherein sparen.

Stimmt.

Beitrag "Re: XC8 compiler - Register schreiben wie bei Atmel"

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Stimmt.
> Beitrag "Re: XC8 compiler - Register schreiben wie bei Atmel"

Ich hatte da bereits 2014 mal einen Konzept-Vorstoß gemacht, wie man die 
AVR-Register-Bits fest an die zugehörigen Register bindet, um die 
Anwendung von falschen Bits in falschen Registern direkt auszuschließen:

Beitrag "AVR-Register als Bitfields"

Leider wäre das für micht allein zuviel Arbeit gewesen, für alle AVRs 
die entsprechenden Header-Dateien zu erzeugen. Deshalb habe ich das 
Konzept nicht weiter verfolgt.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Falk B. schrieb:

> Ist historisch so gewachsen, weil die Header auch für Assembler nutzbar
> sind bzw. waren. Und der AVR Assembler braucht für seine Bitoperationen
> halt die Nummer.

Also, ganz so ist das nicht.

Erstens wäre es problemlos möglich gewesen, die Header so zu generieren, 
dass sowohl Bitnummer als auch Bitmaske darin sind, so wird es 
schließlich heute für die neueren AVR8 auch durchgängig getan 
(Symbol-Suffix _bp bzw. _bm).

Und zweitens käme der AVR-Assembler auch allein mit der Maske zurecht. 
Er bietet nämlich u.a. die Builtin-Funktion Log2.

Also: woran es auch immer lag: der AVR-Assembler jedenfalls war nicht 
schuld.

von Harald K. (kirnbichler)


Lesenswert?

Ob S. schrieb:
> Und zweitens käme der AVR-Assembler auch allein mit der Maske zurecht.
> Er bietet nämlich u.a. die Builtin-Funktion Log2.

Schon immer?

von Ob S. (Firma: 1984now) (observer)


Angehängte Dateien:

Lesenswert?

Harald K. schrieb:
> Ob S. schrieb:
>> Und zweitens käme der AVR-Assembler auch allein mit der Maske zurecht.
>> Er bietet nämlich u.a. die Builtin-Funktion Log2.
>
> Schon immer?

Keine Ahnung, ob das "schon immer" so war, auf jeden Fall schon sehr 
lange, ganz sicher vor der Einführung des AVR Assembler 2 . Siehe 
angehängten Auszug aus der Hilfe zum Studio4.

von Sebastian W. (wangnick)


Lesenswert?

Harald K. schrieb:
> (Und gerne wird auch eine 0 geshiftet, weil das ja "übersichtlicher"
> ist)

Also dass man eine 1 der Konsistenz wegen um 0 binäre Stellen shiftet, 
ok. Aber eine 0 shiften?

LG, Sebastian

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sebastian W. schrieb:
> Aber eine 0 shiften?

Ja, das sieht man öfters in diversen Quellcodes. Es soll ausdrücken, 
dass das genannte Bit eben nicht gesetzt werden soll.

Beispiel:
1
TCCR0A |= (1 << COM0A1) | (0 << COM0A0);

Diese Methode ist daher eher für den geneigten Leser und nicht als 
Anweisung für den Compiler gedacht.

: Bearbeitet durch Moderator
von Sebastian W. (wangnick)


Lesenswert?

Frank M. schrieb:
> Ja, das sieht man öfters in diversen Quellcodes. Es soll ausdrücken,
> dass das genannte Bit eben nicht gesetzt werden soll.

Stimmt, so was hab ich auch schon gesehen.

LG, Sebastian

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Sebastian W. schrieb:
> Frank M. schrieb:
>> Ja, das sieht man öfters in diversen Quellcodes. Es soll ausdrücken,
>> dass das genannte Bit eben nicht gesetzt werden soll.
>
> Stimmt, so was hab ich auch schon gesehen.

Ich mach soetwas zu dokumentationszwecken auch des öfteren - und werde 
prompt von Lintern angemotzt, weil ich sinnlosen Code schreibe 🙈😂

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Mampf F. schrieb:
> und werde
> prompt von Lintern angemotzt, weil ich sinnlosen Code schreibe
Womit ihm auch recht hat!


Das ist eine der Angelegenheiten, wo es (min.) 2 Wahrheiten gibt, die 
beide ihre begründbare Berechtigung haben, aber sich doch widersprechen.

von Martin H. (horo)


Lesenswert?

Frank M. schrieb:
> Ich hatte da bereits 2014 mal einen Konzept-Vorstoß gemacht, wie man die
> AVR-Register-Bits fest an die zugehörigen Register bindet, um die
> Anwendung von falschen Bits in falschen Registern direkt auszuschließen:
>
> Beitrag "AVR-Register als Bitfields"
>
> Leider wäre das für micht allein zuviel Arbeit gewesen, für alle AVRs
> die entsprechenden Header-Dateien zu erzeugen. Deshalb habe ich das
> Konzept nicht weiter verfolgt.

WOW! Gerade in meiner Mittagspause gelesen - schade dass die gute Idee 
im Sande verlaufen ist.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Frank M. schrieb:
> Ich hatte da bereits 2014 mal einen Konzept-Vorstoß gemacht, wie man die
> AVR-Register-Bits fest an die zugehörigen Register bindet, um die
> Anwendung von falschen Bits in falschen Registern direkt auszuschließen

Soweit mir bekannt erfolgt bei Bitfields ein read-modify-write Zugriff. 
Das ist bei Flag und PINX Registern eher nicht gewünscht, bzw. gar 
problematisch. Ein einfaches write ist angemessener.

: Bearbeitet durch User
Beitrag #7517718 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Frank M. schrieb:
>> Ich hatte da bereits 2014 mal einen Konzept-Vorstoß gemacht, wie man die
>> AVR-Register-Bits fest an die zugehörigen Register bindet, um die
>> Anwendung von falschen Bits in falschen Registern direkt auszuschließen
>
> Soweit mir bekannt erfolgt bei Bitfields ein read-modify-write Zugriff.

Genau. Also Blödsinn, dass so zu machen.

Beim AVR gibt es nur rc_w1 flag register.
Bei rc_w0 wäre es zudem vollkommen falsch, weil noch ein AND im rmw 
versteckt ist.

Ähnlich einem "|= oder &=" bei einem Flag-Register.

Deswegen: bit-fields sind für Register-Abstraktion vollkommen 
ungeeignet.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Arduino F. schrieb:

> Soweit mir bekannt erfolgt bei Bitfields ein read-modify-write Zugriff.

Das mag ja allgemein so stimmen, beim AVR-gcc (und nur dafür war das 
Konzept angedacht!) stimmt es jedenfalls nicht.

Assembler-Outputs sind im verlinkten Thread durchaus angegeben, die das 
Gegenteil belegen, z.B. hier:

Beitrag "Re: AVR-Register als Bitfields"

Auszug:
1
    BFM_PORTB5 = 1;         // BFM-Version
ergibt:
1
     sbi  0x05, 5
Und:
1
    BFM_PORTB5 = 0;         // BFM-Version
ergibt:
1
     cbi  0x05, 5

Ich sehe da keinen read-modify-write-Zugriff.

Wilhelm M. schrieb:
> Deswegen: bit-fields sind für Register-Abstraktion vollkommen
> ungeeignet.

Bit-fields sind für so ziemlich alles ungeeignet, da sie grundsätzlich 
nicht portabel sein können. Das habe ich schon oft in einigen Threads 
ausdrücklich betont - auch in Threads, wo Du ebenso tätig warst. Ich 
benutze sie daher grundsätzlich nicht, da ich immer möglichst portabel 
(und auch Prozessor-Familien-übergreifend) programmiere.

Betrachte den verlinkten Thread bitte lediglich als Demonstration, wie 
man es konkret für AVR und avr-gcc hätte machen können. Ich habe dann 
schließlich davon abgesehen, es durchzuziehen: einmal aus Zeitgründen, 
zum anderen wegen zu vielen speziellen Voraussetzungen über die 
Verhaltensweise des avr-gcc. Das geht viel zu schnell in die Hose, 
sobald sich da etwas beim avr-gcc geändert hätte.

Bestimmt kannst Du mit C++ einen registersicheren Zugriff auf die 
AVR-Register konstruieren. Leider kommt in dieser Richtung nix von Dir. 
Es wäre doch ganz toll, wenn man das Thema ein für allemal erschlagen 
könnte. Ich kenne nämlich allzuviele Threads, wo der TO mit den falschen 
Konstanten auf die falschen AVR-Register zugegriffen hat - einfach, weil 
ein und dieselben Bits bei verschiedenen AVRs teilweise auch in 
verschiedenen Registern gehalten werden.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Frank M. schrieb:
> Leider kommt in dieser Richtung nix von Dir.

Ja, das ist schade...
Dabei gibts doch hier ein so schönes Wiki wo man das gut unterbringen 
könnte, damit da jeder was von hat.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Ich sehe da keinen read-modify-write-Zugriff.

Oh ha. Dachte Du kennst Dich aus?
Probiere das mal mit einem SFR mit einer Adresse >= 0x32. Da geht doch 
sbi/cbi nicht mehr.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Frank M. schrieb:
> Assembler-Outputs sind im verlinkten Thread durchaus angegeben, die das
> Gegenteil belegen,

Ist es denn wirklich so, dass alle Flag und PINX Register im Bereich bis 
zu Adresse 0x1F zu finden sind?
Bei allen betreffenden AVR?

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Bit-fields sind für so ziemlich alles ungeeignet, da sie grundsätzlich
> nicht portabel sein können.

Portable müssten sie auch gar nicht sein, weil sie eh 
compiler/mcu-spezifisch sind. Sie müssten nur so funktionieren, wie man 
sich das wünscht. Und das tun sie auch ganz abseits von 
Portabilitätsaspekten nicht.

Und falls jemand sogar
1
    BF_TCCR0A.wgm0 &= 1;

statt
1
    BF_TCCR0A.wgm0 = 1;

schreibt, kommt gar doppelter Bullshit dabei heraus.

Also, mit Bitfields machst Du alles nur noch schlimmer.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Wilhelm M. schrieb:
> Frank M. schrieb:
>> Ich sehe da keinen read-modify-write-Zugriff.
>
> Oh ha. Dachte Du kennst Dich aus?
> Probiere das mal mit einem SFR mit einer Adresse >= 0x32. Da geht doch
> sbi/cbi nicht mehr.

Sorry, muss natürlich 0x20 heißen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Bestimmt kannst Du mit C++ einen registersicheren Zugriff auf die
> AVR-Register konstruieren.

Ja, das kann man.

> Leider kommt in dieser Richtung nix von Dir.

Das habe ich mittlerweile in diesem Forum aufgegeben.

Letztlich benutzen wir einen kompletten rewrite der AVR-Header in C++. 
Darin finden sich für Register der internen Peripherie Klassen, die auf 
die passenden Adressen gemappt werden. Die Elemente der Klassen sind im 
wesentlichen eines Typs der drei templates FlagRegister<>, 
ControlRegister<> und DataRegister<>. Parametriert sind diese templates 
mit den scoped-enums der möglichen Bits bzw. Bit-Kombinationen.

Damit kommen dann Konstrukte wie
1
...
2
mcu_adc()->intflags.testAndReset<intFlags_t::isReady>([&]{
3
    f();
4
});
5
...
6
mcu_adc()->ctrla.add<ctrla_t::leftadj>();
7
...
zustande.
Da diese etwas geschwätzige Art der Notation hier kaum jemanden gefällt, 
ist es müßig, dass hier zu präsentieren.

Jedoch: der Vorteil ist ganz klar: alles hier gezeigten Fehler werden 
vermieden.

Die einzige "Fehlerquelle", die bleibt, ist, falls man
1
mcu_adc()->ctrla.add<ctrla_t::freerun>();

meint, aber dann
1
mcu_adc()->ctrla.add<ctrla_t::leftadj>();

schreibt. Aber gegen semantische Fehler (WYMIWYG) ist keine Kraut 
gewachsen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Bei den STMs etwa ist das Problem schon wesentlich gemildert durch die 
bessere Definition in den Headern:
1
            ADC1->CR |= ADC_CR_ADSTART;

Die Nomenklatur ist wesentlich besser. Es verhindert zwar keine Fehler, 
aber die Fehler werden weniger oft gemacht.

von Stefan F. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> mcu_adc()->intflags.testAndReset<intFlags_t::isReady>([&]{
>     f();
> });

Schreibe das mal in eine Stellenausschreibung. Wir suchen Sie als C++ 
Programmierer, wenn sie diesen Code verstehen und pflegen können.

So kommt man dann zum "Fachkräftemangel".

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan F. schrieb:
> Wilhelm M. schrieb:
>> mcu_adc()->intflags.testAndReset<intFlags_t::isReady>([&]{
>>     f();
>> });
>
> Schreibe das mal in eine Stellenausschreibung. Wir suchen Sie als C++
> Programmierer, wenn sie diesen Code verstehen und pflegen können.
>
> So kommt man dann zum "Fachkräftemangel".

Es würde tatsächlich funktionieren: es kommen nur noch die fähigen ;-)

von Stefan F. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Es würde tatsächlich funktionieren: es kommen nur noch die fähigen ;-)

Ach ja?

Jeder dritte Neuntklässler erfüllt nicht die minimalen Anforderungen ans 
Leseverständnis. Jeder zweite Fällt in der Theoretischen Fahrprüfung 
durch.

Fällt dir was auf?

Wer denkt, dass die Menschen immer intelligenter werden und immer 
komplexere Dinge beherrschen, der irrt gewaltig. Tatsächlich passiert 
gerade das Gegenteil. Wer das ignoriert hat bald kein Personal mehr.

Schau dir mal den Film Idiocracy an. Das sollte mal eine Komödie sein, 
heute wirkt er jedoch gar nicht mehr belustigend.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Stefan F. schrieb:
> Wilhelm M. schrieb:
>> Es würde tatsächlich funktionieren: es kommen nur noch die fähigen ;-)
>
> Ach ja?
>
> Jeder dritte Neuntklässler erfüllt nicht die minimalen Anforderungen ans
> Leseverständnis.

Woran das wohl liegt . . . ?

> Jeder zweite Fällt in der Theoretischen Fahrprüfung
> durch.

Ist doch nur Theorie! Wer braucht die schon in der Praxis! ;-)

> Wer denkt, dass die Menschen immer intelligenter werden und immer
> komplexere Dinge beherrschen, der irrt gewaltig. Tatsächlich passiert
> gerade das Gegenteil. Wer das ignoriert hat bald kein Personal mehr.

Spätrömische Dekandenz. Wie amüsieren und konsumieren uns dumm und 
dämlich, im wahrsten Sinne des Wortes. Aldous Huxley hatte Recht! Orwell 
nur zum Teil.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Wilhelm M. schrieb:

> Da diese etwas geschwätzige Art der Notation hier kaum jemanden gefällt,
> ist es müßig, dass hier zu präsentieren.

Geschwätzig sind sie, das ist unübersehbar. Darüber hinaus aber auf 
unangenehme Art geschwätzig. Trotz ihrer Geschwätzigkeit ist nämlich für 
den geneigten Leser nicht gerade schnell zu erkennen, was der Kram 
eigentlich tut.

Sprich: die typischen Auswüchse einer akademisch gedunsenen 
WO-Programmiersprache. Macht es nur für den Compiler einfach. Aber ja: 
der kann dann auch semantische Fehler finden. Mit ein wenig Glück, wenn 
wenigstens alles syntaktisch richtig eingetippt ist.

Ein Zeichen versehentlich falsch eingetippt oder vergessen oder zuviel 
und der Programmierer wird mit Fehlermeldungen geradezu geflutet, die 
aber überwiegend absolut nicht hilfreich sind.

Oder es gibt mal wieder eine neuer Version dieser Sprache. Na dann wird 
es u.U. richtig lustig den "alten" (vielleicht drei Jahre oder so) Code 
zu kompilieren. Da braucht man schon ein ordentliches Storage-System mit 
Fiber-Channel-Anbindung, um auch nur die Fehlermeldungen in akzeptabler 
Zeit wegzuschreiben.

Nö, das kann nicht die Zukunft des Programmierens sein.

von Gerhard O. (gerhard_)


Lesenswert?

Also, ganz kann ich die ganze Theoretisiererei wie sie hier im Forum oft 
vorkommt, nicht nachvollziehen.

Ich beschäftige mich schon seit einigen Jahrzehnten mit uC und wußte 
nicht, daß die Art der Manipulierung der SFRs in 2023 einen 
krisenartigen Charakter annehmen würde.

Damals, sah man sich die entsprechenden Header Files an und wußte im 
Zusammenhang mit dem Datenblatt vollkommen Bescheid. Und jetzt wird das 
alles so aufgebauscht um zu Zeigen wie man unverständlichen Code baut. 
Da komme ich jedenfalls nicht mehr mit. Die Welt der uC Programmierung 
war damals für mich auf diesen Gebiet vollkommen in Ordnung. Wenn ich 
mir die für Uneingeweihte oft vollkommen unleserlich und verständliche 
C++ Konstrukte ansehe, da finde ich die alte C Schreibweisen wesentlich 
klarer im Ausdruck.

In Fakt, C Konstrukte sind oft wesentlich klarer zu verstehen, als die 
abstrakten C++ Konstrukte, die nur nach extensiver Recherche von 
Nichtversierten nachvollziehbar sind.

Es gibt viele kompetente Fachleute, die nur gelegentlich, 
projekt-orientiert programmieren, um irgend etwas Notwendiges am Laufen 
zu haben. Solche Leute tun sich da mit klarer, einfacherer 
Ausdrucksweise wesentlich leichter, ihren eigenen Code nach langer 
Abwesenheit zu verstehen. Sicher, wer sich mit C++ tagtäglich befasst 
und sich damit seine Brötchen verdient, kommt damit klar und ist damit 
zu Hause. Aber nicht jeder ist ein toller Programmierhecht.  Ich wage 
aber zu behaupten, daß 90% der Forumleserschaft sich nicht in dieser 
Kategorie befindet und für sie eine klare, verständliche 
Programmier-Ausdrucksweise besser dienlich ist. Für diejenigen, die auch 
ein anderes Technikleben haben, als 10 Stunden pro Tag zu programmieren, 
werden meine Ansicht wahrscheinlich besser verstehen.

Wie kommt es, daß ich mir z.B. CodeVisionAVR, CCS oder Keil zulegen 
kann, gute Referenzdokus bekomme und damit alleine alles Notwendige in 
einem gut strukturierten Referenzbuch finden zu können? Auch ein 
Anfänger könnte damit klarkommen, wenn er sich dort durcharbeitet. Mit 
GCC muß man tief tauchen, um Ordnung in den Dokus zu finden. GCC mag ja 
sehr fähig sein, ist aber umständlich zu lernen und die notwendigen und 
klaren Dokus zu finden, ist umständlich. Oft sind auch deren Dokus nur 
schwer verdaulich und bedürfen viel Kreuzsuche und Recherche. Und gute 
Bücher findet man auch nicht immer leicht.

Ich verstehe ohne große Recherche C, Pascal, Fortran, BASIC, also 
Sprachen der früheren Generation. Aber wenn man sich viele esoterische 
C++ Programme anschaue, die sich auf die aktuellen C++ Standards 
stützen, da ist Vieles dabei, daß man als nicht-Fachmann recherchieren 
muß, weil die gewünschte Funktion nicht länger aus ihrem Konstrukt noch 
direkt lesbar ist. Das ist der große Unterschied zu früher, wo K&R 
ausreichte.

Früher konnte man sich eine Programmiersprache mit vollständiger, 
gebundener Dokus zulegen und die Eigenschaften des Produkts lernen ohne 
umständlich im Internet herumsuchen zu müssen oder Bücher kaufen zu 
müssen.

C++ hat Vieles was nützlich ist, aber auch dort sollte es möglich sein, 
einigermassen lesbaren Sourcecode zu erstellen.

Viele uC Anwendungen lassen sich durchaus noch klar und sauber in frühen 
C-Stil realisieren.

Ohne Grund zügelt z.B. MISRA auch nicht die Freiheiten im Gebrauch der 
Sprachen.

Zum Glück kann man sich meistens die Programmiersprache noch selber 
aussuchen. Ich bin froh, daß ich in diesem Rennen nicht mehr mitmachen 
muß. Das Design und Programmieren von uC soll doch eigentlich ansprechen 
und Freude machen und keine Zäsur sein.

Ist nur meine Ansicht.


Gerhard

von Wilhelm M. (wimalopaan)


Lesenswert?

Stefan F. schrieb:
> Wilhelm M. schrieb:
>> Es würde tatsächlich funktionieren: es kommen nur noch die fähigen ;-)
>
> Ach ja?
>
> Jeder dritte Neuntklässler erfüllt nicht die minimalen Anforderungen ans
> Leseverständnis. Jeder zweite Fällt in der Theoretischen Fahrprüfung
> durch.
>
> Fällt dir was auf?

Ja. Und zwar, dass ich noch nie irgendwelche unterdurchschnittlichen 
Neuntklässler einstellen wollte.

> Wer denkt, dass die Menschen immer intelligenter werden und immer
> komplexere Dinge beherrschen, der irrt gewaltig.

Sie werden aber auch nicht dümmer.

> Tatsächlich passiert
> gerade das Gegenteil. Wer das ignoriert hat bald kein Personal mehr.

Probleme habe nur die, die tradierten Vorstellungen von Firmenkultur 
oder Exzellenz anhaften, oder eben glauben, mit irgendwelchen 
langweiligen Stellenanzeigen der Besten Aufmerksamkeit zu erregen.

Aber echt jetzt: Du musst aufpassen, dass Dich hier nicht Arduino F. 
wegen Thread-Kaperns anmacht ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:
> Das ist der große Unterschied zu früher, wo K&R
> ausreichte.
>
> Früher konnte man sich eine Programmiersprache mit vollständiger,
> gebundener Dokus zulegen und die Eigenschaften des Produkts lernen ohne
> umständlich im Internet herumsuchen zu müssen oder Bücher kaufen zu
> müssen.

Oh man, schon wieder so ein Beitrag nach dem Motto: alte Herren erzählen 
von guten alten Sandkastenzeit.

TLDR

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Gerhard O. schrieb:
> C++ hat Vieles was nützlich ist, aber auch dort sollte es möglich sein,
> einigermassen lesbaren Sourcecode zu erstellen.
>
> Viele uC Anwendungen lassen sich durchaus noch klar und sauber in frühen
> C-Stil realisieren.

Das kann man auch gut kombinieren.
1
#include <CombieAdc.h>
2
using Combie::Adc;
3
4
Adc adc;
5
6
void setup() 
7
{
8
   Serial.begin(9600);
9
10
   adc  .enable()
11
        .setClockDivisor(Adc::DIV_128)
12
        .setReference(Adc::REF_11)
13
        .setSource(Adc::MUX_ADC0); 
14
}
15
16
void loop() 
17
{
18
  Serial.println(adc);
19
  delay(1000);
20
}

Es gibt schon nette Features, die C nicht kann:
1
  Serial.println(adc[Adc::MUX_ADC0]);
2
  Serial.println(adc[Adc::MUX_ADC2]);
3
  Serial.println(adc[Adc::MUX_ADC4]);

von Gerhard O. (gerhard_)


Lesenswert?

Arduino F. schrieb:
> Das kann man auch gut kombinieren.

Hallo,

ja. Danke für das Beispiel. Mit dieser Vorgehensweise habe auch ich kein 
Problem und sieht sehr sauber aus.

Ist die ADC Lib ein Eigenbau oder Github Public?

Gerhard

von Arduino F. (Firma: Gast) (arduinof)


Angehängte Dateien:

Lesenswert?

Gerhard O. schrieb:
> Eigenbau

Eigenbau
Ist im inneren etwas unaufgeräumt, deckt aber die meisten AVR der 
Arduinowelt ab.

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

Arduino F. schrieb:
> Gerhard O. schrieb:
>> Eigenbau
>
> Eigenbau
> Ist im inneren etwas unaufgeräumt, deckt aber die meisten AVR der
> Arduinowelt ab.

OK. Sieht im Inneren doch ganz ordentlich aus.
(Kommt mir zumindest so vor:-) )

In den meisten meiner Programme lasse ich den ADC im Hintergrund als 
Multikanal ISR mit Mittlung laufen und habe den ADC immer anhand des 
DaBlas mit den SFRs konfiguriert.

Schön einstellen, lässt sich alles mit Deiner Lösung auf alle Fälle und 
ist sehr übersichtlich.

Gerhard

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Gerhard O. schrieb:
>> Eigenbau
>
> Eigenbau
> Ist im inneren etwas unaufgeräumt, deckt aber die meisten AVR der
> Arduinowelt ab.

Was machst Du mit µC, die mehr als einen ADC haben, z.B. die 
tiny1-Serie?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich verstehe immer nicht was die ganze Diskussion um C und C++ immer 
soll. Gerhard schwelgt in alten Erinnerungen die niemanden vorwärts 
bringen. C ist stehen geblieben, es sollte auch für C einmal einer neuer 
Sprachstandard kommen von dem ich bis heute nichts gelesen habe. Im 
Gegensatz dazu entwickelt sich C++ ständig weiter. Man muss sich 
entscheiden ob man stehen bleiben möchte oder die nützlichen Dinge einer 
sich fortlaufenden Sprache wie C++ anzunehmen. Man muss ja nicht den 
unleserlichsten Code schreiben, aber Vorteile bringt C++ schon. Man kann 
das nutzen was einem Vorteile bringt.
Wie letztens erst festgestellt sind #defines zum Bsp. großer Mist. 
Leider kommt man davon wohl auf lange Sicht nicht los, weil das in den 
Headerfiles drin steckt. Außer man schreibt Eigene. C++ ist nun einmal 
auf Datentypsicherheit ausgelegt. Das ist die Grundlage. Das muss man 
einfach verstehen wollen.
Wer immer wieder von früher erzählt, da weiß ich nicht was ich dazu 
sagen soll. Fakt ist doch:
Wer C programmieren möchte der soll es machen.
Wer C++ programmieren möchte der soll es machen.
Wer Assembler programmieren möchte der soll es machen.
Wer ... programmieren möchte der soll es machen.

Aber lasst doch bitte diese sinnfreie Diskussion das genau die Sprache 
die einem nicht gefällt ausgerechnet Teufelszeug sein soll.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Wilhelm M. schrieb:
> Du
Mach dir mal keine unnützen Sorgen....
Du könntest, anstatt zu nörgeln, auch mal zeigen wie du ALLE AVR 
abdeckst.

Merksatz:
Nörgeln ist einfach, Nörgler vom nörgeln abzubringen eher nicht.

Einen zufriedengestellten Nörgler?
Das riecht nach "Paradoxie"

von Falk B. (falk)


Lesenswert?

Veit D. schrieb:
> ich verstehe immer nicht was die ganze Diskussion um C und C++ immer
> soll.

Ich schon.

> Gerhard schwelgt in alten Erinnerungen die niemanden vorwärts
> bringen.

Nein, das allein ist es nicht. Es geht darum, daß man es mit der 
"Moderne" und Abstraktion gerade bei C++ GEWALTIG übertreiben KANN! Und 
genau DAS wird kritisiert.

> C ist stehen geblieben,

Ausgereift. Irgendwann ist ein Konzept erschöpft. Ist aber auch OK. Die 
ISS ist auch ausgereift und wird in absehbarer Zeit verschrottet. Oder 
doch nicht? Schau mer mal.

> es sollte auch für C einmal einer neuer
> Sprachstandard kommen von dem ich bis heute nichts gelesen habe.

Wenn gleich natürlich in der IT Dinge, welche sich nicht erneuern, 
relativ schnell veralten und irgendwann mal weg vom Fenster sind, so ist 
es andererseits auch eine Seuche, an bewährten Dingen dauernd 
rumzuschrauben.

> Im
> Gegensatz dazu entwickelt sich C++ ständig weiter.

Mit allen Vor- und Nachteilen, allein voran, daß es immer komplexer und 
umfangreicher wird. Wer kann das WIRKLICH VOLLSTÄNDIG überblicken und in 
der Praxis auch gewinnbringend umsetzen? Ich fürchte, nur eine 
Minderheit. Das Schweizer Taschenmesser mit 100 Funktionen, das jedes 
Jahr um 10% wächst, ist sinnlos!

KISS sollte viel öfter berücksichtigt werden! Oder auf gut Deutsch.

So einfach wie möglich, so komplex wie nötig.

> Man muss sich
> entscheiden ob man stehen bleiben möchte oder die nützlichen Dinge einer
> sich fortlaufenden Sprache wie C++ anzunehmen.

Jain. Siehe oben.

> Man muss ja nicht den
> unleserlichsten Code schreiben, aber Vorteile bringt C++ schon.

Das ist glaube ich für die meisten Leute unbestritten, selbst für mich, 
der von C++ keine Ahnung hat ;-)

> Man kann
> das nutzen was einem Vorteile bringt.

Ja, aber! Siehe oben!

> Wer immer wieder von früher erzählt, da weiß ich nicht was ich dazu
> sagen soll. Fakt ist doch:
> Wer C programmieren möchte der soll es machen.
> Wer C++ programmieren möchte der soll es machen.
> Wer Assembler programmieren möchte der soll es machen.
> Wer ... programmieren möchte der soll es machen.

Alles Ok, aber nicht der Punkt. Der Punkt ist die kritische Diskussion 
um die Komplexität einer Lösung sowie deren Fehlersicherheit.

> Aber lasst doch bitte diese sinnfreie Diskussion das genau die Sprache
> die einem nicht gefällt ausgerechnet Teufelszeug sein soll.

Das hat keiner behauptet.

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> C ist stehen geblieben, es sollte auch für C einmal einer neuer
> Sprachstandard kommen von dem ich bis heute nichts gelesen habe.

Mmh ... C11, C17, C23

also, stehengeblieben ist anders.

von Hugo H. (hugo_hu)


Lesenswert?

Hier sind doch einige "verwöhnte Bürschchen" :-)

Erwartet ihr wirklich, dass der Compiler alle logischen und sachlichen 
Fehler findet und ggf. sogar noch ausbügelt?

Ich (O.K. ich nutze C nur im Hobby-Bereich) finde die Bit-Manipulationen 
für Register ganz O.K. - ich öffne parallel sowieso immer das Datenblatt 
um zu wissen, was ich tue.
Bei den XMegas (mit denen ich schon gearbeitet habe) und scheinbar auch 
neueren Tinys ist/scheint das etwas eleganter zu sein, aber mir 
zumindest erspart es nicht den Blick in das DB.

Logische Fehler erkennt wohl kaum ein Compiler sicher - zumindest keiner 
der mir bekannt ist.

Für mich. als Nicht-Experte liest und schreibt sich

TIFR3 |= 1<< OCF3A;

leichter als

mcu_adc()->intflags.testAndReset<intFlags_t::isReady>([&]{
    f();

Inhaltlich nicht vergleichbar, klar, aber die 2. Schreibweise erinnert 
mich irgendwie leicht an "Brainfuck" :-) . Wer es kann prima, für den 
der es nicht kann und warten muss weniger prima.

von Wilhelm M. (wimalopaan)


Lesenswert?

Hugo H. schrieb:
> Für mich. als Nicht-Experte liest und schreibt sich
> TIFR3 |= 1<< OCF3A;
> leichter als

Tja, und schon falsch!

von Falk B. (falk)


Lesenswert?

Hugo H. schrieb:
> Hier sind doch einige "verwöhnte Bürschchen" :-)
>
> Erwartet ihr wirklich, dass der Compiler alle logischen und sachlichen
> Fehler findet und ggf. sogar noch ausbügelt?

Compiler und Hochsprachen sind dazu da, große Datenmengen und 
Komplexitäten zu verwalten und soweit möglich, Fehler zu verhindern. 
Solche Fehler sind prinzipiell vom Compiler verhinderbar, wenn man es 
richtig macht.

> Ich (O.K. ich nutze C nur im Hobby-Bereich) finde die Bit-Manipulationen
> für Register ganz O.K. - ich öffne parallel sowieso immer das Datenblatt
> um zu wissen, was ich tue.

Das ist nicht der Punkt.

> Logische Fehler erkennt wohl kaum ein Compiler sicher - zumindest keiner
> der mir bekannt ist.

Darum geht es nicht! Es geht um die recht lockere Definition der 
Bitnamen. Ein Bit in einem Register per Namen anzusprechen, das gar 
nicht existiert, sollte nicht möglich sein! Die Steigerungsform davon 
ist, bestimmte Bits nur auf bestimmte Weise anzusprechen.

> Für mich. als Nicht-Experte liest und schreibt sich
>
> TIFR3 |= 1<< OCF3A;

Ist sachlich falsch. Die Interrupts werden so gelöscht.

TIFR3 = 1<< OCF3A;

Ja, alles wird mit Null "beschrieben", was aber in diesem Register nur 
das eine, gesetzt Bit löscht! Klingt komisch, ist aber so!

> leichter als
>
> mcu_adc()->intflags.testAndReset<intFlags_t::isReady>([&]{
>     f();

Naja, das Beispiel ist auch nicht sonderlich gut, eher dazu da zu 
zeigen, wie man es nicht "besser" machen sollte.

> Inhaltlich nicht vergleichbar, klar, aber die 2. Schreibweise erinnert
> mich irgendwie leicht an "Brainfuck" :-) . Wer es kann prima, für den
> der es nicht kann und warten muss weniger prima.

von Falk B. (falk)


Lesenswert?

Man könnte es im ollen C so machen.
1
#define clearISRflag(port, bit) port = (1<<bit)
2
clearISRflag(TIFR3, OCF3A);

Das sagt direkt, was passiert. Ja, mit den normalen AVR Headerfiles ist 
das immer noch nicht sicher, man kann da auch illegalerweise schreiben
1
clearISRflag(TIFR3, PB2);

Jetzt kann man enums erfinden, z.b.
1
typedef enum {OCF3A_f, OCF3B_f) isrflag_t;
2
const isrflag_t isrFlags;

Damit könnte man in einer einzigen Funktion alle ISR Flags sauber 
handhaben, einfach den Enum per Switch auswerten.
1
clearISRflag(OCF3A_f);

Da muss man nicht mal wissen, in welchem Register das Flag liegt!
Das ist EINE Möglichkeit, sicher nicht die beste.

von Georg M. (g_m)


Lesenswert?

Worum geht's?

von Hugo H. (hugo_hu)


Lesenswert?

Wilhelm M. schrieb:
> Tja, und schon falsch!

Ein Beispiel für die Schreibweise - nicht für den konkreten Inhalt ...

von Wilhelm M. (wimalopaan)


Lesenswert?

Hugo H. schrieb:
> Wilhelm M. schrieb:
>> Tja, und schon falsch!
>
> Ein Beispiel für die Schreibweise - nicht für den konkreten Inhalt ...

Das
1
TIFR3 |= 1<< OCF3A;

was Du geschrieben hast ist immer falsch.

Du hättest auch
1
TIFR3 |= 0xff;

schrieben können.

von Hugo H. (hugo_hu)


Lesenswert?

Wilhelm M. schrieb:
> was Du geschrieben hast ist immer falsch.

Ja, Du hast Recht.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Gegen Nichtlesen des Datenblatts bzw. Nichtverstehen der Eigenschaften 
der Hardware hilft eine Hochsprache mit Wahnsinnsfeatures ungefaehr so 
sinnvoll, wie Fritzboxeinstellungen gegen pubertierende 
Social-Media-Bratzen.

scnr,
WK

von Veit D. (devil-elec)


Lesenswert?

Falk B. schrieb:

einmal auf den Kern reduziert zitiert, hoffe das ist nicht zu kurz.

> Nein, das allein ist es nicht. Es geht darum, daß man es mit der
> "Moderne" und Abstraktion gerade bei C++ GEWALTIG übertreiben KANN! Und
> genau DAS wird kritisiert.

> Alles Ok, aber nicht der Punkt. Der Punkt ist die kritische Diskussion
> um die Komplexität einer Lösung sowie deren Fehlersicherheit.

Okay, dann habe ich den Threadverlauf falsch eingeschätzt falsch 
verstanden. Bezüglich C++ stimmt was du schreibst. Die Komplexität der 
Möglichkeiten ist extrem. Das in aller Fülle zu beherrschen ist nur noch 
was für Vollblutprogrammierer. Ich kann davon nur einen Bruchteil nutzen 
den ich verstanden habe. Paar erlernte Annehmlichkeiten möchte ich 
jedoch nicht missen.
1
"Wir leben von Möglichkeiten und sterben an Wirklichkeiten."
2
- Hans Kudszus -
Danke für deinen korrigierenden Eingriff.  :-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
>>
>> mcu_adc()->intflags.testAndReset<intFlags_t::isReady>([&]{
>>     f();
>
> Naja, das Beispiel ist auch nicht sonderlich gut, eher dazu da zu
> zeigen, wie man es nicht "besser" machen sollte.

Dass das Beispiel nicht äquivalent zu

Falk B. schrieb:
> TIFR3 = 1<< OCF3A;

ist, dürfte klar sein.

Hierfür würde man
1
timer()->intflags.reset<intflags_t::ocfb>();

schreiben. Und hierbei ist es dann egal, ob das ein rc_w0 oder rc_w1 
ist.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dergute W. schrieb:
> Gegen Nichtlesen des Datenblatts

Genau: und hier (flag-register) bleiben die Datenblätter von 
Atmel/MicroChip hinter denen von STM zurück (wobei sie wieder in anderer 
Hinsicht besser sind).

Wie gesagt, das alles ließe sich vermeiden (mit Ausnahme, dass man ggf. 
OutputCompare3 mit OutputCompare2 desselben Timers verwechselt, aber das 
ist eine andere Geschichte), wenn man verhindert, dass solche Konstrukte 
wie
1
TIFR3 |= 1<< OCF3A;

überhaupt kompilieren. Das geht mit C aber nicht.

Wenn man auf C++ umschwenkt, dann sollte man (wie in meinem Fall) die 
ganzen Header für AVR umschreiben. Dann werden solche Fehler zur 
Compilezeit ausgedeckt. Ob man dabei die "geschwätzige" Form wie in 
meinem Fall verwendet, bliebe dann dem Hersteller überlassen. Jedoch ist 
auch das nicht das Problem, weil ja die IDE das mit autocomplete 
vervollständigt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Hugo H. schrieb:
> Erwartet ihr wirklich, dass der Compiler alle logischen und sachlichen
> Fehler findet und ggf. sogar noch ausbügelt?

Ich erwarte (in diesem Fall nicht vom Compiler, sondern hier von der 
gewählten software-technischen Abstraktion der HW), dass möglichst viele 
falsche Konstrukte nicht compilieren. Denn ich habe nicht wirklich Bock 
auf Laufzeit-Debugging. D.h. der "|=" oder "&=" Operator für rc_w1 oder 
rc_w0 Flag-Register darf nicht möglich sein.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Wilhelm M. schrieb:
>> Du
> Mach dir mal keine unnützen Sorgen....

Um Dich mache ich mir schon lange keine Sorgen mehr ;-)

> Du könntest, anstatt zu nörgeln, auch mal zeigen wie du ALLE AVR
> abdeckst.

Ich habe eine Frage gestellt. Ist das für Dich auch schon nörgeln?

Du hast einen Monostate-Ansatz für Deine Klasse Adc gewählt. Wenn Du das 
erweitern möchtest, könntest Du in etwa
1
Adc adc{1, AT_TINY_1614};

verwenden.
Ich denke allerdings, dass das zu wenig effizientem Code führen wird. 
Zudem wird es schwierig, Fehler wie
1
Adc adc{2, AT_TINY_1614};

zur Compilezeit aufzudecken.

Bei mir wäre es dann
1
using adc = Adc<1, ATiny1614>;

und
1
using adc = Adc<2, ATiny1614>;

compiliert nicht.

von J. S. (jojos)


Lesenswert?

Wilhelm M. schrieb:

> Jedoch ist
> auch das nicht das Problem, weil ja die IDE das mit autocomplete
> vervollständigt.

Aber selbst dieser Luxus bleibt vielen verwehrt weil sie noch an ihrer 
Arduino IDE 1.x festhalten. Dabei hat sich gerade bei Intellisense 
soviel getan in den letzten Jahren.

von Wilhelm M. (wimalopaan)


Lesenswert?

J. S. schrieb:
> Wilhelm M. schrieb:
>
>> Jedoch ist
>> auch das nicht das Problem, weil ja die IDE das mit autocomplete
>> vervollständigt.
>
> Aber selbst dieser Luxus bleibt vielen verwehrt weil sie noch an ihrer
> Arduino IDE 1.x festhalten.

Es soll Leute geben, die immer noch ed(1) verwenden ;-)

> Dabei hat sich gerade bei Intellisense
> soviel getan in den letzten Jahren.

Vim, VSCode, ....

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Falk B. schrieb:
>> Erwartet ihr wirklich, dass der Compiler alle logischen und sachlichen
>> Fehler findet und ggf. sogar noch ausbügelt?
>
> Compiler und Hochsprachen sind dazu da, große Datenmengen und
> Komplexitäten zu verwalten und soweit möglich, Fehler zu verhindern.
> Solche Fehler sind prinzipiell vom Compiler verhinderbar, wenn man es
> richtig macht.

Nicht richtig - der Compiler wird nicht willkürlich sein Verhalten 
ändern, nur weil es für 8Bit AVR irgendwie besser - oder gar logischer - 
wäre.

Ihr müsst es halt lernen, wie es richtig geht.

: Bearbeitet durch User
Beitrag #7518207 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Mampf F. schrieb:
> der Compiler wird nicht willkürlich sein Verhalten
> ändern, nur weil es für 8Bit AVR irgendwie besser - oder gar logischer -
> wäre.

Wer hat das denn behauptet?

von Gerhard O. (gerhard_)


Lesenswert?

Moin,

Jetzt möchte ich mich mal die Frage aufwerfen, ob es nicht im Interesse 
der Klarheit und Unzweideutigkeiten besser wäre, immer mit der 
Hersteller Datenblatt Register Namenskonvention zu arbeiten.

Um beim Beispiel zu bleiben, TIFR3 ist meiner Ansicht nach eindeutiger 
als z.B. (Verzeih Wilhelm)
1
timer()->intflags.reset<intflags_t::ocfb>();
Beim Beispiel ist es nur durch Nachschauen in den Header Files 
erkenntlich, ob sich es eindeutig auf TIFR3 und OCF3A bezieht.

Jetzt würde Wilhelm argumentieren, daß sein Konstrukt damit alle 
vorhandenen Timer unterstützt. Allerdings soll das jetzt keine Kritik 
sein, weil ich mich ohne Recherche nicht gut genug auskenne, inwieweit 
GCC Header files bereitstellt. Z.b. ist "ocfb" schon definiert oder eine 
eigene Bezeichnung? Ich vermute auch, daß man tief eintauchen muß, um 
alles eindeutig nachvollziehen zu können. Ist das wichtig, wird 
wahrscheinlich gefragt werden. Nun, Wer es wirklich bestätigt wissen 
muß, tut sich bei TIFR3 leichter, weil es selbstdokumentierend ist, was 
bei der Abstraktion verloren geht.

Ich habe von Anfang an immer die direkte Hersteller Datenblatt Benamung 
der Register bevorzugt, weil es eindeutig selbstdokumentierend aufs 
Datenblatt zurückführbar ist und deshalb von mir bevorzugt wird.

Da das uC Programmieren am Ende sich immer mit seiner Hardware befasst, 
ist einfach und eindeutige, Datenblatt konforme Benamung eigentlich 
fehlervermeidend, weil nur in Zusammenarbeit mit dem Datenblatt die HW 
genau erfasst und programmiert werden kann. Die Benamung alleine ist 
dann wegen der betroffenen HW selbstdokumentierend.

Früher konnte ohnehin nur so gearbeitet werden. Da ich in der Regel 
meine HW selber entwickle, sind die Datenblätter meine 
Referenzdokumentation und nicht unmittelbar die Compilermöglichkeiten.

Deshalb könnte man auch gegenargumentieren, daß unnötige Abstraktion die 
tatsächliche HW Bezogenheit verschleiert, die dann nur durch Studium der 
relevanten Header Dateien geklärt werden können.

Die Verfechter der Abstraktion fahren dann bestimmt mit gewichtigen 
Gegenargumenten auf, warum deren Konventionen besser sind. Und sofort 
haben wir einen Glaubenskrieg:-)

Wilhelm, ich will Dich nicht (böswillig) angreifen. Es ist nur meine 
Ansicht, warum mir die traditionelle Form der datenblattgerechten SFR 
Manipulierung lieber ist, auch wenn die neuen Sprachenstandards all 
diese Abstraktionen unterstützen, die Dir gefallen.

Für mich ist uC Projekt Erstellung eine HW bezogene Aktivität, wo die 
Programmierung dieser HW eben (auch noch) notwendig ist. Dieser 
Sachverhalt kontrastiert gewaltig mit generellem Computer Programmieren, 
wo die HW nur in anderen Hinsichten relevant ist. Vielleicht kommt 
dieser Hang zur Abstraktion von daher. Meiner Ansicht nach sollte man es 
aber im uC Kontext vielleicht, im Interesse der Eindeutigkeit, nicht zu 
übertreiben.

Vielleicht bin ich wirklich um Jahrzehnte hinter den aktuellen Methoden 
die man heutzutage anwendet. Aber andrerseits habe auch ich meine 
(guten) Gründe aufgeführt warum ich das nicht unbedingt für gut finde 
und man es besser nicht so machen sollte.

Gruß,
Gerhard, der Ketzer:-)

von Falk B. (falk)


Lesenswert?

Gerhard O. schrieb:
> Moin,
>
> Jetzt möchte ich mich mal die Frage aufwerfen, ob es nicht im Interesse
> der Klarheit und Unzweideutigkeiten besser wäre, immer mit der
> Hersteller Datenblatt Register Namenskonvention zu arbeiten.

Das ist mehr als nur empfehlenswert, es ist fast alternativlos. Denn wer 
will schon für all die Register und Bits neue Namen erfinden und 
verwalten? Das ist Wahnsinn, erst recht auf größeren Controllern! Wie 
man die Namen dann in Konstrukten verwendet, ist eine andere Frage.

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:
> Um beim Beispiel zu bleiben, TIFR3 ist meiner Ansicht nach eindeutiger
> als z.B. (Verzeih Wilhelm)timer()->intflags.reset<intflags_t::ocfb>();
> Beim Beispiel ist es nur durch Nachschauen in den Header Files
> erkenntlich, ob sich es eindeutig auf TIFR3 und OCF3A bezieht.

Deine Betrachtung ist sehr zentriert auf die alten AVRs: nur dort heißt 
das Interrupt-Flag-Register des TC3 dann TIFR3, und die Bezeichnung der 
Bitnummer OCF3A für den OCA dieses Timers.

Also: wenn man sich eine sinnvolle Nomenklatur dafür überlegen würde 
seitens Atmel, dann müsste das Register TC3IF oder TC3IFR heißen und die 
Bitnummer OCA oder OCFA; die Nummer 3 ist redundant. Oder TOV statt 
TOV3.

Bei den neueren AVRs (DA, DB, ... du weißt schon) heißt das Register 
tatsächlich INTFLAGS und das Flag TCA_SINGLE_OVF (oder TCA_SPLIT_OVF) in 
den Headern, im Datenblatt dann nur OVF. Das Flag könnte auch OVF in den 
Headern heißen, wenn, ja, wenn die Timer tatsächlich so regulär 
aufgebaut wären wie bei den STM32-Familien, dann bräuchte man kein 
TCB_OVF oder TCD_OVF.

Bei den STMs wiederum heißt das entsprechende Flag-Register SR und das 
Flag immer TIM_SR_UIF, egal welcher Timer.

Also, wenn Du Dein Blick etwas weitest, erkennst Du, dass es auch 
bessere Namensschemata gibt.

Und: ich sprach davon, dass man sinnvollerweise die Header-Files der 
Hersteller ersetzt. Wenn das der Hersteller machen würde, könnte man 
auch alle Namen vereinheitlichen. Da das die Hersteller nicht tun bzw. 
es noch nicht einmal schaffen, sinnvolle C-Header-Files zu erzeugen oder 
wie bei den DA, ... reguläre Peripherie-Strukturen herzustellen, geht es 
nur mit eigenem Aufwand.

Gerhard O. schrieb:
> Wilhelm, ich will Dich nicht (böswillig) angreifen. Es ist nur meine
> Ansicht, warum mir die traditionelle Form der datenblattgerechten SFR
> Manipulierung lieber ist, auch wenn die neuen Sprachenstandards all
> diese Abstraktionen unterstützen, die Dir gefallen.

Alles perfekt: wenn Du damit zufrieden bist, ist ja alles ok.

Gerhard O. schrieb:
> Deshalb könnte man auch gegenargumentieren, daß unnötige Abstraktion die
> tatsächliche HW Bezogenheit verschleiert, die dann nur durch Studium der
> relevanten Header Dateien geklärt werden können.

Dann müssten wir bits schnitzen.

Du siehst aber schon an der Diskussion um den Mist mit dem falschen 
Statement
1
TIFR3 |= 1<< OCF3A;

das auch hier bei simplem C die Zusammenhänge nicht verstanden werden, 
obwohl jemand behauptet, ins DB zu schauen.

Also: C ist eine viel zu hohe Abstraktionsebene.

Noch schlimmer ist es nur mit dem abstrusen Vorschlag der Bit-Fields in 
C für SFR.

von A. B. (Firma: ab) (bus_eng)


Lesenswert?

Falk B. schrieb:

>ist mehr als nur empfehlenswert, es ist fast alternativlos.

Damit verewigt man die Ungeschicktheiten von Atmel, Microchip, STM ... 
in den Headern oder in den IDE's für alle Ewigkeit.

Alternative:
1
 
2
template<>
3
struct TimerRegs<3> { ...                             // ATmega1284
4
5
   enum class tmode : DataT  {
6
 // ****************
7
      wgm0                         = 1 << WGM10,      // waveform0 gen. mode TCCRA | bit0
8
      wgm1                         = 1 << WGM11,      // waveform0 gen. mode TCCRA | bit1
9
   // ----------------------------------------------- // --------------------------------
10
      wgm2                         = 1 << WGM12,      // waveform0 gen. mode TCCRB | bit3
11
      wgm3                         = 1 << WGM13,      // waveform0 gen. mode TCCRB | bit4
12
   // ----------------------------------------------- //---------------------------------
13
      Normal                       = 0,
14
      PwmPhaseCorrect8Bit          =                wgm0,
15
      PwmPhaseCorrect9Bit          =           wgm1,
16
      PwmPhaseCorrect10Bit         =           wgm1|wgm0,
17
      ClearOnCompareOCRA           =      wgm2,
18
      PwmFast8Bit                  =      wgm2|     wgm0,
19
      PwmFast9Bit                  =      wgm2|wgm1,
20
      PwmFast10Bit                 =      wgm2|wgm1|wgm0,
21
      PwmPhaseAndFreqCorrectToICR  = wgm3,
22
      PwmPhaseAndFreqCorrectToOCRA = wgm3|          wgm0,
23
      PwmPhaseCorrectToICR         = wgm3|     wgm1,
24
      PwmPhaseCorrectToOCRA        = wgm3|     wgm1|wgm0,
25
      ClearOnCompareICR            = wgm3|wgm2,
26
   // Reserved                     = wgm3|wgm2|     wgm0,
27
      PwmFastToICR                 = wgm3|wgm2|wgm1,
28
      PwmFastToOCRA                = wgm3|wgm2|wgm1|wgm0,
29
 // ------------------------------------------------------
30
      clearmask_cca                =           wgm1|wgm0,
31
 // ------------------------------------------------------
32
      clearmask_ccb                = wgm3|wgm2
33
    };
34
  ...
35
  } //.TimerRegs
36
37
// enum class - bitmask operators
38
// **********************************************|
39
   template<> struct std::enable_bitmask_operators <Mcucpp::Timers::TimerRegs<3>::tmode>  
40
   { static constexpr bool enable = true; };

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

1
TIFR3 = 1<< OCF3A;  // Flag durch schreiben einer 1 loeschen
Damit hab ich ja wieder eine Lawine losgetreten und der wichtige Fehler 
den ich vorher gemacht habe ist fast untergegangen. Danke für deine 
sorgfältige Code-Analyse.

Fenton G. schrieb:
> Ich wollte eher darauf hinaus, ob es nicht statt:
> if( TIFR3 & OCF3A ) {
> besser
> if( TIFR3 & (1<<OCF3A) ) {
> heißen sollte?
>
Besser - ist gut. Richtig wäre dies !
Hatte da also tatsächlich dass TOV3 abgefragt, aber dass OCF3A gelöscht.
1
iomxx_0_1.h
2
3
#define TIFR3   _SFR_IO8(0x18)
4
#define ICF3    5
5
#define OCF3C   3
6
#define OCF3B   2
7
#define OCF3A   1
8
#define TOV3    0


Spess53 .. schrieb:
> Hi
>
>>Bei dem von mir gewähltem CTC-Mode 4, wird kein Overflow Flag gesetzt,
>
> Wie kommst du auf das schmale Brett?
>
Bitte richtig zitieren und nicht dass Wichtigste weglassen.
Es wird ja nicht ohne Grund zwischen TOP = OCR3A und MAX = 0xFFFF 
unterschieden und ich bleib dabei :

Bei dem von mir gewähltem CTC-Mode 4, wird kein Overflow Flag gesetzt,
da ich nicht bis MAX ( 0xFFFF ) hochzähle. Bzw. dieses Flag wird
wahrscheinlich einmalig doch gesetzt.

Es gibt ja nicht umsonst dass TOV und dass OCFnA Flag.


Bernd_Stein

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Falk B. schrieb:
> Schon mal was von einer for() Schleife gehört? Nicht zu verwechseln mit
> der imaginären if()-Schleife.
>
Da ich dies nur schrittweise bei jedem Interrupt tue, ist eine 
FOR-Schleife nicht dass Richtige.

Bernd S. schrieb:
> Pendeln anders realisieren
> Hat jemand eine elegantere bzw. in der Programmabarbeitung schnellere
> Idee ?
1
ISR( TIMER3_COMPA_vect ) 
2
{ 
3
  //-------------------------------------------------------------------------------
4
  //
5
  // CTC3 MODE 4 Normaler Ausgang
6
  // SM-Sinusrampe abfahren, Schrittmotorschritte runterzaehlen und
7
  // Schrittimpuls erzeugen.
8
  //
9
  //-------------------------------------------------------------------------------
10
  ///////////////////////////////////////////////////////////////////////////////
11
  // Zwischen MIN und MAX pendeln
12
  //
13
  
14
  if( stepCount != 0 )  {
15
    SM1_PORT &= ~SM1_TAKT; // Schrittimpuls vorbereiten
16
/*
17
Serial.print  ( "Takt Low  = "         );
18
Serial.println(  SM_RICHTUNG_PORT, BIN );    
19
*/    
20
    uint8_t x = rampeArrayZeiger; // Zeiger auf die einzelnen Sinuswerte
21
      
22
    // Langsamer werden solange MAX nicht erreicht und Flag auf Aufwaerts steht
23
    if( x >= 0 && flagRegister & AUF_AB ) rampeArrayZeiger++;
24
    
25
    // MAX-Wert ist erreicht, Flag auf Abwaerts stellen und somit Aufwaertzaehlen blockieren
26
    if( x >= rampenLaenge -1 && flagRegister & AUF_AB ) flagRegister ^= AUF_AB; 
27
   
28
    // Schneller werden solange MIN nicht erreicht und Flag auf Abwaerts steht 
29
    if( x > 0 && ~flagRegister & AUF_AB )  rampeArrayZeiger--; 
30
  
31
    // MIN-Wert ist erreicht, Flag auf Aufwaerts stellen und somit Abwaertszaehlen blockieren
32
    if( x <= 0 && ~flagRegister & AUF_AB )  flagRegister ^= AUF_AB;
33
34
    stepCount --;
35
36
/*
37
Serial.print  ( "stepCount = " );
38
Serial.println(  stepCount     );    
39
*/
40
 
41
    SM1_PORT |=  SM1_TAKT; // Schrittimpuls vollenden
42
43
 }
44
} // Ende ISR( TIMER3_COMPA_vect )


Bernd_Stein

von Hugo H. (hugo_hu)


Angehängte Dateien:

Lesenswert?

Wilhelm M. schrieb:
> Du siehst aber schon an der Diskussion um den Mist mit dem falschen
> Statement
> TIFR3 |= 1<< OCF3A;
>
> das auch hier bei simplem C die Zusammenhänge nicht verstanden werden,
> obwohl jemand behauptet, ins DB zu schauen.

Ja - ich schon.

von Spess53 .. (hardygroeger)


Lesenswert?

Hi

>Bei dem von mir gewähltem CTC-Mode 4, wird kein Overflow Flag gesetzt,
>da ich nicht bis MAX ( 0xFFFF ) hochzähle. Bzw. dieses Flag wird
>wahrscheinlich einmalig doch gesetzt.

Du irrst;

Figure 17-6. CTC Mode, Timing Diagram  (ATMega2560)

Dort findest du folgenden Satz

"OCnA Interrupt Flag Set or ICFn Interrupt Flag Set (Interrupt on TOP)"

TOP bezieht sich hier auf den Inhalt von  OCnA- oder  ICFn-Register und 
nicht auf 0xFFFF

MfG Spess

von Wilhelm M. (wimalopaan)


Lesenswert?

Hugo H. schrieb:
> Wilhelm M. schrieb:
>> Du siehst aber schon an der Diskussion um den Mist mit dem falschen
>> Statement
>> TIFR3 |= 1<< OCF3A;
>>
>> das auch hier bei simplem C die Zusammenhänge nicht verstanden werden,
>> obwohl jemand behauptet, ins DB zu schauen.
>
> Ja - ich schon.

Glück gehabt. Da ich schon lange nichts mehr mit den alten Dingen mache, 
ist mir der Spezialfall entfallen.

Versuchst Du da bei einem neueren AVR oder irgendetwas anderem, wirst Du 
auf die Nase fallen.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Spess53 .. schrieb:
> TOP bezieht sich hier auf den Inhalt von  OCnA- oder  ICFn-Register und
> nicht auf 0xFFFF
>
Genau, deshalb kommt es ja nicht zu einem Überlauf.
Ich hatte es mal getestet und daher weiß ich dass es so stimmt.
Es wird nämlich nur einmal die Timer Overflow ISR aufgerufen, danach nur 
noch die Output Compare Match ISR.


Bernd_Stein

von Hugo H. (hugo_hu)


Lesenswert?

Wilhelm M. schrieb:
> Spezialfall

Gilt merkwürdiger Weise auch für den beliebten ATMega328P etc.

Aber klar, die "alten" AVR sind ja nur (noch) Spezialfälle ;-)

von Falk B. (falk)


Lesenswert?

A. B. schrieb:
>>ist mehr als nur empfehlenswert, es ist fast alternativlos.
>
> Damit verewigt man die Ungeschicktheiten von Atmel, Microchip, STM ...
> in den Headern oder in den IDE's für alle Ewigkeit.

Willst du ALLE Register und Bits NEU definieren? Viel SPaß! Klar kann 
man EINIGE zusammenfassen und den Zugriff vereinfachen, aber der Rest?

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

" However, changing the TOP to a value close to BOTTOM when
the counter is running with none or a low prescaler value must be done 
with care since the CTC mode does not have the double buffering feature. 
If the new value written to OCRnA or ICRn is lower than the current 
value of
TCNTn, the counter will miss the compare match. The counter will then 
have to count to its maximum value (0xFFFF) and wrap around starting at 
0x0000 before the compare match can occur. "

Ich vermute, damit kann man dann diesen Fehlerfall erkennen, wenn der 
Timer dann bis MAX ( 0xFFFF ) gezählt hat.


Bernd_Stein

: Bearbeitet durch User
von A. B. (Firma: ab) (bus_eng)


Lesenswert?

Falk B. schrieb:

> Willst du ALLE Register und Bits NEU definieren?

Das macht man ja nur einmal und das funktioniert ja nach einem 
definierten Schema. Der Aufwand hält sich in Grenzen.

von Falk B. (falk)


Lesenswert?

A. B. schrieb:
>> Willst du ALLE Register und Bits NEU definieren?
>
> Das macht man ja nur einmal und das funktioniert ja nach einem
> definierten Schema. Der Aufwand hält sich in Grenzen.

Willst du micht verarschen? Das ist schon grenzwertig bei einem kleinen 
ATtiny. Von größeren AVRs oder ausgewachsenen 32 Bittern mit fetter 
PEripherie ganz zu schweigen! Und wie übersetzt du dann die Namen in der 
Doku in deine eigenen Namen? Mit der selbstgedruckten Bibel?
Und wie arbeitest ud damit, wenn du die Namen in der Doku liest und dann 
in deine "geweihte" Sprache übersetzt?

von A. B. (Firma: ab) (bus_eng)


Lesenswert?

Falk B. schrieb:
> Willst du micht verarschen?

Das ganze ist McuCPP modifiziert mit Ideen von Wilhelm M.
1
//*****************************************************************************
2
// TimerTest.cpp
3
//*****************************************************************************
4
  #include <avr/io.h>
5
  #include <avr/interrupt.h>
6
7
  #include <iopins_.h>
8
//#include <pinlist.h>
9
10
//#include <timer0.h>                                // OLD
11
  #include <avr/ATmega/164-324-644-1284/TimerRegs.h> // NEW
12
13
  using namespace Mcucpp;
14
  using namespace IO;
15
  using namespace Timers;
16
//*****************************************************************************
17
  ISR(TIMER0_OVF_vect)  { PortA::Toggle(0xFF); }
18
  ISR(TIMER0_COMPA_vect){ PortB::Toggle(0xFF); }
19
  ISR(TIMER1_OVF_vect)  { PortC::Toggle(0xFF); }
20
  ISR(TIMER2_OVF_vect)  { PortD::Toggle(0xFF); }
21
22
  int main() {
23
//*****************************************************************************
24
    PortA::SetConfiguration(0xff, PortA::Out); //-> DDRA = 0xff;
25
    PortB::SetConfiguration(0xff, PortB::Out); //-> DDRB = 0xff;
26
    PortC::SetConfiguration(0xff, PortC::Out); //-> DDRC = 0xff;
27
    PortD::SetConfiguration(0xff, PortD::Out); //-> DDRD = 0xff;
28
29
  //***************************************************************************
30
  //Timer0::OutputCompare<0xA>::Set             (F_CPU/256*1e-3 -1 );
31
  //Timer0::OutputCompare<0xA>::EnableInterrupt ();                          // OLD
32
  //***************************************************************************
33
    Timer0::OutputCompareA::Set             (F_CPU/256*1e-3 -1 );
34
    Timer0::OutputCompareA::EnableInterrupt ();
35
    Timer0::                SetTimerMode    (Timer0::TimerMode::ClearOnCompare);
36
    Timer0::                EnableInterrupt ();
37
    Timer0::                Start           (Timer0::TimerDivider::Div256);  // NEW
38
  //***************************************************************************
39
    Timer1::                SetTimerMode    (Timer1::TimerMode::Normal);
40
    Timer1::                EnableInterrupt ();
41
    Timer1::                Start           (Timer1::TimerDivider::Div256);  //NEW
42
  //***************************************************************************
43
    Timer2::                SetTimerMode    (Timer2::TimerMode::Normal);
44
    Timer2::                EnableInterrupt ();
45
    Timer2::                Start           (Timer2::TimerDivider::Div256);  //NEW
46
  //***************************************************************************
47
    sei();
48
49
50
51
    while(1) {
52
    for(;;) {
53
  //*******************************
54
      SysClock::Delay_us<1100>();
55
      PA_0     ::Toggle       ();
56
    }
57
}
58
59
    return 0;
60
  } //____________________________________________________________a.b.08.2015__
61
}

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

A. B. schrieb:
> Das macht man ja nur einmal und das funktioniert ja nach einem
> definierten Schema. Der Aufwand hält sich in Grenzen.

Sowas lässt man Chatti (aka GPT4) in Python in 5 Minuten programmieren 
und verschwendet selbst keine Minute damit^^

Ansonsten ist die Idee doof ...^^

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?

Wenn der Bedarf bestände, würden die Hersteller sicher auch andere 
Programmiersprachen als C mit Hardwaredefinitionen beglücken. Oder diese 
Definitionen in XML oder JSON veröffentlichen. Dann könnte Wilhelm z.B. 
daraus automatisch ein C++-API generieren.

Tun sie aber nicht. Warum wohl?

LG, Sebastian

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Sebastian W. schrieb:
> Wenn der Bedarf bestände, würden die Hersteller sicher auch andere
> Programmiersprachen als C mit Hardwaredefinitionen beglücken. Oder diese
> Definitionen in XML oder JSON veröffentlichen. Dann könnte Wilhelm z.B.
> daraus automatisch ein C++-API generieren.
>
> Tun sie aber nicht. Warum wohl?

Tun sie doch?

In den "Device Packs" gibt's nen Ordner "atdf", der .atdf files enthält, 
welche wiederum XML sind.  Die AVR-LibC generiert sogar ihre Header 
daraus, zumindest für die Devices, für die es solche XML-Beschreibungen 
gibt. (Für alte Devices wie zB ATmega103 etwa gibt es keine XMLs).

Spaßig wirs das ganze erst dann, denn sich in eine solche Datei der 
Tippteufel eingeschlichen hat.

von Wilhelm M. (wimalopaan)


Lesenswert?

Johann L. schrieb:
> Sebastian W. schrieb:
>> Wenn der Bedarf bestände, würden die Hersteller sicher auch andere
>> Programmiersprachen als C mit Hardwaredefinitionen beglücken. Oder diese
>> Definitionen in XML oder JSON veröffentlichen. Dann könnte Wilhelm z.B.
>> daraus automatisch ein C++-API generieren.
>>
>> Tun sie aber nicht. Warum wohl?
>
> Tun sie doch?
>
> In den "Device Packs" gibt's nen Ordner "atdf", der .atdf files enthält,
> welche wiederum XML sind.

Ja, die sind ganz brauchbar. Daraus habe ich meine erste Version 
generiert.

STM liefert die svd-Files (XML), die sind ebenfalls gut, aber auch 
leider hier und da fehlerbehaftet. Das modm-Projekt beschäftigt sich mit 
der Verbesserung der Datenqualität.

von Sebastian W. (wangnick)


Lesenswert?

Wilhelm M. schrieb:
> Ja, die sind ganz brauchbar. Daraus habe ich meine erste Version
> generiert.

Das klingt nun allerdings schon viel weniger nach einem 
Wartungsalbtraum!

LG, Sebastian

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Johann L. schrieb:
> In den "Device Packs" gibt's nen Ordner "atdf", der .atdf files enthält,
> welche wiederum XML sind.

Da drin fehlt die "fast toggle" Fähigkeit der PINX Register.

Im 4er Studio gabs die Info noch.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Johann L. schrieb:
>> In den "Device Packs" gibt's nen Ordner "atdf", der .atdf files enthält,
>> welche wiederum XML sind.
>
> Da drin fehlt die "fast toggle" Fähigkeit der PINX Register.

In den alten XML-Files fehlt noch mehr ;-) Und ich bezweifle, dass die 
tatsächliche Semantik eines Bits da irgendwie mal drin gestanden hat.

Die neueren XML-Files sind da schon etwas besser, weil hier bspw. der 
erlaubte Zugriff ("R", "RW") enthalten ist. Was allerdings immer noch 
fehlt, ist die Info, ob die Bits nun rc_w1 ist (oder rc_w0) sind. 
Insofern kann man hier nur intelligent raten beim Auswerten der XMLs.

Die XMLs von STM sind noch etwas besser: hier ist die Beschreibung der 
Bits enthalten (wobei bei mehrfachem Vorkommen im Text(!) auf die 
Beschreibung eines anderen Bits verwiesen wird). Aber auch hier fehlt 
die Info zu rc_w1, etc. Obwohl das im DB drin steht. Daher: auch diese 
XMLs sind nur die halbe Wahrheit.

Beitrag #7518663 wurde von einem Moderator gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb im Beitrag #7518663:
> Schwachmat!

Wilhelm M. schrieb:
> Arduino F. schrieb:
>> Gerhard O. schrieb:
>>> Eigenbau
>>
>> Eigenbau
>> Ist im inneren etwas unaufgeräumt, deckt aber die meisten AVR der
>> Arduinowelt ab.
>
> Was machst Du mit µC, die mehr als einen ADC haben, z.B. die
> tiny1-Serie?

Wie war jetzt Deine Antwort darauf? Meine konntest Du ja oben schon 
lesen.

Beitrag #7518681 wurde von einem Moderator gelöscht.
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Ich unterbreche die Verbalinjurien ja nur ungerne - aber 
ihaettamolafrooch:

Welche Sprache/n ist geeignet, um aus so XML-Zeugs dann die Headerfiles 
zu generieren?
Hat da wer ein Simpelbeispiel?

Gruss
WK

von Wilhelm M. (wimalopaan)


Lesenswert?

Dergute W. schrieb:
> Hat da wer ein Simpelbeispiel?

C++ mit https://pugixml.org

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Dergute W. schrieb:
> Welche Sprache/n ist geeignet, um aus so XML-Zeugs dann die Headerfiles
> zu generieren?

Ich verwende PHP um solche Dateien zu lesen.
Es gibt für jede halbwegs moderne/brauchbare Sprache irgendeine DOM 
Implementierung.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dergute W. schrieb:
> Welche Sprache/n ist geeignet, um aus so XML-Zeugs dann die Headerfiles
> zu generieren?
> Hat da wer ein Simpelbeispiel?

Hier die Python-Skripte der AVR-LibC.  Ist aber nicht wirklich "simpel".

https://github.com/avrdudes/avr-libc/tree/main/xml

Dann gibt's noch ioreg.pl in

https://github.com/avrdudes/avr-libc/tree/main/devtools

Liest auch XML, aber dient nicht zur Header-Generierung.

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

A. B. schrieb:
> Das macht man ja nur einmal und das funktioniert ja nach einem
> definierten Schema. Der Aufwand hält sich in Grenzen.

Bei dem Tempo, mit dem neue Modelle veröffentlicht werden, wäre ich mir 
da nicht so sicher. Es gibt schließlich noch andere Dinge, mit denen man 
sich im Leben beschäftigen möchte.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Again what learned. Merci!

Gruss
WK

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Dieser Programmabschnitt kann doch keine 5µs, bei 16MHz ( 62,5ns )
CPU-Takt dauern.

Erlaubt diese Arduino-Klamotte, dass ein Interrupt durch einen anderen
unterbrochen werden darf ?
1
ISR( TIMER3_COMPA_vect ) 
2
{ 
3
  //-------------------------------------------------------------------------------
4
  //
5
  // CTC3 MODE 4 Normaler Ausgang
6
  // SM-Sinusrampe abfahren, Schrittmotorschritte runterzaehlen und
7
  // Schrittimpuls erzeugen.
8
  //
9
  //-------------------------------------------------------------------------------
10
  ///////////////////////////////////////////////////////////////////////////////
11
  // Hin und her fahren und am Startpunkt wird eine kurze Pause einlegt
12
  //
13
  if( stepCount != 0 )  {
14
    OCR3A = rampeArray[ rampeArrayZeiger ]; // 
15
    SM1_PORT &= ~SM1_TAKT; // Schrittimpuls vorbereiten
16
    
17
    // Geschwindigkeit verlangsamen und begrenzen
18
    if( stepCount <= rampenLaenge ) {
19
      rampeArrayZeiger ++;
20
      
21
      if( rampeArrayZeiger > rampenLaenge -1 ) rampeArrayZeiger = rampenLaenge -1;
22
    }
23
    // Geschwindigkeit erhoehen und begrenzen
24
    else if( stepCount > rampenLaenge )  {      
25
      rampeArrayZeiger --;
26
      
27
      if( rampeArrayZeiger <= 0 ) rampeArrayZeiger = 0;
28
    }
29
    stepCount --;             // Schrittmotor Schrittanzahl runterzaehlen
30
31
    // Nur jedes 2te mal ist dieses Bit gesetzt bzw. geloescht
32
    if( stepCount == 0 ) flagRegister  ^= EINS;  
33
   
34
    SM1_PORT  |=  SM1_TAKT; // Schrittimpuls vollenden
35
  } 
36
} // Ende ISR( TIMER3_COMPA_vect )



Bernd_Stein

von Veit D. (devil-elec)


Lesenswert?

Hallo,

wie hast du das gemessen?

von Sebastian W. (wangnick)


Lesenswert?

Bernd S. schrieb:
> Erlaubt diese Arduino-Klamotte, dass ein Interrupt durch einen anderen
> unterbrochen werden darf ?

Nein. Wenn also gerade ein anderer Interrupt behandelt wird, muss 
TIMER3_COMPA_vect auf dessen Beendigung warten. Spezialfälle wie die 
explizite Freigabe neuer Interrupts in einem Interrupthandler mal 
ausgenommen.

Bernd S. schrieb:
> Dieser Programmabschnitt kann doch keine 5µs, bei 16MHz ( 62,5ns )
> CPU-Takt dauern.

Zeig mal das Assemblat.

LG, Sebastian

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Bernd S. schrieb:
> Erlaubt diese Arduino-Klamotte, dass ein Interrupt durch einen anderen
> unterbrochen werden darf ?
Da hat/nimmt es keinen Einfluss drauf.
Du bist der Programmierer/Gott deines µC, nicht Arduino.

: Bearbeitet durch User
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Bernd S. schrieb:

> Dieser Programmabschnitt kann doch keine 5µs, bei 16MHz ( 62,5ns )
> CPU-Takt dauern.

Schau dir einfach das Assemblerlisting an, da kannst du die Takte leicht 
auszählen, die der Code benötigt.

Caches oder Pipelines kennt der AVR8 nicht, das Takte-Auszählen ist also 
wirklich eine reine Fleißarbeit, die sogar so jemand wie du (mit dem 
entsprechenden Fleißeinsatz) problemlos leisten könnte.

Nur zu faul dazu?

von Sebastian W. (wangnick)


Lesenswert?

Sebastian W. schrieb:
> Bernd S. schrieb:
>> Dieser Programmabschnitt kann doch keine 5µs, bei 16MHz ( 62,5ns )
>> CPU-Takt dauern.
> Zeig mal das Assemblat.

Um den Assemblercode zu erzeugen, musst du folgendes tun:
1. Aktiviere in den Arduino-Einstellungen "Ausführliche Ausgabe 
während:" "Kompilierung"
2. Übersetze deinen Sketch
3. Notiere dir das in den letzten Zeilen der Ausgabe genannte 
Arduino-Installationsverzeichnis (bei mir zum Beispiel 
C:\\Users\\Hobbyraum\\AppData\\Local\\Arduino15\\packages\\arduino\\tool 
s\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin)  und das temporäre 
Sketchverzeichnis (bei mir zum Beispiel 
C:\\Users\\HOBBYR~1\\AppData\\Local\\Temp\\arduino_build_174782).
4. Öffne ein Windows Eingabeaufforderung
5. Wechsle in der Eingabeaufforderung mit "cd 
C:\\Users\\HOBBYR~1\\AppData\\Local\\Temp\\arduino_build_174782" (oder 
wie auch immer es bei dir gerade heißt) in das temporäre 
Sketchverzeichnis.
6. Führe in der Eingabeaufforderung "dir" aus. Eine der Dateien dort 
sollte die Endung ".elf" haben (bei mir zum Beispiel "gen1mhz.ino.elf").
7. Führe in der Eingabeaufforderung auf der .elf-Datei das Kommando 
avr-objdump mit den Optionen -d (disassemblieren) und -S (mit Sourcecode 
verschränken) aus, und leite die Ausgabe in eine neue Datei um (bei mit 
zum Beispiel 
"C:\\Users\\Hobbyraum\\AppData\\Local\\Arduino15\\packages\\arduino\\too 
ls\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-objdump"  -dS 
gen1mhz.ino.elf >gen1mhz.ino.elf.lst)
8. Öffne das temporäre Sketchverzeichnis in einem Windows 
Dateiexplorer-Fenster
9. Öffne dort die entstandene Datei mit der Endung ".lst" mit einem 
Editor deiner Wahl. Dort findest du den erzeugten Assemblercode.

LG, Sebastian

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich würde einen Pin ein- und ausschalten lassen und am Oszi oder mit 
Logic Analyzer messen. Nur muss man den Pin direkt mit PORT Bit 
Manipulation schalten. Wenn das Bernd mit digitalWrite gemacht haben 
sollte ist das eine Fehlmessung.

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> ich würde einen Pin ein- und ausschalten lassen und am Oszi oder mit
> Logic Analyzer messen.
>
Genau so habe ich es gemacht.
Wer gut im C-Programme lesen ist, hätte gesehen dass ich in dem Programm 
einen negativen Impuls erzeuge, der halt ca. 5µs dauert. Er ist 
natürlich nicht negativ ( nur für die Korintenkacker hier ), aber ich 
weiß nicht wie ich es sonst erklären soll.


Ob S. schrieb:
> Schau dir einfach das Assemblerlisting an, da kannst du die Takte leicht
> auszählen, die der Code benötigt.
>
Bei 16MHz dauert ein Befehlstakt 62,5ns.
Der größte Teil der AVR8-Befehle wird in einem Taktzyklus verarbeitet.
5000ns / 62,5ns = 80. Also hätte ich etwas weniger wie 80 
Assembler-Befehle auszuwerten.

Ich habe 15 C-Befehle verwendet. Wenn ich pro Befehl ca. 5 CPU-Takte 
rechne
kommt das schon hin.

Danke für diesen Denkanstoss, hatte vorher immer im Kopf von ns zu µs 
ist es der Faktor 1000, dabei sind es aller höchstens 80 ASM-Befehle.

Bernd_Stein

von Stefan F. (Gast)


Lesenswert?

Bernd S. schrieb:
> Er ist natürlich nicht negativ..., aber ich
> weiß nicht wie ich es sonst erklären soll.

Ich denke, du hast dich verständlich ausgedrückt. Man könnte es auch 
einen LOW-Impuls nennen.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)



Lesenswert?

Habe ein schwer zu findenden Fehler in meinem Code.
Die PAUSE sollte jeweils nur einmal stattfinden.
Dachte erst, dass dies mit einer Regelmäßigkeit auftritt, da dies beim 
errorZaehler-Stand 3, 8, 13, 18 auftrat.
Dann aber bei 26, 31, 36, 41, 46, 51, 59, 64, 72, 74, 79 und 
noch mehr Stellen. Es gibt also keine erkennbare Regelmäßigkeit, auch 
wenn es oft im 5er Abstand aufkommt.

Im Anhang mein Kot ;-)


Bernd_Stein

von Stefan F. (Gast)


Lesenswert?

Beim Arduino Framework ist serielle Ausgabe innerhalb einer ISR 
problematisch. Denn während die ISR läuft, sind alle anderen Interrupts 
gesperrt. Die Serielle Ausgabe braucht aber ebenfalls Interrupts. 
Deswegen sollte man solche Konstrukte besser vermeiden.

Schau dir mal genau den Code unter dem Kommentar "Sofortigen Interrupt 
verhindern" an. Tut er wirklich sicher das, was der Kommentar sagt? Die 
Abarbeitung dieser Zeilen braucht einige CPU Takte. Innerhalb dieser 
Zeit könnte der Interrupt kommen.

Außerdem hast du den Zugriff "stepCount = SM_SCHRITTANZAHL" auf die 32 
Bit Variable nicht geschützt. Dein AVR braucht auch dafür einige CPU 
Takte. Während dessen kann ein Interrupt dazwischen stören und die halb 
gesetzte Variable verändern. Packe da mal eine Interruptsperre drum 
herum:
1
cli();
2
3
stepCount = SM_SCHRITTANZAHL;  // Variable wird in ISR runtergezaehlt
4
5
// Sofortigen Interrupt verhindern
6
TCNT3   =  0;             // Timer ruecksetzen
7
TIFR3   =  1<< OCF3A;     // Output Compare Interrupt Flag loeschen
8
TIMSK3 |=  1<< OCIE3A;
9
10
sei();

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Stefan F. schrieb:
> Beim Arduino Framework ist serielle Ausgabe innerhalb einer ISR
> problematisch. Denn während die ISR läuft, sind alle anderen Interrupts
> gesperrt. Die Serielle Ausgabe braucht aber ebenfalls Interrupts.
> Deswegen sollte man solche Konstrukte besser vermeiden.
>
Hm - so kenne ich das auch, dass man eigentlich innerhalb einer ISR 
andere ISR freigeben muss, damit die laufende ISR dann durch die Andere 
unterbrochen werden kann.
Ah - dann werden die Print-Befehle gar nicht an dieser Stelle der OC-ISR 
ausgeführt, sondern erst nach verlassen dieser, wobei erst ein Befehl in 
der Loop ausgeführt wird und dann die ISR für die anstehenden 
Print-Befehle
ausgeführt wird.

Stefan F. schrieb:
> Schau dir mal genau den Code unter dem Kommentar "Sofortigen Interrupt
> verhindern" an. Tut er wirklich sicher das, was der Kommentar sagt? Die
> Abarbeitung dieser Zeilen braucht einige CPU Takte. Innerhalb dieser
> Zeit könnte der Interrupt kommen.
>
Irgend einer schon, aber nicht mein OC-IRQ, da ich ihn ja vorher mit
1
TIMSK3 &=  ~1<< OCIE3A;     // Output Compare Interrupt sperren
sperre.

Stefan F. schrieb:
> Außerdem hast du den Zugriff "stepCount = SM_SCHRITTANZAHL" auf die 32
> Bit Variable nicht geschützt. Dein AVR braucht auch dafür einige CPU
> Takte. Während dessen kann ein Interrupt dazwischen stören und die halb
> gesetzte Variable verändern. Packe da mal eine Interruptsperre drum
> herum:
>
Stimmt generell.
Aber in meinem Fall sperre ich ja als aller erstes in der Loop den 
OC-IRQ, der stepCount verändert. Ob irgend eine andere ISR beim Arduino 
Framework zufällig auch stepCount benutzt weiß ich nicht.

Ich verstehe einfach nicht, was sich da in die Quere kommt, denn ich 
habe in der Loop nur drei weitere Print-Befehle ( Neu ) eingefügt und 
255 Error Zählungen sind ohne Fehler von statten gegangen.
1
void loop()
2
{
3
  //----------------------------------------------------------------------------
4
  // 
5
  // void loop()
6
  //
7
  //----------------------------------------------------------------------------
8
  if( stepCount == 0 ) {
9
    TIMSK3 &=  ~1<< OCIE3A;     // Output Compare Interrupt sperren    
10
    
11
    // Nur jedes 2te mal eine Pause einlegen 
12
    if( !( SM_RICHTUNG_PORT & SM_RICHTUNG ))  {
13
          
14
///*                        
15
Serial.print  ( errorZaehler );
16
Serial.print  ( " PAUSE" );  
17
Serial.print  ( "\t" );         // Neu  
18
Serial.print  ( "stepCount" );  // Neu
19
Serial.print  (  stepCount  );  // Neu  
20
Serial.println( ); 
21
//*/    
22
        errorZaehler ++;
23
        
24
        delay( SM_PAUSE );
25
    }
26
        
27
        stepCount = SM_SCHRITTANZAHL;  // Variable wird in ISR runtergezaehlt
28
        // Sofortigen Interrupt verhindern
29
        TCNT3   =  0;             // Timer ruecksetzen
30
        TIFR3   =  1<< OCF3A;     // Output Compare Interrupt Flag loeschen
31
        TIMSK3 |=  1<< OCIE3A;    // Output Compare Interrupt freigeben    
32
  }
33
} // Ende void loop()


Bernd_Stein

: Bearbeitet durch User
Beitrag #7528309 wurde vom Autor gelöscht.
von Stefan F. (Gast)


Lesenswert?

Bernd S. schrieb:
> dann werden die Print-Befehle gar nicht an dieser Stelle der OC-ISR
> ausgeführt, sondern erst nach verlassen dieser

Genau. Die Strings werden in einen Puffer geschrieben. Das Programm wird
sich wohl an dieser Stelle aufhängen, wenn der Puffer voll läuft. Deine
Ausgaben sind offenbar kurz genug, dass das nicht passiert.

> Irgend einer schon, aber nicht mein OC-IRQ, da ich ihn ja vorher
> mit ... sperre.

Guter Hinweis, das hatte ich übersehen.

> Ich verstehe einfach nicht, was sich da in die Quere kommt

Bin da jetzt auch ein bisschen überfordert. Ein Debugger wäre jetzt
nicht schlecht.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Bernd S. schrieb:
> Ah - dann werden die Print-Befehle gar nicht an dieser Stelle der OC-ISR
> ausgeführt, sondern erst nach verlassen dieser, wobei erst ein Befehl in
> der Loop ausgeführt wird und dann die ISR für die anstehenden
> Print-Befehle
> ausgeführt wird.

Das hört sich unsinnig an!
Natürlich gibt es keine Warteschlange für Print Methoden.
Die Print::print() werden sofort ausgeführt.
Es wird ein char/uint8_t Ringbuffer mit den Ausgaben gefüllt.
Die Probleme/Blockaden entstehen, wenn der Ringbuffer voll ist.

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Im Anhang mein Kot ;-)

In der Tat. So eine Scheiße kriegen nur die ganz großen Experten wie du 
hin. Die Meister der Unlogik und der maximal verkorksten Lösung. Bravo!

Wie schon mehrfach gesagt, ist eine Serielle Ausgabe im Interrupt bei 
der Arduinoumgebung nicht möglich. Sinnvoll ist si so oder so nicht. Die 
kann man PROBLEMLOS im Hauptprogramm machen, wenn man weiß was man tut. 
Ach so, du bist es ja!

von Steve van de Grens (roehrmond)


Lesenswert?

Falk B. schrieb:
> Sinnvoll ist si so oder so nicht.

Das hat er doch nur mangels Debugger gemacht, um den Ablauf des 
Programmes zu kontrollieren. Für den Zwecks reicht der Puffer ja auch 
offenbar.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Falk B. schrieb:
> Wie schon mehrfach gesagt, ist eine Serielle Ausgabe im Interrupt bei
> der Arduinoumgebung nicht möglich.

Doch, ist sie!
Solange noch Platz im Ringbuffer ist.
Solange kann man man die Print Methoden ohne Hemmung aufrufen.

Die UART Interrupts kommen allerdings erst nach einem sei(), bzw. ISR 
Ende wieder durch.

Es ist also nur die Leerung des Buffers, der von der Print::print() 
aufrufenden ISR aufgehalten wird.

Falk B. schrieb:
> Sinnvoll ist si so oder so nicht.
Sinnvoll?
Auf jeden Fall sollte man Vorsichtig sein!
Auch da sich Ausgaben des Hauptprogramms und Ausgaben in der ISR 
vermischen können/werden.
Die Endergebnisse werden also, ohne Vorkehrungen(Semaphore?), vermutlich 
wenig zufriedenstellend ausfallen.

Threadsafe, ist vielleicht nicht ganz der richtige Begriff, aber trifft 
es schon ganz gut. Die Print Methoden (Ringbuffer Verwaltung) sind nicht 
Wiedereintritts fähig.

: Bearbeitet durch User
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.