turnon 1 30 августа, 2015 Опубликовано 30 августа, 2015 (изменено) · Жалоба Нужен счетчик количества микросекунд, прошедших с момента старта МК (STM32). Насколько мне известно, переменные длинее байта обновляются не за одну команду МК. И надо чтобы в момент обновления была уверенность, что переменную в это время не читают, потому как она скорее всего будет иметь некорректное значение (1 байт обновился, второй еще и нет и т.д.) Вот набросал такой счетчик, для проверки атомарности используется флаг _busy. Имеет право на жизнь такая конструкция или чего-то не учел? class AtomicUint64 { private: volatile uint8_t _busy; volatile uint64_t _counterBackup; volatile uint64_t _counterValue; public: AtomicUint64(){ _busy = 0; _counterBackup = 0; _counterValue = 0; } inline void inc(uint8_t value = 1){ _counterBackup = _counterValue + value; _busy = 1; _counterValue += value; _busy = 0; } inline uint64_t get(){ if (_busy) return _counterBackup; else return _counterValue; } }; extern AtomicUint64 gTick1MsecCounter; Как используется. В прерывании 1 мsec вызывается gTick1MsecCounter.inc(), в остальном коде где нужно знать текущее значение счетчика - gTick1MsecCounter.get() Изменено 30 августа, 2015 пользователем turnon Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
menzoda 0 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Насколько мне известно, переменные длинее байта обновляются не за одну команду МК. Нет, зависит от архитектуры. Имеет право на жизнь такая конструкция или чего-то не учел? Не учел. Представь такую ситуацию: функция get вызывается из фона, проверяется флаг busy. Так как он равен нулю, то осуществляется переход к return. Чтобы возвратить 64-битное значение нужно скопировать его из памяти в регистры R0 и R1. Копирование происходит по 32 бита. Одна часть скопировалась. Тут происходит прерывание в котором вызывается inc, которая увеличивает значение счетчика. Прерывание завершается и управление возвращается get, которая копирует оставшиеся 32 бита, потенциально изменившиеся в прерывании. В итоге получается хрень. Если используешь RTOS - применяй идущие в комплекте примитивы синхронизации. Если программка простая, без RTOS, то самый легкий и надежный способ - запрещать прерывания при чтении и изменении счетчика. static uint64_t counter; void inc(uint32_t value) { __disable_interrupt(); counter += value; __enable_interrupt(); } uint64_t get(void) { __disable_interrupt(); uint64_t copy = counter; __enable_interrupt(); return copy; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Предложу еще один вариант, который не требует запрета прерываний и работает как с ОС, так и без нее: 1) Копируете во временную переменную счетчик (пусть он будет 64-битный, а копирование идет по 32 бита). 2) Копируете в еще одну временную переменную старшее слово счетчика 3) Сравниваете старшую часть первой переменной со второй. Если они одинаковы - отдаете первую переменную. Если они разные - считываете счетчик в первую переменную еще раз и отдаете ее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
menzoda 0 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Если они разные - считываете счетчик в первую переменную еще раз и отдаете ее. Так тут ведь та же самая проблема будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Предложу еще один вариант, который не требует запрета прерываний и работает как с ОС, так и без нее: 1) Копируете во временную переменную счетчик (пусть он будет 64-битный, а копирование идет по 32 бита). Да 2) Копируете в еще одну временную переменную старшее слово счетчика Да 3) Сравниваете старшую часть первой переменной со второй. Если они одинаковы - отдаете первую переменную. Да Если они разные - считываете счетчик в первую переменную еще раз и отдаете ее. Нет. В общем случае надо повторять в цикле с пункта 1). Просто неизвестно сколько времени проходит между обращениями и счетчик уже может прокрутиться на все младшие биты. Собственно предложенное это классика для считывания аппаратных счетчиков, которые нельзя остановить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Просто неизвестно сколько времени проходит между обращениями и счетчик уже может прокрутиться на все младшие биты.Ну это же несерьезно даже для счетчика из 8-битных чисел ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
turnon 1 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Предложу еще один вариант, который не требует запрета прерываний и работает как с ОС, так и без нее: 1) Копируете во временную переменную счетчик (пусть он будет 64-битный, а копирование идет по 32 бита). 2) Копируете в еще одну временную переменную старшее слово счетчика 3) Сравниваете старшую часть первой переменной со второй. Если они одинаковы - отдаете первую переменную. Если они разные - считываете счетчик в первую переменную еще раз и отдаете ее. Чего-то не пойму принцип работы. Почему на шаге 2 именно старшее слово? Меняться начинает со старшего слова? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Так тут ведь та же самая проблема будет.Какая та же самая? Если старшие байты совпадают, то младший гарантированно относится к текущему значению старшего. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 30 августа, 2015 Опубликовано 30 августа, 2015 · Жалоба Ну это же несерьезно даже для счетчика из 8-битных чисел ;) Лучше написать так, что-бы потом не думать серьезно это или несерьезно. Я не просто так написал, что это стандартный прием считывания аппаратных счетчиков. Мне, например, доводилось считывать счетчик тактов процессора в 16bit контроллере. Если речь идет о счетчике секунд, то тогда, конечно, уже можно рассуждать ну как же так он может неуспеть? А можно написать раз и навсегда, так, что бы и думать не пришлось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maksimp 0 13 сентября, 2015 Опубликовано 13 сентября, 2015 · Жалоба Предложу еще один вариант, который не требует запрета прерываний и работает как с ОС, так и без нее: 1) Копируете во временную переменную счетчик (пусть он будет 64-битный, а копирование идет по 32 бита). 2) Копируете в еще одну временную переменную старшее слово счетчика 3) Сравниваете старшую часть первой переменной со второй..... Чего-то не пойму принцип работы. Почему на шаге 2 именно старшее слово? Меняться начинает со старшего слова? Это если в пункте 1 скопировать сначала старшее слово, затем младшее. Более простой для понимания вариант, но не оптимальный. 1) Копируете во временную переменную счетчик. 2) Копируете в другую временную переменную счетчик. 3) Сравниваете, если совпало то возвращаете, иначе всё сначала - то есть идти на шаг 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться