Actions

Ikea

From Trammell Hudson's Projects

Ikea Tradfri firmware hacking

Ikea Floalt LED driver

Ikea Tradfri LED power supplies with wireless receiver are cheap and easily modifiable. Some of them have accessible SWD programming headers allowing openocd to debug and modify the firmware.

Resources

Ikea LED power supply and Tradfri dimmer
Ikea floalt SWD programming pinout

Brightness adjustment

Ikea LED power supply and Tradfri dimmer

Lowest default firmware dim is 50usec with a 1kHz period is way too bright. Like eye-blinding at night. The ERF32 runs PWM on timer1 to do low side switching on the +24V output.

Dimmest setting

Modified firmware with a 1usec PWM produces a much more acceptable nightlight. Demo video showing how much dimmer the updated firmware is able to produce. This also works on FLOALT panels, although at the lowest dim the light is very non-uniform due to LED spacing.

Dimmer ramp up curve

Replacement brightness curve compared to the default one in the firmware. The stock firmware has 0x380 as the lowest value and uses floating point to generate the curve; due to space constraints the replacement one is piecewise linear, but still produces a similar ramp effect. The code is currently really hacky and requires hard-coded function offsets; a better system needs to be put together to make this usable for non-hardware hacking users.

static inline void
thumb_thunk(
	const unsigned addr
)
{
	// force thumb addressing by setting the bottom bit of the address if it is not already set
	void (*func)(void) = (void*)(addr | 1);
	func();
}

void
brightness_table_fill(void)
{
	volatile unsigned * const brightness_table = (void*) 0x20005f74;
	if (brightness_table[0x100] != 0)
		return;
	brightness_table[0x100] = 1;

	thumb_thunk(0x099fc);
	thumb_thunk(0x0a7f6);
	thumb_thunk(0x176a2);

	// piecewise linear ramp for now, approximating an acceleration
	unsigned pwm = 0x20;
	unsigned bright = 1;
	unsigned acc = 8;
	brightness_table[0] = 0;

	for(unsigned i = 0 ; i < 8 ; i++)
	{
		for(unsigned j = 0 ; j < 0x20 && bright <= 0xFF ; j++)
		{
			brightness_table[bright++] = pwm;
			pwm += acc;
		}

		acc += acc;
	}

	thumb_thunk(0x098b0);
}