Atmel SAM D example config (no ASF) - Page 1
Forum section: electronics / general

author: Dragon88
author_rank: Regular Contributor
timestamp: September 03, 2015, 01:35:26 am
content: HiI have some SAM D10C devices (not the Xplained board, just bare chips) that I am working with. I have programmed one using the example ASF blink project. That works fine. I have modified the example to do various things and that all works fine too. The problem is that ASF creates a real mess of files and includes to hide all of the configuration. I don't want that. I want to know the entire configuration process myself, code it myself, etc. I have tried to strip away the unnecessary junk that ASF creates, but I think a better solution is to start from scratch. A non-ASF example of configuring a SAM chip would be helpful.Anyone have a link to such an example?Or does "everyone" use the toolchain? I know the ARM world is very different from AVRs, but 5 lines of code to configure a pin as an output in RIDICULOUS. Three to five include files to set up the clock is RIDICULOUS. And so is 20% of RAM being occupied just to blink an LED.Thanks

author: retrolefty
author_rank: Super Contributor
timestamp: September 03, 2015, 05:31:29 am
content: Quote from: Dragon88 on September 03, 2015, 01:35:26 amI'm sure the ARM platform is what and where industry is going for many good reasons, but for this hardware side hobbyist I will stay with the AVR 8 bit family for my projects.

author: senso
author_rank: Frequent Contributor
timestamp: September 03, 2015, 11:23:03 am
content: The RAM usage is due to the stack/heap allocation, ARM is stupid in that regard..I have been trying to use a SAMR21, and the datasheet is crap, the documentation is a disgrace, ASF is a mismatch of libs, no documentation whatsoever, just doxygen lists of the .h files, cool, what does this function does?Try it, throw parameters into that, see how it barfs..

author: Bassman59
author_rank: Super Contributor
timestamp: September 03, 2015, 09:18:52 pm
content: Quote from: senso on September 03, 2015, 11:23:03 amFor shits and grins, you should submit tech-support requests.

author: westfw
author_rank: Super Contributor
timestamp: September 03, 2015, 10:42:09 pm
content: I've been gradually moving the SAMD10 Blink example to a non-ASF form, and adding Arduino-like functionality (say what you want about Arduino, but implementing the "core" is a good way to learn a bunch of stuff about a new chip family.)I've got clock_init() replaced, pinMode(), digitalWrite(), Polled UART, millis/micros/delay/etc (using the RTC)A program that uses them all is about 1.5k. Which is pretty good, since the original was over 2k to do just the blink.There are some useful threads over in the SAMD subsection of AVRFreaks.You don't actually have to do much to get an LED blinking; setting up the core clock is about it (and you COULD default to a lot more than I do here...)Code:void system_clock_init(){#ifdef USEPLL#define EXTCLK_DIV ((EXTCLK_FREQ/(2*F_INTERM)) - 1) // Slightly complicated//Enable the 8MHz oscillator input from SAMD10 XMiniSYSCTRL->XOSC.reg = (SYSCTRL_XOSC_ENABLE);//Wait for the crystal oscillator to start upwhile((SYSCTRL->PCLKSR.reg & (SYSCTRL_PCLKSR_XOSCRDY)) == 0);//Set flash wait state to 1, which we need to do at 48MHzREG_NVMCTRL_CTRLB |= (NVMCTRL_CTRLB_RWS(1));//Configure the DPLLSYSCTRL->DPLLCTRLA.reg = 0; // Defaults!/** The output of DPLL is supposed to be between 48MHz and 96MHz.* By setting the PLL output to 2*F_CPU, we have easy acess to* most of the "interesting" frequencies between 24MHz and 48MHz* Lower F_CPU can be obtained by increasing the GCLK0 divisor.*/SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(2*F_CPU/F_INTERM);SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_DIV(EXTCLK_DIV) | /* Refclock divider */SYSCTRL_DPLLCTRLB_REFCLK(SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC);SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;while(!(SYSCTRL->DPLLSTATUS.reg & (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK)) ==(SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK));//For generic clock generator 0, select the DPLL Clock as input, divide by 2GCLK->GENDIV.reg = ((2 << GCLK_GENDIV_DIV_Pos) | (0 << GCLK_GENDIV_ID_Pos));GCLK->GENCTRL.reg = ((0 << GCLK_GENCTRL_ID_Pos) | (GCLK_SOURCE_FDPLL << GCLK_GENCTRL_SRC_Pos)| (GCLK_GENCTRL_GENEN));GCLK->CLKCTRL.reg = ((GCLK_CLKCTRL_GEN_GCLK0) | (GCLK_CLKCTRL_CLKEN)) ;#endif /* USEPLL */}/** Map Arduino pin numbers to hardware specific values.* In the case of the D10, all the pins bits in a single GPIO port* so it's efficient to map to bit numbers (which an ARM can easily* convert to a bitmask, since it has a barrel shifter.)* -1 means the digital pin doesn't exist.*/const int8_t digital_pin_to_pinno[] = {11, 10, 16, 17,27, 25, 30, 31,-1, -1, 23, 22,24, 9, 02, 03,04, 05, 06, 07,15, 14};/** digitalWrite(pinno, level)* This is logically similar to the ASF function port_pin_set_output_level(),* but uses a different mechanism for mapping the "pinno" to the port/bit.*/void digitalWrite(uint8_t pinno, uint8_t level){PortGroup *const port_base = &(PORT->Group); /* port_get_group_from_gpio_pin(1); */ // any pin will work.uint32_t pin_mask = (1UL << (digital_pin_to_pinno));if (level) {port_base->OUTSET.reg = pin_mask;} else {port_base->OUTCLR.reg = pin_mask;}}void pinMode(uint8_t pinno, uint8_t direction){PortGroup *const port_base = &(PORT->Group); /* port_get_group_from_gpio_pin(1); */ // any pin will work.uint32_t pin_mask = (1UL << (digital_pin_to_pinno));if (direction == OUTPUT) {port_base->DIRSET.reg = pin_mask;} else {port_base->DIRCLR.reg = pin_mask;}}

author: westfw
author_rank: Super Contributor
timestamp: September 03, 2015, 11:00:10 pm
content: QuoteMost of it is just the stack, which shows up explicitly in BSS in the ARM compiles, rather than just have the SP set to the "end of ram" by the init code. I wouldn't really call this "stupid"; it's just different. There is also 40 bytes of "clock configuration instance", in case your code needs to know how the clock is configured because you forgot, or something...

author: Dragon88
author_rank: Regular Contributor
timestamp: September 03, 2015, 11:36:55 pm
content: Quote from: westfw on September 03, 2015, 10:42:09 pmExcellent. I will take a look at this. Thanks.

author: westfw
author_rank: Super Contributor
timestamp: September 04, 2015, 12:23:47 am
content: I've uploaded the whole thing to here:https://github.com/WestfW/SAMD10-experiments

author: westfw
author_rank: Super Contributor
timestamp: September 04, 2015, 05:00:27 am
content: (hmm. Note that my clock initialization code uses the 8MHz Xin input provided by the Xplained board, but PROBABLY not present on a bare-chip based board.)

author: Bassman59
author_rank: Super Contributor
timestamp: September 04, 2015, 05:00:25 pm
content: Quote from: westfw on September 03, 2015, 10:42:09 pmI've been stripping ASF down to the bare minimum for the SAM3 devices. Basically, it's all about shitcanning everything but the "drivers," which are pretty much what I'd write myself for doing the low-level peripheral access. I've removed all of the device-abstraction cruft from the drivers, so it only applies to the SAM3 devices and is straightforward. Some of the "services" have been retained, too, since they're useful (a lot are not!), but again layers of abstraction have been removed.It's a work in progress. I suppose I'll post it somewhere when it's all complete.

author: Dragon88
author_rank: Regular Contributor
timestamp: September 04, 2015, 09:31:22 pm
content: Quote from: westfw on September 04, 2015, 05:00:27 amSetting up external clocks is quite easy, even on a bare chip. As much as I dislike all of the garbage ASF creates, conf_clocks.h is a good file. Just go in and enable what you want. All you need to use the DFLL at 48MHz for the main clock is a 32.768 kHz crystal and load capacitors connected to A08 and A09. Here are the modifications needed in conf_clocks.h to use the DFLL if you are interested:Code:/* System clock bus configuration */# define CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT false# define CONF_CLOCK_FLASH_WAIT_STATES 1# define CONF_CLOCK_CPU_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1# define CONF_CLOCK_APBA_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1# define CONF_CLOCK_APBB_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1.../* SYSTEM_CLOCK_SOURCE_XOSC32K configuration - External 32KHz crystal/clock oscillator */# define CONF_CLOCK_XOSC32K_ENABLE true# define CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL# define CONF_CLOCK_XOSC32K_STARTUP_TIME SYSTEM_XOSC32K_STARTUP_65536# define CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL false# define CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT false# define CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT true# define CONF_CLOCK_XOSC32K_ON_DEMAND false# define CONF_CLOCK_XOSC32K_RUN_IN_STANDBY true.../* SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop */# define CONF_CLOCK_DFLL_ENABLE true# define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED# define CONF_CLOCK_DFLL_ON_DEMAND true.../* DFLL closed loop mode configuration */# define CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR GCLK_GENERATOR_1# define CONF_CLOCK_DFLL_MULTIPLY_FACTOR (48000000/32768)# define CONF_CLOCK_DFLL_QUICK_LOCK true# define CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK true# define CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP true# define CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE true# define CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE (0x1f / 8)# define CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE (0xff / 8).../* Configure GCLK generator 0 (Main Clock) */# define CONF_CLOCK_GCLK_0_ENABLE true# define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true# define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL# define CONF_CLOCK_GCLK_0_PRESCALER 1# define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false/* Configure GCLK generator 1 */# define CONF_CLOCK_GCLK_1_ENABLE true# define CONF_CLOCK_GCLK_1_RUN_IN_STANDBY false# define CONF_CLOCK_GCLK_1_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_XOSC32K# define CONF_CLOCK_GCLK_1_PRESCALER 1# define CONF_CLOCK_GCLK_1_OUTPUT_ENABLE true

author: westfw
author_rank: Super Contributor
timestamp: September 05, 2015, 12:38:13 am
content: QuoteMeh; there are examples for running the DFLL from a 32kHz crystal, and the config file is "almost there" to start with. But I didn't find it very intuitive to (say) configure a 32MHz main clock based on the 8MHz Xin input (the Xplained mini has neither a crystal, not a place to mount one.) And the LED_TOGGLE example will shrink by over 800 bytes of code just by getting rid of the ASF clock functions. I consider 800 bytes a relatively significant chunk on a processor family with 16k max... (OTOH, it's more intuitive now that I've gotten more familiar with how the clocking works.)It seems to be the ASF *_init() functions that are most bloated by unnecessary abstraction. You pass them a datastructure containing all the information about all the sub-features that you are NOT interested in, and then it picks its way through a decision tree that is also capable of handling all of the sub-features. And it's a shame, because (as I've complained before, over in the one-dollar STM32 thread) in theory you could pass a set of constants to an inline function, and have the compiler remove most of that code at compile time. Or maybe a C++ template could do something similar (C++ being significantly better at handling data structures with a lot of user-specifiable fields with default values.) But that's not the way the code is written, and not the way it is documented to be used.

author: Dragon88
author_rank: Regular Contributor
timestamp: September 05, 2015, 01:11:37 am
content: It's a good file in that it shows examples of each clock configuration. Certainly the many bytes of clock setup files need to be stripped out once you settle on one. Though I'm sure Atmel just wants you to use ASF, and if you run out of flash, upgrade to a more expensive chip...To be honest though, I'm playing around with a STM32 and CooCox IDE, and it's 100x less bloated than Atmel Studio. It will be a struggle now to get back in there and slog through ASF garbage...

author: Dragon88
author_rank: Regular Contributor
timestamp: September 05, 2015, 01:33:02 pm
content: Against my better judgment I'm back at it.I have gotten program memory usage down, but the RAM usage is still very high for a blinky program. What's up with this? Is it "normal" for this ARM device?Code:Program Memory Usage:2236 bytes 13.6 % FullData Memory Usage:1096 bytes 26.8 % Full

author: westfw
author_rank: Super Contributor
timestamp: September 05, 2015, 04:38:22 pm
content: It's the stack, which defaults to 1024 bytes (and which has been pointed out several times now.)on an AVR, the stack pointer would be initialized to "the end of memory" without actually allocating any space to it.On an ARM, you can theoretically detect when the stack and heap collide (or prevent this...)The stack size can be changed in the linker script (look for STACK_SIZE) or by adding a magic gcc command to set linker symbols (-Xlinker --defsym=__stack_size__=0x100 )