查看: 778|回复: 1

【瑞萨RA4系列开发板体验】3 GPIO流水灯的前生今世

[复制链接]

116

主题

134

帖子

3778

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3778
发表于 2023-2-24 14:12:57 | 显示全部楼层 |阅读模式
【瑞萨RA4系列开发板体验】3 GPIO流水灯的前生今世
作者:ouxiaolong

开发环境:
IDE:MKD 5.30
开发板:RA-Eco-RA4M2
MCU:R7FA4M2AD3CFP
上一章通过控制GPIO的高低电平实现了流水灯,但只是告诉了大家怎么做,如何实现流水灯,本文将深入剖析的GPIO流水灯的前生今世,深入研究流水灯的调用逻辑和数据结构。


1 GPIO配置概述
前面一章大概讲解GPIO流水灯,关于GPIO的内容很多,具体请参看《RA4M2 Group User’s Manual Hardware》中I/O Ports相关的章节吧。

要想控制LED亮灭,就需要做以上三件事:使能时钟,配置GPIO参数,最后循环控制GPIO的高低电平就能实现流水灯的效果,GPIO的寄存器这里就不说了,更多详细的寄存器描述看官方手册就行,下面先来看看RA4M2的时钟。

2 RA4M2的时钟系统
2.1 RA4M2时钟架构
时钟是整个处理器运行的基础,时钟信号推动处理器内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定CPU速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。
RA4M2相对Cortex-3内核系列的MCU更为复杂,不仅是外设非常多,就连时钟来源就有8个之多。但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费,而且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题,因此便有了RA4M2的时钟系统和时钟树。


RA4M2不同的时钟源可以用来驱动系统时钟(SCK):
● MOSC(Main Clock Oscillator):主时钟振荡器,连接外部 8 ~ 24 MHz 高速晶振
● SOSC(Sub-Clock Oscillator):副时钟振荡器,连接外部 32.768 kHz 低速晶振(高速外部时钟信号)
● HOCO(High-speed on-chip oscillator):高速片上振荡器,振荡频率: 16/18/20 MHz
● MOCO(Middle-speed on-chip oscillator):中速片上振荡器,振荡频率: 8 MHz
● LOCO(Low-speed on-chip oscillator):低速片上振荡器,振荡频率: 32.768 kHz
● PLL(Phase Locked Loop): 锁相环时钟,可以对输入时钟进行分频和倍频的功能,PLL 输出频率:100 MHz ~ 200 MHz,PLL2 输出频率:120 MHz ~ 240 MHz
RA4M2有两个二级时钟源:
● IWDTLOCO(IWDT-dedicated clock) :IWDT专用片上振荡器,振荡频率: 15 kHz
● TCK/SWCLK(External clock input for JTAG/ External clock input for SWD) :JTAG/SWD的外部时钟输入,振荡频率: 最大25MHz
每个时钟源在不使用时都可以单独被打开或关闭,这样就可以优化系统功耗。

2.2 RA4M2的时钟系统
RA4M2芯片为了实现低功耗,设计了一个功能完善但却非常复杂的时钟系统。普通的MCU 一般只要配置好 GPIO 的寄存器就可以使用了,但 RA4M2还有一个步骤,就是开启外设时钟。
在 RA4M2中,系统时钟源有很多,从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 XTAL、XCIN和TCK/SWCLK是外部时钟源,其他的是内部时钟源。
下面我们看看RA4M2的系统时钟源,我们讲解顺序是按图中红圈标示的顺序:
MOSC是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为8MHz~24MHz。我们的开发板接的是24M的晶振。
SOSC是副时钟振荡器,接频率为 32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。
HOCO是高速内部时钟,高速片上振荡器,振荡频率: 16/18/20 MHz。
MOCO是中速片上振荡器,振荡频率为8 MHz。
LOCO是低速片上振荡器,振荡频率为32.768 kHz。
PLL 为锁相环倍频输出,其时钟输入源可选择为MOSC、HOCO。倍频可选择为10~30倍,但是PLL输出频率最大不得超过 200MHz,PLL2输出频率最大不得超过 240MHz。


图中我们用 A~C标示就是系统时钟进过系统时钟主要流向的地方。
A. 此处是FCLK,最高50MHz.
B. B处就是 RA4M2的系统时钟 ICLK,它是供 RA4M2内核中绝大部分部件工作的时钟源,分别是CPU、DMAC、DTC、闪存 和 SRAM。系统时钟可选择HCOC、MCOC、LOCO、XTAL、SUBCLK、PLL作为时钟源。系统时钟最大频率为 100MHz,当然你也可以超频,不过一般情况为了系统稳定性是没有必要冒风险去超频的。
C. 这里的C处是大部分外设的时钟输入源了。从时钟图上可以看出,其他所有外设的时钟最终来源都是 SCK。SCK 通过分频器分频后送给各模块使用。


3 RA4M2的时钟配置剖析
主频的时钟为默认的 200 MHz,来源是MOSC的24MHz时钟,经过PLL倍频,流向系统时钟。详细请查看RA Smart Configurator文件的配置。

当系统复位后就会进入Reset_Handler() -> SystemInit() -> bsp_clock_init(),bsp_clock_init()函数就是整个系统时钟的初始化部分,重点看这里,代码如下:
[文件路径: ra\fsp\src\bsp\mcu\all\bsp_clocks.c]

  1. /*******************************************************************************************************************//**
  2. * Initializes system clocks.  Makes no assumptions about current register settings.
  3. **********************************************************************************************************************/
  4. void bsp_clock_init (void)
  5. {
  6.     /* Unlock CGC and LPM protection registers. */
  7.     R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_UNLOCK;

  8. #if BSP_FEATURE_BSP_FLASH_CACHE
  9. #if !BSP_CFG_USE_LOW_VOLTAGE_MODE && BSP_FEATURE_BSP_FLASH_CACHE_DISABLE_OPM

  10.     /* Disable flash cache before modifying MEMWAIT, SOPCCR, or OPCCR. */
  11.     R_BSP_FlashCacheDisable();
  12. #else

  13.     /* Enable the flash cache and don't disable it while running from flash. On these MCUs, the flash cache does not
  14.      * need to be disabled when adjusting the operating power mode. */
  15.     R_BSP_FlashCacheEnable();
  16. #endif
  17. #endif

  18. #if BSP_FEATURE_BSP_FLASH_PREFETCH_BUFFER

  19.     /* Disable the flash prefetch buffer. */
  20.     R_FACI_LP->PFBER = 0;
  21. #endif

  22.     bsp_clock_freq_var_init();

  23. #if BSP_CLOCK_CFG_MAIN_OSC_POPULATED
  24. #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET

  25.     /* Update the main oscillator drive, source, and wait states if the main oscillator is stopped.  If the main
  26.      * oscillator is running, the drive, source, and wait states are assumed to be already set appropriately. */
  27.     if (R_SYSTEM->MOSCCR)
  28.     {
  29.         /* Don't write to MOSCWTCR unless MOSTP is 1 and MOSCSF = 0. */
  30.         FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.MOSCSF, 0U);

  31.         /* Configure main oscillator drive. */
  32.         R_SYSTEM->MOMCR = BSP_PRV_MOMCR;

  33.         /* Set the main oscillator wait time. */
  34.         R_SYSTEM->MOSCWTCR = (uint8_t) BSP_CLOCK_CFG_MAIN_OSC_WAIT;
  35.     }

  36. #else

  37.     /* Configure main oscillator drive. */
  38.     R_SYSTEM->MOMCR = BSP_PRV_MOMCR;

  39.     /* Set the main oscillator wait time. */
  40.     R_SYSTEM->MOSCWTCR = (uint8_t) BSP_CLOCK_CFG_MAIN_OSC_WAIT;
  41. #endif
  42. #endif

  43. #if BSP_FEATURE_CGC_HAS_SOSC
  44. #if BSP_CLOCK_CFG_SUBCLOCK_POPULATED

  45.     /* If Sub-Clock Oscillator is started at reset, stop it before configuring the subclock drive. */
  46.     if (0U == R_SYSTEM->SOSCCR)
  47.     {
  48.         /* Stop the Sub-Clock Oscillator to update the SOMCR register. */
  49.         R_SYSTEM->SOSCCR = 1U;

  50.         /* Allow a stop interval of at least 5 SOSC clock cycles before configuring the drive capacity
  51.          * and restarting Sub-Clock Oscillator. */
  52.         R_BSP_SoftwareDelay(BSP_PRV_SUBCLOCK_STOP_INTERVAL_US, BSP_DELAY_UNITS_MICROSECONDS);
  53.     }

  54.     /* Configure the subclock drive as subclock is not running. */
  55.     R_SYSTEM->SOMCR = ((BSP_CLOCK_CFG_SUBCLOCK_DRIVE << BSP_FEATURE_CGC_SODRV_SHIFT) & BSP_FEATURE_CGC_SODRV_MASK);

  56.     /* Restart the Sub-Clock Oscillator. */
  57.     R_SYSTEM->SOSCCR = 0U;
  58.   #if (BSP_CLOCKS_SOURCE_CLOCK_SUBCLOCK == BSP_CFG_CLOCK_SOURCE) || (BSP_PRV_HOCO_USE_FLL)

  59.     /* If the subclock is the system clock source OR if FLL is used, wait for stabilization. */
  60.     R_BSP_SubClockStabilizeWait(BSP_CLOCK_CFG_SUBCLOCK_STABILIZATION_MS);
  61.   #endif
  62. #else
  63.     R_SYSTEM->SOSCCR = 1U;
  64. #endif
  65. #endif

  66. #if BSP_FEATURE_CGC_HAS_HOCOWTCR
  67. #if BSP_FEATURE_CGC_HOCOWTCR_64MHZ_ONLY

  68.     /* These MCUs only require writes to HOCOWTCR if HOCO is set to 64 MHz. */
  69.   #if 64000000 == BSP_HOCO_HZ
  70.    #if BSP_CFG_USE_LOW_VOLTAGE_MODE

  71.     /* Wait for HOCO to stabilize before writing to HOCOWTCR. */
  72.     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.HOCOSF, 1U);
  73.    #else

  74.     /* HOCO is assumed to be stable because these MCUs also require the HOCO to be stable before changing the operating
  75.      * power control mode. */
  76.    #endif
  77.     R_SYSTEM->HOCOWTCR = BSP_FEATURE_CGC_HOCOWTCR_VALUE;
  78.   #endif
  79. #else

  80.     /* These MCUs require HOCOWTCR to be set to the maximum value except in snooze mode.  There is no restriction to
  81.      * writing this register. */
  82.     R_SYSTEM->HOCOWTCR = BSP_FEATURE_CGC_HOCOWTCR_VALUE;
  83. #endif
  84. #endif

  85. #if !BSP_CFG_USE_LOW_VOLTAGE_MODE
  86. #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET

  87.     /* Switch to high-speed to prevent any issues with the subsequent clock configurations. */
  88.     bsp_prv_operating_mode_set(BSP_PRV_OPERATING_MODE_HIGH_SPEED);
  89. #elif BSP_FEATURE_CGC_LOW_VOLTAGE_MAX_FREQ_HZ > 0U

  90.     /* MCUs that support low voltage mode start up in low voltage mode. */
  91.     bsp_prv_operating_mode_opccr_set(BSP_PRV_OPERATING_MODE_HIGH_SPEED);

  92.   #if !BSP_PRV_HOCO_USED

  93.     /* HOCO must be running during startup in low voltage mode. If HOCO is not used, turn it off after exiting low
  94.      * voltage mode. */
  95.     R_SYSTEM->HOCOCR = 1U;
  96.   #endif
  97. #elif BSP_FEATURE_CGC_STARTUP_OPCCR_MODE != BSP_PRV_OPERATING_MODE_HIGH_SPEED

  98.     /* Some MCUs do not start in high speed mode. */
  99.     bsp_prv_operating_mode_opccr_set(BSP_PRV_OPERATING_MODE_HIGH_SPEED);
  100. #endif
  101. #endif

  102.     /* The FLL function can only be used when the subclock is running. */
  103. #if BSP_PRV_HOCO_USE_FLL

  104.     /* If FLL is to be used configure FLLCR1 and FLLCR2 before starting HOCO. */
  105.     R_SYSTEM->FLLCR2 = BSP_PRV_FLL_FLLCR2;
  106.     R_SYSTEM->FLLCR1 = 1U;
  107. #endif

  108.     /* Start all clocks used by other clocks first. */
  109. #if BSP_PRV_HOCO_USED
  110.     R_SYSTEM->HOCOCR = 0U;

  111. #if BSP_PRV_HOCO_USE_FLL && (BSP_CLOCKS_SOURCE_CLOCK_HOCO != BSP_CFG_PLL_SOURCE)

  112.     /* If FLL is enabled, wait for the FLL stabilization delay (1.8 ms) */
  113.     R_BSP_SoftwareDelay(BSP_PRV_FLL_STABILIZATION_TIME_US, BSP_DELAY_UNITS_MICROSECONDS);
  114. #endif

  115. #if BSP_PRV_STABILIZE_HOCO

  116.     /* Wait for HOCO to stabilize. */
  117.     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.HOCOSF, 1U);
  118. #endif
  119. #endif
  120. #if BSP_PRV_MOCO_USED
  121. #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET

  122.     /* If the MOCO is not running, start it and wait for it to stabilize using a software delay. */
  123.     if (0U != R_SYSTEM->MOCOCR)
  124.     {
  125.         R_SYSTEM->MOCOCR = 0U;
  126.   #if BSP_PRV_STABILIZE_MOCO
  127.         R_BSP_SoftwareDelay(BSP_FEATURE_CGC_MOCO_STABILIZATION_MAX_US, BSP_DELAY_UNITS_MICROSECONDS);
  128.   #endif
  129.     }
  130. #endif
  131. #endif
  132. #if BSP_PRV_LOCO_USED
  133. #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET

  134.     /* If the LOCO is not running, start it and wait for it to stabilize using a software delay. */
  135.     if (0U != R_SYSTEM->LOCOCR)
  136.     {
  137.         R_SYSTEM->LOCOCR = 0U;
  138.   #if BSP_PRV_STABILIZE_LOCO
  139.         R_BSP_SoftwareDelay(BSP_FEATURE_CGC_LOCO_STABILIZATION_MAX_US, BSP_DELAY_UNITS_MICROSECONDS);
  140.   #endif
  141.     }

  142. #else
  143.     R_SYSTEM->LOCOCR = 0U;
  144.   #if BSP_PRV_STABILIZE_LOCO
  145.     R_BSP_SoftwareDelay(BSP_FEATURE_CGC_LOCO_STABILIZATION_MAX_US, BSP_DELAY_UNITS_MICROSECONDS);
  146.   #endif
  147. #endif
  148. #endif
  149. #if BSP_PRV_MAIN_OSC_USED
  150.     R_SYSTEM->MOSCCR = 0U;

  151. #if BSP_PRV_STABILIZE_MAIN_OSC

  152.     /* Wait for main oscillator to stabilize. */
  153.     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.MOSCSF, 1U);
  154. #endif
  155. #endif

  156.     /* Start clocks that require other clocks. At this point, all dependent clocks are running and stable if needed. */

  157. #if BSP_PRV_STARTUP_OPERATING_MODE != BSP_PRV_OPERATING_MODE_LOW_SPEED
  158. #if BSP_FEATURE_CGC_HAS_PLL2 && BSP_CFG_PLL2_SOURCE != BSP_CLOCKS_CLOCK_DISABLED
  159.     R_SYSTEM->PLL2CCR = BSP_PRV_PLL2CCR;
  160.   #if (3U == BSP_FEATURE_CGC_PLLCCR_TYPE)
  161.     R_SYSTEM->PLL2CCR2 = BSP_PRV_PLL2CCR2;
  162.   #endif

  163.     /* Start PLL2. */
  164.     R_SYSTEM->PLL2CR = 0U;
  165. #endif                                /* BSP_FEATURE_CGC_HAS_PLL2 && BSP_CFG_PLL2_ENABLE */
  166. #endif

  167. #if BSP_PRV_PLL_SUPPORTED && BSP_PRV_PLL_USED
  168. #if BSP_CLOCKS_SOURCE_CLOCK_PLL == BSP_CFG_CLOCK_SOURCE

  169.     /* Configure the PLL registers. */
  170.   #if 1U == BSP_FEATURE_CGC_PLLCCR_TYPE
  171.     R_SYSTEM->PLLCCR = (uint16_t) BSP_PRV_PLLCCR;
  172.   #elif 2U == BSP_FEATURE_CGC_PLLCCR_TYPE
  173.     R_SYSTEM->PLLCCR2 = (uint8_t) BSP_PRV_PLLCCR;
  174.   #elif 3U == BSP_FEATURE_CGC_PLLCCR_TYPE
  175.     R_SYSTEM->PLLCCR  = (uint16_t) BSP_PRV_PLLCCR;
  176.     R_SYSTEM->PLLCCR2 = (uint16_t) BSP_PRV_PLLCCR2;
  177.   #endif

  178.   #if BSP_FEATURE_CGC_PLLCCR_WAIT_US > 0

  179.     /* This loop is provided to ensure at least 1 us passes between setting PLLMUL and clearing PLLSTP on some
  180.      * MCUs (see PLLSTP notes in Section 8.2.4 "PLL Control Register (PLLCR)" of the RA4M1 manual R01UH0887EJ0100).
  181.      * Five loops are needed here to ensure the most efficient path takes at least 1 us from the setting of
  182.      * PLLMUL to the clearing of PLLSTP. HOCO is the fastest clock we can be using here since PLL cannot be running
  183.      * while setting PLLCCR. */
  184.     bsp_prv_software_delay_loop(BSP_DELAY_LOOPS_CALCULATE(BSP_PRV_MAX_HOCO_CYCLES_PER_US));
  185.   #endif
  186. #endif

  187.     R_SYSTEM->PLLCR = 0U;

  188. #if BSP_PRV_STABILIZE_PLL

  189.     /* Wait for PLL to stabilize. */
  190.     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.PLLSF, 1U);
  191. #endif
  192. #endif

  193.     /* Set source clock and dividers. */
  194. #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET
  195. #if BSP_TZ_SECURE_BUILD

  196.     /* In case of soft reset, make sure callback pointer is NULL initially. */
  197.     g_bsp_clock_update_callback = NULL;
  198. #endif

  199. #if BSP_FEATURE_CGC_HAS_CPUCLK
  200.     bsp_prv_clock_set(BSP_CFG_CLOCK_SOURCE, BSP_PRV_STARTUP_SCKDIVCR, BSP_PRV_STARTUP_SCKDIVCR2);
  201. #else
  202.     bsp_prv_clock_set(BSP_CFG_CLOCK_SOURCE, BSP_PRV_STARTUP_SCKDIVCR, 0);
  203. #endif
  204. #else
  205.     bsp_prv_clock_set_hard_reset();
  206. #endif

  207.     /* If the MCU can run in a lower power mode, apply the optimal operating speed mode. */
  208. #if !BSP_CFG_USE_LOW_VOLTAGE_MODE
  209. #if BSP_PRV_STARTUP_OPERATING_MODE != BSP_PRV_OPERATING_MODE_HIGH_SPEED
  210.   #if BSP_PRV_PLL_SUPPORTED
  211.    #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET
  212.     if (BSP_PRV_OPERATING_MODE_LOW_SPEED == BSP_PRV_STARTUP_OPERATING_MODE)
  213.     {
  214.         /* If the MCU has a PLL, ensure PLL is stopped and stable before entering low speed mode. */
  215.         R_SYSTEM->PLLCR = 1U;

  216.         /* Wait for PLL to stabilize. */
  217.         FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.PLLSF, 0U);

  218.     #if BSP_FEATURE_CGC_HAS_PLL2

  219.         /* If the MCU has a PLL2, ensure PLL2 is stopped and stable before entering low speed mode. */
  220.         R_SYSTEM->PLL2CR = 1U;

  221.         /* Wait for PLL to stabilize. */
  222.         FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->OSCSF_b.PLL2SF, 0U);
  223.     #endif
  224.     }
  225.    #endif
  226.   #endif
  227.     bsp_prv_operating_mode_set(BSP_PRV_STARTUP_OPERATING_MODE);
  228. #endif
  229. #endif

  230. #if defined(BSP_PRV_POWER_USE_DCDC) && (BSP_PRV_POWER_USE_DCDC == BSP_PRV_POWER_DCDC_STARTUP) && \
  231.     (BSP_PRV_STARTUP_OPERATING_MODE <= BSP_PRV_OPERATING_MODE_MIDDLE_SPEED)

  232.     /* Start DCDC as part of BSP startup when configured (BSP_CFG_DCDC_ENABLE == 2). */
  233.     R_BSP_PowerModeSet(BSP_CFG_DCDC_VOLTAGE_RANGE);
  234. #endif

  235.     /* Configure BCLK if it exists on the MCU. */
  236. #ifdef BSP_CFG_BCLK_OUTPUT
  237. #if BSP_CFG_BCLK_OUTPUT > 0U
  238.     R_SYSTEM->BCKCR   = BSP_CFG_BCLK_OUTPUT - 1U;
  239.     R_SYSTEM->EBCKOCR = 1U;
  240. #else
  241.   #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET
  242.     R_SYSTEM->EBCKOCR = 0U;
  243.   #endif
  244. #endif
  245. #endif

  246.     /* Configure SDRAM clock if it exists on the MCU. */
  247. #ifdef BSP_CFG_SDCLK_OUTPUT
  248.     R_SYSTEM->SDCKOCR = BSP_CFG_SDCLK_OUTPUT;
  249. #endif

  250.     /* Configure CLKOUT. */
  251. #if BSP_CFG_CLKOUT_SOURCE == BSP_CLOCKS_CLOCK_DISABLED
  252. #if BSP_CFG_STARTUP_CLOCK_REG_NOT_RESET
  253.     R_SYSTEM->CKOCR = 0U;
  254. #endif
  255. #else
  256.     uint8_t ckocr = BSP_CFG_CLKOUT_SOURCE | (BSP_CFG_CLKOUT_DIV << BSP_PRV_CKOCR_CKODIV_BIT);
  257.     R_SYSTEM->CKOCR = ckocr;
  258.     ckocr          |= (1U << BSP_PRV_CKOCR_CKOEN_BIT);
  259.     R_SYSTEM->CKOCR = ckocr;
  260. #endif

  261. #if BSP_PRV_STARTUP_OPERATING_MODE != BSP_PRV_OPERATING_MODE_LOW_SPEED
  262. #if BSP_CFG_UCK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED

  263.     /* If the USB clock has a divider setting in SCKDIVCR2. */
  264.   #if BSP_FEATURE_BSP_HAS_USB_CLOCK_DIV && !BSP_FEATURE_BSP_HAS_USBCKDIVCR
  265.     R_SYSTEM->SCKDIVCR2 = BSP_PRV_UCK_DIV << BSP_PRV_SCKDIVCR2_UCK_BIT;
  266.   #endif                               /* BSP_FEATURE_BSP_HAS_USB_CLOCK_DIV && !BSP_FEATURE_BSP_HAS_USBCKDIVCR */

  267.     /* If there is a REQ bit in USBCKCR than follow sequence from section 8.2.29 in RA6M4 hardware manual R01UH0890EJ0050. */
  268.   #if BSP_FEATURE_BSP_HAS_USB_CLOCK_REQ

  269.     /* Request to change the USB Clock. */
  270.     R_SYSTEM->USBCKCR_b.USBCKSREQ = 1;

  271.     /* Wait for the clock to be stopped. */
  272.     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->USBCKCR_b.USBCKSRDY, 1U);

  273.     /* Write the settings. */
  274.     R_SYSTEM->USBCKDIVCR = BSP_PRV_UCK_DIV;

  275.     /* Select the USB Clock without enabling it. */
  276.     R_SYSTEM->USBCKCR = BSP_CFG_UCK_SOURCE | R_SYSTEM_USBCKCR_USBCKSREQ_Msk;
  277.   #endif                               /* BSP_FEATURE_BSP_HAS_USB_CLOCK_REQ */

  278.   #if BSP_FEATURE_BSP_HAS_USB_CLOCK_SEL

  279.     /* Some MCUs use an alternate register for selecting the USB clock source. */
  280.    #if BSP_FEATURE_BSP_HAS_USB_CLOCK_SEL_ALT
  281.     #if BSP_CLOCKS_SOURCE_CLOCK_PLL == BSP_CFG_UCK_SOURCE

  282.     /* Write to USBCKCR to select the PLL. */
  283.     R_SYSTEM->USBCKCR_ALT = 0;
  284.     #elif BSP_CLOCKS_SOURCE_CLOCK_HOCO == BSP_CFG_UCK_SOURCE

  285.     /* Write to USBCKCR to select the HOCO. */
  286.     R_SYSTEM->USBCKCR_ALT = 1;
  287.     #endif
  288.    #else

  289.     /* Select the USB Clock. */
  290.     R_SYSTEM->USBCKCR = BSP_CFG_UCK_SOURCE;
  291.    #endif
  292.   #endif                               /* BSP_FEATURE_BSP_HAS_USB_CLOCK_REQ */

  293.   #if BSP_FEATURE_BSP_HAS_USB_CLOCK_REQ

  294.     /* Wait for the USB Clock to be started. */
  295.     FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->USBCKCR_b.USBCKSRDY, 0U);
  296.   #endif                               /* BSP_FEATURE_BSP_HAS_USB_CLOCK_REQ */
  297. #endif                                /* BSP_CFG_USB_ENABLE */
  298. #endif                                 /* BSP_PRV_STARTUP_OPERATING_MODE != BSP_PRV_OPERATING_MODE_LOW_SPEED */

  299.     /* Set the OCTASPI clock if it exists on the MCU (See section 8.2.30 of the RA6M4 hardware manual R01UH0890EJ0050). */
  300. #if BSP_FEATURE_BSP_HAS_OCTASPI_CLOCK && BSP_CFG_OCTA_SOURCE != BSP_CLOCKS_CLOCK_DISABLED
  301.     bsp_octaclk_settings_t octaclk_settings =
  302.     {
  303.         .source_clock = (bsp_clocks_source_t) BSP_CFG_OCTA_SOURCE,
  304.         .divider      = (bsp_clocks_octaclk_div_t) BSP_CFG_OCTA_DIV
  305.     };
  306.     R_BSP_OctaclkUpdate(&octaclk_settings);
  307. #endif                                 /* BSP_FEATURE_BSP_HAS_OCTASPI_CLOCK && BSP_CFG_OCTASPI_CLOCK_ENABLE */

  308.     /* Set the CANFD clock if it exists on the MCU */
  309. #if BSP_FEATURE_BSP_HAS_CANFD_CLOCK && (BSP_CFG_CANFDCLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED) && \
  310.     (BSP_CFG_CANFDCLK_SOURCE != BSP_CLOCKS_SOURCE_CLOCK_MAIN_OSC)

  311.     bsp_peripheral_clock_set(&R_SYSTEM->CANFDCKCR,
  312.                              &R_SYSTEM->CANFDCKDIVCR,
  313.                              BSP_CFG_CANFDCLK_DIV,
  314.                              BSP_CFG_CANFDCLK_SOURCE);
  315. #endif

  316.     /* Set the SCISPI clock if it exists on the MCU */
  317. #if BSP_FEATURE_BSP_HAS_SCISPI_CLOCK && (BSP_CFG_SCISPICLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  318.     bsp_peripheral_clock_set(&R_SYSTEM->SCISPICKCR,
  319.                              &R_SYSTEM->SCISPICKDIVCR,
  320.                              BSP_CFG_SCISPICLK_DIV,
  321.                              BSP_CFG_SCISPICLK_SOURCE);
  322. #endif

  323.     /* Set the SCI clock if it exists on the MCU */
  324. #if BSP_FEATURE_BSP_HAS_SCI_CLOCK && (BSP_CFG_SCICLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  325.     bsp_peripheral_clock_set(&R_SYSTEM->SCICKCR, &R_SYSTEM->SCICKDIVCR, BSP_CFG_SCICLK_DIV, BSP_CFG_SCICLK_SOURCE);
  326. #endif

  327.     /* Set the SPI clock if it exists on the MCU */
  328. #if BSP_FEATURE_BSP_HAS_SPI_CLOCK && (BSP_CFG_SPICLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  329.     bsp_peripheral_clock_set(&R_SYSTEM->SPICKCR, &R_SYSTEM->SPICKDIVCR, BSP_CFG_SPICLK_DIV, BSP_CFG_SPICLK_SOURCE);
  330. #endif

  331.     /* Set the GPT clock if it exists on the MCU */
  332. #if BSP_FEATURE_BSP_HAS_GPT_CLOCK && (BSP_CFG_GPTCLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  333.     bsp_peripheral_clock_set(&R_SYSTEM->GPTCKCR, &R_SYSTEM->GPTCKDIVCR, BSP_CFG_GPTCLK_DIV, BSP_CFG_GPTCLK_SOURCE);
  334. #endif

  335.     /* Set the IIC clock if it exists on the MCU */
  336. #if BSP_FEATURE_BSP_HAS_IIC_CLOCK && (BSP_CFG_IICCLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  337.     bsp_peripheral_clock_set(&R_SYSTEM->IICCKCR, &R_SYSTEM->IICCKDIVCR, BSP_CFG_IICCLK_DIV, BSP_CFG_IICCLK_SOURCE);
  338. #endif

  339.     /* Set the I3C clock if it exists on the MCU */
  340. #if BSP_FEATURE_BSP_HAS_I3C_CLOCK && (BSP_CFG_I3CCLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  341.     bsp_peripheral_clock_set(&R_SYSTEM->I3CCKCR, &R_SYSTEM->I3CCKDIVCR, BSP_CFG_I3CCLK_DIV, BSP_CFG_I3CCLK_SOURCE);
  342. #endif

  343.     /* Set the ADC clock if it exists on the MCU */
  344. #if BSP_FEATURE_BSP_HAS_ADC_CLOCK && (BSP_CFG_ADCCLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  345.     bsp_peripheral_clock_set(&R_SYSTEM->ADCCKCR, &R_SYSTEM->ADCCKDIVCR, BSP_CFG_ADCCLK_DIV, BSP_CFG_ADCCLK_SOURCE);
  346. #endif

  347.     /* Set the LCD clock if it exists on the MCU */
  348. #if BSP_FEATURE_BSP_HAS_LCD_CLOCK && (BSP_CFG_LCDCLK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  349.     bsp_peripheral_clock_set(&R_SYSTEM->LCDCKCR, &R_SYSTEM->LCDCKDIVCR, BSP_CFG_LCDCLK_DIV, BSP_CFG_LCDCLK_SOURCE);
  350. #endif

  351.     /* Set the USB-HS clock if it exists on the MCU */
  352. #if BSP_FEATURE_BSP_HAS_USBHS_CLOCK && (BSP_CFG_UHSCK_SOURCE != BSP_CLOCKS_CLOCK_DISABLED)
  353.     bsp_peripheral_clock_set(&R_SYSTEM->USBHSCKCR, &R_SYSTEM->USBHSCKDIVCR, BSP_CFG_UHSCK_DIV, BSP_CFG_UHSCK_SOURCE);
  354. #endif

  355.     /* Lock CGC and LPM protection registers. */
  356.     R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_LOCK;

  357. #if BSP_FEATURE_BSP_FLASH_CACHE && BSP_FEATURE_BSP_FLASH_CACHE_DISABLE_OPM
  358.     R_BSP_FlashCacheEnable();
  359. #endif

  360. #if BSP_FEATURE_BSP_FLASH_PREFETCH_BUFFER
  361.     R_FACI_LP->PFBER = 1;
  362. #endif
  363. }
复制代码
其中配置时钟的基地址是R_SYSTEM,定义如下:
  1. #define R_SYSTEM         ((R_SYSTEM_Type *) R_SYSTEM_BASE)
复制代码
可以查看配置时钟的结构体是R_SYSTEM_Type,该结构包含了系统时钟的所有寄存器描述,该结构体非常大,笔者只是截取了部分。

总结下,整个bsp_clock_init()函数的主要工作如下:
Step1:时钟配置准备阶段
  • 解锁CGC和LPM保护
  • 启用闪存缓存
  • 初始化时钟参数
Step2:配置系统时钟
  • 配置MOSC,HOCO,MOCO,PLL参数
  • 设置源时钟和分频器
Step3:配置BCLK/SDRAM/CLKOUT输出和外设时钟
  • 配置BCLK/SDRAM/CLKOUT
  • 根据需求配置相应的外设时钟
Step4:锁定CGC和LPM


4 RA4M2的GPIO配置剖析
从在SystemInit ()函数中可以看到,在初始化系统的时钟前后,均调用了R_BSP_WarmStart()函数,其函数原型如下:
[文件路径: src\hal_entry.c]

  1. /*******************************************************************************************************************//**
  2. * This function is called at various points during the startup process.  This implementation uses the event that is
  3. * called right before main() to set up the pins.
  4. *
  5. * @param[in]  event    Where at in the start up process the code is currently at
  6. **********************************************************************************************************************/
  7. void R_BSP_WarmStart (bsp_warm_start_event_t event)
  8. {
  9.     if (BSP_WARM_START_RESET == event)
  10.     {
  11. #if BSP_FEATURE_FLASH_LP_VERSION != 0

  12.         /* Enable reading from data flash. */
  13.         R_FACI_LP->DFLCTL = 1U;

  14.         /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
  15.          * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
  16. #endif
  17.     }

  18.     if (BSP_WARM_START_POST_C == event)
  19.     {
  20.         /* C runtime environment and system clocks are setup. */

  21.         /* Configure pins. */
  22.         R_IOPORT_Open(&g_ioport_ctrl, g_ioport.p_cfg);
  23.     }
  24. }
