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.

TM4C123GH6PM: Clock Configuration for Deep-Sleep in TM4C123GH6PM (Bare metal)

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: EK-TM4C1294XL

Greetings,

I want to deep sleep a TM4C123GH6PM processor on a custom board, but I think I can't configure the correct clock settings for it.

I'm not using a library for the project that doesn't have any security standards or certifications, like the TivaWare C library... Therefore, I am trying to create everything myself by looking at the datasheet and I think at this stage I think I cannot make the clock settings correctly because when I look at the current level of the processor, I realized that when I put it in sleep mode, it does not drop to the level in deep sleep. I tried 2 different codes for this.

Code in version 1:

/**
 * @brief Set system clock frequency
 *
 * @param ui32Config
 */
void HAL_SYSCTL_Init(uint32_t ui32Config)
{
	uint32_t ui32Delay, ui32RCC, ui32RCC2;

	/* Get the current value of the RCC and RCC2 registers. */
	ui32RCC = HAL_SYSCTL_GENERAL->RCC;
	ui32RCC2 = HAL_SYSCTL_GENERAL->RCC2;

	/* Bypass the PLL and system clock dividers for now. */
	TEK_SETBIT(ui32RCC, (uint32_t) HAL_SYSCTL_RCC_BYPASS);
	TEK_CLRBIT(ui32RCC, (uint32_t) HAL_SYSCTL_RCC_USESYSDIV);
	TEK_SETBIT(ui32RCC2, (uint32_t) HAL_SYSCTL_RCC2_BYPASS2);

	/* Write the new RCC value. */
	HAL_SYSCTL_GENERAL->RCC = ui32RCC;
	HAL_SYSCTL_GENERAL->RCC2 = ui32RCC2;

	/* See if the oscillator needs to be enabled. */
	if ((ui32RCC & HAL_SYSCTL_RCC_MOSCDIS) && !(ui32Config & HAL_SYSCTL_RCC_MOSCDIS)) {
		/* Make sure that the required oscillators are enabled.  For now, the
		 * previously enabled oscillators must be enabled along with the newly
		 * requested oscillators.
		 */
		ui32RCC &= (uint32_t) ((uint32_t) (~HAL_SYSCTL_RCC_MOSCDIS) | (uint32_t) (ui32Config & HAL_SYSCTL_RCC_MOSCDIS));

		/* Clear the MOSC power up raw interrupt status to be sure it is not
		 * set when waiting below.
		 */
		HAL_SYSCTL_GENERAL->MISC = HAL_SYSCTL_MISC_MOSCPUPMIS;

		/* Write the new RCC value. */
		HAL_SYSCTL_GENERAL->RCC = ui32RCC;

		/* Timeout using the legacy delay value. */
		ui32Delay = 524288;

		while ((HAL_SYSCTL_GENERAL->RIS & HAL_SYSCTL_RIS_MOSCPUPRIS) == 0) {
			ui32Delay--;

			if (ui32Delay == 0) {
				break;
			}
		}

		/* If the main oscillator failed to start up then do not switch to
		 * it and return.
		 */
		if (ui32Delay == 0) {
			return;
		}
	}

	/* Set the new crystal value and oscillator source.  Because the OSCSRC2
	 * field in RCC2 overlaps the XTAL field in RCC, the OSCSRC field has a
	 * special encoding within ui32Config to avoid the overlap.
	 */
	TEK_CLRBIT(ui32RCC, (uint32_t) (HAL_SYSCTL_RCC_XTAL_M | HAL_SYSCTL_RCC_OSCSRC_M));
	TEK_SETBIT(ui32RCC, (uint32_t) (ui32Config & (HAL_SYSCTL_RCC_XTAL_M | HAL_SYSCTL_RCC_OSCSRC_M)));
	TEK_CLRBIT(ui32RCC2, (uint32_t) (HAL_SYSCTL_RCC2_USERCC2 | HAL_SYSCTL_RCC2_OSCSRC2_M));
	TEK_SETBIT(ui32RCC2, (uint32_t) ui32Config & (HAL_SYSCTL_RCC2_USERCC2 | HAL_SYSCTL_RCC_OSCSRC_M));
	TEK_SETBIT(ui32RCC2, (uint32_t ) ((ui32Config & 0x00000008) << 3));

	/* Write the new RCC value. */
	HAL_SYSCTL_GENERAL->RCC = ui32RCC;
	HAL_SYSCTL_GENERAL->RCC2 = ui32RCC2;

	/* Set the PLL configuration. */
	TEK_CLRBIT(ui32RCC, (uint32_t) HAL_SYSCTL_RCC_PWRDN);
	TEK_SETBIT(ui32RCC, (uint32_t) (ui32Config & HAL_SYSCTL_RCC_PWRDN));
	TEK_CLRBIT(ui32RCC2, (uint32_t) HAL_SYSCTL_RCC2_PWRDN2);
	TEK_SETBIT(ui32RCC2, (uint32_t) (ui32Config & HAL_SYSCTL_RCC2_PWRDN2));

	/* Clear the PLL lock interrupt. */
	HAL_SYSCTL_GENERAL->MISC = HAL_SYSCTL_MISC_PLLLMIS;

	/* Write the new RCC value. */
	if (ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) {
		HAL_SYSCTL_GENERAL->RCC2 = ui32RCC2;
		HAL_SYSCTL_GENERAL->RCC = ui32RCC;
	} else {
		HAL_SYSCTL_GENERAL->RCC = ui32RCC;
		HAL_SYSCTL_GENERAL->RCC2 = ui32RCC2;
	}

	/* Set the requested system divider and disable the appropriate
	 * oscillators.  This value is not written immediately.
	 */
	TEK_CLRBIT(ui32RCC, (uint32_t) (HAL_SYSCTL_RCC_SYSDIV_M | HAL_SYSCTL_RCC_USESYSDIV | HAL_SYSCTL_RCC_MOSCDIS));
	TEK_SETBIT(ui32RCC, (uint32_t) (ui32Config & (HAL_SYSCTL_RCC_SYSDIV_M | HAL_SYSCTL_RCC_USESYSDIV | HAL_SYSCTL_RCC_MOSCDIS)));
	TEK_CLRBIT(ui32RCC2, (uint32_t) HAL_SYSCTL_RCC2_SYSDIV2_M);
	TEK_SETBIT(ui32RCC2, (uint32_t) ui32Config & HAL_SYSCTL_RCC2_SYSDIV2_M);

	if (ui32Config & HAL_SYSCTL_RCC2_DIV400) {
		TEK_SETBIT(ui32RCC, (uint32_t) HAL_SYSCTL_RCC_USESYSDIV);
		TEK_CLRBIT(ui32RCC2, (uint32_t) HAL_SYSCTL_RCC_USESYSDIV);
		TEK_SETBIT(ui32RCC2, (uint32_t) (ui32Config & (HAL_SYSCTL_RCC2_DIV400 | HAL_SYSCTL_RCC2_SYSDIV2LSB)));
	} else {
		TEK_CLRBIT(ui32RCC2, (uint32_t) HAL_SYSCTL_RCC2_DIV400);
	}

	/* See if the PLL output is being used to clock the system. */
	if (!(ui32Config & HAL_SYSCTL_RCC_BYPASS)) {
		/* Wait until the PLL has locked. */
		for (ui32Delay = 32768; ui32Delay > 0; ui32Delay--) {
			if ((HAL_SYSCTL_GENERAL->PLLSTA & HAL_SYSCTL_PLLSTAT_LOCK)) {
				break;
			}
		}

		/* Enable use of the PLL. */
		TEK_CLRBIT(ui32RCC, (uint32_t) HAL_SYSCTL_RCC_BYPASS);
		TEK_CLRBIT(ui32RCC2, (uint32_t) HAL_SYSCTL_RCC2_BYPASS2);
	}

	/* Write the final RCC value. */
	HAL_SYSCTL_GENERAL->RCC = ui32RCC;
	HAL_SYSCTL_GENERAL->RCC2 = ui32RCC2;

	/* Delay for a little bit so that the system divider takes effect. */
	for (uint32_t i = 0; i < 65535; i++) {
		/* Delay some time */
	}
}


Code in version 2 generated by looking at the TivaWare C SDK:

static const uint32_t g_pui32Xtals[] =
{
    1000000,
    1843200,
    2000000,
    2457600,
    3579545,
    3686400,
    4000000,
    4096000,
    4915200,
    5000000,
    5120000,
    6000000,
    6144000,
    7372800,
    8000000,
    8192000,
    10000000,
    12000000,
    12288000,
    13560000,
    14318180,
    16000000,
    16384000,
    18000000,
    20000000,
    24000000,
    25000000
};


//*****************************************************************************
//
// Maximum number of VCO entries in the g_pui32XTALtoVCO and
// g_pui32VCOFrequencies structures for a device.
//
//*****************************************************************************
#define MAX_VCO_ENTRIES         2
#define MAX_XTAL_ENTRIES        18

//*****************************************************************************
//
// Look up of the possible VCO frequencies.
//
//*****************************************************************************
static const uint32_t g_pui32VCOFrequencies[MAX_VCO_ENTRIES] =
{
    160000000,                              // VCO 320
    240000000,                              // VCO 480
};


//*****************************************************************************
//
// These macros are used in the g_pui32XTALtoVCO table to make it more
// readable.
//
//*****************************************************************************
#define PLL_M_TO_REG(mi, mf)                                                  \
        ((uint32_t)mi | (uint32_t)(mf << HAL_SYSCTL_PLLFREQ0_MFRAC_S))
#define PLL_N_TO_REG(n)                                                       \
        ((uint32_t)(n - 1) << HAL_SYSCTL_PLLFREQ1_N_S)
#define PLL_Q_TO_REG(q)                                                       \
        ((uint32_t)(q - 1) << HAL_SYSCTL_PLLFREQ1_Q_S)

