Stop Wasting Time, Use AVR Timer Interrupts | Baremetal AVR Programming Tutorial

แชร์
ฝัง
  • เผยแพร่เมื่อ 22 เม.ย. 2022
  • Programming embedded systems is difficult. You need to make the most out of the limited processing power you have. The worst thing you could do is waste precious processing cycles by sleeping, waiting for an event to occur. Instead, you should be using INTERRUPTS. Interrupts are a great way for a device to be pre-empted and ran when an event or timer triggers.
    In this video, I'll teach you how to write code that produces a timer interrupt, in baremetal AVR C, without using the Arduino API or libraries.
    🔥🔥🔥 SOCIALS 🔥🔥🔥
    Low Level Merch!: www.linktr.ee/lowlevellearning
    Follow me on Twitter: / lowlevellearni1
    Follow me on Twitch: / lowlevellearning
    Join me on Discord!: / discord
    Code from this video: github.com/lowlevellearning/a...
    Register Documentation: onlinedocs.microchip.com/pr/G...
  • วิทยาศาสตร์และเทคโนโลยี

ความคิดเห็น • 92

  • @proxy1035
    @proxy1035 2 ปีที่แล้ว +15

    6:55 "ISR" is the "Interrupt Service Routine", ie the code that runs when the CPU gets an Interrupt.
    what you meant there is called an "IRQ" which is the "Interrupt Request" signal that goes to the CPU and causes it to run the ISR (if interrupts are enabled).

  • @henokvanni3831
    @henokvanni3831 2 ปีที่แล้ว +6

    i didn't know your channel, but i instantly loved the fact that you started the video saying: "low level GANG".

  • @aajpeter
    @aajpeter 2 ปีที่แล้ว +11

    As a convenience and to exemplify the behavior of the timer:
    LEDHZ = 1
    TCNT = 65535 - (F_CPU/1024)/LEDHZ

  • @vegansynths7757
    @vegansynths7757 2 ปีที่แล้ว +40

    Thanks for this. Can you please do this same thing with another processor, say an SAMD21 or RP2040? I have used up all 6 ISRs on the 328P and need more, but can't understand the datasheets of the Cortex M0+ processor.

    • @kayakMike1000
      @kayakMike1000 2 ปีที่แล้ว +4

      Yeah, took me a few weeks to figure this out. You can make a career outta the stuff you're trying to learn, keep it up! These cortex-m cores have dozens of hardware interrupts.

  • @nimcompoo
    @nimcompoo 2 ปีที่แล้ว +19

    Your videos are extremely helpful and educational. I can not express my appreciation for your work in words. Thank you very much. I have a small request, if it is possible please archive your twitch streams on youtube.

  • @gregtasi
    @gregtasi 2 ปีที่แล้ว +2

    I was just searching for this for a school project! Great timing!

  • @Frost_Byte_Tech
    @Frost_Byte_Tech 2 ปีที่แล้ว +5

    I'm a full stack developer who did embedded systems as well in varsity and enjoyed it, however due to the nature of my work I haven't been writing much C since college but this channel has gotten me practicing again and my skills have level up 10 fold..Thank you so much for your A - Grade content 🔥🔥keep it up and I'll keep recommending you 🙏 also can we get some esp8266 mesh network projects?

  • @SaliyaRuchiranga
    @SaliyaRuchiranga 2 ปีที่แล้ว

    great tutorial, hope to see more like this !!

  • @ljaworski88
    @ljaworski88 2 ปีที่แล้ว +1

    You can also use the CTC modes and set the OCR1A or IC(i forgot the rest of the register name) and use their corresponding ISRs to do this task without fussing around with the timer counter itself.

  • @stuartmcconnachie
    @stuartmcconnachie 2 ปีที่แล้ว +11

    Really you should use OCR1A and OCR1B registers for the timer value and set CTC mode for timer 1, rather than setting TCNT1=0 in the ISR.
    That will get the hardware to reset the timer to zero for you immediately it matches the programmed OCR value. As your code stands there is some latency between the interrupt being triggered and your ISR getting called, so you will not have “exactly” 15KHz (or whatever frequency division of the CPU clock you are aiming for). Worse, if other interrupts preempt your service routine, you will also introduce drift with a manual reset.

    • @alexloktionoff6833
      @alexloktionoff6833 10 หลายเดือนก่อน

      So if i want precise /*let's say for a watch*/ 1ms implementation i need to setup pre-scaler for 64 16000/64 and then implement s/w pre-scaler for 250 for exact 1ms, but it will load uC 250 times harder! Or setup pre-scaler for 1024 but then adjust, i.e. jump over every Nth tick. Do you have a good article/video about it?

    • @B1CL0PS
      @B1CL0PS 9 หลายเดือนก่อน

      @@alexloktionoff6833 This video goes into a little more detail on using CTC mode (which should cause less drift ) th-cam.com/video/cAui6116XKc/w-d-xo.html

  • @WistrelChianti
    @WistrelChianti 2 ปีที่แล้ว

    Thanks I have some code I did ages back using the timer registers but I don't think I understood what I was doing as well as I do now with your explanation. Still... it did at least work!

  • @foxfyre3600
    @foxfyre3600 2 ปีที่แล้ว +1

    I didn't know it was on 16-bit overflow condition, I thought the timers counted down and on zero the ISR was called. Thanks for this!

  • @duality4y
    @duality4y 2 ปีที่แล้ว

    i always learned to do it with timer compare that way you dont have to do the subtract but its just a different way of doing the same thing :)

  • @cornevanzyl5880
    @cornevanzyl5880 2 ปีที่แล้ว

    Wow reminds me of my university days learning how to program a Microchip in assembly.

  • @lis6502
    @lis6502 2 ปีที่แล้ว +11

    Being raised on 6502 and watching SEI for actually enabling interrupts makes me feel dizzy a bit ;p
    But video is as clear as it could be, guess that anyone who understands bitwise C operators and concept of interrupt handler will take benefit from this video, thanks!

    • @williamdrum9899
      @williamdrum9899 2 ปีที่แล้ว

      Same here haha. I actually prefer 6502 to C for the most part since it lets me do what I want 100% of the time (though admittedly C is very good at writing complex equations that would be awful in assembly)

    • @klaus2t703
      @klaus2t703 2 ปีที่แล้ว +3

      @@williamdrum9899 You compare apples to oranges. 6502 is a microcontroller, while C is a language. You can combine 6502 with C and ASM and you can combine AVR with C and ASM. I´m also from the 6502 era, but an AVR is way more powerful, rich of periferals...

    • @Henry-sv3wv
      @Henry-sv3wv 2 ปีที่แล้ว

      coming from arduino trying to learn c64 stuff irritates me that sei is supposed to turn it off -.-
      i prefer c

    • @williamdrum9899
      @williamdrum9899 2 ปีที่แล้ว

      I meant ASM when I said 6502 my bad

    • @williamdrum9899
      @williamdrum9899 2 ปีที่แล้ว

      Is arduino an ARM cpu? I don't remember if ARM even has a dedicated SEI/CLI. Pretty sure it doesn't (from what I remember about the GBA you had to write to a hardware port)

  • @user-st7io9kd9h
    @user-st7io9kd9h 2 ปีที่แล้ว

    Cool baremental programming technique! I think one the pros of interrupt-driven is power save, maybe you can upload another video to explain it.

  • @diegopinilla3431
    @diegopinilla3431 2 ปีที่แล้ว

    Nice video, keep it up!

  • @deokureta108
    @deokureta108 2 ปีที่แล้ว +1

    Hello this was a very informative video but i would like to know if there is any difference between bare metal AVR C an CMSIS in the case of ARM processor?

  • @ZenoTasedro
    @ZenoTasedro 2 ปีที่แล้ว +1

    Oh damn, your makefile... I recall taking some massive makefile for raw AVR programming and distilling it down to a nice hand written makefile like that and it was so much cleaner. But I lost that thing years ago and didn't want to recreate it 🤣, very glad to see you have a MUCH nicer starting place

    • @Henry-sv3wv
      @Henry-sv3wv ปีที่แล้ว +1

      i would add phony but that's it.

    • @thebatchicle3429
      @thebatchicle3429 3 หลายเดือนก่อน

      @@Henry-sv3wv .PHONY: is a GNU extension. Not all Make implementations support it

  • @emoutraspalavras-marloncou4459
    @emoutraspalavras-marloncou4459 ปีที่แล้ว

    thank you so much. if I want to have three timers so what part of the code will repeat? i suppose I would have to change 1 with 2 and 3 in TCNT... and also an ISR should be set for every timer. could you make a bare metal programming video on I2C and another on U(S) ART for the Arduino chip?

  • @querela92
    @querela92 2 ปีที่แล้ว +5

    Nice, easy to understand. I would still suggest adding more comments about the register assignments for easy lookup but the video is short enough to rewind.
    Wouldn't it make sense to also use a macro since we were the same code twice for TCNT1?
    (In the end both the compiler might precompute the constants into a single value so this would only be for the human reader.)
    On the other hand, the TCNT1 assignment in main() is basically setting the first delay. Can we just set it to 65535, as basically an almost zero delay to just not worry about it? Or is there a chance that the timer will tick "too fast" in the background if there is more setup code in main() before the sei() call, so the initial value will overflow and need to increment the total amount before the first "interrupt routine" is being run?

  • @CooperDuper3000
    @CooperDuper3000 ปีที่แล้ว +1

    Great Video, but i think you should always mention or show the specific part in the manual where you get the needen port and interrupt specifications from, its very hard to follow these low level stuff otherwise for beginners. Reading the documentation in the video would also teach your audience how to read these docs properly. Which is a higly needed skill to have if you are programming bare metal stuff.

  • @PASTRAMIKick
    @PASTRAMIKick 2 ปีที่แล้ว

    I used to program the 2560 in the old AVR Studio, its simulator was pretty good and useful, but nowadays I do prefer to program it like this.

  • @TokyoScarab
    @TokyoScarab 10 หลายเดือนก่อน

    Great vid, but I did notice one problem, the Egyptian Braces in your int main :P

  • @eFeXuy
    @eFeXuy 2 ปีที่แล้ว +1

    When I wrote my space invaders rip-off on the AT328 I got a stable framerate by using this interrupt by putting at the end of the frame loop a _while(variable){ }; variable=1;_ and then in the interrupt I set variable=0, so I would just loop there until the interrupt kicks in.
    I don't know if that's the best way to do it tho.

    • @williamdrum9899
      @williamdrum9899 2 ปีที่แล้ว

      That's the same way I do it actually. I don't think there really are any better methods that aren't specific to any particular CPU

  • @ruffrecords
    @ruffrecords 2 ปีที่แล้ว +3

    It would be worth including a comment about how the interrupt flag gets cleared. In many micros you have to do it explicitly but I am guessing the Atmel clears it automatically when you reload the timer. A common mistake used to be forgetting to clear the interrupt flag.

    • @NormanNodDunbar
      @NormanNodDunbar 2 ปีที่แล้ว +1

      The AVR automatically clears interrupt flags when the ISR is executed. You only need to manually cler them if you are not using interrupts.
      Cheers,
      Norm.

    • @NormanNodDunbar
      @NormanNodDunbar 2 ปีที่แล้ว +1

      Another common mistake is forgetting to clear the interrupt flag before enabling interrupts.
      If the stimulus to trigger the interrupt is detected by the hardware, the flag will be set and will remain set even if the stimulus goes away. When interrupts are subsequently enabled, the ISR will trigger even though the interrupt stimulus is no longer present.
      Cheers,
      Norm.

  • @duality4y
    @duality4y 2 ปีที่แล้ว

    would it be possible to explain this for arm ?

  • @LemmeAsk
    @LemmeAsk 2 ปีที่แล้ว +3

    I don't know why I'm watching this, I have no clue what's even going on lol

  • @josephchamness9915
    @josephchamness9915 2 ปีที่แล้ว +1

    Thanks for the helpful video.
    2 things I had to google:
    Do CS10,CS11&CS12 change a lot for different avr chips? Else wouldn't TCCR1B = 0b101; be clearer? maybe that is just me.
    Is using _BV() to show different methods to do the same thing or would (1

    • @LowLevelLearning
      @LowLevelLearning  2 ปีที่แล้ว +1

      They may be the same value across boards, but you want to avoid using magic numbers like that in the event there IS a change and now your code isn’t portable.
      Also using defines makes your code more readable.

    • @Henry-sv3wv
      @Henry-sv3wv ปีที่แล้ว

      i just grep -r CS10 *
      in avr/include
      to see that CS10 is bit 0 on all chips
      ---> tested the rest, bit positions are the same

  • @KkkKkk-re9il
    @KkkKkk-re9il ปีที่แล้ว

    You should have also put the CPU into one of the sleep states to conserve power.

  • @SWAGCOWVIDEO
    @SWAGCOWVIDEO 2 ปีที่แล้ว +1

    If you had something like a TL866 chip programmer and the 328p was removable, could you just dump the hex file directly onto the microcontroller?

    • @Henry-sv3wv
      @Henry-sv3wv 2 ปีที่แล้ว +1

      It's not an (e)eprom, so not the TL866.
      But you can get a dedicated progger.
      cheap ones are based on usbasp.
      there is also an arduino sketch to turn an arduino into an isp prog device.
      avr isp --> AVR In System Programmer
      (using ISP you don't need to remove the avr out of the circuit)
      (you also use avrdude for flashing)
      more expensive: AVR HV-Programmer
      (to rescue a chip from wrong fuse settings (like if you disable reset pin to gain extra IO you can't program it anymore with isp --> bricked without HV Programmer to change fuse settings)

    • @SWAGCOWVIDEO
      @SWAGCOWVIDEO 2 ปีที่แล้ว

      @@Henry-sv3wv Good to know - thanks

  • @asolovets
    @asolovets 11 หลายเดือนก่อน

    Is it possible to put the CPU to sleep instead of spinning an infinite loop?

  • @ME-rv1pw
    @ME-rv1pw ปีที่แล้ว +1

    Is there a reason you use _BV() sometimes but not other times?

  • @johndraper8197
    @johndraper8197 2 ปีที่แล้ว

    Like to see the same type of info for ESP32 boards

  • @NormanNodDunbar
    @NormanNodDunbar 2 ปีที่แล้ว +4

    Instead of XORing PORTB, PIN5 to toggle, just write a 1 to PINB5. That will toggle for you.
    Cheers,
    Norm.

    • @7alfatech860
      @7alfatech860 2 ปีที่แล้ว

      Quite so. Though that may be an Atmel quirk? His code appears easier to understand.

    • @NormanNodDunbar
      @NormanNodDunbar 2 ปีที่แล้ว +3

      @@7alfatech860 yes indeed, it's Atmel. Input pins use the PORT register to enable pull ups, output pins use PIN register to toggle. It's all in the data sheet.
      Cheers,
      Norm.

    • @PASTRAMIKick
      @PASTRAMIKick 2 ปีที่แล้ว +3

      yeah the Atmel datasheets are really good, super thorough, detailed and easy to read as well.

  • @MikeNugget
    @MikeNugget 2 ปีที่แล้ว

    Buildroot & Flutter app tutorial, please 🙂

  • @wm8123
    @wm8123 2 ปีที่แล้ว

    Instead flooding the CPU with "push" and "pop" with using interrupts, you should start coding in a sequential multitasking style. Using a few interrupts is no deal for most conditions. But using interrupts for every single task you have ends up in wasting very very much time executing "push"s and "pop"s. Just have a look at the assembly output from the compiler.
    You are right, sleeping the CPU with delay() is waste of time, but using interrupts as a global task worker results in a lot of time waste as well.

  • @Handelsbilanzdefizit
    @Handelsbilanzdefizit 2 ปีที่แล้ว

    How to compile Rust for Risc-V?

    • @Henry-sv3wv
      @Henry-sv3wv 2 ปีที่แล้ว +1

      you have to hit trees with a rock first and get some stuff to compile a base in rust. then you can attak other players.

  • @edgeeffect
    @edgeeffect 2 ปีที่แล้ว +1

    Bear... metal (laughs)
    I do that infinite loop as `loop: rjmp loop` .... always want to "dare" C programmers to use a goto. ;)

  • @cernejr
    @cernejr 2 ปีที่แล้ว

    I am having trouble with flashing the code using avrdude: avrdude: stk500_recv(): programmer is not responding. I am on Linux Mint, 64 bit.

    • @cernejr
      @cernejr 2 ปีที่แล้ว

      Arduino IDE also could not upload. I bought a Mega, that one works fine with Arduino IDE. Tomorrow I plan to try this tutorial using the Mega.

    • @canuckprogressive.3435
      @canuckprogressive.3435 ปีที่แล้ว +1

      @@cernejr Arduino IDE won't work on my Linux Mint either. It installed but when I click on it the window just flashes onto the screen for an instant. Good thing I did a dual boot so I can go into my old Win7 install and use it from there. I never use Arduino code but just type AVR C into Arduino IDE.

    • @Henry-sv3wv
      @Henry-sv3wv ปีที่แล้ว

      sudo avrdude -v -p atmega328p -c arduino -P /dev/ttyUSB0 -b 115200 -D -U flash:w:firmware.hex:i

    • @Henry-sv3wv
      @Henry-sv3wv ปีที่แล้ว

      (if you use an arduino or 328p with installed arduino bootloader)
      else some other command with usbasp over isp or whatever you use

  • @shvideo1
    @shvideo1 ปีที่แล้ว

    What increments TCNT1?

  • @ArthurTucker
    @ArthurTucker 2 ปีที่แล้ว

    Is your Sublime Text Unregistered?? 🧐

  • @EmbeddedEnigma
    @EmbeddedEnigma 2 ปีที่แล้ว +1

    after using stm32, AVR just feels so underwhelming in every thing :P

    • @Henry-sv3wv
      @Henry-sv3wv 2 ปีที่แล้ว +1

      i just miss more RAM to have more fun with AVR

  • @firedawn
    @firedawn ปีที่แล้ว +1

    Your github repository seems to be missing some code in main() ;-)

  • @zapiton
    @zapiton 2 ปีที่แล้ว

    I need deeper knowledge about atmega 328p

    • @NormanNodDunbar
      @NormanNodDunbar 2 ปีที่แล้ว +2

      The data sheet has everything you'll ever need, but it's a difficult read!
      Arduino Software Internals is a good book, by Norman Dunbar 😉, and explains both the Arduino Software and how it works, the ATmega328 hardware, timers, etc, and how the software talks to the hardware.
      It comes highly recommended by Ralph S Bacon on his You Tube channel.
      Cheers,
      Norm.

    • @zapiton
      @zapiton 2 ปีที่แล้ว +1

      @@NormanNodDunbar ty, I'll read it. I mean channel is called low level learning, but in this video compiler is used. compilers r too easy😅 how about writing code in hex redactor?
      ofc, I'm kidding, but in every joke there is a part of truth😅

    • @canuckprogressive.3435
      @canuckprogressive.3435 ปีที่แล้ว +1

      If you are still struggling try Human Hardrive YT channel.

  • @ugagnskraake
    @ugagnskraake 2 ปีที่แล้ว

    Should it be "by using Arduino Timer Interrupts"?

    • @canuckprogressive.3435
      @canuckprogressive.3435 ปีที่แล้ว +1

      Not really. This is pure avr C programing without the dumbed down Arduino code.

    • @Henry-sv3wv
      @Henry-sv3wv ปีที่แล้ว

      there are different arduino boards, but the hardware timer of the physical microcontroller chip is providing the timer interrupt and uno does have the ATmega328 mcu

  • @metamud8686
    @metamud8686 ปีที่แล้ว

    great, now go to sleep() instead of while(1) nop'ing

  • @JordyDevrixOfficial
    @JordyDevrixOfficial ปีที่แล้ว

    You lost me at 8:57 I don't get how that becomes a second

    • @Henry-sv3wv
      @Henry-sv3wv ปีที่แล้ว

      He set timer clock= F_CPU/1024 = 15625 Hz
      That means after 15625 clocks one second of time passed.
      Timer1 is a 16bit counter and it will overflow to zero after count value: 65535 (2^16-1) (and then cause the enabled overflow interrupt)
      So if you preload the counter value to
      counter_MAX_VALUE+1-clock_counts_for_a_second_passed:
      65535+1-15625 = 2^16 - 15625 = 2^16 - (F_CPU/1024) it will overflow
      after a second. ( and i think we need to add +1 to make it right because overflow from 65535 to 0 will also consume a clk of time )
      he did make a "one off" error i think

    • @JordyDevrixOfficial
      @JordyDevrixOfficial ปีที่แล้ว

      @@Henry-sv3wv yo thanks alot mate 👍

  • @pokemettilp8872
    @pokemettilp8872 2 ปีที่แล้ว

    Second