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.