Has anyone here used AI to write firmware for their flashlights?

I just asked grok if it could write me code for flashlight firmware. It said yes. Then asked me this…

“”““Let me know what behavior you want (e.g. 3 modes + moon, long-press strobe, low voltage shut-off, memory, etc.) and I can give you a more tailored version. Also tell me whether you use a power MOSFET or AMC7135 chips — that sometimes affects PWM polarity or frequency choice.””“”

So I asked for 2 modes using 7135 chips. 100% and Tactical Strobe.

Here is what it wrote.

“”“”"Here’s a tailored ATtiny13(A) firmware for your flashlight driver using AMC7135 chips.Key features:2 modes: Mode 0: 100% (full brightness, PWM = 255)
Mode 1: Tactical strobe (~13–15 Hz, 50% duty cycle) — common for disorienting effect without being annoyingly fast.

Switching: Short press to cycle modes (100% → strobe → off → 100% …)
Off: Long press (>0.4 s) to turn off from any mode
No mode memory (starts off on power-up/reset)
PWM on PB1 (standard for most 7135 drivers like Nanjg/Qlite)
Button on PB0 (active low, internal pull-up)
Debounce and basic long-press detection
Assumes factory fuses (~1.2 MHz internal, or set to 1 MHz if you changed prescaler)
For AMC7135 drivers, PWM is non-inverting — higher OCR0B value = brighter (0 = off, 255 = full on). That’s standard in almost all 7135-based firmwares

Code it wrote.

// ======================================================================
// ATtiny13(A) 2-mode flashlight driver for AMC7135
// Modes: 100% constant  +  Tactical strobe (~13-15 Hz)
// Short click: next mode   Long press (>400 ms): off
// PB0 = button (to GND, active low)
// PB1 = PWM to AMC7135 chain
// Compile: avr-gcc -mmcu=attiny13 -Os -DF_CPU=1200000UL -o fw.elf main.c
// ======================================================================

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define BTN_PIN     PB0
#define PWM_PIN     PB1

// Tactical strobe: ~13-15 Hz (common tactical range), 50% duty
#define STROBE_ON_MS   35
#define STROBE_OFF_MS  35
#define STROBE_PERIOD  (STROBE_ON_MS + STROBE_OFF_MS)  // ~70 ms → ~14.3 Hz

// Long press threshold (ms)
#define LONG_PRESS_MS  400

// PWM values (0-255)
#define PWM_FULL       255
#define PWM_OFF        0

volatile uint8_t mode = 0;          // 0 = off, 1 = 100%, 2 = strobe
volatile uint8_t need_update = 1;   // flag to update PWM/strobe in main loop

// Simple non-blocking delay helper using timer (but we use _delay_ms mostly)
static inline void debounce_delay(void) {
    _delay_ms(25);
}

int main(void) {
    // Setup I/O
    DDRB  = (1 << PWM_PIN);              // PB1 output (PWM)
    PORTB = (1 << BTN_PIN);              // PB0 pull-up for button

    // Timer0: Fast PWM, non-inverting on OC0B (PB1), prescaler /1
    TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);  // Fast PWM mode 7
    TCCR0B = (1 << CS00);                                   // prescaler 1
    OCR0B  = PWM_OFF;                                       // start off

    // Enable global interrupts (for future pin-change if you want wake from sleep)
    sei();

    while (1) {
        // Button handling
        if (bit_is_clear(PINB, BTN_PIN)) {          // button pressed
            debounce_delay();

            uint16_t hold_time = 0;
            while (bit_is_clear(PINB, BTN_PIN)) {   // wait for release or long press
                _delay_ms(10);
                hold_time += 10;

                if (hold_time >= LONG_PRESS_MS) {
                    // Long press → force off
                    mode = 0;
                    need_update = 1;
                    // Wait for release to avoid immediate re-trigger
                    while (bit_is_clear(PINB, BTN_PIN)) {
                        _delay_ms(5);
                    }
                    _delay_ms(200);  // extra anti-bounce
                    break;
                }
            }

            if (hold_time < LONG_PRESS_MS) {
                // Short press → next mode
                mode = (mode + 1) % 3;   // 0→1→2→0...
                need_update = 1;
                _delay_ms(200);          // debounce / prevent double click
            }
        }

        // Update output when mode changes
        if (need_update) {
            need_update = 0;

            if (mode == 0) {
                OCR0B = PWM_OFF;
            }
            else if (mode == 1) {
                OCR0B = PWM_FULL;        // 100%
            }
            // mode 2 = strobe handled in loop below
        }

        // Strobe logic (runs continuously when mode==2)
        if (mode == 2) {
            OCR0B = PWM_FULL;
            _delay_ms(STROBE_ON_MS);
            OCR0B = PWM_OFF;
            _delay_ms(STROBE_OFF_MS);
        }
        else {
            // In non-strobe modes, just idle/sleep if you want lower power
            // But for simplicity we busy-wait here (tiny code size)
            _delay_ms(10);   // small sleep-like delay
        }
    }

    return 0;
}

Usage notes:Short click: cycles off → 100% → strobe → off …
Long press (hold ~0.4–0.5 s): turns off immediately from any mode
Strobe is ~14 Hz (adjust STROBE_ON_MS / STROBE_OFF_MS if you want faster/slower; 10–20 Hz is typical “tactical”)
Code is ~400–500 bytes compiled — plenty of room to add low-voltage protection later (ADC on PB2/3/4)

Possible improvements you might want next:Add low-voltage warning/shutdown (read ADC)
Mode memory (save last mode in EEPROM)
Different strobe frequency or random strobe
Moonlight mode as mode 0
Reverse polarity protection reminder (common in 7135 boards already)

Let me know if you want any of those added, or if the strobe feels too fast/slow after testing! Also, if your switch is momentary vs. latching, or if you prefer different UI (e.g. double-click for strobe), just say. Good luck with the build!“”“”"

we are surely handing over all our keys to the kingdom…

1 Thank

It appears so.

1 Thank

to reference American Dad…“soooooo…anyone heard aaaannnnything about some laaauunnnchhh coooooooodes??”

1 Thank

After a few years of AI being around, specifically generative LLMs for code, what I’ve found is…

It can produce pretty decent working code, but there are some pretty major caveats and limitations and requirements. If you ask it for something trivial, or you know what you’re doing and give it a pretty decent design to start with, and have a pretty robust testing infrastructure to verify correctness, it can eventually produce pretty good results. But if you ask it for something non-trivial and you don’t know what you’re doing or don’t give it a good design to start with, and don’t have good testing infrastructure, it’ll typically produce garbage. Garbage in, garbage out, as they say. Bad prompts produce bad results.

More specifically…

  • It tends to hallucinate a lot, making things which don’t work or depend on things which don’t exist. So it’s very important to have robust testing, to discover and report these errors, so they can be fixed.
  • You really cannot trust anything it says, because it will very confidently and cheerfully just make stuff up. And most models are tuned to be sycophantic and agree with you even when you’re wrong. So you have to verify ALL of it… which tends to take a lot of time.
  • It’ll happily produce egregious amounts of repetitive low-level code instead of building the higher-level abstractions which are the hallmark of good code. So you’ll typically need to do most of the design and architecture work yourself. And that’s the hardest part. Getting it right requires a good understanding of computing at both a high and low level, and a lot of experience.
  • It will often make very unusual decisions which lead to bizarre and unexpected bugs that you wouldn’t even think to test for. So even with robust tests, there is still a high risk of serious problems.
  • Doing anything non-trivial typically will require a paid subscription to a premium model, or ideally to multiple premium models so they can consult with each other, and the fees can get quite expensive very quickly.
  • Even premium models have a knack for failing to understand the design of a system, and writing code which goes directly against that design. So expect to have to throw away the results on a regular basis and try again.
  • While most AIs today start out sounding pretty coherent, the coherence falls off the longer you interact with it. It often doesn’t take long for it to go completely off the rails… especially when using free models.
  • Even with thorough testing, the results still require an awful lot of time and effort to review and understand the code. You can reduce this somewhat by having a second AI do the initial reviews, but at some point the operator still has to do it. And the review process can often be more work than just writing the whole thing yourself.

When using AI to write code, the overall development process still involves a lot of writing code yourself. It’s just that you write the code in a different language, like English mixed with pseudo-code, instead of writing it in an actual programming language. And English isn’t designed for this, so it’s often easier to express concepts clearly in real code form… at which point you’re literally just writing the code yourself.

The process of writing a useful prompt (i.e. asking a good question) will often give you answers before you even press “send”. So it’s frequently not necessary to even use the AI. But this process already has a name… “rubber duck debugging”. It is called that because you can get the same benefit by simply explaining your problem to a rubber duck, wherein the process of describing the issue allows you to realize what the answer is.

But, all that said, it can be pretty useful for letting the programmer focus at a more architectural level, and use the LLM just as a tool for translating detailed designs into actual code. It helps if you think of it like translating from English to French, or otherwise translating between two languages, where the input must be good in order to get a good output. It’s good at finding idiomatic ways to rephrase complete messages in a different language. But it’s not so good at making things up entirely on its own… that’s how you get slop.

Basically, you just can’t be like “write me a story about whales and make it good”. You have to give it a copy of Moby Dick and ask it to translate it into a new form.

Or you can ask it only for really simple things, and it’ll typically do okay with those types of tasks. This makes it really handy for noobs learning a new language, new library, etc. It’s great at the sort of simple one-shot question people traditionally would ask on Stack Overflow. It just tends to fall apart when attempting more complex and ongoing tasks.

8 Thanks

Nicely put ToyKeeper. I’ve never really been an adopter of AI, but thought I would see what it would do with c code.
It did prompt me for changes and even asked if I wanted to show it a known working c file to reference. I even uploaded a hex file and it told me what all of the features of that code were in flashlight terms. Interesting stuff. But, garbage in/out for sure.

I hear that Claude is one of the better AI chatbots for writing code.
That said, I haven’t used Claude yet.
I have used ChatGPT to write code, and ChatGPT makes mistakes practically non-stop when writing code.

1 Thank

Hue Driver is 100% Claude Code as an experiment, but it was a rough journey…

All gestures, hue math and short press detection/state holding code were implemented by Claude with very strict instructions, supervision and interruption when things got too complicated with no reason. (Happened all the time)

It could get even VCC and Temp monitoring/throttling working using only Attiny85 internal features, with no external components as I planned, neat!!

It works but you need very clearly defined unit tests and goals, the AI can and WILL mess everything up VERY quickly without this.

3 Thanks

I don’t want to quote the entire answer, but I agree on almost every word of this analysis.
Things can go out of rails pretty quickly, even while they appear to be progressing good!
You have to cover every aspect with tests that you described in details, and be very clear with your requirements or the AI will just make them up.

In summary based on my experience:

  • Claude code is very capable of modifying and even adding some features on open source FW’s to create new variations. AI’s can just pick a reference from either web or training to start with.
  • It can write a full FW, but someone need to drive it very carefully and will not be that magically fast.
3 Thanks