Forum: Mikrocontroller und Digitale Elektronik BCM flackert beim dimmen


von Stefan M. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe, inspiriert durch 
http://www.batsocks.co.uk/readme/art_bcm_3.htm versucht, eine BCM zu 
schreiben.
Leider hat es beim dimmen teilweise geflackert, weswegen ich dann direkt 
den Code aus dem verlinkten Artikeln genommen habe.

Hier allerdings selbes Problem:
Wenn ich eine LED mit einem bestimmten Wert leuchten lasse ist alles OK. 
Es ist nur dieses typische, ganz leichte Flackern zu sehen. Ich würd es 
sogar eher "unruhiges Leuchten" nennen. Das sollte sich ja durch eine 
höhere Frequenz in den Griff kriegen lassen.

Aber sobald ich anfange die LED zu dimmen, also zyklisch den BCM-Wert 
herunterzähle, wird das flackern "wilder". Ja ich weiß, blöde 
Beschreibung. Es sind halt teilweise ganz kurze Aussetzer zu sehen.

Leider kann ich nicht beurteilen ob dieses Phänomen normal ist oder ob 
der Code nicht passt.
Ich hab den Code mal angehängt.
Es handelt sich um den Original Code von der verlinkten Seite, mit 
Änderungen an den Timer Registern (ich benutze einen ATmega1284P @ 1 
MHz), und einer Änderung in der "Animation" um nur eine LED langsam 
herunterzufaden.

Weiß da jemand Rat?

von Falk B. (falk)


Lesenswert?

@Stefan M. (Gast)

>Aber sobald ich anfange die LED zu dimmen, also zyklisch den BCM-Wert
>herunterzähle, wird das flackern "wilder". Ja ich weiß, blöde
>Beschreibung. Es sind halt teilweise ganz kurze Aussetzer zu sehen.

Klingt nach einer fehlenden Synchronisation zwischen BCM und Dimmung.
Die neuen Dimmwerte düfren NUR exakt zum beginn einer neuen BCM Periode 
übernommen werden.

https://www.mikrocontroller.net/articles/Soft-PWM#Intelligenter_L.C3.B6sungsansatz

"Dieses Prinzip wird oft angewendet. Würde man allerdings einfach am 
Ende die Zeiger tauschen käme es zu einem Crash! Der Interrupt kann 
jederzeit aktiv werden. Wenn dann die Zeiger nur halb kopiert sind 
greift die Interruptroutine auf zerstückelte Daten zu und macht Müll. 
Ebenso würde es zu Fehlfunktionen kommen, wenn während es PWM-Zyklus 
neue Daten in die Arrays kopiert werden. Das muß verhindert werden. Und 
zwar dadurch, daß über eine Variable eine Synchronisation durchgeführt 
wird. Diese wird am Ende des PWM-Zyklus gesetzt und signalisiert, daß 
neue Daten für den nächsten Zyklus kopiert werden können. Deshalb muss 
die Funktion pwm_update ggf. bis zu 1 vollen PWM-Zyklus warten, bis die 
Zeiger getauscht werden können. Wichtig ist dabei, daß die Variable 
pwm_sync, welche sowohl in der Funktion als auch im Interrupt 
geschrieben wird, als volatile deklariert wird. Denn sonst würde die 
Sequenz

pwm_sync=0;             // Sync wird im Interrupt gesetzt
while(pwm_sync==0);

zum Stehenbleiben der CPU führen, weil der Compiler erkennt, daß die 
Variable nie ungleich Null sein kann und damit die Schleife endlos 
ausgeführt wird. Der Compiler kann prinzipbedingt nicht automatisch 
erkennen, daß die Variable im Interrupt auf 1 gesetzt wird. "

von Stefan M. (Gast)


Lesenswert?

Danke erstmal,

Ich habe mal in der Funktion "encode_timeslice" eine while-schleife 
eingefügt.

Direkt vor der Zeile "g_tick=0;" hab ich "while (g_tick != 1);" 
eingefügt.

Sollte dadurch nicht immer bis zum längsten (=letzten) Abschnitt der BCM 
gewartet werden?
Ändert leider garnichts...

von Peter D. (peda)


Lesenswert?

Mit ner fast BCM ist das Flackern nicht mehr so kritisch:

Beitrag "AVR: Fast-PWM (BAM) 12 Bit für 8 Kanäle"

