This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP432E401Y: Putting MSP432 in low power mode instead of polling loop

Part Number: MSP432E401Y


I am using the MSP432E401Y to transmit data from several ADCs to a PC via Ethernet.  The data rate is 1kHz.  The ADCs trigger an interrupt on the MSP432, whose ISR reads the data via SPI then sends the data out the Ethernet port.  After the data has been read the MSP432 goes into a software polling loop waiting for a semaphore to be set.  The semaphore is set in the ISR.  The data collection and transmission process takes less than 250uS, so the MSP432 spends over 75% of the time spinning in the wait loop.

I'd like to put the MSP432 in a low power mode while waiting for the ADCs interrupt.  I've  not used any sleep or low power modes on the MSP432 so I'd like some advice on how to do this.  I am running without an RTOS, and am using the lwIP library.

1) Are there any examples in the Resource Explorer which I can reference?

2) Are there any other resources available to show how to put the MSP432 in a low power mode and wake on an external interrupt?

  • If you always have an ISR to set/free your semaphore, the simplest first step is just to insert "__WFI();" into your polling loop. This will reduce power measurably.

    I don't recall seeing any TI examples of this. The MSP432E series isn't strong on low power modes. There's the Hibernate module, and you can slow down the clock. (I think actually running the Ethernet requires the full 120MHz though.)

    But what we observed is that beyond the simple WFI the board power is dominated by the Ethernet circuitry, which (unless your board design accounted for this) can't be easily turned off.

  • Bruce,

    Thanks.  That seems easy enough so I tried, but it looks like the CPU isn't waking up when the interrupt occurs.  I even tried the procedure described here but no luck.  There must be something else I'm missing.  Maybe WFI can't be woken up with an external GPIO interrupt?

  • Doesn't wake up in the sense that the ISR isn't executed, or it just doesn't come out of the WFI?

    WFI is defined to wake up on any interrupt (even if interrupts are globally disabled, which can be handy sometimes). Can you post the sequence you're using?

    That AppNote makes it sound easy, but both SLEEPONEXIT and DEEPSLEEP should really be designed in at the application level. I suggest taking this one step at a time.

  • Here's the pertinent parts of my code:

    This is the loop where I'd like to go to sleep.  Before the following code I've configured the peripherals and registered the GPIO ISR.  The START command comes in a UDP packet that is handled by the udpReceive() callback.

        pcb = udp_new();                             // create a new UDP structure for incoming host commands
        udp_recv(pcb, udpReceive, NULL);             // associate incoming UDP packets with its callback function
        udp_bind(pcb, IP4_ADDR_ANY, UDPPORT);        // finally bind the PCB to any host on port UDPPORT
    
        while(!running);                             // wait for a START command from the host
    
        UARTprintf("START requested.\n");
                                                                                                                                   
        while(running)                               // until the STOP command is received
        {
            while(!dataReady);                       // wait for valid data in TXbuffer
            dataReady = false;                       // clear the data ready semaphore
    
            struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, sizeof(TXbuffer), PBUF_RAM); // allocate a new pbuf for sending the response
            if(p == NULL) { return;}
    
            memcpy(p->payload, TXbuffer, sizeof(TXbuffer)); // copy the response packet data into the pbuf
            udp_send(pcb, p);                        // send the response
            pbuf_free(p);                            // free the pbuf
    
            __WFI();
        }

    And here's the ISR for the GPIO that I want to wake from sleep.  The GPIO is triggered by the data ready output from the ADC.  I have confirmed that the data ready is toggling at the expected rate.

    void adcReadyFxn(uint_least8_t index)
    {
        int           SPIindex = 1;
        uint16_t      checksum = 0;
        int i;
    
        CS_ADC1;                                     
        ADC_data(&TXbuffer[SPIindex]);               // read one ADC data word
        for (i = 0; i < ADS1283_DATA_WORDSIZE; i++) {
            checksum += TXbuffer[SPIindex++];        // and add to checksum
        }
        CS_ADC2;
        ADC_data(&TXbuffer[SPIindex]);
        for (i = 0; i < ADS1283_DATA_WORDSIZE; i++) {
            checksum += TXbuffer[SPIindex++];
        }
        CS_ADC3;
        ADC_data(&TXbuffer[SPIindex]);
        for (i = 0; i < ADS1283_DATA_WORDSIZE; i++) {
            checksum += TXbuffer[SPIindex++];
        }
        CS_ADC4;
        ADC_data(&TXbuffer[SPIindex]);
        for (i = 0; i < ADS1283_DATA_WORDSIZE; i++) {
            checksum += TXbuffer[SPIindex++];
        }
        CS_ADC5;
    //    ADC_data(&TXbuffer[SPIindex]);                // place holder for additional ADC channels
        for (i = 0; i < ADS1283_DATA_WORDSIZE; i++) {
            TXbuffer[SPIindex] = 0x00;
            checksum += TXbuffer[SPIindex++];
        }
        CS_ADC6;
    //    ADC_data(&TXbuffer[SPIindex]);
        for (i = 0; i < ADS1283_DATA_WORDSIZE; i++) {
            TXbuffer[SPIindex] = 0x00;
            checksum += TXbuffer[SPIindex++];
        }
        CS_NONE;                                     // after reading all channels, disable all CSs
    
        TXbuffer[txBufSize-4] = smplCount;           // insert sample counter value into TX buffer
        *((uint16_t *)&TXbuffer[txBufSize-3]) = checksum; // insert checksum into TX buffer (two bytes)
    
        smplCount = (smplCount+1) % 256;             // increment 8-bit sample counter (modulus 256)
    
        dataReady = true;                            // finally set the data ready semaphore to notify UDP send function
    }
    
    

    If I remove the __WFI() statement it runs as expected.   With the __WFI() statement I never capture any data from the udp_send() command.

  • Ordinarily one would put the WFI in the busy-loop, e.g.

    > while(!dataReady) __WFI();

    but that doesn't explain your symptom, nor does anything else I can think of. It looks like you're using TI Drivers; I wonder if there's something unusual about what that does. 

    Are you fairly certain (breakpoint, e.g.) that adcReadyFxn isn't being called? If you pause in the debugger, where is it executing?

    lwIP also runs from an ISR (timer/Ethernet). Is the networking running?

  • I'd tried the WFI in the busy loop, right after the busy loop and at the end of the wait loop (where it was in the code above) but none of those worked.

    Good advice on using the debugger.  When I paused it was stuck in the Default_Handler() routine.  The PSR Exception register indicates a Hard Fault.  The NVIC Fault Status indicates a Precise Data Bus Error and the Bus Fault Address Register is valid.  The FAULT_ADDR register points to a memory location that is labeled "EMAC0_EMAC_DMARIS", so apparently something is up with the EMAC DMA Interrupt, but I'm not sure what it could be.

    The NVIC PEND registers indicate that there is a pending interrupt on GPIO Port N, which is where the ADC ready pin is connected so I believe the NVIC has seen the external interrupt but obviously something is causing a hard fault before it can service the interrupt.

  • I think your description caused my neuron to fire. I don't have my materials here, but if you can use some hazy memories:

    >MAP_IntPrioritySet(INT_EMAC0, ETHERNET_INT_PRIORITY);
    >MAP_IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY);

    The enet_lwip.c example has these lines (along with an explanation). My symptom was an unexplained Hard Fault apparently returning from the SysTick handler. I worked around it by (I think) setting these two priorities the same, (I think) both to the SysTick priority (i.e. non-0).

    Shortly thereafter, I switched to using FreeRTOS, which has its own priority rules, so I never investigated further. Maybe something to fool with, anyway.

  • I have those two lines (as well as an additional priority setting for the GPIO) in my code right above the section I copied previously in this thread.  I got them from the lwIP example as well.  I tried setting all three priorities to the SysTick priority, as well as setting the EMAC highest but no luck.

    Since this thread has progressed pretty far from the original request, do you think I should post a new topic on the Hard Fault caused by the EMAC interrupt (after I search for an existing solution first)?

    UPDATE:  If I set a break point at the "while (running)" statement, and then use F8 to cycle through the loop, I don't see the fault and I collect data as expected.  As soon as I remove the break point a hard fault is generatred.

  • A new thread is probably more likely to get the attention of a True Wizard. (Sorry. "This was supposed to be easy.")

  • Hey I appreciate the help.  It got me pointed in the direction I need to go.

**Attention** This is a public forum