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

#3746602
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.
Angehängte Dateien:
Gast #5315556
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
Gast #6845364
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren