abi 0 17 февраля, 2020 Опубликовано 17 февраля, 2020 · Жалоба Здравствуйте. Помогите пожалуйста разобраться. Собрал для примера тестовый проект, МК ATxmega256A3U, scmRTOS 5.1.0. Во время выполнения процесса перестают работать прерывания, как только процесс уходит в sleep прерывания начинают работать. В чем может быть причина, что прерывания не работают во время выполнения кода процесса? Причем прерываний нет и от системного таймера OS TCDO, когда работает процесс. int main() { BspClockInit(); BspPin2Init(); BspComUartConnect(); ComSetFrameFormat(); ComSetBaudRate(Baud_19200BPS); TCD0.CTRLA = TC_CLKSEL_DIV1_gc; TCD0.CTRLB = TC_WGMODE_NORMAL_gc; TCD0.CTRLC = 0x00; TCD0.CTRLD = 0x00; TCD0.PER = 24000 - 1; TCD0.INTCTRLA = TC_OVFINTLVL_LO_gc; TCD0.CTRLFSET = TC_CMD_UPDATE_gc; TCD0.CTRLFCLR = TC_CMD_UPDATE_gc; TCD0.CTRLFSET = TC_CMD_RESTART_gc; TCD0.CTRLFCLR = TC_CMD_RESTART_gc; TCF0.CTRLA = TC_CLKSEL_DIV1024_gc; TCF0.CTRLB = TC_WGMODE_NORMAL_gc; TCF0.CTRLC = 0x00; TCF0.CTRLD = 0x00; TCF0.PER = 234 - 1; TCF0.INTCTRLA = TC_OVFINTLVL_LO_gc; TCF0.CTRLFSET = TC_CMD_UPDATE_gc; TCF0.CTRLFCLR = TC_CMD_UPDATE_gc; TCF0.CTRLFSET = TC_CMD_RESTART_gc; TCF0.CTRLFCLR = TC_CMD_RESTART_gc; PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_RREN_bm; OS::run(); } template<> void TProc1::exec() { unsigned char temp; for(;;) { sleep(1000); for (unsigned char i = 0; i < 50; i++) { unsigned int cnt = TCF0.CNT; ComPutchar(cnt >> 8); ComPutchar(cnt & 0xFF); temp = TCF0.INTFLAGS; ComPutchar(temp); temp = SREG; ComPutchar(temp); } } } #pragma vector=TCF0_OVF_vect OS_INTERRUPT void TimerF0_period_ISR() { BspPinTgl2(); } Во время выполнения процесса в цикле в UART вывожу состояния регистров таймера TCF0 и SREG CNT FLAGS SREG 0058 f0 82 В TCF0.INTFLAGS флаг переполнения сброшен, прерывания работали. 0065 f0 80 0095 f0 80 00c6 f0 80 000d f1 80 Произошло переполнение таймера, выставлен флаг переполнения в TCF0.INTFLAGS, 003e f1 80 в SREG I=1 прерывания разрешены 006e f1 80 009f f1 80 00d0 f1 80 Произошло повторное переполнение таймера, прерывания нет, флаг не сброшен. 0017 f1 80 0047 f1 80 0078 f1 80 Заранее спасибо за помощь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 17 февраля, 2020 Опубликовано 17 февраля, 2020 · Жалоба 25 minutes ago, abi said: В чем может быть причина, что прерывания не работают во время выполнения кода процесса? Может быть вы их выключаете в функциях работы с последовательным портом? Ну или не вы, а либа, если используете таковую... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abi 0 17 февраля, 2020 Опубликовано 17 февраля, 2020 · Жалоба 6 minutes ago, haker_fox said: Может быть вы их выключаете в функциях работы с последовательным портом? Ну или не вы, а либа, если используете таковую... В цикле только одна функция используется, просто в UART передает данные void ComPutchar(char ch) { while ((USARTD1.STATUS & USART_DREIF_bm) == 0); USARTD1.DATA = ch; } Пробовал даже вместо цикла с выводом данных, вставлял простую функцию задержки, результат одинаковый. #define delay_ms(ms) ( __delay_cycles((F_CPU / 1000UL) * (ms)) ) for(;;) { sleep(1000); delay_ms(10); } В логе видно, что флаги устанавливаются, прерывания разрешены, вроде все условия для выполнения прерывания есть, но их нет до тех пор пока процесс не уходит в sleep Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба В 17.02.2020 в 21:06, abi сказал: В логе видно, что флаги устанавливаются, прерывания разрешены, вроде все условия для выполнения прерывания есть, но их нет до тех пор пока процесс не уходит в sleep Процесс уходит в слип - означает, что процесс просто отдал управление ядру, а оно, соответственно, передало его (управление) другому процессу. Когда работает ядро, прерывания заблокированы (это короткое время), и если они начинают работать "во время слип", это значит, что они работают, когда активен другой процесс. У другого процесса другой контекст и значения регистров тоже другие. Похоже, что у интересующего вас процесса почему-то залочены прерывания. А у другого не залочены. Что блокирует прерывания во время работы процесса, с ходу сказать сложно. Попробуйте в коде процесса сграбить значение регистров, которые рулят прерываниями - статусный регистр, где глобальный флаг I (если правильно помню, с AVR работал в позапрошлой жизни), например, скопировать его в глобальную переменную и потом вывести её. Если есть эмулятор, то можно остановиться по брейкпоинту и посмотреть просто значения всех интересующих регистров. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба А разве scmRTOS поддерживает XMEGA? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба Кстати, да, хороший вопрос. Правда, я не в курсе, какие там решающие в этом контексте отличия. Вроде ядро-то МК там такое же. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abi 0 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба 6 hours ago, AHTOXA said: А разве scmRTOS поддерживает XMEGA? Сделал несколько небольших изменений для работы с xmega, если кому интересно позже открою проект. Все прерывания установил на один уровень. Перепланирование процессов производится прямой передачи управления #define scmRTOS_CONTEXT_SWITCH_SCHEME 0. Изначально основной проект был сделан под mega128, затем решил адаптировать его под xmega. Проект заработал, но заметил при приеме данных по UART, временами пакеты принимаются с ошибкой. Позже выяснил причину, оказалось, что когда какой-либо процесс активный, прерывания процессор не выполняет. Прерывание откладывается на время выполнения кода процесса, т.е. до тех пор пока не произойдет перепланировка. Если процесс занимает короткое время данные по UART успевают приниматься, иначе несколько байт теряются. Для поиска причины сделал тестовый проект, в нем 3 процесса, в каждом процессе через UART вывожу состояния нескольких регистров. Для примера код одного процесса. template<> void TProc1::exec() { unsigned char temp; unsigned int val; for(;;) { sleep(2500); for (unsigned char i = 0; i < 10; i++) { temp = TCF0.INTFLAGS; ComPutchar(temp); val = SP; ComPutchar(val >> 8); ComPutchar(val & 0xFF); temp = PMIC.INTPRI; ComPutchar(temp); temp = PMIC.STATUS; ComPutchar(temp); temp = SREG; ComPutchar(temp); } } } Полученные данные Proc1 INTFLAGS SP INTPRI STATUS SREG f0 21b1 00 01 82 f0 21b1 00 01 80 f0 21b1 00 01 80 f1 21b1 00 01 80 f1 21b1 00 01 80 f1 21b1 00 01 80 f1 21b1 00 01 80 f1 21b1 00 01 80 f1 21b1 00 01 80 f1 21b1 00 01 80 Proc3 INTFLAGS SP INTPRI STATUS SREG f0 2337 00 01 82 f0 2337 00 01 80 f0 2337 00 01 80 f1 2337 00 01 80 f1 2337 00 01 80 f1 2337 00 01 80 f1 2337 00 01 80 f1 2337 00 01 80 f1 2337 00 01 80 f1 2337 00 01 80 Proc2 INTFLAGS SP INTPRI STATUS SREG f0 2274 00 01 82 f0 2274 00 01 80 f0 2274 00 01 80 f1 2274 00 01 80 f1 2274 00 01 80 f1 2274 00 01 80 f1 2274 00 01 80 f1 2274 00 01 80 f1 2274 00 01 80 f1 2274 00 01 80 Из лога видно, что прерывания всегда разрешены SREG = 0x80, I = 1. Таймер TCF0 после переполнения выставляет флаг (0x01), INTFLAGS = 0xf1. Непонятно почему в регистре PMIC.STATUS всегда 1, насколько я понял статус показывает какого уровня прерывание на данный момент выполняется и этот флаг должен быть сброшен после выполнения. В проекте всего два разрешенных прерывания, системный таймер OS - TCD0 (1 ms) и от таймера TCF0 (2 ms) который просто переключает состояние пина. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба 45 минут назад, abi сказал: когда какой-либо процесс активный, прерывания процессор не выполняет. Вот это не очень понятно. Ведь всегда есть какой-то активный процесс. Если это не рабочие процессы, то процесс Idle. С точки зрения оси нет разницы. А вообще эти прерывания когда-нибудь выполняются? Может, просто вектор неверно задан? Или нужен ещё какой-то флажок разрешения этого прерывания? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abi 0 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба 8 minutes ago, AHTOXA said: Вот это не очень понятно. Для примера запущен таймер TCF0, который каждые 2 ms генерирует прерывания, в обработчике переключаю состояние пина, осциллографом видно что каждые 2 ms пин меняет состояние, т.е. работает правильно. Но когда работают процессы, прерывания от таймера не происходят, например #define delay_ms(ms) ( __delay_cycles((F_CPU / 1000UL) * (ms)) ) template<> void TProc1::exec() { unsigned char temp; unsigned int val; for(;;) { sleep(500); delay_ms(50); } } В течении 500 ms (когда процесс в sleep(500)) прерывания есть, как только процесс становится активным попадает в delay_ms(50) прерываний нет, и по осциллографу видно, что в течении 50 ms, пин не меняет состояние. Далее снова в течении 500 ms прерывания есть и т.д. В посту выше приводил пример с выводом данных через UART, пока в цикле выводятся данные прерываний нет, как только в процессе вызывается любой сервис OS в котором происходит перепланировка прерывания начинают работать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба То есть, если в проекте оставить один процесс TProc1, то тестовый пин будет дёргаться 500 мс, потом 50 мс не дёргаться, потом снова 500 дёргаться и так далее? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abi 0 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба Да, как будто код в процессе находится в критической секции, но это не так, как показывал на примере выше прерывания разрешены и вроде все условия для выполнения прерывания есть. Если запустить несколько процессов, то каждый процесс будет откладывать прерывание на время его выполнения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 19 февраля, 2020 Опубликовано 19 февраля, 2020 · Жалоба Очень интересно. Не могу представить, как такое может быть. Попробуйте задать scmRTOS_IDLE_HOOK_ENABLE 1 и определить функцию idle_process_user_hook(), в которой тоже выдавайте на печать всю эту информацию (STATUS, SREG и проч). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abi 0 20 февраля, 2020 Опубликовано 20 февраля, 2020 · Жалоба 13 hours ago, AHTOXA said: Попробуйте задать scmRTOS_IDLE_HOOK_ENABLE 1 Добавил в idle_process_user_hook() вывод состояния регистров. При активном процессе idle прерывания работают, это видно осциллографом и по состоянию регистров. Флаг регистра TCF0.INTFLAGS сброшен, состояние PMIC.STATUS всегда = 0. INTFLAGS SP INTPRI STATUS SREG f0 23a7 00 00 82 f0 23a7 00 00 80 f0 23a7 00 00 80 f0 23a7 00 00 80 f0 23a7 00 00 80 Не могу понять, почему в рабочих процессах всегда PMIC.STATUS = 1, а в процессе idle PMIC.STATUS = 0 и прерывания работают. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 20 февраля, 2020 Опубликовано 20 февраля, 2020 · Жалоба Сдаётся мне, что вы неверно заполняете начальную структуру контекста проекта. Смотрите реализацию функции init_stack_frame(). Возможно, что для xmega в контекст нужно включить PMIC? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abi 0 20 февраля, 2020 Опубликовано 20 февраля, 2020 · Жалоба 16 minutes ago, AHTOXA said: Возможно, что для xmega в контекст нужно включить PMIC? У PMIC 3 регистра. PMIC.STATUS только для чтения. PMIC.INTPRI сохраняет вектор последнего подтвержденного низкоуровневого прерывания, если разрешен режим Round-Robin, но он отключен. PMIC.CTRL для настройки уровня разрешенных прерываний, т.к. у всех прерываний установлен Low Level, регистр настроен на LOLVLEN и всегда равен 1. Выводил состояние этого регистра в процессах, он не меняется и всегда равен 1. Поэтому думаю сохранять регистры PMIC в контекст смысла нет. А вот интересно при создании объекта IdleProc используется функция init_stack_frame () так же как и при создании рабочих процессов, т.е. все одинаково, а результат разный. Позже попробую добавить в IdleProc функцию sleep и скорее всего и IdleProc начнет блокировать прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться