Перейти к содержанию
    

Подскажите по хитрой функции работы с таймерами в lcp111x

Разбираюсь с проектом DMX512/RDM

Заинтересовала функция работы с таймером

 

void bsp_get_sys_uptime(uint32_t *psec_cnt, uint16_t *pmsec_cnt)
{
    // we do not want to disable the systick interrupt, so we have to deal
    // with a systick during the execution of this function
    uint32_t sec_cnt_1  = sys_seconds_cnt;
    uint16_t msec_cnt_1 = sys_millisec_cnt;
    uint32_t sec_cnt_2  = sys_seconds_cnt;
    uint16_t msec_cnt_2 = sys_millisec_cnt;
    if ((sec_cnt_1 == sec_cnt_2) && (msec_cnt_2 < msec_cnt_1))
    {
        sec_cnt_2 += 1;
    }
    *psec_cnt  = sec_cnt_2;
    *pmsec_cnt = msec_cnt_2;
}

 

переменные sys_seconds_cnt и sys_millisec_cnt инкрементируются в SysTick прерывании.

Зачем нужна такая функция?

 

Предположим,

если сработало прерывание во время инициализации локальных переменных, то увеличить счетчик секунд?

не совсем понимаю назначение, подскажите может кто встречал такие варианты.

 

код перывания

void TickHandler(void)
{
    uint32_t i;
    uint32_t millisec_increment = 1000 / SYS_TICK_RATE_HZ;

    sys_millisec_cnt += millisec_increment;
    if (sys_millisec_cnt >= 1000)
    {
        sys_millisec_cnt -= 1000;
        sys_seconds_cnt++;
    }
    for (i=0; i<NR_OF_MSEC_COUNTERS; i++)
    {
        app_millisec_cnt[i] += millisec_increment;
    }
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ИМХО по поводу функции bsp_get_sys_uptime лучше бы читать только три первых переменных и если секунды отличаются, то миллисекунды обнулять. Возвращать ессно последние прочитанные секунды.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вы этой функцией получаете текущее значение секунд и миллисекунд

 

делаете это не выключая прерывания.

 

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

 

к примеру у вас 1 секунда и 999 мсек

вы сохраняете значение 1 секунда

-------------

происходит прерывание

1сек становиться 2

999 мсек - становится 0 м сек

вы возвращаетесь обратно

-------------

сохраняете миллисекунды 0

 

и вместо 2 сек 0 мсек имеете

1 сек (ее вы сохранили до прерывания) и 0 мсек (вы их сохранили после), то есть на 1 секунду меньше

 

 

с этой же функцией если будет перекрут миллисекунд который вы пропустили, то сработает условие и число секунд увеличится...

 

ИМХО по поводу функции bsp_get_sys_uptime лучше бы читать только три первых переменных и если секунды отличаются, то миллисекунды обнулять. Возвращать ессно последние прочитанные секунды.

 

Не поможет

если любая переменная читается не за 1 команду и изменяется в прерывании, то для работы с ней ОБЯЗАТЕЛЬНО надо запрещать прерывание или быть готовым к получению некорректных данных. Потому что во время ее чтения она может быть изменена, и часть переменной будет новой, а часть старой.

 

тут фактически это и есть, переменная состоит из 2 частей секунду и миллисекунды. Считать ее за 1 такт нет возможности, это 2 значения. Эта переменная меняется в прерывании, значит надо либо его запретить, либо быть готовым что пока вы читаете переменную она может измениться, и часть переменной будет старая, а часть новая.

 

Автор запрещать прерывание не стал, (не понятно почему, ведь ничего не теряется, все отработается через 1, 2 такта, возможно есть еще и другие прерывание более критичные чем от системного таймера), поэтому придумал как поправить некорректные данные.

 

Можно было считать параметры 3 раза, и выбрать пару совпадающих. При повреждении 1 совпали 2 и 3, при повреждении 3 совпали бы 1 и 2, при повреждении 2, все были бы разными, во всех 3 случаях есть верная не поврежденная переменная...

при изменении между переменными, опять же были бы совпадения 1 со 2 или 2 с 3.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

спасибо за разъяснение, все понятно.

в принципе зачем она нужна было понятно.

мозг у меня застопорился на моменте, как вы описали

 

-------------

происходит прерывание

1сек становиться 2

999 мсек - становится 0 м сек

вы возвращаетесь обратно

-------------

сохраняете миллисекунды 0

 

пора отдыхать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...ОБЯЗАТЕЛЬНО надо запрещать прерывание или быть готовым к получению некорректных данных.

....Можно было считать параметры 3 раза, и выбрать пару совпадающих....

 

Для корректного считывания двухбайтной временной переменной, без блокирования прерываний, делается 3 чтения.

старшая часть, младшая часть, старшая часть.

Далее сравниваются старшие части, и если они не равны - то берётся последнее считывание и младшая часть обнуляется.

 

данный приём стар как мир. применяется на камнях не имеющих блокировки прерываний.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для корректного считывания двухбайтной временной переменной, без блокирования прерываний, делается 3 чтения.

старшая часть, младшая часть, старшая часть.

Далее сравниваются старшие части, и если они не равны - то берётся последнее считывание и младшая часть обнуляется.

 

данный приём стар как мир. применяется на камнях не имеющих блокировки прерываний.

 

ну конечно же так нельзя, это верно только для счетчиков, да и то для тех что считают по 1.

 

а если это экзотически 16 битный float?

а если это дата, где младшая часть дни не имеет 0?

 

в частном случае вы правы, в общем нет%)

 

 

