Российский производитель и разработчик сертифицированного измерительного оборудования с 1987 года

L502 подсчёт времени

Вы не вошли.

 Поиск | Регистрация | Вход 

Илья гость
11.10.2023 16:53:30
#1

Гость

L502 подсчёт времени

Здравствуйте. Есть ваша l502 с сигнальным процессором Bfin. Есть необходимость писать свою прошивку для него и в ней считать время с миллисекундной точностью. Не подскажете, как это сделать? Функция clock из time.h возвращает -1. START_CYCLE_COUNT и STOP_CYCLE_COUNT из cycle_count.h тоже не работают. Для сборки прошивки использую тулчейн bfin-elf-gcc под Linux с sourceforge. Спасибо.

Илья гость
12.10.2023 18:13:42
#2

Гость

Re: L502 подсчёт времени

Частично отвечу сам на свой вопрос. В makefile прошивки нужно добавить дефайн DO_CYCLE_COUNTS (строка, начинающаяся с DDEFS=). В файл l502-bf_basiccrt.s добавить строки (я добавил перед //Zero bss memory):

R0 = SYSCFG;
BITSET(R0, 1);
SYSCFG = R0;

В хедере тулчейна /bfin-elf/include/cycle_count_bf.h заменить все вхождения r0, r1, r2 на R0, R1, R2 соответственно. ПОЛНОСТЬЮ пересобрать прошивку. Теперь в прошивке можно делать такие вещи:

#include <cycle_out.h>
.................
cycle_t start, stop;
START_CYCLE_COUNT(start);
профилируемый код
STOP_CYCLE_COUNT(stop, start);

В stop будет лежать количество тактов процессора, прошедших со START_CYCLE_COUNT(start). Чтобы получить миллисекунды, нужно это значение разделить на 530000. У меня осталось пару вопросов. Насколько точен такой метод? Почему бы не включить в прошивку что-то подобное из коробки? Можно ли использовать таймеры в прошивке? Если да, то как?

Илья гость
14.10.2023 07:00:12
#3

Гость

Re: L502 подсчёт времени

Помогите пожалуйста включить таймер и добавить обработчик его прерываний в вашу прошивку. Требуемая частота - 1КГц. Добавил в l502_init.c в l502_init перед hdma_init() следующий код:

*pTIMER0_CONFIG = 0x0000;
*pTIMER0_PERIOD = 0x000C;
*pTIMER0_WIDTH  = 0x000C;
*pTIMER0_CONFIG = 0x0003;
*pTIMER_STATUS  = 0x0001;
*pSIC_IAR4 |= P16_IVG(32);
REGISTER_ISR(12, inc_time);
*pSIC_IMASK1 |= IRQ_TIMER0;

ISR(inc_time) определён, но не срабатывает. Что я делаю не так?

14.10.2023 23:19:05
#4

Сотрудник "Л Кард"
Здесь с 17.04.2014
Сообщений: 1,287

Re: L502 подсчёт времени

Здравствуйте.

По поводу точности, то нужно учитывать, что для любого способа, основанного на внутренней частоте процессора есть ошибка, связанная с неточностью значения самой этой частоты, от которой работает процессор. Для L-502 эта точность 50ppm или 0.005 % (т.е. для измерения времени секунды может быть ошибка до 50 мкс).

По поводу Вашего кода.
Во первых не совсем понятна инициализация таймера, *pTIMER0_CONFIG = 0x0003 - это режим работы EXT_CLK - подсчета импульсов внешнего сигнала, который должен подаваться на соответствующую ножку процессора (чего в схеме L-502 нет), значения pWIDTH и pPERIOD также не очень понял, и они устанавливаются когда *pTIMER0_CONFIG равен 0, т.е. таймер запрещен и эти изменения вообще могут быть неприменимы.

Если Вам нужен таймер, который генерирует прерывания раз в мс, то Вам нужно настроить режим PWM_OUT без использования собственно выходного сигнала PWM на ножке (OUT_DIS = 1), с постоянной (не однократной) генерацией сигнала (PERIOD_CNT = 1) и с разрешенной установкой бита прерывания в конце каждого периода (IRQ_ENA = 1). Таймер по умолчанию работает от частоты SCLK = 132.5 МГц, соответственно в регистр длительности периода, чтобы она была 1 мс, нужно записать значение 132500. Регистр WIDTH определяет длину активного значения импульса (duty cycle) для сигнала pwm и т.к. сам PWM сигнал Вы не используете, то его значение не важно, но на всякий случай лучше установить его в действительное значение, т.е. не менее 1, но меньше PERIOD.

Т.е. код инициализации таймера без разрешения обработчика прерывания таймера может выглядеть так:

*pTIMER0_CONFIG = PWM_OUT | PERIOD_CNT | IRQ_ENA | OUT_DIS;
*pTIMER0_PERIOD = 132500;
*pTIMER0_WIDTH  = 1;
*pTIMER_STATUS = TIMIL0; /* сброс флага прерывания на случай, если он был установлен */

После конфигурации таймер необходимо также запустить через TIMER_ENABLE.

*pTIMER_ENABLE = TIMEN0;

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

if (*pTIMER_STATUS & TIMIL0) {
    *pTIMER_STATUS = TIMIL0; /* сброс идет записью 1 */
    
    /* увеличение счетчика мс */ 
}

Если все работает как надо (идет подсчет мс корректно), то долее можно разрешить уже обработчик.

Строка REGISTER_ISR(12, inc_time); регистрирует обработчик прерывания для прерывания IVG12. Через регистры IAR Вы делаете маппинг прерываний от периферии на прерывания контроллера (IVG7 - IVG15) (что необходимо, т.к. обработчиков под периферию всего 9, а источников намного больше). В макросе Pxx_IVG(n)  значение n - это как раз номер IVG, а значение xx - Peripheral ID# (для TIMER0 - 32), т.е. правильный вызов макроса - P32_IVG(12). Во-вторых делать просто операцию "или" не совсем корректно, т.к. уже есть назначение по умолчанию при старте и поле может быть не 0 (и к слову для TIMER0 это как раз IVG12 и можно было бы ничего не писать), поэтому сперва значение этого поля в IAR4 нужно обнулить. Для этого я не нашел готовый макрос, поэтому в прошивке пишу через явную битовую маску:

*pSIC_IAR4 = (*pSIC_IAR4 & 0xFFFFFFF0) | P32_IVG(12);

Т.е. после настройки таймера и до его разрешения через pTIMER_ENABLE, нужно вставить:

*pSIC_IAR4 = (*pSIC_IAR4 & 0xFFFFFFF0) | P32_IVG(12);
REGISTER_ISR(12, inc_time);
*pSIC_IMASK1 |= IRQ_TIMER0;

В обработчике прерывания необходимо аналогично проверить флаг от таймера и сбросить его, после чего вызвать ssync(), чтобы флаг сбросился до выхода из обработчика и не попасть в обработчик второй раз:

ISR(inc_time) {
    if (*pTIMER_STATUS & TIMIL0) {
        *pTIMER_STATUS = TIMIL0; /* сброс идет записью 1 */
    
        /* увеличение счетчика мс */ 

        ssync()
    }
}

Контакты

Адрес: 117105, Москва, Варшавское шоссе, д. 5, корп. 4, стр. 2

Многоканальный телефон:
+7 (495) 785-95-25

Отдел продаж: sale@lcard.ru
Техническая поддержка: support@lcard.ru

Время работы: с 9-00 до 19-00 мск