Interrupt Safe Ring Buffer :: Bare Metal Programming Series 6

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/lowbyteproductions...

Пікірлер: 26

  • @vic0703
    @vic07034 ай бұрын

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

  • @BigA1
    @BigA110 күн бұрын

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

  • @michaelmichelotti460
    @michaelmichelotti460 Жыл бұрын

    Love the series, keep it up!

  • @faust-cr3jk
    @faust-cr3jk5 ай бұрын

    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.

  • @nitpal9958
    @nitpal99583 ай бұрын

    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.

  • @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

    Жыл бұрын

    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.

  • @randomusername69421
    @randomusername694219 ай бұрын

    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

    7 ай бұрын

    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.

  • @GeorgeBratley
    @GeorgeBratley Жыл бұрын

    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.

  • @MrHaggyy
    @MrHaggyy7 ай бұрын

    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.

  • @nathantron
    @nathantron Жыл бұрын

    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!

  • @aabramek
    @aabramek3 ай бұрын

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

  • @nhanNguyen-wo8fy
    @nhanNguyen-wo8fy3 ай бұрын

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

  • @vdg83
    @vdg839 ай бұрын

    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

    9 ай бұрын

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

  • @AliceErishech
    @AliceErishech Жыл бұрын

    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

    Жыл бұрын

    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

    10 ай бұрын

    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".

  • @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.