Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

STM32F303 запуск АЦП для измерения 6 токов

Пн дек 14, 2015 22:04:12

Столкнулись с проблемой и пока не одолели ее.
Есть 6 датчиков тока для двух трехканальных преобразователя напряжения. Мы ими управляем ШИМ сделанных на двух таймерах, у каждого таймера используется три верхних и нижних ключа.
АЦП тактируется от таймера 6, так что при снятии сигнала ШИМ с фазы, мы запускаем канал АЦП и оцифровываем сигнал с датчика тока.
Проблема в том, что при каждом новом такте нам нужно опрашивать новый канал АЦП.
Для этого задали по рангу опрос каналов - 6 шт. Которые должны поидее при приходе каждого нового тактового импульса от таймера 6 опрашиватся каждый в свой тактовый импульс.
Но вот этого не происходит.
Ставим режим ADC_Mode_Independent вроде другой не подходит.
ADC_RegularChannelConfig(ADC1, 2, 1, ADC_SampleTime_7Cycles5); данной функцией выбираем 6 каналов с рангом от 1 до 6.
ADC_ContinuousConvMode_Disable - преобразование ставим одиночное
NbrOfRegChannel = 6;
В итоге при запуске АЦП от триггера быстренько преобразовывает 6 каналов и вываливается в прерывание по ДМА. Но нам такое не нужно!
Надо чтобы при каждом запуске преобразовывал один канал, при следующем запуске - другой.
Ставили NbrOfRegChannel = 1; - он преобразует только первый канал.
Хотя вот пишут, что есть биты, которые
Как видим, каналы можно опрашивать в любой последовательности. Любой канал можно опрашивать несколько раз. Задаешь список, по которому опрашивать каналы, и все.

Количество каналов в этом списке задается разрядами L[3:0] регистра SQR1 .

но вот как эти биты запрограммировать???
И правильно ли мы текст понимаем?

Кто-то с таким сталкивался???
Подскажите?
Если надо код выложу.

Re: STM32F303 запуск АЦП для измерения 6 токов

Вт дек 15, 2015 12:50:12

победили. Два бита надо было инициализировать. Нашли наконец-то функции.
Вот теперь чтобы усовершенствовать программу есть такая задача:
Выдача 3-х фазного ШИМ (треугольный). Для этого регистры сравнения надо обновлять по прерываниям по переполнению моментально.
Это возможно при использовании ДМА.
Смогли настроить два канала ДМА. И выдавать в два регистра сравнения.
Но вот в третий никак не получается.
Запуск каналов ДМА идет по одному событию - переполнение, второго по сравнения регистра ССR4.
можно было бы помудрить и с запуском по триггеру, но не удается пока. Кому код нужен - пишете кину.
Просто запуск второго канала ДМА идет как по сравнению, так и по триггеру.

Re: STM32F303 запуск АЦП для измерения 6 токов

Вт дек 15, 2015 12:53:37

А в сторону DMAR смотрели?

Re: STM32F303 запуск АЦП для измерения 6 токов

Пт дек 18, 2015 07:45:40

Нет не смотрели.
Глянули, но пока как сделать толком не поняли.
Сможете просветить?!
Заранее спасибо!

Re: STM32F303 запуск АЦП для измерения 6 токов

Пт дек 18, 2015 09:03:56

Да там всё просто. Настраивается таймер. Разрешается работа ДМА в DIER таймера. Настраивается DCR таймера где указывается начальный адрес регистра таймера и количество регистров которые нужно заполнять. Дальше настраивается ДМА. Адрес периферии это TIMx->DMAR. Остальное как обычно. По событию таймера ДМА перебросит значения из таблицы в памяти в регистры таймера с адреса и в количестве которые были указаны в DCR.

Re: STM32F303 запуск АЦП для измерения 6 токов

Чт дек 31, 2015 11:38:33

Вроде нашел данный режим в литературе - называется вспышка ДМА.
Но чтобы работал как как мне нужно - не получается!
Задание массива
unsigned int PWMArr1[9] =
{1200, 60, 1200,
1200, 1200, 60,
60, 1200, 1200}; // массив для формирования скважности по прерываниям таймера 1

Инициализация Таймера
static void TIM_Configuration(PWMDRV_InitTypeDef* pwm) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;

// Настроим Таймер ШИМ-драйвера
//
// 1. Настроим двоичный делитель тактирующей частоты
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 2. Настроим поглощающий счетчик счетных импульсов
TIM_TimeBaseStructure.TIM_Prescaler = 0; // почему было 0???
// 3. Активируем режим реверсивного счёта (inc/dec)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
// 4. Установим максимальное число для счёта
TIM_TimeBaseStructure.TIM_Period = pwm->PeriodMax-0;
// 5. Настроим поглощающий прерывания счетчик реверсов
TIM_TimeBaseStructure.TIM_RepetitionCounter = 1 - 1;
// и как ... сконфигурируем!
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);