von Stefan M. (Gast)


Lesenswert?

Danke für den Link.
Ich würde aber gerne verstehen was hier falsch läuft.

Wie gesagt, das Aktualisieren der Werte ist nun mit dem interrupt 
synchronisiert.
Liegt es wirklich an der niedrigen Frequenz?

PS: doch noch eine Frage zu deinem Code:
12 Bit / 2kHz @ 8 MHz ergeben eine Bitzeit von 0.9765625 Takten. 
Sportlich ;-) oder wo ist mein Rechenfehler?

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


Lesenswert?

Falk Brunner schrieb:
> Klingt nach einer fehlenden Synchronisation zwischen BCM und Dimmung.
> Die neuen Dimmwerte düfren NUR exakt zum beginn einer neuen BCM Periode
> übernommen werden.
 Nicht ganz.
 Ich fahre BAM mit knapp 1KHz und mache mir keine Sorgen um timing.
 Main stellt die RGB-Werte, diese werden gleich umgerechnet und ins
 Port-Array übernommen. Selbstverständlich kann es passieren, dass
 das beim bit2 oder bit5 passiert, Flackern ist trotzdem nicht zu sehen.
 Sein Problem wird eher beim Timer liegen. 32 TaktZyklen für bit0 -
 abzüglich min. 7 für ISR Aufruf und RETI - retten der Register nicht
 mitgerechnet - ist schon ein bisschen knapp. Dazu die ganzen Abfragen
 und Umrechnungen - zumindest die niedrigsten 2 bits haben
 mit Sicherheit Aussetzer.

 EDIT:
 Beim bit2 nicht, da die ISR von bit0 bis bit3 nicht verlassen wird.

: Bearbeitet durch User
von Stefan M. (Gast)


Lesenswert?

Du hast recht.
32 Takte sind natürlich sehr knapp.
Ich habe in meinem jugendlichen Leichtsinn den Code von batsocks 
übernommen und irgendwie impliziert, dass er soweit korrekt ist.

Ich werde mal die CKDIV8 fuse entfernen und gleichzeitig den Timer2 
Prescaler auf 256 stellen.
Dadurch sollte ja die BCM-Frequenz die gleiche bleiben, allerdings die 
ISR wesentlich mehr Takte zur Verfügung haben, wodurch sich Interrupts 
definitiv nicht mehr überschneiden können.

Glaub aber irgendwie nicht dass es daran liegt, weil dieses nervige 
Flackern nur beim dimmen/faden richtig sichtbar wird...

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


Lesenswert?

Stefan M. schrieb:
> Glaub aber irgendwie nicht dass es daran liegt, weil dieses nervige
> Flackern nur beim dimmen/faden richtig sichtbar wird...

 Ja, ich auch nicht.
 Wenn ich das richtig sehe, hast du nur eine LED an PortD.6, richtig ?

 Deine ISR ist weit davon entfernt genau zu sein, die ersten 4 bits sind
 mit Sicherheit zu lang und zu ungenau. Trotzdem solltest du auf
 eine BCM-Frequenz von knapp 100Hz kommen, da sollte Flackern nicht
 mehr zu sehen sein.
 Allerdings dimmst du mit etwa 8-10Hz, wenn da etwas nicht stimmt,
 ist das deutlich zu sehen.
 Erhöhe mal den slowtick auf 100 oder mehr, dann siehst du, ob es
 daran liegt, wenn ja, solltest du ungefähr jede Sekunde einen
 Aussetzer haben.

 BTW, gedimmt wird logarithmisch, nicht linear.

von Stefan M. (Gast)


Lesenswert?

Hallo Marc,

was meinst du mit "genau" bei der ISR?
Alles was sich vor dem Setzen von PORTD abspielt hat ja eine konstante 
Laufzeit da hier keine Verzweigungen im Spiel sind.
Sagen wir, die beiden Zeilen ergeben einen Offset von 10 CPU-Zyklen.
Dieser Offset wäre ja bei jedem Schaltpunkt gleich. D.h. die Zeit 
zwischen den Schaltpunkten würde nicht jittern sondern sich exakt als 
Zweierpotenz erhöhen, so wie vorgesehen.
Richtig?
Alles was nach dem Setzen von PORTD kommt braucht keine konstante 
Laufzeit mehr haben. Natürlich nur, solange die ISR rechtzeitig beendet 
wird.

