Forum: Compiler & IDEs Time interupt schneller machen


von Mike B. (mike13579)


Lesenswert?

Hallo ich hab eine LED Matrix  16X(noch16) soll später 16x192 (12x16) 
werden für die 16 Zeilen verwende ich einen ATmega32 und für die je 16 
spalten einen weiteren ATmega32 alle laufen mit 16MHz die sync. zwischen 
zielen und spalten läuft auch die Verwendung von den vielen ATmega32 
hängt damit zusammen das ich jede LED über soft PWM mit 255 stufen 
dimmen will und dabei komme ich nun zu einem Problem ich wollte dabei 
auch das menschlich Auge Ausgleich und muss dazu die kleinsten dimm 
stufen sehr klein machen stoße dabei aber an ein Problem mit dem zeit 
Interrupt der scheint leider etwa 136 (Vorteiler 8 x Zählerwert 17) 
takte zu brauchen. Hier der Interrupt:
1
ISR (TIMER1_COMPA_vect)
2
  {
3
  cli();
4
  OCR1A = coderunT[y][i];  //Aktualisirung Zeitwert OCR1A
5
  PORTA = coderunA[y][i];  //Aktualisirung Port A
6
  PORTC = coderunC[y][i];  //Aktualisirung Port C
7
  i++;  
8
  sei();
9
  }

die Idee für Soft PWM stammt hier her:
http://www.mikrocontroller.net/articles/Soft-PWM Version 3

die Idee zum Ausgleich des menschlich Auges von hier:
http://www.mikrocontroller.net/articles/LED-Fading

hat jemand eine Idee wie ich den Time-Interrupt verkürzen könnte?

von Uwe (de0508)


Lesenswert?

Hallo,

da wir nicht den gesamten Code sehen, rate ich mal.

Man muss den gesamten logischen Aufbau deines Programms überarbeiten !

In der Main könnte man
1
<datentype> * coderun_ptr= &coderunT[y];

zuweisen.

Was soll das ?
1
cli(); sei();

Welchen Datentyp hat |i++| ?

von Werner (Gast)


Lesenswert?

Mike B. schrieb:
> hat jemand eine Idee wie ich den Time-Interrupt verkürzen könnte?

Du könntest dir im übersetzen Code ansehen, was in der ISR alles auf dem 
Stack gesichert wird, Überflüssiges rauschschmeißen und den Rest als 
Assemblercode in dein Programm einbinden.

von Stefan E. (sternst)


Lesenswert?

Als erstes entfernst du mal das cli/sei. Das ist nicht nur komplett 
überflüssig, sondern sogar gefährlich.

Und dann probiere es mit "vorberechneten" Zeigern statt eines Indexes 
für die 1. Dimension.
Statt
1
uint8_t y;
2
3
main ...
4
  y = 2;
5
6
ISR ...
7
  OCR1A = coderunT[y][i];
eher so was
1
uint8_t *yT;
2
3
main ...
4
  yT = &coderunT[2][0]
5
6
ISR ...
7
  OCR1A = yT[i];

von Mike B. (mike13579)


Lesenswert?

hab eben komplett auf eindimensional umgebaut bring fast eine Halbierung 
der zeit SUPER cli/sei werde ich gleich mal probieren.

bezüglich:

"Du könntest dir im übersetzen Code ansehen, was in der ISR alles auf 
dem
Stack gesichert wird, Überflüssiges rauschschmeißen und den Rest als
Assemblercode in dein Programm einbinden."

ich verwende AVR Studo 4.17 neuer geht nicht wenden isp programmiert 
Gerät
wo kann ich das anschauen? Hab das noch nie gemacht!

von Mike B. (mike13579)


Lesenswert?

ohne cli/sei geht nicht es kommt zu starkem flimmern

von Peter II (Gast)


Lesenswert?

Mike B. schrieb:
> ohne cli/sei geht nicht es kommt zu starkem flimmern

das hast du wo anders noch mehr fehler drin, das cli/sei sollte auf 
jeden Fall dort nicht rein.

von Mike B. (mike13579)


Lesenswert?

ok dann schau mal drüber vielleicht siehst du ja was was ich falsch 
mache.
variablen Tabellen lass ich mal weg die brauchen zu fiel platz.
1
#include <stdint.h>
2
#include <string.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
6
int main()
7
{
8
DDRA = 0xFF; 
9
DDRC = 0xFF;
10
DDRD = 0x00;
11
DDRB = 0x00;
12
13
  //ext inetrupt
14
  GIMSK |= (1<<INT1); //(External Interrupt Request 1 Enable) 
15
  GIMSK |= (1<<INT0); //(External Interrupt Request 0 Enable) 
16
  MCUCR |= (1<<ISC11); //Die steigende Flanke an INT1 erzeugt einen Interrupt
17
  MCUCR |= (1<<ISC10); //Die steigende Flanke an INT1 erzeugt einen Interrupt
18
  MCUCR |= (1<<ISC01); //Die steigende Flanke an INT0 erzeugt einen Interrupt.
19
  MCUCR |= (1<<ISC00); //Die steigende Flanke an INT0 erzeugt einen Interrupt.
20
21
22
// Timer 1 konfigurieren (16bit)
23
  TCCR1B |= (1<<WGM12); // CTC Modus
24
//  TCCR1B |= (1<<CS12); // Prescaler 256/1024
25
  TCCR1B |= (1<<CS11); // Prescaler 8 /64
26
//  TCCR1B |= (1<<CS10); // Prescaler 64/1024/1
27
// (16000000/64/1600) = 156,25
28
// (16000000/8/408000) = 4,9
29
  OCR1A= 20000;
30
// Compare Interrupt erlauben
31
  TIMSK |= (1<<OCIE1A);
32
  
33
34
35
36
37
38
// Global Interrupts aktivieren// Global Interrupts aktivieren
39
  sei();
40
//hauptrotine
41
while( 1 ) 
42
{
den code zum füllen des RAMs (neues Bild) lass ich auch weg der greift 
in den anderen code nicht ein.
1
 
2
ISR(INT0_vect)
3
  {
4
  TCNT1 = 0;  //sync Timer
5
  y=0;    //sync Bild
6
  OCR1A = 1;  //direkter aufruf time interupt  
7
  }
8
ISR(INT1_vect)
9
  {
10
  y++;    //sync Zeile Zählen
11
  if (y==16)y=0;
12
  i=y*16;    //sync Zeile PWMwert  
13
  PORTA = 0x00;  //Verhindert schaten von vorhergegangener zeile Port A
14
  PORTC = 0x00;  //Verhindert schaten von vorhergegangener zeile Port C      
15
  }
16
//time interupt
17
ISR (TIMER1_COMPA_vect)
18
  {
19
  cli();
20
  OCR1A = coderunT[i];  //Aktualisirung Zeitwert OCR1A
21
  PORTA = coderunA[i];  //Aktualisirung Port A
22
  PORTC = coderunC[i];  //Aktualisirung Port C
23
  i++;  
24
  sei();
25
  }
die ersten beiden Interrupts synchronisieren die zwei Atmega32 für Zeile 
und Spalte der code hier ist für Spalte

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.