AtmelStart suggestion

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmel, please provide a Hello World project for the XMini which isn't based on the ASF, but on Atmel Start (start.atmel.com).

 

Ideally this project toggles the LED from an interrupt and allows its brightness to be set from the ADC using PWM.

 

Should be 30 minutes of work for one of your engineers, and invaluable for those who try to come to terms with a completely new architecture.

 

But if someone else can provide this, even better!

 

Thanks!!

 

 

 

This topic has a solution.

Last Edited: Tue. Nov 17, 2015 - 06:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Of course, a complete Hello World example would have higher value if it uses the Event System Channel to connect the timer to the ADC, to then interrupt on the ADC result.

 

Of course this needs to be commented reasonably well (the code I've seen sofar does not!), for otherwise everybody needs to reverse engineer the code to understand (and adapt) it.

 

Such a sample project is urgent and a single example would serve for D11/D10/D09 and possibly D21. The examples provided with the Xmini skimp on all the peripherals that make the D10 so interesting.

 

We don't need extensive docs, we just need snippets, each documenting simple tasks. Examples: setting the timer period, the pwm duty cycle, triggering the ADC on a channel, reading the ADC result, connecting an event to an event user using the event system, capturing and handling an interrupt, sending data out over the UART, setting a pin as an input, an output and configuring pullups!

 

Such code most certainly exists within Atmel, just extract the relevant snippets and publish them! I effectively can't do my job if Atmel doesn't.

 

I love this chip, but my time to market is unacceptable.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I don't use ASF or Atmel Start whenever possible.  Did you contact your local Atmel FAE and ask for help?

 

I am not sure this example will help you as I didn't provide a lot of documentation (it is also for the SAMD10 mini). The greater the flexibility of a peripheral usually coincides with an increase in the complexity.

This code example provides some basic features (to what I envisioned):

- TC1 (8-bit PWM) on PA04, Interrupt to change the duty cycle on an overflow event.

- ADC for Single-Ended Conversion on AIN0 (PA02)

- Event system channel 0 (Generator TC1 Overflow,  User ADC Start)

- Systick to generate periodic interrupts that will toggle PA09 (Yellow LED)

 

Regards, Chris

#define TC1_PERIOD ((uint8_t)0xFEu)
#define TC1_DUTY_CYCLE ((uint8_t)0x60u)

volatile uint32_t cnt;
volatile uint8_t test;
volatile uint8_t myTC1DC;
volatile uint8_t myAdcChannel;
volatile uint16_t myAdcResult;

/* private variables */
static uint8_t dc;

/**
 *
 * @brief  Initialize the ADC peripheral
 */
void ADC_Init(void)
{
	/* Turn on the digital interface clock */
	PM->APBCMASK.reg |= PM_APBCMASK_ADC;

	/* Turn on the analog interface clock and use GCLK Generator
	 */
	GCLK_CLKCTRL_Type adc_clkctrl =
	{
		.bit.WRTLOCK = 0,
		.bit.CLKEN = 1,  /* enable clock */
		.bit.ID = ADC_GCLK_ID,
		.bit.GEN = 0,   /* GCLK_GENERATOR_0 */
	};
	GCLK->CLKCTRL.reg = adc_clkctrl.reg;

	/* reset the ADC to its initial settings */
	ADC->CTRLA.reg = ADC_CTRLA_SWRST;

	/* Load in the fixed device ADC calibration constants */
	ADC->CALIB.reg =
	  ADC_CALIB_BIAS_CAL((*(uint32_t *) ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos)) |
	  ADC_CALIB_LINEARITY_CAL((*(uint64_t *) ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos));

	/* Configure reference */
	ADC_REFCTRL_Type refctrl =
	{
		.bit.REFCOMP = 1, /* enable reference compensation */
		.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val,
	};
	ADC->REFCTRL.reg = refctrl.reg;

	/* Set up the average and samples */
	ADC_AVGCTRL_Type avgctrl =
	{
		.bit.ADJRES = 0,
		.bit.SAMPLENUM = ADC_AVGCTRL_SAMPLENUM_1_Val,
	};
	ADC->AVGCTRL.reg = avgctrl.reg;

	/* Configure sample length */
	ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(5);

	/* Configure CTRLB */
	ADC_CTRLB_Type ctrlb =
	{
		/* ADC clock is 8MHz / 4 = 2MHz */
		.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV4_Val,
		.bit.RESSEL =  ADC_CTRLB_RESSEL_12BIT_Val,
		.bit.CORREN = 0,
		.bit.FREERUN = 0,
		.bit.LEFTADJ = 0,
		.bit.DIFFMODE = 0,
	};
	ADC->CTRLB.reg =  ctrlb.reg;

	/*  */
	ADC_EVCTRL_Type adc_evctrl =
	{
		.bit.WINMONEO = 0,
		.bit.RESRDYEO = 0,
		.bit.SYNCEI = 1,
		.bit.STARTEI = 1,
	};
	ADC->EVCTRL.reg = adc_evctrl.reg;

	/* Configure pin scan mode and positive and negative input pins */
	ADC->INPUTCTRL.reg = ADC_INPUTCTRL_GAIN_DIV2 |
	                     ADC_INPUTCTRL_MUXPOS_PIN0 |
	                     ADC_INPUTCTRL_MUXNEG_IOGND;

	/* enable the ADC */
	ADC->CTRLA.reg = ADC_CTRLA_ENABLE;

	/* Configure channels that are used for ADC */
	PORT->Group[0].PMUX[PIN_PA02 / 2].bit.PMUXE = MUX_PA02B_ADC_AIN0;
	PORT->Group[0].PINCFG[PIN_PA02].reg = PORT_PINCFG_PMUXEN;
}

/**
 *
 * @brief  Convert an analog channel and wait for it to finish
 */
int16_t ADC_ReadSingleChannel(uint8_t channel)
{
	ADC->INPUTCTRL.bit.MUXPOS = channel;

	ADC->SWTRIG.reg = ADC_SWTRIG_START | ADC_SWTRIG_FLUSH;

	while (ADC->INTFLAG.bit.RESRDY == 0)
	{
		/* Wait for analog conversion to complete */
	}

	/* return with converted value */
	return ADC->RESULT.reg;
}

/**
* Event System
*
* @brief
*/
void EVSYS_Init(void)
{
	/* Turn on the digital interface clock */
	PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;

	/* Turn on the peripheral interface clock and select GCLK */
	GCLK_CLKCTRL_Type clkctrl =
	{
		.bit.WRTLOCK = 0,
		.bit.CLKEN = 1,
		.bit.ID = EVSYS_GCLK_ID_0,
		.bit.GEN = 0, /* GCLK_GENERATOR_0 */
	};
	GCLK->CLKCTRL.reg = clkctrl.reg;

	EVSYS_USER_Type user_0 =
	{
		.bit.CHANNEL = 1, /* use channel 0 */
		.bit.USER = EVSYS_ID_USER_ADC_START, /* ADC Start*/
	};
	EVSYS->USER.reg = user_0.reg;

	EVSYS_CHANNEL_Type channel_0 =
	{
		.bit.EDGSEL = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT_Val,
		.bit.PATH = EVSYS_CHANNEL_PATH_ASYNCHRONOUS_Val,
		.bit.EVGEN = EVSYS_ID_GEN_TC1_OVF, /* TC1 Timer OVF */
		.bit.SWEVT = 0,   /* no software trigger */
		.bit.CHANNEL = 0, /* use channel 0 */
	};
	EVSYS->CHANNEL.reg = channel_0.reg;
}

/**
 *
 * @brief  Initialize the TC1
 */
void TC1_Init(void)
{
	/* Turn on the digital interface clock */
	PM->APBCMASK.reg |= PM_APBCMASK_TC1;

	/* Turn on the peripheral interface clock and select GCLK */
	GCLK_CLKCTRL_Type clkctrl =
	{
		.bit.WRTLOCK = 0,
		.bit.CLKEN = 1,
		.bit.ID = TC1_GCLK_ID,
		.bit.GEN = 0, /* GCLK_GENERATOR_0 */
	};
	GCLK->CLKCTRL.reg = clkctrl.reg;

	/* reset the peripheral to its default state */
	TC1->COUNT8.CTRLA.bit.SWRST = 1;
  /* wait for synchronization to complete */
  while (TC1->COUNT8.STATUS.bit.SYNCBUSY == 1);

	/* set the access mode for the timer */
	TC1->COUNT8.CTRLA.reg = TC_CTRLA_MODE_COUNT8;

	/* Set the period of the PWM */
	TC1->COUNT8.PER.reg = TC1_PERIOD;

	/* set the duty cycle for WO[0]*/
	TC1->COUNT8.CC[0].reg = TC1_DUTY_CYCLE;

	/*  */
	TC_EVCTRL_Type tc_evctrl =
	{
		.bit.MCEO1 = 0,
		.bit.MCEO0 = 0,
		.bit.OVFEO = 1, /* allow event on overflow */
		.bit.TCEI = 0,
		.bit.TCINV = 0,
		.bit.EVACT = 0,
	};
	TC1->COUNT8.EVCTRL.reg = tc_evctrl.reg;

	/* configure the mode, PWM generation and prescaler */
	TC_CTRLA_Type tc_ctrla =
	{
		.bit.PRESCSYNC = 0,
		.bit.RUNSTDBY = 0,
		.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV16_Val,
		.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NPWM_Val,
		.bit.MODE = TC_CTRLA_MODE_COUNT8_Val,
		.bit.ENABLE = 1,
	};
	TC1->COUNT8.CTRLA.reg = tc_ctrla.reg;

	/* clear any pending interrupt */
	NVIC_ClearPendingIRQ(TC1_IRQn);
	/* Enable the peripheral interrupt in the NVIC */
	NVIC_EnableIRQ(TC1_IRQn);

	/* configure the pin(s) to be used by the peripheral */
	PORT->Group[0].PMUX[PIN_PA04 / 2].bit.PMUXE = MUX_PA04E_TC1_WO0;
	PORT->Group[0].PINCFG[PIN_PA04].bit.PMUXEN = PORT_PINCFG_PMUXEN;
}

/**
 *
 * @brief  function to change the duty cycle using the overflow interrupt
 */
void TC1_ChangeDutyCycle(uint8_t value)
{
	/* store the new duty cycle value for updating in the interrupt */
	dc = value;
	/* clear the interrupt flag used for the overflow */
	TC1->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF;
	/*  enable the interrupt for overflow */
	TC1->COUNT8.INTENSET.reg = TC_INTENSET_OVF;
}

/**
 *
 * @brief  Interrupt handler for TC1
 */
void TC1_Handler(void)
{
	/* disable the interrupt for overflow */
	TC1->COUNT8. INTENCLR.reg = TC_INTENCLR_OVF;
	/* update the duty cycle */
	TC1->COUNT8.CC[0].reg = dc;
}

/**
* System Tick Initialization
*
* @brief  Set up the systick counter for a 1msec interval
*/
void SYSTICK_Init(void)
{
	/* count value that should result in 10 msec timeout */
	SysTick->LOAD = SysTick->CALIB;
	/* run from cpu clock, enable timer and also the interrupt */
	SysTick->CTRL = SysTick_CTRL_TICKINT_Msk |
	                SysTick_CTRL_ENABLE_Msk;
}

/**
 * System Tick Handler
 *
 * @brief  Exception handler for the SysTick count down counter from the Core
 */
void SysTick_Handler(void)
{
	if (++cnt > 50)
	{
		cnt = 0;
		/* toggle the Yellow LED on the SAMD10 */
		PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA09;
	}
}

/**
 * main
 *
 * @brief  Starting point for the code after compiler initialization
 */
int main(void)
{
#define MY_SYSCTRL_OSC8M_MASK ((uint32_t)0xCFFF0002ul)
	/* change the clock frequency from 1MHz to 8MHz */
	SYSCTRL->OSC8M.reg = (MY_SYSCTRL_OSC8M_MASK & SYSCTRL->OSC8M.reg) |
	                     SYSCTRL_OSC8M_ONDEMAND |
	                     SYSCTRL_OSC8M_RUNSTDBY |
	                     SYSCTRL_OSC8M_PRESC_0;

	/* configure the ADC peripheral */
	ADC_Init();
	/* initialize the system timer */
	SYSTICK_Init();
	/* enable the Event system to use TC1 to trigger an analog conversion */
	EVSYS_Init();
	/* enable TC1 for a 8-bit PWM channel */
	TC1_Init();
	/* enable port output connected to the yellow LED */
	PORT_IOBUS->Group[0].DIRSET.reg = PORT_PA09;

	/* loop forever */
	while (1)
	{
		if (test == 1)
		{
			test = 0;
			/* change the duty cycle */
			TC1_ChangeDutyCycle(myTC1DC);
		}

		if (test == 2)
		{
			test = 0;
			/* ADC */
			myAdcResult = ADC_ReadSingleChannel(myAdcChannel);
		}

	}
}

 

Last Edited: Sat. Nov 14, 2015 - 02:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

cwunder wrote:

I don't use ASF or Atmel Start whenever possible.  Did you contact your local Atmel FAE and ask for help?

 

More power to you!

 

I did contact my local support rep, he could not find time in his schedule for some weeks, nor did he have a hello world ready (which I think is throwing people in at the deep end). He did his best and tried to make a skeleton for my project, but the basics didn't work, so that didn't help. He'll be available soon, but at this point there's not much faith left. Apparently even customers with 5 million units have to wait 2 weeks for answers. For a Hello World...??! Yeah.

 

 

cwunder wrote:

I am not sure this example will help you as I didn't provide a lot of documentation (it is also for the SAMD10 mini).

 

Wow, sample code! This is great, thanks Chris. Working with registers may well be best, as long as I have something that gets me going. I'll test it and post any upgrades back so others can (maybe..) find it. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I added an #include <asf.h> (at the top) to get it to compile, and an #undef ENABLED further below (otherwise .bit.ENABLED) bombs). Then I got an unexpected error, please see post https://community.atmel.com/forum.... I could not find any answers using Google, and it must be something basic I am not getting yet. Thanks again, Chris, for the highly informed (definitely not-rookie) code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You should not use ASF.h unless using ASF.

 

For the example code above it was created using a GCC C Executable project. Here you just need to add #include "sam.h" in each source file.

 

The reason I don't use ASF in my opinion is that it is written for the person tasked to create the driver (and what makes it easier for them to code). Not necessarily for a user to easily understand what the driver is supposed to do (when not familiar to a device/peripheral). By time it takes to figure out the ASF (which can be wrong by the way) and some of its restrictions it seems easier to make your own for your purpose.

 

Last Edited: Mon. Nov 16, 2015 - 06:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed now it compiles fine. Everything is new and the confusion reigns (Start/ASF/GCC/CMSIS/M0/Studio7).

 

Note: I noted that TC1_Handler is defined but never called. I suppose this is correct, because TC1 is configured to generate PWM. For as I understand the datasheet, in this mode it won't generate an interrupt ever. So if I'd like an interrupt I must use another timer or SysTick. Please correct me if I'm wrong.

 

Thanks again.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The Timer can generate interrupts in this mode.

 

The SAMDx Timer Counter (TCx) do not have double buffered registers for the compare or period registers. Thus once written they are acted on so you have to be careful when write an update.

 

The code does use the TC1 OVF interrupt to update the duty cycle of TC1 at the timer overflow. The function TC1_ChangeDutyCycle stores the new duty cycle to a static variable used in the TC interrupt. First it clears the flag and then enables the interrupt flag for OVF.

 

/**
 *
 * @brief  function to change the duty cycle using the overflow interrupt
 */
void TC1_ChangeDutyCycle(uint8_t value)
{
	/* store the new duty cycle value for updating in the interrupt */
	dc = value;
	/* clear the interrupt flag used for the overflow */
	TC1->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF;
	/*  enable the interrupt for overflow */
	TC1->COUNT8.INTENSET.reg = TC_INTENSET_OVF;
}

 

When the TC1 interrupt occurs, the overflow interrupt enable is disabled to prevent further interrupts. The static duty cycle value is now written to the CC0 register.

/**
 *
 * @brief  Interrupt handler for TC1
 */
void TC1_Handler(void)
{
	/* disable the interrupt for overflow */
	TC1->COUNT8.INTENCLR.reg = TC_INTENCLR_OVF;
	/* update the duty cycle */
	TC1->COUNT8.CC[0].reg = dc;
}

There is only one interrupt vector available for the TC so if you enable more than one you will have to add code to determine the cause of the interrupt and act upon it.

 

What are you trying to accomplish?

Last Edited: Mon. Nov 16, 2015 - 09:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

cwunder wrote:

The Timer can generate interrupts in this mode.

 

Yes. I created confusion. The difference is in the availability of a period count. I understand that in 8-bit mode there is one, in 16-bit mode there isn't. There the interrupt is on the full 16-bit overflow, which is much to late. I need to reset the counters manually, from software.

 

 

cwunder wrote:

The SAMDx Timer Counter (TCx) do not have double buffered registers for the compare or period registers. Thus once written they are acted on so you have to be careful when write an update.

 

Ouch! Good call. I presumed buffering was the norm. Not a biggie... now that I'm aware!

 

cwunder wrote:

The code does use the TC1 OVF interrupt to update the duty cycle of TC1 at the timer overflow. The function TC1_ChangeDutyCycle stores the new duty cycle to a static variable used in the TC interrupt. First it clears the flag and then enables the interrupt flag for OVF.

 

Indeed it does. I just needed to change the value of test manually to 1 to get the interrupt. Ok!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

cwunder wrote:

What are you trying to accomplish?

 

I basically need to eliminate the consequences of an ugly 120Hz ripple on top of a rectified 60Hz AC whenever possible. So despite the ripple the output should be as smooth as possible. At high output voltages (a lesss common usage) this obviously becomes impossible.

 

So my problem is at its simplest:

1. Generate PWM (PA22) at the lowest non-audible frequency (variable, to be experimented with).

 

That'll give me about 125 periods to work with within a half wave period.

 

2. Measure input voltage (PA2), under load, right before the PWM ends.

 

So I need a timer triggering the ADC and an interrupt at the same time. Or, possibly, I do everything in the interrupt.

 

In the interrupt I apply the PWM calculated before, and restart the PWM.

 

I then go on to calculate the value to apply for the next PWM period. It is likely that this part will grow.

 

I considered doing this in hardware, but not viable.

 

 

So this is actually quite close to a blinking led demo, demonstrating interrupts and PWM. Which you demonstrated, better yet in the most efficient manner. If you can give me further pointers, much much appreciated, but you have already done what other$ could not, and drawn me out of my pit of confusion. I believe I can get there without wasting too much time.

 

Thnaks again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Just a comment about doing this "mostly" with hardware. 

 

1) If the 8-bit mode of the TCx provides the resolution you need for the Period of the PWM (then use the 8-bit mode and use the period register).

  a) CC0 can be used to generate the PWM signal on the port pin (CC0 and period registers control the waveform).

  b) CC1 can be used to trigger the start of an analog conversion (using the event system, it is not connected to a port pin). The CC1 compare value is set before just before the CC0 event (value) so you can control when to measure "under load" during the period.

  c) The ADC result interrupt is used to calculate the new values for CC0 and CC1. Save the values to consecutive SRAM memory locations.

  d) Use the TCx OVF to trigger the event system (TCx OVF is the generator and DMAx is the user) so the DMA will move the CCx values in SRAM to CCx registers.

 

2) If 8-mode is not enough resolution then use 16-bit mode. The catch is you will need to use two TCx peripherals that are synchronized. CC0 is used for the period (same in both timers) and then you use CC1 to perform the features as above.

 

This approach leads to use only one interrupt per period. 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's forcing the hardware in total submission, nice :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chris,

 

Thanks for this post.  This is the second one from you that has been incredibly helpful to me in a current SAMD09 project (the other as ADC related.)  Thanks again.  You're reducing headaches on my end.

 

-Chris

Chris Callahan

University of Vermont Extension

Agricultural Engineering

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All very good to produce such a big example, but it would have been even better if one could compile it without error. 

The first undefined symbol is 

MUX_PA04E_TC1_WO0

Back to the datasheet!

#include files are not mentioned

Jerry

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another comment on this code:

The variable test has an initial value of 0, in the while loop  the program tests for values 1 or 2, but the value is never changed in the rest of the program

Did the writer test the program at all?

Jerry

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another niggle:

The statement 

PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA09;

in  Systick_Handler() is wrong, the right hand side must be 1 << PORT_PA09.

There's a similar error in the main program where the port bit direction is set

The program can't have been tested before being posted

Jerry

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"the right hand side must be 1 << PORT_PA09" - I don't think so.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I beg to differ, see http://www.atmel.com/Images/Atmel-42242-SAM-D10_Datasheet.pdf#page=392