Das mit dem slowtick werde ich ausprobieren.

Hat sonst zufällig jemand den batsocks Code mal ausprobiert?

PS: ja, gedimmt wird logarithmisch. Aber Code der im Forum gezeigt wird 
wird auch soweit abgespeckt, dass das Problem immer noch auftritt.

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


Lesenswert?

Stefan M. schrieb:
> was meinst du mit "genau" bei der ISR?

 Jetzt habe ich deinen Code durch Debugger laufen lassen.
 bit 0 =   95 Taktzyklen  sollte sein:    32 Taktzyklen
 bit 1 =  129 Taktzyklen  sollte sein:    64 Taktzyklen
 bit 2 =  191 Taktzyklen  sollte sein:   128 Taktzyklen
 bit 3 =  321 Taktzyklen  sollte sein:   256 Taktzyklen
 bit 4 =  576 Taktzyklen  sollte sein:   512 Taktzyklen
 bit 5 = 1088 Taktzyklen  sollte sein:  1024 Taktzyklen
 bit 6 = 2111 Taktzyklen  sollte sein:  2048 Taktzyklen
 bit 7 = 4161 Taktzyklen  sollte sein:  4096 Taktzyklen
=========================================================
 Addieren und Genauigkeit ausrechnen kannst du selbst ;-D

> Alles was sich vor dem Setzen von PORTD abspielt hat ja eine konstante
> Laufzeit da hier keine Verzweigungen im Spiel sind.
 Wenn der Timer2 CTC feuert, steht der TCNT2 schon auf 0 und
 das ist genau. Wenn du TCNT2 in der ISR aber nochmal auf Null setzst,
 hast du mit Sicherheit alles, was zwischen feuern und Nullsetzen
 passiert, dazuaddiert. Plus Vorteilerstand.

 EDIT:
 Beim CTC wird auch die Null mitgezahlt, also immer +1, somit
 stimmen Soll Taktzyklen nicht, jeweils 32 Zyklen dazuaddieren.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Marc Vesely (Firma: Vescomp) (logarithmus)

> Jetzt habe ich deinen Code durch Debugger laufen lassen.
> bit 0 =   95 Taktzyklen  sollte sein:    32 Taktzyklen
> bit 1 =  129 Taktzyklen  sollte sein:    64 Taktzyklen
> bit 2 =  191 Taktzyklen  sollte sein:   128 Taktzyklen
> bit 3 =  321 Taktzyklen  sollte sein:   256 Taktzyklen

Der Witz einr BCM ist ja, dass man die unteren Bits meistens NICHT über 
mehrfache ISR Aufrufe macht sondern direkt nacheinander mit konstanten 
Verzögerungen. Erst bei den höheren Bits lohnt sich ein ISR-Aufruf bzw. 
ist erst dann technisch machbar!

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


Lesenswert?

Falk Brunner schrieb:
> Der Witz einr BCM ist ja, dass man die unteren Bits meistens NICHT über
> mehrfache ISR Aufrufe macht sondern direkt nacheinander mit konstanten

 Ja.
 Für die bits 0 bis 3 mache ich mir gar nicht die Mühe, die ISR zu
 verlassen. Sind 480 Taktzyklen, also 60us bei 8MHz, macht 5,8% der
 CPU Zeit.

von Falk B. (falk)


Lesenswert?

@ Marc Vesely (Firma: Vescomp) (logarithmus)

> Für die bits 0 bis 3 mache ich mir gar nicht die Mühe, die ISR zu
> verlassen.

Muss man nicht, das kann man trotzdem IN der ISR machen.

> Sind 480 Taktzyklen, also 60us bei 8MHz, macht 5,8% der
> CPU Zeit.

Sehr wenig, für das, was man da bekommt.

von Stefan M. (Gast)


Angehängte Dateien:

Lesenswert?

Guten Abend zusammen,

ich habe mal alle Anregungen aus dem Thread in den Code einfliesen 
lassen:
- update-Funktion ist mit ISR synchronisiert, array wird nur in der 
letzten Bitzeit beschrieben
- Zählerregister wird in der ISR nicht mehr explizit genullt (war 
natürlich Schwachsinn, Schande über mich dass ich das ungeprüft 
übernommen habe)
- Controller läuft jetzt mit 8MHz
- Prescaler wurde dafür auch ver-achtfacht => 256
- Erhöhung des slowticks

