SAMD20 Timer setup using START

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

Now that the PORTS have been pretty much figured out, time to get on the timers.  After reading about the timers in the datasheet I elected to modify my test project and add a timer to create an interrupt (or is that an EVENT, or a CALLBACK?) to increment a variable.  In AVRland this is a no brainer.  HEre, not so much

 

I fired up start and added a Timer Driver and it was names Timer_0.  Thing is, START does not offer the ability to configure up all the options that I read in the datasheet like MODE for example.

 

Here is what I see when I open the driver and enable the event:

 

Nothing about MODE selection, or any of the other features I read about in the datasheet.  I elect to update the project and back to Studio I go.  Now what?

 

I decide to do a debug session and see what was configured and it looks like it loaded the defaults, but it did not enable the counter.  How do I do that?  I am guessing I do a bit set and I will try that later.

 

What if I wanted to have an 8 bit counter? or 32bit?  Can I do that in Start?

 

But what about the 'interrupt', 'callback', or 'event'?  Which is it I wonder.  And how do I implement it?

 

I guess my long winded lead in is mostly about the interrupt....how to implement?  I am hoping to avoid ASF

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

Look at the code in examples/driver_examples.c. Should cover the timer needs but you would use other drivers for e.g. pwm.

/Lars

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

I will check that. Thanks

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

Click the "Enable" box next to advanced configurations and you will be presented with more options to configure.

murph

Debugging - Being a detective in a crime movie where you are also the murderer.

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

Ok, so I am still struggling with this timer.

As murph suggested I enabled the Advanced config and there was nothing in there for Interrupt enable or config, but I left it anyway.

 

I looked in the examples folder and then the driver_examples.h and driver_examples.c, and did not see anything jump out at me with regards to interrupts there either.

 

Are the 'events' interrupts in start?

 

So, I went and created an ASF project and in there I was able to add an interrupt driver.  I was given a choice between polled or callback...I picked callback(I looked up callback and from the description I think this was the wrong choice)  anyway in the ASF project I found .h files with interrupt functions but they don't seem to explain their use in a format my simple mind can process.

 

So, here is what I am trying to do.

 

Set up a Timer to cause an interrupt every 500 milliseconds

in the timer Interrupt service routine increment a variable

in the main loop display the value of the variable on a port >>This I know how to do<<

 

Seems simple enough, but not so simple.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
static struct timer_task TIMER_0_task1, TIMER_0_task2;

/**
 * Example of using TIMER_0.
 */
static void TIMER_0_task1_cb(const struct timer_task *const timer_task)
{
}

static void TIMER_0_task2_cb(const struct timer_task *const timer_task)
{
}

void TIMER_0_example(void)
{
	TIMER_0_task1.interval = 100;
	TIMER_0_task1.cb       = TIMER_0_task1_cb;
	TIMER_0_task1.mode     = TIMER_TASK_REPEAT;
	TIMER_0_task2.interval = 200;
	TIMER_0_task2.cb       = TIMER_0_task2_cb;
	TIMER_0_task2.mode     = TIMER_TASK_REPEAT;

	timer_add_task(&TIMER_0, &TIMER_0_task1);
	timer_add_task(&TIMER_0, &TIMER_0_task2);
	timer_start(&TIMER_0);
}

Is what I get in driver_examples.c, seems to be exactly what you need. If you really wish to manage the interrupt and all details in your code then don't use Atmel Start or ASF 3 (where the callback version will be similar, i.e., you provide a function that will be called from a interrupt handler that is part of the driver).

/Lars

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

^ As Lajon has supplied. That code above has everything you need.. There will be some code generated in the driver_init.c/.h files for the new TIMER_0 instance, but you shouldn't have to touch that. Just set the interval and mode desired and add your code within the cb function.

murph

Debugging - Being a detective in a crime movie where you are also the murderer.

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

murph wrote:
As Lajon has supplied. That code above has everything you need.

And I am having some trouble understanding how this works as I come from the AVR world

 

murph wrote:
Just set the interval and mode desired and add your code within the cb function.

THe callback is the issue.  I do not understand how this works:

static void TIMER_0_task1_cb(const struct timer_task *const timer_task)
{
}

static void TIMER_0_task2_cb(const struct timer_task *const timer_task)
{
}

 

JIm

 

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

The callback is effectively like an ISR. Under the hood is the actual isr that does some housekeeping and calls the callback function.

Add your code to blink an led every 10 ticks or whatever.

If you want a system tick of 10ms or whatever, use the systick functions. The ARM has a dedicated timer (called systick) for this.

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

jgmdesign wrote:

THe callback is the issue.  I do not understand how this works:

JIm

 

 

^As Kartman has stated, it should be treated as an ISR... In regards to the CB functions, you can ignore the parameters passed in (const struct timer_task *const timer_task).. Although I believe you still need to put them in the definition, you don't actually have to use them.

 

So usage is as follows.. 

 

Step 1: Ensure you define a timer config struct of the "timer_task" type:

static struct timer_task myTimer_task;

 

Step 2: Create a function to be called periodically - aka your Callback function (cb) - Ensuring to put the parameters in the definition.. Even if you don't use them

static void myPeriodicFunction(const struct timer_task *const timer_task)
{
    // Put your code here that you want to execute at the specified interval
    // Toggle an LED
    // Send data out a UART
    // etc..
    // Whatever you want :)
}

 

Step 3: Setup your timer - Setting the interval, mode, and providing the CB function (This is a function pointer which allows the timer module, when elapsed, to call your function)

 

NOTE: That the .cb parameter is set to the function you want to be called periodically (myPeriodicFunction)

void timerSetup(void)
{
	myTimer_task.interval = 100;
	myTimer_task.cb       = myPeriodicFunction;
	myTimer_task.mode     = TIMER_TASK_REPEAT;

	timer_add_task(&TIMER_0, &myTimer_task);
	timer_start(&TIMER_0);
}

 

 

Once you call timer_start, your function (myPeriodicFunction), should now be executing every 100ms..

 

Hope this clears things up! - I think the key answer to your question is that the CB function, is whatever you want it to be, and then it is provided as a function pointer to the timer module, so it knows what to call when the timer elapses (Just like an ISR executes when an interrupt occurs)..

 

 

// As I think about it more.. I can see the timer_task parameter that is put into the CB parameter being very useful. I THINK you could create a couple different timer_task configs (Different intervals, or modes I suppose), and have them ALL call the same CB function.. And then using the parameter passed in when the CB executes, you could tell which config caused it to trip (i.e. did the CB occur because of my 100ms timeout, or my 600ms timeout), and then have your CB function act accordingly..

murph

Debugging - Being a detective in a crime movie where you are also the murderer.

Last Edited: Mon. Mar 25, 2019 - 02:12 PM