Quantcast
Channel: User Lundin - Code Review Stack Exchange
Viewing all articles
Browse latest Browse all 42

Answer by Lundin for Ring buffer for Arduino

$
0
0

Review addressing the embedded system aspects, assuming the target is Arduino/AVR 328P:

  • Implementing destructors for a class to be used in a bare metal embedded system is very fishy. If you find yourself in a situation where you need to push/pop ring buffers on the stack, you are doing something very wrong. Objects of such classes should always be allocated with static storage duration.

  • RingBuffer<100, int> buffer; is wrong in several ways - it should preferably have static storage duration as mentioned, but more importantly you shouldn't slaughter some 200+ bytes of your stack just like that. Assuming this is for AVR 328P then that's 10% out of your total RAM blown. And maybe some 50% of the stack?

    In addition, there's an old cynical rule saying that we should never allocate any buffers at all on the stack in embedded systems, because buffer overruns and stack overflows are such common bugs.

  • Embedded systems should always use the stdint.h types. This is an 8-bitter so all arithmetic should preferably be done on uint8_t integers whenever possible. You shouldn't use int which is 16 bit and also needlessly signed - signed types are dangerous to use in case they end up in bitwise arithmetic, as is common in embedded systems. Getting rid of int and limiting the max size of the ring buffer to at most 255 will speed up this code considerably.

  • As mentioned in other reviews, any decent ring buffer comes with a "thread-safety" option. In this case interrupt safety, since ring buffers are most commonly used when communicating between for example an UART rx ISR and the UART driver.

    There's a common misconception that the size of variables vs data size of the CPU somehow matters for atomicity. That's plain wrong, C++ code can end up non-atomic even if doing 8 bit access on a 8 bit CPU. You need to use the actual atomic feature (C++11 only?) or inline assembler, or the variables cannot be assumed to be atomic. More info here: https://electronics.stackexchange.com/a/409570/6102.

    The most common way to prevent race conditions in ring buffers is simply to accept a pointer to an interrupt enable register and a mask. So if the UART driver is to utilize the ring buffer, it would pass along a volatile pointer to the UART rx enable/disable register and the ring buffer can simply shut off the interrupt. In the specific case of UART, the data is very slow compared to the program execution, so disabling the interrupt for a few microseconds won't even lead to data loss. Or in case you need tougher real-time than that, you shouldn't be using classes in the first place.

  • Bare metal systems don't return from main(). Who would they return to? You need to have an eternal loop in main(), otherwise you'll just generate pointless bloat return code that chews up stack and flash needlessly. Ideally embedded systems use the implementation-defined form void main (void) but unfortunately there's a misguided PC programmer rule in the C++ standard saying that if a program defines a function main() it must return int. Freestanding systems are not exempt from this rule for reasons unknown. You can avoid this C++ language design flaw by using gcc for AVR and compile for embedded systems with -ffreestanding. (The same option works in C too.)

    To illustrate, here's the code with extra bloat generated by incorrect form int main() with return:

      main:      push r28      push r29      in r28,__SP_L__      in r29,__SP_H__      ldi r24,0      ldi r25,0      pop r29      pop r28      ret

    And here's the code generated by correct form void main (void) enabled with -ffreestanding and then an eternal loop:

      main:      push r28      push r29      in r28,__SP_L__      in r29,__SP_H__  .L2:      rjmp .L2

    (It's weird that they set the SP from main() but that's another story...)


Viewing all articles
Browse latest Browse all 42

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>