Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers system_max32620.c Source File

system_max32620.c

00001 /*******************************************************************************
00002  * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017  * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  *
00022  * Except as contained in this notice, the name of Maxim Integrated
00023  * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024  * Products, Inc. Branding Policy.
00025  *
00026  * The mere transfer of this software does not imply any licenses
00027  * of trade secrets, proprietary technology, copyrights, patents,
00028  * trademarks, maskwork rights, or any other form of intellectual
00029  * property whatsoever. Maxim Integrated Products, Inc. retains all
00030  * ownership rights.
00031  *
00032  ******************************************************************************/
00033 
00034 #include <string.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include "max32620.h"
00038 #include "clkman_regs.h"
00039 #include "adc_regs.h"
00040 #include "pwrseq_regs.h"
00041 #include "pwrman_regs.h"
00042 #include "icc_regs.h"
00043 #include "flc_regs.h"
00044 #include "rtc_regs.h"
00045 #include "trim_regs.h"
00046 
00047 #ifndef RO_FREQ
00048 #define RO_FREQ     96000000
00049 #endif
00050 
00051 #ifndef LP0_POST_HOOK
00052 #define LP0_POST_HOOK
00053 #endif
00054 
00055 extern void (* const __isr_vector[])(void);
00056 /*
00057 * Note: When compiling on ARM Keil Toolchain only.
00058 * If the SystemCoreClock is left uninitialized, post Scatter load
00059 * the clock will default to system reset value(48MHz)
00060 */
00061 uint32_t SystemCoreClock = RO_FREQ;
00062 
00063 void SystemCoreClockUpdate(void)
00064 {
00065     if(MXC_PWRSEQ->reg0 & MXC_F_PWRSEQ_REG0_PWR_RCEN_RUN) {
00066         /* 4 MHz source */
00067         if(MXC_PWRSEQ->reg3 & MXC_F_PWRSEQ_REG3_PWR_RC_DIV) {
00068             SystemCoreClock = (4000000 / (0x1 << ((MXC_PWRSEQ->reg3 & MXC_F_PWRSEQ_REG3_PWR_RC_DIV) >>
00069                 MXC_F_PWRSEQ_REG3_PWR_RC_DIV_POS)));
00070         } else {
00071             SystemCoreClock = 4000000;
00072         }
00073     } else {
00074         /* 96 MHz source */
00075         if(MXC_PWRSEQ->reg3 & MXC_F_PWRSEQ_REG3_PWR_RO_DIV) {
00076             SystemCoreClock = (RO_FREQ / (0x1 << ((MXC_PWRSEQ->reg3 & MXC_F_PWRSEQ_REG3_PWR_RO_DIV) >>
00077                 MXC_F_PWRSEQ_REG3_PWR_RO_DIV_POS)));
00078         } else {
00079             SystemCoreClock = RO_FREQ;
00080         }
00081     }
00082 }
00083 
00084 void CLKMAN_TrimRO(void)
00085 {
00086     uint32_t running;
00087     uint32_t trim;
00088 
00089     /* Step 1: enable 32KHz RTC */
00090     running = MXC_PWRSEQ->reg0 & MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
00091     MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
00092 
00093     /* Wait for RTC warm-up */
00094     while(MXC_RTCCFG->osc_ctrl & MXC_F_RTC_OSC_CTRL_OSC_WARMUP_ENABLE) {}
00095 
00096     /* Step 2: enable RO calibration complete interrupt */
00097     MXC_ADC->intr |= MXC_F_ADC_INTR_RO_CAL_DONE_IE;
00098 
00099     /* Step 3: clear RO calibration complete interrupt */
00100     MXC_ADC->intr |= MXC_F_ADC_INTR_RO_CAL_DONE_IF;
00101 
00102     /* Step 4: -- NO LONGER NEEDED / HANDLED BY STARTUP CODE -- */
00103 
00104     /* Step 5: write initial trim to frequency calibration initial condition register */
00105     trim = (MXC_PWRSEQ->reg6 & MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF) >> MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF_POS;
00106     MXC_ADC->ro_cal1 = (MXC_ADC->ro_cal1 & ~MXC_F_ADC_RO_CAL1_TRM_INIT) |
00107                        ((trim << MXC_F_ADC_RO_CAL1_TRM_INIT_POS) & MXC_F_ADC_RO_CAL1_TRM_INIT);
00108 
00109     /* Step 6: load initial trim to active frequency trim register */
00110     MXC_ADC->ro_cal0 |= MXC_F_ADC_RO_CAL0_RO_CAL_LOAD;
00111 
00112     /* Step 7: enable frequency loop to control RO trim */
00113     MXC_ADC->ro_cal0 |= MXC_F_ADC_RO_CAL0_RO_CAL_EN;
00114 
00115     /* Step 8: run frequency calibration in atomic mode */
00116     MXC_ADC->ro_cal0 |= MXC_F_ADC_RO_CAL0_RO_CAL_ATOMIC;
00117 
00118     /* Step 9: waiting for ro_cal_done flag */
00119     while(!(MXC_ADC->intr & MXC_F_ADC_INTR_RO_CAL_DONE_IF));
00120 
00121     /* Step 10: stop frequency calibration */
00122     MXC_ADC->ro_cal0 &= ~MXC_F_ADC_RO_CAL0_RO_CAL_RUN;
00123 
00124     /* Step 11: disable RO calibration complete interrupt */
00125     MXC_ADC->intr &= ~MXC_F_ADC_INTR_RO_CAL_DONE_IE;
00126 
00127     /* Step 12: read final frequency trim value */
00128     trim = (MXC_ADC->ro_cal0 & MXC_F_ADC_RO_CAL0_RO_TRM) >> MXC_F_ADC_RO_CAL0_RO_TRM_POS;
00129 
00130     /* Step 13: write final trim to RO flash trim shadow register */
00131     MXC_PWRSEQ->reg6 = (MXC_PWRSEQ->reg6 & ~MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF) |
00132                        ((trim << MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF_POS) & MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF);
00133 
00134     /* Step 14: restore RTC status */
00135     if (!running) {
00136         MXC_PWRSEQ->reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
00137     }
00138 
00139     /* Step 15: disable frequency loop to control RO trim */
00140     MXC_ADC->ro_cal0 &= ~MXC_F_ADC_RO_CAL0_RO_CAL_EN;
00141 }
00142 
00143 static void ICC_Enable(void)
00144 {
00145     /* Invalidate cache and wait until ready */
00146     MXC_ICC->invdt_all = 1;
00147     while (!(MXC_ICC->ctrl_stat & MXC_F_ICC_CTRL_STAT_READY));
00148 
00149     /* Enable cache */
00150     MXC_ICC->ctrl_stat |= MXC_F_ICC_CTRL_STAT_ENABLE;
00151 
00152     /* Must invalidate a second time for proper use */
00153     MXC_ICC->invdt_all = 1;
00154 }
00155 
00156 /* This function is called before C runtime initialization and can be
00157  * implemented by the application for early initializations. If a value other
00158  * than '0' is returned, the C runtime initialization will be skipped.
00159  *
00160  * You may over-ride this function in your program by defining a custom
00161  *  PreInit(), but care should be taken to reproduce the initilization steps
00162  *  or a non-functional system may result.
00163  */
00164 __weak int PreInit(void)
00165 {
00166     /* Increase system clock to 96 MHz */
00167     MXC_CLKMAN->clk_ctrl = MXC_V_CLKMAN_CLK_CTRL_SYSTEM_SOURCE_SELECT_96MHZ_RO;
00168 
00169     /* Performance-measurement hook, may be defined as nothing */
00170     LP0_POST_HOOK;
00171 
00172     /* Enable cache here to reduce boot time */
00173     ICC_Enable();
00174 
00175     return 0;
00176 }
00177 
00178 /*
00179 * Note: When compiling on ARM Keil Toolchain only.
00180 * If the SystemCoreClock is modified in this function, post Scatter load
00181 * the clock will default to system reset value(48MHz)
00182 */
00183 /* This function can be implemented by the application to initialize the board */
00184 __weak int Board_Init(void)
00185 {
00186     /* Do nothing */
00187     return 0;
00188 }
00189 
00190 /* This function is called just before control is transferred to main().
00191  *
00192  * You may over-ride this function in your program by defining a custom
00193  *  SystemInit(), but care should be taken to reproduce the initialization
00194  *  steps or a non-functional system may result.
00195  */
00196 __weak void SystemInit(void)
00197 {
00198     /* Configure the interrupt controller to use the application vector table in */
00199     /* the application space */
00200 #if defined ( __GNUC__)
00201     /* IAR sets the VTOR pointer prior to SystemInit and causes stack corruption to change it here. */
00202     __disable_irq(); /* Disable interrupts */
00203     // SCB->VTOR = (uint32_t)__isr_vector; /* set the Vector Table to point at our ISR table */
00204     __DSB();                        /* bus sync */
00205     __enable_irq();                 /* enable interrupts */
00206 #endif /* __GNUC__ */
00207 
00208     /* Copy trim information from shadow registers into power manager registers */
00209     /* NOTE: Checks have been added to prevent bad/missing trim values from being loaded */
00210     if ((MXC_FLC->ctrl & MXC_F_FLC_CTRL_INFO_BLOCK_VALID) &&
00211             (MXC_TRIM->for_pwr_reg5 != 0xffffffff) &&
00212             (MXC_TRIM->for_pwr_reg6 != 0xffffffff)) {
00213         MXC_PWRSEQ->reg5 = MXC_TRIM->for_pwr_reg5;
00214         MXC_PWRSEQ->reg6 = MXC_TRIM->for_pwr_reg6;
00215     } else {
00216         /* No valid info block, use some reasonable defaults */
00217         MXC_PWRSEQ->reg6 &= ~MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF;
00218         MXC_PWRSEQ->reg6 |= (0x1e0 << MXC_F_PWRSEQ_REG6_PWR_TRIM_OSC_VREF_POS);
00219     }
00220 
00221     /* Improve flash access timing */
00222     MXC_FLC->perform |= (/*MXC_F_FLC_PERFORM_EN_BACK2BACK_RDS | */
00223                          MXC_F_FLC_PERFORM_EN_MERGE_GRAB_GNT |
00224                          MXC_F_FLC_PERFORM_AUTO_TACC |
00225                          MXC_F_FLC_PERFORM_AUTO_CLKDIV);
00226 
00227     /* First, eliminate the unnecessary RTC handshake between clock domains. Must be set as a pair. */
00228     MXC_RTCTMR->ctrl |= (MXC_F_RTC_CTRL_USE_ASYNC_FLAGS |
00229                          MXC_F_RTC_CTRL_AGGRESSIVE_RST);
00230     /* Enable fast read of the RTC timer value, and fast write of all other RTC registers */
00231     MXC_PWRSEQ->rtc_ctrl2 |= (MXC_F_PWRSEQ_RTC_CTRL2_TIMER_AUTO_UPDATE |
00232                               MXC_F_PWRSEQ_RTC_CTRL2_TIMER_ASYNC_WR);
00233     MXC_PWRSEQ->rtc_ctrl2 &= ~(MXC_F_PWRSEQ_RTC_CTRL2_TIMER_ASYNC_RD);
00234 
00235     /* Clear the GPIO WUD event if not waking up from LP0 */
00236     /* this is necessary because WUD flops come up in undetermined state out of POR or SRST*/
00237     if(MXC_PWRSEQ->reg0 & MXC_F_PWRSEQ_REG0_PWR_FIRST_BOOT ||
00238        !(MXC_PWRMAN->pwr_rst_ctrl & MXC_F_PWRMAN_PWR_RST_CTRL_POR)) {
00239         /* Clear GPIO WUD event and configuration registers, globally */
00240         MXC_PWRSEQ->reg1 |= (MXC_F_PWRSEQ_REG1_PWR_CLR_IO_EVENT_LATCH |
00241                  MXC_F_PWRSEQ_REG1_PWR_CLR_IO_CFG_LATCH);
00242         MXC_PWRSEQ->reg1 &= ~(MXC_F_PWRSEQ_REG1_PWR_CLR_IO_EVENT_LATCH |
00243                   MXC_F_PWRSEQ_REG1_PWR_CLR_IO_CFG_LATCH);
00244     } else {
00245                 /* Unfreeze the GPIO by clearing MBUS_GATE, when returning from LP0 */
00246                 MXC_PWRSEQ->reg1 &= ~(MXC_F_PWRSEQ_REG1_PWR_MBUS_GATE);
00247                 /* LP0 wake-up: Turn off special switch to eliminate ~50nA of leakage on VDD12 */
00248                 MXC_PWRSEQ->reg1 &= ~MXC_F_PWRSEQ_REG1_PWR_SRAM_NWELL_SW;
00249     }
00250 
00251     /* Turn on retention regulator */
00252     MXC_PWRSEQ->reg0 |= (MXC_F_PWRSEQ_REG0_PWR_RETREGEN_RUN |
00253                          MXC_F_PWRSEQ_REG0_PWR_RETREGEN_SLP);
00254 
00255     /* Turn on Auto GPIO Freeze/UnFreeze in sleep modes */
00256     MXC_PWRSEQ->reg1 |= MXC_F_PWRSEQ_REG1_PWR_AUTO_MBUS_GATE;
00257 
00258     /* Adjust settings in the retention controller for fastest wake-up time */
00259     MXC_PWRSEQ->retn_ctrl0 |= (MXC_F_PWRSEQ_RETN_CTRL0_RC_REL_CCG_EARLY |
00260                                MXC_F_PWRSEQ_RETN_CTRL0_RC_POLL_FLASH);
00261     MXC_PWRSEQ->retn_ctrl0 &= ~(MXC_F_PWRSEQ_RETN_CTRL0_RC_USE_FLC_TWK);
00262 
00263 
00264     /* Set retention controller TWake cycle count to 1us to minimize the wake-up time */
00265     /* NOTE: flash polling (...PWRSEQ_RETN_CTRL0_RC_POLL_FLASH) must be enabled before changing POR default! */
00266     MXC_PWRSEQ->retn_ctrl1 = (MXC_PWRSEQ->retn_ctrl1 & ~MXC_F_PWRSEQ_RETN_CTRL1_RC_TWK) |
00267                              (1 << MXC_F_PWRSEQ_RETN_CTRL1_RC_TWK_POS);
00268 
00269     /* Improve wake-up time by changing ROSEL to 140ns */
00270     MXC_PWRSEQ->reg3 = (1 << MXC_F_PWRSEQ_REG3_PWR_ROSEL_POS) |
00271         (1 << MXC_F_PWRSEQ_REG3_PWR_FAILSEL_POS) |
00272         (MXC_PWRSEQ->reg3 & ~(MXC_F_PWRSEQ_REG3_PWR_ROSEL |
00273            MXC_F_PWRSEQ_REG3_PWR_FLTRROSEL));
00274 
00275     /* Enable RTOS Mode: Enable 32kHz clock synchronizer to SysTick external clock input */
00276     MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;
00277 
00278     /* Set this so all bits of PWR_MSK_FLAGS are active low to mask the corresponding flags */
00279     MXC_PWRSEQ->pwr_misc |= MXC_F_PWRSEQ_PWR_MISC_INVERT_4_MASK_BITS;
00280 
00281     /* Clear this bit to get the latest PT */
00282     MXC_PWRMAN->pt_regmap_ctrl &= ~MXC_F_PWRMAN_PT_REGMAP_CTRL_ME02A_MODE;
00283 
00284     /* Enable FPU on Cortex-M4, which occupies coprocessor slots 10 & 11 */
00285     /* Grant full access, per "Table B3-24 CPACR bit assignments". */
00286     /* DDI0403D "ARMv7-M Architecture Reference Manual" */
00287     SCB->CPACR |= SCB_CPACR_CP10_Msk | SCB_CPACR_CP11_Msk;
00288     __DSB();
00289     __ISB();
00290 
00291     /* Perform an initial trim of the internal ring oscillator */
00292     CLKMAN_TrimRO();
00293 
00294     SystemCoreClockUpdate();
00295     Board_Init();
00296 }