// Setting up the FlexRam and MPU. Called immediately upon entering main() static inline void setupFlexram(void) { /* Setup the FlexRAM control bits, to allow writing of the application into FlexRAM The FlexRAM has 256KB I-TCM at the top, with 128KB D-TCM immediately below, and 128KB OCRAM at the bottom. */ // barriers __DMB(); __DSB(); __ISB(); #if USE_PROPER_FLEXRAM_CONFIG IOMUXC_GPR->GPR17 = 0xffffaa55; // $0:128K OCRAM, $2:128K DTCM, $4:256K ITCM #else IOMUXC_GPR->GPR17 = 0x55555555; // test for all OCRAM #endif __DSB(); __ISB(); /* NOTE: GPR16.0=0 disables ITCM and GPR16.1=0 disables DTCM. This is in AN12077 but not in the TRM */ IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_MASK; // enable FlexRAM from config rather than fuses __DSB(); __ISB(); #if USE_TCM_SIZE_REGISTER // v--- this register access is in the tech-note AN12077, but not in the TRM register definition IOMUXC_GPR->GPR14 = (IOMUXC_GPR->GPR14 & 0x0000ffff) | 0x00890000; // DTCM 8(128K), ITCM 9(256K) __DSB(); __ISB(); #endif #if 0 // experiment with the TCM controls: FLEXRAM->TCM_CTRL = ( FLEXRAM_TCM_CTRL_FORCE_CLK_ON_MASK | FLEXRAM_TCM_CTRL_TCM_WWAIT_EN_MASK | FLEXRAM_TCM_CTRL_TCM_RWAIT_EN_MASK | 0 ); #endif } /* MPU configuration. */ static inline void ConfigMPU(void) { /* Disable I cache and D cache */ if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) { SCB_DisableICache(); } if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)) { SCB_DisableDCache(); } /* Disable MPU */ ARM_MPU_Disable(); /* MPU configure: Use ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) API in mpu_armv7.h. param DisableExec Instruction access (XN) disable bit: 0=enabled, 1=disabled. param AccessPermission Data access permissions: configure read/write access for User and Privileged mode. Use MACROS defined in mpu_armv7.h: ARM_MPU_AP_NONE/ARM_MPU_AP_PRIV/ARM_MPU_AP_URO/ARM_MPU_AP_FULL/ARM_MPU_AP_PRO/ARM_MPU_AP_RO Combine TypeExtField/IsShareable/IsCacheable/IsBufferable to configure MPU memory access attributes. TypeExtField IsShareable IsCacheable IsBufferable Memory Attribute Shareability Cache 0 x 0 0 Strongly Ordered shareable 0 x 0 1 Device shareable 0 0 1 0 Normal not shareable Outer and inner write through no write allocate 0 0 1 1 Normal not shareable Outer and inner write back no write allocate 0 1 1 0 Normal shareable Outer and inner write through no write allocate 0 1 1 1 Normal shareable Outer and inner write back no write allocate 1 0 0 0 Normal not shareable outer and inner noncache 1 1 0 0 Normal shareable outer and inner noncache 1 0 1 1 Normal not shareable outer and inner write back write/read allocate 1 1 1 1 Normal shareable outer and inner write back write/read allocate 2 x 0 0 Device not shareable Above are normal use settings, if you want to see more details or want to config different inner/outter cache policy. please refer to Table 4-55 / 4-56 in arm cortex-M7 generic user guide param SubRegionDisable Sub-region disable field. 0=sub-region is enabled, 1=sub-region is disabled. param Size Region size of the region to be configured. use ARM_MPU_REGION_SIZE_xxx MACRO in mpu_armv7.h. */ /* * Add default region to deny access to whole address space to workaround speculative prefetch. * Refer to Arm errata 1013783-B for more details. * * Note that writing the RBAR with the EN set (as per the macro) will automatically set the RNR. * Note that priority of overlapping regions is given to the higher region number. */ /* Region 0 setting: Instruction access disabled, No data access permission. */ MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U); MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 0, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB); /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U); // SEMC memory space, entire MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); /* Region 2 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U); // FlexSPI1/2 memory space MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); //#if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1) // This is desired for XIP operation, and probably for normal operation as well. // However, AP_RO may affect writing (upgrading) operations, TBD /* Region 3 setting: Memory with Normal type, not shareable, outer/inner write back. */ MPU->RBAR = ARM_MPU_RBAR(3, 0x60000000U); // FlexSPI mem-mapped space, 2MB MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_2MB); //#endif /* Region 4 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U); // entire internal Memory space (not registers) MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB); /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(5, 0x00000000U); // ROM boot loader? MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(6, 0x20000000U); // DTCM?? MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(7, 0x20200000U); // OCRAM2 MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB); /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(8, 0x20280000U); // FlexRAM-OCRAM //MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB); /* Region 9 setting: Memory with Device type, not shareable, no cache (implied), sub-regions, etc Each sub-r is 4KB, so uppper 4 are valid and lower 1 is valid. This still leaves large section of FPGA space that is accessible but invalid. Also instruction access disabled (JIC). */ MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U); // SEMC memory space MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_FULL, 2, 0, 0, 1, 0xf1, ARM_MPU_REGION_SIZE_32KB); /* Region 10 setting: Memory with Device type, not shareable, non-cacheable */ MPU->RBAR = ARM_MPU_RBAR(11, 0x40000000); // AIPS[1:4] register space MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4MB); /* Region 12 setting: Memory with Device type, not shareable, non-cacheable */ MPU->RBAR = ARM_MPU_RBAR(12, 0x42000000); // AIPS5 register space MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB); /* Enable MPU */ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); setupFlexram(); /* Enable I cache and D cache */ // SCB_EnableDCache(); Temporarily disable D-Cache for FlexRAM test SCB_EnableICache(); } // ... then GPIO configured, then clocks configured: static inline void InitClocks(void) { /* what about the internal LDO/DCDC controls? The defaults should be what we use, with 1.1, 2.5, 3.0, and 1.1V nominal outputs */ /* TRM says the boot ROM programs the following CCM registers: CACRR 0x00000001 Arm clock root div.2 CBCDR 0x000A8200 (core clock = 396MHz, default boot frequency) => Periph_clk2 div.1, periph_clk<-pre_periph, (1), SEMC <= div.3, (4), AHB Div.1, IPG div.3, ASEMC<-PLL2.PFD2, SEMC<-periph_clk CSCDR1 0x06490B03 => trace div.4, (5), usdhc2 div.2, usdhc1 div.2, uart clk<-PLL3.80M, uart div.2^4 CBCMR 0x75AE8104 => flexspi2 div.4, lpspi div.6, lcdif div.4, (2), pre_periph<-PLL1, (2), trace<-PLL2.PFD0, periph clk2<=PLL3.SW, flexspi2<-PLL3.PFD0, lpspi<-PLL3.PFD1, (4) CSCMR1 0x67930001 => flexspi<-PLL3.PFD0, (1), flexspi div.8, (1), usdhc2<-PLL2.PFD0, usdhc1<-PLL2.PFD0, sai3<-PLL3.PFD2, sai2<-PLL3.PFD2, sai1<-PLL3.PFD2, perclk<-ipg, perclk div.2 ANALOG_PLL_ARM 0x80002042 => lock, bypass<-REF_CLK_24M, EN, pwrUP, div.66 ANALOG_PLL_SYS 0x80002001 => lock, bypass<-REF_CLK_24M, EN, pwrUP, div.22 ANALOG_PLL_USB1 0x80003040 => lock, bypass<-REF_CLK_24M, EN, pwrUP, en USB clks, div.20 Also, these clock gates are disabled: CCGR0_CG6/7/8/9/10/12/13/14 <= lpuarat3/can1/can1s/can2/can2s/gpt2/gpt2s/lpuart2 CCGR1_CG0/1/2/3/4/5/6/8/12 <= lpspi1/lpspi2/lpspi3/lpspi4/adc2/enet/pit/adc1/lpuart4 CCGR2_CG1/3/4/5/14/15 <= csi/lpi2c1/plpi2c2/lpi2c3/lcd/pxp CCGR3_CG0/1/3/5/10/11/12/13 <= flexio2/lpuart5/lpuart6/lcdif/acmp1/acmp2/acmp3/acmp4 CCGR4_CG8/9/10/11/12/13/14/15 <= pwm1/pwm2/pwm3/pwm4/qdc1/qdc2/qdc3/qdc4 CCGR5_CG1/3/4/7/9/10/11/12/13 <= flexio1/dma/kpp/spdif/sai1/sai2/sai3/lpuart1/lpuart7 CCGR6_CG0/1/2/5/6/7/8/12/13/14/15 <= usboh3/usdhc1/usdhc2/flexspi/trng/lpuart8/timer4/lpi2c4/timer1/timer2/timer3 CCGR6_CG, but s/b <= enet2/flexspi2/can3/can3s/flexio3 */ #define SET_CCM_FIELD(r, m, v) CCM->r = ((CCM->r & ~m) | v) GPIO_WATCHER_1_set; /* Enable 1MHz free-run clock output. */ XTALOSC24M->OSC_CONFIG2 |= XTALOSC24M_OSC_CONFIG2_ENABLE_1M_MASK; XTALOSC24M->OSC_CONFIG2 &= ~XTALOSC24M_OSC_CONFIG2_MUX_1M_MASK; /* Enable XTAL 24MHz clock source. */ CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */ while ((XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0U) {} CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */ while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0UL) {} CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* Enable internal RC. */ XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK; /* Switch clock source to external OSC. */ XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_MASK; /* Set Oscillator ready counter value. */ SET_CCM_FIELD(CCR, CCM_CCR_OSCNT_MASK, CCM_CCR_OSCNT(127)); /* Setting PeriphClk2Mux and PeriphMux to provide stable clock before PLLs are initialized */ SET_CCM_FIELD(CBCMR, CCM_CBCMR_PERIPH_CLK2_SEL_MASK, (1< osc SET_CCM_FIELD(CBCDR, CCM_CBCDR_PERIPH_CLK_SEL_MASK, (1< periph_clk2 /* Set AHB_PODF. */ SET_CCM_FIELD(CBCDR, CCM_CBCDR_AHB_PODF_MASK, (0< div.1 // need to wait for different bus handshake to finish while (CCM->CDHIPR & (CCM_CDHIPR_AHB_PODF_BUSY_MASK)) {} #if 0 ALERT: One of these disables causes the code to hang. Revisit later. /* disable all clock gates NOTE: the boot loader already setup FlexSPI to load myself into OCRAM. We can do it again here for more optimal settings. */ CCM->CCGR0 &= ~(CCM_CCGR0_CG11_MASK | // trace CCM_CCGR0_CG12_MASK | CCM_CCGR0_CG13_MASK | // Gpt2/S CCM_CCGR0_CG14_MASK | CCM_CCGR0_CG6_MASK | // lpuart2/3 CCM_CCGR0_CG7_MASK | CCM_CCGR0_CG8_MASK | CCM_CCGR0_CG9_MASK | CCM_CCGR0_CG10_MASK); // can1/1s/2/2s // do not disable gpio2/dcp/sim_m//mqs/aips_tz2/aips_tz1 CCM->CCGR1 &= ~(CCM_CCGR1_CG0_MASK | CCM_CCGR1_CG1_MASK | CCM_CCGR1_CG2_MASK | CCM_CCGR1_CG3_MASK | // lpspi1/2/3/4 CCM_CCGR1_CG10_MASK | CCM_CCGR1_CG11_MASK | CCM_CCGR1_CG6_MASK | // Gpt1/S, Pit CCM_CCGR1_CG12_MASK | // lpuart4 CCM_CCGR1_CG4_MASK | CCM_CCGR1_CG8_MASK); // ADC1/2 // do not disable gpio5/csu/gpio1/semc_excs/aoi2/enet CCM->CCGR2 &= ~(CCM_CCGR2_CG11_MASK | CCM_CCGR2_CG12_MASK | CCM_CCGR2_CG7_MASK | // xbar1/2/3 CCM_CCGR2_CG3_MASK | CCM_CCGR2_CG4_MASK | CCM_CCGR2_CG5_MASK); // lpi2c1/2/3 // do not disable pxp/lcd/gpio3/ipmux3/2/1/OCOTP/csi/ocram_exsc CCM->CCGR3 &= ~(CCM_CCGR3_CG0_SHIFT | CCM_CCGR3_CG2_MASK | // flexio2/semc CCM_CCGR3_CG1_MASK | CCM_CCGR3_CG3_MASK); // lpuart5/6 // do not disable iomuxc/ocram/acmp4/3/2/1/flexram/wdog1/ewm/gpio4/lcdif/aoi1 // Originally none, but see the TRM note regarding (CCGR6_CG5) //CCM->CCGR4 &= ~(0); // (none) //CCM->CCGR4 &= ~(CCM_CCGR4_CG7_MASK); // sim_eims // do not disable qdcs4/3/2/1/pwm4/3/2/1/sim_eims/sim_m/tsc_dig/sim_m7/bee/iomuxc_gpr/iomuxc/sim_m7_reg CCM->CCGR5 &= ~(CCM_CCGR5_CG12_MASK | CCM_CCGR5_CG13_MASK | // lpuart1/7 CCM_CCGR5_CG1_MASK | CCM_CCGR5_CG7_MASK | // flexio1/spdif CCM_CCGR5_CG9_MASK | CCM_CCGR5_CG10_MASK | CCM_CCGR5_CG11_MASK); // sai1/2/3 // do not disable snvs_ip/hp/sim_main/aips_tz4/wdog2/kpp/dma/wdog3/rom CCM->CCGR6 &= ~(CCM_CCGR6_CG1_MASK | CCM_CCGR6_CG2_MASK | // usdhc1/2 CCM_CCGR6_CG5_MASK | CCM_CCGR6_CG7_MASK); // flexspi/lpuart8 // do not disable timer3/2/1/lpi2c4/anadig/sim_per/aips_tz3/timer4/trng/ipmux4/dcdc/usbch3 // ALERT: UM note says sim_ems_clk_enable (CCGR4_CG7) must be cleared along with flexspi. CCM->CCGR7 &= ~(CCM_CCGR7_CG3_MASK | CCM_CCGR7_CG4_MASK | CCM_CCGR7_CG1_MASK); // can3/3s/flexspi2 // do not disable x9/flexio3/aips_lite/axbs_l/enet2 #endif /* Setup IPG clock*/ SET_CCM_FIELD(CBCDR, CCM_CBCDR_IPG_PODF_MASK, (3< div.4 (no wait necessary) /* Setup ARM clock */ SET_CCM_FIELD(CACRR, CCM_CACRR_ARM_PODF_MASK, (1<CDHIPR & (CCM_CDHIPR_ARM_PODF_BUSY_MASK)) {} // wait for handshake /* setup SEMC clock */ SET_CCM_FIELD(CBCDR, CCM_CBCDR_SEMC_PODF_MASK, (7<CDHIPR & (CCM_CDHIPR_SEMC_PODF_BUSY_SHIFT)) {} // wait for handshake /* Setup PERIPH_CLK2 clock and semc clock sources */ SET_CCM_FIELD(CBCDR, (CCM_CBCDR_PERIPH_CLK2_PODF_MASK | CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK | CCM_CBCDR_SEMC_CLK_SEL_MASK), (3< div.4 (no wait necessary) (0< pll2.pfd2 (alt clock) (0< Periph_clk (main) /* Setup USDHC1/2/trace/uart clock */ SET_CCM_FIELD(CSCDR1, (CCM_CSCDR1_USDHC1_PODF_MASK | CCM_CSCDR1_USDHC2_PODF_MASK | CCM_CSCDR1_TRACE_PODF_MASK | CCM_CSCDR1_UART_CLK_PODF_MASK | CCM_CSCDR1_UART_CLK_SEL_MASK), (4< div.4 (0< div.1 (0< pll3_80m /* Setup usdhc1/2/perclk/flexspi/sai1/2/3 clock */ SET_CCM_FIELD(CSCMR1, (CCM_CSCMR1_USDHC1_CLK_SEL_MASK | CCM_CSCMR1_USDHC2_CLK_SEL_MASK | CCM_CSCMR1_PERCLK_PODF_MASK | CCM_CSCMR1_FLEXSPI_PODF_MASK | CCM_CSCMR1_FLEXSPI_CLK_SEL_MASK | CCM_CSCMR1_SAI1_CLK_SEL_MASK | CCM_CSCMR1_SAI2_CLK_SEL_MASK | CCM_CSCMR1_SAI3_CLK_SEL_MASK), (0< div.5 (2< pll2.pdf2 (2< pll4, 0 -> pll3.pfd2 /* setup can/flexio2 clock */ SET_CCM_FIELD(CSCMR2, (CCM_CSCMR2_CAN_CLK_PODF_MASK | CCM_CSCMR2_CAN_CLK_SEL_MASK | CCM_CSCMR2_FLEXIO2_CLK_SEL_MASK), (1< div.2 (2< pll3_sw_clk(80) (3< pll3_sw_clk /* setup flexspi2/lpspi/trace */ SET_CCM_FIELD(CBCMR, (CCM_CBCMR_FLEXSPI2_PODF_MASK | CCM_CBCMR_FLEXSPI2_CLK_SEL_MASK | CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK | CCM_CBCMR_TRACE_CLK_SEL_MASK), (1< div.2 (3< pll2.main (5< div.6 (2< pll2.main (2< pll2.pfd0 /* Setup SAI1/3/flexio2 clock */ SET_CCM_FIELD(CS1CDR, (CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK | CCM_CS1CDR_SAI3_CLK_PRED_MASK | CCM_CS1CDR_SAI3_CLK_PODF_MASK | CCM_CS1CDR_FLEXIO2_CLK_PRED_MASK | CCM_CS1CDR_FLEXIO2_CLK_PODF_MASK), (1< pre-div.2 (0< div.1 (3< pre-div.4 (1< div.2 (1< pre-div.2 (7< div.8 /* Setup sai2 clock */ SET_CCM_FIELD(CS2CDR, (CCM_CS2CDR_SAI2_CLK_PRED_MASK | CCM_CS2CDR_SAI2_CLK_PODF_MASK), (3< pre-div.4 (1< div.2 /* Setup Lpi2c clock */ SET_CCM_FIELD(CSCDR2, (CCM_CSCDR2_LPI2C_CLK_PODF_MASK | CCM_CSCDR2_LPI2C_CLK_SEL_MASK), (0< div.1 (SDK has 5 -> div.6) (0< pll3.60m /* Setup SPDIF0/flexio1 clock */ SET_CCM_FIELD(CDCDR, (CCM_CDCDR_SPDIF0_CLK_PRED_MASK | CCM_CDCDR_SPDIF0_CLK_PODF_MASK | CCM_CDCDR_SPDIF0_CLK_SEL_MASK | CCM_CDCDR_FLEXIO1_CLK_PRED_MASK | CCM_CDCDR_FLEXIO1_CLK_PODF_MASK | CCM_CDCDR_FLEXIO1_CLK_SEL_MASK), (1< pre-div.2 (7< div.8 (3< pll3_sw_clk (1< pre-div.2 (7< div.8 (3< pll3_sw_clk /* Set Pll3 sw clock source. */ SET_CCM_FIELD(CCSR, CCM_CCSR_PLL3_SW_CLK_SEL_MASK, (0< ref_clk_24m */ CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK)) | // src <= 0 CCM_ANALOG_PLL_ARM_BYPASS_MASK; // bypass <= 1 CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~(CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK | CCM_ANALOG_PLL_ARM_POWERDOWN_MASK))) | // pdwn <= 0 CCM_ANALOG_PLL_ARM_ENABLE_MASK | CCM_ANALOG_PLL_ARM_DIV_SELECT(ARM_PLL_DIVIDER); // enable <= 1, div <= 98 while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0UL) {} // wait to lock CCM_ANALOG->PLL_ARM &= ~CCM_ANALOG_PLL_ARM_BYPASS_MASK; /* Disable Bypass */ /* Init System PLL2 */ #define SYS_PLL_DIVIDER 1 // Fout = Fin * (20 + div*2 + numer/denom) => Fin * (22+1/60000) = 528.0004MHz. #define SYS_PLL_NUMER 1 #define SYS_PLL_DENOM 60000 #define SYS_PLL_PFD0 27 // Fout = (Fpll * 18)/FPD = (9504.0072) /27 => 352.00027MHz #define SYS_PLL_PFD1 16 // => 594.00045MHz #define SYS_PLL_PFD2 24 // => 396.0003MHz #define SYS_PLL_PFD3 16 // => 594.00045MHz /* NOTES: these values came from SDK auto-code. It is unclear why the DENOM is set this way, when dox suggest PLL s/b 528MHz */ /* Bypass PLL first */ CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & ~(CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) | // src <= 0 CCM_ANALOG_PLL_SYS_BYPASS_MASK; // bypass <= 1, CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & ~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK)) | // pwdn <= 0 CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(SYS_PLL_DIVIDER); // enable <= 1, div <= 1 /* Initialize the fractional mode */ CCM_ANALOG->PLL_SYS_NUM = CCM_ANALOG_PLL_SYS_NUM_A(SYS_PLL_NUMER); CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(SYS_PLL_DENOM); /* Initialize the spread spectrum mode */ CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_ENABLE(0) | // Spread-spectrum not enabled CCM_ANALOG_PLL_SYS_SS_STEP(1) | CCM_ANALOG_PLL_SYS_SS_STOP(1); while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL) {} // wait to lock CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK; /* Disable Bypass */ /* The UM recommends cycling gate AFTER the PLL re-locks. */ /* Disable the PFD clock outputs first (gate=1, but keep the old values) */ CCM_ANALOG->PFD_528 |= (CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD1_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD2_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD3_CLKGATE_MASK); /* set the new values and re-enable outputs (gate=0) */ CCM_ANALOG->PFD_528 = CCM_ANALOG_PFD_528_PFD0_FRAC(SYS_PLL_PFD0) | CCM_ANALOG_PFD_528_PFD1_FRAC(SYS_PLL_PFD1) | CCM_ANALOG_PFD_528_PFD2_FRAC(SYS_PLL_PFD2) | CCM_ANALOG_PFD_528_PFD3_FRAC(SYS_PLL_PFD3); /* Init USB1 PLL3 */ #define USB_PLL_DIVIDER 0 // Fout = Fin * (20 + div*2) => Fin * (20) = 480.000MHz. #define USB_PLL_PFD0 12 // Fout = (Fpll * 18)/FPD = (8640) /12 => 720.000MHz #define USB_PLL_PFD1 16 // => 540.000MHz #define USB_PLL_PFD2 17 // => 508.2353MHz #define USB_PLL_PFD3 19 // => 454.7368MHz /* Bypass PLL first */ CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & ~(CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) | // src <= 0 CCM_ANALOG_PLL_USB1_BYPASS_MASK; // bypass <= 1 CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & ~(CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) | // div <= 0 CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK | // enable <= 1, power <= 1 CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK; // USBPHY clk enable <= 1 while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL) {} // wait to lock CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK; /* Disable Bypass */ /* The UM recommends cycling gate AFTER the PLL re-locks. */ /* Disable the PFD clock outputs first (gate=1, but keep the old values) */ CCM_ANALOG->PFD_480 |= (CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD1_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD2_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD3_CLKGATE_MASK); /* set the new values and re-enable outputs (gate=0) */ CCM_ANALOG->PFD_480 = CCM_ANALOG_PFD_480_PFD0_FRAC(USB_PLL_PFD0) | CCM_ANALOG_PFD_480_PFD1_FRAC(USB_PLL_PFD1) | CCM_ANALOG_PFD_480_PFD2_FRAC(USB_PLL_PFD2) | CCM_ANALOG_PFD_480_PFD3_FRAC(USB_PLL_PFD3); /* Setup Audio PLL4. (unused) */ CCM_ANALOG->PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK; // Power down CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_BYPASS_MASK; // bypass CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | // audio.MSB <= 0 CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK; // defaults: audio.LSB <= 1 CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE_MASK; // re-enable (even tho powered down?) /* Setup Video PLL5. */ #define VID_PLL_DIV 33 // Fout = Fref*(DIV_SEL + NUMER/DENOM) = 24M*(33 + 1/3) => 800MHz #define VID_PLL_NUMER 1 #define VID_PLL_DENOM 3 #define VID_PLL_POST_DIV 0 // div.4 (pll_video reg) #define VID_MISC2_POST_DIV 0 // div.1 (misc2 reg) CCM_ANALOG->PLL_VIDEO &= ~(CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK); // disable first CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_BYPASS_MASK; // then bypass CCM_ANALOG->PLL_VIDEO_NUM = CCM_ANALOG_PLL_VIDEO_NUM_A(VID_PLL_NUMER); CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(VID_PLL_DENOM); CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_VIDEO_DIV_MASK)) | CCM_ANALOG_MISC2_VIDEO_DIV(VID_MISC2_POST_DIV); // misc2.div <= 0 CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & ~(CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK | // power up (JIC) CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK)) | // clear old div/post fields CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | // re-enable CCM_ANALOG_PLL_VIDEO_DIV_SELECT(VID_PLL_DIV) | // set div CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(VID_PLL_POST_DIV); // set post-div while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0) { } // wait to lock CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS_MASK; /* Disable Bypass */ /* Powerdown Enet PLL6. */ CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK; // Power down CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_BYPASS_MASK; // bypass, JIC /* Init Usb2 PLL7. */ CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & ~(CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_MASK)) | // src <= 0 CCM_ANALOG_PLL_USB2_BYPASS_MASK; // bypass <= 1 CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & ~(CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK)) | CCM_ANALOG_PLL_USB2_ENABLE_MASK | CCM_ANALOG_PLL_USB2_POWER_MASK | // enable and power-up PLL CCM_ANALOG_PLL_USB2_DIV_SELECT(0) | // div==0 for proper USB operation CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK; // USBPHY clk enable <= 1 while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0UL) {} // wait to lock CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_BYPASS_MASK; /* Disable Bypass */ /* Enable the USB Phy's */ USBPHY1->CTRL &= ~(USBPHY_CTRL_SFTRST_MASK | USBPHY_CTRL_CLKGATE_MASK); /* release PHY from reset */ USBPHY1->PWD = 0; USBPHY1->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK; USBPHY2->CTRL &= ~(USBPHY_CTRL_SFTRST_MASK | USBPHY_CTRL_CLKGATE_MASK); /* release PHY from reset */ USBPHY2->PWD = 0; USBPHY2->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK; /* Set periph clock sources. */ SET_CCM_FIELD(CBCMR, CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK, (3< PLL1.div SET_CCM_FIELD(CBCDR, CCM_CBCDR_PERIPH_CLK_SEL_MASK, (0< pre_periph SET_CCM_FIELD(CBCMR, CCM_CBCMR_PERIPH_CLK2_SEL_MASK, (0< pll3_sw_clk SET_CCM_FIELD(CSCMR1, CCM_CSCMR1_PERCLK_CLK_SEL_MASK, (0< ipg clk root CCM_ANALOG->MISC1 = (CCM_ANALOG->MISC1 & (~CCM_ANALOG_MISC1_LVDS1_CLK_SEL_MASK)) | CCM_ANALOG_MISC1_LVDS1_CLK_SEL(0); // lvds: 0 -> ARM PLL CCM->CCOSR = CCM_CCOSR_CLKO1_EN_MASK | CCM_CCOSR_CLKO2_EN_MASK | // enable CLKO1/2, (0 -> clko1 drives clko1) CCM_CCOSR_CLKO1_SEL(3) | CCM_CCOSR_CLKO1_DIV(0) | // clko1: vid_pll.div2 (div.1) //CCM_CCOSR_CLKO2_SEL(17) | CCM_CCOSR_CLKO2_DIV(0); // clko2: usdhc2_clk_root (div.1) CCM_CCOSR_CLKO2_SEL(28) | CCM_CCOSR_CLKO2_DIV(0); // clko2: uart_clk_root (div.1) /* set sai clock sources */ IOMUXC_GPR->GPR1 = (IOMUXC_GPR->GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK | // clr mask fields IOMUXC_GPR_GPR1_SAI1_MCLK2_SEL_MASK | IOMUXC_GPR_GPR1_SAI1_MCLK3_SEL_MASK | IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL_MASK | IOMUXC_GPR_GPR1_SAI3_MCLK3_SEL_MASK | IOMUXC_GPR_GPR1_ENET1_TX_CLK_DIR_MASK | IOMUXC_GPR_GPR1_ENET2_TX_CLK_DIR_MASK)) | // both enet tx clks disabled IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0) | // 0 -> ccm.ssi1_clk IOMUXC_GPR_GPR1_SAI1_MCLK2_SEL(0) | // 0 -> ccm.ssi1_clk IOMUXC_GPR_GPR1_SAI1_MCLK3_SEL(0) | // 0 -> ccm.spdf0_clk IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL(0) | // 0 -> ccm.spdf0_clk IOMUXC_GPR_GPR1_SAI3_MCLK3_SEL(0); // 0 -> ccm.spdf0_clk /* Set MQS configuration. */ IOMUXC_GPR->GPR2 = (IOMUXC_GPR->GPR2 & ~(IOMUXC_GPR_GPR2_MQS_OVERSAMPLE_MASK | IOMUXC_GPR_GPR2_MQS_CLK_DIV_MASK)) | IOMUXC_GPR_GPR2_MQS_OVERSAMPLE(0) | IOMUXC_GPR_GPR2_MQS_CLK_DIV(0); // oversample 32, 0 -> div.1 IOMUXC_GPR->GPR5 &= ~(IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT1_MASK | IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK); // gpt1/2 ipg_hf <= IPG_PERCLK /* turn on all the clocks we use. Always-on mode. */ CCM->CCGR0 |= (CCM_CCGR0_CG11_MASK | CCM_CCGR0_CG15_MASK | // trace (JIC), gpio2 CCM_CCGR0_CG12_MASK | CCM_CCGR0_CG13_MASK); // Gpt2/S (JIC) CCM->CCGR1 |= (CCM_CCGR1_CG0_MASK | CCM_CCGR1_CG13_MASK | // lpspi1, gpio1 (JIC) CCM_CCGR1_CG10_MASK | CCM_CCGR1_CG11_MASK | CCM_CCGR1_CG6_MASK | // Gpt1/S, Pit CCM_CCGR1_CG8_MASK | CCM_CCGR1_CG4_MASK); // ADC1, ADC2 CCM->CCGR2 |= (CCM_CCGR2_CG11_MASK | CCM_CCGR2_CG12_MASK | CCM_CCGR2_CG7_MASK | // xbar1 xbar2/3 (TBD) CCM_CCGR2_CG3_MASK | CCM_CCGR2_CG13_MASK); // lpi2c1, gpio3 (JIC) CCM->CCGR3 |= (CCM_CCGR3_CG2_MASK | CCM_CCGR3_CG9_MASK | CCM_CCGR3_CG14_MASK | // semc, Flexram, ocram CCM_CCGR3_CG8_MASK | CCM_CCGR3_CG6_MASK); // wdt1 (JIC), gpio4 (JIC) CCM->CCGR4 |= (CCM_CCGR4_CG2_MASK | CCM_CCGR4_CG1_MASK); // iomuxc gpr, clk CCM->CCGR5 |= (CCM_CCGR5_CG12_MASK | CCM_CCGR5_CG3_MASK); // lpuart1, dma (JIC) CCM->CCGR6 |= (CCM_CCGR6_CG5_MASK | // flexspi CCM_CCGR6_CG15_MASK | CCM_CCGR6_CG14_MASK | CCM_CCGR6_CG13_MASK); // timer3/2/1 //CCM->CCGR7 |= (0); // (none) /* Setup SYSTICK for 100Hz, although we don't actually use it. TRM says if external clock used, this is 24MHz XOSC, but is divided to 100KHz prior. Otherwise core clock */ #define CORE_CLK_FREQ 588000000 SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk); SysTick->LOAD = ((CORE_CLK_FREQ / 100) - 1); // This gives 1.23KHz SysTick->VAL = 0UL; // Load the SysTick Counter Value SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; NVIC_SetPriority(SysTick_IRQn, NVIC_PRIO_SYSTICK); /* set Priority for Systick Interrupt */ NVIC_EnableIRQ(SysTick_IRQn); // setup the watchdog. Do not use RTWDOG nor WDOG-2 (security). These disabled in startup.c // setup WDOG-1 for 5s timeout, with external trigger. // Note that the reset sequence actually needs to be called twice // to retrigger the WDOG. WDOG1->WICR = 0; // no interrupts necessary WDOG1->WCR = 0x093c; // 5s, normal operation during LP/Doze, drive WDOG_B, enable // Setting the PDE also starts the operation. No need for initial trigger // The WDOG_B signal can be driven via GPIO to the external POR signal. Note that when // the dog fires, it resets everything except the IOMUXC registers, which define the // internal routing of the external signals. If we drive WDOG_B externally, then it will // be impossible to determine the cause of reset, either WDOG or external. // Alternatively, we can drive POR externally via GPIO B1_13 (gpio2.29). The choice is // setup in the gpio-pins function. Shared->LastDog = 0xaaaa; // "last" value written /* NOTES: the "lifetime" timer uses channel[3] as an initial prescaler: IPG_root clock @147MHz, prescale 8 and terminus count of (147*125=18375) to give a post-scale frequency of 1KHz. Channel[0][1] is a combined 32b "mS" counter. Total lifetime is 3.2y Also note that when timer in "cascade" mode, it doesn't actually use OFLAG; just counts when a match happens. In the case where OFLAG is set, it maybe gets set once then stays set. This is not really useful, but behaviour TBD during debug. */ TMR1->CHANNEL[0].ENBL = 0x0b; // enable all (0/1/3) immediately, but doesn't start until CTRL written // "mS" counter LSW TMR1->CHANNEL[0].COMP1 = 0xffff; // max roll-over TMR1->CHANNEL[0].LOAD = 0x0000; // restart from 0, which it does anyway TMR1->CHANNEL[0].SCTRL = 0x0020; // enable MASTER oflag (dont need to drive it out of module) TMR1->CHANNEL[0].CSCTRL = 0x0000; // not really using the preload features // "mS" counter MSW TMR1->CHANNEL[1].COMP1 = 0xffff; // max roll-over TMR1->CHANNEL[1].LOAD = 0x0000; // restart from 0, which it does anyway TMR1->CHANNEL[1].SCTRL = 0x0000; // Don't really need this for the MSW counter TMR1->CHANNEL[1].CSCTRL = 0x0000; // not really using the preload features // Prescaler TMR1->CHANNEL[3].COMP1 = (18375 -1); // this gives a 1KHz prescale count TMR1->CHANNEL[3].LOAD = 0x0000; // restart from 0 TMR1->CHANNEL[3].SCTRL = 0x0020; // enable MASTER oflag (dont need to drive it out of module) TMR1->CHANNEL[3].CSCTRL = 0x0000; // not really using the preload features #if 0 // Use non-cascaded timers TMR1->CHANNEL[0].CTRL = 0x4e03; // count +/-, channel[3].out, count-up-to-roll-over, oflag Toggle TMR1->CHANNEL[1].CTRL = 0x4803; // count +/-, channel[0].out, count-up-to-roll-over, oflag Toggle #else // Use cascaded timers TMR1->CHANNEL[0].CTRL = 0xee03; // cascade, channel[3].out, count-up-to-roll-over, oflag Toggle TMR1->CHANNEL[1].CTRL = 0xe803; // cascade, channel[0].out, count-up-to-roll-over, oflag Toggle #endif TMR1->CHANNEL[3].CTRL = 0x3623; // count, ipb.div8, count-up-to-COMP1, oflag toggle // Timing values for the fuse controller (OCOTP) // These values are actual counts, so need (-1) to write to register fields #define TIMING_WAIT 23 // 23@147MHz => 156.4nS > 150nS TRM default (48+1) #define TIMING_RELAX 15 // 15@147MHz => 102.0nS > 100nS TRM default (9+1) #define TIMING_STR_PROG 1750 // (1750-2*140)@147MHz => 10uS TRM default (1877+1) #define TIMING_STR_READ 12 // (12-2*2)&147MHz => 54.4nS > 45nS TRM default (13+1) // also 12&147MHz => 81.6nS > 75nS #define TIMING_RLX_READ 2 // 2@147MHz => 13.6nS > 10nS TRM default (3+1) #define TIMING_RLX_PROG 140 // 140@147MHz => 952nS > 950nS TRM default (146+1) // ALERT: TRM dox on T2:relax_prog is confusing. Assume equation LHS is mistake. /* ALERT: SDK doesn't actually program TIMING2 SDK uses "T:relax" field to calculate T:strobe_prog, but TRM says s/b T2:relax_prog Also, T:strobe_read sould be calculated with T2:relax_read but SDK uses T:relax again. SDK code is carp like the fish. */ #define TIMING_DATA ((((TIMING_WAIT-1) & OCOTP_TIMING_WAIT_MASK) << OCOTP_TIMING_WAIT_SHIFT) | \ (((TIMING_RELAX-1) & OCOTP_TIMING_RELAX_MASK) << OCOTP_TIMING_RELAX_SHIFT) | \ (((TIMING_STR_PROG-1) & OCOTP_TIMING_STROBE_PROG_MASK) << OCOTP_TIMING_STROBE_PROG_SHIFT) | \ (((TIMING_STR_READ-1) & OCOTP_TIMING_STROBE_READ_MASK) << OCOTP_TIMING_STROBE_READ_SHIFT)) #define TIMING2_DATA ((((TIMING_RLX_PROG-1) & OCOTP_TIMING2_RELAX_PROG_MASK) << OCOTP_TIMING2_RELAX_PROG_SHIFT) | \ (((TIMING_RLX_READ-1) & OCOTP_TIMING2_RELAX_READ_MASK) << OCOTP_TIMING2_RELAX_READ_SHIFT)) OCOTP_Type *base = OCOTP; // Setup the OCOTP clock and timing values (hard-coded for our system) base->TIMING = TIMING_DATA; while (base->CTRL & OCOTP_CTRL_BUSY_MASK) {}; base->TIMING2 = TIMING2_DATA; while (base->CTRL & OCOTP_CTRL_BUSY_MASK) {}; // Check for errors and clear. (should not be) if (OCOTP->CTRL & OCOTP_CTRL_ERROR_MASK) base->CTRL_CLR = OCOTP_CTRL_CLR_ERROR_MASK; GPIO_WATCHER_1_clr; } // The we init the other periphs, including LED driver (GPT4), Console (LPUART1), LPI2C1 // Output a startup message to console // Setup ADC for measuring on-board voltages, etc, // Setup SEMC and LPSPI1 for interface to FPGA (as yet untested) // At this point, the FlexRAM is already broken.