Sunday, April 25, 2010

Power Supply Woes

In recent power surge and outage, the Seasonic SS-400ET power supply I had for about a year would not boot up. The power led on the motherboard blinked but nothing happened when I pushed the power button.

I knew Seasonic made reliable power supplies but dying over one power surge is unacceptable. Shipping it back for RMA would cost about the same as getting a new one, so I decided to open it up and fix it. I would suspect capacitor problems with cheaper power supplies but nonetheless I checked the capacitors. Low and behold, the standby power capacitor had bulged slightly. It appeared that the surge just stressed it enough to pop it.

Once it was replaced, it booted right up again.

Monday, April 5, 2010

Beagleboard & QNX: GPIO Interrupts

This is a short guide on how to use the GPIO interrupts on the Beagleboard running QNX.

My setup:
Beagleboard C3
512MB SD boot
4-port USB 2.0 hub
linksys USB 1.1 100TX adapter (for debug through momentics IDE)

references required:
  1. Beagleboard technical reference - http://beagleboard.org/resources
  2. OMAP3530 techinical reference manual (TRM) - http://focus.ti.com/docs/prod/folders/print/omap3515.html
steps overview:
  1. change mux to get GPIO signals (/src/hardware/startup/boards/omap3530/init_pinmux.c)
  2. add interrupt triggers (edge/level)
  3. write interrupt handler
For this guide, I will use use GPIO 130 and 131 as interrupt lines. Refer to BB TRM section 8.19.1 for what GPIO lines are available. Refer to section 7.4.4.3 in the TRM for which register the GPIO is muxed on. So in init_pinmux.c, I add:
/* ################GPIO5 SETUP################### */
/* MMC2 CLK */
pad = in32(CONTROL_PADCONF_MMC2_CLK) & 0x0000ffff;
out32(CONTROL_PADCONF_MMC2_CLK, pad | INPUTENABLE1 | PULLTYPE1_UP | PULLUDENABLE1 | MUXMODE1_MODE4);
/* MMC2 CMD */
pad = in32(CONTROL_PADCONF_MMC2_CLK) & 0xffff0000;
out32(CONTROL_PADCONF_MMC2_CLK, pad | INPUTENABLE0 | PULLTYPE0_UP | PULLUDENABLE0 | MUXMODE0_MODE4);

/* GPIO IRQ */
out32(OMAP3530_GPIO5_BASE + OMAP2420_GPIO_RISINGDETECT, (1 << 2)|(1 << 3));
out32(OMAP3530_GPIO5_BASE + OMAP2420_GPIO_FALLINGDETECT, (1 << 2)|(1 << 3));

Create a new QNX project to test the interrupt handler. GPIO5 lines share IRQ 33, so I would need to check the irqstatus of each line if I use more than one interrupt.
#define GPIO5_IRQ 33

int count;
int error;
struct sigevent event;

const struct sigevent *
isr_handler (void *arg, int id)
{
return (&event);
}

void *
int_thread (void *arg)
{
// enable I/O privilege
ThreadCtl (_NTO_TCTL_IO, 0);

// attach the ISR to IRQ
if (InterruptAttach (GPIO5_IRQ, isr_handler, NULL, 0, _NTO_INTR_FLAGS_TRK_MSK) == -1) {
error = 1;
}
while (1)
{
InterruptWait (NULL, NULL);
count++;
}
}

int main(int argc, char *argv[]) {
event.sigev_notify = SIGEV_INTR;

printf("Creating interrupt thread...\n");

pthread_create (NULL, NULL, int_thread, NULL);
delay(5);

while(!error) {
printf("count=%i\n", count);
fflush(stdout);
sleep(1);
}

return EXIT_SUCCESS;
}
In my example you have to reset 2 status registers to have the interrupts trigger again. After count++, add:

out32(omap3530_intc_base + 0xa8, 0x2);
out32(GPIO5 + OMAP35XX_GPIO_IRQSTATUS1, in32(GPIO5 + OMAP35XX_GPIO_IRQSTATUS1) | 0xFFFFFFFF);

I will make a more complete guide later on... feel free to comment or email questions.