Author Topic: ATSAMD09/D21 - any writes to the GCLK resource appears to crash the part?  (Read 981 times)

0 Members and 1 Guest are viewing this topic.

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
While my bread-and-butter micro has been the SAMD51, I have an application where the ATSAMD09 is the perfect fit (by spec). I don't actually need much more than to configure some clocks, as all I'm using the D09 for is as a integer-N prescalar. As such, the core of my need is to manipulate the GCLK resources. Reading over the DS, unlike the D51 where you can manipulate the resource through individual bit operations, the D09/D21 must be written to "in bulk" or with all settings in one go. No problem, I can switch my methods to just OR'ing values. The datasheet also indicates you must 1. set the divisor first, 2. set the generator resource, then 3. set the Clock resource (if you're using it).

My finding is that any write to the GCLK peripheral crashes the part. For example:

   pGCLK->generatorDivisor = DIVIDE_BY_1 | GCLK_ID1;

Locks the part. Using the SAMICE debugger, you can pause before hand and it responds fine. You step into this instruction, and the system hangs. Pausing the debugger does nothing.

Now traditionally, this kind of behavior has me looking at the address mapping of a peripheral, and then to the register itself should the general mapping be correct. In this case, the root resource GCLK is correctly mapped to 0x4000C00; the division register is correctly offset by 8 bytes (0x4000C08). Other issues I have considered was perhaps (somehow) the GCLK resource in the power manager was janky, but no, the GCLK resource is enabled (1) in APBAMASK.

Now proceeding, just to be thorough, I went to the generator control. The following line:

       pGCLK->generatorControl = GCLK_ID1 | GCLK_GEN_SOURCE_OSC8M | GCLK_GEN_ENABLE | GCLK_OUTPUT_ENABLE; // Use the int 8M osc, route to gen 1, enable output and generator
   
Also causes the part to lock up. And both do this on ID0 as well. The current program, just to figure out the problem I'm having with GCLK, is:

Code: [Select]
int main(void)
{
volatile uint32_t configWord=0;

// Setup the port
pPortA->directionSet = (1 << 9); // pa09 to output
pPortA->pinMux[4].member.word = 0x66;
    pPortA->pCfg[8].member.bits.pmuxEnable=1;
pPortA->pCfg[8].member.bits.inputEnable=1;
pPortA->pCfg[9].member.bits.pmuxEnable=1;
pPortA->pCfg[9].member.bits.driveStrength=1;


pPortA->directionSet = (1 << 14);
pPortA->out = 0;

pSysControl->XOSC.word=0x2;
pSysControl->OSC8M.bits.prescalar = 0;

pGCLK->control.bits.reset = 1; // reset the GCLK resource


pGCLK->generatorDivisor = DIVIDE_BY_1 | GCLK_ID1; // setup a baseline division rate for GCLK1

pGCLK->generatorControl = GCLK_ID1 | GCLK_GEN_SOURCE_OSC8M | GCLK_GEN_ENABLE | GCLK_OUTPUT_ENABLE; // Use the int 8M osc, route to gen 1, enable output and generator


   
    while (1)
    {
pPortA->outToggle = (1<<14);

    }
}

The aim is to just toggle a pin if I can get through the clocking resource, but thus far it's all a miss. Does anyone have any inputs or ideas on what I'm missing?
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 828
Quote
the root resource GCLK is correctly mapped to 0x4000C00
I would assume these are typos, with a missing 0, but if not that could be a problem.

Your uppercase defines/enums/const's could be suspects as we cannot see if these are shifted values or not (they do not look like manufacturer defines). So, for instance you may be setting the id to some reserved value with unknown results if these are not shifted values.

This example is for a samD10, which is similar enough to the D09. It blinks an led from GCLK1 at 1Hz. The startup code is default generated, which is not doing anything special. The mcu headers were used for the registers only, the enums were produced from looking at the datasheet as its faster than finding/matching define names from headers to datasheet.
Code: [Select]
#include <sam.h>
#include <stdint.h>
#include <stdbool.h>

//functions are example specific, not complete
//no clock synchronization checks done

//------------------------------------------------------------------------------
//SYSCTRL
//------------------------------------------------------------------------------
                    typedef enum {
                    SYSCTRL_OSC8M_DIV1, SYSCTRL_OSC8M_DIV2, SYSCTRL_OSC8M_DIV4, SYSCTRL_OSC8M_DIV8 }
sysctrl_osc8m_div_t;

                    static inline void
sysctrl_osc8m_div   (sysctrl_osc8m_div_t e)
                    {
                    uint32_t bmclr = ~(3<<8); //PRESC[9:8]
                    uint32_t bmset = e<<8;
                    volatile uint32_t* preg = &SYSCTRL_REGS->SYSCTRL_OSC8M;
                    *preg = (*preg & bmclr) | bmset;
                    }

//------------------------------------------------------------------------------
//PORT
//------------------------------------------------------------------------------
                    typedef enum {
                    PORT_ALT_A, PORT_ALT_B, PORT_ALT_C, PORT_ALT_D, PORT_ALT_E,
                    PORT_ALT_F, PORT_ALT_G, PORT_ALT_H }
port_altfunc_t;

                    static inline void
port_altfunc        (const uint8_t pin, port_altfunc_t af)
                    { //mcu w/PORTA only
                    if( pin > 31 ) return; //invalid pin, do nothing
                    uint8_t bmclr = pin&1 ? ~0xF0 : ~0x0F;
                    uint8_t bmset = pin&1 ? af<<4 : af;
                    volatile uint8_t* preg = &PORT_REGS->GROUP[0].PORT_PMUX[pin/2];
                    *preg = (*preg & bmclr) | bmset;
                    PORT_REGS->GROUP[0].PORT_PINCFG[pin] |= 1; //PMUXEN
                    }

//------------------------------------------------------------------------------
//GCLK
//------------------------------------------------------------------------------
                    typedef enum {
                    GCLK0, GCLK1, GCLK2, GCLK3, GCLK4, GCLK5 }
gclk_id_t;
                    typedef enum {
                    GCLK_OSCULP32K = 3, GCLK_OSC8M = 6 }
gclk_src_t;

                    static inline void
gclk_generator      (gclk_id_t id, gclk_src_t src, const uint16_t div, const bool output)
                    {
                    GCLK_REGS->GCLK_GENDIV = div<<8 | id;
                    GCLK_REGS->GCLK_GENCTRL =  output<<19 | /*ENABLE*/1<<16 | src<<8 | id;
                    }

//------------------------------------------------------------------------------
//MAIN
//------------------------------------------------------------------------------
                    int
main                ()
                    {

                    //sysctrl_osc8m_div( SYSCTRL_OSC8M_DIV1 ); //works, not needed here
                    port_altfunc( 9, PORT_ALT_H ); //GCLKIO[1]->PA09 (led connected)
                    gclk_generator( GCLK1, GCLK_OSCULP32K, 32768, true ); //output enable

                    //PA09 blinks at 1Hz (osculp32k, div=32768)
                    while(1){}

                    }
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us


Quote from: XFDDesign on Today at 09:59:57 am
   pGCLK->generatorDivisor = DIVIDE_BY_1 | GCLK_ID1;


Is there some reason you're not using the Microchip-provided symbol definitions:
Code: [Select]
GCLK->GENDIV.reg = ((2 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));

 

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
Quote
the root resource GCLK is correctly mapped to 0x4000C00
I would assume these are typos, with a missing 0, but if not that could be a problem.

Your uppercase defines/enums/const's could be suspects as we cannot see if these are shifted values or not (they do not look like manufacturer defines). So, for instance you may be setting the id to some reserved value with unknown results if these are not shifted values.


Yes, typo there with the comment. Here is the list of address defines I use:

Code: [Select]
#define PAC0_ADDRESS 0x40000000
#define PM_ADDRESS 0x40000400
#define SYSCTRL_ADDRESS 0x40000800
#define GCLK_ADDRESS 0x40000c00
#define WDT_ADDRESS 0x40001000
#define RTC_ADDRESS 0x40001400
#define EIC_ADDRESS 0x40001c00
#define PAC1_ADDRESS 0x41000000
#define DSU_ADDRESS 0x41002000
#define NVMCTRL_ADDRESS 0x41004000
#define PORT_ADDRESS 0x41004400
#define DMAC_ADDRESS 0x41004800
#define MTB_ADDRESS 0x41006000
#define PAC2_ADDRESS 0x42000000
#define EVSYS_ADDRESS 0x42000400
#define SERCOM0_ADDRESS 0x42000800
#define SERCOM1_ADDRESS 0x42000C00
#define TC1_ADDRESS 0x42001800
#define TC2_ADDRESS 0x42001C00
#define ADC_ADDRESS 0x42002000

Directly copy/pasting the example program used fails to compile.


Is there some reason you're not using the Microchip-provided symbol definitions:
Code: [Select]
GCLK->GENDIV.reg = ((2 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));

I've not had a positive experience with ASF, finding it poorly documented, equal parts verbose and obfuscating and generally not a value add. Early efforts in using Atmel's framework didn't do well to communicate configuring hardware, and looking through the code found functions that refer to other functions which referred to skeletal functions, which... etc.

For what it is worth, for all of my other developments (SAMD51, SAME70/SAMS70) the abandoning of atmel's clunky framework has been without issue.
 

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
One incidental:

You can readback the current setting of a given GCLK GeneratorControl resource through writing ID to the register and then reading back the GCLK GenControl register. Reading both GCLK0 and GCLK1 do correctly report the Power-On-Default values per the DS.
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 828
Quote
Directly copy/pasting the example program used fails to compile.
Not a surprise as its using the manufacturer headers for the register access, and there are several flavors it seems. You would have to translate the register access lines to whatever you have in use. Figured you could handle that if/when you saw the error messages pertaining to the registers.

