Заголовок сообщения: stm32f103 Dual mode ADC+DMA по таймеру4
Добавлено: Вт ноя 22, 2022 14:28:08
Встал на лапы
Зарегистрирован: Пт мар 19, 2021 08:58:45 Сообщений: 120
Рейтинг сообщения:0
Всем привет! с недавних пор решил потихоньку изучать STM32. И поставил себе задачу потренироваться в парном режиме измерения АЦП с запуском по таймеру. Частота измеряемого синусоидального сигнала 100Гц, 256 измерений на период входящего сигнала, исходил что 100Гц=10000uS, значит 10000/256 = 39,0625uS или 25600Гц. Конечно пользуюсь пока Кубом, в дальнейшем может перейду на Кейл. 1. Настройка Таймера4 Channel4 > Output Compare No Output Prescaler > 2187 (56000000/25600Гц=2187) Counter Period > 1 Mode > Toggle on match 2.Настройка АЦП. ADC1: - ADCs_Common_Settings > Dual regular simultaneous mode only - Выравнивание по правому краю - Extrernal Trigger ConversionMode > Timer 4 Capture Compare 4 event - ADC2 в таком случае подчинен ADC1. NVIC settings: ADC1 and ADC2 global interrupts галочка DMA settings: - ADC1 DMA1 Channel 1 - Mode>Normal и полное Word Вообщем в отладке я еще хоть как то могу первые значения обоих АЦП увидеть что они верные, а дальше почему то завышает(( что делаю не так? Спойлер
Код:
/* USER CODE BEGIN PV */ char trans_str[63] = {0,}; // буфер для UART1 volatile uint16_t adc[2] = {0,}; // переменные для АЦП volatile uint16_t adc1[NPT]; volatile uint16_t adc2[NPT]; volatile uint16_t cnt_NPT = 0; volatile uint8_t flag = 0; /* USER CODE END PV */
..........................................
/* USER CODE BEGIN 0 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance == ADC1 && !flag) { //Если преобразование закончено и флаг в основном цикле был сброшен if(cnt_NPT < NPT) { adc1[cnt_NPT] = adc[0]; //запомнили значения для первого канала АЦП1 adc2[cnt_NPT] = adc[1]; //запомнили значения для второго канала АЦП2 adc[0] = 0; //сбросили значения adc[1] = 0; //сбросили значения cnt_NPT++; } else {flag = 1; cnt_NPT = 0;} //ставим флаг что результат можно забирать } } /* USER CODE END 0 */ ..........................................
/* USER CODE BEGIN 2 */ HAL_ADCEx_Calibration_Start(&hadc1); //запуск автоматической самоккалибровки АЦП1 HAL_ADCEx_Calibration_Start(&hadc2); //запуск автоматической самоккалибровки АЦП2 HAL_ADC_Start(&hadc2); //запустить работу АЦП2 HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&adc, 1); //АЦП1 в мульти-режиме HAL_TIM_OC_Start(&htim4, TIM_CHANNEL_4); //запустить рабуту таймера 4 /* USER CODE END 2 */
/* USER CODE BEGIN WHILE */ while (1) { if(flag) //Если флаг 1, значит результат измерения АЦП1 и АЦП2 готов { flag = 0; for (uint16_t i=0; i<NPT; ){ snprintf(trans_str, 63, "%d %d %d\r\n", i, adc1[i], adc2[i]); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 35); i++; //инкрементируем после вывода инфы } //цикл пробежали, запускает АПЦ1 и АЦП2 //HAL_ADC_Start(&hadc2); //запустить работу АЦП2 //HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&adc, 1); //длина равна 1 так как в DMA указано целое «слово» }else{ //Если флаг 0, запускает АПЦ1 и АЦП2 //HAL_ADC_Start(&hadc2); //запустить работу АЦП2 //HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)&adc, 1); //длина равна 1 так как в DMA указано целое «слово» } /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ static void MX_ADC1_Init(void) {
Заголовок сообщения: Re: stm32f103 Dual mode ADC+DMA по таймеру4
Добавлено: Ср ноя 23, 2022 20:34:52
Встал на лапы
Зарегистрирован: Пт мар 19, 2021 08:58:45 Сообщений: 120
Рейтинг сообщения:0
a797945 писал(а):
Но очень вероятно, что ошибки нет и то что видите это реальность на f103
Неё... Пока без синусоиды, просто подал 3.3в через разные резисторы adc1 и adc2. И реальные значения ацп я знаю. Эти же значения только в первом измерении в массиве под номером [0], потом остальные 255 завышены, что в отладке смотришь массив измерений, что в уарте выводишь его. Завышены на много вместо 2700 выдаёт 3600. Потом код повторяется и тоже самое только первое измерение обоих каналов верно. Ну что постоянно калибровку делать?
камень старый в сети полно статей и примеров, что Вам мешает с ними повнимательнее ознакомится. расписано же когда нужен ОУ, какие номиналы RC цепочки на входе ацп, ... т.е. не обеспечена аппаратная часть. зачем счетчику для работы оставили только два такта - только шагнул и тут же сброс - зачем так? режим канала таймера Toggle ( т.е. переворачивание) - а значит на один период adc должно быть 2 периода таймера. если соотв. ногу настроить - можно проконтролировать, что период выдается правильный. период для измерения, сами насчитали, 39,0625uS - зачем в измерении ужиматься до 1мкс, примените 13.5 (12,5+13,5) т.е. время до следующей выборки остается (а так же может не понадобится ОУ). цифры если такт adc - 14МГц.
камень старый в сети полно статей и примеров, что Вам мешает с ними повнимательнее ознакомится. расписано же когда нужен ОУ, какие номиналы RC цепочки на входе ацп, ... т.е. не обеспечена аппаратная часть.
Поделитесь если у вас есть что в загашнике? может не совсем по тем примерам иду что нашёл! пока читаю книгу Освоение STM32. Я всегда рад пересмотреть свой подход!
сорри, но обучать я не могу - я не спец., у самого предостаточно пробелов в знаниях. да и моим путем идти не надо - цели профессионально осваивать МК себе не ставил, староват я для такой цели. режимом Dual regular simultaneous никогда не пользовался, кстати НАЛом то же. часть мыслей озвученных ранее - просто из здравого смысла, про другую часть можете почитать ну, например, здесь : https://dzen.ru/media/tdmlab/stm32-i-cu ... 055a94cb98 и в конце статьи достаточно ссылок на документы.
если что-то не получается - разбиваю задачу на более мелкие и проверяю так ли они работают, если где заткнусь ищу ответы или в черепной коробке или в статьях и документах.
зачем счетчику для работы оставили только два такта - только шагнул и тут же сброс - зачем так?
вы об этом куске кода? правильно вас понял? Спойлер
Код:
/* USER CODE BEGIN 0 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance == ADC1 && !flag) { //Если преобразование закончено и флаг в основном цикле был сброшен if(cnt_NPT < NPT) { adc1[cnt_NPT] = adc[0]; //запомнили значения для первого канала АЦП1 adc2[cnt_NPT] = adc[1]; //запомнили значения для второго канала АЦП2 adc[0] = 0; //сбросили значения adc[1] = 0; //сбросили значения cnt_NPT++; } else {flag = 1; cnt_NPT = 0;} //ставим флаг что результат можно забирать } } /* USER CODE END 0 */
период для измерения, сами насчитали, 39,0625uS - зачем в измерении ужиматься до 1мкс, примените 13.5 (12,5+13,5) т.е. время до следующей выборки остается (а так же может не понадобится ОУ). цифры если такт adc - 14МГц.
одна микросекунда поставил с заделом, к примеру - реализовать ДПФ алгоритм и там быстродействие важно все же с определение фазы. Но это пока взгляд на будущее где к примеру можно применить парный режим измерения.
"вы об этом куске кода?" нет, об этом: " htim4.Init.Prescaler = 2187; htim4.Init.Period = 1; " но портянку хала смотрел по "диагонали", он для меня непривычен.
используете быстрое преобразование 1,5 (12,5+1,5) - необходим буферный ОУ, по ссылкам расписано почему и когда нужен.
натыкался вчера на коды аналогичные вашей задаче - можете взять какой-нибудь за основу и поэтапно привести к нужному вам механизму. или проанализировать отличия и исправить ваш, обращая внимание на аппаратную составляющую.
нет пованговал за автора(извениет что влез) и привел пример, и мне тоже интересен это процесс опроса ацп в режиме dual. Для меня интересен алгоритм ДПФ и применение для него такого режима измерения ацп.
1.htim4.Init.Prescaler = 2187; htim4.Init.Period = 1; ................ 2.натыкался вчера на коды аналогичные вашей задаче - можете взять какой-нибудь за основу и поэтапно привести к нужному вам механизму. или проанализировать отличия и исправить ваш, обращая внимание на аппаратную составляющую.
1. это я начудил конечно, перечитал по таймерам, в моем случае желаемую частоту в 25600Гц(39,0625uS) получить нужно сделать так: Prescaler > 0 Counter Period > 2187 (56000000/25600Гц=2187)
2. в принципе так и делаю, по поводу аппаратной части тоже подтягиваю себя сейчас!
одна микросекунда поставил с заделом, к примеру - реализовать ДПФ алгоритм и там быстродействие важно все же с определение фазы. Но это пока взгляд на будущее где к примеру можно применить парный режим измерения.
Стесняюсь спросить, а зачем для ДПФ парный режим и какую фазу вы собрались определять с каким то там быстродействием? Для ДПФ всего то нужно выбрать частоту дискретизации с учетом потребного подавления неиспользуемых зон Найквиста. И всё. Фазовый спектр в ДПФ получается относительно синусно-косинусных базисов. Никакой "парности" измерений там не требуется.
kote52, вообще перевёл Халовский юзер мануал по ф103, то что касается парного ацп в мультирежиме, там прямым текстом написано что ведомый ацп2 останавливать HAL_ADC_Stop_IT(&hadc2); а у вас HAL_ADC_Stop(&hadc2); и закоментировано. Stop conversion and disable the ADC HAL_ADC_Stop_IT(&hadc2) (slave) using function HAL_ADC_Stop_IT() А стартует как у вас в коде в мульти режиме с ДМА ведомый HAL_ADC_Start();.
Фазовый спектр в ДПФ получается относительно синусно-косинусных базисов. Никакой "парности" измерений там не требуется.
не знаю что там имел ввиду там человек, но мы с вами в одной из тем говорил как то о дпф... я поднял старую ветку, вы отозвались... у меня вопрос сейчас в чем?... тогда если не парность, т.е. получается нужно как то одновременно синхронизировать DAC и ADC, что бы минимизировать тот промежуток времени который может возникнуть между началом работы DAC и началом измерения ADC? Сэмплировать и DAC и оба ADC от одного таймера одной частоты? так получается? И можете объяснить почему не важно "с каким то там быстродействием?" По другому сформулирую от себя, т.е. 1uS время преобразования ADС у STM32 или 13uS у Atmega, роли не сыграют?
Основным принципом при выборе частоты дискретизации является верхняя частота спектра входного сигнала и требования к антиалиасингу. Поскольку у ЦАПа нет времени преобразования, а есть время переходного процесса и оно зависит от перепада входного кода, то выводить в ЦАП можно по завершении преобразования АЦП и без таймера. Только непонятно зачем весь этот перфоманс? А если имеется обработка перед выводом, то время преобразования перестает быть значимым. Ну и потребуется семплировать ЦАП от таймера.
Заголовок сообщения: Re: stm32f103 Dual mode ADC+DMA по таймеру4
Добавлено: Вс дек 04, 2022 15:15:26
Встал на лапы
Зарегистрирован: Пт мар 19, 2021 08:58:45 Сообщений: 120
Рейтинг сообщения:0
КРАМ писал(а):
Только непонятно зачем весь этот перфоманс? А если имеется обработка перед выводом, то время преобразования перестает быть значимым. Ну и потребуется семплировать ЦАП от таймера.
да какой тут перфоманс?)) я пытаюсь нащупать как делать правильно что изложил в начале темы - "измерения АЦП с запуском по таймеру. Частота измеряемого синусоидального сигнала 100Гц, 256 измерений на период входящего сигнала". И тут в принципе парный режим может вообще не нужен, ну хотя бы я его худо бедно покрутил и получилось. Научился сейчас запускать то таймеру и получил массив из 256 измерений на частое 25,6кГц. Единственное что мне не нравится, я сразу забираю из ДМА результат после каждого преобразовании АЦП, а можно сделать весь массив заполнился и только потом... или еще - набрать к примеру 100 таких массивом(но в этом я пока не уверен возможно ли ) и потом забрать из ДМА для обработки.
А зачем ДМА, если вы забираете каждое измерение? Вообще то нужно при каждом запуске сессии ДМА, если речь идет о one shot mode, ставить нужное значение в счетчик ДМА. Или однократно, если речь идет о continuous mode. Тогда прерывание по ДМА возникнет либо по завершении транзакций по всему массиву, либо по каждой половине - зависит от разрешений.
Частота измеряемого синусоидального сигнала 100Гц, 256 измерений на период входящего сигнала.
Что вы хотите измерить у синусоидального сигнала при такой высокой частоте дискретизации? Даже при 16 выборках за период антиалиасинговый фильтр будет очень простым и вы получите амплитуду и фазу сигнала с хорошей точностью. Если нет опасности получить паразитный сигнал на частотах 2-й и выше зон Найквиста, то достаточно и удобно иметь ровно 4 выборки на период. Вообще то хватит и БОЛЕЕ, чем двух.
Что вы хотите измерить у синусоидального сигнала при такой высокой частоте дискретизации? Даже при 16 выборках за период антиалиасинговый фильтр будет очень простым и вы получите амплитуду и фазу сигнала с хорошей точностью. Если нет опасности получить паразитный сигнал на частотах 2-й и выше зон Найквиста, то достаточно и удобно иметь ровно 4 выборки на период. Вообще то хватит и БОЛЕЕ, чем двух.
да ни чего не измеряю, поставил себе задачу, все опять же из первого моего сообщения, вот. Задача то более чем интересная, что мне общие примеры с ацп и дма. В такой задаче есть что покрутить и увидеть в работе на практике. Тут нет каких-то измерений чего-то или проектирования чего-то... то что раньше о ДПФ спрашивал, возможно эти знания применить в ДПФ и там обработки сигнала какого-то... но пока просто учусь. Ну вы же видете я плаваю в обычной теории и почти ни чего не знаю.
Вот я вам в контексте ДПФ/БПФ и ответил. 100 выборок за период - это оверсемплинг. Его обычно применяют для увеличения разрядности АЦП. При сохранении разрядности в оверсемплинге нет никакого смысла и выбор частоты дискретизации производится на основании требований к антиалиасинговому фильтру ПЕРЕД АЦП. Вторая зона Найквиста (первый зеркальный диапазон частот) лежит между половиной частоты дискретизации и частотой дискретизации. Сигнал оказавшейся в этой зоне будет отражен в первую, то есть вы не сможете его отличить от сигнала в первой зоне. Поэтому нужно делать ФНЧ на входе АЦП, который подавит сигнал на половине частоты дискретизации и выше нее на величину динамического диапазона АЦП, то есть сигнал в паразитных зонах (второй и выше) будет лежать ниже шума квантования. Однако, если качество УВХ в АЦП (так называемая апертура или полоса пропускания) позволяют, то можно работать в режиме даунсемплинга (стробоскопическом). И тогда на входе ставят ПОЛОСОВОЙ фильтр вырезающий необходимую зону Найквиста выше первой.
Вообще то нужно при каждом запуске сессии ДМА, если речь идет о one shot mode, ставить нужное значение в счетчик ДМА. Или однократно, если речь идет о continuous mode. Тогда прерывание по ДМА возникнет либо по завершении транзакций по всему массиву, либо по каждой половине - зависит от разрешений.
Все вас в ДПФ уводит, оставьте его в покое... лучше вернемся к проблеме с кодом! можно как то подробнее о счетчике, куда именно поставить...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения