SAMD20 Problem mit PWM

OP #5462097
Lesenswert?

Hallo Forum,
ich habe ein Problem mit der PWM des ATSAMD20J18A auf dem Board von 
Microchip (Atmel) SAMD20-XPRO. Das Programmbeispiel habe ich aus einer 
Elektor-Zeitschrift entnommen. Das Programm macht erstmal was es soll, 
dennoch zeigen sich regelmäßig Überlagerungen im PWM-Verlauf (siehe 
Anhang). Leider übersteigt der Fehler meinen derzeitigen Kenntnisstand. 
Kann jemand helfen? Die LEDs sind an PB02 und PB03
1
#include <asf.h>
2

3
volatile uint16_t i;                 //declarations of the variables
4
volatile uint16_t c0value = 65535;
5
volatile uint16_t c1value = 0;
6

7
void configure_tc(void);  //function prototype
8

9
struct tc_module tc_instance; //generate a instance-structure
10

11
void configure_tc(void) //configurate the TC
12
{
13
  struct tc_config config_tc;
14

15
  tc_get_config_defaults(&config_tc);
16

17
  config_tc.counter_size    = TC_COUNTER_SIZE_16BIT;
18
  config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
19
  
20
  config_tc.counter_16_bit.compare_capture_channel[0] = 0xFFFF;  //compare-channel0
21
  config_tc.pwm_channel[0].enabled = true;
22
  config_tc.pwm_channel[0].pin_out = EXT1_PWM_0_PIN;
23
  config_tc.pwm_channel[0].pin_mux = EXT1_PWM_0_MUX;
24
  config_tc.counter_16_bit.compare_capture_channel[1] = 0xFFFF;  //compare-channel1
25
  config_tc.pwm_channel[1].enabled = true;
26
  config_tc.pwm_channel[1].pin_out = EXT1_PWM_1_PIN;
27
  config_tc.pwm_channel[1].pin_mux = EXT1_PWM_1_MUX;
28

29
  tc_init(&tc_instance, EXT1_PWM_MODULE, &config_tc);
30
  tc_enable(&tc_instance);
31
}
32

33
int main(void)
34
{
35
  system_init();
36
  delay_init();
37
  configure_tc();
38

39
  while (true) {
40
    for(i = 0; i < 65535; i++ ){  //turn channel0 slowly off and channel1 slowly on
41
      c0value = 65535 - i;
42
      c1value = i;
43
      tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, c0value);
44
      tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_1, c1value);
45
      delay_us(20);
46
    }
47
    for(i = 0; i < 65535; i++ ){  //turn channel1 slowly off and channel0 slowly on
48
      c0value = i;
49
      c1value = 65535 - i;
50
      tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, c0value);
51
      tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_1, c1value);
52
      delay_us(20);
53
    }
54
  }
55
}
Angehängte Dateien:
Gast #5462352
Lesenswert?

Ohne jetzt die Timer des SAMD20 zu kennen, vermute ich, dass durch dein 
wildes Rumgeballere auf das Compare-Register (mit 50kHz, 20µs) der Timer 
ab und zu keinen Match macht (z.B. während der Timer hochzählt, setzt du 
das Compare-Register auf eine kleineren Wert) und dann für diese Periode 
der Ausgang nicht abgeschaltet wird.
OP #5462643
Lesenswert?

Jim M. schrieb:
> Bernd E. schrieb:
>> Leider lag es nicht daran. Es sieht aus
>
> Wir sehen Deinen Source Code nicht. Vermutlich schreibst Du immer nocht
> eines der Capture Register zum falschen Zeitpunkt.
>
> Übrigens mache ich sowas gerne mit DMA...


Leider nicht ganz weg. LED an PB3 sieht gut aus, oder Fehler ist 
verdeckt.
LED an PB2 hat immer noch den beschriebenen Fehler.

1
#include <asf.h>
2

3
volatile uint16_t i;                 //declarations of the variables
4
volatile uint16_t c0value = 65535;
5
volatile uint16_t c1value = 0;
6

7
void configure_tc(void);  //function prototype
8

9
struct tc_module tc_instance; //generate a instance-structure
10

11
void configure_tc(void) //configurate the TC
12
{
13
  struct tc_config config_tc;
14

15
  tc_get_config_defaults(&config_tc);
16

17
  config_tc.counter_size    = TC_COUNTER_SIZE_16BIT;
18
  config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
19
  
20
  config_tc.counter_16_bit.compare_capture_channel[0] = 0xFFFF;  //compare-channel0
21
  config_tc.pwm_channel[0].enabled = true;
22
  config_tc.pwm_channel[0].pin_out = EXT1_PWM_0_PIN;
23
  config_tc.pwm_channel[0].pin_mux = EXT1_PWM_0_MUX;
24
  config_tc.counter_16_bit.compare_capture_channel[1] = 0xFFFF;  //compare-channel1
25
  config_tc.pwm_channel[1].enabled = true;
26
  config_tc.pwm_channel[1].pin_out = EXT1_PWM_1_PIN;
27
  config_tc.pwm_channel[1].pin_mux = EXT1_PWM_1_MUX;
28

29
  tc_init(&tc_instance, EXT1_PWM_MODULE, &config_tc);
30
  tc_enable(&tc_instance);
31
}
32

33
int main(void)
34
{
35
  system_init();
36
  delay_init();
37
  configure_tc();
38

39
  while (true) {
40
    if (tc_get_count_value(&tc_instance) == 0x0000){
41
      for(i = 0; i < 65535; i++ ){  //turn channel0 slowly off and channel1 slowly on
42
        c0value = 65535 - i;
43
        c1value = i;
44
        tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, c0value);
45
        tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_1, c1value);
46
        delay_us(20);
47
      }
48
      for(i = 0; i < 65535; i++ ){  //turn channel1 slowly off and channel0 slowly on
49
        c0value = i;
50
        c1value = 65535 - i;
51
        tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, c0value);
52
        tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_1, c1value);
53
        delay_us(20);
54
      }
55
    }
56
  }
57
}
Gast #5463007
Lesenswert?

Wenn bisheriger PWM-Wert gleich 0, dann direkt setzen, ansonsten Wert 
merken und den Match or Capture Channel Interrupt setzen (INTENSET->MC1 
oder MC0, je nach verwendetem Kanal). Im richtigen Interrupt (INTFLAG 
abfragen nach Kanal) dann den Interrupt löschen und wieder abschalten, 
zum Schluss den gemerkten Wert setzen. Register-Synchronisierung nicht 
vergessen (STATUS->SYNCBUSY), falls nötig.
Damit wird ein neuer Wert immer nur gesetzt, wenn der aktuelle gerade 
erreicht wurde und der Zähler von vorne beginnt. Bei sehr hoher 
PWM-Frequenz und niedrigem Wert könnte es zum gleichen Effekt kommen, 
wenn der Code im Interrupt den neuen Wert nicht rechtzeitig setzen kann 
(PWM läuft ja weiter), von daher den Wert möglichst früh setzen.

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