platformio / platform-atmelsam

Atmel SAM: development platform for PlatformIO
https://registry.platformio.org/platforms/platformio/atmelsam
Apache License 2.0
78 stars 105 forks source link

SAME51J20A: HW-registers not editable through debug #222

Open pr2zi opened 4 months ago

pr2zi commented 4 months ago

I am currently developing on the SAME51J20A and need to turn down the MCU frequency to 100 MHz or less. I previsouly managed to tune it up to 120 MHz but my program fails when trying to do so. First of all I was developing on VSC with platformio and realised that the program is stopping at:

while (0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY || 0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK); //wait for the DPLLSTATUS.bit.CLKRDY = ReadyBit= 1 and LOCKbit = 1;

and is never able to leave that. I then pasted exakt the same code into my Microchipstudio test project to use their debugger for better clearance and realised that my code works there. Upon further investigations I saw that commands likeOSCCTRL->Dpll[0].DPLLCTRLA.bit.ENABLE = 0;don’t do anything in my Peripherals view. Also closing it and reopening does nothing to the values. It also seems like values that are initialized on MCU startup are also completly ignored by this view. Some other registers can be changed but i don't undestand why few specific registers seem to be locked for pio. HW register adress are confirmed to be the same.

Below my full Code for clock init:

#define CLOCK100

#define GCLK0 0
#define GCLK1 1
#define GCLK2 2
#define GCLK3 3
#define GCLK4 4
#define GCLK5 5
#define GCLK6 6
//testing

#ifdef CLOCK100 // for higher temperature for up to 125°C
#define F_CPU 11000000
#define LDR_var (((unsigned long)F_CPU * 32) / 32768)
void clock_init()
{
    NVMCTRL->CTRLA.bit.AUTOWS = 1;

    GCLK->CTRLA.bit.SWRST = 1;
    while (GCLK->CTRLA.bit.SWRST);

    //switch on the extern 32,768 KHz Quarz
    OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ENABLE |
                              OSC32KCTRL_XOSC32K_XTALEN |
                              OSC32KCTRL_XOSC32K_EN32K |
                              OSC32KCTRL_XOSC32K_RUNSTDBY |
                              OSC32KCTRL_XOSC32K_STARTUP(7);

    while (0 == OSC32KCTRL->STATUS.bit.XOSC32KRDY);

    //XOSC32K -> GCLK2
    PORT->Group[PORTA].PINCFG[16].reg = PORT_PINCFG_PMUXEN| PORT_PINCFG_DRVSTR; // Enable peripheral multiplexer
    PORT->Group[PORTA].PMUX[16/2].reg = 12; // Set peripheral function F (TCC0/WO[2])
    GCLK->GENCTRL[GCLK2].reg = GCLK_GENCTRL_SRC(GCLK_SOURCE_XOSC32K) | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_OE;

/* disable the DPLL before changing the configuration */
    OSCCTRL->Dpll[0].DPLLCTRLA.bit.ENABLE = 0;
    while (OSCCTRL->Dpll[0].DPLLSYNCBUSY.reg) {}

    //XOSC32K -> GCLK2 -> FDPLL0
    GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = GCLK_PCHCTRL_GEN_GCLK2 | GCLK_PCHCTRL_CHEN;

    while (0 == (GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg & GCLK_PCHCTRL_CHEN));

    OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR_var % 32) | OSCCTRL_DPLLRATIO_LDR((LDR_var / 32) - 1);

    OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_XOSC32 |
                                     OSCCTRL_DPLLCTRLB_DIV(1) |
                                     OSCCTRL_DPLLCTRLB_WUF |
                                     OSCCTRL_DPLLCTRLB_LBYPASS;

    //FDPLL0 enable
    OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE | OSCCTRL_DPLLCTRLA_RUNSTDBY;

    //REG_OSCCTRL_DPLLCTRLB0 = 0;    
    //REG_OSCCTRL_DPLLCTRLB0 = OSCCTRL_DPLLCTRLB_LBYPASS | OSCCTRL_DPLLCTRLB_REFCLK(0);              // errata says to bypass lock when using internal 32k oscillator as source

    OSCCTRL->Dpll[0].DPLLCTRLA.bit.ENABLE = 1;
    while (OSCCTRL->Dpll[0].DPLLSYNCBUSY.reg) {}

    while (0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY || 0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK);       //wait for the DPLLSTATUS.bit.CLKRDY = ReadyBit= 1 and LOCKbit = 1;

    //FDPLL0 (120MHz) --> CPU
    PORT->Group[PORTB].PINCFG[14].reg = PORT_PINCFG_PMUXEN| PORT_PINCFG_DRVSTR; // Enable peripheral multiplexer
    PORT->Group[PORTB].PMUX[14/2].reg = 12; // Set peripheral function F (TCC0/WO[2])
    GCLK->GENCTRL[GCLK0].reg = GCLK_GENCTRL_SRC(GCLK_SOURCE_DPLL0) | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_OE;

    while ((GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL_GCLK0) == GCLK_SYNCBUSY_GENCTRL_GCLK0);

    OSCCTRL->DFLLCTRLA.reg = 0;

    OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP(0x1) |
                           OSCCTRL_DFLLMUL_FSTEP(0x1) |
                           OSCCTRL_DFLLMUL_MUL(0xBB80);

    while (OSCCTRL->DFLLSYNC.bit.DFLLMUL);

    OSCCTRL->DFLLCTRLB.reg = 0;
    while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB);

    OSCCTRL->DFLLCTRLA.bit.ENABLE = 1;
    while (OSCCTRL->DFLLSYNC.bit.ENABLE);

    OSCCTRL->DFLLVAL.reg = OSCCTRL->DFLLVAL.reg;
    while (OSCCTRL->DFLLSYNC.bit.DFLLVAL);

    OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_WAITLOCK |
                             OSCCTRL_DFLLCTRLB_CCDIS |
                             OSCCTRL_DFLLCTRLB_USBCRM;

    while (!OSCCTRL->STATUS.bit.DFLLRDY);
    //Switch Generic Clock Generator 5 to DFLL48M. for SERCOM5 48 MHz
    GCLK->GENCTRL[GCLK5].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) |
                               GCLK_GENCTRL_RUNSTDBY |
                               GCLK_GENCTRL_IDC |
                               GCLK_GENCTRL_OE |
                               GCLK_GENCTRL_GENEN;

    while (GCLK->SYNCBUSY.bit.GENCTRL5);
    //Switch Generic Clock Generator 6 to 120MHz. for observation purposeses
    GCLK->GENCTRL[GCLK6].reg = GCLK_GENCTRL_SRC(GCLK_SOURCE_DPLL0) |
                               GCLK_GENCTRL_RUNSTDBY |
                               GCLK_GENCTRL_IDC |
                               GCLK_GENCTRL_OE |
                               GCLK_GENCTRL_GENEN;
    while (GCLK->SYNCBUSY.bit.GENCTRL6);

