Julian Investigates: How Slow is Arduino?

Поделиться
HTML-код
  • Опубликовано: 26 окт 2024
  • НаукаНаука

Комментарии • 320

  • @deangreenhough3479
    @deangreenhough3479 9 лет назад +2

    Interesting, thoughtful and intelligently explained. You have a gift Julian, once again you just make it sound so easy to understand

  • @das250250
    @das250250 8 лет назад +51

    Julian - As always a very well explained video . You are the master of complexity made simple : a great teacher.

    • @JulianIlett
      @JulianIlett  8 лет назад +12

      +graham kaveman Many thanks Graham. Much appreciated.

    • @seanocansey2956
      @seanocansey2956 6 лет назад

      The Kaveman so true

  • @AlexBlate
    @AlexBlate 9 лет назад +11

    And to the many folks who have suggested that Julian take up AVR assembly programming... I would remind you of two important principles. The first, paraphrasing the great Don Knuth, is, "a cardinal sin in computer science is premature optimization." Put simply, focus on getting your code and algorithms correct and then address performance issues as needed. The second is Amdhal's Law, which basically says that you should focus optimizations on code that is both slow and which takes up a significant percent of processing time. Julian followed both of these rules -- he wrote a correct program, assessed its performance, and then optimized the bits that were causing performance issues. Granted, this is a very simple example. But, unless one just really enjoys coding in assembly, one is best advised to avoid it except in the (generally) rare circumstances where it's appropriate to insert it. And, at that, one should examine the machine code generated by the compiler *first* before claiming that the compiler didn't/doesn't do a good job or that it can be done substantively better by hand and that the cost of doing so in terms of readability, portability, and time invested is really worth it.
    And, for the record, yes, the Arduino libraries do introduce overheads, sometimes very large ones. So, if timing or performance is critical, bypassing them, which is generally quite easy to do without abandoning the Arduino IDE, is certainly the right thing to do... or, perhaps, write better ones and contribute them back to the community. :)

  • @GeeTheBuilder
    @GeeTheBuilder 8 лет назад +1

    Love this video. Ever since school I've wanted a reason to buy an oscilloscope- now I gave one!
    Seriously, another great and well explained video. I learnt a lot!

  • @jeffbeck6501
    @jeffbeck6501 9 лет назад

    This video gets better and better every time I watch it. Jam packed with amazing info. Thank you Jullian.

  • @stephencripps9643
    @stephencripps9643 5 лет назад

    Excellent stuff, extremely well explained and also showed why we should be cautious about what we see on a scope.

  • @mikeydk
    @mikeydk 9 лет назад +78

    Could be interesting to se to see how fast
    while(true)
    {
    PORTB = B001000000;
    PORTB = B000000000;
    }
    is, compared to loop(), the "while" should remove the arduino housekeeping on every loop()

    • @RWoody1995
      @RWoody1995 9 лет назад +6

      K5HJ wouldn't that just continually set PINB to 1 so it would just stay high?

    • @RWoody1995
      @RWoody1995 9 лет назад

      K5HJ ah gotcha, forgot about those, been using them a lot while programming xmega chips and for some reason assumed the older mega chips didnt have the same functionality and could only directly write to the pins hehe... >

    • @AnsyCrofts
      @AnsyCrofts 9 лет назад +3

      K5HJ Good Grief! Never used that!!!
      When I've finished Windows 10 upgrade, I'll give it a shot! Time to re-read the datasheet. Knew Xmegas had it, but...

    • @seanocansey2956
      @seanocansey2956 6 лет назад

      K5HJ that is very cool actually

    • @JensRoland
      @JensRoland 6 лет назад +5

      Of course, you could unroll the loop and just insert a hundred identical lines of:
      PINB = B00100000;
      PINB = B00100000;
      PINB = B00100000;
      PINB = B00100000;
      ...
      That would be much faster 99% of the time, limiting the loop overhead to just one ‘sputtering’ every 100 instructions. It’s a hack, but it would show more clearly how many times Arduino can actually switch a pin on and off in a microsecond.

  • @flyingbrick88
    @flyingbrick88 7 лет назад

    I'm a very novice arduino user- You are a brilliant teacher. This should have been way over my head but you made it quite understandable.
    My mind boggles at how you know what you are talking about!

  • @DrenImeraj
    @DrenImeraj 9 лет назад +19

    The Global Interrupt Enable is bit 7 of the Status Register (SREG)

    • @JulianIlett
      @JulianIlett  9 лет назад +5

      Dren Imeraj Ah, too simple! I missed the obvious. Thanks Dren.

    • @DrenImeraj
      @DrenImeraj 9 лет назад +1

      Julian Ilett No problem. Great video, as usual. Please keep them comin!

    • @superdau
      @superdau 9 лет назад +6

      Julian Ilett
      Or ignore the bit and just call "noInterrupts()". Yeah, it's that obvious ;) . And you get them back with "interrupts()". "cli()" and "sei()" do the same but might not be that obvious if you don't know AVR assembler.

    • @alexholguin4825
      @alexholguin4825 8 лет назад

      Dren Imeraj black movies play Wet Willie

  • @DasIllu
    @DasIllu 9 лет назад

    As always i learn something from your videos. It's never wasted time. Thank you

  • @AxelWerner
    @AxelWerner 8 лет назад +7

    btw: there is a "arduino function" to disable interrupts. i think its " nointerrupts() " . you should also try using bitwise or and bitwise and operations to set and delete bits on a register. dont know it its faster, but it clearly does not overwrite or clear any other bits in the register. Also if you want to be in total controll or timing and things to happen, it might be a good idea to NOT USE the "loop()" routine, but making your own "while" loop. that is, because if you disabled interrupts in your own while loop there will be nothing else but what you wrote yourself. with the "loop()" loop its more likely that this is "NOT" a real loop, there are things happening before and after one "loop()" run. things that are not interrupt driven, but may interfere with your expected timing.

    • @AxelWerner
      @AxelWerner 8 лет назад +13

      +Julian Ilett , i did some more research and testing. i was able to bring it up to 2.6MHz. see my results and screenshots here: bit.ly/1P00hKn

  • @jakesoft
    @jakesoft 8 лет назад +1

    Wow, I've been using Arduino for years and had no idea I was incurring this kind of overhead. I guess I've been lucky that it hasn't mattered for any my projects yet, but it's good to know. Thanks for sharing!

  • @nunyabiznez4408
    @nunyabiznez4408 9 лет назад

    Very insightful. Thanks for answering these questions, I wish more folks would do the same.

  • @rupertrooksby
    @rupertrooksby 9 лет назад

    I have only just begun playing about with Arduinos this month (pretty much due to your videos - you are responsible for the postman visiting almost everyday this week with a new little free-shipping treat).
    But the first thing I did after Blink was throw the Arduino IDE and its libraries overboard. I understand the beginner-friendly broad-appeal thing they were going for, and it probably works for that, but as your video clearly shows, too much is happening behind the curtain. For me anyway, I think a lot of the fun of mucking about with this whole embedded caper is to be right down there, and just that little bit closer to the silicon. You can't do that with Arduino libraries slowly moving the scenery behind your back.
    So for me that means using something like SublimeText, makefiles, and writing code just based directly off the Atmel datasheet and lots of google. Very happy with that setup. Fast and direct. There's a steeper learning curve for sure, but that's more than half the fun.

  • @clearwavepro100
    @clearwavepro100 8 лет назад

    Thank you for creating and sharing this! My favorite part about(of) this video, is the awesomely good perspective to have(applicable to anyone, really) that doesn't point a finger at anyone, just points a finger to the answer!!!! Perfect, thank you. :)

  • @s4rg380
    @s4rg380 5 лет назад

    For what it is, and what it costs, it is still an impressive little piece of hardware. Thanks for the insightful video,

  • @Derek_Read
    @Derek_Read 6 лет назад

    Thanks for bringing this to my attention. I can't see the need for it at the moment given the projects I'm playing around with, but it is good to be aware of these kinds of things in case I run into something very time-sensitive in future.
    That would probably have to be a very specific requirement though, as I very much appreciate ability to write once and compile for different systems, plus the readability of most Arduino commands, and the fact that I don't have to worry about taking all port values into account when using PORTB/C/D.

  • @sbern42
    @sbern42 9 лет назад +6

    It should most definitely be a crystal. They get smaller than that. :)
    Also, if you set your scope probes to 10x (and tell your scope that's what they're set at) it should show a better square shape. 1x mode usually lowpass filters the input at around 8MHz or so.
    And if you put a while(1) { } inside the loop() around the PORTB:s, it should reduce the overhead a little bit more in the jump back to the start again.

  • @dkean4
    @dkean4 8 лет назад +1

    Good Digital Design insights. Excellent presentation, Julian.

  • @ribb4200
    @ribb4200 6 лет назад

    Yes, the C compiler leaves a lot of guesswork for bit-banging. Look at the machine code, then write in machine code, or simply do it in assembly language which can be done on Arduino if you can find an assembler. Microchip was more my style since that is native assembly language. At first and still, I was disappointed with Arduino, trying to figure out what it was doing and immediately started on a difficult path looking for an Arduino assembler to make the Arduino do what I wanted it to do. Not much luck, except that assembly language with Arduino is possible or fast machine code can be inserted into the compiler for critical fast timing.
    Thank you Julian for scoping the Arduino and showing the C compiler confusion trying to make the Arduino do what you wanted to do and what you know is possible.

  • @MrTopfpflanze1
    @MrTopfpflanze1 8 лет назад +1

    I really love your idea of trying to get the most out of these microcontrollers, and the video is really nice to watch.
    I'm not sure if it works for this specific chip, but the avr libs include the functions "cli()" (clear interrupt) and "sei()" (set interrupt), which disable or enable all kinds of interrupts (timers, external, etc), I don't think it wouod change anything though as you disabled the timer0 interrupt already.
    Also I think digitalWrite and digitalRead are slower because to my knowledge function calls (depending on the used calling convention) just happen to be slow (pushing parameters, creating stack frame, jumping to function, jumping back etc). I could imagine though that these time critical functions are inlined and I don't know if function calls are the same on microcontrollers, I have way more experience on Intel/AMD CPUs in regular home computers.
    Keep up your work!

  • @mirkomueller3412
    @mirkomueller3412 9 лет назад

    How amazing - will probably come in handy with my next project. Great Job !

  • @mortensentim511
    @mortensentim511 9 лет назад

    I did exactly this experiment before Christmas for a project I'm working on. Port masking and manipulation are more confusing to deal with, but the overhead of DigitalWrite is huge. Nice catch with the interrupts, I didn't think about that.
    After that was sorted the ADC became the bottleneck, it's a shame the Arduino has such a slow ADC compared to say a Nucleo board.

  • @kitecraft
    @kitecraft 6 лет назад

    That was a really neat experiment. Thanks for sharing it.

  • @tobortine
    @tobortine 9 лет назад +13

    Some one has already suggested this but I will repeat it. If you're going to do these type of experiments then use assembler. The Arduino IDE is designed to make development easy but in so doing it introduces masses of overhead. Even the loop in the code is generating many, many instructions. The IDE abstraction prevents you from getting accurate results at the level you're measuring.

    • @superdau
      @superdau 9 лет назад +19

      tobortine
      That's why he wrote "How slow is Arduino?" and not "how slow is an atmega?". It wouldn't be Arduino if you are programming in assembler.

    • @tmmtmm
      @tmmtmm 9 лет назад +1

      superdau but then i guess then it is "how slow are arduino functions" and not "how slow is arduino" since arduino doesn't limit you to using the provided libraries.

    • @tobortine
      @tobortine 9 лет назад

      superdau
      Ardiuino = Atmel processor + Peripherals + IDE
      The peripherals are only used to load the code so the IDE (libraries, macros, etc) are what slow down the native chip. If you're making a video about how slow an Arduino can be then showing the relative speed of the native chip with efficient code illustrates the point.

    • @RWoody1995
      @RWoody1995 9 лет назад

      tobortine i don't think so to be honest, i think if you are comparing arduino code to something you should compare it to C because C is the language someone looking to transition away from arduino is most likely to be moving to.
      you dont compare a sports car to a race car when your audience really want a supercar do you? :P

    • @AlexBlate
      @AlexBlate 9 лет назад

      megaspeed2v2 At last check, the Arduino development environment already uses C++... some code does actually use the object-oriented features in C++, but most doesn't or cleverly hides it from you; so, without starting a religious war about C vs. C++, Arduino programmers are already programming in C. The point, though, is that you *can* develop high-performance applications while retaining some of the Arduino IDE and toolchain's benefits; you just have to RTFM a little more. The nice thing is that you can decide how much deep magic you wish to explore and are not thrust headlong into a raw microcontroller development environment with all of the attendant arcane goo that's required just to get a simple program working.

  • @Chiller3k
    @Chiller3k 9 лет назад +1

    If you don't want to go through the trouble of using port manipulation, there is a great library called "Fast digital I/O for Arduino" from Jan Dolinay which is way more convenient but still gives you a considerably faster code execution

  • @JerryEricsson
    @JerryEricsson 9 лет назад

    Nice to see a fellow can still get to the raw insides of one of these little gems. Shades of the old C=64 machine language programmer that came with RUN magazine or one of those Commodore magazines, perhaps it was Commodore?

  • @tubical71
    @tubical71 9 лет назад +1

    Thanx Julian!!!
    This is very commen on high-level coding, as it is more easy for beginners to get something going, it creates also a lot of overhead in the final code. Best example here is BASIC. As it is an interpreter language and it also creates lots and lots of code to be executed, when you use a compiler BASIC.
    But you can always do some "inline-assember" for quick execution, but it you do so you have to deal with all this "unwanted" side-effects witch made assembler coding more difficult....
    Speed or simplicity YOU have to choose.....and as always, it all depends on YOUR very own needs;)
    Julian, you may take a look at the final output ASM-code to be executed by the AtM168 when using the arduino envoirement. As it clearly shows the overhead created by the arduino IDE....;)

  • @TKomoski
    @TKomoski 9 лет назад +13

    Morning Julian - If you really want to push the speed limit try Assembly Language. The native code that all micro's normally use. What Arduino does is disassemble your code into assembly language so that the micro can execute it. Assembly is quite lengthy and cryptic, understanding the Instruction Set is the key. I would suggest using Atmel Studio 6.X because you have the benefit of a full fledged programmer. If you don't want to use assembly try using C+ because it is the closest thing to it. I'm sure that you are aware of this and your channel is geared toward the beginers side. Since Atmel Studio is FREE for Windows users I never use Arduino to code any more. Sure the learning curve for steep, but there is ton's of info online to get you started. Code you write in Arduino is the same as in Atmel Studio, but the major difference is that you're not restricted to one language. Thanks for all the great video's, Cheers ;-)

    • @originalmianos
      @originalmianos 9 лет назад +8

      T Komoski C is closer the machine than c++. Yep, good idea to try Atmel Studio of you don't mind the 2G download but the problem here is the overhead in the 'arduino' libraries and chip setup, and that's how the majority of people here are going to be using the boards.
      Also, I use gcc with my own waf 'makefiles'. You can use -S with to output the actually assembly language generated. If you do that in this case you will see there are surprisingly few instructions emitted for this code. The problem here is all in the 'arduino' framework.

    • @RogerKeulen
      @RogerKeulen 7 лет назад +3

      Thanx for the advice... I'm downloading it now !
      I hate these higher languages for simple devices. Now i can use my old C64 tricks to optimize for speed but also important SIZE ! (speeds doesn't cost money, memory size does)

    • @FawfulDied
      @FawfulDied 7 лет назад +2

      Under GCC, identical C and C++ code produces identical output. C++ classes and C++ iterators are zero-cost abstractions (compared to the same thing in C).
      avr-gcc is pretty smart; it is able to turn PORTB |= (1

  • @Jadinandrews
    @Jadinandrews 9 лет назад

    Great video, I see a lot of people saying you should have used assembly, but then you wouldn't really be assessing the performance of an 'Arduino'. I'd rather switch to a more powerful micro if performance was that big a deal before learning assembly. That said, it would be real interesting to see how far the atmega 328 can be pushed with assembly.

  • @jwcolby54
    @jwcolby54 5 лет назад

    Two things. C++ is closer to the metal but it is not assembler.
    1) Each line of code will be 1 to n lines of assembler.
    2) any function call in c++ pushes values onto the stack and the return pops those values off the stack... Or potentially anyway. Pushes and pops are moving registers to / from memory and take time.
    3) use an xor to flip the bit. That should leave the other bits of the register alone.

  • @k0ppit
    @k0ppit 9 лет назад

    +Julian Ilett A trick to toggle an output pin is to write 1 to that pins "Input Pins Register". Use "cli()" end "sei()" to disable/enable global interrupts.

    • @k0ppit
      @k0ppit 9 лет назад

      k0ppit
      Got an Arduino Diecimila to toggle pin 8 at 2,66MHz and 50% duty cycle with this code.
      void setup() {
      cli(); // clear global interrupt
      DDRB |= 1

    • @k0ppit
      @k0ppit 9 лет назад

      k0ppit
      Got an Arduino Diecimila to toggle pin 8 at 4MHz and 25% duty cycle with this code.
      void setup() {
      cli(); // clear global interrupt
      DDRB |= 1

  • @nonchip
    @nonchip 6 лет назад

    the digitalWrite actually performs a hell of hand-holding to try and prevent unexpected behaviour like writing digitally to a pin reserved by a peripheral and stuff like that, that's why they do it at runtime (they check a bunch of registers to see if it should actually do stuff to the port). also the loop does other stuff in the background like checking/managing a system timer etc, this most likely introduces the overhead. also remember arduino is derived from C++, this might also introduce a small call overhead as opposed to C, also loop is an actual function, so not just a jump-back has to be performed but also stack stuff and calling/returning.
    tl;dr: safer/nicer for hobbyists who aren't that much into low level programming or just too lazy to care for a small project that doesn't have to run that performant, but introduces a LOAD of overhead. that's why I try not to use it if possible (avr-gcc/libc and a few small libraries to link to for common tasks is just fine) but it's great it exists, gets people into microcontrollers :)

  • @AlexBlate
    @AlexBlate 9 лет назад

    Great tutorial on high-performance Arduino magic.
    To avoid the overhead of the loop() routine, you can enclose the body of loop() in an infinite loop, e.g.,
    void loop() {
    while(1) {
    //your code here
    }
    }
    At minimum, this avoids the overhead of returning from loop() and calling it again from the Arduino libraries. This should also obviate the need for any delays between the writes, though parasitics may still give you an "ugly" square wave.
    Another useful trick along the same lines as what you presented is to change the state of multiple pins (on the same port/bank) simultaneously. Due to the goofy mapping of Arduino canonical pin names and the actual ports, you sometimes end up with goofy combinations of pins... but, if you wanted to do a simple bit-banged 8-bit DAC, for example, this would do the trick. (I think W2AEW used this trick in one of his videos a while back).
    Cheers, mate!
    Alex

  • @PetRatty
    @PetRatty 9 лет назад

    Great work Julian, this extract is taken from the core library arduino folder/hardware/arduino/cores/arduino/wiring_digital.c
    void digitalWrite(uint8_t pin, uint8_t val)
    {
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;
    if (port == NOT_A_PIN) return;
    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);
    out = portOutputRegister(port);
    uint8_t oldSREG = SREG;
    cli();
    if (val == LOW) {
    *out &= ~bit;
    } else {
    *out |= bit;
    }
    SREG = oldSREG;
    }
    As you can see there are loads of C commands just to change the pin state.

  • @spikekent
    @spikekent 7 лет назад

    Wow! That was fascinating and very expertly explained for a novice like me.

  • @mybirds2525
    @mybirds2525 5 лет назад

    The issue is loop overhead. Calling a subroutine is very tedious. This is fixable by applying Bit-Banging which is port read right of all 8 pins in a port in one step. Reading a port the same way is much faster. Also clocking loop out using while(1) {...} to contain the action speeds up things by about 62 clock cycles vs the loop() { .... } thing

  • @hellterminator
    @hellterminator 6 лет назад

    And this is precisely why I do all my Arduino programming in Atmel studio. You lose all the Arduino functions and libraries, but you actually know what your code is doing.

  • @aitorsierra
    @aitorsierra 9 лет назад

    I recently made this test with the same Arduino code but also i made other tests with other boards such as Stellaris (Texas Instruments), Arduino M0 Pro and Microchip PIC. I will upload a video with the results

  • @eight-double-three
    @eight-double-three 7 лет назад

    There's a valid reason to doing the mapping dynamically: This way you're able to use digital write with the port number from a variable. Analysing the code, and replacing the ones where the pin number argument to digitalWrite() is a constant would be a solution, but that's not a trivial job on one hand, and would pretty much make the timing with different digitalWrite() calls inconsistent.

  • @GoodScienceForYou
    @GoodScienceForYou 8 лет назад

    When doing mechanical "operations" as on a machine (calling out functions) the Arudino is so fast that humans can't tell there is a delay. When "this" goes on and "that" goes off, or from the time the button is pressed and 16 relays are switched It is less than 1/2 second. It is an amazingly easy to use device for controlling a lot of things. I am using a Mega board for my project and all but 4 pins are empty.

  • @malgailany
    @malgailany 9 лет назад

    Thanks Julian, good to know this kind of information.

  • @Inspironator
    @Inspironator 7 лет назад +1

    I like your Arduino videos, especially the finer points in this video, as well as your MPPT videos. Maybe you could create a how it's done video on the MPPT graphing -- really cool.

  • @neildarlow
    @neildarlow 9 лет назад

    Let us analyse what is going on here:
    1) digitalwrite(output, state)
    The output number has to be translated to a specific bit of a specific port. This involves two lookups using tables. One lookup determines the port associated with the output and the other constructs a bitmask to associate with the output. Finally the action of setting or clearing the bit has to be determined from the state parameter. Given that the lookups incur significant overhead it is not surprising that digitalwrite takes a good amount of time to execute.
    2) loop function
    Associated with the loop function there is some housekeeping code. It is small but it is executed once per loop function iteration. I believe this housekeeping is associated with managing serial I/O at a low level.
    You should be wary of using direct port I/O for the reasons that Julian described but it is important to make your I/O operations atomic to prevent side-effects caused by code executed in e.g. interrupt service routines from clashing with the values you wish to write and causing undesirable effects. At a high level you can use the &=, |= and ^= assigmnent-with-modification syntax to only operate on the bit(s) you intend to modify but this requires that the compiler handles these assignments atomically. At a lower level, assembly language bit-set and bit-clear instructions are a better solution because they are atomic by design.

  • @ChrisFredriksson
    @ChrisFredriksson 9 лет назад +1

    Quite interesting and fun! Thanks for trying and sharing this with the internet =) Great video! =)

  • @jameslamb4573
    @jameslamb4573 9 лет назад

    I'm surprised you didn't reverse the order, i.e. off then on, to check it was the loop introducing the delay and not some weird propagation problem or capacitance etc. effect.
    Funny how programming goes back to basics, it's as if machine code has decided to make itself known to a whole new generation of programmers.
    Nice work!

  • @JerryEricsson
    @JerryEricsson 7 лет назад

    Cool video, I dug out one of my old Nano's and installed Tiny Basic in it, now I can play around with the first programming language I ever used, and on such a small platform. It is really cool that I can reach it with both the Arduino programmer or cool term, actually cool term makes it feel more like programming on the C=128, my first computer, and, of course my first love.

  • @davidkempton2894
    @davidkempton2894 9 лет назад

    Hey Julian, that was really interesting. Thanks.

  • @byronwatkins2591
    @byronwatkins2591 5 лет назад +6

    Try 'cli();' to disable all interrupts.

  • @ArcAiN6
    @ArcAiN6 7 лет назад

    and now that i've watched the rest of the video, i see you've already figured that out :D

  • @DeeegerD
    @DeeegerD 9 лет назад

    Did something similar a few months back using a logic analyzer. I was able to get the Arduino board to 4 MHz and could see those glitches in the pattern as well. I did not set interrupts off - just bit toggled the one pin off and on.

  • @pedromms8908
    @pedromms8908 9 лет назад

    And that's why I allways used AVR Studio to develop Arduino ASSEMBLY scripts when I needed a "fast" arduino response time.
    I now it was slow, but I never thought that "arduino IDE style" sketches were so slow!

  • @espenbgh2540
    @espenbgh2540 8 лет назад

    The glory of the Arduino isnøt all that glory and the 16 MHz througput isn't allways 16 MHz. Brilliant show Julian.

  • @oreubens
    @oreubens 9 лет назад +9

    Just because a CPU runs at X Mhz doesn't mean it can do X million instructions per second (or 1 instruction per clock cycle). It still depends on bus cycle, memory speed, instruction decoding and some complex instructions like multiplying and especially dividing can be pretty slow. And stuff like memory waitstates, DRAM refresh can make things even slower.
    For example on the intel 8086 a bus cycle takes 4 clock cycles, so fetching any memory (instructions as well as data) couldn't happen any faster than once every 4 clockcycles, this also explains why the 8088 with it's 8bit bus was so much slower because fetching instructions was half as fast (and accessing 16bit data as well).
    A full IDIV (32bit/16bit signed integer divide) Could take up to a whopping 212 clockcycles.
    CPU designers have become better (even for very cheap cpu's) since then and on the 8bit AVR, most common instructions take 1 cycle, but there's a few handsfull that take 2 or 3, and a couple go up to 5 (CALL, RET, RETI).
    FYI. There's optimal digitalWrite() versions in the Wiring framework for arduino. if the pin number is const (as is the case here), the digitalWrite will be compiled to a single SBI or CBI When the pin number is in a variable however, then there's a price to pay for the convenience of writing digitalWrite(pinnum, HIGH). Avoid if possible (even a switch/case cascade with const pin numbers will be faster (at the expense of code size).

    • @igorspitz
      @igorspitz 7 лет назад

      If you look at Atmel Atmega datasheet, they do say that most instructions takes 1 cycle. The problem is, that turning GPIO on/off is more than one instruction - in 'arduino language' for sure. Maybe if he would set DDR & PORT registers directly, it would be faster. Apart to that, he said enough.

    • @igorspitz
      @igorspitz 7 лет назад

      Ok, he got to that in video. I showed myself... :D

    • @PerchEagle
      @PerchEagle 5 лет назад

      How about defining the pins as #define? Is it similar as putting them as const int ? Or even const byte.

  • @reggiebacci
    @reggiebacci 9 лет назад

    I think the reason for the runtime conversion is so that you're able to specify the Arduino output pin as a variable, so you can loop through or address a number of pins e.g. for (myPin...) {digitalWrite (myPin, HIGH); }
    Obviously this wouldn't be possible if these were translated as constants at compile time.

  • @PeterBrockie
    @PeterBrockie 9 лет назад

    I think A0-A5 are defined as D14+ under Arduino if you don't need the analog functions.

  • @collingtech1
    @collingtech1 8 лет назад

    very good masterclass julian thanks for video , cheers

  • @gerrymcerlean8432
    @gerrymcerlean8432 3 года назад

    Thank you. Extremely well explained. Doesn't the Arduino also have a 'micros' function which keeps a count of the elapsed microseconds? Does this also use an interrupt?

  • @davepauljones
    @davepauljones 4 года назад

    Thanks Julian, I wonder if the bootloader is taking up any cycles or resources.

  • @jpl0087
    @jpl0087 8 лет назад +3

    arduino might use bitwise operation to change only 1 output. so your test ist missleading since you make 2 total different compairison. write the second part manipulation in a way that the other 7 bits are ignored. now you set acctually 1 bit high and 7 low. since it is an 8 bit processor you can manipulate 8 outputs in parallel. thanks for a follow-up

    • @NGC1433
      @NGC1433 8 лет назад

      Atmegas ALWAYS overwrite the whole buffer at once, disregarding how much bits you change, it is a single cycle instruction.

    • @jpl0087
      @jpl0087 8 лет назад +2

      yes, but to get a 8 bit row of outputs changed, you need some math, and that takes time. modify one complete Port in AVR, and you bypass the arduino implementation.
      DDRB = 0b11111111; //set all pins of port b as outputs
      PORTB = 0xFF; //write data on port
      This will be the faster way. It is regular C AVR programming and no arduino interaction is being processed.

  • @tengelgeer
    @tengelgeer 9 лет назад

    Julian, as you might have found by now there is a interrupt enable bit. It's (for a Atmega168) bit 7 of the SREG register. But there is a quick macro for it, cli() (CLear Interrupt) en sei() (SEt Interrupt).
    And yeay, Arduino has a lot of overhead. But it's always a trade of between fast, versatile and complex or slower, more static but a lot easier. And the last part is the whole reason, making it easy to use.
    But what are you planning on doing? Sounds like you should just use the PWM.

  • @VoidHalo
    @VoidHalo 6 лет назад

    That is some really rustic looking soldermask and silkscreen on that arduino. Looks almost like when you get a PCB from the 80s where the solder mask goes all crinkly.

  • @MilanKarakas
    @MilanKarakas 8 лет назад +1

    The fastest possible output is 4 MHz for 16 MHz Atmega328P. But, it has 62.5 ns ON state, and three times that (three cycles, or 187.5 ns) OFF state (if one want equal ON and OFF state - out freq is 2.6666...7 MHz, so un-comment asm codes if needed):
    void setup(){
    TIMSK0=0; //disable watchdog interrupt
    DDRB = DDRB | B00100000;//only pin13 (PB5) as output
    while(1){
    PORTB=(1

  • @nickpelov
    @nickpelov 9 лет назад

    the arduino is probably doing more than just a jump in the loop function. What you could try is to do the direct portB write instructions in a while loop.

  • @a1fliema1fie
    @a1fliema1fie 9 лет назад

    As others have said , a while true loop and a single bit toggle is the fastest. For reference I got around 4MHz from an arduino uno. Also, I noticed you get a much cleaner signal if the usb power is supplied by a wall wart. Mty laptop usb produces an unacceptable amount of noise.

  • @fifaham
    @fifaham 4 года назад

    Remember that the sampling capability of your scope may not be linear relative to slowing down and speeding up the time scale. May I ask what is the sampling capability of your scope? And if it maintains the same sampling rate at this very slow time scale? You are doing great job BTW.

  • @makingthings277
    @makingthings277 9 лет назад

    Very inturesting! Good in depth check!

  • @KiR_3d
    @KiR_3d 6 лет назад +1

    Wow, impressed! I guess you have a professor degree. Did they've used some improvements for the compiler? Three years passed... Probably somebody from the Arduino team is watching your videos constantly. They should know...

  • @NiCadHeliPilot
    @NiCadHeliPilot 8 лет назад

    Great vid. That's quite a surprise on how slow the Arduino Bootloader (the firmware that uses the stuff that you've typed up in the IDE) actually is.
    I suppose it wouldn't matter so much for most general stuff, but I"m wonderin' how much would that hold back something like a brushless ESC?

  • @leebolton9275
    @leebolton9275 9 лет назад +1

    Hi, love watching your videos, thought i would do a comparison between arduino bootloader and using Atmel Studio, Atmel Studio was 120ns between port on and off where as Arduino was 400us. Massive diference!!

  • @das250250
    @das250250 8 лет назад

    Julin just a little note when showing the scope ..turning down ambient light makes the screen much sharper :_)

    • @JulianIlett
      @JulianIlett  8 лет назад

      +graham kaveman Thanks Graham. Reflections seem to be the biggest problem. But reducing ambient lighting (closing the blinds) would help that too.

  • @MilanKarakas
    @MilanKarakas 8 лет назад

    Good examples! Thanks for the video.

  • @fifaham
    @fifaham 4 года назад

    Time frame 8:50 > this is because of the parasitic on board capacitor and the sampling capability of your scope. If you use a scope with much higher sampling capability, and probes with better isolation, then you may be able to see that flat top ON section of your "Square" wave. Since you are still using the brackets of your loop then that takes relatively much more time to execute and that why the OFF period is way much longer that ON. If you use assembly code and the Atmel Studio I bet you will get way much better response / without having to duplicate PORTB = B00100000 and slow down the CPU execution speed > better yet, use PORTB.5 to slightly speed it up. Atmel Studio is easy to use and has very powerful features and I highly recommend that everyone use it along with Arduino IDE. That also looks good on your resume.

  • @LynkedVideos
    @LynkedVideos 8 лет назад +1

    Julian, you need only one statement in the main loop: PORTB ^= (1

    • @NormanNodDunbar
      @NormanNodDunbar 4 года назад

      Even better, writing 1 to the PINx register for an output pin, toggles it.
      PINB |= (1

  • @GogogoFolowMe
    @GogogoFolowMe 7 лет назад

    Very interesting, I was going to make these mesures, thanks for the vid !

  • @BokoMoko65
    @BokoMoko65 8 лет назад

    Have you tried to invert the order of the high/low ? Just to make sure the overhead is actually from the flow control and not the high/low process itself.

  • @RWoody1995
    @RWoody1995 9 лет назад

    Just gonna post this since you didn't mention it, you can use the direct manipulation method in a way that means you dont have to worry about changing all pins on the port at once if you do PORTB /= B00100000; rather than just =, it will only write 1 to the positions you write 1's into becuase it will take the current state of PORTB and OR it with the number you give it so any 0 stays 0, any 1 stays 1 and any 0 you want changed to 1 will become 1.
    Also for changing something from 1 to 0 you'd do PORTB &= ~(B00100000); and again it will take the state of PORTB and AND it with the complement of the number you give so whatever you put as 1 will turn to 0 and everything else stays as it was.
    I don't know if this would add much/any extra time to execute the line of code but it should still be faster than arduino functions.

  • @nickyflachy6599
    @nickyflachy6599 7 лет назад

    Hi Julian, at first, well explained and easy to understand, but you can do something to bring the speed up to nearly 8MHz ( 2 clockcycles), without using Assembler. For example, try a "while 1- loop" (like Captain-Slow sad) with Portmanipulation. I know, its not good in a program, but works fine. At second, You don't have to write only "1" to Pin 13 and at last once "0", if you "copy-paste" the "ON-OFF-command" a serval times, the speed will increase drastically. ^^) (I tried with about 100, 200, 400 and 21000 changes within the while(true) [last one doesn't work --> little joke :) ] )
    I know you are a few steps ahead of me, but I like it if someone gives me a little push to see new/better results. ^^)

  • @36trooper
    @36trooper 9 лет назад

    Do you still need the pinmode function in the setup if you're using port assignments instead of the digital out command?

  • @PabloPazosGutierrez
    @PabloPazosGutierrez 8 лет назад

    Using a high level programming language will always generate more than one processor level instructions. Also the loop itself is not 1 processor instruction, at a machine level that is mapped to many processor instructions. The functions digitalWrite and pinMode, might also be implemented in hundreds of low level instructions.

    • @xFuaZe
      @xFuaZe 8 лет назад

      Using a low level programming language will always generate code that is not portable at all.
      I'm not sure what you consider high or low, but programming in C is as fast as assembly.
      There is no reason that a "While" loop in C should take more as a loop instruction. You can bet your ass it will be translated into the same code.
      But yes, Arduino itself is quite, inefficiënt. But that doesn't have to be a problem.
      You can check the code out, like for digitalWrite:
      void digitalWrite(uint8_t pin, uint8_t val)
      {
      uint8_t timer = digitalPinToTimer(pin);
      uint8_t bit = digitalPinToBitMask(pin);
      uint8_t port = digitalPinToPort(pin);
      volatile uint8_t *out;
      if (port == NOT_A_PIN) return;
      // If the pin that support PWM output, we need to turn it off
      // before doing a digital write.
      if (timer != NOT_ON_TIMER) turnOffPWM(timer);
      out = portOutputRegister(port);
      uint8_t oldSREG = SREG;
      cli();
      if (val == LOW) {
      *out &= ~bit;
      } else {
      *out |= bit;
      }
      SREG = oldSREG;
      }

  • @kuyanatnatdkrx7
    @kuyanatnatdkrx7 9 лет назад

    if you want to remove the noise which is caused from the built pre coded interrupts you can type noInterupt() function to disable them and type interrupts() to reable them. If you really want a high efficient code for tasks that require high precision time based code then I think it is best to stick to the original type of microcontroller coding and that is doing it the hard way. Also note when I say efficient I mean being able to type code like _asm("wfi") and save power but that would be redundant in the arduino IDE and libraries as there is interrupts happening everywhere.

  • @r3corpinformatica
    @r3corpinformatica 9 лет назад

    Julian, coud you please make the same video kind for the ESP 8266 ?

  • @mantaz111
    @mantaz111 9 лет назад +2

    What if you put port output set instructions in a while(true) loop, so that function loop() doesn't have to end?

    • @RonNewsham
      @RonNewsham 9 лет назад +2

      mantaz111 I was wondering the same thing and dug out the code that Arduino executes. There is behind the scenes a main() that does some stuff including:
      setup();
      for (;;) {
      loop();
      if (serialEventRun) serialEventRun();
      }
      It is fairly clear that there is the overhead of calling the loop() function (so that's a few instructions to throw some registers onto the stack, perform the call then restore the registers from stack) - not too much, but nonetheless a function call.
      But then there is also the test to decide whether to run a serial event.
      The bottom line here is that there is the overhead of convenience (being able to use pin 13 rather than port D bit 5 or whatever), and the overhead of the framework (additional function calls, overhead of timers) that may be useful and helpful, or not.
      The nice thing is that you generally have a choice - use the Arduino and the convenience (and limitations), or use the lower-level machine instructions (either in C or assembly language).

  • @fifaham
    @fifaham 4 года назад

    In time frame of 5:30 and time frame 11:50 there appear to be signal aliasing, although I could be wrong. Signal aliasing arises from the fact that the scope maybe not perfectly aligned to sampling the Atmel chip signal. You may need to use a scope of higher sampling capability at this specific setup.

  • @bwack
    @bwack 9 лет назад

    Here is an improvement that Arduino IDE developers can improve. The MikroC compiler from MikroElectronica does compiletime optimizations. Does the Arduino IDE have a disassembler ? If so you can clearly see how a function call is compiled...

  • @MithiSevilla
    @MithiSevilla 9 лет назад

    Thanks for this! Great video!
    I do hope the developers find a way to optimize the conversion eventually.
    For example from pololu's library this command:
    set_digital_output(IO_D3, HIGH);
    compiles to this in assembly:
    sbi 0x0b, 3 ;i.e. PORTD |= 1

  • @Dalekmun2010Two
    @Dalekmun2010Two 6 лет назад

    If the conversion is done at runtime, I like to think you could replace the pin number with an int, and increment/decrement it at will. I don't know why I find this concept so funny, but for some reason, I do.

  • @Ed19601
    @Ed19601 7 лет назад

    Very good explanation

  • @k.chriscaldwell4141
    @k.chriscaldwell4141 Год назад

    Fascinating, and good info. Thanks.

  • @robertw1871
    @robertw1871 5 лет назад

    You can use bitwise OR with a bitmask, this will set only the bit needed.

  • @PerchEagle
    @PerchEagle 5 лет назад

    OK what I understood by this video, is that 16mhz microcontroller can't drive the output pin high/low at the same operating frequency. It's just the 16mhz is for CPU clock and that's it.

  • @RobAbdul
    @RobAbdul 9 лет назад +1

    How much is the current draw on this in an hour?

  • @RaoulRacingRC
    @RaoulRacingRC 8 лет назад

    Nice video, I got a question after watching this video. What do I need to use instead of analogWrite, analogRead and digitalRead? If my porgram still contains analogWrite, analogRead or digitalRead it is slowing down on that isn't it?

  • @rudolphriedel541
    @rudolphriedel541 6 лет назад

    Pin-Toggle on AVRs like the M328: PINB = (1

  • @MrSoulBack
    @MrSoulBack 9 лет назад

    if you use a forloop inside the loop function it will work much faster. the loop function does some stuff every time it repeats itself.

  • @Relations99
    @Relations99 9 лет назад

    Hey Julian!
    Great work on and research on this topic! Long time supporter and fan of your channel. Do you have anyway to speed up AnalogRead? I am trying to use the arduino as a oscilloscope. I dont have the $$$ to get one xD And I already have an arduino around. Thanks!

    • @sbern42
      @sbern42 9 лет назад

      Relations99 While it is possible to speed up analogRead() a bit, its main delay isn't due to code overhead (that much). The ADC needs time for the hardware to convert analog to digital. If you were to skip analogRead(), you'd have to manually check if the ADC was done converting before reading its registers, otherwise you wouldn't get sensible data. This is done by analogRead() for you, by simply waiting until it returns something.

    • @JulianIlett
      @JulianIlett  9 лет назад

      Relations99 I think you read my mind! I'll be looking at analogRead() next. I also want to build a cheap Arduino oscilloscope and speeding up ADC operation is the key to maximising it's frequency range. There may be a way to have continuous analogRead()s by putting all the other code into the gaps where the successive approximations take place. This would require interrupts from the ADC to break into the code for display updates and keyswitch reads etc. Not sure how feasible this is yet though ;)

    • @AsafShahar
      @AsafShahar 9 лет назад

      Julian Ilett this meettechniek.info/embedded/arduino-analog.html might save you a lot of work... (and much less fun) but the overall estimation you are looking at 77khz max using continuous ADC conversion (about 13 clock cycles per conversion) for the ATMEGA328. not very impressive.

    • @sbern42
      @sbern42 9 лет назад

      Relations99 Also, using an arduino as an oscilloscope is a useful exercise for your own development, but to be honest, it will be useless for pretty much anything as a scope. Even the oldest analog scopes from the 60's and such will be far more capable.
      As a learning experience and fun project, go for it. It'll be a great thing. As a useful tool, look around with universities, second hand on-/offline and auctions and such, even ebay, and get the cheapest analog scope you can possibly find where the trace is visible and a curve is shown on the display (indicates that the scope works and triggers). I got myself a Tektronix 2465 (300MHz 4-channels) for less than the equivalent of 100 GBP about 8 months ago at an annular university electronics auction. And that's much more than you'll need. Lesser scopes went for 10-30 GBP.

    • @Relations99
      @Relations99 9 лет назад

      Stefan Berndtsson yeah noted thanks. I was and still am looking out for scopes. But it's rather frustrating because they then to go very very fast.
      Julian Ilett there is a sort of a guide online, On indestructibles, that uses and external ADC and external clock for the ADC, all to save some processor calls on the arduino. Also, might wanna look into SerialWrite. ;)

  • @TechBuild
    @TechBuild 7 лет назад

    Which is the fastest and the slowest Arduino board?

  • @hurterbe
    @hurterbe 4 года назад

    How do I read a complete port in a similar way that what you wrote to a port without using the Digital write function?

  • @MilanKarakas
    @MilanKarakas 8 лет назад

    My last comment is about the "fastest possible" output of only 4 MHz from Arduino working on 16 MHz. It can do better - 8 MHz, but only in burst mode - switching on and off by some sort of lookup table. The code:
    void setup(){
    TIMSK0=0; //disable watchdog interrupt
    DDRB = DDRB | B00100000;//only pin13 (PB5) as output
    }
    void loop(){
    eightMHzBurst();
    }
    void eightMHzBurst(){
    PORTB=(1

  • @joseperezmiranda6226
    @joseperezmiranda6226 8 лет назад

    Very well explained. Thanks.