Interrupt Safe Ring Buffer :: Bare Metal Programming Series 6

Поделиться
HTML-код
  • Опубликовано: 20 окт 2024
  • In this episode of the bare metal programming series, we're building a ring buffer to back our UART driver. This buffer comes with a set of operations and properties that make it safe and consistent to use from both the main code and interrupt routines.
    =[ 🔗 Links 🔗 ]=
    🎥 Series Playlist: • Blinky To Bootloader: ...
    🗣 Discord: / discord
    ⭐️ Patreon: / lowleveljavascript
    💻 Github Repo: github.com/low...

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

  • @lorito6995
    @lorito6995 День назад

    Many thanks for the series, I am learning so many interesting things

  • @xp_pk
    @xp_pk 5 дней назад

    I wish I could fulfill my course requirements this semester just by doing the Bare Metal Programming Series. Completing the series would be an incredible learning experience (and great resume project) that would teach me orders of magnitude more about embedded systems and how computer systems actually work than my entire packed semester of courses. I basically have to wait to graduate if I want to learn anything actually useful because I'm so busy doing meaningless lab assignments filled with grammar mistakes, poor programming practices, and written by instructors who seem to have forgotten that labs are supposed to teach you something rather than just tell you to do something.

  • @faust-cr3jk
    @faust-cr3jk 9 месяцев назад

    I know this is quite old video and I am not sure if you still check for new comments, but I decided to give it a try anyway.
    Please imagine the following case
    - One byte in a ring buffer (read and write indices set to 1)
    - Two readers
    Reader A executes the first line of ring_buffer_read routine (line 15 of ring-buffer.c) and then gets preempted by reader B. In such case, both, reader A and B set their local_read_index to 0. local_write_index will be set to 1. So both readers will believe that the righ buffer is not empty and eventually end up with reading the same byte twice.

  • @randomusername69421
    @randomusername69421 Год назад

    I saw you writing the incorrect sign and It was fun waiting for you to find the bug
    Anyway cybersecurity analyst and software developer just discovering embedded systems here .. and I’m really impressed by your work .. keep it up 🎉

    • @MrHaggyy
      @MrHaggyy 10 месяцев назад

      And i'm an embedded engineer who is getting into safety and security.
      He does a really good job. Mentioning all those edgecases he wont cover but might be relevant. For example multiple writer to an error handler buffer or an diagnostic system is something that merges embedded and security.

  • @vic0703
    @vic0703 7 месяцев назад

    You did a great job in this series ! Thanks a lot !

  • @GeorgeBratley
    @GeorgeBratley Год назад +2

    Really glad you're doing this series in C - I'm somebody who only ever really programs in high level languages like Javascript/Typescript and Python, and it's really helping to demystify a lot of C concepts for me.

    • @LowByteProductions
      @LowByteProductions  Год назад

      Glad to hear it George. C definitely has a few tricky parts, but IMO with the right framing for people who already have a lot of experience in other languages, it's pretty easy to pick up. Especially in this context, where all memory is statically allocated.

  • @cleightthejw2202
    @cleightthejw2202 Год назад

    @Host
    Yes, that is extremely interesting to me. I am absolutely looking forward to seeing those videos on making packets and impleenting/checking them.
    I'm all kinds of ecstatic! :)

    • @LowByteProductions
      @LowByteProductions  Год назад +1

      Rally glad to hear it. The packet protocol is one of the most fun parts of the project, and probably also the one that you can tweak and experiment with the most too.

  • @MrHaggyy
    @MrHaggyy 10 месяцев назад

    Great video. Would love to see you go further with this.
    With the RING_BUFFER_SIZE comment i thought quite a bit about the correct wording. The way this stuff is tought here in germany: "for a cycle time of 10ms" makes sense. In practice and for myself i prefer: "// 10ms cycle at 9600 baud" This gives you the time as the most important information first, and with the baud rate in second you know what's the buffer is for.
    In C++ i have an implementation that takes baudrate and cycle time to calculate those things in the preprocessor. Great to build systems fast, but you should switch to fixed size to keep the sanity of your coworkers i guess.

  • @michaelmichelotti460
    @michaelmichelotti460 Год назад

    Love the series, keep it up!

  • @aabramek
    @aabramek 6 месяцев назад +1

    shouldn't ring buffer stucture be marked as volatile since it is accessed and modified from both interrupt routine and main loop ?

  • @gabrielwong1991
    @gabrielwong1991 2 месяца назад

    How do you do multiple changes like adding brackets with multiple functions together in VS Code?

  • @BigA1
    @BigA1 3 месяца назад

    Feel like I want to say a lot - but will just say 'Well Done'

  • @nitpal9958
    @nitpal9958 6 месяцев назад

    Correct me if I am wrong:
    1. Ring Buffer solves (or rather avoids) the "race condition problem" because there is no shared variable (like data_available) between the reader and the writer of the buffer. And because the reader and writer don't "race" for accessing the shared variable, the race condition is avoided.
    2. Ring Buffer solves the "problem of needing more space" by simply providing a bigger buffer. This essentially buys the Firmware more time in between accesses to data received at the UART RX pin.

  • @ltlt6117
    @ltlt6117 2 месяца назад

    Hi how I can move or copy data from a 16bit buffer to an 8 bit buffer?

  • @nathantron
    @nathantron Год назад +1

    If I may recommend. Try taking a breath every now and then, give people a second to process, and while you do that, take a drink. It will help you with your coughing and make things a bit more processable and smoother on the timing.

    • @LowByteProductions
      @LowByteProductions  Год назад

      Appreciate the feedback. Thanks for taking the time to lay it out!

  • @vdg83
    @vdg83 Год назад

    Thank you for this fantastic series!
    A question in ring_buffer_read( ) about the need for local_read_index: If we were to have multiple consumers, wouldn't each consumer have its own ring_buffer_t structure, pointing to the same buffer but with its own unique read_index? If so, then it seems to me that there would be no read collisions and hence the copy of read_index into local_read_index could be eliminated.

    • @LowByteProductions
      @LowByteProductions  Год назад +1

      The thing is, once you start bringing in the idea of more consumers or producers, the semantics break down.

  • @SaboteurPro
    @SaboteurPro Месяц назад

    You helped me a lot with your video!
    Like and subscription is out!

  • @AliceErishech
    @AliceErishech Год назад +2

    Isn't "if (length == 0)" still not correct behavior for "uart_read()"? Unless I misread your code, if length is somehow negative then it'll return length when 0 seems to be your intended failure value. It might not end up making an actual difference but it at the very least seems to make your code a bit more ambiguous. If you're only checking for "length == 0" then it seems to just be extraneous code since if you removed that check then you should get the same behavior you get with the way it's currently written since simply running through the loop with a length of 0 would end up returning a 0 regardless.
    On that note, glad to see that I'm not the only one who occasionally makes a one-character error and then spends far longer than it should trying to hunt it down.

    • @LowByteProductions
      @LowByteProductions  Год назад +1

      You're totally right - the length check against 0 is extraneous, and I wouldn't be surprised if the generated code was *exactly* the same when removing it.

    • @magnusosterlind5107
      @magnusosterlind5107 Год назад

      I think comparing against 0 is the correct thing to do here, because the length variable is unsigned, so it can never be negative. I also think this is why the compiler was optimizing everything out - it saw the condition "if (length > 0) return 0", which would return 0 in every case apart from the case where length is 0, but then it also saw that in the "length == 0" case the function should also return 0, so it just optimized everything to "return 0".

  • @nhanNguyen-wo8fy
    @nhanNguyen-wo8fy 7 месяцев назад

    4:38 race condition problem
    17:50 ring buffer.h

  • @angryman9333
    @angryman9333 Год назад

    Galaxy brain

  • @nurmohammed9642
    @nurmohammed9642 Год назад

    Is there any chance to use Rust 🦀instead of C ?

    • @LowByteProductions
      @LowByteProductions  Год назад

      It's possible! There are some projects out there working to get rust code running for STM32s and ARM Cortex-M chips in general (docs.rs/stm32f4/latest/stm32f4/ is one). I can't speak to how far along these projects are, or how much of the surface area of the chip is covered, but I bet with some work you could get it up and running. Let me know if you follow along in rust, I'd love to see that!

    • @nurmohammed9642
      @nurmohammed9642 Год назад

      ​ @LowByteProductions ​How about calling C (libopencm3) from Rust
      You can use cbindgen library to generate bindings from C header file.