Forum: Mikrocontroller und Digitale Elektronik ATtiny25 asynchronen Modus von Timer1 aktivieren


von Jürgen (Gast)


Lesenswert?

Guten Tag,

ich versuche nun schon seit gestern den Timer1 des ATtiny 25 im 
asynchronen Modus mit 64Mhz zu betreiben. Durch das Datenblatt werde ich 
nicht schlauer. Im Datenblatt steht, dass PCKE in PLLCSR gesetzt sein 
muss, aber das habe ich ja.
Muss ich eventuell etwas an den Fusebits ändern? - momentan betreibe ich 
den ATtiny mit internen 8Mhz-

Es wäre echt klasse, wenn mir hier jemand einen entscheidenden Tipp 
geben kann.

Meine Timerinitialisierung:
1
// Timer 1 konfigurieren: 
2
TCCR1 |= (1<<CS10); 
3
PLLCSR |= (1<<PCKE);
4
5
//Overflow Interrupt Timer 1 aktivieren
6
TIMSK |= (1<<TOIE1);
7
8
// Global Interrupts aktivieren
9
sei();

Vielen Dank shconmal!

von Stefan E. (sternst)


Lesenswert?

Jürgen schrieb:
> Im Datenblatt steht, dass PCKE in PLLCSR gesetzt sein
> muss, aber das habe ich ja.

Da steht aber noch mehr. Wie ich schon im anderen Thread (warum 
überhaupt ein neuer?) sagte, du musst anfangen genauer zu lesen. Nur 
einen flüchtigen Blick rein werfen reicht nun mal einfach nicht.

In der Beschreibung zu PCKE steht z.B. auch:
1
This bit can be set only if PLLE bit is set. It is safe to set this
2
bit only when the PLL is locked i.e the PLOCK bit is 1. The bit PCKE can
3
only be set, if the PLL has been enabled earlier.
Daraus ergibt sich eine einzuhaltende Folge von 3 Schritten.
Welche sind das?

von Jürgen (Gast)


Lesenswert?

Ich hab einen enuen Thread aufgemacht, da sich mein Problem nun 
eingrenzen lies und ich dachte, dass es mit der genauernen Überschrift 
überischtlicher wird.

Mit den 3 Schritten müsste der code so aussehen?:
1
// Timer 1 konfigurieren: Clock = PCK 
2
TCCR1 |= (1<<CS10); 
3
4
//asynchronen Modus aktivieren (64Mhz)
5
PLLCSR |= (1<<PLOCK); 
6
PLLCSR |= (1<<PLLE);
7
PLLCSR |= (1<<PCKE);
8
9
//Overflow Interrupt Timer 1 aktivieren
10
TIMSK |= (1<<TOIE1);

Leider scheint irgend etwas immer noch nicht zu stimmen? - Mein Programm 
funktioniert zumindest noch nicht wie es soll...

Danke für deine Geduld mit mir ;) - ich hab an einer völlig falschen 
Stelle im Datenblatt gesucht.

von Stefan E. (sternst)


Lesenswert?

Und weiterhin machst du den Fehler nur flüchtig zu lesen.
Oder macht das Englisch dir Probleme?

Die drei Schritte sind:
1) PLL aktivieren
2) Warten bis PLL eingerastet
3) PCKE setzen

von Jürgen (Gast)


Lesenswert?

Im Englischen bin ich zugegeben auch nicht besonders fit...

Wie realisiere ich denn das warten bis PLL einrastet ?

Also Schritt 1 ist:
1
PLLCSR |= (1<<PLLE);

Schritt 3 ist:
1
PLLCSR |= (1<<PCKE);

Falls ich das warten dadurch realisiere, dass ich das PLOCK bit setze 
ist Schritt 2:
1
PLLCSR |= (1<<PLOCK);

Allerdings funktioniert so das Programm acuh ncoh nciht...

Danke weiterhin

von Stefan E. (sternst)


Lesenswert?

Jürgen schrieb:
> Falls ich das warten dadurch realisiere, dass ich das PLOCK bit setze

PLOCK ist Read-Only, das kannst du nicht selber setzen. Das wird von der 
Hardware gesetzt.

