luxdrv - custom modes driver firmware with ramping

Strange.
Fuses are fine, 0x75 and 0x79 are basically the same.

Did you try tapping the button a couple of times in quite quick succession, say 3-4 taps within one second?
Did you change the LOCKTIME to a lower value? (should be 7 or more)
Did you change the #define WDTIME 0b01000011 line?

Problem was a grounding issue (I’m pretty sure). I say pretty sure because I only briefly tested it after soldering the drivers’ grounding ring to the pill. It seemed to work great in that brief test. Please consider the problem resolved. Thank you DrJones for taking the time to reply. I feel bad that I wasted your time.

I only briefly tested it because I disabled the driver after doing some other work on it while the iron was still hot. I think I reversed the protection diode after I accidentally unsoldered it. It maybe be a good thing in the end though. When I was researching how to figure out which way to orient the diode, I found out the diode consumes .6 volts. I started a new thread on that.

Encouraged by post for a new mobydrv I changed luxdrv 0.30b code to run attiny at 9.6 MHz (define F_CPU 9600000, low fuse: 0x76) in order to get approx. 18 kHz pwm. So far there are no problems, minimal pwm values need to be raised a little bit but driver is now perfectly silent in all modes. There is however question of increased attiny consumption (for battery life in really low power modes) and stability at low battery voltages…

Once again a big thanks to DrJones!!!
Luxdrv0.30b works perfect!!!

Greetings from sunny Cyprus!!!

Hello DR Jones and everybody!!!

I have been using the luxdrv0.30b for the past days with modes set to 3–15–33–100-Beacon/batt. monitor and No Memory… the driver is a nanjg105c with 9 AMC7135 @ 3050ma…

I love this modes and the battery monitor BUT I want to change something… The BEACON lights up every 10s if I am not mistaken, How can I make it light up every 3s?

Thanks a lot guys and especially thank you Dr Jones!!

I may have found it!!! :bigsmile:

mypwm=255; while(1){ PWM=mypwm; _delay_ms(20); PWM=0; i=70;do{SLEEP;}while(—i); } break; //beacon 10s //+48
#endif

Isn’t this in bolt?? (i70)

Yes, set it to 21 for about 3 seconds.

Thanks dr jones!!! I have set it to 14 which is about 2S!!

Now I have it set to 100ma-400ma-1000ma-3050ma-2sec beacon with batt. monitor and NoMem!!! Perfect for me!!! :bigsmile:

THANK YOU SIR!!!

Dear Dr. Jones,

Would you please teach me how to change the ADC input from PB2 to PB4.

Thanks,

Change these lines

#define adcpin 2
#define adcchn 1

to

#define adcpin 4
#define adcchn 2

PPtk

Thanks for your reply.

Hello guys, it’s me again! :stuck_out_tongue:

I have a very small problem with my luxdrv0.3b

I have it set as follows

12-40-90-255-beacon NO MEMORY

it works great BUT sometimes (1-2 out of 10) it has memory :~

what might be wrong with it???

it always starts from lowest mode but sometimes it starys from the mode I last used, and it happens that most of those time the flashlight was used some days or hours before…

I don’t know how to explain it better…

any ideas??

I’m not intimately familiar with the LuxDrv code, but from a quick perusal, I would say the exact behavior you’re seeing is pretty much impossible. The Mode-Memory procedure is completely left out of the compiled code when you set the #define NOMEM directive, which means the microcontroller has no idea how to do mode memory.

What’s far more likely is that you’re turning it on for a very brief burst (less than about 7/8 of a second) and then setting it down. This is less time than it takes to perform a mode lock of the first mode rather than a ‘next-mode’ cycle. When you come back and pick it up, it starts in the ‘next’ mode as if you had just quickly power cycled it during use (to move to the next mode).

I could be wrong, but I’d bet pretty heavily that I’m not. Post your exact compiled code if you disagree with my assessment.

PPtk

just happened again now…
I thought about what you said but if I was pressing the button 2 times quickly without realizing it wouldn’t light come otf???

I just pushed the button once fully until it clicked and it came up in the 3rd brightness mode…

I can post the code but now I am writing from my phone in the middle of the night!! :stuck_out_tongue:

That’s not actually what I said. I wasn’t suggesting you were pressing it twice without realizing it.

What I am suggesting is that the last time you used the light (perhaps a minute, hour, day or week ago), you turned it on to mode 1, cycled it to mode 2 and then turned if off and left it off without waiting for mode reset to occur (about 7/8 of a second of ON time). It can’t ‘do’ anything while it’s off, so the next time you use it (just now), it continues where it left off - cycling to mode 3.

PPtk

This set of questions is specifically aimed at DrJones, but if anyone can help I'd be very grateful! I have a small linear driver I've built, and purely because I'm using the TINY25 on a different circuit, I have chosen to use the same chip on this little driver. It's a simple 3-mode driver, with temperature and voltage regulation.

My pin layout is typical for VCC and GND (obviously), but I have to check how the rest stacks up:

  • Voltage monitoring on pin 7 - VIN to a 3k resistor, sensed on pin 7, and 10k resistor to GND.
  • Temperature monitoring on pin 3 - Vref out of pin 2, into a 10k resistor, sensed on pin 3, and a 100k NTC thermistor to GND.
  • PWM out is on pin 6.

Anyway - my idea is to try and use DrJone's luxdrv firmware for this driver as setting the modes and brightness levels should be easy. I have managed to compile the firmware for the Tiny25 in AVR Studio 6, though I have not had the time yet to test it to see if it does anything.

texaspyro helpfully pointed out in Tido's original thread that there is a subtle difference between the Tiny13 and Tiny25:

[QUOTE]one nasty difference between the TINY13 and TINY25/45/85 is the register value that you have to write to select the 1.1V bandgap reference for the A/D converter. Atmel could have easily made the registers compatible, but they screwed up…[/QUOTE]

So I guess my questions need to be:

  1. What pin is DrJones using for PWM out?
  2. How is the good Doctor performing cell voltage detection?
  3. How can I incorporate my voltage divider circuit for cell voltage detection?
  4. How can I incorporate my NTC voltage divider circuit for thermal detection?
  5. Finally, if relevant (which given that pin 2 is required to output a reference voltage I think it is) how to work around the issue texaspyro raised?
Anyone willing to help? I have read through the luxdrv firmware already but ill read it again to see if anything stands out to me a second time through...

I'm sooooo close to having this driver done, and I'm sure the changes would be trivial for some, but for me it'll be a hard slog :-(

- Matt

  1. PWM Out on PB1 (OCR0B) - Same as yours.
  2. Same way you are, on the same pin. Your voltage divider is wrong though - your returned voltage will be far above the 1.1V Reference.
  3. It's already incorporated. Just change the resistor values to provide a <1.1V Value at 4.2V
  4. Why bother? The Tiny25 has an internal temperature sensor that is surprisingly accurate
  5. You don't have to. Luckily, Even though the register is different, the value for it is the same in this case. it will work as compiled.

//

// LuxDrv 0.30b DrJones 2011++

//

// 808 bytes with ramping

//

// License: Free for private and noncommercial use for members of BudgetLightForum

//

// changes:

// 0.1 first version: levels,strobe,beacon,timer(136) (638bytes)

// 0.2 ramping(200), improved timer(180), skip mode1 as next mode if already in mode 1 (898bytes)

// 0.21 changed EEPROM handling to reduce power-off-while-writing glitches -->eepsave(byte) (874bytes)

// 0.22 bugfix in ramping; mode not stored on (very) short tap (878bytes)

// 0.3 battery monitoring added; step down and indicator in beacon mode (994bytes)

// 0.3b improved config, const progmem, no dummy any more, timer removed, 4 main modes as default

// 0.3c Added Temperature Sensor for ATTINY25

//ToDo:

// ? off-time checking; requires adding diode,R,C

// ? blink your name in morse code :)

#define F_CPU 4800000 //CPU: 4.8MHz PWM: 9.4kHz ####### use low fuse: 0x75 #######

//########################################################################################### MODE/PWM SETUP

//Special modes; comment out to disable

#define RAMPING 254 //+156

#define STROBE 253 //+50

#define BEACON 252 //+74

#define MODES 6,15,56,255, RAMPING, STROBE, BEACON

#define RAMPMODE 5 //the number of the RAMPING mode in the MODES order; e.g. RAMPING is 5th mode -> 5

//define NOMEM //deactivate mode memory.

#define LOCKTIME 7 //time in 1/8 s until a mode gets locked, e.g. 12/8=1.5s

#define BATTMON 125 //enable battery monitoring with this threshold

#define TEMPMON 87 //Temperature Value - Most Likely Have to Play with this value.

#define MINPWM 5 //needed for ramping

//###########################################################################################

#define outpin 1

#define PWM OCR0B //PWM-value

#define adcpin 2

#define adcchn 1

#define portinit() do{ DDRB=(1<<outpin); PORTB=0xff-(1<<outpin)-(1<<adcpin); }while(0)

#include <avr/pgmspace.h>

#define byte uint8_t

#define word uint16_t

PROGMEM byte modes[]={ MODES };

#include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>

#include <avr/sleep.h>

#include <avr/eeprom.h>

#define WDTIME 0b01000011 //125ms

#define sleepinit() do{ WDTCR=WDTIME; sei(); MCUCR=(MCUCR &~0b00111000)|0b00100000; }while(0) //WDT-int and Idle-Sleep

#define SLEEP asm volatile ("SLEEP")

#define pwminit() do{ TCCR0A=0b00100001; TCCR0B=0b00000001; }while(0) //chan A, phasePWM, clk/1 ->2.35kHz@1.2MHz

#define adcinit() do{ ADMUX =0b01100000|adcchn; ADCSRA=0b11000100; }while(0) //ref1.1V, left-adjust, ADC1/PB2; enable, start, clk/16

#define adcread() do{ ADMUX =0b01100000|adcchn; ADCSRA|=64; while (ADCSRA&64); }while(0)

#define tempread() do{ ADMUX = 0b01101111; ADCSRA|=64; while (ADCSRA&64); }while(0)

#define adcresult ADCH

#define ADCoff ADCSRA&=~(1<<7) //ADC off (enable=0);

#define ADCon ADCSRA|=(1<<7) //ADC on

#define ACoff ACSR|=(1<<7) //AC off (disable=1)

#define ACon ACSR&=~(1<<7) //AC on (disable=0)

//_____________________________________________________________________________________________________________________

volatile byte mypwm=0;

volatile byte ticks=0;

volatile byte mode=0;

byte pmode=50;

byte eep[32]; //EEPROM buffer

byte eepos=0;

#ifdef RAMPING

byte ramped=0;

#endif

byte lowbattcounter=0;

byte overtempcounter=0;

void eepsave(byte data) { //central method for writing (with wear leveling)

byte oldpos=eepos;

eepos=(eepos+1)&31; //wear leveling, use next cell

EEARL=eepos; EEDR=data; EECR=32+4; EECR=32+4+2; //WRITE //32:write only (no erase) 4:enable 2:go

while(EECR & 2); //wait for completion

EEARL=oldpos; EECR=16+4; EECR=16+4+2; //ERASE //16:erase only (no write) 4:enable 2:go

}

ISR(WDT_vect) { //WatchDogTimer interrupt

if (ticks<255) ticks++;

if (ticks==LOCKTIME)

#ifdef NOMEM

eepsave(0); //current mode locked -> next time start over, no memory.

#else

eepsave(mode);

#endif

#ifdef BATTMON //code to check voltage and ramp down

adcread();

if (adcresult<BATTMON) { if (++lowbattcounter>8) {mypwm=(mypwm>>1)+3;lowbattcounter=0;} }

else lowbattcounter=0;

tempread();

if (adcresult>TEMPMON) { if (++overtempcounter>8) {mypwm=(mypwm>>1)+3;overtempcounter=0;) }

else overtempcounter==0;

#endif

}

inline void getmode(void) { //read current mode from EEPROM and write next mode

eeprom_read_block(&eep, 0, 32); //read block

while((eep[eepos]==0xff) && (eepos<32)) eepos++; //find mode byte

if (eepos<32) mode=eep[eepos];

else eepos=0;

byte next=0;

if (mode==0) next=1; //skip 1st mode if memory is 1st mode already

#ifdef RAMPING

if (mode & 0x40) { //RAMPING

ramped=1;

if (mode & 0x80) { next=RAMPMODE; mode&=0x7f; } //mode: for savemode

}else //ENDRAMPING

#endif

if (mode & 0x80) { //last on-time was short

mode&=0x7f; if (mode>=sizeof(modes)) mode=0;

next=mode+1; if (next>=sizeof(modes)) next=0;

}

eepsave(next|0x80); //write next mode, with short-on marker

}

int main(void) {

portinit();

sleepinit();

ACoff;

#ifdef BATTMON

adcinit();

#else

ADCoff;

#endif

pwminit();

getmode(); //get current mode number from EEPROM

byte i=0;

#ifdef RAMPING

byte p,j=0,dn=1; //for ramping

if (ramped) { //use the ramped mode

pmode=255; i=30-MINPWM-(mode&0x3f); while(i--){pmode=pmode-(pmode>>3)-1;} //get PWM value //never gives 250..254

} else

#endif

pmode=pgm_read_byte(&modes[mode]); //get actual PWM value (or special mode code)

switch(pmode){

#ifdef RAMPING

case RAMPING:

ticks=100; //crude way to deactivate the 2s-lock //RAMPING

while(EECR & 2); //wait for completion of getmode's write

while(1){ p=255; i=30-MINPWM-j; while(i--){p=p-(p>>3)-1;} //ramp up

PWM=p;

eepsave(192+j);

SLEEP;

if (dn) {if (j ) j--; else {dn=0;SLEEP;SLEEP;} }

else {if (j<30-MINPWM) j++; else {dn=1;SLEEP;SLEEP;} }

} break;

#endif

#ifdef STROBE

case STROBE: mypwm=255; while(1){ PWM=mypwm; _delay_ms(20); PWM=0; _delay_ms(60); } break; //strobe 12.5Hz //+48

#endif

#ifdef BEACON

case BEACON:

#ifdef BATTMON

adcread(); i=adcresult; while (i>BATTMON) {PWM=8; SLEEP;SLEEP; PWM=0; SLEEP; i-=5;} SLEEP;SLEEP;SLEEP;

#endif

mypwm=255; while(1){ PWM=mypwm; _delay_ms(20); PWM=0; i=70;do{SLEEP;}while(--i); } break; //beacon 10s //+48

#endif

default: mypwm=pmode; while(1){PWM=mypwm;SLEEP;} //all other: us as PWM value

}//switch

return 0;

}//main

Thanks for the reply Pilot :)

[quote=PilotPTK]

  1. PWM Out on PB1 (OCR0B) - Same as yours.
  2. Same way you are, on the same pin. Your voltage divider is wrong though - your returned voltage will be far above the 1.1V Reference.
  3. It's already incorporated. Just change the resistor values to provide a <1.1V Value at 4.2V
  4. Why bother? The Tiny25 has an internal temperature sensor that is surprisingly accurate
  5. You don't have to. Luckily, Even though the register is different, the value for it is the same in this case. it will work as compiled.

[/quote]

  1. Excellent
  2. So long as the circuit connections themselves are OK, and it's just poor resistor choices, then I will re-calculate the required resistors. (not sure how I screwed that up!)
  3. The resistor values you refer to are the ones from my second question? I'm therefore assuming DrJones is performing the detection on the same pin as I am then (pin7/PB2)?
  4. In this particular circuit you are correct - it's a waste of time. However I have another driver for different purposes that is set up in the same way, but uses an NTC thermistor on a lead. This way I can get temperature readings at the source rather than relying on how hot the uC is to determine if the LEDs themselves are running too hot or not.
  5. More good news!

Thanks for the code as well! From the looks of things the luxdrv firmware would have actually more or less worked out of the box although my cell voltage circuit would have ruined things for me, and the thermal sensing circuit would not function. So you've activated the Tiny25's internal temperature circuit? I'll focus on getting this up and running on the driver I have (once I've replaced the resistors) and then I'll work out how to use my external temperature sensor after that.

Baby steps haha.

I'll be back to report on what happens, good or bad.

Thanks as always

- Matt

Regarding your #3, yes, he is using the same pins.

The external temperature circuit you've designed will work, but not quite how you want it to.. You can only output the 2.56V Internal reference on PB0(Pin5), and the microcontroller can only generate the 2.56V Reference if input voltage to the uC is above 3.0V. All bad.

That said, it's not a total loss. Absolute values don't matter with your NTC circuit. It gives you a proportion of the voltage which is perfect. Your best bet is to output digital HIGH on Pin2(PB3), set the ADC voltage reference to VCC (ADMUX 7:6,4 [000]), and then take a reading of ADC2. You'll get an 8(or10) bit value and no matter the voltage input, it will be the same(ish) return at the same temperature.

For your voltage resistors, you want the one connected to VCC to be 19.1K and the one connected to Ground to be 4.7K. If memory serves, this will match the NANJG. With what you've got now, at 4.2V, you'll end up with

10000/13000 * 4.2 = 3.23V. Far above the 1.1V Reference. With the 1.1V Reference, you can only measure between 0 and 1.1v

Using 19.1K and 4.7K

4700/23800 * 4.2 = .82V

and 2.8V (a good cutoff)

4700/23800 * 2.8 = .55V (about half of 1.1V, which is good).

PPtk