Author Topic: Question about Arduino ms implementation  (Read 2003 times)

0 Members and 1 Guest are viewing this topic.

Offline _Vlad_Topic starter

  • Newbie
  • Posts: 3
  • Country: ua
Question about Arduino ms implementation
« on: July 03, 2020, 09:49:43 am »
Hello boys and girls, geeks and weebs!

Small question:

So we have Arduino (UNO, NANO, don't care) with ATMEGA328p on board.
We have 16Mhz oscillator on board.

Arduino library uses TIMER0 in this case with prescale of 64 AND overflow interruption. TIMER0 is 8-bit timer..
and here my question is.. WHY? I don't get it. WHY OVERFLOW? Why not COMPARE mode?

So we have 16 000 000 / 64 = 250 000 ticks per second.

Please! I just cant understand why you don't want to set OCR to (250-1) and get compare interrupt every 250 ticks.. or 250 000/250 = 1000 interrupts per second. Which is called, you know, milliseconds. For a milliseconds counting. Or I apocalyptically missing something?


Instead it's implemented as clear overflow, so our timer generate interrupt when it get's over 255..
So it's actually counting slower and you get 1000 interrupts in actual 1024ms.

Code: [Select]
void init()
{
// this needs to be called before setup() or some functions won't
// work there
sei();

/***** some code for ATMEGA8 and other *****/

// set timer 0 prescale factor to 64
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
// this combination is for the standard 168/328/1280/2560
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);

// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
sbi(TIMSK0, TOIE0);
#else
#error Timer 0 overflow interrupt not set correctly
#endif

/***** other timer's initialization *****/

And they know it. So They get kinda "correction" in ISR:
Code: [Select]
ISR(TIMER0_OVF_vect)
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;

m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}

timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
}

So can somebody explain this to me? I just don't understand why you want to do this not in straight way? Thank you!
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8179
  • Country: fi
Re: Question about Arduino ms implementation
« Reply #1 on: July 03, 2020, 09:55:49 am »
There is absolutely no technical reason for about anything in Arduino. It's a total hobby project made within days by total noobs. (Nothing wrong in that, just stating this fact.) The reason for most design decision is, "just popped in mind".

Hence, it's mostly a waste of time to look at how Arduino implements things. It's for you to write some super simple projects with trivial requirements, utilizing existing shields and their libraries as widely as possible. It's literally designed for artists, not programmers nor electronic designers, professional or hobbyist. This is what the Arduino company themselves define their role as.

Once you start asking "why", it's time to just go forward. Then you can begin doing what you want and need.

Otherwise, it's like having lengthy discussions about the bearing grades of training wheels.
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3240
  • Country: gb
Re: Question about Arduino ms implementation
« Reply #2 on: July 03, 2020, 10:18:40 am »
The CCP modules on all three timers are used for the PWM outputs.
 
The following users thanked this post: _Vlad_

Offline Peabody

  • Super Contributor
  • ***
  • Posts: 2008
  • Country: us
Re: Question about Arduino ms implementation
« Reply #3 on: July 03, 2020, 01:43:07 pm »
Yes I think mikerj is right.  Rolling over allows them to use the compare registers for PWM.

But I agree that the method they chose can cause problems.  Periodically the millis value increases by two.  So if you're using millis for something like 7-segment multiplexing, you can get what appears to be flicker caused by variability in the segment ON time.

However, you're welcome to write your own millis ISR and do the compare at 249.  Here's my version:

Code: [Select]
/*
This is a replacement for the ISR(TIMER0_OVF_vect)
interrupt that drives millis(). It disables the OVF
interrupt, enables the COMPA interrupt, sets OCR0A to 249,
and changes Timer0 to CTC mode.  This results in an
interrupt every 250 timer clock cycles, which is exactly 1ms
for a 16MHz crystal, or 2ms for an 8MHz crystal.  The new ISR
increments millis, but since the interrupt rate is exactly
correct, no periodic double increment of millis is needed.

Using this code probably means you can't do any analog
writes that use Timer0, which would include pins 5 and 6.
*/

extern volatile unsigned long timer0_millis;   //these defined in wiring.c
extern volatile unsigned long timer0_overflow_count;

volatile unsigned long MILLIS_INCB = (64 * 250) / (F_CPU / 1000);  // ms between timer overflows

const int cycleTime = 500;                 // flash LED every second
int LEDcount = cycleTime;
unsigned long oldMillis = millis();
unsigned long newMillis = 0;

void setup() {                             //Set up alternate interrupt
                                           //   at 249 on timer0
                                           
  cli();                                   // disable interrupts while doing this

  TCCR0A = 0;                              // set entire TCCR0A register to 0
  TCCR0B = 0;                              // same for TCCR0B
  TCNT0  = 0;                              // initialize timer0 count to 0

  OCR0A = 249;                             // set top of counter
  TIMSK0 &= ~bit(TOIE0);                   // disable overflow interrupt
  TCCR0A |= bit(WGM01);                    // turn on CTC mode
  TCCR0B |= (bit(CS01)+bit(CS00));         // Set CS00&CS01 bits for prescaler = 64
  TIMSK0 |= bit(OCIE0A);                   // enable timer compare interrupt

  sei();                                   // enable interrupts

  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);

}


void loop() {                               // flashes LED for 1/2 second
                                            //    every second

  newMillis = millis();
  if ((newMillis - oldMillis) > 0) {
    oldMillis = newMillis;
    LEDcount -= 1;
    if (LEDcount == 0) {
      digitalWrite(13,!digitalRead(13));    // invert pin 13 state
      LEDcount = cycleTime;
    }   
  }
}


ISR(TIMER0_COMPA_vect) {                    // this is the new ISR - much
                                            //   simpler than original
 
  timer0_millis += MILLIS_INCB;
  timer0_overflow_count++;

}
 

Offline _Vlad_Topic starter

  • Newbie
  • Posts: 3
  • Country: ua
Re: Question about Arduino ms implementation
« Reply #4 on: July 03, 2020, 03:30:09 pm »
Thank you!

Yep, looks like it's really like mikerj said. Well at least it's sounds reasonable.

And at least I'm not missing something, so good to get a small fight to kinda Impostor syndrome :)

Thank you guys for response!
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4040
  • Country: nz
Re: Question about Arduino ms implementation
« Reply #5 on: July 04, 2020, 03:15:48 am »
Привіт Влад,

While I agree somewhat with what Siwastaja said I think a lot of people overlook that the Arduino people simply had different priorities to professional engineers. They emphasize getting the maximum functionality out of the chip for somewhat low performance (human timescale) applications rather than getting maximum performance -- and also to get an API which is reasonably implementable over a wide range of different microcontrollers.

In this case the trade-off of getting three PWM outputs and a little bit of jitter on the ms counter seems like a good one for most users, compared to having two PWM outputs and a "perfect" ms. They could also have chosen to leave the ms counter at slightly the wrong speed, but jitter-free, which also would have been fine for many uses. However I think, again, introducing a tiny bit of jitter in order to get good long-term timing accuracy (at least to the limits of the crystal) is also the right decision.

