This is a WS2812B RGB LED strip driving code for AVR (Arduino hardware). I have some issues with the compiler optimizing away parts of my code. I tried -O1, -O2, -Os
, same result.I can't use -O0
because then delays don't work.
Macros
Here is my ws_driverm.h
file:
#pragma once
#include <util/delay_basic.h>
#include <avr/io.h>
#include "lib/pins.h"
#define WS_T_1H 800
#define WS_T_1L 450
#define WS_T_0H 200
#define WS_T_0L 850
#define WS_T_LATCH 7000
/** Latch and display the RGB values */
#define ws_show(io) do { pin_low(io_pack(io)); delay_ns_c(WS_T_LATCH, 0); } while(0)
/** Send one byte to the RGB strip */
#define ws_send_byte(io, bb) do { \
for (int8_t __wsba_i = 7; __wsba_i >= 0; --__wsba_i) { \
if (bb & (1 << __wsba_i)) { \
pin_high(io_pack(io)); delay_ns_c(WS_T_1H, -2); \
pin_low(io_pack(io)); delay_ns_c(WS_T_1L, -10); \
} else { \
pin_high(io_pack(io)); delay_ns_c(WS_T_0H, -2); \
pin_low(io_pack(io)); delay_ns_c(WS_T_0L, -10); \
} \
} \
} while(0)
/** Send RGB color to the strip */
#define ws_send_rgb(io, r, g, b) do { \
ws_send_byte(io_pack(io), g); \
ws_send_byte(io_pack(io), r); \
ws_send_byte(io_pack(io), b); \
} while(0)
I'm not happy about it being macros, but all my attempts to use pointer to IO port, port address etc failed.
The io
is part of my pin handling system, just ignore it, it's not relevant for the question.
Problem
Here's the problem (in main)
When I use it with variables that are guaranteed to change, or mark them volatile, it works as expected:
volatile uint8_t r = 0;
volatile uint8_t g = 255;
volatile uint8_t b = 0;
ws_send_rgb(PIN_WS, r, g, b);
ws_show(PIN_WS);
// results in GREEN color
When the variables are not volatile, or if I just put numbers in the macro invocation, it does not work:
uint8_t r = 0;
uint8_t g = 255;
uint8_t b = 0;
ws_send_rgb(PIN_WS, r, g, b);
ws_show(PIN_WS);
// results in YELLOW color
Same result:
ws_send_rgb(PIN_WS, 0, 255, 0);
ws_show(PIN_WS);
// results in YELLOW color
Clearly the code produced by the macro is for some reason optimized away, if it's constant and zero (at least it looks that way - I'm not really sure why the LED displays yellow).
Interesting: -> If I use 1
in place of 0
for the color, it works as expected.
What is wrong with my macro, and how can I fix it? Dirty workarounds are fine, at this point.