182 lines
4.7 KiB
C
182 lines
4.7 KiB
C
/*
|
|
* @copyright (c) 2023-2024, MR Development Team
|
|
*
|
|
* @license SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* @date 2023-11-11 MacRsh First version
|
|
*/
|
|
|
|
#include "drv_adc.h"
|
|
|
|
#ifdef MR_USING_ADC
|
|
|
|
#if !defined(MR_USING_ADC1) && !defined(MR_USING_ADC2)
|
|
#warning "Please enable at least one ADC driver"
|
|
#endif /* !defined(MR_USING_ADC1) && !defined(MR_USING_ADC2) */
|
|
|
|
enum drv_adc_index
|
|
{
|
|
#ifdef MR_USING_ADC1
|
|
DRV_INDEX_ADC1,
|
|
#endif /* MR_USING_ADC1 */
|
|
#ifdef MR_USING_ADC2
|
|
DRV_INDEX_ADC2,
|
|
#endif /* MR_USING_ADC2 */
|
|
DRV_INDEX_ADC_MAX
|
|
};
|
|
|
|
static const char *adc_path[] =
|
|
{
|
|
#ifdef MR_USING_ADC1
|
|
"adc1",
|
|
#endif /* MR_USING_ADC1 */
|
|
#ifdef MR_USING_ADC2
|
|
"adc2",
|
|
#endif /* MR_USING_ADC2 */
|
|
};
|
|
|
|
static struct drv_adc_data adc_drv_data[] =
|
|
{
|
|
#ifdef MR_USING_ADC1
|
|
{ADC1, RCC_APB2Periph_ADC1},
|
|
#endif /* MR_USING_ADC1 */
|
|
#ifdef MR_USING_ADC2
|
|
{ADC2, RCC_APB2Periph_ADC2},
|
|
#endif /* MR_USING_ADC2 */
|
|
};
|
|
|
|
static struct drv_adc_channel_data adc_channel_drv_data[] = DRV_ADC_CHANNEL_CONFIG;
|
|
|
|
static struct mr_adc adc_dev[MR_ARRAY_NUM(adc_drv_data)];
|
|
|
|
static struct drv_adc_channel_data *drv_adc_get_channel_data(int channel)
|
|
{
|
|
if (channel >= MR_ARRAY_NUM(adc_channel_drv_data))
|
|
{
|
|
return NULL;
|
|
}
|
|
return &adc_channel_drv_data[channel];
|
|
}
|
|
|
|
static int drv_adc_configure(struct mr_adc *adc, int state)
|
|
{
|
|
struct drv_adc_data *adc_data = (struct drv_adc_data *)adc->dev.drv->data;
|
|
ADC_InitTypeDef ADC_InitStructure = {0};
|
|
|
|
/* Configure clock */
|
|
RCC_APB2PeriphClockCmd(adc_data->clock, state);
|
|
#ifdef MR_USING_CH32V00X
|
|
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
|
|
#else
|
|
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
|
|
#endif /* MR_USING_CH32V00X */
|
|
|
|
/* Configure ADC */
|
|
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
|
|
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
|
|
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
|
|
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
|
|
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
|
|
ADC_InitStructure.ADC_NbrOfChannel = 1;
|
|
ADC_Init(adc_data->instance, &ADC_InitStructure);
|
|
ADC_Cmd(adc_data->instance, state);
|
|
return MR_EOK;
|
|
}
|
|
|
|
static int drv_adc_channel_configure(struct mr_adc *adc, int channel, int state)
|
|
{
|
|
struct drv_adc_channel_data *adc_channel_data = drv_adc_get_channel_data(channel);
|
|
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
|
|
|
/* Check channel is valid */
|
|
if (adc_channel_data == NULL)
|
|
{
|
|
return MR_EINVAL;
|
|
}
|
|
|
|
/* Configure clock */
|
|
RCC_APB2PeriphClockCmd(adc_channel_data->gpio_clock, ENABLE);
|
|
|
|
/* Configure pin */
|
|
if (adc_channel_data->port != MR_NULL)
|
|
{
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
|
|
GPIO_InitStructure.GPIO_Pin = adc_channel_data->pin;
|
|
GPIO_Init(adc_channel_data->port, &GPIO_InitStructure);
|
|
}
|
|
|
|
#ifndef MR_USING_CH32V00X
|
|
/* Configure temp-sensor */
|
|
if ((adc_channel_data->channel == ADC_Channel_16) || (adc_channel_data->channel == ADC_Channel_17))
|
|
{
|
|
ADC_TempSensorVrefintCmd(ENABLE);
|
|
}
|
|
#endif /* MR_USING_CH32V00X */
|
|
return MR_EOK;
|
|
}
|
|
|
|
static uint32_t drv_adc_read(struct mr_adc *adc, int channel)
|
|
{
|
|
struct drv_adc_data *adc_data = (struct drv_adc_data *)adc->dev.drv->data;
|
|
struct drv_adc_channel_data *adc_channel_data = drv_adc_get_channel_data(channel);
|
|
size_t i = 0;
|
|
|
|
/* Check channel is valid */
|
|
if (adc_channel_data == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Read data */
|
|
#ifdef MR_USING_CH32V00X
|
|
ADC_RegularChannelConfig(adc_data->instance, adc_channel_data->channel, 1, ADC_SampleTime_15Cycles);
|
|
#else
|
|
ADC_RegularChannelConfig(adc_data->instance, adc_channel_data->channel, 1, ADC_SampleTime_13Cycles5);
|
|
#endif /* MR_USING_CH32V00X */
|
|
ADC_SoftwareStartConvCmd(adc_data->instance, ENABLE);
|
|
while (ADC_GetFlagStatus(adc_data->instance, ADC_FLAG_EOC) == RESET)
|
|
{
|
|
i++;
|
|
if (i > UINT16_MAX)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
ADC_ClearFlag(adc_data->instance, ADC_FLAG_EOC);
|
|
return ADC_GetConversionValue(adc_data->instance);
|
|
}
|
|
|
|
static struct mr_adc_ops adc_drv_ops =
|
|
{
|
|
drv_adc_configure,
|
|
drv_adc_channel_configure,
|
|
drv_adc_read
|
|
};
|
|
|
|
static struct mr_drv adc_drv[] =
|
|
{
|
|
#ifdef MR_USING_ADC1
|
|
{
|
|
&adc_drv_ops,
|
|
&adc_drv_data[DRV_INDEX_ADC1],
|
|
},
|
|
#endif /* MR_USING_ADC1 */
|
|
#ifdef MR_USING_ADC2
|
|
{
|
|
&adc_drv_ops,
|
|
&adc_drv_data[DRV_INDEX_ADC2],
|
|
},
|
|
#endif /* MR_USING_ADC2 */
|
|
};
|
|
|
|
static void drv_adc_init(void)
|
|
{
|
|
for (size_t i = 0; i < MR_ARRAY_NUM(adc_dev); i++)
|
|
{
|
|
mr_adc_register(&adc_dev[i], adc_path[i], &adc_drv[i]);
|
|
}
|
|
}
|
|
MR_INIT_DRV_EXPORT(drv_adc_init);
|
|
|
|
#endif /* MR_USING_ADC */
|