SpenceKonde / megaTinyCore

Arduino core for the tinyAVR 0/1/2-series - Ones's digit 2,4,5,7 (pincount, 8,14,20,24), tens digit 0, 1, or 2 (featureset), preceded by flash in kb. Library maintainers: porting help available!
Other
542 stars 140 forks source link

analogWrite does not work for ATtiny412 pin PA6 #1050

Open second-string opened 5 months ago

second-string commented 5 months ago

The default implementation does not correctly configure TCD0 to output PWM on pin PA6 for the ATtiny 412. I went fairly deep into the megaTinyCore source code and I'm guessing something isn't configured correctly with the different #defined macros, because it seems to be defaulting to the "pwm not available on this pin" path in the code instead of using TCD0, which is available.

Code to reproduce

Board: ATtiny412/402/212/202 Chip: ATtiny412 Clock speed: 20MHz internal (also tried with 1MHz internal) millis/micros timer: Default, which I believe is TCD0 on this chip (also tried with TCB0 and TCA)

void setup() {
  // put your setup code here, to run once:
  pinMode(PIN_PA6, OUTPUT);
  analogWrite(PIN_PA6, 200);
}

void loop() {
  // put your main code here, to run repeatedly:

}

I can properly configure TCD manually to output with WOA on PA6

Code that works

Same chip settings as above

void pwm_init(void) {
    // Enable-protected reg must have 0 written to enable bit before any other bits can be changed, and it defaults to
    // enabled on startup
    TCD0.CTRLA &= ~TCD_ENABLE_bm;

    // Don't need overlapping PWM signals so just do oneramp
    TCD0.CTRLB = TCD_WGMODE_ONERAMP_gc;

    // Disable all input control
    TCD0.INPUTCTRLA = TCD_INPUTMODE_NONE_gc;

    // Set/clear values to create desired duty cycle. Don't care about CMPB (outputs on PA7) at all so leave it off
    TCD0.CMPASET = 0x000;
    TCD0.CMPACLR = 0x1FF;

    // System 1MHz clock w/ DIV4 standard prescaler but no synchronization prescaler (I think they multiply together, not add).
    // Must be done as last operation before starting timer with ENABLE bit
    // NOTE :: DEFAULT TIMER FOR MILLIS/MICROS FUNCTIONS ON 1-SERIES ATTINIES IS TCD. I think this still works with it set as the default,
    // but if not, try switching it to TCB0.
    TCD0.CTRLA = TCD_CLKSEL_SYSCLK_gc | TCD_CNTPRES_DIV4_gc | TCD_SYNCPRES_DIV1_gc;
}

void pwm_start(void) {
  // Turn off output override (because we want pwm to run it duh)
  TCD0.CTRLC &= ~TCD_CMPOVR_bm;

  // Enable WOA (PA6) but not and WOB/C/D (PA7/?/?). Since FAULTCTRL reg is write protected we need to make it editable in
  // CCP reg. Must be done in start func because we can't take over output pins in stop func unless we disable them in FAULTCTRL.
  CPU_CCP        = CCP_IOREG_gc;
  TCD0.FAULTCTRL = TCD_CMPAEN_bm;

  while (!(TCD0.STATUS & TCD_ENRDY_bm)) {
      ;
  }

  TCD0.CTRLA |= TCD_ENABLE_bm;
}

/*
 * Must be called every time TCD0.CMPASET or TCD0.CMPACLR are updated for them to take effect if they're changed while PWM running.
 */
void pwm_sync(void) {
    TCD0.CTRLE = TCD_SYNCEOC_bm;
}

void setup() {
  pwm_init();
  pwm_start();
}

void loop() {}

Not sure if I'm doing something wrong with the setup/config, or if it's a megatinycore issue. Happy to test any changes out on my board if needed.

hmeijdam commented 5 months ago

Maybe it has something to do with this announcement from March '23

https://github.com/SpenceKonde/megaTinyCore/discussions/928

I just tested on both Github and Boards Manager version of MTC and get the same what you get. As you seem to have passed the complex hurdle of beating TCD into submission, I would stick with your second approach for now.

second-string commented 5 months ago

Yeah I'm all set, it's a simple one-off little project. Just raising the issue here in case it wasn't known. The version of megaTinyCore that I have installed is from before that post. Actually I'm not sure what version it is, so maybe it's been fixed since honestly.

SpenceKonde commented 5 months ago

Yeah it seems that it isn't passing one of the params it needs to...