复制代码

这里可以看到,在系统时钟初始化后,代码如下:
  1. R_BSP_WarmStart(BSP_WARM_START_POST_CLOCK);
复制代码
因此,这里就进入了GPIO的配置,核心代码如下:
  1. R_IOPORT_Open(&g_ioport_ctrl,
  2. g_ioport.p_cfg);
复制代码
g_ioport_ctrl和g_ioport是全局变量,定义如下:
  1. ioport_instance_ctrl_t g_ioport_ctrl;
  2. const ioport_instance_t g_ioport =
  3.         {
  4.             .p_api = &g_ioport_on_ioport,
  5.             .p_ctrl = &g_ioport_ctrl,
  6.             .p_cfg = &g_bsp_pin_cfg,
  7.         };
复制代码
而g_ioport又内嵌了g_bsp_pin_cfg,g_bsp_pin_cfg相关的定义如下:
  1. const ioport_pin_cfg_t g_bsp_pin_cfg_data[] = {
  2.     {
  3.         .pin = BSP_IO_PORT_01_PIN_08,
  4.         .pin_cfg = ((uint32_t) IOPORT_CFG_PERIPHERAL_PIN | (uint32_t) IOPORT_PERIPHERAL_DEBUG)
  5.     },
  6.     {
  7.         .pin = BSP_IO_PORT_01_PIN_09,
  8.         .pin_cfg = ((uint32_t) IOPORT_CFG_PERIPHERAL_PIN | (uint32_t) IOPORT_PERIPHERAL_DEBUG)
  9.     },
  10.     {
  11.         .pin = BSP_IO_PORT_01_PIN_10,
  12.         .pin_cfg = ((uint32_t) IOPORT_CFG_PERIPHERAL_PIN | (uint32_t) IOPORT_PERIPHERAL_DEBUG)
  13.     },
  14.     {
  15.         .pin = BSP_IO_PORT_03_PIN_00,
  16.         .pin_cfg = ((uint32_t) IOPORT_CFG_PERIPHERAL_PIN | (uint32_t) IOPORT_PERIPHERAL_DEBUG)
  17.     },
  18.     {
  19.         .pin = BSP_IO_PORT_04_PIN_04,
  20.         .pin_cfg = ((uint32_t) IOPORT_CFG_PORT_DIRECTION_OUTPUT | (uint32_t) IOPORT_CFG_PORT_OUTPUT_LOW)
  21.     },
  22.     {
  23.         .pin = BSP_IO_PORT_04_PIN_05,
  24.         .pin_cfg = ((uint32_t) IOPORT_CFG_PORT_DIRECTION_OUTPUT | (uint32_t) IOPORT_CFG_PORT_OUTPUT_LOW)
  25.     },
  26.     {
  27.         .pin = BSP_IO_PORT_04_PIN_15,
  28.         .pin_cfg = ((uint32_t) IOPORT_CFG_PORT_DIRECTION_OUTPUT | (uint32_t) IOPORT_CFG_PORT_OUTPUT_LOW)
  29.     },
  30. };

  31. const ioport_cfg_t g_bsp_pin_cfg = {
  32.     .number_of_pins = sizeof(g_bsp_pin_cfg_data)/sizeof(ioport_pin_cfg_t),
  33.     .p_pin_cfg_data = &g_bsp_pin_cfg_data[0],
  34. };
