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.

Setting ADC clock for deep sleep mode

What I'm using

Tiva C launchpad (TM4C123GH6PMI chip)

CCS v5.4

Tiva C driver library v1.1

Hello,

I need a little guidance regarding deep sleep mode.  My understanding (from reading the datasheet and peripheral users guide) is that you are required to power your peripherals off of the PIOSC when in deep sleep mode.  I would like to run my system clock off of the PLL to do work then go to sleep still running the peripherals while sleeping. 

While reading the data sheet I saw that, for the ADC, you are supposed to power up the PLL and then enable PIOSC in the CS bit field and then disable the PLL.  I've tried all the ways I could come up with but I don't seem to be having much luck.  Could someone explain how to do this using the API?  I've tried variations of this code:

	SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_INT);
	SysCtlDelay(5);
	//HWREG(ADC0_BASE + 0xFC8) |= 0x01;
	SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_INT);
	SysCtlDelay(5);

but it doesn't seem to work no matter what I or in there. 

I am also having a similar problem with my timer.  It is being set based on an 80Mhz clock then I hit deep sleep and I think it changes to 16Mhz making my counter now very very slow.  In other words, I'm setting my counter to count to 80,000,000 based on an 80Mhz clock, but when I go to deep sleep my counter runs off of the 16Mhz clock meaning I'm counting to 80,000,000 with a 16Mhz clock making it take much longer to generate an interrupt. 

I'm confident my code works correctly because if I configure the system clock to 16Mhz PIOSC from the beginning and use deep sleep it looks like it works fine.  I get interrupts and my adc values get updated etc...  I think I'm just lacking an good enough understanding of how things behave in deep sleep mode and how you run with the PLL at high speeds when woken up, but still run peripherals off the 16Mhz PIOSC. 

Below is some of my pertinent code sections:

Below is the code that works fine off of the 16Mhz PIOSC in deep sleep mode.  The commented sections are things I've tried to figure this out.  How do I accomplish running the CPU at 80Mhz when the system wakes up (or just off of the PLL in general) while running everything else off of the PIOSC while asleep?  Is that even correct...am I'm understanding correctly that you have to use the PIOSC for peripherals in deep sleep? 

#include <stdio.h>

/*
 * TM4C123G
 */


// TI file includes
#include "driverlib/pin_map.h"
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "uartstdio.h"
#include "driverlib/timer.h"
#include "driverlib/adc.h"

// My file includes
#include "ADC_configuration.h"





//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif










void InitConsole(void)
{

	// ---- Setup UART0 PA0/PA1 ---- //

	// Enable PORTA	(Uart)
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);

	// Enable UART0
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
	// Use 16Mhz internal Oscillator as UART BRCLK
	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
	// Select UART function for PA0/PA1
	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	// Initialize the UART for console I/O.
	UARTStdioConfig(0, 115200, 16000000);
	SysCtlDelay(5);

	//-------------------------------//

}



int main(void) {

	uint32_t clock_rate;
	//uint32_t ADC_data_1step[1];
	//uint32_t ADC_data_1step[8];
	//uint32_t ADC_data_1step[2];
	uint32_t ADC_data_1step[4];
	uint32_t ui32TempValueC;

	// Initialize variables
	ADC_data_flag = 0;		// ADC data ready
	//ADC_data_1step[0] = 0;




	// System clock set to 80Mhz using the 16 Mhz external crystal (MainOscillator) using PLL
	//SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_INT);
	SysCtlDelay(5);
	//HWREG(ADC0_BASE + 0xFC8) |= 0x01;
	SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_INT);
	SysCtlDelay(5);


	// Enable PortF	(LEDS)
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

	// Enable PORTF (toggle pin)
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

	// Setup GPIOF Pins as outputs
	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
	// Setup PB.1 as an output for scope
	GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_1);

	InitConsole();




	WTimer0_64_config();




	// Configure ADC
	ADC0_ProcTrig_Oversampling0_4ch();
	// Operate ADC in Deep Sleep from PIOSC


	// Configuration for sleep mode (not working yet in deep sleep)
	SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_WTIMER0);
	SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_ADC0);
	SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_UART0);
	SysCtlPeripheralClockGating(true);


	// Enable Global processor interrupts
	IntMasterEnable();

	// Config complete, turn on green LED
	UARTprintf("Configuration complete! \n");
	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);
	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0x04);
	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);





	// Enable Timer0
	TimerEnable(WTIMER0_BASE, TIMER_A);



	while(1){


		clock_rate = SysCtlClockGet();



		if(ADC_data_flag == 1){
			ADCSequenceDataGet(ADC0_BASE, 0, ADC_data_1step);
			ui32TempValueC = 1475 - ((2475 * ADC_data_1step[0]) / 4096);
			UARTprintf("Degrees C = %3d*C", ui32TempValueC/10);
			UARTprintf("\n");
			ADC_data_flag = 0;
		}


		SysCtlDeepSleep();



	}


	
	return 0;
}

My timer configuration:

void WTimer0_64_config(void)
{
	//------ Setup Timer 64-bit -----//

	// Enable Timer peripheral
	SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
	// Configure WTimer0 in 64-bit mode
	TimerConfigure(WTIMER0_BASE, TIMER_CFG_PERIODIC_UP);
	// load timer with SysClk/100 (1mS increments)
	TimerLoadSet64(WTIMER0_BASE, (uint64_t)SysCtlClockGet());
	// Enable interrupts
	TimerIntEnable(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
	// Register ISR
	TimerIntRegister(WTIMER0_BASE, TIMER_A, *WTimer0IntHandler);
	// Clear interrupts
	TimerIntClear(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
	//-------------------------------//

}

My ADC configuration:

void ADC0_ProcTrig_Oversampling0_4ch(void)
{
	// ADC0
	// Sequence0	(2-steps, 8-sample FIFO)
	// Step0		(Only use 4 step in 8 step sequencer)
	// Processor Triggered
	// Sample Channel = AIN0 (PE3)
	//


	// Enable ADC peripheral
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
	// Enable PORTE so we and use A0 (PE3)
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	// Set GPIO PE3 as an ADC input
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
	// Enable Sequence 0 (single sample), trigger on processor,
	// highest priority
	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
	// Configure Sequencer 0 to sample 4 channels each store in a step
	// Interrupt on step3 -> final step
	ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH0);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);
	// Register interrupt handler
	ADCIntRegister(ADC0_BASE, 0, *ADC0IntHandler);
	// Clear interrupt flag
	ADCIntClear(ADC0_BASE, 0);
	// Enable interrupts
	ADCIntEnable(ADC0_BASE, 0);
	// Enable Sequencer
	ADCSequenceEnable(ADC0_BASE, 0);

}

I've worked on using the:

	// Configuration for sleep mode (not working yet in deep sleep)
	SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_WTIMER0);
	SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_ADC0);
	SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_UART0);
	SysCtlPeripheralClockGating(true);

calls a bit as well and they don't seem to help.

Thanks for any input,

Rob

  • Hi Robbie,

         I have not checked your clocking. Also, I am not an expert in deep sleep mode. I have some questions below.

    Robbie Valentine said:
    if(ADC_data_flag == 1){

    How does ADC_data_flag become 1?

    Robbie Valentine said:
    ADCIntRegister(ADC0_BASE, 0, *ADC0IntHandler);

    Why do you have an asterisk there? Are you sure that is correct? Please, post your ADC0IntHandler.

    Robbie Valentine said:
    TimerIntRegister(WTIMER0_BASE, TIMER_A, *WTimer0IntHandler);

    Why do you have an asterisk there? Are you sure that is correct? Please, post your WTimer0IntHandler.

    -kel

  • ADC ISR routine:

    // ============================================ //
    // ====== Interrupt Service Routine =========== //
    void ADC0IntHandler(void)
    {
    	ADC_data_flag = 1;
    
    
    	ADCIntClear(ADC0_BASE, 0);
    }
    // ============================================ //

    Timer0 ISR routine:

    // ============================================ //
    // ======== WTimer0 Service Routine =========== //
    void WTimer0IntHandler(void)
    {
        WTimer0_flag = 1;
    
        // Clear Interrupt Flag
        TimerIntClear(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
    
    }
    // ============================================ //

    ADC_data_flag becomes 1 in the adc ISR.  All I do is set this flag and clear the interrupts.  Above are my two interrupt handlers.  I didn't need the asterisk...not sure what I was thinking when I put them in :p 

    Just to reiterate this all works fine when I use the 16Mhz PIOSC as my clock source with no PLL.

    Thanks for the reply!

  • You set your system clock to run off PLL at 80Mhz with the following call.

    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_INT);

    Then you enable ADC module and configure it, after that, you can change the clock source of ADC to be PIOSC with this code.
    HWREG(ADC0_BASE + ADC_O_CC) = ADC_CC_CS_PIOSC;(you seemed to set this bit before ADC is even enabled, it will cause fault in your code)
     
    After this, ADC should be running off 16Mhz of internal PIOSC and should continue to operate during deep sleep mode.
     

    As for the timer, you can run your timer off PIOSC as well, use this API

    TimerClockSourceSet(uint32_t ui32Base, TIMER_CLOCK_PIOSC). Timer should run at the same speed in deepsleep as in normal mode.

    Let me know if this solves the problems.

    Angela

  • Hi Angela,

        I just recently read this below at Tivaware Peripheral Driver Library User Guide 1.0.

        Chapter 21. System Control: "The PIOSC is not available on all Tiva devices"

        Is this a document error?

    -kel


  • Angella,

    Thanks so much for the reply.  I'll work on getting these fixes in tonight and report back.  One quick question I have though is where did you find the function TimerClockSourceSet?  I didnt find it in the Tiva ware peripheral users guide.

     

    update:  That function for the timer doesn't seem to be recognized in the driverlib in tiva ware v1.1.  The timer modules in the part specific data sheet (using the block diagram) only show a lock input of "system clock".  I can't seem to find any bits in the register that allow me to set any clock sources so either.  This is leading me to believe if I set my system clock to 80Mhz my timer will run at that until it hits deep sleep dropping to the 16Mhz PIOSC meaning my Timer will bounce between clock sources.  Am I missing something?

  • Hi Robbie,

    I was wrong about the timer API, it doesn't exist for this device as you have found out. Sorry about giving you the false information.

    I have been reading the datasheet, and I agree with you, the timer in this device cannot source its clock from PIOSC. Does your system have to run at a speed above 16Mhz? If it does, the only thing I can think of is to reconfigure the timer before entering deep sleep mode to use 16Mhz clock, and re-configure it back to use 80Mhz again after waking up. It is cumbersome, but I cannot think of any other solution.

    Hi Kel

    Regarding to "Chapter 21. System Control: "The PIOSC is not available on all Tiva devices""

    You are correct, this is an error in the document, I have raised a bug against it. Thanks for bringing it to our attention. 

    Angela