/*============================================================================== * Инициализация АЦП с использованием бибилотеки PLIB035 *------------------------------------------------------------------------------ * ЦНИИ СЭТ, Разваляев Алексей *============================================================================== * ЦНИИ СЭТ *============================================================================== */ //-- 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) //{ //}