// Настроим выходы каналов Захвата / Сравнения таймера
//
// 1. Установим режим сравнения CCR >= CNT или CCR <= CNT
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM1
// 2. Активируем выход OCx Регистра Сравнения (верхний ключ)
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 3. Активируем выход OCNx Регистра Сравнения (нижний ключ)
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
// 4. Установим полярность сигнала OCx для верхнего ключа
TIM_OCInitStructure.TIM_OCPolarity = pwm->CnfgReg.bit.SW_H_Polarity
? TIM_OCPolarity_High : TIM_OCPolarity_Low;
// 5. Установим полярность сигнала OCNx для нижнего ключа
TIM_OCInitStructure.TIM_OCNPolarity = pwm->CnfgReg.bit.SW_L_Polarity
? TIM_OCNPolarity_High : TIM_OCNPolarity_Low;
// 6. Определим состояние выходов OCx для IDLE режима
TIM_OCInitStructure.TIM_OCIdleState = pwm->CnfgReg.bit.SW_H_IdleState
? TIM_OCIdleState_Set : TIM_OCIdleState_Reset;
// 7. Определим состояние выходов OCNx для IDLE режима
TIM_OCInitStructure.TIM_OCNIdleState = pwm->CnfgReg.bit.SW_L_IdleState
? TIM_OCNIdleState_Set : TIM_OCNIdleState_Reset;
// Установим число в Регистра Сравнения = половину от ARR
TIM_OCInitStructure.TIM_Pulse = pwm->HalfPerMax;
// TIM1, 8: Конфигурируем каналы
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OC1Init(TIM8, &TIM_OCInitStructure);
TIM_OC2Init(TIM8, &TIM_OCInitStructure);
TIM_OC3Init(TIM8, &TIM_OCInitStructure);


// Настроим защиту моста (ST.com: DM00080497.pdf DM00042534.pdf)
//
// 1. Определим величину бестоковой паузы
TIM_BDTRInitStructure.TIM_DeadTime = pwm->Deadband;
// 2. [Де]Активируем Компаратор Защиты
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
// 3. Укажем активный уровень для Компаратора Защиты
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
// 4. Установим уровень срабатывания Компаратора Защиты
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
// 5. Не используем однотактный режим управления мостом (Run-режим)
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
// 6. Не отключаем таймер от выходов при выключении ШИМ-а (Idle-режим)
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
// 7. Не используем автоматическое включение после срабатывания защиты
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
// и как ... сконфигурируем!
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
TIM_BDTRConfig(TIM8, &TIM_BDTRInitStructure);


TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM8, ENABLE);
// TIM1: прерывания по переполнению
//TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
// TIM8: прерывания по переполнению
TIM_ITConfig(TIM8, TIM_IT_Update, ENABLE);

//Начальное значение счетчика обеспечивающего фазовый сдвиг на 180 градусов
TIM_SetCounter(TIM8, pwm->PeriodMax-1); //

//Конфигурация для таймера синхронизации АПЦ1

// 1. Настроим двоичный делитель тактирующей частоты
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 2. Настроим поглощающий счетчик счетных импульсов
TIM_TimeBaseStructure.TIM_Prescaler = 0; // почему было 0???
// 3. Активируем режим реверсивного счёта (inc/dec)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 4. Установим максимальное число для счёта
TIM_TimeBaseStructure.TIM_Period = pwm->PeriodMax-1;
// 5. Настроим поглощающий прерывания счетчик реверсов
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// и как ... сконфигурируем!
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

// TIM6: Подаем на Триггер Событий (TRGO) сигнал обновления
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
// TIM6: прерывания по переполнению
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);

//включение ДМА по переполнению таймера 1
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
// указание места записи для ДМА и количество записываемых байт за раз
TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_3Transfers);

Инициализация ДМА
// Настроим контроллер ПДП для обслуживания TIM1_CH1
DMA_DeInit(DMA1_Channel5);
// Укажем адрес периферийного устройства (УВВ) т.е. АЦП
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &TIM1->DMAR;
// Укажем адрес массива в ОЗУ (для результатов преобразования)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &PWMArr1;
// Укажем направление передачи данных: из ОЗУ в TIM1_CCR1
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
// Укажем размер массива для результатов преобразования
DMA_InitStructure.DMA_BufferSize = 9; //3
// Укажем, что адрес TIM1_CH1 инкрементировать не нужно
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// Укажем, что адрес в ОЗУ необходимо инкрементировать
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// Укажем размер данных по указанному адресу периферии
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
// Укажем размер данных по указанному адресу в ОЗУ
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
// Укажем режим кольцевого буфера для канала ПДП
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// DMA_Mode_Normal; //
// Установим приоритет для канала ПДП
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// Укажем, что канал не используется для передачи данных из ОЗУ в ОЗУ
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// Инициализируем канал контроллера ПДП
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
// Сбрасываем флаг прерывания по завершению передачи
DMA_ClearFlag(DMA1_FLAG_TC5);
// Разрешаем прерывание по завершению передачи
//DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
// Включаем канал контроллера ПДП
DMA_Cmd(DMA1_Channel5, ENABLE);

Вроде переписывает данные из массива в регистры сравнения, но как-то не так.
Должен поидее по 3 ячейки памяти в три регистра сравнения, потом еще три, и еще три, а потом с самого начала.
unsigned int PWMArr1[9] =
{1200, 60, 1200,
1200, 1200, 60,
60, 1200, 1200};
На первом шаге д.б.
ССR1=1200
CCR2=60
CCR3=1200
На втором шаге д.б.
ССR1=1200
CCR2=1200
CCR3=60
На третьем шаге д.б.
ССR1=60
CCR2=1200
CCR3=1200

А получается примерно так - переписал ячейки из массива, но в какой-то произвольной последовательности
То так
ССR1=1200
CCR2=1200
CCR3=1200
То так
ССR1=1200
CCR2=60
CCR3=60
и т.д.
Когда верно, когда нет.

Не могу понять в чем дело!

Re: STM32F303 запуск АЦП для измерения 6 токов

Вс янв 03, 2016 14:53:40

pos13 писал(а):То так
То так

Попробуйте настроить таймеры для остановки при отладке и посмотреть в чем дело.
DBG_TIM8_STOP
DBG_TIM1_STOP биты

Тогда в отладчике можно посмотреть, что происходит. Вы в отладчике видите состояние на момент просмотра регистров, но таймер постоянно идет, и этот момент может соответствовать любому состоянию таймера. Конечно силовые ключи нужно отключить, а то ведь таймеры будут остановлены вместе с процессором.
При отладке таймеров есть еще один момент. Таймеру все равно, кто прочитает регистры, процессор или отладчик. Это касается тех флагов что сбрасываются при чтении какого либо регистра.

Re: STM32F303 запуск АЦП для измерения 6 токов

Вс янв 03, 2016 16:16:44

Galizin писал(а):Попробуйте настроить таймеры для остановки при отладке и посмотреть в чем дело.
........
Конечно силовые ключи нужно отключить, а то ведь таймеры будут остановлены вместе с процессором.
........
При отладке таймеров есть еще один момент. Таймеру все равно, кто прочитает регистры, процессор или отладчик. Это касается тех флагов что сбрасываются при чтении какого либо регистра.

Всё это чревато и безнадёжно... Взять другую плату... без ключей и прочего... даже можно с другим МК... подключить логанализатор... обрезать текст проги до минимума... и гонять её с нуля как обычно без всяких там тормозов... Там всё дело в правильных настройках... ну и понимании принципа... А всякие там попытки извращения... это сродни футболу по минному полю...

Re: STM32F303 запуск АЦП для измерения 6 токов

Пн янв 04, 2016 12:57:23

HHIMERA писал(а):Всё это чревато и безнадёжно
- излишнее обобщение
HHIMERA писал(а):подключить логанализатор
можно и так судить о содержимом регистров таймера.
Обратите внимание на Bit OC1PE: Output Compare 1 preload enable. Это даст фору во времени.

Re: STM32F303 запуск АЦП для измерения 6 токов

Пн янв 04, 2016 13:54:36

Galizin писал(а):излишнее обобщение

Может быть...
можно и так судить о содержимом регистров таймера.

ИМХО это самый правильный и надёжный вариант... всё происходит в реальном времени и ничто ничему не мешает...
Обратите внимание на Bit OC1PE: Output Compare 1 preload enable. Это даст фору во времени.

Если это мне... то спасибо, я в курсе... Я очень активно применяю таймера и ДМА...
Вот пример применения DMAR в многоканальном 1-wire... хардварная реализация... На 7-ом канале висит датчик... на остальных пусто... На 6-ом диаграмма чтения порта на предмет состояния шин всех датчиков...
Вложения
TIM_DMAR.png
(99.13 KiB) Скачиваний: 810

Re: STM32F303 запуск АЦП для измерения 6 токов

Пт янв 08, 2016 10:37:12

Еще раз все проверил.
Неправильно работали таймеры в предыдущем проекте.
Поменял в действующем, рабочем в итоге все сразу заработало и так, как надо.
Вот это добавил и все работает. А таймер действительно показывает содержимое регистров в разный момент времени.

//включение ДМА по переполнению таймера 1
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
// указание места записи для ДМА и количество записываемых байт за раз
TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_3Transfers);

// Укажем адрес периферийного устройства (УВВ) т.е. TIM1
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &TIM1->DMAR;

Так что в предыдущем моем коде все было правильно, просто где-то не так работали таймеры.

Re: STM32F303 запуск АЦП для измерения 6 токов

Пн сен 26, 2016 18:29:12

Указанная тема успешно решена и закрыта, но в процессе работы выявился толи глюк, толи баг, толи обычный косяк в программе.

Есть плата с кучей всего. Есть усилители выводы с которых идут на АЦП.
Так получается, что задействованы все 4 АЦП у микроконтроллера. По 3 вывода каждый АЦП оцифровывает. По сигналу от таймера запускается АЦП 1 и 3 и оцифровывает свой вывод, указанный в секвенсоре. АЦП работают попарно. АЦП1 и АЦП2, АЦП3 и АЦП4.
Есть вывод РВ14 - ADC4_IN4. Вот с которым проблемы. А также используется вывод РВ15 - ADC4_IN5 с которым проблем нету.
В чем проблема: все 3 сигнала с АЦП4 должны быть равны или около значения 2290. Так вот с вывода РВ14 - ADC4_IN4- сигнал будет 2100. Если обрываю провод к этой ножке, подцепляю на общий или на плюс питания - сигнал не меняется. Если два рабочих вывода подключаю к общему, то сигнал РВ14 - ADC4_IN4 будет 1700.
Менял этот "корявый" пин на другой - все нормально работает.

Также этот же проект залил в дискавери. И такая же хрень. Понимаю, что дело не в схеме, а в программе. Но где и как неясно. Все просмотрели.
Главное соседний вывод РВ15 работает нормально. Инициализация одинаковая для РВ14 и РВ15. Но РВ14 не работает как надо!!!

Помогите! может кто-то сталкивался с такой проблемой. Или ей подобной. Если надо будет - код предоставлю.

Re: STM32F303 запуск АЦП для измерения 6 токов

Вт апр 17, 2018 21:48:15

Приветствую уважаемые форумчане!!!
Опять столкнулся с проблемой. Сижу уже вторую неделю и наконец-то определил в чем дело, но как это исправить и из-за чего случается пока не понял.
Может кто сталкивался и поможет.
микроконтроллер использую следующий - STM32F303RB. Частота кварца 16 МГц.
Используется для преобразователя напряжения.
Есть несколько аналоговых входов - АЦП1 - 1, 4, 5(ток по каждой из фаз); АЦП2 - 4, 6 (входное и выходное напряжение).
Рулит всем АЦП1. опрашивает с частотой 48 кГц по одному каналу 1-1,4,5; 2-6,4,6.
и через 3 опроса прерывание по ДМА.
т.е. частота прерываний 16кГц.При отсутствии напряжения входного и выходного сигнал с АЦП2 поидее должен быть около 0. Но это оказывается не так. Сигнал входного напряжения - нулевой с АЦП2 канал 4. А сигнал выходного напряжения с АПЦ2 канал 6 не нулевой. около 360. В пересчете на коэффициенты входного усилителя - около 5В.
Но на входах 0!!!
Если работает 1 канал преобразователя, то напряжение на выходе соответствует задаваемому напряжению.
Но если включены 2 или 3 канал вместе, то уже напряжение на выходе на 5В меньше задаваемого. Но тоже все зависит от уровня задаваемого напряжения - 10-15В стоит мертво 5-10В, если выше 20В, то на 5В меньше сначала, а потом со временем становиться равным задаваемому. Вот в этом вся странность. Чем выше напряжение задаваемое - до 50В, тем быстрее выходит на правильное напряжение, но глюк этот есть все равно.
В общем мысли в том, что как-то неправильно работает 6 канал АЦП2 (или 1). Но настройка не отличается от других каналов и АЦП и проектов, которые работают исправно.
Даже все дорожки пропаял, но ничего не изменилось.
Не пойму в чем дело.
Было у кого-то такое?!

Re: STM32F303 запуск АЦП для измерения 6 токов

Вс апр 22, 2018 10:47:07

Приведите схему включения входов АЦП.
У STM32 используется АЦП с уравновешиванием заряда, а не уравновешиванием тока. Во время выборок на входе создатся импульс тока, старающийся подтянуть вывод к середине напряжения питания. О причинах и следствии - гугл поможет.
Если вход подключен через резисторы БЕЗ буферного усилителя (выход ОУ -> вход АЦП) - то напряжение будет при достаточно больших номиналах делителя.

Re: STM32F303 запуск АЦП для измерения 6 токов

Вс апр 22, 2018 13:21:47

https://leoniv.livejournal.com/194681.html
Ответить