In the SAMD10D pin PA09 has pin number 9, so setting DIRSET to this value would make PA00 (which isn't on the chip) and PA02 outputs

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What toolchain/ASF version are you using? In anything that I have seen PORT_PA09 is defined as (1u << 9). For example:

grep -r PORT_PA09 * | grep samd10d
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d13am.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d13as.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d14am.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d14as.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ezharkov wrote:

What toolchain/ASF version are you using? In anything that I have seen PORT_PA09 is defined as (1u << 9). For example:

grep -r PORT_PA09 * | grep samd10d
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d13am.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d13as.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d14am.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */
CMSIS_Atmel/Device/ATMEL/samd10/include/pio/samd10d14as.h:#define PORT_PA09                  (1u <<  9) /**< \brief PORT Mask  for PA09 */

You're right, my mistake, I apologise. Perhaps I read PIN_PA09 (red face).

I also tested the program on a Sparkfun SAMD21 Dev breakout board, using pin PB03 for the yellow LED, which blinks. The include files are:

#include <samd21g18a.h>
#include <instance/adc.h>
#include <instance/eic.h>
#include <instance/eic.h>
#include <instance/pm.h>
#include <component/port.h>
#include <instance/port.h>
#include <pio/samd21g18a.h>
#include <component/tc.h>
#include <instance/tc3.h>

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think you need all those includes. I think one single #include should be enough.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Has anyone else looked at the source that was posted up in #3 above?  It isn't close to compiling for me; using AS7 it has 48 errors and 29 warnings.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, it needs an include file. For example, it seems to compile if I add "-include <my-path>samd10d14am.h" to the command line. What errors do you get?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Really that's all you needed?  I thought it was an ASF project, based on the "#include <asf.h>" it has.  But I only use the AS7 GUI not the command line. The first errors are things like "tc_enable()" etc. are undefined. You must be including paths for more than just a part specific header.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

#3 is not an ASF project. What asf.h? I don't see any asf.h in #3.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh man.... I must have mixed the example from #3 up with a different one was looking at, sorry.  After scanning for examples it seems that I've confused them - The SAMD21 is my real interest, and post #20 lead me here.  

 

However, posts #14, #15, #16 point out serious errors. Actually #15 says "test" is initialized to 0, but in fact it is never initialized. Maybe this is a bad example of code to look at...

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't looked closely at #3, but my general impression is that all cwunder's examples were very good. Changing it to SAMD21 shouldn't be difficult. Well, SAMD21 doesn't have TC1. So you would have to change it to, say, TC3. And then it should compile for SAMD21 too.