Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
gankoji
PostPosted: Jul 14, 2012 - 08:18 AM
Rookie


Joined: Jun 30, 2011
Posts: 46
Location: La Habra, CA

Hey Kartman,

Obviously, this post is old so my thanks on your wonderful tutorial are a bit behind the times, but I figured I'd put them here anyways. I've not yet had time to read (and digest) Dean's timer tutorial fully, so the values you use to setup the timer interrupt are kind of a mystery. Perhaps you might consider commenting those, or lines like it, in future tutorials for the slowpokes in the pack like me Smile.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Jul 14, 2012 - 11:14 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62230
Location: (using avr-gcc in) Finchingfield, Essex, England

Code:
 TCCR0B = 0x00; //stop
 TCNT0 = 0x00; //set count
 TCCR0A = 0x02;   //CTC mode
 OCR0A = 0x9C;
 TCCR0B = 0x05; //start timer

Are the comments not enough then? That's almost as simple a timer setup as you can get and the key comment is "// CTC mode". A quick look at any AVR datasheet will show you that is the mode where the timer counts up to the value in a compare register (OCR0A in this case) and then resets to 0 (possibly generating an interrupt as it does so). So this timer is going to count 0x00, 0x01, 0x02... 0x93, 0x94, 0x95 (interrupt), 0x00, 0x01, 0x02..

As the count of 0x00 is included in that it's really counting 150 (0x95+1) timer "ticks" between overflows.

Also the "// start timer" comment shows 0b101 being loaded in to the B register. That is going to be /1024 so the timer will be running at 1/1024th of the CPU speed. It will therefore count 150*1024 = 153,600 CPU cycles between compare match interrupts. The comment at the top of the code say 16MHz so it executes 16,000,000 in 1 second therefore the interrupts will be 153600/16000000 apart that is 0.96ms - so close to 1ms.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
gankoji
PostPosted: Jul 15, 2012 - 05:19 PM
Rookie


Joined: Jun 30, 2011
Posts: 46
Location: La Habra, CA

After finally getting through the Timers document in this forum they all make perfect sense. I think the names of the registers and such were more confusing than anything, but I see now that the comments are appropriate if you reference any AVR datasheet you have handy.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
shahriar_pollob
PostPosted: Jul 21, 2012 - 10:21 PM
Rookie


Joined: Jul 01, 2012
Posts: 23


Hi, Kartman, this is an awesome tutorial! Many many thanks!

I have two questions.
1) I noticed this portion of code:
Code:
while (task <= NUM_TASKS )
    {
     if ((task_bits & pgm_read_byte(&bit_mask[task])))
           {
           break; /* if activate task found..*/
         }
      task++;         /* else try the next one */
    }

Shouldn't it be "<" in stead of "<="? Because, after task=7 and task++, it'll be task=8 and program will enter the loop and try to find bit_mask[8], but bit_mask is only 0:7.

2) When you're writing "set_task(6)", it's only writing 64 to task_bits, right? The "task6()" function will actually start (I mean, the timer for task 6 and its LED blinking) in the "task_dispatch()" function, right? The reason I'm asking this is this portion of code:
Code:
set_task(7);   //task7 runs
set_task(6);   //task6 runs

What I've understood is happening here is "task_bits" is assigned 128 first, then without actually starting "task7()" (I mean, the timer for task 7 and its LED blinking), "task_bits" is assigned 64. And then the main loop starts and "task_dispatch()" is called which starts "task6()". And I didn't find "task_bits" being assigned 128 afterwards which would start "task7()" in ""task_dispatch()".

It's probably my mistake in understanding. But I'll appreciate your or anyone else's help very much in helping me with this.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Jul 22, 2012 - 07:06 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18531
Location: Lund, Sweden

Quote:

Shouldn't it be "<" in stead of "<="?

If you read/search through the whole thread you will find that there has been two such remarks prior to yours. (And unless I am missing something, you are correct.)

Quote:

What I've understood is happening here is "task_bits" is assigned 128 first, then without actually starting "task7()" (I mean, the timer for task 7 and its LED blinking), "task_bits" is assigned 64.

No. The set_task function uses the |= operator, not the = operator. Thus, first call ( set_task(7) ) sets bit 7 (the task_bits gets the value 128), Next call ( set_task(6) ) sets bit 6 without setting or clearing any other bits, so now the task_bits has the value 192.

If you are unfamiliar with bit manipulating operators then there is an excellent tutorial here at AVRfreaks. Mandatory read.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
shahriar_pollob
PostPosted: Jul 22, 2012 - 07:46 AM
Rookie


Joined: Jul 01, 2012
Posts: 23


Thanks, Johan!! I've read the bit manipulation tutorial recently, and haven't got very used to it. So, I misunderstood that part. Thanks for clearing it up!
 
 View user's profile Send private message  
Reply with quote Back to top
larryvc
PostPosted: Jul 22, 2012 - 09:08 AM
Raving lunatic


Joined: Dec 06, 2007
Posts: 2512
Location: Redmond, WA USA

JohanEkdahl wrote:
Quote:

Shouldn't it be "<" in stead of "<="?

If you read/search through the whole thread you will find that there has been two such remarks prior to yours. (And unless I am missing something, you are correct.)

I agree, although Kartman's response to the first remark was:
Kartman wrote:
Why? What benefit would the change make?

_________________
Larry

Those afraid to embrace the future will quickly fade into the past. - larryvc
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Jul 23, 2012 - 02:11 PM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8733
Location: Melbourne,Australia

