Список разделов Flyback.org.ru » не HV » Микроконтроллеры и всё, что с ними связано
Тему сейчас просматривают - зарегистрированных: 0, скрытых: 0 и гостей: 0
Зарегестрированные - Нет
Ответить с цитатой

Денис
 


Seriyvolk писал(а):
Заводишь просто таймер. По его прерыванию делаешь с ногами всё, что тебе нужно. Хоть с одной, хоть с несколькими. Николай тебе об этом говорил.
Просто таймер с прерыванием по переполнению + прерывания по совпадениям с OCR1A, OCR1B. Устанавливаем ножки в прерывании по переполнению, сбрасываем в прерываниях по совпадению TCNT1 с OCR1A(B). Это работает, но косяк - на высоких частотах увеличивается ошибка фактического рабочего цикла ШИМ относительно установленного, вплоть до неприличной (смотря по осциллу).
А как еще можно? Без настройки сравнений TCNT1 с OCR1A(B), не вкурю, как можно обойтись одним прерыванием по переполнению TCNT=TOP?
Можно перезаводить таймер в каждом цикле на новые значения, но тогда с больше чем одним каналом будет каша какая-то.

Добавлено: Sat Feb 05, 2022 11:40 pm
Ответить с цитатой

Seriyvolk
Бездельник


Денис писал(а):
Это работает, но косяк - на высоких частотах увеличивается ошибка фактического рабочего цикла ШИМ относительно установленного, вплоть до неприличной (смотря по осциллу).
Прости, но на каком языке ты пытаешься это всё реализовать? И почему у тебя увеличивается ошибка цикла ШИМ, если последний жёстко привязан к таймеру? Единственный вариант, который мне с дивана видно - ты пытаешься запихать простыни в прерывания. Ну или не ты, а компилятор, что по факту то же самое.

Добавлено: Sun Feb 06, 2022 2:05 am
Ответить с цитатой

Денис
 


В общем, остановился пока на штатном режиме таймера с ШИМ где ТОП=0х03FF. Для охвата нужного диапазона частот, с таким низким разрешением (счет до 03FF против FFFF) приходится использовать все допустимые делители, с частотой тактирования таймера от 16МГц до 62,5 кГц. Если бы был аппаратный режим двухканального ШИМ с ТОП=FFFF, ограничился бы двумя частотами 16 МГц и 2 МГц и этого бы хватило.

Почему сбивается заполнение на аппаратно-программном варианте, не знаю точно, но видимо неправильно выбирал режимы и оставалось слишком мало тактов счёта на высоких частотах, из-за чего такты потраченные на прерывания (а прерываний же три - попереполнению и два посовпадению с OCRx). В самих прерываниях предельно просто и без кустов.

Вопрос такой, давно не прогал и подзабыл битовые операции. Как проще всего часть регистра сделать равной битовой маске, а оставшуюся часть оставить нетронутой? Например есть регистр REG = 10101ххх, есть маска вида 110, нужно чтобы стало в таком случае REG = 10101110.

Так пойдет? (REG & 0b11111000) | 0b110

Добавлено: Tue Feb 08, 2022 12:00 am
Ответить с цитатой

N1X
 


Пойдет

Добавлено: Tue Feb 08, 2022 5:46 am
Ответить с цитатой

Николай
 


в прерываниях вообще пяток байт максимум. все остальное за пределами него.

но... причес тут время проведенное в прерывании? таймер то тикает (должен) всегда. даже когда в прерывании сидишь.

Добавлено: Tue Feb 08, 2022 8:42 am
Ответить с цитатой

N1X
 


Николай писал(а):
в прерываниях вообще пяток байт максимум. все остальное за пределами него.
Ну это таки от задачи зависит Smile Правильнее будет сказать: находясь в прерывании надо понимать, к чему это приведет и сколько мы можем в нем висеть...

Добавлено: Tue Feb 08, 2022 8:47 am
Ответить с цитатой

Денис
 


Сейчас в командировке, вернусь скину пример кода, хочу посоветоваться. Всё-таки остаются для меня непонятные моменты.

Добавлено: Tue Feb 08, 2022 9:04 am
Ответить с цитатой

Николай
 


сидя в прерывании мы как минимум можем проебать другое. лучше все делать за пределами.

Добавлено: Tue Feb 08, 2022 9:09 am
Ответить с цитатой

N1X
 


Николай писал(а):
сидя в прерывании мы как минимум можем проебать другое. лучше все делать за пределами.
Другое можно проебать, если их придет два. А иначе флаг запроса повиснет и вполне оно потом обработается Smile
Николай писал(а):
лучше все делать за пределами.
Ну вот у меня допустим сейчас just4fun проект, куда я воткнул валявшийся у меня без дела HCPL-786J. Есть буфер, куда DMA складывает данные. Данные он берет из SPI, а в SPI они валятся из сигма-дельта модулятора. Соответственно SPI в слейве, модулятор генерит клок 10МГц, буфер 250 байт, DMA валит данные по кольцу, попутно генерит прерывание когда половина (125) пришла, затем когда вторая половина пришла. Соответственно каждые 100 мкс я получаю прерывание. После этого мне надо прокрутить полученную половину буфера (125 байт) через фильтр, пока DMA не нафигачил поверху следующую порцию.
Ну ничего, все в цикле считается прямо внутри прерывания. Помимо этого есть еще прерывание синхры с сетью для симмисторов и от таймера, который углы отпирания выставляет. Норм все в принципе. Единственное, что синхра стоит приоритетом повыше и может вклиниться в предыдущее прерывание. Но в принципе и без этого для периода сети 20мс ошибка получалась небольшая и особого джиттера я не видел, приоритет поднял уже после, просто прикинул что так правильнее Smile

