STAR Firmware by JonnyC - Source Code and Explanation

Nice work Richard! Seems like that could work for JW980 too.

Thanks a lot to all of you, who provided code and let us, who can’t code from scratch, participate in this.

JonnyC, especially your commenting is truly helpful. Last time I coded on my own was back in the 80’s and I never have fiddled with C before. But I now I can just try to understand what is there and then adapt it.

I’m very happy with the shutdown-option (when using unprotected cells) but what truly got me hooked was when you came up with off-time memory.

I used a 100nF capacitor - which was the closest I could find in my boxes - between Star 4 and ground.

That worked surprisingly well (cap_threshold still 100) and even gave a reasonable switch-time. Memory kicked in at about what feels less than a second or so. I ordered some 1uF capacitors, so I can follow your path and settings.

Thx
HQ

Being completely new to programming ATtiny, coding C and using Atmel studio, I ran into several situations which I like to share for others, to whom all this is unknown territory as well.

  • The programmer from Fasttech (SKU 1002900) works.
  • I took a SOIC clamp from ebay, see pic above, and changed the connector. The single lines of the cable had to be adapted, the link to flashlight-wiki in the OP helps a lot, as do TomE and Sirius9 in this thread.
  • I needed to install the USBasp driver that is mentioned on flashlight-wiki. Just copying the missing libusb.dll to the avrdude directory or a windows directory was not enough. With this driver avrdude can now reach the MCU.
  • The clamp sometimes does not make contact to the ATtiny13A for several tries, but it always does in the end.
    I position the clamp not too tight to the board but slightly higher. Then I gently rotate the clamp back and forth and test with avrdude again and again until it has contact.
  • I googled for Atmel Studio 5.1 and found an installation file (“as5installer-stable-5.1.208-full.exe”) that is 631.208.120 bytes in size. It installed and works fine to load, change and compile the code. Comfy’s brilliant howto must have saved me an hour at least.
  • I first changed the code using windows-editor. Line-break gave very interesting results when compiling and I had to start over again. I now change the code in Atmel studio, but turning off line-break might help as well…
  • Don’t fiddle with fuses unless you know what you are doing. I did (fuse 78), it cost me a driver. I then found a ‘fuse calculator’ on this website which explaines a lot.
    This is what I believe to have understood: Fuses are 2 bytes of basic settings which will not be changed by the code itself. Important for us is the MCU frequency, which should correspond to #define F_CPU. So low fuse is 75 for 4800000 and 7A for 9600000. No other low fuse should be necessary.
    Low fuse 79 is like 75 but only with one setting changed: the start up time (SUT) from +4ms to +64ms. I believe this is not relevant for our use, so fuse 79 simply works as well.

greetings
HQ

Excellent work HQ, and thanks for sharing your experience!

“How do you access turbo, or does it always turn on to turbo and step down until the next time you turn it on?”

Turbo is accessed just as with the original code, so yes - always turns on in turbo and steps down until the next time I turn it on.

Here’s what I did with the code:

Set the modes as follows:

#define MODE_LOW 25
//#define MODE_MED
#define MODE_HIGH_W_TURBO 135
//#define MODE_HIGH
#define MODE_TURBO 255

Under “#ifdef MODE_TURBO”, changed the line “PWM_LVL = modes[—mode_idx];” to “PWM_LVL = 175;”

So, in effect - it cycles through 25-135-255-25-135-etc. normally, just like a normal 3-mode driver.

BUT - if left to time-out at 255 (turbo), it drops to 175. Following an off/on cycle it returns to 255 and starts the timer again. Otherwise the 175 level is skipped when cycling through modes. This is with memory enabled, of course.

I suppose that with no memory and L-H mode order, an off/on cycle following turbo time-out would cause it to go to low mode, and cycling through modes would be the same as with memory.

I’ve been using my EDC set up this way for about a week now, and I think I like it (so far).

Thanks,
-JW

Looks like you got it!

Yup, correct.

So it’s a low, med, turbo w/timeout fallback to high…low, med, turbo w/timeout fallback to high
9.8, 52.9, 100% w/ fallback to 68.6%, that is of course having star 4 soldered down, I kinda like the Hi -> Lo function myself (of soldering down star 3), but yours is quite nice too!

fyi, I'm using Atmel Studio 6.2 BETA now, no probs, here: http://www.atmel.com/tools/atmelstudio.aspx

Well, I’ve managed to get single-mode operation (capable of signaling) with 1-minute turbo step-down and ADC_CRIT warning/cutoff, but can’t seem to get ramping-down on ADC_LOW.

Still trying, though.

I just thought a configuration like this would be good for a hard-driven C8 that doesn’t normally need to be multipurpose like an EDC.

-JW

Whoops, major bug in the off-time firmware that disabled low battery detection when compiled without a turbo mode (disabled WDT which caused it to never wake up from its sleep state). Will have the fixed code up on my site soon in case anyone downloaded it yet.

Cool. STILL haven't gotten around to trying it! Been trying to catch up on everyone's orders...those take priority over tinkering time these days. I will also share my multi-group code, different turbo stepdown code, etc. once I get it cleaned up so that it doesn't look so...um...crazy. I don't really know what I'm doing but sometimes I get lucky and make something new work!

How do I post code?

When I try copy/paste, several parts will disappear with save/preview:

  • some brackets and what’s inside,
  • double ‘=’
  • line breaks missing

Can someone give me a hint please?

Thx
HQ

Probably best to upload the file to google docs or something similar then share it, that way we can all see the exact same thing you see. I also think that pastebucket is a good solution.

Use “pre” and “/pre” tags around the pasted part (substitute quotes for angle brackets, of course)

That works fine, thx!

As a workaround I comment out turbo and activate WDT by default. Voltage Monitor still works that way.

// #define MODE_TURBO
...
// Don't even bother turning on the WDT if turbo is not enabled
// #ifdef MODE_TURBO
WDT_on();
// #endif

I just tried removing all parts with turbo and turbo timeout - at the moment I don’t need both - which seems to work, but I don’t understand this segment:

ISR(WDT_vect) {
    static uint8_t ticks = 0;
    if (ticks < 255) ticks++;
#ifdef MODE_TURBO   
    if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
        PWM_LVL = modes[--mode_idx];    // Turbo mode is always at end
    }
#endif
}

What function has the ISR-part (first 3 lines (and last bracket))? If I don’t need turbo and turbo timeout, I can remove lines 4-8, but if I remove the ISR-part as well, the voltage monitor is again gone.

Thx for your kind help.
HQ

Harley,

You discovered the same issue I did :) See the "sleep_mode()" at the end of the file? That will trigger the driver to power down until the WDT wakes it back up (within .5 seconds), which is set up with this code:

// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
// Will allow us to go idle between WDT interrupts
set_sleep_mode(SLEEP_MODE_IDLE);

If the WDT or associated ISR is disabled, then it will never wake up and never check the voltage level. We really could remove the "sleep_mode()" at the end, but then there would be no waiting between battery level checks - it would do 8 in rapid succession. What I just realized now is that it might take up to 4 seconds for the initial low battery check, which actually might be good so that if you turn the light on it won't ramp down immediately. I guess I didn't intend this, but it worked out. I never even tried it without the sleep_mode to see what would happen.

Throughout all the testing (experimenting) I’ve been doing with Star1.1, if you turned the light off once low battery rampdown had started - it would always come back on in whatever the last memorized mode was, then rampdown would begin again.

Then I started thinking about this part of the code…

// See if we should change the current mode level if we've gone under the current mode.
                if (PWM_LVL < modes[mode_idx]) {
                    // Lower our recorded mode
                    mode_idx--;

…and added a line…

// See if we should change the current mode level if we've gone under the current mode.
                if (PWM_LVL < modes[mode_idx]) {
                    // Lower our recorded mode
                    mode_idx--;
                    store_mode_idx(mode_idx);

Now, if you turn the light off once low battery rampdown has started - it comes back on in a lower mode.

FWIW- a single used CR123 works well for testing the low battery rampdown and warning functions.

-JW

Tonight, I went back and loaded the original (unmodified) Star1.1 firmware onto my test driver, tested low battery operation, and confirmed that while the low battery ramp-down functioned properly, the low battery cut-off did not. Output just remained steady at the minimum level.

Below is part of the original code…

// Wait until we hit the critical level before flashing 10 times and turning off
                while (!low_voltage(ADC_CRIT));

I removed the NOT condition (!), so the same code looks like this…

// Wait until we hit the critical level before flashing 10 times and turning off
                while (low_voltage(ADC_CRIT));

That appears to have fixed the problem.

-JW

PS-
FWIW - I have also successfully modified the code for a single level light (capable of signalling), but retained the low battery ramp-down and cut-off features of the original program.

So that needs to be fixed in all of the V1.1 then?