|
【瑞萨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 //具体HAL层代码见 \bsp\renesas\libraries\HAL_Drivers\drv_adc.c,此处仅提供核心代码
- 2 //其中 _ra_adc0_device 和 _ra_adc1_device为对应fsp部分代码
- 3
- static rt_err_t ra_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel,
- rt_bool_t enabled)
- 4
- 5 {
- 6 RT_ASSERT(device != RT_NULL);
- 7 struct ra_adc_map *adc = (struct ra_adc_map *)device->parent.user_data;
- 8 /**< start adc*/
- 9 if (enabled)
- 10 {
- 11 if (FSP_SUCCESS != R_ADC_ScanStart((adc_ctrl_t *)adc->g_ctrl))
- 12 {
- 13 LOG_E("start adc%c failed.", adc->name);
- 14 return -RT_ERROR;
- 15 }
- 16 }
- 17 else
- 18 {
- 19 /**< stop adc*/
- 20 if (FSP_SUCCESS != R_ADC_ScanStop((adc_ctrl_t *)adc->g_ctrl))
- 21 {
- 22 LOG_E("stop adc%c failed.", adc->name);
- 23 return -RT_ERROR;
- 24 }
- 25 }
- 26 return RT_EOK;
- 27 }
- 28
- static rt_err_t ra_get_adc_value(struct rt_adc_device *device, rt_uint32_t channel,
- rt_uint32_t *value)
- 29
- 30 {
- 31 RT_ASSERT(device != RT_NULL);
- 32 struct ra_adc_map *adc = (struct ra_adc_map *)device->parent.user_data;
- 33 if (RT_EOK != R_ADC_Read32((adc_ctrl_t *)adc->g_ctrl, channel, value))
- 34 {
- 35 LOG_E("get adc value failed.\n");
- 36 return -RT_ERROR;
- ii.
- 37 }
- 38 return RT_EOK;
- 39 }
- 40
- 41 static const struct rt_adc_ops ra_adc_ops =
- 42 {
- 43 .enabled = ra_adc_enabled, // 对应应用层代码 rt_adc_enable 和 rt_adc_disable
- 44 .convert = ra_get_adc_value, // 对应应用层代码 rt_adc_read
- 45 };
- 46
- 47
- 48 static int ra_adc_init(void)
- 49 {
- 50 #if defined(BSP_USING_ADC0)
- 51 R_ADC_Open((adc_ctrl_t *)_ra_adc0_device.ra_adc_dev->g_ctrl,
- 52 (adc_cfg_t const * const)_ra_adc0_device.ra_adc_dev->g_cfg);
- 53
- 54 R_ADC_ScanCfg((adc_ctrl_t *)_ra_adc0_device.ra_adc_dev->g_ctrl,
- 55 (adc_cfg_t const * const)_ra_adc0_device.ra_adc_dev->g_channel_cfg);
- 56
- if (RT_EOK != rt_hw_adc_register(_ra_adc0_device.ra_adc_device_t, "adc0",
- &ra_adc_ops, (void *)_ra_adc0_device.ra_adc_dev))
- 57
- 58 {
- 59 LOG_E("adc0 register failed");
- 60 return -RT_ERROR;
- 61 }
- 62 #endif
- 63
- 64 #if defined(BSP_USING_ADC1)
- 65 R_ADC_Open((adc_ctrl_t *)_ra_adc1_device.ra_adc_dev->g_ctrl,
- 66 (adc_cfg_t const * const)_ra_adc1_device.ra_adc_dev->g_cfg);
- 67
- 68 R_ADC_ScanCfg((adc_ctrl_t *)_ra_adc1_device.ra_adc_dev->g_ctrl,
- 69 (adc_cfg_t const * const)_ra_adc1_device.ra_adc_dev->g_channel_cfg);
- 70
- if (RT_EOK != rt_hw_adc_register(_ra_adc1_device.ra_adc_device_t, "adc1",
- &ra_adc_ops, (void *)_ra_adc1_device.ra_adc_dev))
- 71
- 72 {
- 73 LOG_E("adc1 register failed");
- 74 return -RT_ERROR;
- 75 }
- 76 #endif
- 77
- 78 return RT_EOK;
- 79 }
- 80 INIT_BOARD_EXPORT(ra_adc_init);
复制代码 BSP层代码
- 1 //此部分代码须在keil工程中查看
- 2 // 所在文件为r_adc.c
- 3 // 从HAL层代码看,此部分代码为具体寄存器操作,所操作的参数为HAL层传递下来的参数
- 4
- /***************************************************************************************
- ****************************//**
- 5
- * Sets the operational mode, trigger sources, interrupt priority, and configurations
- for the peripheral as a whole.
- 6
- * If interrupt is enabled, the function registers a callback function pointer for
- notifying the user whenever a scan
- 7
- 8 * has completed.
- 9 *
- 10 * @retval FSP_SUCCESS Module is ready for use.
- 11 * @retval FSP_ERR_ASSERTION An input argument is invalid.
- * @retval FSP_ERR_ALREADY_OPEN The instance control structure has already
- been opened.
- 12
- * @retval FSP_ERR_IRQ_BSP_DISABLED A callback is provided, but the interrupt is
- not enabled.
- 13
- * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT The requested unit does not exist on this
- MCU.
- 14
- 15 * @retval FSP_ERR_INVALID_HW_CONDITION The ADC clock must be at least 1 MHz
- ****************************************************************************************
- ******************************/
- 16
- 17 fsp_err_t R_ADC_Open (adc_ctrl_t * p_ctrl, adc_cfg_t const * const p_cfg)
- 18 {
- 19 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
- 20
- 21 /* Perform parameter checking */
- 22 #if ADC_CFG_PARAM_CHECKING_ENABLE
- 23
- 24 /* Verify the pointers are valid */
- 25 FSP_ASSERT(NULL != p_instance_ctrl);
- iii.
- 26
- 27 /* Verify the configuration parameters are valid */
- 28 fsp_err_t err = r_adc_open_cfg_check(p_cfg);
- 29 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
- 30
- 31 /* Check for valid argument values for options that are unique to the IP */
- 32 err = r_adc_open_cfg_resolution_check(p_cfg);
- 33 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
- 34
- 35 /* Verify this unit has not already been initialized */
- 36 FSP_ERROR_RETURN(ADC_OPEN != p_instance_ctrl->opened, FSP_ERR_ALREADY_OPEN);
- 37
- 38 /* If a callback is used, then make sure an interrupt is enabled */
- 39 adc_extended_cfg_t const * p_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
- 40 if (NULL != p_cfg->p_callback)
- 41 {
- FSP_ERROR_RETURN((p_cfg->scan_end_irq >= 0) || (p_extend->window_a_irq >= 0) ||
- (p_extend->window_b_irq >= 0),
- 42
- 43 FSP_ERR_IRQ_BSP_DISABLED);
- 44
- /* Group B interrupts are never required since group B can be configured in
- continuous scan mode when group A
- 45
- 46 * has priority over group B. */
- 47 }
- 48
- 49 #else
- 50 adc_extended_cfg_t const * p_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
- 51 #endif
- 52
- 53 /* Save configurations. */
- 54 p_instance_ctrl->p_cfg = p_cfg;
- 55 p_instance_ctrl->p_callback = p_cfg->p_callback;
- 56 p_instance_ctrl->p_context = p_cfg->p_context;
- 57 p_instance_ctrl->p_callback_memory = NULL;
- 58
- 59 /* Calculate the register base address. */
- 60 uint32_t address_gap = (uint32_t) R_ADC1 - (uint32_t) R_ADC0;
- p_instance_ctrl->p_reg = (R_ADC0_Type *) ((uint32_t) R_ADC0 + (address_gap * p_cfg-
- >unit));
- 61
- 62
- 63 /* Initialize the hardware based on the configuration. */
- 64 r_adc_open_sub(p_instance_ctrl, p_cfg);
- 65
- 66 /* Enable interrupts */
- 67 r_adc_irq_enable(p_cfg->scan_end_irq, p_cfg->scan_end_ipl, p_instance_ctrl);
- 68 r_adc_irq_enable(p_cfg->scan_end_b_irq, p_cfg->scan_end_b_ipl, p_instance_ctrl);
- 69 r_adc_irq_enable(p_extend->window_a_irq, p_extend->window_a_ipl, p_instance_ctrl);
- 70 r_adc_irq_enable(p_extend->window_b_irq, p_extend->window_b_ipl, p_instance_ctrl);
- 71
- 72 /* Invalid scan mask (initialized for later). */
- 73 p_instance_ctrl->scan_mask = 0U;
- 74
- /* Mark driver as opened by initializing it to "RADC" in its ASCII equivalent for
- this unit. */
- 75
- 76 p_instance_ctrl->opened = ADC_OPEN;
- 77
- 78 /* Return the error code */
- 79 return FSP_SUCCESS;
- 80 }
- 81
- /***************************************************************************************
- ****************************//**
- 82
- * Configures the ADC scan parameters. Channel specific settings are set in this
- function. Pass a pointer to
- 83
- 84 * @ref adc_channel_cfg_t to p_channel_cfg.
- 85 *
- * @note This starts group B scans if adc_channel_cfg_t::priority_group_a is set to
- ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN.
- 86
- 87 *
- 88 * @retval FSP_SUCCESS Channel specific settings applied.
- 89 * @retval FSP_ERR_ASSERTION An input argument is invalid.
- 90 * @retval FSP_ERR_NOT_OPEN Unit is not open.
- ****************************************************************************************
- ******************************/
- 91
- 92 fsp_err_t R_ADC_ScanCfg (adc_ctrl_t * p_ctrl, void const * const p_channel_cfg)
- 93 {
- adc_channel_cfg_t const * p_adc_channel_cfg = (adc_channel_cfg_t const *)
- p_channel_cfg;
- 94
- 95 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
- 96 fsp_err_t err = FSP_SUCCESS;
- 97
- 98 #if ADC_CFG_PARAM_CHECKING_ENABLE
- 99 FSP_ASSERT(NULL != p_instance_ctrl);
- 100 FSP_ASSERT(NULL != p_adc_channel_cfg);
- 101 FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
- 102
- 103 err = r_adc_scan_cfg_check(p_instance_ctrl, p_adc_channel_cfg);
- 104 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
- 105 #endif
- 106
- 107 /* Configure the hardware based on the configuration */
- 108 r_adc_scan_cfg(p_instance_ctrl, p_adc_channel_cfg);
- 109
- 110 /* Save the scan mask locally; this is required for the infoGet function. */
- 111 p_instance_ctrl->scan_mask = p_adc_channel_cfg->scan_mask;
- 112
- 113 /* Return the error code */
- 114 return err;
- 115 }
- 116
- /***************************************************************************************
- ****************************//**
- 117
- * Starts a software scan or enables the hardware trigger for a scan depending on how
- the triggers were configured in
- 118
- * the R_ADC_Open call. If the unit was configured for ELC or external hardware
- triggering, then this function allows
- 119
- * the trigger signal to get to the ADC unit. The function is not able to control the
- generation of the trigger itself.
- 120
- * If the unit was configured for software triggering, then this function starts the
- software triggered scan.
- 121
- 122 *
- 123 * @pre Call R_ADC_ScanCfg after R_ADC_Open before starting a scan.
- 124 *
- * @pre On MCUs that support calibration, call R_ADC_Calibrate and wait for calibration
- to complete before starting
- 125
- 126 * a scan.
- 127 *
- * @retval FSP_SUCCESS Scan started (software trigger) or hardware
- triggers enabled.
- 128
- 129 * @retval FSP_ERR_ASSERTION An input argument is invalid.
- 130 * @retval FSP_ERR_NOT_OPEN Unit is not open.
- 131 * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
- * @retval FSP_ERR_IN_USE Another scan is still in progress (software
- trigger).
- 132
- ****************************************************************************************
- ******************************/
- 133
- 134 fsp_err_t R_ADC_ScanStart (adc_ctrl_t * p_ctrl)
- 135 {
- 136 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
- 137
- 138 /* Perform parameter checking */
- 139 #if ADC_CFG_PARAM_CHECKING_ENABLE
- 140
- 141 /* Verify the pointers are valid */
- 142 FSP_ASSERT(NULL != p_instance_ctrl);
- 143 FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
- 144 FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->initialized, FSP_ERR_NOT_INITIALIZED);
- 145 if (ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN != p_instance_ctrl->p_reg->ADGSPCR)
- 146 {
- 147 FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->ADCSR_b.ADST, FSP_ERR_IN_USE);
- 148 }
- 149 #endif
- 150
- 151 /* Enable hardware trigger or start software scan depending on mode. */
- 152 p_instance_ctrl->p_reg->ADCSR = p_instance_ctrl->scan_start_adcsr;
- 153
- 154 return FSP_SUCCESS;
- 155 }
- 156
- /***************************************************************************************
- ****************************//**
- 157
- * Reads conversion results from a single channel or sensor register into a 32-bit
- result.
- 158
- 159 *
- 160 * @retval FSP_SUCCESS Data read into provided p_data.
- 161 * @retval FSP_ERR_ASSERTION An input argument is invalid.
- 162 * @retval FSP_ERR_NOT_OPEN Unit is not open.
- 163 * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
- ****************************************************************************************
- ******************************/
- 164
- fsp_err_t R_ADC_Read32 (adc_ctrl_t * p_ctrl, adc_channel_t const reg_id, uint32_t *
- const p_data)
- 165
- 166 {
- 167 uint16_t result = 0U;
- 168 uint32_t result_32 = 0U;
- 169
- 170 #if ADC_CFG_PARAM_CHECKING_ENABLE
- 171 FSP_ASSERT(NULL != p_data);
- 172 #endif
- 173
- 174 fsp_err_t err = R_ADC_Read(p_ctrl, reg_id, &result);
- 175 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
- 176
- 177 result_32 = result;
- 178
- /* Left shift the result into the upper 16 bits if the unit is configured for left
- alignment. */
- 179
- 180 adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
- 181 if (ADC_ALIGNMENT_LEFT == p_instance_ctrl->p_cfg->alignment)
- 182 {
- 183 result_32 <<= ADC_SHIFT_LEFT_ALIGNED_32_BIT;
- 184 }
- 185
- 186 *p_data = result_32;
- 187
- 188 return FSP_SUCCESS;
- 189 }
- 190
- /***************************************************************************************
- ****************************//**
- 191
- * Stops the software scan or disables the unit from being triggered by the hardware
- trigger (ELC or external) based on
- 192
- * what type of trigger the unit was configured for in the R_ADC_Open function.
- Stopping a hardware triggered scan via
- 193
- * this function does not abort an ongoing scan, but prevents the next scan from
- occurring. Stopping a software
- 194
- 195 * triggered scan aborts an ongoing scan.
- 196 *
- * @retval FSP_SUCCESS Scan stopped (software trigger) or hardware
- triggers disabled.
- 197
- 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 // 此代码贴至hal_entry.c中
- 2 // P002为测试ADC口
- 3
- 4 #define DEV_ADC "adc0"
- 5 #define DEV_ADC_CHANNEL 0
- 6
- c.
- 4.
- a.
- b.
- 外接DAC的情况下,DAC电压调节可以正确读到电压变化。
- RA6M5、RA4M2和RA2L1在不改动应用层软件的情况下,可以实现同样的功能,仅需要在FSP层
- 面做IO口功能配置即可。
- 瑞萨在硬件设计时,有在一定程度上实现不同芯片之间的兼容。在软件层面上,除了在HAL层做不
- 同芯片之间的区分外,还在HAL层的下一层做了标准化,用户仅需要使用FSP配置对应功能,部分芯片
- 需要更换一下功能口编号即可快速实现工程迁移。
- 理论上,在不跑RTT的情况下,用户也可以使用类似于RTT的方式,在HAL层参数上做标准化,实
- 现工程在RA系列上的快速迁移。
- 7 #define REFER_VOLTAGE 330
- 8 #define CONVERT_BITS (1 << 12)
- 9
- 10 void ad_test(void)
- 11 {
- 12 rt_adc_device_t dev_adc = (rt_adc_device_t)rt_device_find(DEV_ADC);
- 13 rt_uint32_t vol, value = 1000;
- 14
- 15 if(dev_adc == RT_NULL)
- 16 {
- 17 rt_kprintf("no adc device named %s\n", DEV_ADC);
- 18 }
- 19 rt_adc_enable(dev_adc, DEV_ADC_CHANNEL);
- 20
- 21 value = rt_adc_read(dev_adc, DEV_ADC_CHANNEL);
- 22
- 23 vol = value * REFER_VOLTAGE / CONVERT_BITS;
- 24 rt_kprintf("the adc voltage is :%d.%02d \n", vol / 100, vol % 100);
- 25
- 26 rt_adc_disable(dev_adc, DEV_ADC_CHANNEL);
- 27 }
- 28 MSH_CMD_EXPORT(ad_test, ad_test);
复制代码 验证结果
外接DAC的情况下,DAC电压调节可以正确读到电压变化。
RA6M5、RA4M2和RA2L1在不改动应用层软件的情况下,可以实现同样的功能,仅需要在FSP层面做IO口功能配置即可。
5.结论
瑞萨在硬件设计时,有在一定程度上实现不同芯片之间的兼容。在软件层面上,除了在HAL层做不同芯片之间的区分外,还在HAL层的下一层做了标准化,用户仅需要使用FSP配置对应功能,部分芯片需要更换一下功能口编号即可快速实现工程迁移。
理论上,在不跑RTT的情况下,用户也可以使用类似于RTT的方式,在HAL层参数上做标准化,实现工程在RA系列上的快速迁移。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|