1. Use a timer interrupt and in thee Isr change a pwm generator duty cycle. Or

2. Use a timer and set up two compare channels with a fixed offset. In the compare Isr, advance the math points forward and then flip an output pin. You will see the brightness goes up and down, whose speed depends on the offset.

No need for gamma correction.

edit: to demonstrate how the 2nd approach might work, here is a quick example.

It runs off of TIMER0, Output Compare Ch A and Ch B.

TIMER0 is set with a 256x prescaler, free running. Ch A is set to interrupt every LED_PR ticks, and Ch B is set to interrupt every LED_PR + LED_OFFSET ticks. they run the same user interrupt handler -> to flip a pin attached on LED_PORT / LED pin.

	tmr0_init(TMR0_PS256x);					//initialize tmr0 with a prescaler
	tmr0a_setpr(LED_PR);					//set up output compare ch a period
	tmr0a_act(led_flp);						//install user handler for ch a
	tmr0b_setpr(LED_PR + LED_OFFSET);		//set up output compare ch b period, with offset
	tmr0b_act(led_flp);						//install user handler for ch b
	ei();

and here is how it works in simulation: 

[![enter image description here][1]][1]


  [1]: https://i.sstatic.net/H5lhM.png

the DC will go up then down, then up and then down, ....