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.

Power management in Tiva c



Hi There,

I want to put some of my peripheral in sleep mode or deep sleep mode depending which one is possible. Actually I'm sampling ADC every ms over the 1ms timer interrupt. So I want to put ADC in sleep mode once I got the ADC value and then after 1ms read the ADC and put it in sleep.

Actually I have not much understanding how can I implement this in my application. Kindly could you please provide me some code for this. Thanks

Regards,

Moz

  • Hello Moz,

    The device power management depends on the CPU executing SysCtlSleep or SysCtlDeepSleep function. This would keep the device in idle condition. There are two ways that you can achieve it

    1. Use the SysCtlSleep and/or SysCtlDeepSleep to keep the entire device in idle state, periodically set a timer to generate an ADC conversion which will cause the ADC to convert and then send an interrupt to the CPU causing a system wakeup.

    2. The CPU can use the SysCtlPeripheralDisable to disable the ADC when conversion is not required, then on a periodic interrupt, enable the clock to ADC, trigger the ADC, read the data and shut down the clock.

    The latter I believe has an errata as well, though it is simpler in implementation if the rest of the system is not to be idled.

    Regards

    Amit

  • Hi Amit,

    Thanks for your reply. I'm able to read ADC every ms on 1ms timer interrupt as you can see in my code. Kindly could you please send me some code which shows how I can put the ADC in sleep/deep sleep and enable the ADC when want to get the ADC value after 1ms. Thanks

    See my code below

    //
    // Enable the Timer in Sleep Mode.
    //
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER0);

    //
    // Disable the Adc in Sleep Mode.
    //
    SysCtlPeripheralSleepDisable(SYSCTL_PERIPH_ADC0);

    This is the way iam reading the ADC every ms of timer timer interrupt

    //
    // Trigger the ADC conversion.
    //
    TimerControlTrigger(TIMER0_BASE,
    SysCtlClockGet() / 1000, true);

    while(!ADCIntStatus(ADC0_BASE, 0, false))
    {
    }

    ADCIntClear(ADC0_BASE, 0);

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    ADCSequenceDataGet(ADC0_BASE, 0, &ADC0ValueS0[0]);

    Regards,

    Moz

  • Hello Moz,

    I would modify the code as follows

    //
    // Enable the Timer in Sleep Mode.
    //
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER0);

    //
    // Enable the ADC in Sleep Mode.
    //
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_ADC0);

    AMIT>> I would suggest using Periodic Mode of the timer and enable the ADC Interrupt, with ADC Interrupt Handler to do the following

    ADCIntClear(ADC0_BASE, 0);

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    ADCSequenceDataGet(ADC0_BASE, 0, &ADC0ValueS0[0]);

    AMIT>> For Sleep operations

    //
    // Trigger the ADC conversion.
    //
    TimerControlTrigger(TIMER0_BASE,
    SysCtlClockGet() / 1000, true);

    while(1)

    {

    SysCtlSleep();

    }

    Regards

    Amit

  • Hi Amit,

    I'm still struggling to understand how I can put the ADC in sleep mode. See my code below

    uint32_t ADCValue;

    //*****************************************************************************
    //
    // ADC0 Interrupt Handler
    //
    //*****************************************************************************
    void
    ADCIntHandler(void)
    {
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    ADCIntClear(ADC0_BASE, 0);
    }

    void
    ConfigADC(void)
    {

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    ADCReferenceSet(ADC0_BASE, ADC_REF_INT);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

    ADCSequenceConfigure(ADC0_BASE, 0,

    ADC_TRIGGER_TIMER, 0);

    ADCSequenceStepConfigure(ADC0_BASE, 0,
    0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);

    ADCIntRegister(ADC0_BASE, 0, ADCIntHandler);

    ADCSequenceEnable(ADC0_BASE, 0);

    ADCIntClear(ADC0_BASE, 0);
    }

    void
    ADCRead(void)
    {

    TimerControlTrigger(TIMER0_BASE,
    SysCtlClockGet() / 1000, true);

    //
    // Wait for conversion to be completed.
    //
    while(!ADCIntStatus(ADC0_BASE, 0, false))
    {}

    ADCIntClear(ADC0_BASE, 0);

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    ADCSequenceDataGet(ADC0_BASE, 0, &ADCValue);

  • Hello Moz,

    Since I do not see the place where ADCRead is called and how the timer is being configured, I will suggest the following.

    1. Replace

    //
    // Wait for conversion to be completed.
    //
    while(!ADCIntStatus(ADC0_BASE, 0, false))
    {}

    ADCIntClear(ADC0_BASE, 0);

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    with

    SysCtlSleep();

    2. Add the following as followes (and same for timer)

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_ADC0);

    In general, when making changes for Sleep/Deep Sleep, we would require the scope of the entire project, so that it makes it simpler understanding program flow, rather than code snippets (which would mean our suggestions may not be fully functional)

    Regards

    Amit

  • Hi Amit,

    I'm taking ADC samples every 1ms over 1ms interrupt. I want to put ADC in sleep mode such that when it reads the ADC sample after 1ms, it should go into sleep and should wake up after 1ms to read ADC sample and go back to sleep again. I'm pasting my code below. Kindly could you please modify my code to fulfill the above requirement. Thanks 

    Moz

    void
    TimerIntHandler(void)
    {
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    }

    void
    ConfigTimer(void)
    {

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER0);

    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 1000);

    IntMasterEnable();

    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    IntEnable(INT_TIMER0A);

    TimerEnable(TIMER0_BASE, TIMER_A);

    }

    void
    ADCIntHandler(void)
    {
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    ADCIntClear(ADC0_BASE, 0);
    }

    uint32_t ADCValue;

    void
    ConfigADC(void)
    {

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    ADCReferenceSet(ADC0_BASE, ADC_REF_INT);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

    ADCSequenceConfigure(ADC0_BASE, 0,

    ADC_TRIGGER_TIMER, 0);

    ADCSequenceStepConfigure(ADC0_BASE, 0,
    0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);

    ADCIntRegister(ADC0_BASE, 0, ADCIntHandler);

    ADCSequenceEnable(ADC0_BASE, 0);

    ADCIntClear(ADC0_BASE, 0);
    }

    void
    ADCRead(void)
    {
    TimerControlTrigger(TIMER0_BASE, SysCtlClockGet() / 1000, true);

    while(!ADCIntStatus(ADC0_BASE, 0, false))
    {
    }

    ADCIntClear(ADC0_BASE, 0);

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    ADCSequenceDataGet(ADC0_BASE, 0, &ADCValue);

    }

    int main()

    {

    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);

    ConfigTimer();

    ConfigADC();

    SysCtlPeripheralClockGating(true);

    SysCtlLDOSleepSet(SYSCTL_LDO_1_15V);

    SysCtlSleepPowerSet(SYSCTL_SRAM_STANDBY);

    while(1)

    {

    // Read ADC every 1ms
    ADCRead();

    }

    }

  • Hello Moz,

    Thanks for the code

    Suggestion-1 Replace

    while(!ADCIntStatus(ADC0_BASE, 0, false))
    {
    }

    ADCIntClear(ADC0_BASE, 0);

    with

    SysCtlSleep

    Suggestion-2: remove the following as that is being done in the Timer Interrupt Handler

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    Suggestion-3: Move this to the ADC Interrupt Handler

    ADCSequenceDataGet(ADC0_BASE, 0, &ADCValue);

    Suggestion-4: Add this to the ADC Initialization as well

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_ADC0);

  • Hello Amit,

    I was looking this old post because I want to get 1KHz of sampling frequency of ADC and I wanto to ask you some clarifitications about it.

    1) Why it's no necessary to use

    while(!ADCIntStatus(ADC0_BASE, 3, false))

    { } ADCIntClear(ADC0_BASE, 3); ??

    2) Why the instruction ADCSequenceDataGet() has to be in ADCO Interrupt Handler insteaod of in the while(1)?

    3) To get 1KHz of frequency, if ui32freq=SysCtlGet()=50MHz, I have to put n=5000 in

    TimerLoadSet(TIMER0_BASE, TIMER_A, ui32freq / n);, right?

    4) Is it wrong put SysCtlSleep() after the data acquisition, in this way: 

     ConfigTimer();

    while(1)

    TimerControlTrigger(TIMER0_BASE, SysCtlClockGet() / 1000, true);

    ADCProcessorTrigger(ADC0_BASE, 3);

     while(!ADCIntStatus(ADC0_BASE, 3, false))

    { }

    ADCIntClear(ADC0_BASE, 3);*/

    ADCSequenceDataGet(ADC0_BASE,3,&ADC0Value);

    ADC_Val[i]=ADC0Value;

    SysCtlSleep();

     

    i++;

    }

    I am using Tiva C Launch Pad TM4C123G. ConfigTimer() is the same used by Moz.

    Thank you for any help you can provide.

  • Hello Sabry

    1. The Interrupt Status bit is set (either in RIS or the MIS) only once the conversion is complete and data is in the FIFO. Otherwise you may end up reading the wrong data.
    2. If the Interrupt is used for conversion completion indication then the fastest place to read will be in the interrupt handler, instead of updating a SW flag and reading it the main application.
    3. Yes that is correct.
    4. The SysCtlSleep will put the device into a Sleep Condition and it will not execute any code till an interrupt is asserted. Also note that during debug mode the Sleep state will be skipped and this can only work when not in debug mode. So you need to have a clean and well defined method of waking from sleep mode.

    Regards
    Amit
  • But  to get 1KHz of sampling frequency, I need to use only the timer interrupt, it's not necessary to put ADC in sleep mode, right?

  • Hello Sabry,

    The peripheral that needs to be active in a lower power mode "must" not be in sleep mode. Thus both Timer and ADC must be enabled in sleep mode using the SysCtlPeriperalSleepEnable API and the SysCtlPeripheralClockGating set to true.

    Regards
    Amit
  • Hello All,

    I have used SysCtlSleepEnable(); function to bring my controller in sleep mode. But i dont know how to bring it out of sleep mode? I want using one of my gpio pin input it should go to sleep mode and using another gpio pin input it should come out of sleep mode.

    I have enabled SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOF) so tat i can use PF0 and PF4 switch to do my operation but I dont know how to begin with and how to use it?

    Can anyone suggest?

    Thanks in advance
  • Hello Mitesh

    To wake up the device from Sleep or Deep Sleep mode, you would need to configure the GPIO Pin for interrupt generation as per the requirement of edge (rising or falling or both edge). Also register the interrupt handler in the startup vector table and clear the interrupt so that the device can go back to sleep again.

    Regards
    Amit
  • Thanks Amit for replying,

    I have got a small query. I have generated an interrupt bt is there any function which I need to call so that device can come out of sleep mode?

  • Hello Mitesh,

    No. You only need to call SysCtlSleep or SysCtlDeepSleep to enter sleep/deep sleep mode. Exit is by interrupt automatically,

    Regards
    Amit