复制代码
从结构体数组g_bsp_pin_cfg_data中可以看到,我们芯配置的3个GPIO端口,在后面的初始时就能将其初始化了。
R_IOPORT_Open()函数的核心是r_ioport_pins_config ()。
[文件路径: ra\fsp\src\r_ioport\r_ioport.c]

  1. /*******************************************************************************************************************//**
  2. * Configures pins.
  3. *
  4. * @param[in]    p_cfg          Pin configuration data
  5. **********************************************************************************************************************/
  6. void r_ioport_pins_config (const ioport_cfg_t * p_cfg)
  7. {
  8. #if BSP_MCU_VBATT_SUPPORT
  9.     /* Handle any VBATT domain pin configuration. */
  10.     bsp_vbatt_init(p_cfg);
  11. #endif

  12.     uint16_t       pin_count;
  13.     ioport_cfg_t * p_pin_data;

  14.     p_pin_data = (ioport_cfg_t *) p_cfg;

  15.     R_BSP_PinAccessEnable();           // Protect PWPR from re-entrancy

  16.     for (pin_count = 0U; pin_count < p_pin_data->number_of_pins; pin_count++)
  17.     {
  18.         r_ioport_pfs_write(p_pin_data->p_pin_cfg_data[pin_count].pin, p_pin_data->p_pin_cfg_data[pin_count].pin_cfg);
  19.     }

  20.     R_BSP_PinAccessDisable();
  21. }