Der neue Code ist angehängt.

Marc Vesely, ich trau mich ja fast nicht fragen, aber magst du den Code 
vielleicht nochmal simulieren um zu bestätigen, dass ich die Bitzeiten 
jetzt einhalte? Ich bin hier auf Linux unterwegs und habe kein Atmel 
Studio...

Die Änderungen führen jetzt zu folgendem Ergebnis:
Grundsätzlich flackert die LED beim Dimmen immer noch. Wohlgemerkt, nur 
beim Dimmen. Und das ist das, was mich so verwundert.
Und niedriger der Wert desto besser sichtbar.
Kurz bevor ich den Wert 0 erreiche verhält sich die LED fast wie eine 
Kerze, die langsam erlischt. Sie wird dunkler, und bäumt sich regelmäsig 
nochmal gegen das Erlischen auf. Man merkt direkt wie sie für den 
Bruchteil eines Augenblickes nochmal Heller wird.

Ich habe mir jetzt folgendes zusammengereimt:
Dieses Flackern liegt an der niedrigen Frequenz.
Die Frequenz ist zwar hoch genug dass im statischen Betrieb kein 
Flimmern zu erkennen ist.
Beim Runterdimmen allerdings ändern sich die BCM-Werte. Dabei kippen 
eben ab und zu die höherwertigen Bits (7,6,5). Die Bitzeiten dieser Bits 
sind bei der gewählten Frequenz anscheinend lange genug um mit dem Auge 
sichtbar zu sein. Somit liegt das Flackern eher daran, dass eben ein 
Sprung 0->1 oder 1->0 an einem Bit auftritt, das lange genug anliegt um 
sichtbar zu sein.
=> es liegt also doch an der Frequenz?

Kann meinen Gedankengang jemand bestätigen?

Danke bisher an alle Helfer!

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


Lesenswert?

Stefan M. schrieb:
> Marc Vesely, ich trau mich ja fast nicht fragen, aber magst du den Code
> vielleicht nochmal simulieren um zu bestätigen, dass ich die Bitzeiten
> jetzt einhalte? Ich bin hier auf Linux unterwegs und habe kein Atmel
> Studio...

 Hier die Zeiten:
 bit 0 =   511 Taktzyklen  min.      513 Taktzyklen  Max.
 bit 1 =   767 Taktzyklen  min.      769 Taktzyklen  Max.
 bit 2 =  1279 Taktzyklen  min.     1281 Taktzyklen  Max.
 bit 3 =  2304 Taktzyklen
 bit 4 =  4351 Taktzyklen
 bit 5 =  8449 Taktzyklen
 bit 6 = 16639 Taktzyklen
 bit 7 = 33025 Taktzyklen

 Muss jetzt gehen, werde später etwas genauer durch deinen Code gehen.
 Vielleicht kommt da etwas gescheites dabei raus, obwohl ich das stark
 bezweifle.

von Stefan M. (Gast)


Lesenswert?

Danke Marc, das hat zumindest ergeben dass ich mich im Prescaler verhaun 
hab ;-)

Stefan M. schrieb:
> Ich habe mir jetzt folgendes zusammengereimt:
> Dieses Flackern liegt an der niedrigen Frequenz.
> Die Frequenz ist zwar hoch genug dass im statischen Betrieb kein
> Flimmern zu erkennen ist.
> Beim Runterdimmen allerdings ändern sich die BCM-Werte. Dabei kippen
> eben ab und zu die höherwertigen Bits (7,6,5). Die Bitzeiten dieser Bits
> sind bei der gewählten Frequenz anscheinend lange genug um mit dem Auge
> sichtbar zu sein. Somit liegt das Flackern eher daran, dass eben ein
> Sprung 0->1 oder 1->0 an einem Bit auftritt, das lange genug anliegt um
> sichtbar zu sein.
> => es liegt also doch an der Frequenz?

Kann dazu noch jemand was sagen?
Mir will sonst einfach nicht einleuchten, wieso statischer Betrieb 
perfekt funktioniert, aber das Dimmen nicht.

von Peter D. (peda)


Lesenswert?

Man muß die Bitzeiten aufsteigend ausgeben und nach dem Setzen der 
höchstwertigen Bitzeit das komplette Bitmuster updaten. Dann können 
nicht mitten drin falsche Bits entstehen.
Das Main muß allerdings auch immer komplette Bitmuster erzeugen, ehe sie 
dann der Interrupt in das PWM-Array kopiert.

