Files
VK035_Template/Core/App/adc.c
Razvalyaev c7fdf6776f Добавлен ADC SEQ (заготовка пока)
И небольшой рефакторинг
2025-12-26 18:45:23 +03:00

437 lines
14 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.
/*==============================================================================
* Инициализация АЦП с использованием бибилотеки PLIB035
*------------------------------------------------------------------------------
* ЦНИИ СЭТ, Разваляев Алексей <wot890089@mail.ru>
*==============================================================================
* ЦНИИ СЭТ
*==============================================================================
*/
//-- Includes ------------------------------------------------------------------
#include "periph_config.h"
ADC_HandleTypeDef hadc;
//-- Defines -------------------------------------------------------------------
//-- Peripheral init functions -------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////SEQUENCORS/////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void adc_init_first(void)
{
#if (USE_ADC_SEQ0==1) || (USE_ADC_SEQ1==1) || (USE_ADC_DC0==1) || (USE_ADC_DC1==1) || (USE_ADC_DC2==1) || (USE_ADC_DC3==1)
// Настройка тактирования
if(rcu_set_clock_adc(ADC_ClockSource, ADC_ClockMHz, ENABLE) != OK)
{
Error_Handler();
}
RCU_ADCRstCmd(ENABLE);
// Включаем аналоговый модуль
ADC_AM_Cmd(ENABLE);
hadc.Instance = ADC;
#endif
#if (USE_ADC_SEQ0==1)
adc_seq_init(&hadc, ADC_SEQ_Num_0, &adc_seq0_config);
if(hadc.SEQ[ADC_SEQ_Num_0].Config->IT == ENABLE)
{
NVIC_EnableIRQ(ADC_SEQ0_IRQn);
}
#endif
#if (USE_ADC_SEQ1==1)
adc_seq_init(&hadc, ADC_SEQ_Num_1, &adc_seq1_config);
if(hadc.SEQ_Config[ADC_SEQ_Num_1]->IT == ENABLE)
{
NVIC_EnableIRQ(ADC_SEQ1_IRQn);
}
#endif
#if (USE_ADC_DC0==1)
#endif
#if (USE_ADC_DC1==1)
#endif
#if (USE_ADC_DC2==1)
#endif
#if (USE_ADC_DC3==1)
#endif
#if (USE_ADC_SEQ0==1) || (USE_ADC_SEQ1==1) || (USE_ADC_DC0==1) || (USE_ADC_DC1==1) || (USE_ADC_DC2==1) || (USE_ADC_DC3==1)
uint32_t starttick = millis();
while (!ADC_AM_ReadyStatus()) {
if((millis() - starttick) > 1000)
Error_Handler();
}
#endif
}
/**
* @brief Инициализация секвенсора АЦП
* @param hadc указатель на хендл АЦП
* @param SEQ_Num номер секвенсора
* @param NewConfig указатель на новую конфигурацию ADC, иначе используется та, что в структуре
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
*/
OperationStatus adc_seq_init(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_SEQ_ExtInit_TypeDef *NewConfig)
{
if(!hadc || !hadc->Instance)
return ERROR;
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
if(NewConfig != NULL)
{
hseq->Config = NewConfig;
}
if(hseq->Config == NULL)
{
return ERROR;
}
ADC_SEQ_Init(SEQ_Num, &hseq->Config->SEQ_Init);
return OK;
}
/**
* @brief Установка коллбека секвенсора АЦП
* @param hadc указатель на хендл АЦП
* @param cb_type Тип коллбека
* @param Callback Функция коллбека
* @retval void
*/
OperationStatus adc_seq_set_callback(ADC_HandleTypeDef* hadc, ADC_SEQ_Num_TypeDef SEQ_Num, ADC_CallbackTypeDef cb_type, void (*Callback)(void))
{
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
return ERROR;
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
switch(cb_type)
{
case ADC_Callback_Seq:
hseq->Config->SEQCpltCallback = Callback;
break;
case ADC_Callback_Error:
hseq->Config->ErrorCallback = Callback;
break;
case ADC_Callback_BuffFull:
hseq->Config->BuffFullCallback = Callback;
break;
case ADC_Callback_BuffHalf:
hseq->Config->BuffFullCallback = Callback;
break;
default:
return ERROR;
}
return OK;
}
/**
* @brief Запуск секвенсора АЦП с буфером
* @param hadc указатель на хендл АЦП
* @param SEQ_Num номер секвенсора
* @param data_buffer указатель на буфер данных [ch][buffer_size] или NULL
* @param buffer_size размер буфера для каждого канала (0 если буфер не используется)
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
*/
OperationStatus adc_seq_start(ADC_HandleTypeDef *hadc,
ADC_SEQ_Num_TypeDef SEQ_Num,
uint16_t (*data_buffer)[],
uint32_t buffer_size)
{
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
return ERROR;
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
ADC_SEQ_ExtInit_TypeDef *conf = hseq->Config;
// Сохраняем буферные параметры
hseq->data_buffer = (uint16_t *)data_buffer;
hseq->buffer_size = buffer_size;
hseq->buffer_count = 0; // Сбрасываем счетчик
// Настраиваем прерывания если нужно
if (conf->IT == ENABLE)
{
ADC_SEQ_ITConfig(SEQ_Num, conf->ITCount, DISABLE);
ADC_SEQ_ITCmd(SEQ_Num, ENABLE);
}
// Включаем секвенсор
ADC_SEQ_Cmd(SEQ_Num, ENABLE);
// Помечаем как запущенный
hseq->running = 1;
return OK;
}
/**
* @brief Остановка секвенсора АЦП
* @param hadc указатель на хендл АЦП
* @param SEQ_Num номер секвенсора
* @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
*/
OperationStatus adc_seq_stop(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
{
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
return ERROR;
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
// Выключаем секвенсор
ADC_SEQ_Cmd(SEQ_Num, DISABLE);
// Выключаем прерывания
ADC_SEQ_ITCmd(SEQ_Num, DISABLE);
// Сбрасываем флаг запуска
hseq->running = 1;
return OK;
}
/**
* @brief Получение текущего значения канала
* @param hadc указатель на хендл АЦП
* @param channel номер канала
* @retval значение ADC (0 если данные невалидны)
*/
uint16_t adc_get_channel_value(ADC_HandleTypeDef *hadc, ADC_CH_Num_TypeDef channel)
{
if (!hadc || channel >= ADC_CH_Total)
return 0;
if (hadc->ChannelValid[channel])
{
return hadc->ChannelData[channel];
}
return 0;
}
/**
* @brief Программный запуск преобразования
*/
void adc_sw_start(void)
{
ADC_SEQ_SwStartCmd();
}
/**
* @brief Обработчик прерываний секвенсора
* @param hadc указатель на хендл АЦП
* @param SEQ_Num номер секвенсора
* @retval void
*/
void adc_seq_handler(ADC_HandleTypeDef *hadc, ADC_SEQ_Num_TypeDef SEQ_Num)
{
if (!hadc || !hadc->Instance || !hadc->SEQ[SEQ_Num].Config)
return;
ADC_SEQ_HandleTypeDef *hseq = &hadc->SEQ[SEQ_Num];
ADC_SEQ_ExtInit_TypeDef *conf = hseq->Config;
// Проверяем флаг прерывания
if (ADC_SEQ_ITMaskedStatus(SEQ_Num) == SET)
{
// Очищаем флаг
ADC_SEQ_ITStatusClear(SEQ_Num);
// Последний запрос в секвенсоре
ADC_SEQ_ReqNum_TypeDef last_request = conf->SEQ_Init.ReqMax;
// Читаем все доступные данные из FIFO
uint8_t channels_processed = 0;
while (ADC_SEQ_GetFIFOLoad(ADC_SEQ_Num_0))
{
uint32_t data = ADC_SEQ_GetFIFOData(SEQ_Num);
ADC_SEQ_ReqNum_TypeDef req_num = ADC_SEQ_GetReqCurrent(SEQ_Num);
if (req_num < ADC_SEQ_Req_Total)
{
ADC_CH_Num_TypeDef channel = conf->SEQ_Init.Req[req_num];
if (channel < ADC_CH_Total)
{
// 1. Обновляем текущее значение
hadc->ChannelData[channel] = (uint16_t)data;
hadc->ChannelValid[channel] = 1;
// 2. Записываем в буфер если он есть
if (hseq->data_buffer &&
hseq->buffer_size > 0)
{
// Вычисляем offset для [ch][buffer_size]
uint32_t offset = channel * hseq->buffer_size +
hseq->buffer_count;
hseq->data_buffer[offset] = (uint16_t)data;
}
channels_processed++;
// Если это последний канал в секвенсоре - увеличиваем счетчик буфера
if (req_num == last_request)
{
hseq->buffer_count++;
if(hseq->buffer_count == hseq->buffer_size/2)
{
if (conf->BuffHalfCallback)
{
conf->BuffHalfCallback();
}
}
if(hseq->buffer_count >= hseq->buffer_size)
{
// Кольцевой буфер
if(conf->buffer_circular)
hseq->buffer_count = 0;
else
adc_seq_stop(hadc, SEQ_Num);
if (conf->BuffFullCallback)
{
conf->BuffFullCallback();
}
}
}
}
}
}
// Вызываем коллбек пользователя
if (conf->SEQCpltCallback)
{
conf->SEQCpltCallback();
}
}
// Обработка ошибок
if (ADC_SEQ_DMAErrorStatus(SEQ_Num) == SET)
{
ADC_SEQ_DMAErrorStatusClear(SEQ_Num);
if (conf->ErrorCallback)
{
conf->ErrorCallback();
}
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////DIGITAL COMPARATORS/////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///**
// * @brief Инициализация цифрового компаратора АЦП
// * @param hadc указатель на хендл АЦП
// * @param DC_Num номер компаратора
// * @param NewConfig указатель на конфигурацию
// * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
// */
//OperationStatus adc_dc_init(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num, ADC_DC_ExtInit_TypeDef *NewConfig)
//{
// if(!hadc || !hadc->Instance)
// return ERROR;
//
// if(NewConfig != NULL)
// {
// hadc->DC_Config[DC_Num] = NewConfig;
// }
//
// if(hadc->DC_Config[DC_Num] == NULL)
// {
// return ERROR;
// }
//
// // Инициализация компаратора
// ADC_DC_Init(DC_Num, &hadc->DC_Config[DC_Num]->DC_Init);
//
// return OK;
//}
///**
// * @brief Установка коллбека цифрового компаратора АЦП
// * @param hadc указатель на хендл АЦП
// * @param DC_Num номер компаратора
// * @param cb_type тип коллбека
// * @param Callback функция коллбека
// * @retval OperationStatus
// */
//OperationStatus adc_dc_set_callback(ADC_HandleTypeDef* hadc, ADC_DC_Num_TypeDef DC_Num, ADC_CallbackTypeDef cb_type, void (*Callback)(void))
//{
// if (!hadc || !hadc->Instance || !hadc->DC_Config[DC_Num])
// return ERROR;
//
// switch(cb_type)
// {
// case ADC_Callback_DC:
// hadc->DC_Config[DC_Num]->DC_TrigCallback = Callback;
// break;
// case ADC_Callback_Error:
// hadc->DC_Config[DC_Num]->ErrorCallback = Callback;
// break;
// default:
// return ERROR;
// }
// return OK;
//}
///**
// * @brief Запуск цифрового компаратора АЦП
// * @param hadc указатель на хендл АЦП
// * @param DC_Num номер компаратора
// * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
// */
//OperationStatus adc_dc_start(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num)
//{
// if (!hadc || !hadc->Instance || !hadc->DC_Config[DC_Num])
// return ERROR;
//
// ADC_DC_ExtInit_TypeDef *conf = hadc->DC_Config[DC_Num];
//
// // Включаем выход компаратора
// ADC_DC_OutputCmd(DC_Num, ENABLE);
//
// // Настраиваем прерывания если нужно
// if(conf->IT == ENABLE)
// {
// ADC_DC_ITCmd(DC_Num, ENABLE);
// }
//
// return OK;
//}
///**
// * @brief Остановка цифрового компаратора АЦП
// * @param hadc указатель на хендл АЦП
// * @param DC_Num номер компаратора
// * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
// */
//OperationStatus adc_dc_stop(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num)
//{
// if (!hadc || !hadc->Instance || !hadc->DC_Config[DC_Num])
// return ERROR;
//
// // Выключаем выход компаратора
// ADC_DC_OutputCmd(DC_Num, DISABLE);
//
// // Выключаем прерывания
// ADC_DC_ITCmd(DC_Num, DISABLE);
//
// return OK;
//}
//void adc_dc_handler(ADC_HandleTypeDef *hadc, ADC_DC_Num_TypeDef DC_Num)
//{
//}