Добавлено: Tue Feb 08, 2022 10:03 am
Ответить с цитатой

Николай
 


N1X писал(а):
А иначе флаг запроса повиснет и вполне оно потом обработается
дорога ложка к обеду, а прерывание к моменту его наступления.
просто идеологически более правильно чтобы прерывание всегда заканчивалось раньше чем может наступить следующее. очередь из прерываний это так себе конструкция.

каюсь. есть у меня такой костыль, когда одно прерывание прерывает другое. по входу в первое принудительно sei() и тогда по приходу байта в uart он обрабатывается, даже если первое прерывание не кончилось. но это криво и так не стоит делать

Добавлено: Tue Feb 08, 2022 10:28 am
Ответить с цитатой

N1X
 


Николай писал(а):
просто идеологически более правильно чтобы прерывание всегда заканчивалось раньше чем может наступить следующее.
Ну это даже теоретически сложно реализуемо. Ибо чисто статистически при минимально коротких прерываниях 2 собития могут наступить почти одновременно. Так что как по мне - это нормальная ситуация, просто если архитектура устройства это учитывает - ничего плохого в этом нету.
Т.е. если у нас есть прерывание, которое не может ждать и при этом есть место, где прерывания блокируются (будь то другое прерывание или di в программе с какой-то целью) на достаточно долгий срок - это уже проблема. А если чего-то из этих двух условий нет (в смысле второе прерывание может ждать, допустим уарт на скорости 9600 нам гарантированно быстрее чем время приема байта второе прерывание точно не сгенерит) - ничего не случится. Уж что-то а коммуникаця вообще имеет приоритет где-то под ковром... Ну а если нам может прилететь что-то вроде сигнала аварийного тока в силе и нужно рубить концы - тогда про эту ситуацию помнить нужно (хотя и здесь притянуто зауши, ибо рубить концы должен кто-то еще до микроконтроллера, либо хотя-бы без участия ядра, а он уже по факту об этом узнает).

Добавлено: Tue Feb 08, 2022 11:27 am
Ответить с цитатой

Behram
 


Николай писал(а):
просто идеологически более правильно чтобы прерывание всегда заканчивалось раньше чем может наступить следующее. очередь из прерываний это так себе конструкция.
Не совсем. На очереди прерываний вполне можно сделать аппаратное подобие RTOS, если правильно расставить прерыванием приоритеты.
Например, у меня в одном проекте все относительно важные задачи сидят в прерываниях, а в мейновском while(1) сидят задачи, которые выполняются при появлении свободного процессорного времени.

Добавлено: Tue Feb 08, 2022 8:12 pm
Ответить с цитатой

Денис
 


Денис писал(а):
Сейчас в командировке, вернусь скину пример кода, хочу посоветоваться. Всё-таки остаются для меня непонятные моменты.

В общем, упростил уже донельзя содержимое прерывания по переполнению таймера №1. ШИМ чисто аппаратный здесь.
Просто напрямую устанавливаем в прерывании значение TCNT, с которого начнется следующий цикл счета, и значение при котором сбрасывается ножка шим-выхода. Сброс ровно при половине счета, т.е. заполнение должно быть ~50%. Комменты в коде есть. Смотрю на осциллограмму, видно рабочий цикл примерно 60%. Схрена ли? Smile Ничего лишнего в коде нет. Пробовал уже while(1); вместо основного кода программы, то есть МК работал только на прерывание, никакой разницы. В чем собака зарыта?

Код:
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TCNT1H = 0b00000011;  //устанавливаем счетный регистр на старте в TCNT1H + TCNT1L = 936, таймер настроен считать до 0x03FF=1023, потом переполнение и попадаем в это прерывание
TCNT1L = 0b10101000;

OCR1AH=0b00000011;  //устанавливаем уровень сброса ножки шим-выхода в OCR1H + OCR1L = 979. Таймер стартует при 936, переполняется при 1023, то есть 979 - это середина счета.
OCR1AL=0b11010011;
}


Добавлено: Sun Feb 13, 2022 4:14 pm
Ответить с цитатой

Кейс
 


А может это чип такой? Кривой.

Добавлено: Sun Feb 13, 2022 4:32 pm
Ответить с цитатой

Николай
 


а другие прерывания не мешают? может что-то срабатывает и затягивает время?

в протеусе запусти и глянь как в симуляторе работает и почему оно так работает

Добавлено: Sun Feb 13, 2022 4:36 pm
Ответить с цитатой

Денис
 


Блин, ну я вот хз что думать уже. Может и кривой. Попробую другую платку прошить.

Других прерываний нет, и другие таймеры отключены.
В Протеус не умею огорчён

Добавлено: Sun Feb 13, 2022 4:39 pm
Ответить с цитатой

Николай
 


освой протеус. самая важная программулина при работе с аврками.

кинь целиком код. вместе с инициализацией суну в протеус.
.

вообщем кидай код целиком

Добавлено: Sun Feb 13, 2022 4:48 pm
Ответить с цитатой

SilverRay
 


Всегда думал, что искать баги через протеус бессмысленно, он и своих добавит. Или что-то поменялось, он может симулировать реалтайм?

Добавлено: Sun Feb 13, 2022 5:01 pm
Ответить с цитатой

Николай
 


нет. он охуенен. реально. я в нем такие недокументированные вещи тестировал, как одновременная работа пина и на выход и на вход ацп, или подключение диф-ацп одним выводом к ресету, и измерение падения напряжения на внутренем фете пина этим ацп.

не реалтайм, он работае медленнее на сложных вещах, но просто дольше... а моделирует идеально. по крайней мере 328р и тини85.
прям вообще идеально.
даже когда ацп заводишь на вдвое большей частоте чем документировано - и в протеусе и в жизни совпадает

разрабатываю и обкатываю все в протеусе. больше ни какого софта не испольщую. потом финальную прошивку из него лью в контроллер и он работает абсолютно также. даже когда с костылями.

прям совсем совсем рекомендую. с жизнью сходится на сто процентов. модели авр там идеальные

Добавлено: Sun Feb 13, 2022 5:26 pm
Ответить с цитатой

Денис
 


Блин, где-то теряются такты, не могу понять где. С такими вводными, как ниже (старт счета с 1003, сброс ШИМ-вывода на 1004, счет до 1023) - заполнение получается ~45%, хотя должно быть ~5%.

Код:

#include <mega328p>

//библиотеки для не связанного с таймером. В коде на время дебага не используются, т.к. тормозим на while(1) и крутимся в прерывании.
#include <twi>
#include <delay>
#include <stdio>

// Timer1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TCNT1H = (1003 >> 8);
TCNT1L = (1003 & 0xff);
}

void main(void){
DDRB.1=DDRB.2=1; //PWM outputs Timer_1

//////////////
// Timer/Counter 1 initialization Clock value: 16000,000 kHz Mode: Fast PWM top=0x03FF OC1A output: Non-Inverted PWM OC1B output: Non-Inverted PWM
TCCR1A=(1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (1<<WGM11) | (1<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (1<<TOIE1>> 8);

// Global enable interrupts
#asm("sei")

OCR1AH=(1004 >> 8);
OCR1AL=(1004 & 0xff);

while(1);

...
}


Добавлено: Sun Feb 13, 2022 7:36 pm
Ответить с цитатой

Денис
 


Вот так меняется заполнение, при тех же условиях старт TCNT=1003, TOP=1023, OCR1A меняем от 1004 до 1023 и так в цикле. Просто чтобы наглядно понять, как оно реагирует на разные значения OCR1A. А должно получаться заполнение от 5 до 100%.

ps проверил на другом МК, купленным с разницей в годы. Все аналогично, т.е. дело не в лыжах не знаю

Добавлено: Sun Feb 13, 2022 8:27 pm
1644772971820.mp4 (20.79 Мб)
Ответить с цитатой

Николай
 


гляну утром

Добавлено: Sun Feb 13, 2022 9:31 pm
Ответить с цитатой

Денис
 


Становится заметно только на высоких частотах ШИМ. Есть косвенное подозрение, что таймер просирает где-то ощутимое время от момента переполнения до выхода из обработчика переполнения (или даже от переполнения до входа в обработчик). Просираемое время при этом фиксировано, и на десятках кГц ШИМ эффект уже на осцилле не заметен. А на сотнях, ну выше осцилограмма, "вижу лошадь у крыльца, где быть должна моя" (с) Хой.

Добавлено: Sun Feb 13, 2022 10:14 pm
Ответить с цитатой

IRFC
 


А торможение через while точно работает? У меня оптимизатор сам убирает подобные конструкции, а если его отключить, то библиотеки задержек перестают работать

Добавлено: Mon Feb 14, 2022 9:48 am
Ответить с цитатой

N1X
 


если вставишь nop в тело то оставит. Он выкидывает потому, что в теле ничего не выполняется... Ну или переменную, которую модифицируешь в цикле объяви как volatile, тоже должно быть норм Smile

Добавлено: Mon Feb 14, 2022 9:59 am
Список разделов Flyback.org.ru » не HV » Микроконтроллеры и всё, что с ними связано
На страницу Пред.  1, 2, 3 ... 135, 136, 137 ... 151, 152, 153  След.     Просмотр темы целиком



Лицензионное соглашение

(c)Flyback.org.ru
Российское общество любителей высоких напряжений.
Использование материалов с данного сайта и форума возможно только с разрешения администрации.