查看: 1221|回复: 2

【瑞萨RA4系列开发板体验】不同芯片之间迁移,ADC修改工...

[复制链接]

116

主题

134

帖子

3790

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3790
发表于 2023-2-24 16:22:12 | 显示全部楼层 |阅读模式
【瑞萨RA4系列开发板体验】不同芯片之间迁移,ADC修改工作量验证
作者:oxlm_1

1.背
前发布会上,瑞萨提到RA系列芯片设计时就考虑了平台移植的维度,刚好有机会拿到瑞萨的
RA2,RA4,RA6三款芯片的板子,便同步做实验,验证该信息的准确性。


2.硬件描述对比



硬件对比结论
在不考虑芯片封装的情况下,RA2L1和RA4M2之间,在硬件上adc的功能定义并未做到完全的pin2pin,但这不算什么大问题,如果能在软件上实现底层驱动差异化,HAL层向上兼容,也可以实现减少不同方案移植的工作量要求。RA4M2和RA6M5之间在接口功能上实现了有功能口的pin2pin兼容,理论上工程可以顺切。

3.代码层面分析
对比计划
由于最近在用rtthread,因此便基于rtthread上rensa代码进行分析。
代码分析
rtt代码层
见测试代码,应用层和驱动层通过device框架实现通信,该通信机制可以去RTT官网学习,具体实现方式为打开一个注册的adc设备,然后对应的ops即为顶层所调用的接口。
HAL(driver)层代码
  1. 1 //具体HAL层代码见 \bsp\renesas\libraries\HAL_Drivers\drv_adc.c,此处仅提供核心代码
  2. 2 //其中 _ra_adc0_device 和 _ra_adc1_device为对应fsp部分代码
  3. 3
  4. static rt_err_t ra_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel,
  5. rt_bool_t enabled)
  6. 4
  7. 5 {
  8. 6 RT_ASSERT(device != RT_NULL);
  9. 7 struct ra_adc_map *adc = (struct ra_adc_map *)device->parent.user_data;
  10. 8 /**< start adc*/
  11. 9 if (enabled)
  12. 10 {
  13. 11 if (FSP_SUCCESS != R_ADC_ScanStart((adc_ctrl_t *)adc->g_ctrl))
  14. 12 {
  15. 13 LOG_E("start adc%c failed.", adc->name);
  16. 14 return -RT_ERROR;
  17. 15 }
  18. 16 }
  19. 17 else
  20. 18 {
  21. 19 /**< stop adc*/
  22. 20 if (FSP_SUCCESS != R_ADC_ScanStop((adc_ctrl_t *)adc->g_ctrl))
  23. 21 {
  24. 22 LOG_E("stop adc%c failed.", adc->name);
  25. 23 return -RT_ERROR;
  26. 24 }
  27. 25 }
  28. 26 return RT_EOK;
  29. 27 }
  30. 28
  31. static rt_err_t ra_get_adc_value(struct rt_adc_device *device, rt_uint32_t channel,
  32. rt_uint32_t *value)
  33. 29
  34. 30 {
  35. 31 RT_ASSERT(device != RT_NULL);
  36. 32 struct ra_adc_map *adc = (struct ra_adc_map *)device->parent.user_data;
  37. 33 if (RT_EOK != R_ADC_Read32((adc_ctrl_t *)adc->g_ctrl, channel, value))
  38. 34 {
  39. 35 LOG_E("get adc value failed.\n");
  40. 36 return -RT_ERROR;
  41. ii.
  42. 37 }
  43. 38 return RT_EOK;
  44. 39 }
  45. 40
  46. 41 static const struct rt_adc_ops ra_adc_ops =
  47. 42 {
  48. 43 .enabled = ra_adc_enabled, // 对应应用层代码 rt_adc_enable 和 rt_adc_disable
  49. 44 .convert = ra_get_adc_value, // 对应应用层代码 rt_adc_read
  50. 45 };
  51. 46
  52. 47
  53. 48 static int ra_adc_init(void)
  54. 49 {
  55. 50 #if defined(BSP_USING_ADC0)
  56. 51 R_ADC_Open((adc_ctrl_t *)_ra_adc0_device.ra_adc_dev->g_ctrl,
  57. 52 (adc_cfg_t const * const)_ra_adc0_device.ra_adc_dev->g_cfg);
  58. 53
  59. 54 R_ADC_ScanCfg((adc_ctrl_t *)_ra_adc0_device.ra_adc_dev->g_ctrl,
  60. 55 (adc_cfg_t const * const)_ra_adc0_device.ra_adc_dev->g_channel_cfg);
  61. 56
  62. if (RT_EOK != rt_hw_adc_register(_ra_adc0_device.ra_adc_device_t, "adc0",
  63. &ra_adc_ops, (void *)_ra_adc0_device.ra_adc_dev))
  64. 57
  65. 58 {
  66. 59 LOG_E("adc0 register failed");
  67. 60 return -RT_ERROR;
  68. 61 }
  69. 62 #endif
  70. 63
  71. 64 #if defined(BSP_USING_ADC1)
  72. 65 R_ADC_Open((adc_ctrl_t *)_ra_adc1_device.ra_adc_dev->g_ctrl,
  73. 66 (adc_cfg_t const * const)_ra_adc1_device.ra_adc_dev->g_cfg);
  74. 67
  75. 68 R_ADC_ScanCfg((adc_ctrl_t *)_ra_adc1_device.ra_adc_dev->g_ctrl,
  76. 69 (adc_cfg_t const * const)_ra_adc1_device.ra_adc_dev->g_channel_cfg);
  77. 70
  78. if (RT_EOK != rt_hw_adc_register(_ra_adc1_device.ra_adc_device_t, "adc1",
  79. &ra_adc_ops, (void *)_ra_adc1_device.ra_adc_dev))
  80. 71
  81. 72 {
  82. 73 LOG_E("adc1 register failed");
  83. 74 return -RT_ERROR;
  84. 75 }
  85. 76 #endif
  86. 77
  87. 78 return RT_EOK;
  88. 79 }
  89. 80 INIT_BOARD_EXPORT(ra_adc_init);
