Заголовок сообщения: Самопроизвольное изменение значения переменной
Добавлено: Чт мар 23, 2023 19:47:46
Открыл глаза
Зарегистрирован: Сб мар 26, 2016 01:01:31 Сообщений: 49
Рейтинг сообщения:0
Доброго всем времени! Если у кого-то есть время, желание, помогите разобраться в чем проблема.
Дано: STM32G041J6M6, для управления WS2812B. Проблема: в функции WS2812B_fill_buf при наступлении условия k=1, при заполнении G-составляющей, при i=1 происходит самопроизвольное присвоение переменной tim_stat значением 0x19. И естественно ничего не работает. В коде в данном месте, явно нет такого присвоения, как такое может быть?
спасибо за ответ, но так как я не профи(не занимаюсь коммерческой деятельностью в области микроконтроллеров, это мое хобби) возникло еще большее недопонимание:TIM17->SR &= ~TIM_SR_UIF; - анафема за что? в данной строчке я подразумевал простое снятие флага (было прерывание, выставлен флаг, его надо снять) разве не так? если можете поясните в чем не прав. GPIOB->BSRR |= GPIO_BSRR_BR0; и за что ту вечное проклятие, подскажите более интересный способ сбросить бит.
"Разаер uint8_t led_buf[BUF_LEN] равен 25 элементов(байт). Что будет тут buf[k*24+i] = WS2812_0; при k=1 и i=1?" ага... переполнение (надеюсь правильно понял) тут пошел думать. А почему счетчик циклов не надо делать __IO ? Ну если есть возможность обЪяснить эту конструкцию __IO, я то так понял шо это команда компилятору, мол компилируй и не оптимизируй эту штуку, ну как-то так.
За непрочтение RM на предмет того как работать с битами регистров TIMx->SR и GPIOx->BSRR и соответственно неправильное применения операторов &= и |= к ним. В первом регистре флаги сбрасываются записью ноля, а втрой вообще только для записи.
А почему счетчик циклов не надо делать __IO ? Ну если есть возможность обЪяснить эту конструкцию __IO, я то так понял шо это команда компилятору, мол компилируй и не оптимизируй эту штуку, ну как-то так.
Ну и откуда взялось желание сказать компилятору "не оптимизируй счётчик циклов"? Бывают случаи, когда это действительно нужно, но тут то зачем? Хотелось бы услышать ваши рассуждения по этому поводу.
Добавлено after 28 minutes 32 seconds: Ещё интересно было бы узнать, что по вашему замыслу делает команда (void)tmp; ? Почему она где-то __IO, а где-то нет? И кто вам рассказал, что нужно делать /* Delay after an RCC peripheral clock enabling */?
Ну если есть возможность обЪяснить эту конструкцию __IO, я то так понял шо это команда компилятору, мол компилируй и не оптимизируй эту штуку, ну как-то так.
Компилятор в праве удалить любые переменные и операции с ними - если они ограничиваются областью видимости функции. Область видимости функции ограничена скобками самой функции, буквально. По этому любая запись во внешнюю переменную будет безусловной, и на неё необязательно вешать __IO. По поводу кода. Постарайся раскидать функции по уровням и типу действия. Например RCC_Cfg() и GPIO_test_cfg() относятся к предварительным настройкам МК, этим функциям самое место в SystemInit() или что-то подобное - то вызывается до main.c. WS2812_init() и всё связанное с WS2812 - должно иметь свой файл, без лишних торчащих ушей. Делать буфер для WS2812 глобальным - очень плохая идея, он должен быть виден там где используется, и больше нигде. Тогда станет доступной возможность оперативно менять количество светодиодов, без смены алгоритма и переписывания части кода.
И кстати, WS2812 длинная пауза в единице - автоматически применяет полученные данные, даже если они были неполные.
чем же глобальный буфер плох? плоха лишь реализация работы с ним - если он глобален и фиксированного размера и один - нет никакого смысла передавать указатель на него и его размер в параметрах функций.
Компилятор в праве удалить... Постарайся раскидать функции... И кстати, WS2812 длинная пауза в единице...
Спасибо, этого я не знал, Раскидать по разным модулям это для меня еще сложно, есть непонимание в обмене данными между этими модулями(static, extern) где как обьявлять переменные, с этим буду позже разбираться, да и програмки у меня пока не большие. WS2812 в DS написано RET Code 0 более 50us, а про единичку не знал, попробую.
За непрочтение RM на предмет того как работать с битами регистров TIMx->SR и GPIOx->BSRR и соответственно неправильное применения операторов &= и |= к ним. В первом регистре флаги сбрасываются записью ноля, а втрой вообще только для записи.
А почему счетчик циклов не надо делать __IO ? Ну если есть возможность обЪяснить эту конструкцию __IO, я то так понял шо это команда компилятору, мол компилируй и не оптимизируй эту штуку, ну как-то так.
Ну и откуда взялось желание сказать компилятору "не оптимизируй счётчик циклов"? Бывают случаи, когда это действительно нужно, но тут то зачем? Хотелось бы услышать ваши рассуждения по этому поводу.
Добавлено after 28 minutes 32 seconds: Ещё интересно было бы узнать, что по вашему замыслу делает команда (void)tmp; ? Почему она где-то __IO, а где-то нет? И кто вам рассказал, что нужно делать /* Delay after an RCC peripheral clock enabling */?
Про BSRR я знаю, что только для записи 1 (биты 0-15 для установки, а 16-31 для сброса) , так и в коде у меня только запись единички в этот регистр или про BSRR я опять не правильно понимаю? По поводу SR записью 0, а логическое & инвертированного TIM_SR_UIF разве не есть запись нолика? Про счетчик циклов, как-то столкнулся с проблемкой, по поводу переменной счетчика. Пока не нарисовал ей __IO не работало, ну с тех пор так и привык. Сейчас проверил конкретно в данной программе , убрал __IO работает. Спасибо, записал на память, при случае буду изучать этот вопрос до полного понимания
Компилятор в праве удалить любые переменные и операции с ними - если они ограничиваются областью видимости функции. Область видимости функции ограничена скобками самой функции, буквально. По этому любая запись во внешнюю переменную будет безусловной, и на неё необязательно вешать __IO.
Я немного понимаю в программировании. Но из этого вообще ничего не понял.
Постарайся раскидать функции по уровням и типу действия. Например RCC_Cfg() и GPIO_test_cfg() относятся к предварительным настройкам МК, этим функциям самое место в SystemInit() или что-то подобное - то вызывается до main.c.
Тут, пожалуй, соглашучь. Но для любителя это не обязательно. Считать что "жизнь начинается с main" для С-программиста вполне нормальная практика. Качество кода это как-то заметно не ухудшает.
Делать буфер для WS2812 глобальным - очень плохая идея, он должен быть виден там где используется, и больше нигде.
А каки же как не глобальным он должен быть? Вы, наверное, глобальность с областью видимости путаете? Так тут одна единица трансляции, куда что прятать?
Про BSRR я знаю, что только для записи 1 (биты 0-15 для установки, а 16-31 для сброса) , так и в коде у меня только запись единички в этот регистр или про BSRR я опять не правильно понимаю? По поводу SR записью 0, а логическое & инвертированного TIM_SR_UIF разве не есть запись нолика?
Ну тогда всё ещё хуже. Стоит открыть учебник по С раздел про операторы |= и &= - удивитесь.
Заголовок сообщения: Re: Самопроизвольное изменение значения переменной
Добавлено: Пт мар 24, 2023 07:55:53
Открыл глаза
Зарегистрирован: Сб мар 26, 2016 01:01:31 Сообщений: 49
Рейтинг сообщения:0
Ой... ваще поплыл. Для начала: запись GPIOC->BSRR |= GPIO_BSRR_BR0 сбросит нулевой бит в регистре, а GPIOC->BSRR |= GPIO_BSRR_BS0 установит нулевой бит в регистре. Это я правильно понимаю?
Добавлено after 5 minutes 10 seconds: Ида по поводу (void)tmp это когда я переписывал инициализацию с автоматически сгенерированного CubeMX файла там используется библиотека LL, а мне нравится CMSIS. Так там и была эта конструкция, задержка после включения.
Ой... ваще поплыл. Для начала: запись GPIOC->BSRR |= GPIO_BSRR_BR0 сбросит нулевой бит в регистре, а GPIOC->BSRR |= GPIO_BSRR_BS0 установит нулевой бит в регистре. Это я правильно понимаю?
Нет, не правильно понимаете. Написанное вами выражение означает не запись единицы, а последовательное выполнение: ЧТЕНИЕ РЕГИСТРА (который возвращает только нули, ибо не подлежит чтению,), логическая функция результата чтения с маской и запись обратно в регистр. НАМЕКАЮ. Запись в такие регистры должна иметь ТОЛЬКО ПРИСВОЕНИЕ ЗНАЧЕНИЯ. Без какой либо математики с содержимым этого регистра.
Последний раз редактировалось КРАМ Пт мар 24, 2023 08:44:05, всего редактировалось 2 раз(а).
Согласен. Не гарантировано. Но возвращает. Итальянцы с французами не понимают таких приколов. Однако, я один из "любителей CMSIS". Это никак не мешает читать RM и не делать таких ошибок. А если точнее, то мне, как радиоинженеру, не близки ваши предпочтения как программиста. И это тоже не мешает мне успешно делать проекты. ЗЫ. В догон. Я нынче предпочитаю Artery европейским МК. По известным причинам. А там регистры объявлены как битовые структуры. То есть не надо писать с масками.
Заголовок сообщения: Re: Самопроизвольное изменение значения переменной
Добавлено: Пт мар 24, 2023 08:53:05
Открыл глаза
Зарегистрирован: Сб мар 26, 2016 01:01:31 Сообщений: 49
Рейтинг сообщения:0
То есть правильно будет GPIOB->BSRR = GPIO_BSRR_BS0 для установки, а для сброса GPIOB->BSRR = GPIO_BSRR_BR0. Ну и по SR TIM17->SR = ~TIM_SR_UIF. Мне кажется я смог избавиться от анафемы и вечного проклятия. Спасибо.
Заголовок сообщения: Re: Самопроизвольное изменение значения переменной
Добавлено: Пт мар 24, 2023 09:21:31
Открыл глаза
Зарегистрирован: Сб мар 26, 2016 01:01:31 Сообщений: 49
Рейтинг сообщения:0
Что? Опять? Как так-то? SR TIM17->SR = 0 я понимаю это обнулит весь регистр (сбросит все флаги), а если мне надо обнулить определенный флаг? SR TIM17->SR = ~TIM_SR_UIF Это не сработает?
Маска на сброс флага это нормально. Не путайте человека. Учитывая, что вектора прерываний таймеров не избирательны на флаги, на входе в обработчик ставят семафор, который эти флаги и проверяет. Немаскируемый сброс флагов приведет к потере событий.
дык, обычно то, берешь SR проверяешь нужный флаг, проверяешь дополнительный (типа "не произошло ли еще что-то", что нужно учитывать). и зачем оставлять SR у таймера?
у более сложной периферии, вероятно, так огульно не следует, но (честно говоря) я о ней сразу не подумал - перед глазами был TIM.
дык, обычно то, берешь SR проверяешь нужный флаг, проверяешь дополнительный
А не проще и удобнее в начале каждой секции семафора проверять и сбрасывать единственный флаг? В чем проблема? Что малочитабельного в маске? Дело ведь не в маске, а в месте ее применения. Не стоит же всех считать идиотами не способными сообразить, что в семафоре проверяется и сбрасывается флаг сгенерировавший прерывание. Тем более, что маска при проверке флага и при его сбросе идентична. Ну и немаловажна латентность между проверкой флага и его сбросом, если сброс выполняется "оптом". Так и пропустить событие несложно.
Я немного понимаю в программировании. Но из этого вообще ничего не понял.
Не ожидал . Функцию придумали для выполнения полезной работы над внешними данными. Любая бурная псевдо-деятельность без полезного выхлопа - полностью удаляется компилятором, потому как не влияет на внешнюю память.
Маска на сброс флага это нормально. Не путайте человека. Учитывая, что вектора прерываний таймеров не избирательны на флаги, на входе в обработчик ставят семафор, который эти флаги и проверяет. Немаскируемый сброс флагов приведет к потере событий.
Нет, в таких случаях нужно явно читать весь пакет флагов в переменную, сразу сбрасывать все флаги, и уже потом разбираться с флагами из сохранения. Потому как периферия в большинстве случаев живёт своей жизнью, и тактируется автономно. Пока чего-то там делаешь с одним флагом - срабатывают ещё несколько, после чего всё падает. Не надо гонятся за хвостом, это бесполезно. Это прерывание, ничего страшного - оно просто сработает ещё раз, но теперь обработка будет чётко по алгоритму, сверху вниз.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения