Forum: Mikrocontroller und Digitale Elektronik Atmega162 im Simulator geht es, in der Hardware nicht


von Wolfgang (Gast)


Lesenswert?

Hallo,

ich habe hier ein kleines Problem, bei dem ich nicht weiterkomme - 
vielleicht hat ja einer einen Denkanstoß für mich.

Also, ich will eine RGB-Led so richtig schön mit Übergängen ansteuern 
und habe mir dafür an Timer2 und Timer3 je an die OCRs einen FET mit 
jeweiligen Farbe drangebaut. Die Timer betreibe ich mit 8 Bit (der 
Timer2 kann eh nicht mehr), normaler FastPWM, die OCR sind auch gemappt. 
Wenn ich einen Wert in das OCR-Register schreibe, kommt aus der Hardware 
auch sauber die PWM raus.

Dann habe ich mir eine Interpolatorroutine gebaut, die zwischen zwei 
RGB-Werten linear interpoliert und die ich alle 20ms aufrufe. Den 
Interpolationswert schreibe ich dann in die OCR-Register. Das kann ich 
am Simulator wunderbar nachvollziehen - es fällt der richtige Wert aus 
der Routine raus, die OCR2 bzw. OCR3AL und OCR3BL stehen richtig und 
wandern auch brav bei jedem Durchlauf mit.

Lade ich aber das in die Hardware, kommt immer Fullscale raus. Zum 
Gegencheck habe ich mal das Rechenergebnis einfach mit 7F maskiert - ja, 
dann kommt halt 7F raus, maskiere ich anders, ja es kommt so raus. Auch 
die 20ms habe ich überprüft - alles okay - es ist einfach das 
Rechenergebnis nicht mit dem Simulator konform. Ach ja, Data Space 
(Stack) ist noch genug da.  (AVR GCC, 37% Data usage)

 Irgendwie begreife ich das nicht. Im Simulator ist alles paletti, die 
Hardware funktioniert (ich kann 'zu Fuß' PWM-Werte ausgeben), aber das 
Interpolationsergebnis scheint immer 0xFF zu sein. Gibt es da ev. 
Errata, die man kennen sollte?

Den Code poste ich mal noch nicht, ist etwas umfangreicher.

Frustriert ... Wolfgang

von holger (Gast)


Lesenswert?

>Den Code poste ich mal noch nicht, ist etwas umfangreicher.

Dann lass es halt bleiben und such selber den Fehler.

von Wolfgang (Gast)


Lesenswert?

Okay, dann beginnen wir mal, hier init und Hardwarezugriff:
1
void init_rgb_timer(void)
2
  {
3
    // Init Timer2 as Fast PWM with a CLKDIV (prescaler) of 64
4
5
    #define T2_PRESCALER   64    // may be 1, 8, 32, 64, 128, 256, 1024
6
    #if   (T2_PRESCALER==1)
7
        #define T2_PRESCALER_BITS   ((0<<CS22)|(0<<CS21)|(1<<CS20))
8
    #elif (T2_PRESCALER==8)
9
        #define T2_PRESCALER_BITS   ((0<<CS22)|(1<<CS21)|(0<<CS20))
10
    #elif (T2_PRESCALER==32)
11
        #define T2_PRESCALER_BITS   ((0<<CS22)|(1<<CS21)|(1<<CS20))
12
    #elif (T2_PRESCALER==64)
13
        #define T2_PRESCALER_BITS   ((1<<CS22)|(0<<CS21)|(0<<CS20))
14
    #elif (T2_PRESCALER==128)
15
        #define T2_PRESCALER_BITS   ((1<<CS22)|(0<<CS21)|(1<<CS20))
16
    #elif (T2_PRESCALER==256)
17
        #define T2_PRESCALER_BITS   ((1<<CS22)|(1<<CS21)|(0<<CS20))
18
    #elif (T2_PRESCALER==1024)
19
        #define T2_PRESCALER_BITS   ((1<<CS22)|(1<<CS21)|(1<<CS20))
20
    #else
21
        #error void value T2_PRESCALER
22
    #endif
23
24
    TCCR2 = (0 << FOC2)        // Timer2: fastpwm
25
          | (1 << WGM20)       // wgm = 00: normal mode, top=0xff
26
          | (1 << COM21)       // COMx1,COMx0 = 00: normal mode, pin operates as usual
27
          | (0 << COM20)       // COMx1,COMx0 = 10: compare match: set OC2 at TOP. clear at OCR
28
                               // COMx1,COMx0 = 11: compare match: clear OC2 at TOP. set at OCR
29
                               // 
30
          | (1 << WGM21)       // 
31
          | T2_PRESCALER_BITS; 
32
33
    TCNT2 = 0;
34
35
    // Init Timer3 as Fast PWM with a CLKDIV (prescaler) of 64
36
37
    #define T3_PRESCALER   64   // may be 1, 8, 16, 32, 64, 256, 1024
38
    #if   (T3_PRESCALER==1)
39
        #define T3_PRESCALER_BITS   ((0<<CS32)|(0<<CS31)|(1<<CS30))
40
    #elif (T3_PRESCALER==8)
41
        #define T3_PRESCALER_BITS   ((0<<CS32)|(1<<CS31)|(0<<CS30))
42
    #elif (T3_PRESCALER==16)
43
        #define T3_PRESCALER_BITS   ((1<<CS32)|(1<<CS31)|(0<<CS30))
44
    #elif (T3_PRESCALER==32)
45
        #define T3_PRESCALER_BITS   ((1<<CS32)|(1<<CS31)|(1<<CS30))
46
    #elif (T3_PRESCALER==64)
47
        #define T3_PRESCALER_BITS   ((0<<CS32)|(1<<CS31)|(1<<CS30))
48
    #elif (T3_PRESCALER==256)
49
        #define T3_PRESCALER_BITS   ((1<<CS32)|(0<<CS31)|(0<<CS30))
50
    #elif (T3_PRESCALER==1024)
51
        #define T3_PRESCALER_BITS   ((1<<CS32)|(0<<CS31)|(1<<CS30))
52
    #else
53
        #error void value T3_PRESCALER
54
    #endif
55
56
    // FastPWM, 8 Bit = Mode 5: WGM3 = 0101
57
58
    TCCR3A = (1 << COM3A1)          // compare match A
59
           | (0 << COM3A0)          // 
60
           | (1 << COM3B1)          // compare match B
61
           | (0 << COM3B0) 
62
           | (0 << FOC3A)
63
           | (0 << FOC3B)
64
           | (0 << WGM31)  
65
           | (1 << WGM30);  
66
    TCCR3B = (0 << ICNC3) 
67
           | (0 << ICES3) 
68
           | (0 << WGM33) 
69
           | (1 << WGM32) 
70
           | (T3_PRESCALER_BITS);   // clkdiv
71
72
    TCNT3 = 0;
73
  }
74
75
unsigned char RED;     // mirror, fuer den Simulator
76
unsigned char GREEN;
77
unsigned char BLUE;
78
79
// hardware access, values given from 0..255
80
81
void set_R(unsigned char red_value)
82
  {
83
    OCR3AL = red_value;
84
    RED = red_value;
85
  }
86
87
void set_G(unsigned char green_value)
88
  {
89
    OCR2 = green_value;
90
    GREEN = green_value;
91
  }
92
93
void set_B(unsigned char blue_value)
94
  {
95
    OCR3BL = blue_value;
96
    BLUE = blue_value;
97
  }

von Wolfgang (Gast)


Lesenswert?

Und dann die Routine, welche die Interpolation macht:
1
#define SIZE_RGB_FADE      24         // number of entries (triples) in one control
2
3
typedef struct    // fade values, normalized [0..255]
4
      {
5
        unsigned char time;       
6
        unsigned char red;            
7
        unsigned char green;            
8
        unsigned char blue;            
9
      } t_rgb_point;
10
11
t_rgb_point farbkreis[] PROGMEM = 
12
  {
13
   // time, r, g, b
14
    {   0 , 255 ,   0 ,   0 },
15
    {   1 , 255 , 255 ,   0 },
16
    {   2 ,   0 , 255 ,   0 },
17
    {   3 ,   0 , 255 , 255 },
18
    {   4 ,   0 ,   0 , 255 },
19
    {   5 , 255 ,   0 , 255 },
20
    {   6 , 255 ,   0 ,   0 },
21
    {   0 ,   0 ,   0 ,   0 },              // end of list: time = 0
22
  };
23
24
t_rgb_point *pre_def_fades[] =
25
  {
26
    farbkreis,                              //  0: farbkreis
27
  };
28
29
t_rgb_point rgb_fade[SIZE_RGB_FADE]; 
30
31
typedef struct
32
  { 
33
    unsigned char redmax;               // upper  limit [0..255]
34
    
35
    unsigned char greenmax;               // upper  limit [0..255]
36
    
37
    unsigned char bluemax;               // upper  limit [0..255]
38
    
39
    unsigned char control;      
40
41
    unsigned char repeat;           // if REPEAT: this is the number of repeats to do
42
43
    unsigned char fade_index;      // points to actual target in curve
44
45
    t_rgb_point *fade;           // fading curve, normalized [0..255]
46
      
47
    unsigned int active_time;       // runtime: relative time to start point
48
                                    // 0        = restart Servos
49
                                    // 0xffff   = finished
50
51
    unsigned char time_ratio;       // ratio between runtime and curve time
52
  } t_rgb_ctrl;
53
54
t_rgb_ctrl rgb_ctrl =
55
  {     255,            // unsigned char redmax; 
56
        255,            // unsigned char greenmax; 
57
        255,            // unsigned char bluemax; 
58
          0,            // unsigned char control;
59
          0,            // unsigned char repeat;
60
          1,            // unsigned char fade_index;
61
      rgb_fade,     // pointer to curve
62
          0,            // active time
63
          1,            // ratio of curve
64
  };
65
66
67
//------------------------------------------------------------------------------
68
//
69
#define CALC_GAIN  128L            // 2 bis 128; 128 ist obere Grenze wegen möglichen Überlauf
70
71
void calc_rgb_next_val(void)
72
  {
73
    unsigned char myindex;        // index in curve
74
    int16_t posi;
75
    int16_t dt, delta_t;          // time delta always > 0
76
    int32_t posl;
77
    int16_t delta_pos;
78
    unsigned char end_of_list_reached = 0;
79
80
    if (rgb_ctrl.active_time == 0xFFFF) return;    // inactive - do nothing
81
82
    rgb_ctrl.active_time++;
83
    
84
    // check, if next curve point is reached
85
    myindex = rgb_ctrl.fade_index;
86
    
87
    if ((rgb_ctrl.fade[myindex].time * rgb_ctrl.time_ratio) == rgb_ctrl.active_time)
88
      {
89
        myindex++;
90
        // new curve point reached, how to proceed?
91
        if (rgb_ctrl.fade[myindex].time == 0)
92
          {
93
            // end of list
94
            end_of_list_reached = 1;
95
            myindex--;                    // stay on last curve point             
96
          }
97
        else
98
          {
99
            rgb_ctrl.fade_index = myindex;        // save index
100
          } 
101
      }
102
103
    // now calc linear interpolation
104
    // val = val_prev + (dt / delta_t) * (val - val_prev)
105
106
    dt = rgb_ctrl.active_time - (int)rgb_ctrl.fade[myindex-1].time * rgb_ctrl.time_ratio;   // int
107
108
    delta_t = (int)(rgb_ctrl.fade[myindex].time - rgb_ctrl.fade[myindex-1].time)            // int
109
              *  rgb_ctrl.time_ratio;
110
111
    if (delta_t == 0) delta_t = 1;  // avoid div0 (this is dirty)
112
113
    //---->  make red
114
115
    delta_pos = ((int)rgb_ctrl.fade[myindex].red
116
                 - (int)rgb_ctrl.fade[myindex-1].red)   
117
                * CALC_GAIN;    
118
    posl = (int32_t)delta_pos * dt;
119
        
120
    posl = posl / delta_t;                                        
121
    posl = posl + (int)rgb_ctrl.fade[myindex-1].red * CALC_GAIN; 
122
                                                                  
123
    // scale this fade value according to max volume
124
    // scaled = interpolated * max
125
126
    posl = posl * rgb_ctrl.redmax;      
127
128
    // now scale to timer
129
130
    posl = posl / 256;
131
    posi = posl / CALC_GAIN;
132
                                          // range 0 ... 256
133
    set_R(posi);
134
    // die anderen Farben schenke ich mir hier
135
  }

Und der Aufruf ist dann:
1
void do_rgb_fade(void)
2
  {
3
    rgb_ctrl.redmax = my_eeprom_read_byte(&CV.REDmax);
4
    rgb_ctrl.greenmax = my_eeprom_read_byte(&CV.GREENmax);
5
    rgb_ctrl.bluemax = my_eeprom_read_byte(&CV.BLUEmax);
6
    
7
    rgb_copy_fade(my_eeprom_read_byte(&CV.RGB_profile));
8
    rgb_ctrl.time_ratio = my_eeprom_read_byte(&CV.RGB_time);
9
    rgb_ctrl.fade_index = 1;
10
    rgb_ctrl.active_time = 0;
11
    rgb_ctrl.repeat = my_eeprom_read_byte(&CV.RGB_repeat);
12
    rgb_ctrl.control = 0;    
13
    set_R(0);   //   red_value
14
    set_G(0);  //   green_value;
15
    set_B(0);  //   blue_value;
16
  }

Und dann wird alle 20ms calc_rgb_next_val(); aufgerufen.

Servus Wolfgang

von soundso (Gast)


Lesenswert?

libm eingebunden?

du machst hier Rechnungen mit Multiplikationen und Divisionen ...

und falls jetzt kommt da sind keine floats drin:

#define CALC_GAIN 128L ist ein float ...

gruss

von Karl H. (kbuchegg)


Lesenswert?

soundso schrieb:
> libm eingebunden?
>
> du machst hier Rechnungen mit Multiplikationen und Divisionen ...
>
> und falls jetzt kommt da sind keine floats drin:
>
> #define CALC_GAIN 128L ist ein float ...

Seit wann?

@Wolfgang

EEPROM hast du gebrannt?

Ansonsten: Konzentrier dich auf die 20ms. Die Berechnungen laufen auf 
dem µC auch nicht anders als auf dem Simulator. Du hast doch in beiden 
Fällen identische Optimizer-Einstellungen?
Dem Simulator sind deine Berechnungen wurscht, der arbeitet nur 
Assembler Instruktionen ab, genauso wie der µC. Da kommt im Simulator 
dasselbe raus, wie auf dem µC. Timing ist aber eine andere Sache, das 
kann abweichen, zb wenn im Simulator falsche Takteinstellungen gemacht 
sind.

von Wolfgang K. (opendcc)


Lesenswert?

Hallo,

ich ziehe
1
#include <stdlib.h>
2
#include <stdbool.h>
3
#include <inttypes.h>
 rein.

128L ist doch ein Long, oder?

Servus Wolfgang

von Wolfgang K. (opendcc)


Lesenswert?

Hallo,

> Ansonsten: Konzentrier dich auf die 20ms.

Hatte ich auch schon in Verdacht, habe daher einfach mal 
set_R(my_static_i++) reingehängt - und die LED dimmt in 5sec einmal rum; 
5 sec = 256/20ms, paßt.

> Du hast doch in beiden Fällen identische Optimizer-Einstellungen?

Ja, und EEPROM ist auch geladen. Das werde ich aber nochmal zur Probe 
rücklesen und das eep file genau ansehen.

Servus Wolfgang

von spess53 (Gast)


Lesenswert?

Hi

>Ja, und EEPROM ist auch geladen. Das werde ich aber nochmal zur Probe
>rücklesen und das eep file genau ansehen.

Und EESAVE-Fuse setzen.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Hast du irgendeine Möglichkeit für die Ausgabe?
LCD, UART?

von Wolfgang K. (opendcc)


Lesenswert?

Hallo,

LCD und UART ist keiner dran, die Zielplatine ist recht minimalistisch 
und klein. UART könnte ich mal nachverdrahten und über ein FTDI-Kabel 
mal ein bischen printf machen - Danke für den Hinweis.

Servus Wolfgang

von Karl H. (kbuchegg)


Lesenswert?

Ansonsten fällt mir nur noch ein;

Abspecken. Du hast einen Fehler gemacht: Zuviel Code geschrieben ohne 
ihn auf der realen Hardware zwischendurch immer wieder zu testen.

von Wolfgang (Gast)


Lesenswert?

Hallo,

und heute des Rästels Lösung: der ISP war einen Tick zu schnell - ich 
habe den AVRmkII auf langsamere Speed gestellt, et voila, es dimmt. 
Danke nochmals für die Denkanstöße.

Übrigens, obige Rumrechnerei habe ich bereits bei der Servoansteuerung 
drin - um mit Integer etwas Auflösung hinzuzaubern, muß man das einfach 
ein bischen hochskalieren.

Servus Wolfgang, www.opendcc.de

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.