Hallo AVR-Profis,
ich habe eine Frage zur Nutzung der Timer in den Series 1 ATtinys
(momentan ATTiny814).
Ich möchte gerne z.B. alle 64 CPU-Take ein Trigger-Signal ausgeben und
dann jeden 4096ten Durchlauf davon in einen IRQ Daten übertragen.
Überlicherweise eignet sich dafür der SINGLE_OVF Mode:
1
voidTCA0_init(void)
2
{
3
/* enable overflow interrupt */
4
TCA0.SINGLE.INTCTRL=TCA_SINGLE_OVF_bm;
5
/* set Normal mode */
6
TCA0.SINGLE.CTRLB=TCA_SINGLE_WGMODE_NORMAL_gc;
7
/* disable event counting */
8
TCA0.SINGLE.EVCTRL&=~(TCA_SINGLE_CNTEI_bm);
9
/* set the period */
10
TCA0.SINGLE.PER=4096;
11
TCA0.SINGLE.CTRLA=TCA_SINGLE_CLKSEL_DIV64_gc/* set clock source (sys_clk/64) */
12
|TCA_SINGLE_ENABLE_bm;/* start timer */
13
}
Ich möchte nun also an einem Pin, z.B. PB0 =(WO0) den Timer-Takt als
Trigger ausgeben.
Wie muss ich den TCA0 dazu noch konfigurieren, oder geht das mit dem
Event-System?
Wer kann mir das weiterhelfen?
PORTMUX scheint beim ATTiny814 nicht zu funktionieren:
Zu dem ATtiny841 kann ich nichts Definitives sagen, aber das 'Register
Summary' für den TCA0 sieht, zumindest auf den ersten Blick, bei den
AVRnDx gleich aus, und dort läuft es. Falls es weiterhilft, hier der
Assemblercode, sollte allgemeinverständlich sein:
Hallo,
vielen Dank für die schnelle Antwort!
Den Split mode hatte ich wegen der schlechter dokumentierten Handhabung
und Aufteilung 16bit-> 2x8Bit bei 4096 Schritten bislang nicht
berücksichtigt.
Ich habe es letztlich geschafft, die passenden gcc-Makros dazu zu
finden.
So wie ich es verstehe, nutzt du den Split-Mode (der ja nur 8-Bit hat)
um in 2 Schritten auf 4096 zu kommen, richtig?
Und die beiden 8-Bit "Pseudo-PWMs" (mit Länge 2) werden nun auf den WO0
und WO1 ausgegeben und könnten als Trigger genutzt werden?
Wird auch der TCA0-Haupttakt (CLKSEL_DIV16) auf einem Pin ausgegeben,
denn den brauche ich ja auf jeden Fall?
Die zugehörige ISR, läuft die mit (CLKSEL_DIV16) oder
CLKSEL_DIV16/4/256?
So richtig verstehe ich die Fragen nicht; ich will es mal aus meiner
Sicht versuchen:
> Ich möchte gerne z.B. alle 64 CPU-Take ein Trigger-Signal> ausgeben und dann jeden 4096ten Durchlauf davon in einen> IRQ Daten übertragen.
Diese Anforderung war der Ausgangspunkt: TCA0 läuft mit dem Vorteiler 16
(CTRLA); im Low-Byte wird weiter geteilt durch 4 und eine PWM (mit /64)
für das verlangte 'Trigger-Signal' erzeugt, im High-Byte wird weiter
geteilt durch 256 für den Interrupt (mit /4096).
Falls das
> jeden 4096ten Durchlauf davon
sich jedoch nicht auf den CPU-Takt (wie von mir interpretiert), sondern
auf das Triggersignal bezieht, reichen die 8-bit natürlich nicht aus -
dann wäre vielleicht ein Softwarezähler auf 16 in der ISR eine Lösung.
Damit bekomme ich einen IRQ und der Wo0 toggled wie gewünscht, so weit
sehr gut.
Da der Split-mode aber nur 8 bit hat, habe ich maximal 256 Düchläufe der
ISR. ich brauche aber 4096.
Hat einer dazu eine Idee?
Unsere Antworten haben sich überschnitten, deine Lösung läuft gut, aber
ja ich benötige 4096 ISR-Durchläufe.
Beim Atmega328/Tiny85 ging so was doch mit dem TIMER0_COMPA_vect,
1
// CTC with OCR0A as TOP
2
TCCR0A=(1<<WGM01);
3
// clk_io/1024 (From prescaler)
4
TCCR0B=((1<<CS02)|(1<<CS00));
5
// Generate an interrupt every 4096 clock cycles
6
OCR0A=3;
7
// Enable Timer/Counter0 Compare Match A interrupt
8
TIMSK0|=(1<<OCIE0A);
ich dachte so was sollten die neuen auch beherrschen, irre ich mich?
So ad hoc sehe ich keine Lösung, wenn nicht ein weiterer der bei den
Tinies raren Timer geopfert werden soll.
Aber wie wäre es mit dem vorgeschlagenen Zähler in Software? Oder ist
die Auslastung so hoch?
Lars H. schrieb:> Ich möchte gerne z.B. alle 64 CPU-Take ein Trigger-Signal ausgeben und> dann jeden 4096ten Durchlauf davon in einen IRQ Daten übertragen.
Alle 64 Zyklen ein Interrupt, ist schon recht heftige CPU-Last und
dürfte auch einen hohen Jitter haben. Außerdem besteht die Gefahr, daß
andere Interrupts in die Suppe spucken.
Ich würde daher 2 Timer benutzen. Der eine macht den 64 Zyklen-Puls in
Hardware (Waveform Generation Mode), d.h. ganz ohne CPU-Last.
Der andere Timer macht dann die Aktion alle 262144 Zyklen per Interrupt,
also völlig zeitunkritisch.
Ob man das per Split-Mode machen kann, weiß ich nicht. Die Timer im
Tiny814 unterscheiden sich ja extrem zu denen in den Classic-AVRs.
Peter Dannegger schrieb:
> Alle 64 Zyklen ein Interrupt
Die 64 Takte gelten für das Trigger-Signal, welches in Hardware per PWM
erzeugt wird. Die ISR wird derzeit alle 4096 Takte aufgerufen, da
könnte/sollte dann eine weitere Teilung per Software möglich sein.
Wenn es sein muss, kann ich den TCB auch mit nutzen.
Also könnte eine Lösung folgendes sein:?
1. TCA mit Prescaler (z.B. 64) laufen lassen
2. TCB im 8-bit PWM mit diesem Takt das Trigger-Signal erzeugen
3. mit dem TCA den Overlow-mode bei 4096 einen IRQ auslösen, der dann
entsprechen die Datenausgabe übernimmt.
Was denkt ihr, ginge das?
Peter D. schrieb:> Die Timer im> Tiny814 unterscheiden sich ja extrem zu denen in den Classic-AVRs.
Was heißt hier "extrem"?
Der TCA ist ein Universaltimer und kann selbstverständlich alles, was
frühere AVR Timer/Counter machen.
Für weniger anspruchsvolle Aufgaben (z.B. Periodic Interrupt) gibt es
zusätzlich den TCB, der auch synchron mit dem TCA laufen kann.
Wenn der TCB genutzt wird, muss ich allerdings einen anderen Port
nutzen, das wäre ungünstig.
>Der TCA ist ein Universaltimer und kann selbstverständlich alles, was
frühere AVR Timer/Counter machen.
Das versuche ich ja und - soweit ich das sehen kann - hatte der ATtiny85
Timer0 noch die von mir gesuchte Möglichkeit:
1
2
// CTC with OCR0A as TOP
3
TCCR0A=(1<<WGM01);
4
// clk_io/64 (From prescaler)
5
TCCR0B=(1<<CS01)|(1<<CS00);
6
// Generate an interrupt every (Value_CTC_TOP + 1) * 64 clock cycles
7
OCR0A=Value_CTC_TOP;
Damit kann - wie von mir benötigt - so weit ich weiß das Triggersignal
am PB4 ausgegeben werden
Sowas scheint der neue TCA beim ATtiny814 nicht (mehr) zu können, oder
blicke ich es nur nicht?
Es werden doch zwei verschiedene Frequenzen benötigt, oder habe ich das
falsch verstanden? F_CPU/64 fur das Triggersignal sowie F_CPU/262144 für
diese Datensende-ISR?
Und zwei Frequenzen mit dem ATtiny85.Timer0? Nicht dass ich wüsste.
Hallo,
eine wichtige Nachfrage von S. Landolt blieb noch unbeantwortet. Worauf
beziehen sich die 4096 Takte? Auf den gleichen Ursprungstakt wie die 64
Takttriggergeneration oder auf die Triggerauslösung aller 64 Takte? Also
möchtest du aller 4096 Takte Daten ausgeben oder aller 64*4096?
Hallo,
um es klar zu stellen.
Ich benötige:
1. den Systemtakt mit Prescaler -> CLK/64
2. ein Trigger-Ausgang auf einem Port (am besten PB0/Wo0) mit diesem
Takt (CLK/64)
3. eine ISR mit CLK/64/4096 (am einfachsten TCA OVFL), in der Daten
rausgeschickt werden
Hallo,
ich glaube jetzt habe ich das verstanden.
a) aller 64 Takte Trigger
b) aller 262144 Takte Datenausgabe oder anders gesagt aller 4096
"Events" von a).
Mal eine verrückte Idee für den Fall das ein Timer noch für andere
Zwecke benötigt wird. Die RTC ist frei? Dann lege den 64er Takt vom
Timerausgang mit an den externen RTC Takteingang. Intern übers
Eventsystem verbinden scheint nicht vorgesehen zu sein. Oder ich habe es
noch nicht gefunden. Laut meines Wissens kann die RTC nur Events
erzeugen. Dann konfigurierst du die RTC auf aller 4096 Takte was machen.
Hast die Wahl zwischen Eventsystem oder Interrupt.
S. Landolt schrieb:> Peter Dannegger schrieb:>> Alle 64 Zyklen ein Interrupt>> Die 64 Takte gelten für das Trigger-Signal, welches in Hardware per PWM> erzeugt wird. Die ISR wird derzeit alle 4096 Takte aufgerufen, da> könnte/sollte dann eine weitere Teilung per Software möglich sein.
Du hast ja schon weiter oben vorgeschlagen, den Timer zu splitten. Wenn
also die Intention des TO wirklich nicht war, alle 4096 CPU-Takte den
Interrupt zu erzeugen, sondern vielmehr alle 4096 Zyklen des
Triggersignals, dann geht natürlich noch mehr, nämlich ein Interrupt
alle 16384 CPU-Takte.
Klar man muss dann in Software noch eine Variable zyklisch bis 16
hochzählen lassen, aber das sollte ja wohl spätestens dann wirklich kein
Problem mehr sein.
Übrigens, zum Split-Betrieb mit Kaskadierung: Scheinbar gibt es keine
"direkte" Möglichkeit, das zu erreichen, wenn, dann müsste man über das
Eventsystem gehen. Da wird's allerdings irgendwie etwas dünne mit der
Doku. Klar ist die Event-Quelle, das ist easy. Aber für den Event-User
ist das leider weit weniger klar. In dem Abschnitt für den Split-Mode
taucht die Konfiguration für einen Event-Input garnicht erst auf.
Das könnte heißen: Das geht garnicht. Oder es könnte heißen: Wir haben's
vergessen zu dokumentieren. Hast du damit schonmal rumgespielt?
Ich würde mal vermuten, dass die Konfiguration wie im Normalmode ist,
aber sich grundsätzlich nur auf den Lo-Teil bezieht (was natürlich im
Nicht-Split-Betrieb den gesamen Timer betreffen würde). Wie gesagt: das
würde ich vermuten, ausprobiert habe ich es nicht, da bisher nie
benötigt.
Wäre aber schonmal interessant, ob das geht. Wenn es so wäre, wie ich
vermute, würde es für die konkrete Anwendung des TO bedeuten, dass der
"schnelle" Timer der Hi-Teil sein muss, der langsame, abhängige der
Lo-Teil, also genau umgekehrt wie bei der impliziten Kaskadierung im
Normal-Mode.
c-hater schrieb:> Oder es könnte heißen: Wir haben's> vergessen zu dokumentieren.
Der neue Dokustil gefällt mir generell nicht. Man kann da nur sehr
schwer durchsehen. Da ist kein System dahinter.
Die Blockschaltbilder kann man in der Pfeife rauchen, z.B. "Figure
20-13. Timer/Counter Block Diagram Split Mode." Alles geht in die
Black-Box "Control Logic". Man könnte vermuten, daß der Prescalerausgang
auf beide Timer parallel geht.
Dagegen z.B. beim 8051 kapiert den Split-Mode jeder Dödel sofort (siehe
Bild).
Hallo,
vielen Dank für eure Hilfe, ich habe das jetzt mit TCA/TCB umgesetzt:
-TCA läuft mit CLKSEL_DIV64 und erzeugt mit einer "Pseudo-PWM" das
Takt/Triggersignal an Wo0
-TCB läuft mit TCA-Takt ein Timer mit TCB0.CCMP=4095
-> damit wird ISR(TCB0_INT_vect) ausgelöst
Das läuft in gcc wunderbar.
Es hat sich gelohnt euch zu fragen, viele gute Ideen und Ratschläge, die
zur Lösung geführt haben.
Viele Grüße,
Lars