Close

A Good Use of Time

A project log for Yapolamp

An experimental torch/flashlight intended to be safer for eyes, completely inspired by and built upon the TritiLED project

simon-merrettSimon Merrett 11/30/2017 at 03:120 Comments

Sorry, no pictures this time but perhaps the news that the Yapolamp code is "done" enough to warrant its own Github repository is exciting enough to make up for that!

So, after trying a variety of approaches, I now have the main software features implemented:

  1. Short, timed pulses to drive the MOSFET, "charge" the inductor and then pulse the LED bank on.  This was achieved by using port manipulation and assembly language NOPs to ensure the additional clock cycles of e.g.
    delayMicroseconds()

     weren't adding significantly to the timings, especially the duration that the MOSFET was allowing current to pass. I used both Nick Gammon's approaches to work out if the higher level language was adding unnecessary delay. The first, using the Profile Timer Code makes it possible to monitor the device you are running code on and allows you to capture the duration of execution of code sections you specify. Unfortunately, using an ATtiny85 made it difficult to interface with a serial connection, so I ran the code on an Arduino Nano clone. The resolution was 4uS, which I would have preferred to improve upon, as I knew my ON pulse should be around or less than 4uS. Next, I used Nick's Frequency Counter sketch for Atmega328. It runs on a second device to that of the device under test, so I made the device under test the ATtiny85 and the Arduino Nano clone ran the frequency counter sketch. You connect the D5 pin to the pulse source (PB1 in Yapolamp) and it gives you a count of pulses over 1 second, which are then easy to convert to a period duration with a calculator. This is what really showed me that the port manipulation and NOPs were enabling much faster and finer resolution pulses and pauses:

    PORTB |= (1 << driverPin);  // turns ATtiny85 MOSFET on
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    PORTB &= ~(1 << driverPin); // turns ATtiny85 MOSFET off
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); //1uS @ 8MHz
  2. Low power ALWAYS ON mode. I used the sleep and watchdog timer features of the ATtiny85. By setting the watchdog timer to fire every 32mS, you can achieve around 30Hz blink rates and therefore it appears as a solid, low brightness light, thanks to the Persistence of Vision effect.

  3. Toggling through modes. This was a real challenge for me. For a couple of evenings I struggled to get a reliable button press registration, despite using Nick Gammon's software Debounce without Delay code that I have used sucessfully before. After a long time I realised that the Nano's D5 pin was still connected to the pulse pin - PB1 on the ATtiny85. Along with a capacitor across VCC and GND,  disconnecting this made everything work. I think the capacitor is fully warranted because the voltage spike of the inductor must be significant (at around 50kHz!) and I will need to include a capacitor in the next revision of the torch PCB. A leaded capacitor across the battery connection will do for now. Once I had a button input sorted, I needed to set up Yapolamp so that  it would self time the ON period, before switching to an obvios "wind-down" period. As the user notices this wind-down mode, they can then press the button to start another full period of ON. If they don't do anything, the Yapolamps times a further short period before moving into ALWAYS ON mode to save power until needed again.  I tried using this with an 

    if (millis() - oldTime > waitDuration)

    approach but from an interesting post on StackExchange and subsequent analysis, millis() would appear to take just under 4uS and I didn't fancy relying upon the "mode code" to produce part of the pulse delays. So, before resorting to setting a timer up, I looked at using the watchdog timer but without the often associated sleep function. It took me a while to realise that you need to call it every time the previous one ends (not every "loop" and not "once") but now I can reuse the watchdog code I'm already using with sleep function for the ALWAYS ON mode. It seems to work quite nicely, although there is the odd instance where it refuses to go back into ALWAYS ON, after a period of ON and wind-down. A little more reliability work required here.

So, all in all, I'm very happy to get to this stage. Please go and have a look around the sketch on Github. I'll try to upload some schematics another day and then other people can have a go!

Discussions