1
•Bit 0 - PLOCK: PLL Lock Detector
2
When the PLOCK bit is set, the PLL is locked to the reference clock.
3
The PLOCK bit should be ignored during initial PLL lock-in sequence
4
when PLL frequency overshoots and undershoots, before reaching steady
5
state. The steady state is obtained within 100 µs. After PLL lock-in
6
it is recommended to check the PLOCK bit before enabling PCK for
7
Timer/Counter1.
PLOCK gibt also an, ob die PLL eingerastet ist, oder nicht. Allerdings 
soll man dieses Bit in der ersten Startphase der PLL ignorieren. Diese 
erste Startphase dauert 100µs. Daraus ergibt sich, dass dies
> Wie realisiere ich denn das warten bis PLL einrastet ?
wiederum aus zwei Schritten besteht:
1) 100µs warten
2) warten bis PLOCK 1 ist

von avion23 (Gast)


Lesenswert?

Mein Code:
1
void initTimer1(void){
2
  //cs13:cs10 = 0010 for 125kHz
3
  //cs13:cs10 = 0001 for 250kHz
4
  //TCCR1 |= (1<<CTC1);    // Clear timer/counter on compare match
5
  TCCR1 |= (1<<PWM1A);    // Pulse width modulator A enable
6
  //TCCR1 |= (1<<COM1A1);    // comparator A mode select, 01 here
7
  TCCR1 |= (1<<COM1A0);
8
  //TCCR1 |= (1<<CS13);      // clock select, prescaler
9
  //TCCR1 |= (1<<CS12);      // 125kHz
10
  TCCR1 |= (1<<CS11);
11
  //TCCR1 |= (1<<CS10);
12
13
  //GTCCR = 0;
14
  //GTCCR |= (1<<PWM1B);      // enable PWM B
15
  //GTTCR |= (1<<COM1B1);      // comparator B mode select
16
  //GTTCR |= (1<<COM1B0);
17
  //GTTCR |= (1<<FOC1B);    // force output compare match
18
  //GTTCR |= (1<<FOC1A);    // force output compare match
19
  //GTTCR |= (1<<PSR1);      // Reset the prescaler
20
21
  OCR1A = 100;
22
  OCR1B = 0;
23
  OCR1C = 255;        // maximum value for pwm
24
  //TIMSK |= (1<<OCIE1A);    // Output compare match a interrupt enable
25
  PLLCSR |= (1<<PLLE);    // enable PLL before enabling it as source for timer1
26
  _delay_us(100);        // wait 100us for pll to stabilize
27
  //PLLCSR |= (1<<LSM);     // low speed mode
28
29
  // lock detection
30
  // Blocks until lock is detected, i.e. PLOCK = 1
31
  while(!(PLLCSR & (1<<PLOCK)))
32
      ;
33
34
  PLLCSR |= (1<<PCKE);    // enable PLL as timer1 clock source
35
36
  // init dead times
37
  //DTPS1 |= (1<<DTPS11);       // dead time prescaler
38
  //DTPS1 |= (1<<DTPS10);      // 00 = 1, 11 = 8
39
/*
40
  // amount of dead cycles coded in binary
41
  DT1A |= (1<<DT1AH3);
42
  DT1A |= (1<<DT1AH2);
43
  DT1A |= (1<<DT1AH1);
44
  DT1A |= (1<<DT1AH0);
45
  DT1A |= (1<<DT1AL3);
46
  DT1A |= (1<<DT1AL2);
47
  DT1A |= (1<<DT1AL1);
48
  DT1A |= (1<<DT1AL0);
49
*/
50
}

von Stefan E. (sternst)


Lesenswert?

avion23 schrieb:
> Mein Code:

Genau. Da versucht man ihn dazu zu bringen es so weit wie möglich selber 
herauszufinden, nur damit dann doch wieder jemand vorbeikommt und ihm 
eine vorgekaute Fertiglösung hinspuckt.

von Jürgen (Gast)


Lesenswert?

Vielen Dank !

Nun bin ich auf jedenfall schon um einiges klüger.
Allerdings tut mein Programm immer noch nciht was es soll - Es soll eine 
rote LED immer heller faden.

Wwäre toll, wenn ihr nochmal über meinen gesamten Programmcode schauen 
könntet:
1
#ifndef F_CPU
2
#define F_CPU 8000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
9
#define rot_an    PORTB |= (1 << PB1)
10
#define rot_aus    PORTB &= ~(1 << PB1)
11
12
// Variablen definieren
13
volatile uint8_t rot;
14
volatile uint16_t timer; 
15
16
uint16_t Helligkeit[64] = {  0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5,
17
              5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17,
18
              19, 21, 23, 26, 29, 32, 36, 40, 44, 49, 55,
19
              61, 68, 76, 85, 94, 105, 117, 131, 146, 162,
20
              181, 202, 225, 250, 279, 311, 346, 386, 430,
21
              479, 534, 595, 663, 739, 824, 918, 1023};
22
23
// ***** Timer1-Overflow-Interrupt ****** --> PWM Frequenz = 8MHz/1023/256(Timer)/1(Prescaler) = 32 Hz
24
ISR (TIMER1_OVF_vect){ 
25
// zähle die Variable timer von 0-1023
26
timer++;
27
if (timer > 1023) {timer = 0;}
28
}
29
30
// ***** Timer0-Overflow-Interrupt ******
31
ISR (TIMER0_OVF_vect){ 
32
rot++;
33
if (rot > 64) {rot = 0;}
34
}
35
36
// ***** Hauptprogramm *****
37
int main(void){
38
// Variablen setzen
39
rot = 0;
40
timer = 0;
41
42
// PortB 345 zu Ausgängen und auf 0
43
DDRB |= (1<<DDB3)|(1<<DDB4)|(1<<DDB1);
44
PORTB &= ~(1<<PB3)|(1<<PB4)|(1<<PB1);
45
                
46
// Timer 1 konfigurieren: Clock = PCK 
47
TCCR1 |= (1<<CS10); 
48
//asynchronen Modus aktivieren (64Mhz) - dazu: 1) PLL aktivieren 2) Warten bis PLL eingerastet 3) PCKE setzen
49
PLLCSR |= (1<<PLLE);
50
  _delay_us(100); 
51
while(!(PLLCSR & (1<<PLOCK)))
52
      ;
53
PLLCSR |= (1<<PCKE);
54
55
//Overflow Interrupt Timer 1 aktivieren
56
TIMSK |= (1<<TOIE1);
57
58
// Timer 0 konfigurieren: Prescaler 1024
59
TCCR0B |= (1<<CS00)|(1<<CS02);
60
// Overflow Interrupt Timer 0 aktivieren
61
TIMSK |= (1<<TOIE0);
62
63
// Global Interrupts aktivieren
64
sei();
65
66
// ***** Endlosschleife *****
67
while(1){
68
if (timer < Helligkeit[rot]) {rot_an;}
69
else {rot_aus;}
70
71
} //eof while
72
} //eof main

Danke! Ihr rettet mir mein Wochenende :-)