Complete, no manufacturer headers. Still blinks the led from GCLK1-

Code: [Select]
#include <stdint.h>
#include <stdbool.h>

//functions are example specific, not complete
//no clock synchronization checks done

//------------------------------------------------------------------------------
//SYSCTRL
//------------------------------------------------------------------------------
                    enum { SYSCTRL_BASE = 0x40000800 };
                    struct sysctrl_s { uint8_t unused_[0x20]; uint32_t OSC8M; };
                    volatile struct sysctrl_s* const SYSCTRL = (struct sysctrl_s*)SYSCTRL_BASE;

                    typedef enum {
                    SYSCTRL_OSC8M_DIV1, SYSCTRL_OSC8M_DIV2, SYSCTRL_OSC8M_DIV4, SYSCTRL_OSC8M_DIV8 }
sysctrl_osc8m_div_t;

                    static inline void
sysctrl_osc8m_div   (sysctrl_osc8m_div_t e)
                    {
                    uint32_t bmclr = ~(3<<8); //PRESC[9:8]
                    uint32_t bmset = e<<8;
                    SYSCTRL->OSC8M = (SYSCTRL->OSC8M & bmclr) | bmset;
                    }

//------------------------------------------------------------------------------
//PORT
//------------------------------------------------------------------------------
                    enum { PORT_BASE = 0x41004400 };
                    struct port_s { uint8_t unused_[0x30]; uint8_t PMUX[16]; uint8_t PINCFG[32]; };
                    volatile struct port_s* const PORT = (struct port_s*)PORT_BASE;

                    typedef enum {
                    PORT_ALT_A, PORT_ALT_B, PORT_ALT_C, PORT_ALT_D, PORT_ALT_E,
                    PORT_ALT_F, PORT_ALT_G, PORT_ALT_H }
port_altfunc_t;

                    static inline void
port_altfunc        (const uint8_t pin, port_altfunc_t af)
                    { //mcu w/PORTA only
                    if( pin > 31 ) return; //invalid pin, do nothing
                    uint8_t bmclr = pin&1 ? ~0xF0 : ~0x0F;
                    uint8_t bmset = pin&1 ? af<<4 : af;
                    PORT->PMUX[pin/2] = (PORT->PMUX[pin/2] & bmclr) | bmset;
                    PORT->PINCFG[pin] |= 1; //PMUXEN
                    }

//------------------------------------------------------------------------------
//GCLK
//------------------------------------------------------------------------------
                    enum { GCLK_BASE = 0x40000C00 };
                    struct gclk_s { uint8_t unused_[4]; uint32_t GENCTRL; uint32_t GENDIV; };
                    volatile struct gclk_s* const GCLK = (struct gclk_s*)GCLK_BASE;

                    typedef enum {
                    GCLK0, GCLK1, GCLK2, GCLK3, GCLK4, GCLK5 }
gclk_id_t;
                    typedef enum {
                    GCLK_OSCULP32K = 3, GCLK_OSC8M = 6 }
gclk_src_t;

                    static inline void
gclk_generator      (gclk_id_t id, gclk_src_t src, const uint16_t div, const bool output)
                    {
                    GCLK->GENDIV = div<<8 | id;
                    GCLK->GENCTRL = output<<19 | /*ENABLE*/1<<16 | src<<8 | id;
                    }

//------------------------------------------------------------------------------
//MAIN
//------------------------------------------------------------------------------
                    int
main                ()
                    {

                    //sysctrl_osc8m_div( SYSCTRL_OSC8M_DIV1 ); //works, not needed here
                    port_altfunc( 9, PORT_ALT_H ); //GCLKIO[1]->PA09 (led connected)
                    gclk_generator( GCLK1, GCLK_OSCULP32K, 32768, true ); //output enable

                    //PA09 blinks at 1Hz (osculp32k, div=32768)
                    while(1){}

                    }

https://godbolt.org/z/ejeq7jjcn

and since functions were created, can easily use more gclkio w/led's-
https://godbolt.org/z/EnGa96rM7
« Last Edit: August 28, 2023, 04:33:59 pm by cv007 »
 

Offline XFDDesignTopic starter

  • Frequent Contributor
  • **
  • Posts: 442
  • Country: us
Credit where it's due, this works. Thanks! I'll work to figure out what is functionally different. My best guess is that I'm missing some kind of configuration step.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Quote
Quote
Is there some reason you're not using the Microchip-provided symbol definitions:
I've not had a positive experience with ASF
Using the provided CMSIS headers is a lot less obnoxious and intrusive than using ASF (the set of library functions)!
I don't like ASF either, but it would take much more extreme problems for me to reject the hardware definition .h files provided by a vendor.  (the directory structure of the rp2040 almost does it.)

For instance, My immediate guess as to your problem is that you have the structure for GLCK defined wrong (it's MUCH different between SAMD9 and SAMD51.)  But I really don't want to wade through your definitions and compare them to the official versions.
« Last Edit: August 28, 2023, 06:16:29 pm by westfw »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf