MCUdude / MegaCoreX

An Arduino hardware package for ATmega4809, ATmega4808, ATmega3209, ATmega3208, ATmega1609, ATmega1608, ATmega809 and ATmega808
GNU Lesser General Public License v2.1
245 stars 48 forks source link

TCA register probleme #149

Closed amchiri closed 1 year ago

amchiri commented 2 years ago

Hi I am a student (from french sorry for my expression) and i try to to use the waveform generator for my project but it doens't work i think that there might be a probleme with the the register CTRLA from TCA it's like we cannot set the TCA in FRQ generator because whatever I write in that register the period always depend about the register PER from TCA could you try to check that please? (below here my code copied from https://www.avrfreaks.net/forum/atmega4808-wave-form-generator)

/ */

void Clock_Init(void){ // Main Clock Configuration

CPU_CCP = CCP_IOREG_gc; // Select 20MHz Internal Oscillator CLKCTRL_MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc;

CPU_CCP = CCP_IOREG_gc; // Disable Prescaler CLKCTRL_MCLKCTRLB = ~CLKCTRL_PEN_bm;

while(CLKCTRL_MCLKSTATUS & CLKCTRL_SOSC_bm); } void Port_Init(void){ PORTA_DIR |= PIN0_bm; } void TimerA_Init(void){ // Set PA[0:5] as output for the wave form PORTMUX_TCAROUTEA = PORTMUX_TCA0_PORTA_gc;

//Frequency Mode and Compare Channels enabled TCA0_SINGLE_CTRLB = 0x01 | TCA_SINGLE_CMP0EN_bm;

//Disable Event count. Ticks counter instead TCA0_SINGLE_CTRLA &= ~(TCA_SINGLE_CNTEI_bm);

// TOP --> 5000Hz = (20e6/6)/(21(CMPn + 1)) <=> CMPn = 1999 // or TOP --> 4000Hz = (16e6/6)/(21(CMPn + 1)) <=> CMPn = 1999 TCA0_SINGLE_CMP0 = 0x7cf;

//Select DIV1 for Timer prescaler and Enable peripheral TCA0_SINGLE_CTRLA = (TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm); }

void setup() { //http://ww1.microchip.com/downloads/en/DeviceDoc/40002015A.pdf Clock_Init(); Port_Init(); TimerA_Init();

for ( ; ;){

  }

}

SpenceKonde commented 2 years ago

I think this core sets the timer up initially in SPLIT MODE in order to get 3 extra 8-bit PWM channels, since analogWrite only supports 8-bit PWM anyway. To put it back into non-split mode [required for all other modes - in split mode, the 16-bit timer is split into two 8-bit timers, which need not have the same period (though they use the same clock). There is only one supported mode, with each half of the timer downcounting. Buffering is not used. Event inputs are not supported except for the, and most of the commands are also gone. What is not gone is the hard reset command, which is probably the best approach if you're going to be taking over TCA0. Before any of your TCA code, you must 1. disable TCA0, as hard reset is not valid while the timer is running and 2. Write the hard reset command (0x3 << 2) and for good measure apply it to both timers (meaning 0x3); (0x03<<2) | 0x03 = 0x0F

The whole TCA0 and CTRLE/CTRLF and the set/clear registers has never made much sense to me. I

TCA0_SPLIT_CTRLA=0; //stop TCA0.
TCA0_SPLIT_CTRLESET=0x0F // hard reset TCA0, TCA0 is now in power on reset state. 

Oh - also don't manually do the CCP .... to write to protected registers. Do _PROTECTED_WRITE(register,value) instead. This will ensure that the compiler doesn't do anything funky that causes the timed write sequence to not be completed in time.

mcuee commented 1 year ago

In this case, I guess this issue can be closed?