von avion23 (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Genau. Da versucht man ihn dazu zu bringen es so weit wie möglich selber
> herauszufinden, nur damit dann doch wieder jemand vorbeikommt und ihm
> eine vorgekaute Fertiglösung hinspuckt.

Oh Sorry. Ich habe den Thread nicht gelesen, ich habe nur gesehen, dass 
jemand ein Problem hat und wollte helfen.

@ jürgen

Du musst das leider selbst mache. Ich würde so vorgehen:
- testen ob pwm funktioniert mit 10, 100, 250 als werte
- überprüfen ob ISR aufgerufen wird, und wie oft, z.B. über led togglen.
und dann erst deinen Code.
Übrigens hilft es funktionierenden code in funktionen zu packen.

von Jürgen (Gast)


Lesenswert?

Sobald ich den Timer 1 nicht im asynchronen Modus mit 64 Mhz betreibe 
sondern mit 8Mhz(interner Takt ohne Prescaler) funktioniert der code 
einwandfrei, die LED flackert nur sehr stark, da ja meine PWM Frequenz 
nur 8Mhz / 256(8bit-Timer1) /1024(Variable"timer") /1(Prescaler)= 30,5 
Hz beträgt.
Wenn ich es nun aber schaffe den Timer 1 mit 64 Mhz zu betreiben reicht 
die Frequenz und es sollte nciht mehr flackern?

Leider leuchtet die LED nun anscheinend durchgehend(volle Helligkeit) 
und die ISR scheint nicht aufgerufen zu werden. (Dies habe ich getestet 
indem ich in der ISR eine andere LED angeschaltet habe.)

Hier die Version meines funktionierenden codes(mit flackernder LED):
1
#ifndef F_CPU
2
#define F_CPU 8000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
9
#define rot_an    PORTB |= (1 << PB1)
10
#define rot_aus    PORTB &= ~(1 << PB1)
11
12
// Variablen definieren
13
volatile uint8_t rot;
14
volatile uint16_t timer;
15
16
uint16_t Helligkeit[64] = {  0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5,
17
              5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17,
18
              19, 21, 23, 26, 29, 32, 36, 40, 44, 49, 55,
19
              61, 68, 76, 85, 94, 105, 117, 131, 146, 162,
20
              181, 202, 225, 250, 279, 311, 346, 386, 430,
21
              479, 534, 595, 663, 739, 824, 918, 1023};
22
23
// ***** Timer1-Overflow-Interrupt ****** --> PWM Frequenz = 8MHz/1023/256(Timer)/1(Prescaler) = 32 Hz
24
ISR (TIMER1_OVF_vect){ 
25
// zähle die Variable timer von 0-1023
26
timer++;
27
if (timer > 1023) {timer = 0;}
28
}
29
30
// ***** Timer0-Overflow-Interrupt ******
31
ISR (TIMER0_OVF_vect){ 
32
rot++;
33
if (rot > 64) {rot = 0;}
34
}
35
36
// ***** Hauptprogramm *****
37
int main(void){
38
// Variablen setzen
39
rot = 0;
40
timer = 0;
41
42
// PortB 345 zu Ausgängen und auf 0
43
DDRB |= (1<<DDB3)|(1<<DDB4)|(1<<DDB1);
44
PORTB &= ~(1<<PB3)|(1<<PB4)|(1<<PB1);
45
                
46
// Timer 1 konfigurieren: Clock 8Mhz
47
TCCR1 |= (1<<CS10);
48
49
//Overflow Interrupt Timer 1 aktivieren
50
TIMSK |= (1<<TOIE1);
51
52
// Timer 0 konfigurieren: Prescaler 1024
53
TCCR0B |= (1<<CS00)|(1<<CS02);
54
// Overflow Interrupt Timer 0 aktivieren
55
TIMSK |= (1<<TOIE0);
56
57
// Global Interrupts aktivieren
58
sei();
59
60
// ***** Endlosschleife *****
61
while(1){
62
if (timer < Helligkeit[rot]) {rot_an;}
63
else {rot_aus;}
64
65
} //eof while
66
} //eof main

Da ich ja nur die Frequenz von Timer 1 ändere (und nicht die von Timer 
0!) verstehe ich nciht, warum es nciht Funktioniert, wenn doch nun die 
Timerinitialisierung richtig seien sollte.

Grüße
Jürgen

von avion23 (Gast)


Lesenswert?

- clkdiv 8 fuse deaktiviert? default ist an, dann werden aus deinen 8MHz 
1MHz
- avr entkoppelt mit ~100nF Keramik?
- Versorgungsspannung 5V?
- _delay_us(100) mal auf _delay_ms(1) stellen und testen.
- nicht 64 mhz sondern 32mhz verwenden. da gibt's ein bit mit dem du auf 
den slow modus umschalten kannst o.ä.

von Jürgen (Gast)


Lesenswert?

- clkdiv 8 fuse ist deaktiviert
- _delay auf 1ms bringt nichts
- 32Mhz eingestellt, also das LSM bit gesetzt und es geht
- Habe den Attiny nicht mit einem Kondensator entkoppelt und würde mir 
dies auch gerne sparen - könnte ich damit denn die 64 Mhz fahren? - wie 
wird der Kondesnator angeschlossen?

Danke nochmal!

von avion23 (Gast)


Lesenswert?

Jürgen schrieb:
> - 32Mhz eingestellt, also das LSM bit gesetzt und es geht
D.h. Problem ist im Prinzip gelöst? Ursache dafür kann sein:
- zu niedrige Versorgungsspannung. Takt gegen Spannung steht im 
Datenblatt. Ab wann schafft er denn die PLL mit 64MHz?
- kein Kondensator. Wie das geht steht in einer application note von 
atmel, im rn-wissen wiki sehr anschaulich und überall sonst im internet

von Jürgen (Gast)


Lesenswert?

- Die Versorgungsspannung beträgt 5Volt (über 7805)
- Die 64 Mhz sollte er laut Datenblatt ab 2,7 Volt schaffen glaube ich

Bis jetzt hab ich es noch nciht geschafft, dass es mit 64Mhz geht.

Ich werde mich nun noch über den Kondensator schlau lesen.

von avion23 (Gast)


Lesenswert?

<Nekrophilie>
Es ist mit Sicherheit der Kondensator gewesen. Das habe ich 
herausgefunden, weil bei mir der 100nF nicht richtig verlötet war. Ohne 
die 100nF resetet er oder stürzt mitten im Programm ab. Alles nicht 
reproduzierbar und sehr frustrierend.
</Nekrophilie>

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.