//GCLK5 -> SERCOM5 48 MHz
    GCLK->PCHCTRL[SERCOM5_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK5 | GCLK_PCHCTRL_CHEN;
    while ((GCLK->PCHCTRL[SERCOM5_GCLK_ID_CORE].reg & GCLK_PCHCTRL_CHEN) != GCLK_PCHCTRL_CHEN);

    //FDPLL0 -> GCLK1 -> GCLK6 -> Pb12 -> LED Alive 120MHz
//--------------------------------------------------------------------------------------------------
//                                                                                    !!! with Bit12 = 1 !!!
    GCLK->GENCTRL[GCLK1].reg =
            GCLK_GENCTRL_DIV(120) | GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DPLL0) | GCLK_GENCTRL_DIVSEL | GCLK_GENCTRL_GENEN;
//                          120 : 120 = 1 MHz with GCLK_GENCTRL_DIVSEL 100KHz     ^------------------------------0x07 (Manual page 166)
    while ((GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL_GCLK1) == GCLK_SYNCBUSY_GENCTRL_GCLK1) {
        //wait for the GCLK1 Generator 1 synchronization
    }
//--------------------------------------------------------------------------------------------------
//                                                                                        !!! with Bit12 = 1 !!!   v---PB12 Pin25
    GCLK->GENCTRL[GCLK6].reg =
            GCLK_GENCTRL_DIV(100) | GCLK_GENCTRL_SRC(GCLK_SOURCE_GCLKGEN1) | GCLK_GENCTRL_DIVSEL | GCLK_GENCTRL_OE |
            GCLK_GENCTRL_GENEN;
//                          1MHz : 100 = 10 kHz with GCLK_GENCTRL_DIVSEL 1,8Hz 0,56 ms Periode                     ^------------------------------0x03 (Manual page 166)
    while ((GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL_GCLK6) == GCLK_SYNCBUSY_GENCTRL_GCLK6) {
        //wait for the GCLK1 Generator 6 synchronization
    }

    //FDPLL0 -> GCLK4
    GCLK->GENCTRL[GCLK4].reg = GCLK_GENCTRL_DIV(2) | GCLK_GENCTRL_SRC(GCLK_SOURCE_DPLL0) | GCLK_GENCTRL_GENEN;
//                                120Mhz :  2 = 60MHz             ^---------------------------------------------0x07 DPLL0 DPLL0 output (Manual Seite 166)
//                                120Mhz :  5 = 24MHz
//                                120Mhz : 15 =  8MHz
    while((GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL_GCLK4) == GCLK_SYNCBUSY_GENCTRL_GCLK4)
    {
        // wait for GCLK4 synchronization
    }
}
valeros commented 4 months ago

Hi @pr2zi, there is no support for SAME51J20A in this development platform, besides the atmelsam dev-platform only supports Arduino and Zephyr, but to you code doesn't seem to be either of those.