STAR Firmware by JonnyC - Source Code and Explanation

FWIW, I’ve started a firmware repository and I added a new STAR flavor designed for use as a bike tail light.

The repository currently only contains STAR and a couple derivatives, but I’ll be adding anything and everything I can get permission to share.

The biking tail light code will go into a little 1x16340 light with red XP-E2 as soon as I get the host. It has the following modes: moon, low, med, high, moon-low flasher, low-med flasher, med-high flasher, and heartbeat. It’s my first attiny firmware and I only spent a couple hours on it so far, so it’s a work in progress. However, it does at least work if anyone is interested.

The firmware repository is on Launchpad: Flashlight Firmware Repository in Launchpad
Here’s the link if you’d like to browse the code online.

The tail light .hex file is also pre-built for easy flashing: here.

Nice thanks!!

BTW, I just wanted to thank everyone who has contributed to the STAR firmware.

When I was little, I learned how to read from a programming manual. I learned about variables and syntax errors before I ever heard of Dick & Jane or an Etch-A-Sketch. As long as I can remember, I’ve been putting code into a computer to make it do what I want, and my current computers have their screens filled up almost entirely with stuff I created. It’s just how I do things.

But with flashlights, something was always missing. I’ve really enjoyed them, and modding lights made it even more fun, but there were always little things I still wanted to change…

Until the past couple days, that is.

Today I took apart one of my lights, wrote some new firmware for it, flashed it, tweaked it, put it all back together, and now it’s finally doing what I wanted all along — namely, whatever I told it to do. Its behavior may have been just thrown together quickly based on what I wanted from it today, but that’s okay. It feels right. That’s how things are supposed to be. It’s running custom code which didn’t exist this morning, a crystalized snapshot of my ideas, dumped out of my brain so I could get rid of them and make room for new ideas.

Is it “finished”? Probably not. I’ll probably reflash it a few dozen more times in the foreseeable future. But that’s okay too, code is fluid and changes with circumstance.

As for STAR, I’m thankful because other people already did all the hard parts. It’s a great basis for derivative projects. I didn’t have to spend all week referring to the encyclopedic attiny13a manual to figure out basic things like using the watchdog timer to implement short-cycle memory, or painstakingly measure the values for low-voltage detection. I got to do the fun parts instead, designing modes and watching them in action just moments later. So thank you! I’m having a great time and making all sorts of terrible blinky things.

Awesome ToyKeeper! Thanks for sharing your experience. It's fun stuff! I'm at the point now where my lights do what I want them to with a basic 3-mode with off-time. I'm really done tinkering with new versions of the code, programmability, flashy modes, etc. But this is great because I can now focus on other things.

Toykeeper could you please explain a bit what this is?
Can I send you a modified STAR Firmware and you will add them in this STAR Encyclopedia or what?

Werner, I’m basically just applying some of the most common “best practices” from the software world and applying them to flashlight firmware. I’m hoping it will encourage more collaboration.

In general, open-source software projects organize their activities around a project management service such as Launchpad or GitHub. This provides a central hub for storing and publishing source code and other project files, along with a system for keeping old revisions and managing code patches. It also provides bug tracking or issue tracking, along with a variety of other optional services like mailing lists or documentation systems. Plus, it’s just nice having everything in one place.

So, you could send me a modified version and I could add it to the repository for you. Or you could branch the repo, add your improvements, publish your own branch, and share it. Or submit a merge proposal to get it back into the main repository. Or you could fork the whole thing complete with history and start your own project if you don’t like the way it’s being managed.

A lot of the features are probably more than we really need, but it’s nice to have room to grow. For example, I doubt we’ll need to bisect the revision history to figure out exactly where a bug was introduced in a firmware’s code, but stuff like that is available if anyone needs it.

That sounds good, code sharing in this forum is terrible and so I am quite sure a lot of useful things fall under the carpet…

I’m not entirely sure how to use Launchpad’s revision control tools (bzr) in Windows or MacOS, but those are both supported platforms. I think both have a few GUIs available too, but I’m not familiar with them.

I just “bzr branch lp:flashlight-firmware” to get a copy of the code, and then otherwise use bzr at the command line to check in new versions or do other common operations. The only GUI part I use is “bzr vis” from bzr-gtk, which is handy for viewing the revision history. It looks like this:

This is all optional though. I’m happy to accept patches and such via email and do all the revision control and publishing steps myself.

This is not email, but wanted to post the enhanced _delay_ms() function here so that it won't get buried to another thread as OT post..

I have seen this "_delay_ms() can't take variables" so many times that it's time to do something for it:

#define OWN_DELAY
#ifdef OWN_DELAY
#include <util/delay_basic.h>
// Having own _delay_ms() saves some bytes AND adds possibility to use variables as input
static void _delay_ms(uint16_t n)
{
    while(n-- > 0)
        _delay_loop_2(1024);
}
#else
#include <util/delay.h>
#endif

…main…

#ifndef OWN_DELAY
uint16_t randTime;
#endif

while(1)
{
// turn the emitter on at a random level,
// for a random amount of time between 1ms and 20ms (* 4/3)
PWM_LVL = rand() % 190 + 10;
#ifdef OWN_DELAY
_delay_ms(rand() % 19 + 1);
#else
randTime = rand() % 19 + 1;
while(randTime–) // _delay_ms() can’t take variables that can change, make loop with variable instead
_delay_ms(1); // and delay_ms with fixed value within loop
#endif
// turn the emitter off,
// for a random amount of time between 1ms and 1000ms (* 4/3)
PWM_LVL = 0;
#ifdef OWN_DELAY
_delay_ms(rand() % 999 + 1);
#else
randTime = rand() % 999 + 1;
while(randTime–)
_delay_ms(1);
#endif
}

In this example, using own delay saved us 16 bytes (with -Os) and made the code cleaner.

Enjoy!

This is good stuff. It should probably replace the standard _delay_ms() in every firmware which calls _delay_ms() more than once. On one of my STAR derivatives, this delay function saved me at least 140 bytes.

The parameter sent to _delay_loop_2() is also a handy thing to change per-driver if you want more accurate timing, since it can be calibrated for each individual chip. I’ve tried it on three now, and the value has been anywhere from 890 to 950 if I want _delay_ms(1000) to be reasonably close to one second.

I suppose I should probably update STAR with this. I may need to upgrade my avr-gcc first though, since what I have now compiles STAR to about 1060 bytes instead of 1024.

I posted this in the random flash thread, but can post it here too:

I did a shorter one some time ago so you don’t even have to include delay_basic.h. I basically just ripped out one of the assembler loops from delay_basic.h. The variable entered does not resemble a nice even millisecond value, like 1 or 10 ms or similar, but I don’t need exact millisecond numbers, I only have to adjust the value until I like what I see.

By the way, how did you post your code? It looks like code, when I try to paste in my code it looks like garbage so I post images instead. How did you get it formatted nicely like that?

I looked into it, but I needed something with fairly precise timing so I didn’t use it.

I used the HTML ‘pre’ tag.
<pre>
(insert code here)
</pre>

Helios made me a kewl Roche F6 driver (momentary switch) with two battery level indicators, but I have zero clue how to add whatever to the FW to make them work. They're run by MCU pin 3 & pin 5, circuits for both are totally separate so it's possible to use them one at a time or both together, to get a third color. Any suggestions for what the LEDs should do? Keep the original low voltage behavior (blink + ramp down) or ditch it?

Depends on your preference I suppose. In order to get the most mileage out of those indicators it seems that removing the ramp/step-down makes sense. Replace that with warning indications… but really I probably wouldn’t do it unless I could make the indicators pretty visible.

OTOH there’s nothing wrong with having both systems in place - a red indicator is just a confirmation that the stepdown is due to LVP.

I could use some help. I’m not sure what I need to do to move PWM from PB1 to PB0.

Here is what I have so far.

I changed:

  • the PWM_PIN define
  • the PWM_LVL define (output compare register)

I did not change the TCCR0A or TCCR0B stuff.

This is for the LD-29 project. In retrospect it may have made more sense to hookup the normal PWM pin… maybe that’s what I’ll end up doing.

Thanks in advance.

Bump. I could still use some help with this. Even if I hookup PB1 to the PWM input on the LD-29, I would still like to know about how this would be done. I have another project (17mm DD+7135 — linear regulated driver w/ FET turbo) which would benefit from the ability to use two PWM outputs (not simultaneously). The PCB for that project is already laid out for using both PB0 and PB1.

Dunno, but I’ll be quite happy if anyone has an answer… because when I get time I’d rather like to make a RGBW light with each color controlled individually… and I’m hoping I can use PWM arbitrarily on any two colors at the same time (most likely will need a better MCU though, with two PWM channels).

It might be a while before I can start on that though… too many other projects.

Sorry guys, was hoping someone else would chime in ;)

I've never changed the PWM from PB1 to PB0, but it looks like, along with what you changed already, you need to change TCCR0A to this...

TCCR0A = 0x83; // phase corrected PWM is 0x81 for PB0, fast-PWM is 0x83

That's my guess looking at the datasheet, which I've never been the best at reading. I just searched for TCCR0A and the first two bits relate to COM0A (PB0), and the next two bits relate to COM0B (PB1). So instead of it being "0010", it's "1000".

An outstanding thing for me to look into for RMM is the ability to change the PWM output pin based on the mode selected (so you could have a single 7135 on one pin, the rest on the other), and/or be able to change the PWM mode between phase correct and fast PWM based on the mode as phase correct does a better job with lower levels. I'm sure this was discussed before, I just haven't been paying attention lately :(

Thanks JonnyC, I’ll try that and continue to poke around in that vein if it doesn’t work by itself.

If there was a discussion about the minimum level that Fast PWM vs Phase Correct PWM could sustain, I missed it too.

I was thinking of using a 2D array to store pin states (including PWM levels) for modes. I think that could be implemented in a reasonably flexible way in order to facilitate drivers which need to do various pin sequences for modes. We currently have drivers with one PWM pin, plus drivers which operate like the DQG 26650 driver (a run pin + several pins which should be turned on exclusively for different modes), and in the future I’d really like to have a driver which operates the way I described here (#32). I think it might be possible for us to describe the modes for each of those drivers (plus the DD+7135 one I linked to before) using the same array format.


Tried to compile SRK no ramp firmware with this result.
Any ideas?