Bei meinem Code habe ich allerdings auch ohne Synchronisation kein 
Flackern bemerkt.
Das kann zum einen daran liegen, daß die PWM sehr hochfrequent ist und 
auch daran, daß das nächste Bitmuster per Macros sehr schnell in das 
PWM-Array konvertiert wird. Dadurch ist die Dauer und die 
Warscheinlichkeit des Flackerns stark reduziert.

Wenn man die Umsortierung der Bits mit geschachtelten Schleifen macht, 
dauert das viel länger. Und wenn man dann mitten drin halb alte und halb 
neue Daten auf die PWM gibt, flackert es.

100% flackersicher kann man es mit einem Flag machen.
Das Main wartet, bis das Flag gelöscht ist, erzeugt das neue Array und 
setzt das Flag.
Der Interrupt wiederum prüft das Flag und ist es gesetzt, kopiert er in 
der letzen Bitzeit das Main-Array in sein PWM-Array und löscht das Flag.

: Bearbeitet durch User
von Stefan M. (Gast)


Lesenswert?

PeDa,
ich danke dir dass du die Zeit gefunden hast hier ein paar Sätze dazu zu 
schreiben.

Allerdings, alle Dinge die du hier nennst sind in meinem (bzw dem 
batsocks Code mit meinen Änderungen) bereits enthalten.
Die Main ist mit der ISR auf die letzte (=längste Bitzeit 
synchronisiert).

Mir geht es hierbei in erster Linie darum zu verstehen, wo in meinem 
Code das Problem liegt. Denn meiner Meinung nach hab ich auf alles 
aufgepasst.
Deswegen will ich hier auch nicht auf deine Lösung zurückgreifen.

von Peter D. (peda)


Lesenswert?

Stefan M. schrieb:
> Allerdings, alle Dinge die du hier nennst sind in meinem (bzw dem
> batsocks Code mit meinen Änderungen) bereits enthalten.

>  while (g_tick != 1);
>  g_tick = 0;

Und wenn jetzt ein Interrupt kommt?
Das main freut sich nur, daß das Flag irgendwann mal gesetzt wurde. Das 
muß nicht gerade eben gewesen sein.

1)
g_tick darf erst nach der Umsortierung gelöscht werden.
Und der Interrupt muß g_tick testen und nur dann das neue Array in 
seinen Puffer übernehmen. Du brauchst einen zusätzlichen Puffer.

2)
Alternativ könnte ein weiterer Interrupt g_tick wieder löschen, wenn 
nicht mehr genug Zeit ist für das Main, das neue Array zu erzeugen.

3)
Alternativ ginge auch:
1
  g_tick = 0;
2
  while (g_tick != 1); // wait until next transition

2), 3) setzen voraus, daß die Umsortierung garantiert kürzer als die 
längste Bitzeit dauert.

von Stefan M. (Gast)


Lesenswert?

Hach ja, wie recht du doch hast... Kopf => Tisch

Werde ich heut Abend gleich mal testen.

Auf das Array werde ich erstmal auch verzichten und stattdessen nur mit 
einem Kanal (= normale Variable) Arbeiten. Dann sollte auch das 
Berechnen des Bitmusters garantiert nicht zu lange dauern.

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


Lesenswert?

Peter Dannegger schrieb:
> Bei meinem Code habe ich allerdings auch ohne Synchronisation kein
> Flackern bemerkt.

 Dasselbe hier.

Peter Dannegger schrieb:
> Der Interrupt wiederum prüft das Flag und ist es gesetzt, kopiert er in
> der letzen Bitzeit das Main-Array in sein PWM-Array und löscht das Flag.

 Habe ich auch gemacht, aber es war weder besser noch schlechter, da
 habe ich es wieder sein lassen.
 Von bit0 bis bit3 wird die ISR nicht verlassen, eine Änderung kann also
 nur von bit4 bis bit7 auftretten. Das sind bei etwas mehr als 1KHz
 PWM ganze 930us. Es ist 8 Kanal RGB bzw. 24 Kanal Mono.
 Dimmen und Farbenwechsel wird selten schneller als 50Hz gemacht, das
 sind 20ms. Ein Verhältnis also von mindestens 20 zu 1. Einfach keine
 Chance, daß man da etwas merkt, selbst wenn es beim 7-ten bit passieren
 sollte.
 Nur  ein wechseln zwischen 128 und 127 könnte BAM flackern lassen, aber
 auch nur dann, wenn dauernd zwischen diesen 2 Werten umgeschaltet wird
 und die Umschaltfrequenz langsamer als 20-30Hz ist.

 Somit bleibt beim TO nur die Dimmroutine übrig, die muß ja mit der
 ISR synchronisiert werden.

von Stefan M. (Gast)


Lesenswert?

Hallo zusammen,

ich bin immer noch am Testen meines Codes, heute habe ich endlich wieder 
Zeit.
So ganz hinhauen tuts immer noch ned.
Ich könnte natürlich PeDas Code benutzen, aber mir gehts immer noch 
darum meinen Fehler zu finden.

Evtl. liegts aber doch noch an den Parametern, also Frequenz, Auflösung 
und Update-Rate.

Kann hier mir jemand Zahlen aus eigener Erfahrung nennen, bei denen eine 
BCM ohne flackern funktioniert?

Also, z.B.:
300Hz BCM Frequenz, 9 Bit Auflösung, 10Hz Update-Rate

Dann könnte ich meinen Code an Parameter anpassen die woanders ja 
anscheinend laufen, und dort gezielt Fehlersuche betreiben.

Viele Grüße, und schönen Sonntag,
Stefan

von Falk B. (falk)


Lesenswert?

@Stefan M. (Gast)

>Ich könnte natürlich PeDas Code benutzen, aber mir gehts immer noch
>darum meinen Fehler zu finden.

Dann poste vollständigen, aktuellen Quelltext als Anhang.

von Stefan M. (Gast)


Angehängte Dateien:

Lesenswert?

Gerne, hie rmeine aktuelle Version, bereits mit dem von PeDa 
angesprochenen Bugfix

PS: mir wäre es trotzdem lieb wenn du mir das hier beantwortest 
(sozusagen als Hilfe zur Selbsthilfe)

Stefan M. schrieb:
> Kann hier mir jemand Zahlen aus eigener Erfahrung nennen, bei denen eine
> BCM ohne flackern funktioniert?

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


Lesenswert?

Stefan M. schrieb:
> Kann hier mir jemand Zahlen aus eigener Erfahrung nennen, bei denen eine
> BCM ohne flackern funktioniert?

 Habe ich dir doch.
 BAM mit etwas mehr als 1KHz.
 Dimmen von 10Hz bis 45Hz ohne flackern.
 Allerdings:
  Es wird logarithmisch gedimmt.
  Bei 10Hz - 20Hz und weniger als etwa 40 Schritten muss man die
  Übergänge bemerken.
  Bei linearem dimmen (also 255 Schritte) merkt man nichts, aber es
  ist halt nicht gleichmässig - von 1 bis 40 ist es sprunghaft, von
  180 bis 255 ist kaum ein Unterschied zu merken.

von Falk B. (falk)


Lesenswert?

@ Stefan M. (Gast)

>Gerne, hie rmeine aktuelle Version, bereits mit dem von PeDa
>angesprochenen Bugfix

Naja. So richitg gut ist es nicht. Denn du wartest auf das SYNC Signal, 
aber dann erst leiert die ganze Umwandlung an. Wie man es besser macht, 
steht im schon verlinkten Artikel.

https://www.mikrocontroller.net/articles/Soft-PWM#Intelligenter_L.C3.B6sungsansatz

Die Sache mit den Pointern ist optimal, es reicht auch, wenn man zuerst 
die Daten in einem lokalen Array berechnet und dann nach dem SYNC 
kopiert.

Deine ISR ist auch suboptimal.
1
// Timer interrupt handler - called once per bit position.
2
ISR( TIMER2_COMPA_vect )
3
{
4
  g_bitpos ++ ;
5
  g_bitpos &= 7;
6
  PORTD = g_timeslice[ g_bitpos ] ;
7
  // now set the delay...
8
  OCR2A <<= 1 ;
9
  if (g_bitpos == 0) OCR2A = 1 ; // reset the compare match value.
10
  if (g_bitpos == 7) g_tick = 1 ; // give the main loop a kick.
11
}

