Posted on Leave a comment

CH32V003 driving WS2812B LEDs with SPI – Part 5

2 March 2025

The test apparatus doesn’t like it when I get up or sit down in front of it. This adds more evidence to the theory that the problem is an intermittent connection, and random vibration from the environment is causing something to conduct either better or worse than it was. There were over 100,000,000 loops and only 1,355 errors overnight, but there was a run of errors just as I came in to view. Should I take this personally?

So I decidedly wish to rebuild a more substantial test platform, but part of me wants to understand exactly what is going wrong with the present system. One of the many un-followed-up-on trouble-shooting ideas was to make the power supply monitor generate an interrupt, as only occasionally glancing at the status bit in code has not revealed a correlation between the failures and the power status.

Adding an interrupt routine to a MRA2 project is not difficult, as most of the required coding gymnastics have already been performed for us. The PVD interrupt is only a little more involved, as it is routed through the external interrupt controller, EXTI.

Here is the code to enable voltage monitoring:

// initialize power monitoring

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // enable peripheral clock
//PWR_DeInit(); // reset peripheral - hope it doesn't brick the chip! (it does)
//PWR_PVDLevelConfig(PWR_PVDLevel_2V9); // lowest voltage monitoring
PWR_PVDLevelConfig(PWR_PVDLevel_4V4); // highest voltage monitoring

PWR_PVDCmd(ENABLE); // enable programmable voltage detector
//Delay_Ms(100); // short delay for voltage detector to "warm up"
printf("Power is %s\r\n", PWR_GetFlagStatus(PWR_FLAG_PVDO) == SET ? "*** LOW ***" : "OK");

EXTI_InitTypeDef EXTI_InitStruct = { 0 };
EXTI_StructInit(&EXTI_InitStruct); // set default values
EXTI_InitStruct.EXTI_Line = EXTI_Line8; // PVD is connected to EXTI8
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // rising edge on PVD means voltage is dropping out of specified range
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct); // initialize EXTI8/PVD

NVIC_EnableIRQ(PVD_IRQn);

And here is the simple interrupt handler I wrote to catch those pesky power glitches:

void PVD_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void PVD_IRQHandler(void) { // programmable voltage detector interrupt handler

    // the supply voltage has dropped below 4.4 VDC

    power_glitch++; // count this power glitch

    EXTI_ClearITPendingBit(EXTI_Line8); // clear interrupt pending bit

    printf("*** POWER GLITCH! ***\r\n");

    //while(true); // *** debug *** stop here for now

    while(PWR->AWUCSR & PWR_FLAG_PVDO != 0) {
        // wait for power to return to return to normal values, i.e., > 4.4 VDC
    }
}

I originally added a while(true); loop in the interrupt handler to stop and let me see when a power glitch was detected, and sure enough, I was rewarded very quickly. So the power is dipping down enough to confuse the SPI peripheral but not actually reset the core. This is not as surprising as it sounds, as the core power-up and power-down reset voltage levels are set at 2.5V. We’re losing some voltage, somewhere, for only a moment, but not enough to trigger a full system reset.

Again, to me it seems that all this points to a low-quality connection somewhere in the mix. It’s time to build that improved test fixture.

Leave a Reply