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.

MSP430FR5994: Problem with low power modes

Part Number: MSP430FR5994


Hello,

I'm new to the MSP430 so apologies if this a stupid question.

Here is my setup,

DCO at 8MHz

MCLK at 8MHz  (1x divider)

SMCLK at 4MHz (2x divider from DCO)

I2C SCL at 100kHz (auto divider)

The SMCLK is used for an external camera and P3.4 is used to output SMCLK to the camera.

The camera is triggered by writing a register through I2C, at that point the camera raises a pin to indicate a frame is starting and that triggers a DMA transfer from the 3 output pins of the camera to FRAM. The camera outputs a pixel clock which is used as DMAE0. The camera trigger is initiated by a button press.

Here is some pseudo-code:

main()
{
  init_clocks();
  init_GPIO();
  init_i2c();
  init_camera();
  __enable_interrupt();

while(1)
{
       if(img_capturing == 1)
        {
            _low_power_mode_0();
        }
        else
        {
            _low_power_mode_2();
        }

        if(trig_camera)
        {
            trigger_camera();
            trig_camera = 0;
            img_capturing = 1;
        }
       if(image_ready)
       {
            //do something
            img_capturing = 0;
            image_ready = 0;
       }
}
} //main()

// This is the ISR for the VSYNC signal
__interrupt void PORT8_ISR()
{
  setup_DMA_transfer();
  enable_transfer();
}

// ISR to know when the transfer is done
__interrupt void DMA_ISR()
{
  image_ready = 1;
  disable_DMA_interrupt();

  __low_power_mode_off_on_exit();
}

//ISR for the button that triggers the camera
__interrupt void buttonIsrHandler(void)
{
    switch (__even_in_range(P5IV, P5IV_P5IFG7))
    {

        case P5IV_P5IFG6:
            trig_camera = 1;
            __low_power_mode_off_on_exit();
            break;
        default: break;
   }
}

Without using the low power modes everything works fine.

But when I add the management of low power modes as above, the camera is not responding. The VSYINC signal that is generated by the camera, goes high and never goes low again.

My idea is to stay in LPM2 (or lower) when the camera is not taking any pictures (standby). After the camera has been triggered however the chip needs to stay in LPM0 in order to generate the SMCLK that the camera needs. The camera does not need a clock when is in standby so it should be fine if the SMCLK is stopped while not taking pictures.

A strange thing perhaps is that If I add a breakpoint at the line (image_ready = 0;) in the main loop then the code seems to work, every time I press the button the camera is triggered fine. It seems there is some race condition which does not occur if the execution stops for the breakpoint.

What am I missing?

Thanks

  • Hey Alessandro,

    As you have guessed, internal timings can behave while debugging and using breakpoints.  You can run the device in freerun mode while debugging to see a much truer performance, but it will ignore all breakpoints in this mode. 

    Anyway, Are you getting into the Port8_ISR when Vsync goes high in this failure case?    Is the DMA setup successfully and running?  

    If the debugger is interfering, you might have to toggle external GPIO's in the ISR's and use an LSA to monitor them in relation to the video signal.  That way you can see if you make it into the Port8 ISR everytime Vysnc goes high, ect.  

    Thanks,

    JD

  • Hi JD,

    I toggled a pin inside the Port8_ISR and I could see that working every time the Vsync would go hi. However, I noticed that sometimes the pin would toggle also when the device comes out of LPM2. I saw that by probing the SMCLK and the pin I toggle. I could see that when the SMCLK is started the pin would toggle also, only sometimes though.

    Another thing I noticed is that if I put a delay in the main loop, inside the image_ready condition, the device behaves fine, i.e. the Vsync triggers fine, it goes low after the image has been captured and all the ISRs work fine. My thought is that without the delay the device goes to LPM2 "too quickly" stopping the SMCLK to the camera and that somehow upsets the camera. I read the camera's datasheet but there is no mention about this timing or anything related.

    Since I don't like having and arbitrary delay there I tried to capture both edges of the Vsync signal. The rising edge starts the DMA transfer as before but now the image_ready flag is set when the falling edge of Vsync is detected and not at the end of the DMA transfer as before. This way the camera works fine, Vsync goes hi and then low and everything seems ok. Only thing I noticed is that when I toggle a pin in the Port8_ISR, I see that sometimes it toggles also when the device wakes up from the LP (as explained before) even when the Vsync signal is not changing.

    Here is how I modified the Port8_ISR and DMA_ISR:

    volatile uint8_t low_to_hi = 1;
    GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6);
    
    // This is the ISR for the VSYNC signal
    __interrupt void PORT8_ISR()
    {
      P8IFG &= 0b11111110;    // clear irq flag
      P8IES ^= 0x01;          // Toggle Edge sensitivity
    
      if(low_to_hi)
      {
        setup_DMA_transfer();
        enable_transfer();
        low_to_hi = 0;
      }
      else
      {
        low_to_hi = 1;
        image_ready = 1;
        __low_power_mode_off_on_exit();
      }
       
      P2OUT ^= 0x40;          //Toggle 2.6 for testing
    }
    
    // ISR to know when the transfer is done
    __interrupt void DMA_ISR()
    {
      disable_DMA_interrupt();
      __low_power_mode_off_on_exit();
    }

    Another doubt I have regards the FRAM in LPM0. I see from the documentation that it should be in standby. What does it mean exactly? The DMA transfer I set up should write into the FRAM while the chip is in LPM0 so I'm wondering if that is a problem.

    Thanks a lot!

  • Without completely understanding the flow here, I'll just mention that, since wakeups aren't queued, there's a race between the last time you check for an event and the LPM instruction. If the event happens within that window, the wakeup will be lost (and the program may wait forever). The usual defense looks something like:

    > __disable_interrupt();

    > check_for_event_one_last_time();

    > set_LPM_bits_along_with_GIE();

    It looks like _low_power_mode_0() sets GIE (0x08), so you probably don't need to change anything there.

    It seems possible that introducing the delay you mention pushes time back, so the event happens before the last-time-you-check.

    I defer to the Wizards on DMA into FRAM (I haven't had occasion to try it) but the discussion in User Guide (SLAU367O) Sec 7.8 suggests the FRAM controller accommodates this. "Memory accesses pointing into the FRAM address space automatically reset the FRPWR = 1 and re-enable the power supply of the FRAM." doesn't seem to distinguish between CPU and DMA references.

    [Edit: Removed spurious comment about the LEA.]

  • Hi Bruce,

    maybe I didn't understand well your suggestion but to me it seems that what you are describing should not happen here because I have the __low_power_mode_off_on_exit(); instruction in all ISRs that modify the important flags and then, in the main loop I check for these flags after the LPM instructions. So the idea is that as long as the ISRs are executed the system should wake up and do something based on the values of the flags.

    Regarding DMA into FRAM, actually it seems that it is not possible. Leaving the system in LPM0 during the transfer results in a corrupted image read from the camera (the image buffer in FRAM contains garbage). Instead, if I keep the system in active mode the image data is fine. I'm wondering if there is a way to explicitly keep the FRAM on in LPM0.

    Thanks

  • If a wakeup is done while main() is in active mode, that event is lost. If main then goes into LPM, that wakeup will not wake it up. If that event is the only wakeup source, main will wait in LPM forever. Consider what happens if VSYNC triggers on the instruction before the low_power_mode_0() statement.

    In some systems this isn't a big deal -- maybe there's also a periodic wakeup (1ms timer, e.g.) and latency isn't a concern. It's hard to tell from your pseudo-code whether yours is one of them.

    Sorry about the DMA thing. Maybe this is a useful addition to the User Guide. Is your pixel clock fairly fast? That Section implies that the FRAM requestor will stall, which I think is OK for the DMA, but if the pixel clock is faster than the FRCTL wakeup it would garble things.

  • Hey Alessandro,

    I think bruce might be onto something here.  Based on your pseudo code, it looks like you are always assuming that you will be back to LPM mode before an interrupt fires and that interrupt will wake you and then you will proceed. 

    I think bruce is just saying that, if your interrupt happens to fire before you make it LPM mode, then you will miss it because after the interrupt you will go to sleep and not wake.  (Since the interrupt to wake you already happened.) 

    I like his suggested flow because it should prevent this scenario where the interrupt happens before you make it to LPM mode.

    1. disable interrupts
    2. check if any important interrupts have already happened/set flags
    3. go to LPM mode and re-inable interrupts. 

    You can test out this flow, or you might be able to add another GPIO for when you go to LPM in main and compare that to when your ISR fires and see if these conditions the ISR fires before you go to sleep.    

    Let us know.  

    Thanks,

    JD

**Attention** This is a public forum