Hier wird teilweise mehrfach auf OCR2A geschrieben. Das geht einfacher 
und besser.
1
// Timer interrupt handler - called once per bit position.
2
ISR( TIMER2_COMPA_vect )
3
{
4
  g_bitpos ++ ;
5
  g_bitpos &= 7;
6
  PORTD = g_timeslice[ g_bitpos ] ;
7
8
  if (g_bitpos == 0) {
9
    OCR2A = 1 ; // reset the compare match value.
10
  } else {
11
    OCR2A <<= 1 ;
12
  }
13
  if (g_bitpos == 7) {
14
    g_tick = 1 ; // give the main loop a kick.
15
  }
16
}

Das ist aber nicht der Grund für das Flackern.

Deine BCM hat 8 Bit, das LSB ist 256 Takte, macht bei 8 MHz CPU Takt 122 
Hz. Sollte passen.

Hmmm?

Für die Neukodierung hat die CPU 256*128=32768 takte Zeit, das sollte 
reichen.

Was kann man besser machen? Keine variablen Schiebeoperationen!

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Schiebeoperationen
1
// encode an array of 8 LED brightness bytes into the pattern
2
// to be shown on the port for each of the 8 timeslices.
3
void led_encode_timeslices( uint8_t intensity[] )
4
{
5
  uint8_t portbits = 0;
6
  uint8_t bitvalue ;
7
  uint8_t mask;
8
9
  g_tick = 0;
10
  while (g_tick != 1);
11
  for ( uint8_t bitpos = 0, mask=1 ; bitpos < 8 ; bitpos++, mask<<=1 )
12
  {
13
    portbits = 0;
14
    bitvalue = 1 ;
15
    for ( uint8_t ledpos = 0 ; ledpos < 8 ; ledpos++ )
16
    {
17
      if (intensity[ ledpos ] & mask) portbits |= bitvalue ;
18
      bitvalue = bitvalue << 1 ;
19
    }
20
    g_timeslice[ bitpos ] = portbits ;
21
  }
22
}

Trotzdem sollten die 32k Takte reichen. Hmmm?

HUH! Ich glaube ich habs! Wegen deiner schlechten Formatierung (fehlende 
Einrückung!) steht dein led_encode_timeslices( brightness ) falsch! 
Besser so!
1
    while(1)
2
    {
3
      while(g_tick==0){ /*wait for g_tick to be non-zero*/ }
4
      slowtick-- ;
5
      if (slowtick==0)
6
      {
7
        slowtick = 100;
8
        position++ ;
9
        position &= 7 ;
10
        //for ( uint8_t index = 0 ; index < 8 ; index++ )
11
12
        if (brightness[ 6 ] > 0) brightness[ 6 ]-- ;
13
        else brightness[ 6 ] = 30 ;
14
        //and now re-encode all the timeslices...
15
        led_encode_timeslices( brightness ) ;
16
      }
17
    }
18
    return(0);
19
}

von Stefan M. (Gast)


Lesenswert?

Falk Brunner schrieb:
> HUH! Ich glaube ich habs! Wegen deiner schlechten Formatierung (fehlende
> Einrückung!) steht dein led_encode_timeslices( brightness ) falsch!
> Besser so!
Das ist unschön, ja.

Allerdings sehe ich nicht, wie sich das problematisch auswirken kann.
Momentan wird das Array öfter neu berechnet als notwendig. Solange die 
Update-Funktion auf die 7te Bitzeit synchronisiert ist sollte es aber 
deswegen nicht zu Problemen kommen.

Werde ich aber trotzdem mal ändern, Danke fürs drüberschauen!

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


Lesenswert?

Stefan M. schrieb:
> Momentan wird das Array öfter neu berechnet als notwendig. Solange die
> Update-Funktion auf die 7te Bitzeit synchronisiert ist sollte es aber
> deswegen nicht zu Problemen kommen.

 Ist es aber nicht unbedingt.
 g_tick aus led_encode und main() rausschmeissen,
 in main() led_encode rausschmeissen,
 brightness als volatile deklarieren.
 in der ISR nachdem bit7 steht, led_encode aufrufen.
 Anstatt:
1
  if (g_bitpos == 7) g_tick = 1 ; // give the main loop a kick.
 So:
1
  if (g_bitpos == 7) led_encode_timeslices( brightness ) ;


 slowtick rausschmeissen, mit _delay_ms dimmen.

: 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.