[原创] XMC4700 Relax 5V shield 评测:分析XMC4700 Easy Start Project

qwerghf   2017-12-12 22:49 楼主
今天有空可以休息,继续开始玩转XMC4700,在上一节介绍了如何使用官方的IDE,本节开始使用官方的IDE来创建学习XMC4700。本次我们使用第一个工程选项创建工程,如下: 1.jpg 如上就是我们基于XMC4700创建Easy Start Project,根据以前开发的经验,我们先从系统时钟开始分析XMC4700工程。 对于M内核的MCU来说,都是先从汇编启动文件,然后跑到系统配置函数,系统时钟默认配置文件为system_XMC4700.c,如下所示 2.jpg 打开文件,根据硬件我们可以知道系统外部时钟源为12M晶振,可以从代码中看到
  1. /*
  2. // <o> External crystal frequency [Hz]
  3. // <8000000=> 8MHz
  4. // <12000000=> 12MHz
  5. // <16000000=> 16MHz
  6. // <i> Defines external crystal frequency
  7. // <i> Default: 8MHz
  8. */
  9. #define OSCHP_FREQUENCY (12000000U)
  10. /* USB PLL settings, fUSBPLL = 48MHz and fUSBPLLVCO = 384 MHz */
  11. /* Note: Implicit divider of 2 and fUSBPLLVCO >= 260 MHz and fUSBPLLVCO <= 520 MHz*/
  12. #if OSCHP_FREQUENCY == 8000000U
  13. #define USB_PDIV (1U)
  14. #define USB_NDIV (95U)
  15. #elif OSCHP_FREQUENCY == 12000000U
  16. #define USB_PDIV (1U)
  17. #define USB_NDIV (63U)
  18. #elif OSCHP_FREQUENCY == 16000000U
  19. #define USB_PDIV (1U)
  20. #define USB_NDIV (47U)
  21. #else
  22. #error "External crystal frequency not supported"
  23. #endif