复制代码
r_ioport_pins_config ()函数中,根据GPIO的梳数量依次进行初始化。
r_ioport_pfs_write()函数的原型如下:
[文件路径: ra\fsp\src\r_ioport\r_ioport.c]

  1. /*******************************************************************************************************************//**
  2. * Writes to the specified pin's PFS register
  3. *
  4. * @param[in]    pin        Pin to write PFS data for
  5. * @param[in]    value      Value to be written to the PFS register
  6. *
  7. **********************************************************************************************************************/
  8. static void r_ioport_pfs_write (bsp_io_port_pin_t pin, uint32_t value)
  9. {
  10.     /* PMR bits should be cleared before specifying PSEL. Reference section "20.7 Notes on the PmnPFS Register Setting"
  11.      * in the RA6M3 manual R01UH0886EJ0100. */
  12.     if ((value & IOPORT_PRV_PERIPHERAL_FUNCTION) > 0)
  13.     {
  14.         /* Clear PMR */
  15.         R_PFS->PORT[pin >> IOPORT_PRV_PORT_OFFSET].PIN[pin & BSP_IO_PRV_8BIT_MASK].PmnPFS_b.PMR = 0;

  16.         /* New config with PMR = 0 */
  17.         R_PFS->PORT[pin >> IOPORT_PRV_PORT_OFFSET].PIN[pin &
  18.                                                        BSP_IO_PRV_8BIT_MASK].PmnPFS =
  19.             (value & ~((uint32_t) IOPORT_PRV_PERIPHERAL_FUNCTION));
  20.     }

  21.     /* Write configuration */
  22.     R_PFS->PORT[pin >> IOPORT_PRV_PORT_OFFSET].PIN[pin & BSP_IO_PRV_8BIT_MASK].PmnPFS = value;
  23. }
复制代码
R_PFS就是GPIO的基地址,定义如下:
  1. #define R_PFS            ((R_PFS_Type *) R_PFS_BASE)
复制代码
这里就是对GPIO 进行初始化操作,包括模式、方向等
到此,基本对时钟和GPIO分析玩了,我想大家已经对RA4M2固件库的逻辑有了一定的认识,从本质上讲,都是在配置寄存器,只是地址和值不同罢了。只是RA4M2的固件库设计比较复杂,可能对于习惯ST的风格,初学者可能会有些不适用,但是其本质是一样的。


回复

使用道具 举报

3

主题

195

帖子

1510

积分

金牌会员

Rank: 6Rank: 6

积分
1510
发表于 2023-3-14 10:15:21 | 显示全部楼层

学习了不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

用户排行榜

RA助手

主题: 116帖子:134精华:0

RA_Lance

主题: 92帖子:132精华:9

lugl

主题: 44帖子:133精华:0

xujiwei263

主题: 16帖子:73精华:0

books咦

主题: 11帖子:11精华:2

Juggernaut

主题: 9帖子:95精华:0
快速回复 返回顶部 返回列表