motor_f103/User/system/bsp/adcs.c

469 lines
13 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file adcs.c
* @author xxx
* @date 2023-09-04 15:59:16
* @brief LL库ADC驱动
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "adcs.h"
#include "dma.h"
adcs_t adcs[ADCS_MAX];
static uint8_t adc_get_channels_count(uint32_t channnels); // 通过用户配置的通道号获取通道数量
/**
* @brief ADC初始化
* @param {adcs_e} num ADC编号
* @param {ADC_TypeDef} *adc ADC外设
* @param {DMA_TypeDef} *dma DMA外设
* @param {uint32_t} dma_channel DMA通道
* @param {uint8_t} adc_cct ADC采样次数
* @param {uint32_t} channels 存储数据所在的序列号
* @return {*}
* @note TCONV(转换时间) = (采样时间 + 12.5 个周期)/(主频/ADC分频系数)
*/
void adc_init(adcs_e num, ADC_TypeDef *adc, DMA_TypeDef *dma, uint32_t dma_channel, uint16_t adc_cct, uint32_t channels)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
DBG_ASSERT(adc != NULL __DBG_LINE);
DBG_ASSERT(dma != NULL __DBG_LINE);
DBG_ASSERT(adc_cct > 0 __DBG_LINE);
adcs_t *p = &adcs[num];
osel_memset((uint8_t *)p, 0, sizeof(adcs_t));
p->adc = adc;
p->dma = dma;
p->dma_channel = dma_channel;
p->channels.data = channels;
p->adc_cct = adc_cct;
p->adc_chans_count = adc_get_channels_count(channels);
p->adc_sum = adc_cct * p->adc_chans_count;
#if defined(SRAM2_BASE) // SRAM2速度更快
p->adc_value = (uint16_t *)osel_mem_alloc2(sizeof(uint16_t) * p->adc_sum);
#else
p->adc_value = (uint16_t *)osel_mem_alloc(sizeof(uint16_t) * p->adc_sum);
#endif
DBG_ASSERT(p->adc_value != NULL __DBG_LINE);
osel_memset((uint8_t *)p->adc_value, 0, sizeof(uint16_t) * p->adc_sum);
uint32_t backup_setting_adc_dma_transfer = 0U;
backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(p->adc);
LL_ADC_REG_SetDMATransfer(p->adc, LL_ADC_REG_DMA_TRANSFER_NONE);
// ADC开始校准
LL_ADC_StartCalibration(p->adc, LL_ADC_SINGLE_ENDED);
// 等待校准完成
while (LL_ADC_IsCalibrationOnGoing(p->adc))
;
LL_ADC_REG_SetDMATransfer(p->adc, backup_setting_adc_dma_transfer);
LL_mDelay(10);
LL_ADC_EnableIT_OVR(p->adc);
LL_ADC_Enable(p->adc);
LL_mDelay(10);
if (BIT_IS_SET(channels, INVREF))
{
// 使能VREFINT
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(p->adc), LL_ADC_PATH_INTERNAL_VREFINT);
}
LL_DMA_SetDataLength(p->dma, p->dma_channel, p->adc_sum);
LL_DMA_SetPeriphAddress(p->dma, p->dma_channel, LL_ADC_DMA_GetRegAddr(p->adc, LL_ADC_DMA_REG_REGULAR_DATA));
LL_DMA_SetMemoryAddress(p->dma, p->dma_channel, (uint32_t)p->adc_value);
LL_DMA_EnableChannel(p->dma, p->dma_channel);
if (backup_setting_adc_dma_transfer == LL_ADC_REG_DMA_TRANSFER_UNLIMITED)
{
LL_ADC_REG_StartConversion(p->adc); // 开始转换
}
}
/**
* @brief 启动样本
*
* 根据给定的 ADCS 枚举值启动 ADC 样本校准。
*
* @param num ADCS 枚举值
*/
void start_sample(adcs_e num)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
adcs_t *p = &adcs[num];
LL_DMA_SetDataLength(p->dma, p->dma_channel, p->adc_sum);
LL_DMA_SetPeriphAddress(p->dma, p->dma_channel, LL_ADC_DMA_GetRegAddr(p->adc, LL_ADC_DMA_REG_REGULAR_DATA));
LL_DMA_SetMemoryAddress(p->dma, p->dma_channel, (uint32_t)p->adc_value);
LL_DMA_EnableChannel(p->dma, p->dma_channel);
LL_ADC_ClearFlag_OVR(p->adc);
LL_ADC_ClearFlag_EOC(p->adc);
LL_ADC_REG_StartConversion(p->adc); // 开始转换
// ADC开始校准
LL_ADC_StartCalibration(p->adc, LL_ADC_SINGLE_ENDED);
}
/**
* @brief 停止样本采集
*
* 根据给定的 ADCS 枚举值,停止相应的 ADCS 样本采集。
*
* @param num ADCS 枚举值
*/
void stop_sample(adcs_e num)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
adcs_t *p = &adcs[num];
LL_ADC_REG_StopConversion(p->adc);
while (LL_ADC_REG_IsConversionOngoing(p->adc) != 0)
;
LL_DMA_DisableChannel(p->dma, p->dma_channel);
DMA_CLEAR_FLAG_TC_CHANNEL(p->dma, p->dma_channel);
DMA_CLEAR_FLAG_TE_CHANNEL(p->dma, p->dma_channel);
}
/**
* @brief ADC重新开始转换
* @param {adcs_e} num ADC编号
* @return {*}
* @note
*/
void adc_restart(adcs_e num)
{
stop_sample(num);
start_sample(num);
}
/**
* @brief ADC反初始化
* @param {adcs_e} num ADC编号
* @return {*}
* @note
*/
void adc_dinit(adcs_e num)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
adcs_t *p = &adcs[num];
LL_ADC_REG_StopConversion(p->adc);
LL_DMA_DisableChannel(p->dma, p->dma_channel);
LL_ADC_Disable(p->adc);
if (p->adc_value != NULL)
{
#if defined(SRAM2_BASE)
osel_mem_free2((uint16_t *)p->adc_value);
#else
osel_mem_free((uint16_t *)p->adc_value);
#endif
}
}
/**
* @brief 获取ADC转换结果,只需要第一个值
* @param {adcs_e} num
* @param {uint8_t} chan
* @return {*}
* @note
*/
uint16_t adc_result_only_one(adcs_e num, uint8_t chan)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
adcs_t *p = &adcs[num];
DBG_ASSERT(p != NULL __DBG_LINE);
uint16_t(*gram)[p->adc_chans_count] = (uint16_t(*)[p->adc_chans_count])p->adc_value;
return gram[0][chan];
}
/**
* @brief 中位值平均滤波,获取ADC转换结果
* @param {adcs_e} num ADC编号
* @param {uint8_t} chan 存储数据所在的序列号
* @return {*}
* @note 不适合在中断中使用因为排序算法时间复杂度为O(n^2)
*/
uint16_t adc_result_median_average(adcs_e num, uint8_t chan)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
adcs_t *p = &adcs[num];
DBG_ASSERT(p != NULL __DBG_LINE);
if (p->adc_cct <= 2)
return 0; // 如果adc_cct小于等于2直接返回0
p->median_average_ticks.uticks = sys_get_tick();
uint16_t adc_temp[p->adc_cct];
uint32_t adc_sum = 0;
uint16_t count = p->adc_cct >> 2; // 使用位移操作计算n的值
// 减少重复计算,计算基础偏移量
uint16_t *adc_values = (uint16_t *)p->adc_value + chan;
for (uint16_t i = 0; i < p->adc_cct; ++i, adc_values += p->adc_chans_count)
{
adc_temp[i] = *adc_values;
}
insertion_sort(adc_temp, p->adc_cct);
// 计算中间部分的和
for (uint16_t i = count; i < p->adc_cct - count; ++i)
{
adc_sum += adc_temp[i];
}
// 计算平均值确保不会除以0
uint16_t res = adc_sum / (p->adc_cct - (count << 1));
p->median_average_ticks.ticks_current = sys_get_tick() - p->median_average_ticks.uticks;
if (p->median_average_ticks.ticks_current > p->median_average_ticks.ticks_max)
{
p->median_average_ticks.ticks_max = p->median_average_ticks.ticks_current;
}
return res;
}
/**
* @brief 中位值滤波,获取ADC转换结果
* @param {adcs_e} num ADC编号
* @param {uint8_t} chan 存储数据所在的序列号
* @return {*}
* @note 不适合在中断中使用因为排序算法时间复杂度为O(n^2)
*/
uint16_t adc_result_median(adcs_e num, uint8_t chan)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
uint16_t res = 0;
adcs_t *p = &adcs[num];
DBG_ASSERT(p != NULL __DBG_LINE);
p->median_ticks.uticks = sys_get_tick();
uint16_t adc_temp[p->adc_cct];
// 减少重复计算,计算基础偏移量
uint16_t *adc_values = (uint16_t *)p->adc_value + chan;
for (uint16_t i = 0; i < p->adc_cct; ++i, adc_values += p->adc_chans_count)
{
adc_temp[i] = *adc_values;
}
insertion_sort(adc_temp, p->adc_cct);
res = adc_temp[p->adc_cct >> 1];
p->median_ticks.ticks_current = sys_get_tick() - p->median_ticks.uticks;
if (p->median_ticks.ticks_current > p->median_ticks.ticks_max)
{
p->median_ticks.ticks_max = p->median_ticks.ticks_current;
}
return res;
}
/**
* @brief 平均值,获取ADC转换结果
* @param {adcs_e} num ADC编号
* @param {uint8_t} chan 存储数据所在的序列号
* @return {*}
* @note
*/
uint16_t adc_result_average(adcs_e num, uint8_t chan)
{
DBG_ASSERT(num < ADCS_MAX __DBG_LINE);
uint16_t res = 0;
uint32_t adc_sum = 0;
adcs_t *p = &adcs[num];
DBG_ASSERT(p != NULL __DBG_LINE);
p->average_ticks.uticks = sys_get_tick();
// 减少重复计算,计算基础偏移量
uint16_t *adc_values = (uint16_t *)p->adc_value + chan;
for (uint16_t i = 0; i < p->adc_cct; ++i, adc_values += p->adc_chans_count)
{
adc_sum += *adc_values;
}
res = adc_sum / p->adc_cct;
p->average_ticks.ticks_current = sys_get_tick() - p->average_ticks.uticks;
if (p->average_ticks.ticks_current > p->average_ticks.ticks_max)
{
p->average_ticks.ticks_max = p->average_ticks.ticks_current;
}
return res;
}
/**
* @brief 计算内部温度
* @param {uint16_t} adc_value ADC转换结果
* @return {*}
* @note 计算公式为:(measure * VDD_APPLI / VDD_CALIB) - (int32_t)*TEMP30_CAL_ADDR) * (int32_t)(130 - 30) / (int32_t)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR)) + 30
* adc_value 是从ADC读取的温度传感器数据。
TS_CAL1 是在30°C时校准的温度传感器数据地址为TEMPSENSOR_CAL1_ADDR。
TS_CAL2 是在110°C时校准的温度传感器数据地址为TEMPSENSOR_CAL2_ADDR。
TEMPSENSOR_CAL1_TEMP 是30°C。
TEMPSENSOR_CAL2_TEMP 是110°C。
*/
float32 adc_result_temperature(uint16_t adc_value)
{
uint16_t ts_cal1 = *TEMPSENSOR_CAL1_ADDR;
uint16_t ts_cal2 = *TEMPSENSOR_CAL2_ADDR;
float32 temperature = ((float32)(adc_value - ts_cal1) / (ts_cal2 - ts_cal1)) * (TEMPSENSOR_CAL2_TEMP - TEMPSENSOR_CAL1_TEMP) + TEMPSENSOR_CAL1_TEMP;
return temperature;
}
/**
* @brief 计算内部电压
* @param {uint16_t} adc_value ADC转换结果
* @return {*} 电压值V
* @note
*/
float32 adc_result_value_local(uint16_t adc_value)
{
float32 vdd = (VREFINT_CAL_VREF * (*VREFINT_CAL_ADDR)) / 4095;
return ((vdd / adc_value) * 4095) / 1000;
}
/**
* @brief ADC DMA转换回调函数
{
* @param {adcs_e} num ADC编号
* @return {*}
* @note
*/
void adc_dma_callback(adcs_e num)
{
adcs_t *p = &adcs[num];
DBG_ASSERT(p != NULL __DBG_LINE);
if (LL_DMA_IsActiveFlag_TC1(p->dma) != 0)
{
LL_DMA_ClearFlag_TC1(p->dma);
// 停止ADC转换
LL_ADC_REG_StopConversion(p->adc);
// 关闭ADC,可以不关闭但是校准无法清除
// LL_ADC_Disable(p->adc);
}
// 检查DMA1的传输错误标志是否为1如果是则清除该标志
if (LL_DMA_IsActiveFlag_TE1(p->dma) != 0)
{
LL_DMA_ClearFlag_TE1(p->dma);
}
}
/**
* @brief ADC回调函数
* @param {adcs_e} num ADC编号
* @return {*}
* @note
*/
void adc_env_callback(adcs_e num)
{
adcs_t *p = &adcs[num];
DBG_ASSERT(p != NULL __DBG_LINE);
if (LL_ADC_IsActiveFlag_OVR(p->adc) != 0)
{
p->ovr_count++;
LL_ADC_REG_StopConversion(p->adc);
LL_DMA_DisableChannel(p->dma, p->dma_channel);
LL_DMA_SetDataLength(p->dma, p->dma_channel, p->adc_sum);
LL_DMA_SetPeriphAddress(p->dma, p->dma_channel, LL_ADC_DMA_GetRegAddr(p->adc, LL_ADC_DMA_REG_REGULAR_DATA));
LL_DMA_SetMemoryAddress(p->dma, p->dma_channel, (uint32_t)p->adc_value);
LL_DMA_EnableChannel(p->dma, p->dma_channel);
LL_ADC_ClearFlag_OVR(p->adc);
LL_ADC_ClearFlag_EOC(p->adc);
LL_ADC_REG_StartConversion(p->adc); // 开始转换
}
}
/**
* @brief 通过用户配置的通道号获取通道数量
* @param {uint32_t} channnels 存储数据所在的序列号
* @return {*}
* @note
*/
static uint8_t adc_get_channels_count(uint32_t channnels)
{
uint8_t ch_num = 0;
if (BIT_IS_SET(channnels, IN0))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN1))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN2))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN3))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN4))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN5))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN6))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN7))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN8))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN9))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN10))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN11))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN12))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN13))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN14))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN15))
{
ch_num++;
}
if (BIT_IS_SET(channnels, IN16))
{
ch_num++;
}
if (BIT_IS_SET(channnels, INVREF))
{
ch_num++;
}
if (BIT_IS_SET(channnels, INVBAT))
{
ch_num++;
}
if (BIT_IS_SET(channnels, INTEMP))
{
ch_num++;
}
return ch_num;
}