пример.

 

счетчик

старшая часть 1, младшая 95

 

считает по 10 каждое прерывание

 

читаем старшую часть = 1

--- прерывание, счетчик становится 2 05

читаем младшую часть = 05

читаем старшую часть = 2

2 не равно 1, обнуляем младшую часть и получаем

 

2.00, вместо 1.95 или 2.05 - может в старом мире проканало бы, но в моем новом я говорю нее:)

 

 

если кто-то перестроит системный таймер на инкремент по 100 мСек, или по 10, то такой подход опять же будет давать не совсем верные результаты... а если считать интервалы, ошибочка может и накопиться....

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавлю.

1. Переменные-счётчики секунд и мсек должны быть ессно волатильными.

 

2. Если бы считанные значения времени использовались для алгоритмов ЦОС (что такое DMX512/RDM - не знаю в деталях), то можно было бы и четвёртую переменную считывать из начального примера. Тогда если секунды не совпадают, то в качестве миллисекунд брать последние (вместо ранее предложеного обнуления), а если секунды совпадают, то брать ранее прочитанные. Это при сохранении исходной последовательности чтения переменных.

 

3. Непонятно, зачем в заголовке темы указание на LPC111x.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Это даже не обсуждается;)

2. Опять не так

 

время 1 - 999

 

считали 1, потом 999, потом 1, прерывание (становится 2 - 0), считали 0

 

секунды совпадают, берем меньшие миллисекунды получаем 1 - 0, не верно. Если миллисекунды изменяются только на 1,то ваш алгоритм первоначальный с 3 чтениями подходит, если миллисекунды меняются на заданный интервал отличный от 1, или в обратную сторону, то надо 4 считывания и проверку как у ТС в примере.

 

3. да это и не важно%)

 

 

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если миллисекунды изменяются только на 1,то ваш алгоритм первоначальный с 3 чтениями подходит, если миллисекунды меняются на заданный интервал отличный от 1, или в обратную сторону, то надо 4 считывания и проверку как у ТС в примере.

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

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2. Опять не так

Исправил. Реальный чёрт слегка попутал. Показалось, что мсек считываются раньше секунд. Причём это резко "показалось" именно для второго варианта условия во второй версии :)

 

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

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...