/** * @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; }