复制代码
BSP层代码
  1. 1 //此部分代码须在keil工程中查看
  2. 2 // 所在文件为r_adc.c
  3. 3 // 从HAL层代码看,此部分代码为具体寄存器操作,所操作的参数为HAL层传递下来的参数
  4. 4
  5. /***************************************************************************************
  6. ****************************//**
  7. 5
  8. * Sets the operational mode, trigger sources, interrupt priority, and configurations
  9. for the peripheral as a whole.
  10. 6
  11. * If interrupt is enabled, the function registers a callback function pointer for
  12. notifying the user whenever a scan
  13. 7
  14. 8 * has completed.
  15. 9 *
  16. 10 * @retval FSP_SUCCESS Module is ready for use.
  17. 11 * @retval FSP_ERR_ASSERTION An input argument is invalid.
  18. * @retval FSP_ERR_ALREADY_OPEN The instance control structure has already
  19. been opened.
  20. 12
  21. * @retval FSP_ERR_IRQ_BSP_DISABLED A callback is provided, but the interrupt is
  22. not enabled.
  23. 13
  24. * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT The requested unit does not exist on this
  25. MCU.
  26. 14
  27. 15 * @retval FSP_ERR_INVALID_HW_CONDITION The ADC clock must be at least 1 MHz
  28. ****************************************************************************************
  29. ******************************/
  30. 16
  31. 17 fsp_err_t R_ADC_Open (adc_ctrl_t * p_ctrl, adc_cfg_t const * const p_cfg)
  32. 18 {
  33. 19 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
  34. 20
  35. 21 /* Perform parameter checking */
  36. 22 #if ADC_CFG_PARAM_CHECKING_ENABLE
  37. 23
  38. 24 /* Verify the pointers are valid */
  39. 25 FSP_ASSERT(NULL != p_instance_ctrl);
  40. iii.
  41. 26
  42. 27 /* Verify the configuration parameters are valid */
  43. 28 fsp_err_t err = r_adc_open_cfg_check(p_cfg);
  44. 29 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
  45. 30
  46. 31 /* Check for valid argument values for options that are unique to the IP */
  47. 32 err = r_adc_open_cfg_resolution_check(p_cfg);
  48. 33 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
  49. 34
  50. 35 /* Verify this unit has not already been initialized */
  51. 36 FSP_ERROR_RETURN(ADC_OPEN != p_instance_ctrl->opened, FSP_ERR_ALREADY_OPEN);
  52. 37
  53. 38 /* If a callback is used, then make sure an interrupt is enabled */
  54. 39 adc_extended_cfg_t const * p_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
  55. 40 if (NULL != p_cfg->p_callback)
  56. 41 {
  57. FSP_ERROR_RETURN((p_cfg->scan_end_irq >= 0) || (p_extend->window_a_irq >= 0) ||
  58. (p_extend->window_b_irq >= 0),
  59. 42
  60. 43 FSP_ERR_IRQ_BSP_DISABLED);
  61. 44
  62. /* Group B interrupts are never required since group B can be configured in
  63. continuous scan mode when group A
  64. 45
  65. 46 * has priority over group B. */
  66. 47 }
  67. 48
  68. 49 #else
  69. 50 adc_extended_cfg_t const * p_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
  70. 51 #endif
  71. 52
  72. 53 /* Save configurations. */
  73. 54 p_instance_ctrl->p_cfg = p_cfg;
  74. 55 p_instance_ctrl->p_callback = p_cfg->p_callback;
  75. 56 p_instance_ctrl->p_context = p_cfg->p_context;
  76. 57 p_instance_ctrl->p_callback_memory = NULL;
  77. 58
  78. 59 /* Calculate the register base address. */
  79. 60 uint32_t address_gap = (uint32_t) R_ADC1 - (uint32_t) R_ADC0;
  80. p_instance_ctrl->p_reg = (R_ADC0_Type *) ((uint32_t) R_ADC0 + (address_gap * p_cfg-
  81. >unit));
  82. 61
  83. 62
  84. 63 /* Initialize the hardware based on the configuration. */
  85. 64 r_adc_open_sub(p_instance_ctrl, p_cfg);
  86. 65
  87. 66 /* Enable interrupts */
  88. 67 r_adc_irq_enable(p_cfg->scan_end_irq, p_cfg->scan_end_ipl, p_instance_ctrl);
  89. 68 r_adc_irq_enable(p_cfg->scan_end_b_irq, p_cfg->scan_end_b_ipl, p_instance_ctrl);
  90. 69 r_adc_irq_enable(p_extend->window_a_irq, p_extend->window_a_ipl, p_instance_ctrl);
  91. 70 r_adc_irq_enable(p_extend->window_b_irq, p_extend->window_b_ipl, p_instance_ctrl);
  92. 71
  93. 72 /* Invalid scan mask (initialized for later). */
  94. 73 p_instance_ctrl->scan_mask = 0U;
  95. 74
  96. /* Mark driver as opened by initializing it to "RADC" in its ASCII equivalent for
  97. this unit. */
  98. 75
  99. 76 p_instance_ctrl->opened = ADC_OPEN;
  100. 77
  101. 78 /* Return the error code */
  102. 79 return FSP_SUCCESS;
  103. 80 }
  104. 81
  105. /***************************************************************************************
  106. ****************************//**
  107. 82
  108. * Configures the ADC scan parameters. Channel specific settings are set in this
  109. function. Pass a pointer to
  110. 83
  111. 84 * @ref adc_channel_cfg_t to p_channel_cfg.
  112. 85 *
  113. * @note This starts group B scans if adc_channel_cfg_t::priority_group_a is set to
  114. ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN.
  115. 86
  116. 87 *
  117. 88 * @retval FSP_SUCCESS Channel specific settings applied.
  118. 89 * @retval FSP_ERR_ASSERTION An input argument is invalid.
  119. 90 * @retval FSP_ERR_NOT_OPEN Unit is not open.
  120. ****************************************************************************************
  121. ******************************/
  122. 91
  123. 92 fsp_err_t R_ADC_ScanCfg (adc_ctrl_t * p_ctrl, void const * const p_channel_cfg)
  124. 93 {
  125. adc_channel_cfg_t const * p_adc_channel_cfg = (adc_channel_cfg_t const *)
  126. p_channel_cfg;
  127. 94
  128. 95 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
  129. 96 fsp_err_t err = FSP_SUCCESS;
  130. 97
  131. 98 #if ADC_CFG_PARAM_CHECKING_ENABLE
  132. 99 FSP_ASSERT(NULL != p_instance_ctrl);
  133. 100 FSP_ASSERT(NULL != p_adc_channel_cfg);
  134. 101 FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
  135. 102
  136. 103 err = r_adc_scan_cfg_check(p_instance_ctrl, p_adc_channel_cfg);
  137. 104 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
  138. 105 #endif
  139. 106
  140. 107 /* Configure the hardware based on the configuration */
  141. 108 r_adc_scan_cfg(p_instance_ctrl, p_adc_channel_cfg);
  142. 109
  143. 110 /* Save the scan mask locally; this is required for the infoGet function. */
  144. 111 p_instance_ctrl->scan_mask = p_adc_channel_cfg->scan_mask;
  145. 112
  146. 113 /* Return the error code */
  147. 114 return err;
  148. 115 }
  149. 116
  150. /***************************************************************************************
  151. ****************************//**
  152. 117
  153. * Starts a software scan or enables the hardware trigger for a scan depending on how
  154. the triggers were configured in
  155. 118
  156. * the R_ADC_Open call. If the unit was configured for ELC or external hardware
  157. triggering, then this function allows
  158. 119
  159. * the trigger signal to get to the ADC unit. The function is not able to control the
  160. generation of the trigger itself.
  161. 120
  162. * If the unit was configured for software triggering, then this function starts the
  163. software triggered scan.
  164. 121
  165. 122 *
  166. 123 * @pre Call R_ADC_ScanCfg after R_ADC_Open before starting a scan.
  167. 124 *
  168. * @pre On MCUs that support calibration, call R_ADC_Calibrate and wait for calibration
  169. to complete before starting
  170. 125
  171. 126 * a scan.
  172. 127 *
  173. * @retval FSP_SUCCESS Scan started (software trigger) or hardware
  174. triggers enabled.
  175. 128
  176. 129 * @retval FSP_ERR_ASSERTION An input argument is invalid.
  177. 130 * @retval FSP_ERR_NOT_OPEN Unit is not open.
  178. 131 * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
  179. * @retval FSP_ERR_IN_USE Another scan is still in progress (software
  180. trigger).
  181. 132
  182. ****************************************************************************************
  183. ******************************/
  184. 133
  185. 134 fsp_err_t R_ADC_ScanStart (adc_ctrl_t * p_ctrl)
  186. 135 {
  187. 136 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
  188. 137
  189. 138 /* Perform parameter checking */
  190. 139 #if ADC_CFG_PARAM_CHECKING_ENABLE
  191. 140
  192. 141 /* Verify the pointers are valid */
  193. 142 FSP_ASSERT(NULL != p_instance_ctrl);
  194. 143 FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
  195. 144 FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->initialized, FSP_ERR_NOT_INITIALIZED);
  196. 145 if (ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN != p_instance_ctrl->p_reg->ADGSPCR)
  197. 146 {
  198. 147 FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->ADCSR_b.ADST, FSP_ERR_IN_USE);
  199. 148 }
  200. 149 #endif
  201. 150
  202. 151 /* Enable hardware trigger or start software scan depending on mode. */
  203. 152 p_instance_ctrl->p_reg->ADCSR = p_instance_ctrl->scan_start_adcsr;
  204. 153
  205. 154 return FSP_SUCCESS;
  206. 155 }
  207. 156
  208. /***************************************************************************************
  209. ****************************//**
  210. 157
  211. * Reads conversion results from a single channel or sensor register into a 32-bit
  212. result.
  213. 158
  214. 159 *
  215. 160 * @retval FSP_SUCCESS Data read into provided p_data.
  216. 161 * @retval FSP_ERR_ASSERTION An input argument is invalid.
  217. 162 * @retval FSP_ERR_NOT_OPEN Unit is not open.
  218. 163 * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
  219. ****************************************************************************************
  220. ******************************/
  221. 164
  222. fsp_err_t R_ADC_Read32 (adc_ctrl_t * p_ctrl, adc_channel_t const reg_id, uint32_t *
  223. const p_data)
  224. 165
  225. 166 {
  226. 167 uint16_t result = 0U;
  227. 168 uint32_t result_32 = 0U;
  228. 169
  229. 170 #if ADC_CFG_PARAM_CHECKING_ENABLE
  230. 171 FSP_ASSERT(NULL != p_data);
  231. 172 #endif
  232. 173
  233. 174 fsp_err_t err = R_ADC_Read(p_ctrl, reg_id, &result);
  234. 175 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
  235. 176
  236. 177 result_32 = result;
  237. 178
  238. /* Left shift the result into the upper 16 bits if the unit is configured for left
  239. alignment. */
  240. 179
  241. 180 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
  242. 181 if (ADC_ALIGNMENT_LEFT == p_instance_ctrl->p_cfg->alignment)
  243. 182 {
  244. 183 result_32 <<= ADC_SHIFT_LEFT_ALIGNED_32_BIT;
  245. 184 }
  246. 185
  247. 186 *p_data = result_32;
  248. 187
  249. 188 return FSP_SUCCESS;
  250. 189 }
  251. 190
  252. /***************************************************************************************
  253. ****************************//**
  254. 191
  255. * Stops the software scan or disables the unit from being triggered by the hardware
  256. trigger (ELC or external) based on
  257. 192
  258. * what type of trigger the unit was configured for in the R_ADC_Open function.
  259. Stopping a hardware triggered scan via
  260. 193
  261. * this function does not abort an ongoing scan, but prevents the next scan from
  262. occurring. Stopping a software
  263. 194
  264. 195 * triggered scan aborts an ongoing scan.
  265. 196 *
  266. * @retval FSP_SUCCESS Scan stopped (software trigger) or hardware
  267. triggers disabled.
  268. 197
  269. 198 * @retval FSP_ERR_ASSERTION An input argument is invalid.
复制代码

FSP层
由于此层为FSP工具生成代码,我们仅需知道他和RTT对应关系为drv_adc.c中特定定义即可,且在瑞萨RA系列代码中,drv_adc.c为不会更改的部分,因此FSP层也不会更改。

4.编码验证
fsp和KConfig配置
此处省略
测试代码
  1. 1 // 此代码贴至hal_entry.c中
  2. 2 // P002为测试ADC口
  3. 3
  4. 4 #define DEV_ADC "adc0"
  5. 5 #define DEV_ADC_CHANNEL 0
  6. 6
  7. c.
  8. 4.
  9. a.
  10. b.
  11. 外接DAC的情况下,DAC电压调节可以正确读到电压变化。
  12. RA6M5、RA4M2和RA2L1在不改动应用层软件的情况下,可以实现同样的功能,仅需要在FSP层
  13. 面做IO口功能配置即可。
  14. 瑞萨在硬件设计时,有在一定程度上实现不同芯片之间的兼容。在软件层面上,除了在HAL层做不
  15. 同芯片之间的区分外,还在HAL层的下一层做了标准化,用户仅需要使用FSP配置对应功能,部分芯片
  16. 需要更换一下功能口编号即可快速实现工程迁移。
  17. 理论上,在不跑RTT的情况下,用户也可以使用类似于RTT的方式,在HAL层参数上做标准化,实
  18. 现工程在RA系列上的快速迁移。
  19. 7 #define REFER_VOLTAGE 330
  20. 8 #define CONVERT_BITS (1 << 12)
  21. 9
  22. 10 void ad_test(void)
  23. 11 {
  24. 12 rt_adc_device_t dev_adc = (rt_adc_device_t)rt_device_find(DEV_ADC);
  25. 13 rt_uint32_t vol, value = 1000;
  26. 14
  27. 15 if(dev_adc == RT_NULL)
  28. 16 {
  29. 17 rt_kprintf("no adc device named %s\n", DEV_ADC);
  30. 18 }
  31. 19 rt_adc_enable(dev_adc, DEV_ADC_CHANNEL);
  32. 20
  33. 21 value = rt_adc_read(dev_adc, DEV_ADC_CHANNEL);
  34. 22
  35. 23 vol = value * REFER_VOLTAGE / CONVERT_BITS;
  36. 24 rt_kprintf("the adc voltage is :%d.%02d \n", vol / 100, vol % 100);
  37. 25
  38. 26 rt_adc_disable(dev_adc, DEV_ADC_CHANNEL);
  39. 27 }
  40. 28 MSH_CMD_EXPORT(ad_test, ad_test);
复制代码
验证结果
外接DAC的情况下,DAC电压调节可以正确读到电压变化。
RA6M5、RA4M2和RA2L1在不改动应用层软件的情况下,可以实现同样的功能,仅需要在FSP层面做IO口功能配置即可。

5.结论
瑞萨在硬件设计时,有在一定程度上实现不同芯片之间的兼容。在软件层面上,除了在HAL层做不同芯片之间的区分外,还在HAL层的下一层做了标准化,用户仅需要使用FSP配置对应功能,部分芯片需要更换一下功能口编号即可快速实现工程迁移。
理论上,在不跑RTT的情况下,用户也可以使用类似于RTT的方式,在HAL层参数上做标准化,实现工程在RA系列上的快速迁移。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

12

主题

118

帖子

1万

积分

论坛元老

Rank: 8Rank: 8

积分
13584
发表于 2023-2-25 10:50:52 | 显示全部楼层

有FSP这都不是事
回复

使用道具 举报

3

主题

195

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
发表于 2023-3-14 10:07:50 | 显示全部楼层

有点麻烦
回复

使用道具 举报

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

本版积分规则

用户排行榜

RA助手

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

RA_Lance

主题: 93帖子:136精华:9

lugl

主题: 52帖子:150精华:1

xujiwei263

主题: 18帖子:86精华:0

Juggernaut

主题: 12帖子:118精华:0

books咦

主题: 11帖子:11精华:2
快速回复 返回顶部 返回列表