Custom Anduril 2 fw3x-lume1 build - help with device configuration changes?

Apologies for the longish post. If anyone with Anduril expertise could have a look at the code changes below, I would much appreciate it.

Background

I recently transplanted a lume1 driver into my FW3S. However, while doing that, I managed to damage the red AUX channel connection pad on the lume1 driver board so that I can’t use it any more. I’ve tried connecting a wire directly to the associated pin on the MCU, but it’s too small and I just can’t get a wire to stay on. I don’t want to damage the MCU by trying further.

So my initial thought was that I would have a lume1 FW3S with no AUX, which is still an improvement over the original driver.

However, I’m not satisfied by this. My next thought was to do the single channel AUX mod linked to here, however that would mean going back to the 1+7+FET driver.

Inspired by that, my current idea is to add a single channel AUX by using one of the remaining undamaged RGB channels on the lume1 driver and connecting it to only one of the channels on the lume1 AUX board (which one would depend on the colour I want for my single AUX channel).

I could do this by connecting only one AUX channel and just leaving everything else as-is, but that would leave me with a somewhat wonky UI – e.g. when I set the AUX, I would be cycling through all of the RGB colours but mostly seeing nothing except for when it gets to exactly the one colour I’ve connected. That would also be unsatisfying, so I’m now thinking about a custom Anduril hex with the proper single channel AUX settings.

Anduril 2 changes

Update: See full set of changes in reply post below

I would base my custom hex on the fw3x-lume1 tree and change various lines in anduril.h and hwdef.h. I would change the files to define a single channel AUX configuration like, for example, in the Wurkkos TS10 files.

anduril/hw/lumintop/fw3x-lume1/anduril.h

Here, I would remove this part:

// this light has three aux LED channels: R, G, B
#define USE_AUX_RGB_LEDS

// the aux LEDs are front-facing, so turn them off while main LEDs are on
#ifdef USE_INDICATOR_LED_WHILE_RAMPING
#undef USE_INDICATOR_LED_WHILE_RAMPING
#endif

and replace it with:

// this light uses single aux LED channel
#define USE_INDICATOR_LED

// the aux LEDs are front-facing, so turn them off while main LEDs are on
#ifdef USE_INDICATOR_LED_WHILE_RAMPING
#undef USE_INDICATOR_LED_WHILE_RAMPING
#endif

// default aux LED to high
#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2)

I would also remove this part:

// use aux red + aux blue for police strobe
#define USE_POLICE_COLOR_STROBE_MODE
#define POLICE_STROBE_USES_AUX
#define POLICE_COLOR_STROBE_CH1        CM_AUXRED
#define POLICE_COLOR_STROBE_CH2        CM_AUXBLU

anduril/hw/lumintop/fw3x-lume1/hwdef.h

I would remove this part:

// this driver allows for aux LEDs under the optic
#ifdef FW3X_RGB_SWAP  // wiring fixed by end user
    #define AUXLED_R_PIN    PA5    // pin 2
    #define AUXLED_G_PIN    PA4    // pin 3
    #define AUXLED_B_PIN    PA3    // pin 4
#else  // Lumintop's factory wiring
    #define AUXLED_R_PIN    PA3    // pin 4
    #define AUXLED_G_PIN    PA4    // pin 3
    #define AUXLED_B_PIN    PA5    // pin 2
#endif
#define AUXLED_RGB_PORT PORTA  // PORTA or PORTB or PORTC
#define AUXLED_RGB_DDR  DDRA   // DDRA or DDRB or DDRC
#define AUXLED_RGB_PUE  PUEA   // PUEA or PUEB or PUEC

and replace it with:

// front-facing aux LEDs only on the lume1 driver Green channel
#define AUXLED_PIN    PA4    // pin 3
#define AUXLED_PORT   PORTA  // PORTA or PORTB or PORTC

However, here I am stuck with what to do with AUXLED_RGB_DDR and AUXLED_RGB_PUE, as , as I don’t understand what they are for.

Do I replace these with

#define AUXLED_DDR    DDRA   // DDRA or DDRB or DDRC
#define AUXLED_PUE    PUEA   // PUEA or PUEB or PUEC

or leave as-is, or remove?

Finally, I would change

inline void hwdef_setup() {

    ...
    
    // Main PWM, Buck Boost Enable Pin, aux R/G/B
    DDRA = (1 << CH1_PIN)
         | (1 << CH1_ENABLE_PIN)
         | (1 << AUXLED_R_PIN)
         | (1 << AUXLED_G_PIN)
         | (1 << AUXLED_B_PIN)
         ;

    ...
}

to…

inline void hwdef_setup() {

    ...
    
    // Main PWM, Buck Boost Enable Pin, single-channel aux
    DDRA = (1 << CH1_PIN)
         | (1 << CH1_ENABLE_PIN)
         | (1 << AUXLED_PIN)
         ;

    ...
}

Does that all look right?

1 Thank

I think I’ve answered this myself.

The only place in the code I can find any reference to AUXLED_RGB_DDR and AUXLED_RGB_PUE is in fsm/misc.c within an #ifdef USE_AUX_RGB_LEDS.

Since this is not defined in my changed anduril.h, I’m using #define USE_INDICATOR_LED instead, I don’t need AUXLED_RGB_DDR or AUXLED_RGB_PUE.

5 Thanks

Yep, exactly what I would do.

Also note the difference between INDICATOR_LED and BUTTON_LED - INDICATOR_LED is the correct one for what you want, e.g. this is the one used for the TS10’s single colour forward aux, while BUTTON_LED will also be used while the light is on.

1 Thank

So, after implementing this, I came across a few additional changes needed for the hex to compile.

Just in case anyone is interested or wants to do the same in future, here are the changes needed for the conversion of the fw3x-lume1 driver to single channel AUX.

After these changes the hex compiled successfully. I haven’t tested in a real light yet as I haven’t done the driver swap yet (waiting for parts). In case something else needs to be changed, I’ll add it here.


anduril.h

Before:

#define USE_AUX_RGB_LEDS

After:

#define USE_INDICATOR_LED

Before:

nothing

After:

#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2)

Before:

#define USE_POLICE_COLOR_STROBE_MODE
#define POLICE_STROBE_USES_AUX
#define POLICE_COLOR_STROBE_CH1        CM_AUXRED
#define POLICE_COLOR_STROBE_CH2        CM_AUXBLU

After:

removed


hwdef.c

Before:

#include "fsm/chan-rgbaux.c"

After:

#include "fsm/chan-aux.c"

Before:

Channel channels[] = {
    { // channel 1 only
        .set_level    = set_level_main,
        .gradual_tick = gradual_tick_main
    },
    RGB_AUX_CHANNELS
};

After:

Channel channels[] = {
    { // main LEDs
        .set_level    = set_level_main,
        .gradual_tick = gradual_tick_main
    },
    { // aux LEDs
        .set_level    = set_level_aux,
        .gradual_tick = gradual_tick_null
    }
};

hwdef.h

Before:

// allow using aux LEDs as extra channel modes
#include "fsm/chan-rgbaux.h"

After:

// allow using aux LEDs as an extra channel mode
#include "fsm/chan-aux.h"

Before:

// channel modes:
// * 0. main LEDs
// * 1+. aux RGB
#define NUM_CHANNEL_MODES   (1 + NUM_RGB_AUX_CHANNEL_MODES)
enum CHANNEL_MODES {
    CM_MAIN = 0,
    RGB_AUX_ENUMS
};

After:

// channel modes:
// * 0. main LEDs
// * 1. only single channel aux LEDs
#define NUM_CHANNEL_MODES  2
enum CHANNEL_MODES {
    CM_MAIN = 0,
    CM_AUX
};

Before:

// this driver allows for aux LEDs under the optic
#ifdef FW3X_RGB_SWAP  // wiring fixed by end user
    #define AUXLED_R_PIN    PA5    // pin 2
    #define AUXLED_G_PIN    PA4    // pin 3
    #define AUXLED_B_PIN    PA3    // pin 4
#else  // Lumintop's factory wiring
    #define AUXLED_R_PIN    PA3    // pin 4
    #define AUXLED_G_PIN    PA4    // pin 3
    #define AUXLED_B_PIN    PA5    // pin 2
#endif
#define AUXLED_RGB_PORT PORTA  // PORTA or PORTB or PORTC
#define AUXLED_RGB_DDR  DDRA   // DDRA or DDRB or DDRC
#define AUXLED_RGB_PUE  PUEA   // PUEA or PUEB or PUEC

After:

// front-facing aux LEDs only on the lume1 driver Green channel
#define AUXLED_PIN    PA4    // pin 3
#define AUXLED_PORT   PORTA  // PORTA or PORTB or PORTC

Before:

inline void hwdef_setup() {
...
    DDRA = (1 << CH1_PIN)
         | (1 << CH1_ENABLE_PIN)
         | (1 << AUXLED_R_PIN)
         | (1 << AUXLED_G_PIN)
         | (1 << AUXLED_B_PIN)
         ;
...
}

After:

inline void hwdef_setup() {
...
    DDRA = (1 << CH1_PIN)
         | (1 << CH1_ENABLE_PIN)
         | (1 << AUXLED_PIN)
         ;
}

I finally got to the point where I could test the above and, of course, the AUX LEDs didn’t work when I flashed my custom firmware with the changes above.

It took a while to find the reason, but eventually I found it in fsm/misc.c.

For posterity, and just in case someone else ends up with the same challenge, I’m describing it here.

It looks like no consideration is made for the case where a single AUX colour configuration is used with an ATtiny1634 MCU - a reasonable assumption given that the MCU supports 3-channel RGB AUX. Why would anybody want to use USE_INDICATOR_LED instead of USE_AUX_RGB_LEDS with a lume1 driver? Only those (like me) clumsy enough to damage at least one of the AUX LED pads on the driver and then be stubborn enough to want a single-AUX firmware variation to use with the damaged driver.

So, in fsm/misc.c we have:

...

#ifdef USE_INDICATOR_LED
void indicator_led(uint8_t lvl) {
    switch (lvl) {
        // FIXME: move this logic to arch/*
        #if (MCU==0x1616) || (MCU==0x32dd20)  // ATTINY816, 817, etc

        ___SOME___STUFF___
      
        #else  // MCU is old tiny style, not newer mega style

        case 0:  // indicator off
            DDRB &= 0xff ^ (1 << AUXLED_PIN);
            PORTB &= 0xff ^ (1 << AUXLED_PIN);
            #ifdef AUXLED2_PIN  // second LED mirrors the first
            DDRB &= 0xff ^ (1 << AUXLED2_PIN);
            PORTB &= 0xff ^ (1 << AUXLED2_PIN);
            #endif
            break;
        case 1:  // indicator low
            DDRB &= 0xff ^ (1 << AUXLED_PIN);
            PORTB |= (1 << AUXLED_PIN);
            #ifdef AUXLED2_PIN  // second LED mirrors the first
            DDRB &= 0xff ^ (1 << AUXLED2_PIN);
            PORTB |= (1 << AUXLED2_PIN);
            #endif
            break;
        default:  // indicator high
            DDRB |= (1 << AUXLED_PIN);
            PORTB |= (1 << AUXLED_PIN);
            #ifdef AUXLED2_PIN  // second LED mirrors the first
            DDRB |= (1 << AUXLED2_PIN);
            PORTB |= (1 << AUXLED2_PIN);
            #endif
            break;

        #endif  // MCU type
    }
}

...

For whatever reason, some dedicated settings have been added for the T1616 and AVR32dd20, but otherwise, in the #else clause, the assumption is that the single AUX channel is connected to one of the “B-side” pins on the MCU – explicitly using DDRB and PORTB. This corresponds to #define AUXLED_PIN PB2 // pin 7 in the 1+7+FET AUX mod, where the AUX channel is connected to the “spare” pin 7.

That meant that the code would not work for my single AUX configuration on the T1634 - because all three AUX channels, including the one channel I wanted to use for controlling the single AUX colour, are on the “A-side” of the MCU, specifically in my case pin 3: #define AUXLED_PIN PA4 // pin 3.

So the fix (aka hack) was to introduce an additional #if to “correct” this for the T1634 in my custom build. That looks like this:

...

#ifdef USE_INDICATOR_LED
void indicator_led(uint8_t lvl) {
    switch (lvl) {
        // FIXME: move this logic to arch/*
        #if (MCU==0x1616) || (MCU==0x32dd20)  // ATTINY816, 817, etc

        ___SOME___STUFF___
      
        #else  // MCU is old tiny style, not newer mega style

            ### NEW STUFF HERE ###

            #if (MCU==0x1634)  // For lume1-singleaux
                case 0:  // indicator off
                    DDRA &= 0xff ^ (1 << AUXLED_PIN);
                    PORTA &= 0xff ^ (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRA &= 0xff ^ (1 << AUXLED2_PIN);
                    PORTA &= 0xff ^ (1 << AUXLED2_PIN);
                    #endif
                    break;
                case 1:  // indicator low
                    DDRA &= 0xff ^ (1 << AUXLED_PIN);
                    PORTA |= (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRA &= 0xff ^ (1 << AUXLED2_PIN);
                    PORTA |= (1 << AUXLED2_PIN);
                    #endif
                    break;
                default:  // indicator high
                    DDRA |= (1 << AUXLED_PIN);
                    PORTA |= (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRA |= (1 << AUXLED2_PIN);
                    PORTA |= (1 << AUXLED2_PIN);
                    #endif
                    break;
            #else
                case 0:  // indicator off
                    DDRB &= 0xff ^ (1 << AUXLED_PIN);
                    PORTB &= 0xff ^ (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRB &= 0xff ^ (1 << AUXLED2_PIN);
                    PORTB &= 0xff ^ (1 << AUXLED2_PIN);
                    #endif
                    break;
                case 1:  // indicator low
                    DDRB &= 0xff ^ (1 << AUXLED_PIN);
                    PORTB |= (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRB &= 0xff ^ (1 << AUXLED2_PIN);
                    PORTB |= (1 << AUXLED2_PIN);
                    #endif
                    break;
                default:  // indicator high
                    DDRB |= (1 << AUXLED_PIN);
                    PORTB |= (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRB |= (1 << AUXLED2_PIN);
                    PORTB |= (1 << AUXLED2_PIN);
                    #endif
                    break;

        #endif  // MCU type
    }
}

...

Note DDRA instead of DDRB and PORTA instead of PORTB.

A learning experience for me :slight_smile:

1 Thank

…and one more update after I found out that, while the single AUX channel was working nicely on the high setting, it was not working (i.e. not turning on) with the low setting :frowning:

A quick google found me this reddit post that mentions that

Q: Just out of curiosity, how are the Aux lights currently controlled, anyway?

A: Single resistor from microcontroller pin through LED to ground. Set pin as input for LED off, set pin as input and enable internal pull-up resistor for low brightness, set pin as output (high) for high brightness.

(my emphasis)

Guessing that the PUE settings in the Anduril code have something to do with “internal pull-up resistors”, whatever they are, and then looking at the code for USE_AUX_RGB_LEDS, I made a guess that I should add settings for PUEA to my modification.

That is:

...

            #if (MCU==0x1634)  // For lume1-singleaux
                case 0:  // indicator off
                    DDRA &= 0xff ^ (1 << AUXLED_PIN);
                    PUEA &= 0xff ^ (1 << AUXLED_PIN);        ### ADDED !!!
                    PORTA &= 0xff ^ (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRA &= 0xff ^ (1 << AUXLED2_PIN);
                    PUEA &= 0xff ^ (1 << AUXLED2_PIN);       ### ADDED !!!
                    PORTA &= 0xff ^ (1 << AUXLED2_PIN);
                    #endif
                    break;
                case 1:  // indicator low
                    DDRA &= 0xff ^ (1 << AUXLED_PIN);
                    PUEA |= (1 << AUXLED_PIN);       ### ADDED !!!
                    PORTA |= (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRA &= 0xff ^ (1 << AUXLED2_PIN);
                    PUEA |= (1 << AUXLED2_PIN);       ### ADDED !!!
                    PORTA |= (1 << AUXLED2_PIN);
                    #endif
                    break;
                default:  // indicator high
                    DDRA |= (1 << AUXLED_PIN);
                    PUEA |= (1 << AUXLED_PIN);       ### ADDED !!!
                    PORTA |= (1 << AUXLED_PIN);
                    #ifdef AUXLED2_PIN  // second LED mirrors the first
                    DDRA |= (1 << AUXLED2_PIN);
                    PUEA |= (1 << AUXLED2_PIN);       ### ADDED !!!
                    PORTA |= (1 << AUXLED2_PIN);
                    #endif
                    break;
            #else
                ___ETC...___

...

That’s it. It worked! I now have a FW3A with lume1 driver and single-colour AUX LEDs (working in both low and high modes) with the proper UI for that.

Phew.

1 Thank

Thanks for sharing!