437 lines
14 KiB
C
437 lines
14 KiB
C
/*==============================================================================
|
||
* Инициализация АЦП с использованием бибилотеки 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)
|
||
//{
|
||
//}
|