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.