//*****************************************************************************
//
// Look up of the values that go into the PLLFREQ0 and PLLFREQ1 registers.
//
//*****************************************************************************
static const uint32_t g_pppui32XTALtoVCO[MAX_VCO_ENTRIES][MAX_XTAL_ENTRIES][3] =
{
    {
        //
        // VCO 320 MHz
        //
        { PLL_M_TO_REG(64, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 5 MHz
        { PLL_M_TO_REG(62, 512), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 5.12 MHz
        { PLL_M_TO_REG(160, 0),  PLL_N_TO_REG(3), PLL_Q_TO_REG(2) },     // 6 MHz
        { PLL_M_TO_REG(52, 85),  PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 6.144 MHz
        { PLL_M_TO_REG(43, 412), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 7.3728 MHz
        { PLL_M_TO_REG(40, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 8 MHz
        { PLL_M_TO_REG(39, 64),  PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 8.192 MHz
        { PLL_M_TO_REG(32, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 10 MHz
        { PLL_M_TO_REG(80, 0),   PLL_N_TO_REG(3), PLL_Q_TO_REG(2) },     // 12 MHz
        { PLL_M_TO_REG(26, 43),  PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 12.288 MHz
        { PLL_M_TO_REG(23, 613), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 13.56 MHz
        { PLL_M_TO_REG(22, 358), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 14.318180 MHz
        { PLL_M_TO_REG(20, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 16 MHz
        { PLL_M_TO_REG(19, 544), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 16.384 MHz
        { PLL_M_TO_REG(160, 0),  PLL_N_TO_REG(9), PLL_Q_TO_REG(2) },     // 18 MHz
        { PLL_M_TO_REG(16, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 20 MHz
        { PLL_M_TO_REG(40, 0),   PLL_N_TO_REG(3), PLL_Q_TO_REG(2) },     // 24 MHz
        { PLL_M_TO_REG(64, 0),   PLL_N_TO_REG(5), PLL_Q_TO_REG(2) },     // 25 MHz
    },
    {
        //
        // VCO 480 MHz
        //
        { PLL_M_TO_REG(96, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 5 MHz
        { PLL_M_TO_REG(93, 768), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 5.12 MHz
        { PLL_M_TO_REG(80, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 6 MHz
        { PLL_M_TO_REG(78, 128), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 6.144 MHz
        { PLL_M_TO_REG(65, 107), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 7.3728 MHz
        { PLL_M_TO_REG(60, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 8 MHz
        { PLL_M_TO_REG(58, 608), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 8.192 MHz
        { PLL_M_TO_REG(48, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 10 MHz
        { PLL_M_TO_REG(40, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 12 MHz
        { PLL_M_TO_REG(39, 64),  PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 12.288 MHz
        { PLL_M_TO_REG(35, 408), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 13.56 MHz
        { PLL_M_TO_REG(33, 536), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 14.318180 MHz
        { PLL_M_TO_REG(30, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 16 MHz
        { PLL_M_TO_REG(29, 304), PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 16.384 MHz
        { PLL_M_TO_REG(80, 0),   PLL_N_TO_REG(3), PLL_Q_TO_REG(2) },     // 18 MHz
        { PLL_M_TO_REG(24, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 20 MHz
        { PLL_M_TO_REG(20, 0),   PLL_N_TO_REG(1), PLL_Q_TO_REG(2) },     // 24 MHz
        { PLL_M_TO_REG(96, 0),   PLL_N_TO_REG(5), PLL_Q_TO_REG(2) },     // 25 MHz
    },
};

//*****************************************************************************
//
// This macro converts the XTAL value provided in the ui32Config parameter to
// an index to the g_pui32Xtals array.
//
//*****************************************************************************
#define SysCtlXtalCfgToIndex(a) ((a & 0x7c0) >> 6)

STATIC uint32_t _SysCtlMemTimingGet(uint32_t ui32SysClock);
STATIC uint32_t _SysCtlFrequencyGet(uint32_t ui32Xtal);



/**
 * @brief
 *
 * @param ui32Config
 * @param ui32SysClock
 * @return
 */
uint32_t HAL_SYSCTL_Init2(uint32_t ui32Config, uint32_t ui32SysClock)
{
    int32_t i32Timeout, i32VCOIdx, i32XtalIdx;
    uint32_t ui32MOSCCTL;
    uint32_t ui32Delay;
    uint32_t ui32SysDiv, ui32Osc, ui32OscSelect, ui32RSClkConfig;

    // Get the index of the crystal from the ui32Config parameter.
    i32XtalIdx = SysCtlXtalCfgToIndex(ui32Config);

    // Determine which non-PLL source was selected.
    if((ui32Config & 0x38) == HAL_SYSCTL_RCC_OSCSRC_INT) {
            // Use the nominal frequency for the PIOSC oscillator and set the
            // crystal select.
            ui32Osc = 16000000;
            ui32OscSelect = HAL_SYSCTL_RSCLKCFG_OSCSRC_PIOSC;
            ui32OscSelect |= HAL_SYSCTL_RSCLKCFG_PLLSRC_PIOSC;

            // Force the crystal index to the value for 16-MHz.
            i32XtalIdx = SysCtlXtalCfgToIndex(HAL_SYSCTL_RCC_XTAL_16MHZ);
    } else if((ui32Config & 0x38) == HAL_SYSCTL_RCC_OSCSRC_INT30) {
            // Use the nominal frequency for the low frequency oscillator.
            ui32Osc = 30000;
            ui32OscSelect = HAL_SYSCTL_RSCLKCFG_OSCSRC_LFIOSC;
    } else if((ui32Config & 0x38) == (HAL_SYSCTL_RCC_OSCSRC_EXT32 & 0x38)) {
            // Use the RTC frequency.
            ui32Osc = 32768;
            ui32OscSelect = HAL_SYSCTL_RSCLKCFG_OSCSRC_RTC;
    } else if((ui32Config & 0x38) == HAL_SYSCTL_RCC_OSCSRC_MAIN) {
            // Bounds check the source frequency for the main oscillator.  The is
            // because the PLL tables in the g_pppui32XTALtoVCO structure range
            // from 5MHz to 25MHz.
            if((i32XtalIdx > (SysCtlXtalCfgToIndex(HAL_SYSCTL_RCC_XTAL_25MHZ))) ||
                 (i32XtalIdx < (SysCtlXtalCfgToIndex(HAL_SYSCTL_RCC_XTAL_5MHZ)))) {
                    return(0);
            }

            ui32Osc = g_pui32Xtals[i32XtalIdx];

            // Set the PLL source select to MOSC.
            ui32OscSelect = HAL_SYSCTL_RSCLKCFG_OSCSRC_MOSC;
            ui32OscSelect |= HAL_SYSCTL_RSCLKCFG_PLLSRC_MOSC;

            // Clear MOSC power down, high oscillator range setting, and no crystal
            // present setting.
            ui32MOSCCTL = HAL_SYSCTL_GENERAL->MOSCCTL & ~(HAL_SYSCTL_MOSCCTL_OSCRNG | HAL_SYSCTL_MOSCCTL_PWRDN | HAL_SYSCTL_MOSCCTL_NOXTAL);

            // Increase the drive strength for MOSC of 10 MHz and above.
            if(i32XtalIdx >= (SysCtlXtalCfgToIndex(HAL_SYSCTL_RCC_XTAL_10MHZ) -
                                                (SysCtlXtalCfgToIndex(HAL_SYSCTL_RCC_XTAL_5MHZ)))) {
                    ui32MOSCCTL |= HAL_SYSCTL_MOSCCTL_OSCRNG;
            }

            HAL_SYSCTL_GENERAL->MOSCCTL = ui32MOSCCTL;

            // Timeout using the legacy delay value.
            ui32Delay = 524288;

            while((HAL_SYSCTL_GENERAL->RIS & HAL_SYSCTL_RIS_MOSCPUPRIS) == 0) {
                    ui32Delay--;

                    if(ui32Delay == 0)
                            break;
            }

            //
            // If the main oscillator failed to start up then do not switch to
            // it and return.
            //
            if(ui32Delay == 0)
                return(0);
    } else {
            //
            // This was an invalid request because no oscillator source was
            // indicated.
            //
            ui32Osc = 0;
            ui32OscSelect = HAL_SYSCTL_RSCLKCFG_OSCSRC_PIOSC;
    }

    //
    // Check if the running with the PLL enabled was requested.
    //
    if((ui32Config & HAL_SYSCTL_USE_OSC) == HAL_SYSCTL_USE_PLL) {
            //
            // ui32Config must be SYSCTL_OSC_MAIN or SYSCTL_OSC_INT.
            //
            if(((ui32Config & 0x38) != HAL_SYSCTL_RCC_OSCSRC_MAIN) && ((ui32Config & 0x38) != HAL_SYSCTL_RCC_OSCSRC_INT))
                return(0);

            //
            // Get the VCO index out of the ui32Config parameter.
            //
            i32VCOIdx = (ui32Config >> 24) & 7;

            //
            // Set the memory timings for the maximum external frequency since
            // this could be a switch to PIOSC or possibly to MOSC which can be
            // up to 25MHz.
            //
            HAL_SYSCTL_GENERAL->MEMTIM0 = _SysCtlMemTimingGet(25000000);

            // Clear the old PLL divider and source in case it was set.
            ui32RSClkConfig = HAL_SYSCTL_GENERAL->RSCLKCFG & ~(HAL_SYSCTL_RSCLKCFG_PSYSDIV_M | HAL_SYSCTL_RSCLKCFG_OSCSRC_M | HAL_SYSCTL_RSCLKCFG_PLLSRC_M | HAL_SYSCTL_RSCLKCFG_USEPLL);

            // Update the memory timings to match running from PIOSC.
            ui32RSClkConfig |= HAL_SYSCTL_RSCLKCFG_MEMTIMU;

            // Update clock configuration to switch back to PIOSC.
            HAL_SYSCTL_GENERAL->RSCLKCFG = ui32RSClkConfig;

            // The table starts at 5 MHz so modify the index to match this.
            i32XtalIdx -= SysCtlXtalCfgToIndex(HAL_SYSCTL_RCC_XTAL_5MHZ);

            //
            // Calculate the System divider such that we get a frequency that is
            // the closest to the requested frequency without going over.
            //
            ui32SysDiv = (g_pui32VCOFrequencies[i32VCOIdx] + ui32SysClock - 1) /
                                     ui32SysClock;

            // Set the oscillator source.
            HAL_SYSCTL_GENERAL->RSCLKCFG |= ui32OscSelect;

            //
            // Set the M, N and Q values provided from the table and preserve
            // the power state of the main PLL.
            //
            HAL_SYSCTL_GENERAL->PLLFREQ1 = g_pppui32XTALtoVCO[i32VCOIdx][i32XtalIdx][1];
            HAL_SYSCTL_GENERAL->PLLFREQ1 |= PLL_Q_TO_REG(ui32SysDiv);
            HAL_SYSCTL_GENERAL->PLLFREQ0 = (g_pppui32XTALtoVCO[i32VCOIdx][i32XtalIdx][0] | (HAL_SYSCTL_GENERAL->PLLFREQ0 & HAL_SYSCTL_PLLFREQ0_PLLPWR));

            // Calculate the actual system clock as PSYSDIV is always div-by 2.
            ui32SysClock = _SysCtlFrequencyGet(ui32Osc) / 2;

            // Set the Flash and EEPROM timing values.
            HAL_SYSCTL_GENERAL->MEMTIM0 = _SysCtlMemTimingGet(ui32SysClock);

            // Check if the PLL is already powered up.
            if(HAL_SYSCTL_GENERAL->PLLFREQ0 & HAL_SYSCTL_PLLFREQ0_PLLPWR)  // Trigger the PLL to lock to the new frequency.
                    HAL_SYSCTL_GENERAL->RSCLKCFG |= HAL_SYSCTL_RSCLKCFG_NEWFREQ;
            else                                                                                                                         // Power up the PLL.
                    HAL_SYSCTL_GENERAL->PLLFREQ0 |= HAL_SYSCTL_PLLFREQ0_PLLPWR;

            //
            // Wait until the PLL has locked.
            //
            for(i32Timeout = 32768; i32Timeout > 0; i32Timeout--) {
                    if((HAL_SYSCTL_GENERAL->PLLSTA & HAL_SYSCTL_PLLSTAT_LOCK)) {
                            break;
                    }
            }

            //
            // If the loop above did not timeout then switch over to the PLL
            //
            if(i32Timeout) {
                    ui32RSClkConfig = HAL_SYSCTL_GENERAL->RSCLKCFG;
                    ui32RSClkConfig |= (1 << HAL_SYSCTL_RSCLKCFG_PSYSDIV_S) | ui32OscSelect | HAL_SYSCTL_RSCLKCFG_USEPLL;
                    ui32RSClkConfig |= HAL_SYSCTL_RSCLKCFG_MEMTIMU;

                    //
                    // Set the new clock configuration.
                    //
                    HAL_SYSCTL_GENERAL->RSCLKCFG = ui32RSClkConfig;
            } else
                    ui32SysClock = 0;
    } else {
            //
            // Set the Flash and EEPROM timing values for PIOSC.
            //
            HAL_SYSCTL_GENERAL->MEMTIM0 = _SysCtlMemTimingGet(16000000);

            //
            // Make sure that the PLL is powered down since it is not being used.
            //
            HAL_SYSCTL_GENERAL->PLLFREQ0 &= ~HAL_SYSCTL_PLLFREQ0_PLLPWR;

            //
            // Clear the old PLL divider and source in case it was set.
            //
            ui32RSClkConfig = HAL_SYSCTL_GENERAL->RSCLKCFG;
            ui32RSClkConfig &= ~(HAL_SYSCTL_RSCLKCFG_OSYSDIV_M | HAL_SYSCTL_RSCLKCFG_OSCSRC_M | HAL_SYSCTL_RSCLKCFG_USEPLL);

            //
            // Update the memory timings.
            //
            ui32RSClkConfig |= HAL_SYSCTL_RSCLKCFG_MEMTIMU;

            //
            // Set the new clock configuration.
            //
            HAL_SYSCTL_GENERAL->RSCLKCFG = ui32RSClkConfig;

            //
            // If zero given as the system clock then default to divide by 1.
            //
            if(ui32SysClock == 0)
                    ui32SysDiv = 0;
            else {
                    //
                    // Calculate the System divider based on the requested
                    // frequency.
                    //
                    ui32SysDiv = ui32Osc / ui32SysClock;

                    //
                    // If the system divisor is not already zero, subtract one to
                    // set the value in the register which requires the value to
                    // be n-1.
                    //
                    if(ui32SysDiv != 0)
                        ui32SysDiv -= 1;

                    //
                    // Calculate the system clock.
                    //
                    ui32SysClock = ui32Osc / (ui32SysDiv + 1);
            }

            //
            // Set the memory timing values for the new system clock.
            //
            HAL_SYSCTL_GENERAL->MEMTIM0 = _SysCtlMemTimingGet(ui32SysClock);

            //
            // Set the new system clock values.
            //
            ui32RSClkConfig = HAL_SYSCTL_GENERAL->MEMTIM0;
            ui32RSClkConfig |= (ui32SysDiv << HAL_SYSCTL_RSCLKCFG_OSYSDIV_S) | ui32OscSelect;

            //
            // Update the memory timings.
            //
            ui32RSClkConfig |= HAL_SYSCTL_RSCLKCFG_MEMTIMU;

            //
            // Set the new clock configuration.
            //
            HAL_SYSCTL_GENERAL->RSCLKCFG = ui32RSClkConfig;
    }

    //
    // Finally change the OSCSRC back to PIOSC
    //
    HAL_SYSCTL_GENERAL->RSCLKCFG &= ~(HAL_SYSCTL_RSCLKCFG_OSCSRC_M);

    return(ui32SysClock);
}

uint32_t HAL_SYSCTL_GetClockFreq()
{
  uint32_t ui32RCC, ui32RCC2, ui32PLL, ui32Clk, ui32Max;
  uint32_t ui32PLL1;

  //
  // Read RCC and RCC2.
  //
  ui32RCC = HAL_SYSCTL_GENERAL->RCC;
  ui32RCC2 = HAL_SYSCTL_GENERAL->RCC2;

  //
  // Get the base clock rate.
  //
  switch((ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) ?
         (ui32RCC2 & HAL_SYSCTL_RCC2_OSCSRC2_M) :
         (ui32RCC & HAL_SYSCTL_RCC_OSCSRC_M)) {
      //
      // The main oscillator is the clock source.  Determine its rate from
      // the crystal setting field.
      //
      case HAL_SYSCTL_RCC_OSCSRC_MAIN:{
          ui32Clk = g_pui32Xtals[(ui32RCC & HAL_SYSCTL_RCC_XTAL_M) >>
                                                                 HAL_SYSCTL_RCC_XTAL_S];
          break;
      }
      //
      // The internal oscillator is the source clock.
      //
      case HAL_SYSCTL_RCC_OSCSRC_INT: {
          //
          // The internal oscillator on all devices is 16 MHz.
          //
          ui32Clk = 16000000;
          break;
      }
      //
      // The internal oscillator divided by four is the source clock.
      //
      case HAL_SYSCTL_RCC_OSCSRC_INT4: {
          //
          // The internal oscillator on all devices is 16 MHz.
          //
          ui32Clk = 16000000 / 4;
          break;
      }
      //
      // The internal 30-KHz oscillator is the source clock.
      //
      case HAL_SYSCTL_RCC2_OSCSRC2_30: {
          //
          // The internal 30-KHz oscillator has an accuracy of +/- 30%.
          //
          ui32Clk = 30000;
          break;
      }
      //
      // The 32.768-KHz clock from the hibernate module is the source clock.
      //
      case HAL_SYSCTL_RCC2_OSCSRC2_32: {
          ui32Clk = 32768;
          break;
      }

      //
      // An unknown setting, so return a zero clock (that is, an unknown
      // clock rate).
      //
      default: {
          return(0);
      }
  }

  //
  // Default the maximum frequency to the maximum 32-bit unsigned value.
  //
  ui32Max = 0xffffffff;

  //
  // See if the PLL is being used.
  //
  if(((ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) &&
      !(ui32RCC2 & HAL_SYSCTL_RCC2_BYPASS2)) ||
     (!(ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) && !(ui32RCC & HAL_SYSCTL_RCC_BYPASS))) {
      //
      // Read the two PLL frequency registers.  The formula for a
      // TM4C123 device is "(xtal * m) / ((q + 1) * (n + 1))".
      //
      ui32PLL = HAL_SYSCTL_GENERAL->PLLFREQ0;
      ui32PLL1 = HAL_SYSCTL_GENERAL->PLLFREQ1;

      //
      // Divide the input clock by the dividers.
      //
      ui32Clk /= ((((ui32PLL1 & HAL_SYSCTL_PLLFREQ1_Q_M) >>
              HAL_SYSCTL_PLLFREQ1_Q_S) + 1) *
                  (((ui32PLL1 & HAL_SYSCTL_PLLFREQ1_N_M) >>
                          HAL_SYSCTL_PLLFREQ1_N_S) + 1) * 2);

      //
      // Multiply the clock by the multiplier, which is split into an
      // integer part and a fractional part.
      //
      ui32Clk = ((ui32Clk * ((ui32PLL & HAL_SYSCTL_PLLFREQ0_MINT_M) >>
              HAL_SYSCTL_PLLFREQ0_MINT_S)) +
                 ((ui32Clk * ((ui32PLL & HAL_SYSCTL_PLLFREQ0_MFRAC_M) >>
                         HAL_SYSCTL_PLLFREQ0_MFRAC_S)) >> 10));

      //
      // Force the system divider to be enabled.  It is always used when
      // using the PLL, but in some cases it does not read as being enabled.
      //
      ui32RCC |= HAL_SYSCTL_RCC_USESYSDIV;

      //
      // Calculate the maximum system frequency.
      //
      switch(HAL_SYSCTL_GENERAL->DC1 & HAL_SYSCTL_DC1_MINSYSDIV_M) {
          case HAL_SYSCTL_DC1_MINSYSDIV_80: {
              ui32Max = 80000000;
              break;
          }
          case HAL_SYSCTL_DC1_MINSYSDIV_50: {
              ui32Max = 50000000;
              break;
          }
          case HAL_SYSCTL_DC1_MINSYSDIV_40: {
              ui32Max = 40000000;
              break;
          }
          case HAL_SYSCTL_DC1_MINSYSDIV_25: {
              ui32Max = 25000000;
              break;
          }
          case HAL_SYSCTL_DC1_MINSYSDIV_20: {
              ui32Max = 20000000;
              break;
          }
          default: {
              break;
          }
      }
  }

  //
  // See if the system divider is being used.
  //
  if(ui32RCC & HAL_SYSCTL_RCC_USESYSDIV) {
      //
      // Adjust the clock rate by the system clock divider.
      //
      if(ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) {
          if((ui32RCC2 & HAL_SYSCTL_RCC2_DIV400) &&
             (((ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) &&
               !(ui32RCC2 & HAL_SYSCTL_RCC2_BYPASS2)) ||
              (!(ui32RCC2 & HAL_SYSCTL_RCC2_USERCC2) &&
               !(ui32RCC & HAL_SYSCTL_RCC_BYPASS)))) {
              ui32Clk = ((ui32Clk * 2) / (((ui32RCC2 &
                                            (HAL_SYSCTL_RCC2_SYSDIV2_M |
                                            HAL_SYSCTL_RCC2_SYSDIV2LSB)) >>
                                           (HAL_SYSCTL_RCC2_SYSDIV2_S - 1)) +
                                          1));
          } else {
              ui32Clk /= (((ui32RCC2 & HAL_SYSCTL_RCC2_SYSDIV2_M) >>
                      HAL_SYSCTL_RCC2_SYSDIV2_S) + 1);
          }
      } else {
          ui32Clk /= (((ui32RCC & HAL_SYSCTL_RCC_SYSDIV_M) >>
                  HAL_SYSCTL_RCC_SYSDIV_S) + 1);
      }
  }

  //
  // Limit the maximum clock to the maximum clock frequency.
  //
  if(ui32Max < ui32Clk) {
      ui32Clk = ui32Max;
  }

  //
  // Return the computed clock rate.
  //
  return(ui32Clk);
}


void HAL_SYSCTL_SetACGStatus(bool enable)
{
  if(enable) {
      HAL_SYSCTL_GENERAL->RCC |= HAL_SYSCTL_RCC_ACG;
  } else {
      HAL_SYSCTL_GENERAL->RCC &= ~(HAL_SYSCTL_RCC_ACG);
  }
}


//*****************************************************************************
//
//! Sets the output voltage of the LDO when the device enters sleep mode.
//!
//! \param ui32Voltage is the required output voltage from the LDO while in
//! sleep mode.
//!
//! This function sets the output voltage of the LDO while in sleep mode.
//! The \e ui32Voltage parameter must be one of the following values:
//! \b SYSCTL_LDO_0_90V, \b SYSCTL_LDO_0_95V, \b SYSCTL_LDO_1_00V,
//! \b SYSCTL_LDO_1_05V, \b SYSCTL_LDO_1_10V, \b SYSCTL_LDO_1_15V, or
//! \b SYSCTL_LDO_1_20V.
//!
//! \note The availability of this feature, the default LDO voltage, and the
//! adjustment range varies with the Tiva part in use.  Please consult the
//! data sheet for the part you are using to determine whether this support is
//! available.
//!
//! \return None.
//
//*****************************************************************************
void HAL_SYSCTL_SetLDOSleep(uint32_t ui32Voltage)
{
    //
    // Set the sleep-mode LDO voltage to the requested value.
    //
    HAL_SYSCTL_GENERAL->LDOSPCTL = ui32Voltage;
}

void HAL_SYSCTL_SetSleepPower(uint32_t ui32Config)
{
    //
    // Set the sleep-mode flash and SRAM power configuration.
    //
    HAL_SYSCTL_GENERAL->SLPPWRCFG = ui32Config;
}

//*****************************************************************************
//
// The mapping of system clock frequency to flash memory timing parameters.
//
//*****************************************************************************
STATIC const struct
{
    uint32_t ui32Frequency;
    uint32_t ui32MemTiming;
}
g_sXTALtoMEMTIM[] =
{
    { 16000000, (HAL_SYSCTL_MEMTIM0_FBCHT_0_5 | HAL_SYSCTL_MEMTIM0_FBCE |
                 (0 << HAL_SYSCTL_MEMTIM0_FWS_S) |
                                 HAL_SYSCTL_MEMTIM0_EBCHT_0_5 | HAL_SYSCTL_MEMTIM0_EBCE |
                 (0 << HAL_SYSCTL_MEMTIM0_EWS_S) |
                                 HAL_SYSCTL_MEMTIM0_MB1) },
    { 40000000, (HAL_SYSCTL_MEMTIM0_FBCHT_1_5 | (1 << HAL_SYSCTL_MEMTIM0_FWS_S) |
            HAL_SYSCTL_MEMTIM0_EBCHT_1_5 | (1 << HAL_SYSCTL_MEMTIM0_EWS_S) |
                HAL_SYSCTL_MEMTIM0_MB1) },
    { 60000000, (HAL_SYSCTL_MEMTIM0_FBCHT_2 | (2 << HAL_SYSCTL_MEMTIM0_FWS_S) |
            HAL_SYSCTL_MEMTIM0_EBCHT_2 | (2 << HAL_SYSCTL_MEMTIM0_EWS_S) |
                HAL_SYSCTL_MEMTIM0_MB1) },
    { 80000000, (HAL_SYSCTL_MEMTIM0_FBCHT_2_5 | (3 << HAL_SYSCTL_MEMTIM0_FWS_S) |
            HAL_SYSCTL_MEMTIM0_EBCHT_2_5 | (3 << HAL_SYSCTL_MEMTIM0_EWS_S) |
                HAL_SYSCTL_MEMTIM0_MB1) },
    { 100000000, (HAL_SYSCTL_MEMTIM0_FBCHT_3 | (4 << HAL_SYSCTL_MEMTIM0_FWS_S) |
            HAL_SYSCTL_MEMTIM0_EBCHT_3 | (4 << HAL_SYSCTL_MEMTIM0_EWS_S) |
                HAL_SYSCTL_MEMTIM0_MB1) },
    { 120000000, (HAL_SYSCTL_MEMTIM0_FBCHT_3_5 | (5 << HAL_SYSCTL_MEMTIM0_FWS_S) |
            HAL_SYSCTL_MEMTIM0_EBCHT_3_5 | (5 << HAL_SYSCTL_MEMTIM0_EWS_S) |
                HAL_SYSCTL_MEMTIM0_MB1) },
};


//*****************************************************************************
//
// Get the correct memory timings for a given system clock value.
//
//*****************************************************************************
STATIC uint32_t _SysCtlMemTimingGet(uint32_t ui32SysClock)
{
    uint_fast8_t ui8Idx;

    //
    // Loop through the flash memory timings.
    //
    for(ui8Idx = 0;
        ui8Idx < (sizeof(g_sXTALtoMEMTIM) / sizeof(g_sXTALtoMEMTIM[0]));
        ui8Idx++)
    {
        //
        // See if the system clock frequency is less than the maximum frequency
        // for this flash memory timing.
        //
        if(ui32SysClock <= g_sXTALtoMEMTIM[ui8Idx].ui32Frequency)
        {
            //
            // This flash memory timing is the best choice for the system clock
            // frequency, so return it now.
            //
            return(g_sXTALtoMEMTIM[ui8Idx].ui32MemTiming);
        }
    }

    //
    // An appropriate flash memory timing could not be found, so the device is
    // being clocked too fast.  Return the default flash memory timing.
    //
    return(0);
}

//*****************************************************************************
//
// Calculate the system frequency from the register settings base on the
// oscillator input.
//
//*****************************************************************************
STATIC uint32_t _SysCtlFrequencyGet(uint32_t ui32Xtal)
{
    uint32_t ui32Result;
    uint_fast16_t ui16F1, ui16F2;
    uint_fast16_t ui16PInt, ui16PFract;
    uint_fast8_t ui8Q, ui8N;

    //
    // Extract all of the values from the hardware registers.
    //
    ui16PFract = ((HAL_SYSCTL_GENERAL->PLLFREQ0 & HAL_SYSCTL_PLLFREQ0_MFRAC_M) >> HAL_SYSCTL_PLLFREQ0_MFRAC_S);
    ui16PInt = HAL_SYSCTL_GENERAL->PLLFREQ0 & HAL_SYSCTL_PLLFREQ0_MINT_M;
    ui8Q = (((HAL_SYSCTL_GENERAL->PLLFREQ1 & HAL_SYSCTL_PLLFREQ1_Q_M) >> HAL_SYSCTL_PLLFREQ1_Q_S) + 1);
    ui8N = (((HAL_SYSCTL_GENERAL->PLLFREQ1 & HAL_SYSCTL_PLLFREQ1_N_M) >> HAL_SYSCTL_PLLFREQ1_N_S) + 1);

    //
    // Divide the crystal value by N.
    //
    ui32Xtal /= (uint32_t)ui8N;

    //
    // Calculate the multiplier for bits 9:5.
    //
    ui16F1 = ui16PFract / 32;

    //
    // Calculate the multiplier for bits 4:0.
    //
    ui16F2 = ui16PFract - (ui16F1 * 32);

    //
    // Get the integer portion.
    //
    ui32Result = ui32Xtal * (uint32_t)ui16PInt;

    //
    // Add first fractional bits portion(9:0).
    //
    ui32Result += (ui32Xtal * (uint32_t)ui16F1) / 32;

    //
    // Add the second fractional bits portion(4:0).
    //
    ui32Result += (ui32Xtal * (uint32_t)ui16F2) / 1024;

    //
    // Divide the result by Q.
    //
    ui32Result = ui32Result / (uint32_t)ui8Q;

    //
    // Return the resulting PLL frequency.
    //
    return(ui32Result);
}




the code I use to put the program to sleep:

uint32_t *sysctrl_ptr = (uint32_t*) 0xE000ED10;
uint32_t sysctrl_ptr_value  = *sysctrl_ptr;
*sysctrl_ptr = 2;
__asm("    wfi\n");

Specifications of the board:
- Using the code in version 1, I can run the processor at 80 MHz with an external 16 MHz crystal on the board.

Here's what I tried:
- When I tried the code in version 1, it goes into sleep mode and the current drops, but not as much as in deep sleep.

HAL_SYSCTL_Init(HAL_SYSCTL_SYSDIV_2_5 | HAL_SYSCTL_USE_PLL | HAL_SYSCTL_RCC_MOSCDIS | HAL_SYSCTL_RCC_XTAL_16MHZ);


- When I tried the 2nd version code (the function to configure the clock settings I got by looking at the TivaWare C SDK), the processor enters HardFault error mode when I run the code.

HAL_SYSCTL_Init2(HAL_SYSCTL_SYSDIV_2_5 | HAL_SYSCTL_USE_PLL | HAL_SYSCTL_RCC_OSCSRC_MAIN | HAL_SYSCTL_RCC_XTAL_16MHZ, 80000000);


- I had the idea to install the deep-sleep example from the TivaWare C SDK on my own processor and see how it works, but the example is based on TM4C129, not TMC123.
Therefore I couldn't implement this either.

How can I follow a path about this issue, how can I achieve this? I can't find enough examples or resources, so I don't know what to do.

  • Hi,

    I'm not using a library for the project that doesn't have any security standards or certifications, like the TivaWare C library...

    Is there a strong reason not using TivaWare? The SDK is meant to help ease software development for the developers. You are reinventing the wheel doing creating entire driver library. Per FAQ#4 https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/695568/faq-faqs-for-tm4c-arm-cortex-m4f-microcontrollers, we do not recommend writing in DRM style of coding. If you must write in DRM and create your driver library, please refer to the source code of TivaWare APIs. Among all TivaWare APIs, I will say the API SysCtlClockSet() is among the ones that are most critical. This API has been specially fine tuned. I strongly recommend you go through SysCtlClockSet() if you want to write your own. 

    - I had the idea to install the deep-sleep example from the TivaWare C SDK on my own processor and see how it works, but the example is based on TM4C129, not TMC123.
    Therefore I couldn't implement this either.

    Although there is no sleep mode example for TM4C123 in TivaWare, the sleep_modes example in C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\sleep_modes for TM4C129 is definitely the one for reference. The API such as SysCtlDeepSleepClockConfigSet() is common between TM4C123 and TM4C129. 

  • According to our project, every code that is written needs to be tested, but we realized that most of the Tiva code is not testable (infinite loops, direct hardware access without layer structure...). Therefore, we thought we should rewrite the code in a testable way.

    In addition, we are paying attention to DRM, but at this stage we are more focused on solving this problem than on testing the code, so we tried to integrate only the clock part to learn how to solve it. We don't have such a breach in other parts anyway.