Если регистр не буферизирован, он моментально обновляется (для TIMxCR1 обновляются значения PSC, ARR). Если буферизирован , то обновление новых значений только после события Update Event (после переполнения счетчика). Если нужно на ходу обновить ARR, PSC при установленном бите ARPE(Auto-reload preload): 1) Меняем в программе значения ARR, PSC 2) Вызываем IRQ: TIMx->EGR |= TIM_EGR_UG 3) Сбрасываем флаг UIF: TIMx->SR &= ~TIM_SR_UIF
Все время вижу глупую ошибку на просторах. На 8:39 пример. Правильный вариант TIM1->CR1 &= ~(TIM_CR1_xxx | TIM_CR1_xxx | ..). Неправильный вариант в видео TIM1->CR1 &= ~(TIM_CR1_ххх); TIM1->CR1 &= ~(TIM_CR1_xxx); ... То есть вместо того чтобы сделать запись все за один раз, ты дергаешь регистр на изменение каждого бита. А одна эта строчка у кортекса это 3 операции: считать, изменить, записать и ты их бессмысленно дублируешь по каждому биту. А регистры как бы volatile то есть не следует оптимизировать. И ещё, когда тебе нужно сконфигурировать какие то регистры, как в случае инита таймера, когда тебе без разницы что там в них до этого было не нужно по маске сначала что то сбрасывать и потом через или ставить, то есть в 6 операций (чтение/изменение/запись 2 раза), когда можно просто в одну операцию записать нужное значение, естественно понимая что каждый бит значит (но обычно значение reset регистра 0 и все просто). TIM1->CR1 = (TIM1_CR1_xxx |...); Сорян, весь Видос не смотрел, на это место просто ткнул и все что увидел. Может ещё б чего сказал. Вот простейший инит, не самый лучший, с просто константами делителей, но просто для понимания, на прерывание через определенное время, никаких & и | с регистрами таймера, они тут просто не нужны, т.к что было до не имеет значение и нам не нужно сохранять. Понятно что нужно все делать с умом, а не просто не напрягая серое вещество все везде лепить по одному шаблону. RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; TIM2->PSC = xxx - 1; TIM2->ARR = xxx - 1; // Load PSCR (это если нужно чтоб уже первый раз сработал именно после установленного промежутка, то есть с выставленными делителямя, нужно тут загрузить самостоятельно в теневой) TIM2->CR1 = TIM_CR1_URS; TIM2->EGR = TIM_EGR_UG; TIM2->DIER = TIM_DIER_UIE; // UIE: Update interrupt enable TIM2->CR1 = (TIM_CR1_ARPE | TIM_CR1_CEN); // CEN: Counter enable, ARPE: Auto-reload preload enable NVIC_EnableIRQ(TIM2_IRQn);
Я это все понимаю, НО. Какая разница, сколько операций кортекс сделает. Это же инициализация. Делается раз и все) Разницы мы не ощутим. К тому же, когда делаешь по биту - можно быстро менять настройки(удобней для восприятия, заменив SET на CLEAR, нежели удалить бит из одной пачки и прописать в другую). Ну и конечно же не забываем про то, что иногда нельзя сразу все биты назначить, т.к. нужно соблюдать порядок.
@@Solderingironspb Я это тоже понимаю. Но это же обучение для других. Лучше уж видеть и изучать как правильнее. А уж потом свой подчерк формировать. Мы ж учимся писать буквы и слова с примера как должно быть, а не по кривому подчерку конкретного человека как видит и смог для себя он и что сильно отличается от как должно быть. Я думаю мысль понятна )
И переписал код инициализации и работы таймера в своем проекте, все сделал на регистрах, прикольно, и у камушка stm32030f4 всего то 16кБ флеша, HAL жрет так память, будто ее там 2Гб, вообще странно, что она не старается экономить память там где ее мало, было бы супер.
@@Solderingironspb в видео, да. Но как сделать, при счёте таймера вверх или вниз. Возможно отключать канал только до конца счета таймера, тоесть я хочу немножко вмешиваться в длительность ШИМ посреди счета таймера
Если регистр не буферизирован, он моментально обновляется (для TIMxCR1 обновляются значения PSC, ARR).
Если буферизирован , то обновление новых значений только после события Update Event (после переполнения счетчика).
Если нужно на ходу обновить ARR, PSC при установленном бите ARPE(Auto-reload preload):
1) Меняем в программе значения ARR, PSC
2) Вызываем IRQ: TIMx->EGR |= TIM_EGR_UG
3) Сбрасываем флаг UIF: TIMx->SR &= ~TIM_SR_UIF
Комментарий в поддержку этого отличного канала.
Все время вижу глупую ошибку на просторах. На 8:39 пример.
Правильный вариант
TIM1->CR1 &= ~(TIM_CR1_xxx | TIM_CR1_xxx | ..).
Неправильный вариант в видео
TIM1->CR1 &= ~(TIM_CR1_ххх);
TIM1->CR1 &= ~(TIM_CR1_xxx);
...
То есть вместо того чтобы сделать запись все за один раз, ты дергаешь регистр на изменение каждого бита. А одна эта строчка у кортекса это 3 операции: считать, изменить, записать и ты их бессмысленно дублируешь по каждому биту. А регистры как бы volatile то есть не следует оптимизировать.
И ещё, когда тебе нужно сконфигурировать какие то регистры, как в случае инита таймера, когда тебе без разницы что там в них до этого было не нужно по маске сначала что то сбрасывать и потом через или ставить, то есть в 6 операций (чтение/изменение/запись 2 раза), когда можно просто в одну операцию записать нужное значение, естественно понимая что каждый бит значит (но обычно значение reset регистра 0 и все просто).
TIM1->CR1 = (TIM1_CR1_xxx |...);
Сорян, весь Видос не смотрел, на это место просто ткнул и все что увидел. Может ещё б чего сказал.
Вот простейший инит, не самый лучший, с просто константами делителей, но просто для понимания, на прерывание через определенное время, никаких & и | с регистрами таймера, они тут просто не нужны, т.к что было до не имеет значение и нам не нужно сохранять. Понятно что нужно все делать с умом, а не просто не напрягая серое вещество все везде лепить по одному шаблону.
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = xxx - 1;
TIM2->ARR = xxx - 1;
// Load PSCR (это если нужно чтоб уже первый раз сработал именно после установленного промежутка, то есть с выставленными делителямя, нужно тут загрузить самостоятельно в теневой)
TIM2->CR1 = TIM_CR1_URS;
TIM2->EGR = TIM_EGR_UG;
TIM2->DIER = TIM_DIER_UIE; // UIE: Update interrupt enable
TIM2->CR1 = (TIM_CR1_ARPE | TIM_CR1_CEN); // CEN: Counter enable, ARPE: Auto-reload preload enable
NVIC_EnableIRQ(TIM2_IRQn);
Я это все понимаю, НО. Какая разница, сколько операций кортекс сделает. Это же инициализация. Делается раз и все) Разницы мы не ощутим. К тому же, когда делаешь по биту - можно быстро менять настройки(удобней для восприятия, заменив SET на CLEAR, нежели удалить бит из одной пачки и прописать в другую). Ну и конечно же не забываем про то, что иногда нельзя сразу все биты назначить, т.к. нужно соблюдать порядок.
@@Solderingironspb Я это тоже понимаю. Но это же обучение для других. Лучше уж видеть и изучать как правильнее. А уж потом свой подчерк формировать. Мы ж учимся писать буквы и слова с примера как должно быть, а не по кривому подчерку конкретного человека как видит и смог для себя он и что сильно отличается от как должно быть. Я думаю мысль понятна )
А если у одного регистра нужно один бит сбросить, а другой установить, одной строчкой оботись то можно ?
@@smart_electronics_il можно. Используя макрос. Но это будет только написание в виде строчки. МК в любом случае будет делать и отдельно, или отдельно.
Спасибо 👍 всё-таки перешли на GDB
Ух...., запустил ШИМ на отладочной плате stm32f030f4, есть там светодиод пользовательский на РА4 ножке, подключен он а каналу 1 таймера 14
И переписал код инициализации и работы таймера в своем проекте, все сделал на регистрах, прикольно, и у камушка stm32030f4 всего то 16кБ флеша, HAL жрет так память, будто ее там 2Гб, вообще странно, что она не старается экономить память там где ее мало, было бы супер.
Спасибо, а как сдвинуть по фазе один из сигналов, например на 90*
Хороший материал.
Спасибо, как раз с шимом хотел поиграть.
о спасибо)
Надо шим сделать в рамках счета 0-1000, к примеру 200-500. Аппаратно не сделать? Только в прерываниях ногой дрыгать?
Так в данном видео никто ногой не дрыгает. Все аппаратно
@@Solderingironspb в видео, да. Но как сделать, при счёте таймера вверх или вниз. Возможно отключать канал только до конца счета таймера, тоесть я хочу немножко вмешиваться в длительность ШИМ посреди счета таймера
28:20 важный момент.
А как скважность менять?
TIMx->CCRx = значение.
Супер!
мне одно интересно, не проще в самом начале сбросить одной строчкой, например CR1 = 0 ?
Хотя вроде после сброса МК, там и так всё по 0.
Я первый лайк!
👍👍👍👍👍
А точно нужно включать тактирование ножки при использовании ШИМ?
В стм для любой периферии включается тактирование, а в случае если периферия имеет выход наружу то и соответствующих портов gpio
Все верно)