可以看到系统时钟为12M,符合硬件,代码中也给我出8M和16M对应的配置定义。 系统的时钟配置函数如下:
  1. __WEAK void SystemInit(void)
  2. {
  3. memcpy(g_chipid, CHIPID_LOC, 16);
  4. SystemCoreSetup();
  5. SystemCoreClockSetup();
  6. }
  7. __WEAK void SystemCoreSetup(void)
  8. {
  9. uint32_t temp;
  10. /* relocate vector table */
  11. __disable_irq();
  12. SCB->VTOR = (uint32_t)(&__Vectors);
  13. __DSB();
  14. __enable_irq();
  15. #if ((__FPU_PRESENT == 1) && (__FPU_USED == 1))
  16. SCB->CPACR |= ((3UL << 10*2) | /* set CP10 Full Access */
  17. (3UL << 11*2) ); /* set CP11 Full Access */
  18. #endif
  19. /* Enable unaligned memory access - SCB_CCR.UNALIGN_TRP = 0 */
  20. SCB->CCR &= ~(SCB_CCR_UNALIGN_TRP_Msk);
  21. temp = FLASH0->FCON;
  22. temp &= ~FLASH_FCON_WSPFLASH_Msk;
  23. temp |= PMU_FLASH_WS;
  24. FLASH0->FCON = temp;
  25. }
  26. __WEAK void SystemCoreClockSetup(void)
  27. {
  28. #if FOFI_CALIBRATION_MODE == FOFI_CALIBRATION_MODE_FACTORY
  29. /* Enable factory calibration */
  30. SCU_PLL->PLLCON0 |= SCU_PLL_PLLCON0_FOTR_Msk;
  31. #else
  32. /* Automatic calibration uses the fSTDBY */
  33. /* Enable HIB domain */
  34. /* Power up HIB domain if and only if it is currently powered down */
  35. if((SCU_POWER->PWRSTAT & SCU_POWER_PWRSTAT_HIBEN_Msk) == 0)
  36. {
  37. SCU_POWER->PWRSET |= SCU_POWER_PWRSET_HIB_Msk;
  38. while((SCU_POWER->PWRSTAT & SCU_POWER_PWRSTAT_HIBEN_Msk) == 0)
  39. {
  40. /* wait until HIB domain is enabled */
  41. }
  42. }
  43. /* Remove the reset only if HIB domain were in a state of reset */
  44. if((SCU_RESET->RSTSTAT) & SCU_RESET_RSTSTAT_HIBRS_Msk)
  45. {
  46. SCU_RESET->RSTCLR |= SCU_RESET_RSTCLR_HIBRS_Msk;
  47. delay(DELAY_CNT_150US_50MHZ);
  48. }
  49. #if STDBY_CLOCK_SRC == STDBY_CLOCK_SRC_OSCULP
  50. /* Enable OSC_ULP */
  51. if ((SCU_HIBERNATE->OSCULCTRL & SCU_HIBERNATE_OSCULCTRL_MODE_Msk) != 0UL)
  52. {
  53. /*enable OSC_ULP*/
  54. while (SCU_GENERAL->MIRRSTS & SCU_GENERAL_MIRRSTS_OSCULCTRL_Msk)
  55. {
  56. /* check SCU_MIRRSTS to ensure that no transfer over serial interface is pending */
  57. }
  58. SCU_HIBERNATE->OSCULCTRL &= ~SCU_HIBERNATE_OSCULCTRL_MODE_Msk;
  59. /* Check if the clock is OK using OSCULP Oscillator Watchdog*/
  60. while (SCU_GENERAL->MIRRSTS & SCU_GENERAL_MIRRSTS_HDCR_Msk)
  61. {
  62. /* check SCU_MIRRSTS to ensure that no transfer over serial interface is pending */
  63. }
  64. SCU_HIBERNATE->HDCR |= SCU_HIBERNATE_HDCR_ULPWDGEN_Msk;
  65. /* wait till clock is stable */
  66. do
  67. {
  68. while (SCU_GENERAL->MIRRSTS & SCU_GENERAL_MIRRSTS_HDCLR_Msk)
  69. {
  70. /* check SCU_MIRRSTS to ensure that no transfer over serial interface is pending */
  71. }
  72. SCU_HIBERNATE->HDCLR |= SCU_HIBERNATE_HDCLR_ULPWDG_Msk;
  73. delay(DELAY_CNT_50US_50MHZ);
  74. } while ((SCU_HIBERNATE->HDSTAT & SCU_HIBERNATE_HDSTAT_ULPWDG_Msk) != 0UL);
  75. }
  76. /* now OSC_ULP is running and can be used*/
  77. /* Select OSC_ULP as the clock source for RTC and STDBY*/
  78. while (SCU_GENERAL->MIRRSTS & SCU_GENERAL_MIRRSTS_HDCR_Msk)
  79. {
  80. /* check SCU_MIRRSTS to ensure that no transfer over serial interface is pending */
  81. }
  82. SCU_HIBERNATE->HDCR |= SCU_HIBERNATE_HDCR_RCS_Msk | SCU_HIBERNATE_HDCR_STDBYSEL_Msk;
  83. #endif /* STDBY_CLOCK_SRC == STDBY_CLOCK_SRC_OSCULP */
  84. /* Enable automatic calibration of internal fast oscillator */
  85. SCU_PLL->PLLCON0 |= SCU_PLL_PLLCON0_AOTREN_Msk;
  86. #endif /* FOFI_CALIBRATION_MODE == FOFI_CALIBRATION_MODE_AUTOMATIC */
  87. delay(DELAY_CNT_50US_50MHZ);
  88. #if ENABLE_PLL
  89. /* enable PLL */
  90. SCU_PLL->PLLCON0 &= ~(SCU_PLL_PLLCON0_VCOPWD_Msk | SCU_PLL_PLLCON0_PLLPWD_Msk);
  91. #if PLL_CLOCK_SRC != PLL_CLOCK_SRC_OFI
  92. /* enable OSC_HP */
  93. if ((SCU_OSC->OSCHPCTRL & SCU_OSC_OSCHPCTRL_MODE_Msk) != 0U)
  94. {
  95. SCU_OSC->OSCHPCTRL &= ~(SCU_OSC_OSCHPCTRL_MODE_Msk | SCU_OSC_OSCHPCTRL_OSCVAL_Msk);
  96. SCU_OSC->OSCHPCTRL |= ((OSCHP_GetFrequency() / FOSCREF) - 1UL) << SCU_OSC_OSCHPCTRL_OSCVAL_Pos;
  97. /* select OSC_HP clock as PLL input */
  98. SCU_PLL->PLLCON2 &= ~SCU_PLL_PLLCON2_PINSEL_Msk;
  99. /* restart OSC Watchdog */
  100. SCU_PLL->PLLCON0 &= ~SCU_PLL_PLLCON0_OSCRES_Msk;
  101. while ((SCU_PLL->PLLSTAT & SCU_PLL_PLLSTAT_OSC_USABLE) != SCU_PLL_PLLSTAT_OSC_USABLE)
  102. {
  103. /* wait till OSC_HP output frequency is usable */
  104. }
  105. }
  106. #else /* PLL_CLOCK_SRC != PLL_CLOCK_SRC_OFI */
  107. /* select backup clock as PLL input */
  108. SCU_PLL->PLLCON2 |= SCU_PLL_PLLCON2_PINSEL_Msk;
  109. #endif
  110. /* Go to bypass the Main PLL */
  111. SCU_PLL->PLLCON0 |= SCU_PLL_PLLCON0_VCOBYP_Msk;
  112. /* disconnect Oscillator from PLL */
  113. SCU_PLL->PLLCON0 |= SCU_PLL_PLLCON0_FINDIS_Msk;
  114. /* Setup divider settings for main PLL */
  115. SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
  116. (PLL_K2DIV_24MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
  117. (PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
  118. /* Set OSCDISCDIS */
  119. SCU_PLL->PLLCON0 |= SCU_PLL_PLLCON0_OSCDISCDIS_Msk;
  120. /* connect Oscillator to PLL */
  121. SCU_PLL->PLLCON0 &= ~SCU_PLL_PLLCON0_FINDIS_Msk;
  122. /* restart PLL Lock detection */
  123. SCU_PLL->PLLCON0 |= SCU_PLL_PLLCON0_RESLD_Msk;
  124. while ((SCU_PLL->PLLSTAT & SCU_PLL_PLLSTAT_VCOLOCK_Msk) == 0U)
  125. {
  126. /* wait for PLL Lock at 24MHz*/
  127. }
  128. /* Disable bypass- put PLL clock back */
  129. SCU_PLL->PLLCON0 &= ~SCU_PLL_PLLCON0_VCOBYP_Msk;
  130. while ((SCU_PLL->PLLSTAT & SCU_PLL_PLLSTAT_VCOBYST_Msk) != 0U)
  131. {
  132. /* wait for normal mode */
  133. }
  134. #endif /* ENABLE_PLL */
  135. /* Before scaling to final frequency we need to setup the clock dividers */
  136. SCU_CLK->SYSCLKCR = __SYSCLKCR;
  137. SCU_CLK->PBCLKCR = __PBCLKCR;
  138. SCU_CLK->CPUCLKCR = __CPUCLKCR;
  139. SCU_CLK->CCUCLKCR = __CCUCLKCR;
  140. SCU_CLK->WDTCLKCR = __WDTCLKCR;
  141. SCU_CLK->EBUCLKCR = __EBUCLKCR;
  142. SCU_CLK->USBCLKCR = __USBCLKCR | USB_DIV;
  143. SCU_CLK->EXTCLKCR = __EXTCLKCR;
  144. #if ENABLE_PLL
  145. /* PLL frequency stepping...*/
  146. /* Reset OSCDISCDIS */
  147. SCU_PLL->PLLCON0 &= ~SCU_PLL_PLLCON0_OSCDISCDIS_Msk;
  148. SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
  149. (PLL_K2DIV_48MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
  150. (PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
  151. delay(DELAY_CNT_50US_48MHZ);
  152. SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
  153. (PLL_K2DIV_72MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
  154. (PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
  155. delay(DELAY_CNT_50US_72MHZ);
  156. SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
  157. (PLL_K2DIV_96MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
  158. (PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
  159. delay(DELAY_CNT_50US_96MHZ);
  160. SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
  161. (PLL_K2DIV_120MHZ << SCU_PLL_PLLCON1_K2DIV_Pos) |
  162. (PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
  163. delay(DELAY_CNT_50US_120MHZ);
  164. SCU_PLL->PLLCON1 = ((PLL_NDIV << SCU_PLL_PLLCON1_NDIV_Pos) |
  165. (PLL_K2DIV << SCU_PLL_PLLCON1_K2DIV_Pos) |
  166. (PLL_PDIV << SCU_PLL_PLLCON1_PDIV_Pos));
  167. delay(DELAY_CNT_50US_144MHZ);
  168. #endif /* ENABLE_PLL */
  169. #if ENABLE_USBPLL
  170. /* enable USB PLL first */
  171. SCU_PLL->USBPLLCON &= ~(SCU_PLL_USBPLLCON_VCOPWD_Msk | SCU_PLL_USBPLLCON_PLLPWD_Msk);
  172. /* USB PLL uses as clock input the OSC_HP */
  173. /* check and if not already running enable OSC_HP */
  174. if ((SCU_OSC->OSCHPCTRL & SCU_OSC_OSCHPCTRL_MODE_Msk) != 0U)
  175. {
  176. /* check if Main PLL is switched on for OSC WDG*/
  177. if ((SCU_PLL->PLLCON0 &(SCU_PLL_PLLCON0_VCOPWD_Msk | SCU_PLL_PLLCON0_PLLPWD_Msk)) != 0UL)
  178. {
  179. /* enable PLL first */
  180. SCU_PLL->PLLCON0 &= ~(SCU_PLL_PLLCON0_VCOPWD_Msk | SCU_PLL_PLLCON0_PLLPWD_Msk);
  181. }
  182. SCU_OSC->OSCHPCTRL &= ~(SCU_OSC_OSCHPCTRL_MODE_Msk | SCU_OSC_OSCHPCTRL_OSCVAL_Msk);
  183. SCU_OSC->OSCHPCTRL |= ((OSCHP_GetFrequency() / FOSCREF) - 1UL) << SCU_OSC_OSCHPCTRL_OSCVAL_Pos;
  184. /* restart OSC Watchdog */
  185. SCU_PLL->PLLCON0 &= ~SCU_PLL_PLLCON0_OSCRES_Msk;
  186. while ((SCU_PLL->PLLSTAT & SCU_PLL_PLLSTAT_OSC_USABLE) != SCU_PLL_PLLSTAT_OSC_USABLE)
  187. {
  188. /* wait till OSC_HP output frequency is usable */
  189. }
  190. }
  191. /* Setup USB PLL */
  192. /* Go to bypass the USB PLL */
  193. SCU_PLL->USBPLLCON |= SCU_PLL_USBPLLCON_VCOBYP_Msk;
  194. /* disconnect Oscillator from USB PLL */
  195. SCU_PLL->USBPLLCON |= SCU_PLL_USBPLLCON_FINDIS_Msk;
  196. /* Setup Divider settings for USB PLL */
  197. SCU_PLL->USBPLLCON = ((USB_NDIV << SCU_PLL_USBPLLCON_NDIV_Pos) |
  198. (USB_PDIV << SCU_PLL_USBPLLCON_PDIV_Pos));
  199. /* Set OSCDISCDIS */
  200. SCU_PLL->USBPLLCON |= SCU_PLL_USBPLLCON_OSCDISCDIS_Msk;
  201. /* connect Oscillator to USB PLL */
  202. SCU_PLL->USBPLLCON &= ~SCU_PLL_USBPLLCON_FINDIS_Msk;
  203. /* restart PLL Lock detection */
  204. SCU_PLL->USBPLLCON |= SCU_PLL_USBPLLCON_RESLD_Msk;
  205. while ((SCU_PLL->USBPLLSTAT & SCU_PLL_USBPLLSTAT_VCOLOCK_Msk) == 0U)
  206. {
  207. /* wait for PLL Lock */
  208. }
  209. #endif
  210. /* Enable selected clocks */
  211. SCU_CLK->CLKSET = __CLKSET;
  212. #if __EXTCLKPIN != 0
  213. #if __EXTCLKPIN == EXTCLK_PIN_P1_15
  214. /* P1.15 */
  215. PORT1->PDR1 &= ~PORT1_PDR1_PD15_Msk;
  216. PORT1->IOCR12 = (PORT1->IOCR12 & ~PORT0_IOCR12_PC15_Msk) | (0x11U << PORT0_IOCR12_PC15_Pos);
  217. #else
  218. /* P0.8 */
  219. PORT0->HWSEL &= ~PORT0_HWSEL_HW8_Msk;
  220. PORT0->PDR1 &= ~PORT0_PDR1_PD8_Msk;
  221. PORT0->IOCR8 = (PORT0->IOCR8 & ~PORT0_IOCR8_PC8_Msk) | (0x11U << PORT0_IOCR8_PC8_Pos);
  222. #endif
  223. #endif /* ENABLE_EXTCLK == 1 */
  224. SystemCoreClockUpdate();
  225. }
  226. __WEAK void SystemCoreClockUpdate(void)
  227. {
  228. uint32_t pdiv;
  229. uint32_t ndiv;
  230. uint32_t kdiv;
  231. uint32_t temp;
  232. if (SCU_CLK->SYSCLKCR & SCU_CLK_SYSCLKCR_SYSSEL_Msk)
  233. {
  234. /* fPLL is clock source for fSYS */
  235. if(SCU_PLL->PLLCON2 & SCU_PLL_PLLCON2_PINSEL_Msk)
  236. {
  237. /* PLL input clock is the backup clock (fOFI) */
  238. temp = OFI_FREQUENCY;
  239. }
  240. else
  241. {
  242. /* PLL input clock is the high performance osicllator (fOSCHP) */
  243. temp = OSCHP_GetFrequency();
  244. }
  245. /* check if PLL is locked */
  246. if (SCU_PLL->PLLSTAT & SCU_PLL_PLLSTAT_VCOLOCK_Msk)
  247. {
  248. /* PLL normal mode */
  249. /* read back divider settings */
  250. pdiv = ((SCU_PLL->PLLCON1 & SCU_PLL_PLLCON1_PDIV_Msk) >> SCU_PLL_PLLCON1_PDIV_Pos) + 1;
  251. ndiv = ((SCU_PLL->PLLCON1 & SCU_PLL_PLLCON1_NDIV_Msk) >> SCU_PLL_PLLCON1_NDIV_Pos) + 1;
  252. kdiv = ((SCU_PLL->PLLCON1 & SCU_PLL_PLLCON1_K2DIV_Msk) >> SCU_PLL_PLLCON1_K2DIV_Pos) + 1;
  253. temp = (temp / (pdiv * kdiv)) * ndiv;
  254. }
  255. else
  256. {
  257. /* PLL prescalar mode */
  258. /* read back divider settings */
  259. kdiv = ((SCU_PLL->PLLCON1 & SCU_PLL_PLLCON1_K1DIV_Msk) >> SCU_PLL_PLLCON1_K1DIV_Pos) + 1;
  260. temp = (temp / kdiv);
  261. }
  262. }
  263. else
  264. {
  265. /* fOFI is clock source for fSYS */
  266. temp = OFI_FREQUENCY;
  267. }
  268. temp = temp / ((SCU_CLK->SYSCLKCR & SCU_CLK_SYSCLKCR_SYSDIV_Msk) + 1);
  269. temp = temp / ((SCU_CLK->CPUCLKCR & SCU_CLK_CPUCLKCR_CPUDIV_Msk) + 1);
  270. SystemCoreClock = temp;
  271. }
从上述代码可以看出系统的时钟配置,具体配置的信息如下: /* // Clock tree // System clock source selection // <0=> fOFI // <1=> fPLL // Default: fPLL // System clock divider <1-256><#-1> // Default: 2 // CPU clock divider // <0=> fCPU = fSYS // <1=> fCPU = fSYS / 2 // Default: fCPU = fSYS // Peripheral clock divider // <0=> fPB = fCPU // <1=> fPB = fCPU / 2 // Default: fPB = fCPU // CCU clock divider // <0=> fCCU = fCPU // <1=> fCCU = fCPU / 2 // Default: fCCU = fCPU // Enable WDT clock // WDT clock source <0=> fOFI // <1=> fSTDBY // <2=> fPLL // Default: fOFI // WDT clock divider <1-256><#-1> // Default: 1 // // Enable EBU clock // EBU clock divider <1-64><#-1> // Default: 4 // // Enable ETH clock // // Enable MMC clock // // Enable USB clock // USB clock source <0=> fUSBPLL // <1=> fPLL // Default: fPLL // // Enable external clock // External Clock Source Selection // <0=> fSYS // <2=> fUSB // <3=> fPLL // Default: fPLL // External Clock divider <1-512><#-1> // Default: 288 // Only valid for USB PLL and PLL clocks // External Clock Pin Selection // <0=> Disabled // <1=> P0.8 // <2=> P1.15 // Default: Disabled // // 接下来分析main函数程序
  1. int main(void)
  2. {
  3. /* Setup the system timer to tick every 100us */
  4. SysTick_Config(SystemCoreClock / TICKS_PER_SECOND);
  5. /* Configure P3.9 (LED) */
  6. // P3.9 is used as GPIO for LED indication. Macros can be find in GPIO.h
  7. P5_9_set_mode(OUTPUT_PP_GP);
  8. P5_9_set_driver_strength(STRONG);
  9. P5_9_reset();
  10. /* Initialize and start ADC */
  11. ADC0_Init();
  12. /* Infinite loop */
  13. for(;;){
  14. do{
  15. adc_result = VADC_G0->RES[1];
  16. } while (!(adc_result >> VADC_G_RES_VF_Pos));
  17. // wait until ADC result register 0 value is valid
  18. // VADC.G0RES1.VF = 1: Valid Flag
  19. // Indicates a new result in bitfield RESULT or bit FCR.
  20. // 1B = Bitfield RESULT has been updated with new
  21. // result value and has not yet been read, or bit
  22. // FCR has been updated
  23. adc_result &= 0xFFF; // mask ADC result
  24. Delay100US((adc_result << 1) + 500);
  25. // tune minimum and maximum flashing time
  26. P5_9_toggle();
  27. // toggle P3.9 (toggle LED) using GPIO.h macros
  28. }
  29. return 0;
  30. }
先配置系统SysTick为100us中断一次,配置引脚5.9为输出引脚,引脚输出为强输出,先输出为低电平。然后初始化ADC0,并且启动ADC0转换。在while循环中,读取ADC转换的数据,用来产生延时的基数,翻转点灯。 对于DAVE的IDE发现有几个很好的功能,没有实际编译的代码为黑色背景,这样方便我们分析代码。 3.jpg 智能提醒,直接把鼠标停在代码上面,自动给出代码定义,比iar和mdk好很多,不需要再用第三方编辑器看代码。 4.jpg 此内容由EEWORLD论坛网友qwerghf原创,如需转载或用于商业用途需征得作者同意并注明出处 本帖最后由 qwerghf 于 2017-12-12 22:55 编辑

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复