The same goes for all the "extra" work digitalWrite() does to map the virtual pin number to a physical port and pin, set up the pin mode etc. Yes, it limits the maximum frequency at which you can toggle a pin to (I don't remember exactly) a few hundred kHz instead of the several MHz you can get with low level code, but for the intended applications the intended user isn't going to need over (or anywhere near) 1 kHz anyway. When you need more, for example to do fast SPI transfers or drive WS2812 LED strips (which need *very* precise timing), you use a specialized library for that anyway.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8179
  • Country: fi
Re: Question about Arduino ms implementation
« Reply #6 on: July 04, 2020, 08:35:56 am »
There is absolutely no excuse for the digitalWrite() farce. You can speculate whether it's "good enough" "for the job" or not, but this is all meaningless, it doesn't need to be that way, there is no benefit for it to be that way, and it wouldn't have been any harder to do it properly. (Similarly, there would have been no extra work alingning the 0.1" pin headers to 0.1" grid so you could connect them to a breadboard.)

For a beginner artist not interested in low-level stuff, it would be much easier if such basic building block worked without exposing the user to said low level ("why the heck is this taking so long??") The entire conundrum just wouldn't exist, it would "just work".

They do run the entire code through their own preprocessor anyway - could have just made a simple implementation to replace digitalWrite(123) with PORTx = xyz; operation. Basically run the same digitalWrite() logic during the preprocessing. Heck, just auto-including the exact current digitalWrite() implementation defined as a static function to the project would likely make the compiler just optimize it away completely.

The fact they couldn't do that and ever fix this trivial thing shows perfectly how it was a "designed in a few days" project with absolutely zero interest in maintaining it or making it any better, just generate as much money with large-scale guerilla marketing as possible.

Note these are just the cold facts, not opinions about whether all this is "good" or "bad". On that matter, I think Arduino has done much more good than bad, especially being the "stepping stone" on way to start designing electronics and writing embedded software, hobby or professional. On the other hand, people who insist, no matter what, how Arduino somehow "must" be the way electronics and embedded systems are designed, despite that even the Arduino company itself understands it's just a stepping stone for non-programmers, non-electronic-designers, are severely hindering people who started with Arduino, from going forward.

Because when you really start hitting the limits, and that happens pretty soon, you are wasting colossal amount of time trying to figure out why every single Arduino feature is the way it is, and how to work around it. Looking at "how others do things" is educational, but it pays off to use a bit more professionally designed projects as references. There is not much design behind Arduino.
« Last Edit: July 04, 2020, 08:56:39 am by Siwastaja »
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3240
  • Country: gb
Re: Question about Arduino ms implementation
« Reply #7 on: July 04, 2020, 01:18:48 pm »
There is absolutely no excuse for the digitalWrite() farce. You can speculate whether it's "good enough" "for the job" or not, but this is all meaningless, it doesn't need to be that way, there is no benefit for it to be that way, and it wouldn't have been any harder to do it properly.

Sorry but there absolutely is a good excuse; enumerating a pin to a simple integer value simplifies things at a high level and that is ultimately the aim of the language.  If this gets in the way for your use then use plain C/C++ rather than the Arduino language.

Out of interest how would you do it "properly"?
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3025
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: Question about Arduino ms implementation
« Reply #8 on: July 04, 2020, 01:50:50 pm »
[Sorry but there absolutely is a good excuse; enumerating a pin to a simple integer value simplifies things at a high level and that is ultimately the aim of the language.  If this gets in the way for your use then use plain C/C++ rather than the Arduino language.

Out of interest how would you do it "properly"?

At compile time wherever possible, specifically, when the pin is a compile time constant

I did it that way in my ATTinyCore fork

https://github.com/sleemanj/ATTinyCore/blob/master/avr/cores/tiny/Arduino.h#L275

If the pin is compile time constant, then the work of figuring out what bit to set in what register is all done compile time.

NB: it is in practical terms almost always the case that the pin is constant, especially in arduino land.
~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 

Offline ledtester

  • Super Contributor
  • ***
  • Posts: 3036
  • Country: us
Re: Question about Arduino ms implementation
« Reply #9 on: July 04, 2020, 01:59:29 pm »
There is absolutely no excuse for the digitalWrite() farce.

There are alternate implementations of digitalRead/Write which generate optimal code, e.g.:

https://github.com/NicksonYap/digitalWriteFast
 

Offline langwadt

  • Super Contributor
  • ***
  • Posts: 4427
  • Country: dk
Re: Question about Arduino ms implementation
« Reply #10 on: July 04, 2020, 02:18:57 pm »
There is absolutely no excuse for the digitalWrite() farce. You can speculate whether it's "good enough" "for the job" or not, but this is all meaningless, it doesn't need to be that way, there is no benefit for it to be that way, and it wouldn't have been any harder to do it properly. (Similarly, there would have been no extra work alingning the 0.1" pin headers to 0.1" grid so you could connect them to a breadboard.)

the  misaligned pins were a mistake on first batch of boards, they can't really change it now since it would break
compatibility with all the shields done since then
 
The following users thanked this post: Siwastaja

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4040
  • Country: nz
Re: Question about Arduino ms implementation
« Reply #11 on: July 05, 2020, 12:05:39 am »
NB: it is in practical terms almost always the case that the pin is constant, especially in arduino land.

I strongly disagree with that.

While it is of course true that in any given hardware project configuration the pin assignments don't change, it is not true for the library writer. Most Arduino projects use libraries that provide things such as Object-Oriented interfaces to bit-banged facilities such as SPI, UART, WS2812 LEDs or whatever. The user instantiates objects with particular pin assignments which can vary from project to project, and there can even be more than one object in a given project. For the code inside the library the pin numbers are not at all literal constants.

An Object-Oriented interface is potentially better than a function interface in this regard because with functions the user has to pass the pin number on every call, which is necessarily inefficient (unless the function is so trivial it can be inlined). With an OO interface you can choose to have the constructor do a logical pin to port address + mask mapping (if ports are memory-mapped) and just use those in the other functions. But most library writers don't bother and just save the logical pin number. Which is absolutely fine in most cases.
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3025
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: Question about Arduino ms implementation
« Reply #12 on: July 05, 2020, 04:20:01 am »
NB: it is in practical terms almost always the case that the pin is constant, especially in arduino land.

I strongly disagree with that.

While it is of course true that in any given hardware project configuration the pin assignments don't change, it is not true for the library writer.

Fair point, but when ever hardware interface libraries (and libraries that use those libraries) are concerned that's of course moot, ie, the (typical) Wire library doesn't bit-bang with digitalWrite or otherwise, it uses the SPI I2C hardware.

Unfortunately, AFAIK, __builtin_constant_p is considered before Link-Time Optimization (LTO) happens so the constant-folding etc of LTO as the linked whole doesn't really help a lot. 

It is irksome that the Arduino ecosystem does not allow any way for the "sketch writer" to edit a header that can be included by libraries (ie, you can't have Configuration.h included by libraries).  The Arduino powers that be refuse to implement it.

But, it certainly is possible to write libraries such that they still deal with user specified compile time constants by using C++ templates, although it's unusual in the Arduino world to use templates.  However for example FastLED (WS2811 etc) is a notable exception with very very heavy reliance on templates internally.

This thread seems to have got derailed a bit, it was originally about millisecond counting!



~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8179
  • Country: fi
Re: Question about Arduino ms implementation
« Reply #13 on: July 05, 2020, 06:10:00 am »
Library writer does not need to use digitalWrite() because library writers are not artists with zero programming experience.

The artist, however, tries to bitbang an interface with digitalWrite() sooner than later. Now the artist is exposed to the low level because the solution is not working and the artist is wondering why. The only reason for digitalWrite()s existence was to avoid this.
« Last Edit: July 05, 2020, 06:11:48 am by Siwastaja »
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3025
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: Question about Arduino ms implementation
« Reply #14 on: July 05, 2020, 08:14:35 am »
Library writer does not need to use digitalWrite() because library writers are not artists with zero programming experience.

You make the assumption that the library is only intended to run on one specific architecture or that the library author should need to care about the specific vagaries of every archicture, indeed every chip within every architecture.

The Arduino collection of abstractions such as digitalWrite have been ported to many architectures.

digitalWrite (and co) were not brilliantly implemented abstractions, but the abstraction itself is good.
~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8179
  • Country: fi
Re: Question about Arduino ms implementation
« Reply #15 on: July 05, 2020, 08:22:04 am »
No, not making such assumption. I'm asserting library writers must be able to create a portable library for different platforms without having to use digitalWrite(), exactly this digitalWrite() and how it is implemented. They have options because they are not (or should not be) artists without any programming experience. This is what many libraries do exactly because of the crappiness of digitalWrite().

Heck, it's just the opposite, if the library does use digitalWrite() instead of rolling a better-working abstraction, they have literally limited the portability to the Arduino ecosystem only.

Claims that "abstraction itself is good" are meaningless and lead to poor abstractions for the sake of abstraction. Measuring the results directly, instead of the means, leads to better, eh, results. In this case, what you really want and are referring to, is "portability", which isn't very good with Arduino libraries, so digitalWrite() clearly isn't solving any portability problems.
« Last Edit: July 05, 2020, 08:26:15 am by Siwastaja »
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3240
  • Country: gb
Re: Question about Arduino ms implementation
« Reply #16 on: July 05, 2020, 08:58:01 am »
Heck, it's just the opposite, if the library does use digitalWrite() instead of rolling a better-working abstraction, they have literally limited the portability to the Arduino ecosystem only.

Do you consider Arduino as some kind of professional development system?  It was literally designed as a "my first microcontroller" for people that wanted to make interactive art projects who had little programming experience.  It includes a certain set of compromises to achieve that, if you don't like those compromises why are you using it when other alternative exist?
 
The following users thanked this post: Siwastaja, tooki

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4040
  • Country: nz
Re: Question about Arduino ms implementation
« Reply #17 on: July 05, 2020, 09:45:46 am »
Library writer does not need to use digitalWrite() because library writers are not artists with zero programming experience.

The artist, however, tries to bitbang an interface with digitalWrite() sooner than later. Now the artist is exposed to the low level because the solution is not working and the artist is wondering why. The only reason for digitalWrite()s existence was to avoid this.

The solution *does* work, in the vast majority of cases.

The readme for the digitalWriteFast library you pointed to says that theirs takes 0.125 us on an Uno (i.e. ATMega328 @16 MHz), while the standard library function takes 6.28 us.

Most users, doing the usual things of controlling LEDs or motors or steppers etc would not even notice the difference, let alone care about it. Most Arduino users aren't interested in doing things below the ms time grain level.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8179
  • Country: fi
Re: Question about Arduino ms implementation
« Reply #18 on: July 05, 2020, 10:06:11 am »
Heck, it's just the opposite, if the library does use digitalWrite() instead of rolling a better-working abstraction, they have literally limited the portability to the Arduino ecosystem only.

Do you consider Arduino as some kind of professional development system?  It was literally designed as a "my first microcontroller" for people that wanted to make interactive art projects who had little programming experience.  It includes a certain set of compromises to achieve that, if you don't like those compromises why are you using it when other alternative exist?

Ex-act-ly!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf