This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/system/bsp/adcs.c

400 lines
10 KiB
C
Raw 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 "sys.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 ADC通道
* @return {*}
* @note TCONV(转换时间) = (采样时间 + 12.5 个周期)/(主频/ADC分频系数)
*/
void adc_init(adcs_e num, ADC_TypeDef *adc, DMA_TypeDef *dma, uint32_t dma_channel, uint8_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);
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 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(p->adc_value);
#else
osel_mem_free(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 ADC通道
* @return {*}
* @note
*/
uint16_t adc_result_median_average(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);
uint16_t adc_temp[p->adc_cct];
uint32_t adc_sum = 0;
for (uint8_t i = 0; i < p->adc_cct; i++)
{
adc_temp[i] = p->adc_value[i * p->adc_chans_count + chan];
}
quicksort(adc_temp, 0, p->adc_cct - 1);
for (uint8_t i = 0; i < p->adc_cct; i++) // 遍历所有ADC通道
{
adc_sum += adc_temp[i]; // 将每个ADC通道的数据累加到adc_sum中
}
res = adc_sum / p->adc_cct;
return res;
}
/**
* @brief 中位值滤波,获取ADC转换结果
* @param {adcs_e} num ADC编号
* @param {uint8_t} chan ADC通道
* @return {*}
* @note
*/
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];
uint16_t adc_temp[p->adc_cct];
for (uint8_t i = 0; i < p->adc_cct; i++)
{
adc_temp[i] = p->adc_value[i * p->adc_chans_count + chan];
}
// 使用快速排序
quicksort(adc_temp, 0, p->adc_cct - 1);
res = adc_temp[p->adc_cct / 2];
return res;
}
/**
* @brief 平均值,获取ADC转换结果
* @param {adcs_e} num ADC编号
* @param {uint8_t} chan ADC通道
* @return {*}
* @note
*/
uint16_t adc_result_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);
DBG_ASSERT(p->adc_cct != 0 __DBG_LINE); // 避免除以零的错误
uint32_t adc_sum = 0;
uint16_t(*gram)[p->adc_chans_count] = (uint16_t(*)[p->adc_chans_count])p->adc_value;
for (uint8_t i = 0; i < p->adc_cct; i++)
{
uint32_t next_sum = adc_sum + gram[i][chan];
DBG_ASSERT(next_sum >= adc_sum __DBG_LINE); // 避免溢出
adc_sum = next_sum;
}
return adc_sum / p->adc_cct;
}
/**
* @brief N次平均值,获取ADC转换结果
* @param {adcs_e} num ADC编号
* @param {uint8_t} chan ADC通道
* @return {*}
* @note
*/
uint16_t adc_result_n_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);
uint16_t adc_temp[p->adc_cct];
uint8_t n = p->adc_cct / 4;
uint8_t count = p->adc_cct > (2 * n) ? n : 0;
for (uint8_t i = 0; i < p->adc_cct; i++)
{
adc_temp[i] = p->adc_value[i * p->adc_chans_count + chan];
}
quicksort(adc_temp, 0, p->adc_cct - 1);
for (uint8_t i = count; i < p->adc_cct - count; i++)
{
adc_sum += adc_temp[i];
}
res = adc_sum / (p->adc_cct - 2 * count);
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
*/
int32_t adc_result_temperature(uint16_t adc_value)
{
#define TEMP130_CAL_ADDR ((uint16_t *)((uint32_t)0x1FF8007E))
#define TEMP30_CAL_ADDR ((uint16_t *)((uint32_t)0x1FF8007A))
#define VDD_CALIB ((uint16_t)(300))
#define VDD_APPLI ((uint16_t)(330))
int32_t res;
res = ((adc_value * VDD_APPLI / VDD_CALIB) -
(int32_t)*TEMP30_CAL_ADDR);
res = res * (int32_t)(130 - 30);
res = res / (int32_t)(*TEMP130_CAL_ADDR -
*TEMP30_CAL_ADDR);
res = res + 30;
return res;
}
/**
* @brief 计算内部电压
* @param {uint16_t} adc_value ADC转换结果
* @return {*}
* @note
*/
int32_t adc_result_value_local(uint16_t adc_value)
{
return (1224.0 / adc_value) * 4096;
}
/**
* @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 ADC通道
* @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, INVREF))
{
ch_num++;
}
if (BIT_IS_SET(channnels, INTEMP))
{
ch_num++;
}
return ch_num;
}