Forum: Projekte & Code AVR: Fast-PWM (BAM) 12 Bit für 8 Kanäle


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei mal meine Version der 8 * 12Bit BAM komplett als Knight Rider.
Bei 8MHz CPU-Takt ergibt sich eine PWM von 2kHz.
Verschiedene PWM- und Dimmstufen kann man in der "main.h" ausprobieren.

Benutzt wird ein 16Bit Timer mit 2 Compare-Interrupts.
Für 8 LEDs braucht man ja eh mindestens einen ATtiny24.
Eine Änderung auf >12 Bit oder 16 Ausgänge sollte kein Problem sein.
Bei 16 Ausgängen ist die Bitzeit natürlich 2 Zyklen.

Der Interrupthandler wurde auf den GAS umgeschrieben, was nicht so 
schwer war. Auch werden alle Register gesichert, so daß es keine 
Probleme mit den C-Routinen gibt. Damit lassen sich alle nicht 
zeitkritischen Routinen bequem in C schreiben.
Die unterschiedliche Laufzeit der beiden Interrupts bis zur Portausgabe 
wird im OCR1BL-Wert korrigiert.

Die Umwandlung der PWM-Werte in die Ausgabedaten erfordert ein 
Umsortieren von quer nach längs. Das wird mit Bitbefehlen gemacht (SBRS 
+ OR). Der Compiler hat das auch sofort gemerkt und alle Variablen in 
Register gehalten. Dadurch ist der Code klein und sauschnell.
Die Polarität der LEDs ist per Define einstellbar.

Die Umwandlung der Helligkeitsstufen in PWM-Werte erfolgt über eine 
Tabelle.


Anmerkungen:

Der Latenzausgleich umfaßt nur 3 Zyklen, es sind also keine anderen 
Interrupts erlaubt. Man könnte Interrupts in der letzten Bitzeit 
erlauben, dann sind ~2000 Zyklen bis zum nächsten PWM-Interrupt Zeit.

Das Einschreiben der neuen PWM-Daten ist nicht interruptfest. Erfolgt 
eine Änderung von 2047 auf 2048 oder umgekehrt, kann es flackern.
Falls das stört, muß man das Ändern mit der letzten Bitzeit 
synchronisieren. Z.B. wartet man in der Routine, bis TCNT1 größer als 
die letzte Bitzeit und noch genügend Zeit zum Laden vor dem nächsten 
Zyklus ist.

Die 2kHz mögen viel klingen, sind es aber nicht unbedingt.
Die LEDs des STK500 sind klein und punktförmig, bewegt man die Augen, 
ist bei nur 100Hz ein deutliches Flackern zu sehen.
Mit 2kHz ist man also auf der sicheren Seite, die PWM sieht quasi wie 
Gleichstrom aus.

: Bearbeitet durch User
von Masl (Gast)


Lesenswert?

Hallo,

ich kann hier auf Arbeit das Zip grad nicht downloaden.
Kannst du vielleicht sagen wieviele Cycles die ISR braucht?

von Info (Gast)


Lesenswert?


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


Lesenswert?

Peter Dannegger schrieb:
> Anbei mal meine Version der 8 * 12Bit BAM komplett als Knight Rider.
> Bei 8MHz CPU-Takt ergibt sich eine PWM von 2kHz.

 Entschuldige wenn ich da etwas Falsch verstehe, aber...
 BAM mit 2KHz wurde heissen, dass bit0 weniger als 16Cy hat -
 mit jump, reti usw... ?

von Peter D. (peda)


Lesenswert?

Eine Bitzeit = 1/8MHz = 125ns
8MHz / 4095 = 1,95kHz

Die ersten 7 Bits werden im Compare-A Interrupt erzeugt, d.h. 127 
Zyklen. Insgesamt dauert der Interrupt 159 Zyklen.
Die weiteren Compare-B Interrupts dauern 51 Zyklen.
Das ergibt bei 12Bit:
(159 + 4 * 51) / 4095 = 9% CPU-Last

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


Lesenswert?

Peter Dannegger schrieb:
> Die ersten 7 Bits werden im Compare-A Interrupt erzeugt, d.h. 127
> Zyklen. Insgesamt dauert der Interrupt 159 Zyklen.

 Sorry, war zu faul um mich durchzulesen. Bei mir habe ich nur
 die bits 0 und 1 ins bit7 verlegt, bin aber nicht besonders
 glücklich damit.

von der alte Hanns (Gast)


Lesenswert?

Nur für die Registratur (und um zu zeigen, dass das Projekt interessiert 
und Anklang findet):

in pwm.c
>   TCCR1B = 1<<WGM12 | 1<<CS00;                  // CTC-mode, F_CPU / 1

sollte es wohl eher CS10 heißen.

von Äxl (geloescht) (Gast)


Lesenswert?

der alte Hanns schrieb:
> Nur für die Registratur (und um zu zeigen, dass das Projekt interessiert
> und Anklang findet):
>
> in pwm.c
>>   TCCR1B = 1<<WGM12 | 1<<CS00;                  // CTC-mode, F_CPU / 1
>
> sollte es wohl eher CS10 heißen.

Da gerade Beitrag "Suche günstigen 5V Mikrocontroller mit 6 PWM Channel für LED Steuerung" drauf 
verwiesen wird...

ist im Define (hier mal die iom8.h genommen) aber (auch nach vier 
Jahren) mit der gleichen Zahl hinterlegt, (Schwein gehabt - hihi)
Aber: der Ordnung halber hast Du Recht.
1
/* TCCR0 */
2
/* bits 7-3 reserved */
3
#define CS02    2
4
#define CS01    1
5
#define CS00    0  <---
6
...
7
...
8
/* TCCR1B */
9
#define ICNC1   7
10
#define ICES1   6
11
/* bit 5 reserved */
12
#define WGM13   4
13
#define WGM12   3
14
#define CS12    2
15
#define CS11    1
16
#define CS10    0  <---

VlG Äxl

von Äxl (geloescht) (Gast)


Lesenswert?

*im Beitrag... :|

von äh ja nee (Gast)


Lesenswert?

Für den "aktuellen" GCC aus 
https://ww1.microchip.com/downloads/Secure/en/DeviceDoc/avr8-gnu-toolchain-3.6.2.1778-win32.any.x86.zip 
(Registrierung, aber keine E-Mail-Aktivierung erforderlich) ist eine 
kleine Anpassung erforderlich:

1
ap
2
5.4.0
3
In file included from dimm_array.c:3:0:
4
dimm_array.h:8:25: error: variable 'DIMM_ARRAY' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
5
 extern uint16_t PROGMEM DIMM_ARRAY[];
6
                         ^
7
dimm_array.c:18:18: error: variable 'DIMM_ARRAY' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
8
 uint16_t PROGMEM DIMM_ARRAY[] =
9
                  ^
10
In file included from main.c:5:0:
11
dimm_array.h:8:25: error: variable 'DIMM_ARRAY' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
12
 extern uint16_t PROGMEM DIMM_ARRAY[];
13
                         ^
14
Drücken Sie eine beliebige Taste . . .
15
16
pwm_8ch>ap
17
5.4.0
18
AVR Memory Usage
19
----------------
20
Device: atmega48
21
22
Program:    1216 bytes (29.7% Full)
23
(.text + .data + .bootloader)
24
25
Data:         28 bytes (5.5% Full)
26
(.data + .bss + .noinit)
27
28
29
Drücken Sie eine beliebige Taste . . .

tiny24 geht auch, aber tiny40 ergibt:
1
pwm_int.S:38: Error: illegal opcode elpm for mcu avrtiny
2
pwm_int.S:52: Error: illegal opcode elpm for mcu avrtiny
3
pwm_int.S:84: Error: illegal opcode elpm for mcu avrtiny
4
pwm_int.S:31: Warning: operand out of range: 0x23
5
pwm_int.S:77: Warning: operand out of range: 0x23


Meine eigentliche Frage: wie kann man einzelne Bits (Pins, 5 & 7) für 
die Ausgabe im ASM-Interrupthandler maskieren?

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.