-2

I'm trying to program an Arduino Due to PWM a LED matrix by turning the LEDs on and off very quickly. In order to control brightness I want to add extra instructions between the on and off states of the LEDs. The brightness should be set by a preprocessor variable. The Arduino has a 84MHz Cortex-M3 ARM processor.

This is a simplification of how my code currently increases the brightness:

uint8_t volatile dummy = 0;
uint8_t i;

for (i=0;i<1<<current_layer;i++) { // every next layer has double the amount of pulses
    LED_STATE = ON; // several pulses in one go speeds up the for loop
    dummy = 0; // increases ON-time
    LED_STATE = OFF;
    LED_STATE = ON;
    dummy = 0; 
    LED_STATE = OFF;
    LED_STATE = ON;
    dummy = 0; 
    LED_STATE = OFF;
    LED_STATE = ON;
    dummy = 0;
    LED_STATE = OFF;
}

Now I want to be able to increase the brightness based on a preprocessor variable like so:

#define BRIGHTNESS 2 
// inside loop
        LED_STATE = ON; // several pulses in one go speeds up the for loop
        #if BRIGHTNESS > 0
        dummy = 0; // increases ON-time
        #if BRIGHTNESS == 2
        dummy = 0; // increases ON-time even more
        #endif
        #endif
        LED_STATE = OFF;
        LED_STATE = ON;
        #if BRIGHTNESS > 0
        dummy = 0;
        #if BRIGHTNESS == 2
        dummy = 0;
        #endif
        #endif
        LED_STATE = OFF;
        LED_STATE = ON;
        #if BRIGHTNESS > 0
        dummy = 0;
        #if BRIGHTNESS == 2
        dummy = 0;
        #endif
        #endif
        LED_STATE = OFF;
        LED_STATE = ON;
        #if BRIGHTNESS > 0
        dummy = 0;
        #if BRIGHTNESS == 2
        dummy = 0;
        #endif
        #endif
        LED_STATE = OFF;

As you can see, this makes the code very unreadable. I would like to define a preprocessor macro that adds these dummy statements based on the value of BRIGHTNESS.

This is how the code should look like:

#define BRIGHTNESS 2 
#define B1 ... // adds dummy=0; when BRIGHTNESS > 0 or else nothing at all
#define B2 ...
#define B3 ...
#define B4 ...
// inside loop
        LED_STATE = ON;
        B1 B2 B3 B4 // adds a number of dummy statements based on the value of BRIGHTNESS
        LED_STATE = OFF;
        LED_STATE = ON;
        B1 B2 B3 B4
        LED_STATE = OFF;
        LED_STATE = ON;
        B1 B2 B3 B4
        LED_STATE = OFF;
        LED_STATE = ON;
        B1 B2 B3 B4
        LED_STATE = OFF;

Even better would be a function that inserts those statements based on a variable:

#define ADD_DUMMIES ...
// inside loop
        LED_STATE = ON;
        ADD_DUMMIES(BRIGHNESS)
        LED_STATE = OFF;

How would I define preprocessor macros so that they insert dummy statements based on the value of BRIGHTNESS?

Arafangion
  • 11,517
  • 1
  • 40
  • 72
uzumaki
  • 1,743
  • 17
  • 32
  • Why don't you use regular `if` statements?? – DimChtz Aug 02 '17 at 23:21
  • @DimChtz How do if statements improve readability? – uzumaki Aug 02 '17 at 23:23
  • If you are intending on having a changing brightness on the LED, why is it a constant? Did I miss something? – Easton Bornemeier Aug 02 '17 at 23:23
  • @uzumaki That was a question not an answer. – DimChtz Aug 02 '17 at 23:23
  • Why don't you use hardware PWM? Or, if you want software PWM, you can use timer interrupt. – devalone Aug 02 '17 at 23:24
  • @uzumaki I was talking about this `#if BRIGHTNESS > 0` ...etc Why did he use `#if` instead of regular `if` statements in the first place. – DimChtz Aug 02 '17 at 23:26
  • @EastonBornemeier The BRIGHTNESS variable is supposed to set the overall brightness before compiling the code. – uzumaki Aug 02 '17 at 23:26
  • @DimChtz The line of code "dummy = 0;" should only be compiled when the preprocessor variable BRIGHTNESS is set accordingly. – uzumaki Aug 02 '17 at 23:29
  • Beware of compiler optimizations. Some compilers may remove dummy statements. Have you considered decrementing or incrementing a volatile (static volatile) variable for a delay? You may want to use a `for` loop or call an *inline* function. The inline function could change content based on your PWM rate (I think this would be a better fit). – Thomas Matthews Aug 02 '17 at 23:32
  • @ThomasMatthews dummy is declared as volatile, I thought this would be enough. Anyway it does work, as I tested it. I can change the statement later on. – uzumaki Aug 02 '17 at 23:35
  • Arduino has very accurate clock, why do you want to use dummy instructions? Really, consider using timer interrupts. Something like this http://www.avrfreaks.net/forum/timer-interrupt-arduino-due I don't have arduino to test, so google it – devalone Aug 02 '17 at 23:38
  • @devalone I know what I'm doing. I only need help to improve readability with preprocessor macros. – uzumaki Aug 02 '17 at 23:41
  • I think you may be over-complicating things here. A decent compiler should unroll a `for` loop with constant bounds. For example `for (int count = 0; count < BRIGHTNESS; count++) {dummy = 0;}` should resolve to `dummy = 0; dummy = 0; dummy = 0; dummy = 0;` for `BRIGHTNESS` of 4, – user4581301 Aug 02 '17 at 23:54
  • @user4581301 It looks a bit cryptic but it would work, if the compiler does unroll it. – uzumaki Aug 02 '17 at 23:58
  • In this I must say our definitions of cryptic differ greatly. If you want assurances that it will be unrolled, take a look at [template metaprogramming for loops](http://www.cs.rpi.edu/~musser/design/blitz/meta-art.html). That smurf meets my definition of cryptic. A note on the link: the writer [illegally prefixes with underscores](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). Copy the intent. Don't copy the style. – user4581301 Aug 03 '17 at 00:20
  • Out of curiosity, which compiler are you using that doesn't optimise away those obvious no-ops? – Arafangion Aug 03 '17 at 01:45
  • @Arafangion dummy is declared as volatile. – uzumaki Aug 03 '17 at 03:56
  • @uzumaki: But he doesn't read from it - I thought volatile only prevented optimisations for *read*? – Arafangion Aug 03 '17 at 06:19

1 Answers1

0

This is how the dummy = 0; statements can be added with the help of the preprocessor:

#define BRIGHTNESS 2
#define _GETFOO(n) _FOO ## n
#define ADD_DUMMIES(n) _GETFOO(n) ()

#define _FOO0()
#define _FOO1() dummy = 0;
#define _FOO2() dummy = 0; dummy = 0;
#define _FOO3() dummy = 0; dummy = 0; dummy = 0;
#define _FOO4() dummy = 0; dummy = 0; dummy = 0; dummy = 0;

uint8_t volatile dummy = 0;
// inside loop
        LED_STATE = ON;
        ADD_DUMMIES(BRIGHTNESS)
        LED_STATE = OFF;
        LED_STATE = ON;
        ADD_DUMMIES(BRIGHTNESS)
        LED_STATE = OFF;
        LED_STATE = ON;
        ADD_DUMMIES(BRIGHTNESS)
        LED_STATE = OFF;
        LED_STATE = ON;
        ADD_DUMMIES(BRIGHTNESS)
        LED_STATE = OFF;

The compiler inserts the same store instruction as many times inbetween the lines as the value of BRIGHTNESS dictates, as long as it is within the boundaries.

uzumaki
  • 1,743
  • 17
  • 32