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
554 stars 143 forks source link

Using TCD0 for PWM on Pin 0 instead of DAC #222

Closed Nbelles closed 4 years ago

Nbelles commented 4 years ago

Hi,

Is it possible to force the analogWrite function to turn on TCD0’s PWM instead of outputting a DAC voltage On Pin 0 on the ATtiny 412? It looks like the logic is there in the wiring_analog.c file for TCD0 PWM on both pins 0 and 1 but because the DAC is defined, the switch case always goes to that before it gets to TCD0. I tried just commenting out all the DAC lines in that file (which is I’m sure the worst way to try and fix it) but it didn’t fix anything (surprise!). I have made sure I used the TimerDPWM define in my sketch. Is there any easier way to disable the DAC and enable TCD0 PWM that I’m not aware of?

Thanks!

Nbelles commented 4 years ago

I've been doing some more searching and have found something that might need to be changed in txy2/pins_arduino.h

const uint8_t digital_pin_to_timer[] = {
    #if defined(DAC0)
        DACOUT,
    #else
        NOT_ON_TIMER, // 0  PA6
    #endif
    TIMERA0, // 1  PA7
    TIMERA0, // 2  PA1
    TIMERA0, // 3  PA2
    // skip PA0 UPDI
    TIMERA0, // 4  PA3
    NOT_ON_TIMER  // 5  PA0
};

This doesn't take into account if someone has defined USE_TIMERD0_PWM which means analogWrite doesn't ever run the TIMERD0 case. This hasn't fixed my issue of being unable to use PWM on pin 0 or pin 1 but figured I would bring it up.

I would guess that something similar to this would be the expected resulting code:

const uint8_t digital_pin_to_timer[] = {
    #if defined(DAC0)
            DACOUT,
    #elif defined(USE_TIMERD0_PWM)
        TIMERD0,
    #else
        NOT_ON_TIMER, // 0  PA6
    #endif
    #if defined(USE_TIMERD0_PWM)
        TIMERD0,
    #else
        TIMERA0, // 1  PA7
    #endif
    TIMERA0, // 2  PA1
    TIMERA0, // 3  PA2
    // skip PA0 UPDI
    TIMERA0, // 4  PA3
    NOT_ON_TIMER  // 5  PA0
};
Nbelles commented 4 years ago

Alright, I've spent some more time on this trying to get it working but still haven't gotten anywhere. I tried running the code (copied below) on both the ATtiny412 and ATtiny1614 (with changes to the port direction pins) and on both I am able to get WOB working but I can't for the life of me get WOA working on TCD0.

void setup() {
     PORTA.DIRSET |= 0b00110000;
     PORTA.OUTSET |= 0b00000000;
     TCD0.CTRLA=0x60; // Stop the timer and set clock to system clock
     TCD0.CTRLB |= TCD_WGMODE_FOURRAMP_gc;
     TCD0.CMPASET = 0x001;
     TCD0.CMPACLR = 0x200;
     TCD0.CMPBSET = 0x001;
     TCD0.CMPBCLR = 0x800;
    _PROTECTED_WRITE(TCD0.FAULTCTRL, TCD_CMPAEN_bm | TCD_CMPA_bm); 
    _PROTECTED_WRITE(TCD0.FAULTCTRL, TCD_CMPBEN_bm | TCD_CMPB_bm);
    while (!(TCD0.STATUS & TCD_ENRDY_bm)){;}
    TCD0.CTRLA |= 0x01; // Start the timer
}

void loop() {
    // Nothing
}
SpenceKonde commented 4 years ago

Sorry I wasn't able to get back to you earlier. You're pretty much there... only thing I think is wrong is:

    _PROTECTED_WRITE(TCD0.FAULTCTRL, TCD_CMPAEN_bm | TCD_CMPA_bm);  // Turn on only CMPA....
    _PROTECTED_WRITE(TCD0.FAULTCTRL, TCD_CMPBEN_bm | TCD_CMPB_bm); // then immediately turn on only CMPB, turning off CMPA 

I think you want:

    _PROTECTED_WRITE(TCD0.FAULTCTRL, TCD_CMPAEN_bm | TCD_CMPA_bm | TCD_CMPBEN_bm | TCD_CMPB_bm);
SpenceKonde commented 4 years ago

Closing issue as does not represent a defect in the core.

Nbelles commented 4 years ago

That's what I get for trying to use other people's code without knowing what it does or how it works. Thanks for the help, that fixed the issue!

No need to be sorry, I know you've got a lot more important stuff to do than help people with tech support. I just kept posting with updates so that whenever you did get around to it you might be able to see the progression of events of what I tried.