That portion of code is not ideal, but the later switch() relies on the value 8 being 'no task'. Therefore even though i go over the end of the bit_mask table, nothing comes of it. In retrospect i should've coded things clearer. Pascal would've given a runtime error! The challenge is to rewrite that section of code so it doesn't overflow the table and doesn't rely on a side-effect. The change is not simply using < as opposed to <=
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Jul 24, 2012 - 05:38 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8733
Location: Melbourne,Australia

This method saves some bytes as well as avoiding the abovementioned problems.
Code:
if (task_bits & 0x01)
   {
   task0();
   }
  else if (task_bits & 0x02)
   {
   task1();
   }
  else if (task_bits & 0x04)
   {
   task2();
   }
  else if (task_bits & 0x08)
   {
   task3();
   }
  else if (task_bits & 0x10)
   {
   task4();
   }
  else if(task_bits & 0x20)
   {
   task5();
   }
  else if (task_bits & 0x40)
   {
   task6();
   }
  else if(task_bits & 0x80)
   {
   task7();
   }



No one seemed to answer my question:

Quote:
I agree, although Kartman's response to the first remark was:

Kartman wrote:
Why? What benefit would the change make?

The answer I was looking for was, well, it would break the code as I described in my previous post.
 
 View user's profile Send private message  
Reply with quote Back to top
larryvc
PostPosted: Jul 24, 2012 - 08:02 AM
Raving lunatic


Joined: Dec 06, 2007
Posts: 2512
Location: Redmond, WA USA

I saw your previous post last night but was too tired to reply. Good explanation. I also like the very simple fix above.

Thanks Kartman.

_________________
Larry

Those afraid to embrace the future will quickly fade into the past. - larryvc
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Jul 24, 2012 - 08:41 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8733
Location: Melbourne,Australia

Cheers Larry. That code had remained unchanged for 15 years or so. My new attempt just felt 'clunky' as there was no looping but it does seem to be much simpler and more obvious. I was modifying some code at the office today and thought I'd try it. Imagecraft reported around 20 bytes less code for the new method and one less byte of ram. So win-win. I wasn't motivated enough to measure the execution time, but I'd expect it is probably a few cycles less worst case especially since the compiler should be able to cache the task_bits variable in a register. I have had part two written for the past two years but never got around to proof reading it to make it suitable for publication. Not enough time since children and home construction projects eat up my time.
 
 View user's profile Send private message  
Reply with quote Back to top
RedDuck
PostPosted: Aug 22, 2012 - 09:01 PM
Newbie


Joined: Aug 22, 2012
Posts: 1


Hi Kartman,

First of all, thanks for the inspiring code.

If I understand your code correctly, when two task timers run to zero at the same time, only the task with the lowest number will be executed in the current time slice. The other task will be executed 10 ms later. This would also imply that the task timer of this second task will be re-initialized 10 ms later. It will never make up for the lost time will it? So basically only task0 would be really deterministic...

By the way, same here with kids and construction,
Cheers.
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Aug 23, 2012 - 04:11 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8733
Location: Melbourne,Australia

RedDuck, you understand correctly. In many cases hard real time is not necessary. If you're just controlling relays and a lcd, such anomalies are not apparent or cause a problem. Obviously, if you really needed hard timing, then you would have that done via an interrupt or hardware (timer etc).
 
 View user's profile Send private message  
Reply with quote Back to top
powermcu
PostPosted: Aug 26, 2012 - 02:41 PM
Newbie


Joined: Jan 30, 2011
Posts: 1


thanks, is part 2 completed?
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Aug 27, 2012 - 04:51 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8733
Location: Melbourne,Australia

Can you find it?... No. Maybe soon.
 
 View user's profile Send private message  
Reply with quote Back to top
jsundownr
PostPosted: Sep 28, 2012 - 05:54 PM
Hangaround


Joined: Jul 13, 2008
Posts: 146
Location: Roswell, New Mexico - US

Kartman

Informative tutorial... thanks.

sundownr
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
ereihani
PostPosted: Nov 04, 2012 - 06:11 AM
Wannabe


Joined: Mar 07, 2005
Posts: 77
Location: Mashhad, Iran

Thanks a lot Kartman. You made my work very easy and
I learned other things aside from multitasking.
Please find a free time to complete second part. Many of us are waiting.
 
 View user's profile Send private message  
Reply with quote Back to top
perlon
PostPosted: Nov 14, 2012 - 11:37 AM
Newbie


Joined: Mar 04, 2008
Posts: 1


instead of
Code:
pgm_read_byte(&bit_mask[task])

can and it's just a simple
Code:
(1<<task)
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Nov 14, 2012 - 11:55 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62230
Location: (using avr-gcc in) Finchingfield, Essex, England

Yeah that'd work but one would have to study the generated Asm to see which is more space/time efficient.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Nov 15, 2012 - 05:21 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8733
Location: Melbourne,Australia

There's little doubt that (1<<task) is probably more obvious. As for efficiency, I agree with Cliff. Nevertheless, the net result is not going to be much of an efficiency gain methinks.
The source of that code goes back to the early days of an IAR 8051 compiler where I would look carefully at the generated code to coax the compiler into doing its best. If I was doing a code review and came across this, the questions I would ask:
1. does it work? No potential side effects?
2. is the intention reasonably obvious?
3. what would be gained by changing it?
4. Is the use consistant?
5. Is it MISRA compliant?

Granted it's a lot more verbose, but again, the pgm_read_byte() is a avr-gcc - ism. given another compiler, it would probably read a lot simpler. Does less source == less object?? (that was a rhetorical question). Less chance for typing errors though!
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits