Forum: Mikrocontroller und Digitale Elektronik ATxMega16A4: Zu dumm für PWM?!


von Christoph S. (mcseven)


Lesenswert?

Hi *,

ich glaub ich bin zu doof, mir ein PWM Ambilight zu bauen. Code anbei, 
ist für die Hardware des STK-600 geschrieben (man kan also einfach die 
beigelegten Kabel stecken auf PortD und ein zweipoliges für USART).
1
#define F_CPU 7373742
2
#define MAX_CHANNELS 9
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
const unsigned int gamma22[256] = { 0, 564, 1125, 1684, 2240, 2794, 3345, 3893, 4438, 4981, 5521, 6059, 6594, 7126, 7656, 8183, 8707, 9229, 9748, 10265, 10779, 11290, 11799, 12305, 12808, 13309, 13807, 14303, 14796, 15286, 15774, 16260, 16742, 17222, 17700, 18175, 18647, 19117, 19584, 20048, 20510, 20970, 21427, 21881, 22333, 22782, 23229, 23673, 24114, 24553, 24989, 25423, 25855, 26283, 26710, 27133, 27554, 27973, 28389, 28803, 29214, 29622, 30028, 30432, 30833, 31231, 31627, 32021, 32411, 32800, 33186, 33569, 33950, 34329, 34705, 35078, 35449, 35818, 36184, 36547, 36908, 37267, 37623, 37977, 38328, 38677, 39023, 39367, 39709, 40048, 40384, 40718, 41050, 41379, 41706, 42031, 42353, 42672, 42989, 43304, 43616, 43926, 44234, 44539, 44841, 45142, 45440, 45735, 46028, 46319, 46607, 46893, 47177, 47458, 47737, 48014, 48288, 48560, 48829, 49096, 49361, 49623, 49883, 50141, 50397, 50650, 50900, 51149, 51395, 51639, 51880, 52119, 52356, 52591, 52823, 53053, 53281, 53506, 53729, 53950, 54169, 54385, 54599, 54811, 55020, 55228, 55433, 55635, 55836, 56034, 56230, 56424, 56616, 56805, 56992, 57177, 57360, 57541, 57719, 57895, 58069, 58241, 58411, 58578, 58743, 58906, 59067, 59226, 59383, 59537, 59690, 59840, 59988, 60134, 60278, 60420, 60559, 60697, 60832, 60965, 61097, 61226, 61353, 61478, 61601, 61722, 61841, 61957, 62072, 62185, 62295, 62404, 62511, 62615, 62718, 62818, 62917, 63014, 63108, 63201, 63292, 63380, 63467, 63552, 63635, 63716, 63795, 63872, 63948, 64021, 64092, 64162, 64230, 64296, 64360, 64422, 64482, 64540, 64597, 64652, 64705, 64756, 64806, 64854, 64900, 64944, 64986, 65027, 65066, 65103, 65139, 65173, 65205, 65236, 65265, 65293, 65319, 65343, 65366, 65387, 65406, 65424, 65441, 65456, 65470, 65482, 65493, 65503, 65511, 65518, 65524, 65528, 65531, 65533, 65535, 65535 };
8
unsigned char volatile currentChannelNumber = 255;
9
unsigned char volatile channelValues[MAX_CHANNELS] = {0,0,0,0,0,0,0,0,0};
10
11
12
ISR(USARTC1_RXC_vect) {
13
  unsigned char data;
14
15
  data  = USARTC1.DATA;
16
  
17
   if (currentChannelNumber == 0) { PORTD.OUT &= 0x7F; }
18
19
  channelValues[currentChannelNumber] = data;
20
21
  if (currentChannelNumber == 8)   {
22
    PORTD.OUT |= 0x80;
23
    TCD0.CCA = gamma22[channelValues[0]];
24
    TCD0.CCB = gamma22[channelValues[1]];
25
    TCD0.CCC = gamma22[channelValues[2]];
26
    TCD0.CCD = gamma22[channelValues[3]];
27
    TCD1.CCA = gamma22[channelValues[4]];
28
    TCD1.CCB = gamma22[channelValues[5]];
29
  }
30
  currentChannelNumber++;
31
32
  if (currentChannelNumber==9) { currentChannelNumber=0; }
33
34
}
35
36
int main() {
37
  
38
  PORTD.DIR = 0xFF;
39
  PORTD.OUT = 0b11111111;
40
41
42
  OSC.CTRL = OSC_RC32MEN_bm | OSC_XOSCEN_bm; //enable 32MHz oscillator and external OSC
43
44
  while(!(OSC.STATUS & OSC_RC32MRDY_bm)); //wait for stability for 32MHz
45
46
47
  while(!(OSC.STATUS & OSC_XOSCRDY_bm));  //wait for stability for External Clock Source
48
49
  CCP = CCP_IOREG_gc; // Conf.Änderung erlauben
50
  CLK.CTRL = 0x03;    // CSource Clock Extern
51
  CCP = CCP_IOREG_gc; // Conf.Änderung erlauben
52
  CLK.PSCTRL = 0x00;  // Prescaler 0 (Teiler)
53
54
55
  //USART INIT
56
  PORTC.DIR &= 0b10111111; // RX Bit (6) als Eingang
57
  PORTC.DIR |= 0b10000000; // TX Bit (7) als Ausgang
58
  USARTC1.CTRLA = 0b00010000; // Interrupt-Level: RX High, alles andere Off
59
  USARTC1.CTRLC = 0b00000011; // Async, NoPar, 1SBit, 8Bit Wortgröße
60
61
  USARTC1.BAUDCTRLA = 0b00010111; // 23 = 19k2
62
  USARTC1.BAUDCTRLB = 0b00000000; //BSCALe=3x0, 23 hat keine high bits, daher auch 0
63
64
  USARTC1.CTRLB = 0b00011000; // 000, RX ein, TX ein, Single-Speed, No-Multi, 2xDontCare
65
66
  //TIMER PORTD_0 INIT
67
  TCD0.CTRLA = 0x01;    // divide clock by 0, enable Timers
68
  TCD0.PER   = 0xFFFF;  // set resolution to 16Bit
69
  TCD0.CTRLB = 0xF3;    // enable frequency generation for all 4 Channels
70
71
  //TIMER PORTD_1 INIT
72
  TCD1.CTRLA = 0x01;
73
  TCD1.PER   = 0xFFFF;
74
  TCD1.CTRLB = 0xF3;    // Es scheint nichts zu machen, wenn mann Bits für
75
                        // Output-Compare setzt, die nicht vorhanden sind.
76
            // Manual schweigt sich darüber aus.
77
78
  CCP = CCP_IOREG_gc;   // Conf.Änderung erlauben
79
  PMIC.CTRL  = 0b00000111; // EN hi mi und lo level interrupts
80
81
  sei();
82
83
  TCD0.CCA = 0xFFFF;
84
  TCD0.CCB = 0xFFFF;
85
  TCD0.CCC = 0xFFFF;
86
  TCD0.CCD = 0xFFFF;
87
  TCD1.CCA = 0xFFFF;
88
  TCD1.CCB = 0xFFFF;
89
90
  while (1) { }
91
92
}

Ich möchte einfach nur, dass die LEDs entsprechend hell oder dunkler 
werden, die Software auf dem PC ist boblight 1.3; das Protokoll momo 
(also einfach 9 Bytes für R1-3,G1-3,B1-4); es funktioniert auch soweit 
ganz gut, nur flackern die LEDs reproduzierbar sporadisch auf. Habe 
Single-Slope,
DualS und Freq-Modi der Timer probiert.

Ich hatte zunächst auf ein Indexproblem mit der Channelnumber getippt, 
aber wie ich's auch drehe und wende, das glaub ich ist es nicht. Es 
scheint eine Art Konflikt zwischen USART Interrupt und Timer Interrupt 
zu sein, denn wenn ich Code zum ändern der Helligkeit ohne USART 
schreibe funktioniert alles einwandfrei.

Könnte das vielleicht jemand auf einem STK600 nachvollziehen oder hätte 
sonst jemand einen Tip?

Danke, Christoph

von Peter D. (peda)


Lesenswert?

Christoph Söllner schrieb:
> ich glaub ich bin zu doof

Kommt drauf an, wie Deine Vorkenntnisse mit MCs sind.

Die Xmega sind ja noch sehr wenig verbreitet, daher vielleicht nicht 
gerade für Einsteiger geeignet.

Ich benutze lieber die ATtiny, die sind so schön klein und 
unkompliziert.

Du solltest vielleicht erstmal das Protokoll beschreiben, nachdem Du die 
Daten über die UART schickst.
Bzw. wenn Du kein Protokoll hast, solltest Du schleunigst eins 
spezifizieren, da Du ja mehr als ein Byte übertragen willst.

Ein Protokoll muß minimal synchronisierend sein. D.h. nach einem 
Übertragungsfehler muß es für den Master eine Möglichkeit geben, dem 
Slave ein gültiges Paket zu senden, völlig unabhängig davon, wo grade 
die Statemachine (bzw. der Parser) des Slaves hängt.


Ich mache für die UART immer erstmal ne FIFO.
Die Mainloop liest dann die FIFO aus und überprüft den Paketrahmen.
Wenn ein vollständiges und gültiges Paket empfangen wurde, parst die 
Mainloop es.


Peter

von Christoph S. (mcseven)


Lesenswert?

Hi Peter, Protokoll ist einfach 9 Bytes hintereinander, dann 10ms Pause, 
dann wieder 9 Bytes hintereinander usw.

Es geht mir aber nicht um die Syncronisation. Zum Testen soll es 
ausreichen, dass bei einem Byteverlust sich die Kanalwerte verschieben.

Es geht mir darum, dass ich wohl die HArdware-PWM entweder falsch 
ansteuere, der Chip defekt ist (unwahrscheinlich) oder eben einen Bug 
hat.

Am Oszi sehe ich auf dem entsprechenden PWM-Kanal, dass bei Änderung des 
Wertes zwischendurch hin und wieder ein Zyklus übersprungen wird, also 
entweder ein falscher Wert in das Timer-Register geschrieben wird oder 
der Timer sich irgendwie resettet.

Daher meine Frage an die Gemeinschaft, ob der Code oben Sinn macht mit 
nem
Xmega A4; Kenntnisse mit normalen Megas und Tinys hab ich genug, aber 
keiner von denen hat 16 16bit Hardware-PWM-Channels. Und Soft-PWM hab 
ich schon, die ist zu langsam.

Danke, Christoph

von Peter D. (peda)


Lesenswert?

Xmega habe ich noch keinen. Die scheinen aber langsam verfügbar zu sein, 
Farnell hat schon einige Typen lagernd.

Was mir bei den Xmega aber schwer auf den Magen schlägt, ist die 
fehlende 5V-Toleranz der IO-Pins. Daher sind die zur Zeit für mich tabu.

Die Gerätelogik ist für TTL-Pegel ausgelegt (2,4..5V = high). D.h. ARM7 
von NXP kann ich daher verwenden.

Es ist auch blöd, daß die XMega nicht pinkompatibel zu ATmega128/1280 
sind.


Peter

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

XMegas gibt es lagernd bei CSD-electronics und bei TME.eu . 5V-I/O 
braucht man bei den XMegas nicht mehr wirklich, alle dafür interessante 
Peripherie (SD-Karte, Bluetooth, Ethernet, RS232/RS485) gibt es als 
3.3V-Bausteine. Lediglich bei einigen LCDs und blauen/weißen LEDs muß 
man ein wenig in die Trickkiste greifen.

von GG (Gast)


Lesenswert?

Servus,

3,3 Volt Displays:

 DOGM128, DOGM132, DOGM162  gibt es bei Reichelt.

Gruß GG

von Christoph S. (mcseven)


Lesenswert?

Hi *,

danke, ich denke, es wird gelöst werden. Kann es erst heute abend 
testen, aber der Fehler scheint im Schreibzugriff auf die *.CCx-Register 
zu liegen. Diese sind (wie übrigens im Datenblatt nur winzigst erwähnt) 
die direkten Counter-Werte. Möchte man die gepufferte Variante benutzen, 
so ist auf CCxBUF[L:H] zu schreiben.
1
    TCD0.CCA = gamma22[channelValues[0]];
2
    TCD0.CCB = gamma22[channelValues[1]];
3
    TCD0.CCC = gamma22[channelValues[2]];
4
    TCD0.CCD = gamma22[channelValues[3]];
5
    TCD1.CCA = gamma22[channelValues[4]];
6
    TCD1.CCB = gamma22[channelValues[5]];

müßte somit werden zu:
1
    TCD0.CCABUF = gamma22[channelValues[0]];
2
    TCD0.CCBBUF = gamma22[channelValues[1]];
3
    TCD0.CCCBUF = gamma22[channelValues[2]];
4
    TCD0.CCDBUF = gamma22[channelValues[3]];
5
    TCD1.CCABUF = gamma22[channelValues[4]];
6
    TCD1.CCBBUF = gamma22[channelValues[5]];

und alles sollte passen. Wie gesagt, verifiziert wird das heute abend. 
Vielleicht erspart das noch jemandem 3 Abende Kopfkratzen.

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.