Although an LPC2148 has more than those, they are not very conveniently grouped on the board I have, so I used simple GPIO pins with software PWM. That reduced the amount of cabeling to using a single 10 pin flat ribbon cable to connect the LPC2148 board and the I/O board.
#define LAMPS_COUNT 4
void fiqISR (void)
{
int i;
++fiqCounter;
for (i=0; i<4 ; ++i) {
++lampPWM[i].counter;
if (lampPWM[i].counter > 99) {
lampPWM[i].counter=0;
if (lampPWM[i].duty!=0)
/* Unless off forever, turn it on now */
GPIO0_FIOCLR = lampPWM[i].gpio_mask;
}
if (lampPWM[i].counter > lampPWM[i].duty)
/* Turn off when duty cycle is fulfilled */
GPIO0_FIOSET = lampPWM[i].gpio_mask;
}
T1_IR = T_IR_MASK;
}
lampPWM is a struct with some fields, namely counter which counts up 1 per FIQ, duty which is the duty cycle from 0..100 with 0 being off, and 100 being on, and 1..99 for anything between, and gpio_mask which contains the GPIO pin to set/reset.
With an interrupt frequency of 10kHz (100 Hz update with 100 steps) this uses 3.4% CPU time on a LPC2148 at 48MHz and MAM fully enabled.
That's quite impressive. On a Z80 just entering the interrupt routine takes 3.2uS (19 cycles at 6MHz clock). Here the interrupt routine including all overhead runs in 3.3uS for 4 PWMs generated.