|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 14)
|
May 11 2014, 08:19
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Как мне казалось, handler-mode включается при обработке прерывания, а при его выходе возвращается в thread-mode с обнулением флага прерывания, что позволяет прерыванию снова сработать. Возможно я ошибаюсь, но в противном случае я не могу понять почему прерывание от таймера у меня срабатывает только один раз.
|
|
|
|
|
May 11 2014, 08:48
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Инициализация таймера Код AREA HEAP, CODE, READONLY systick PROC EXPORT systick MOV R0,#0x03e8; 0x03e8 = 1000 - количество тактов до прерывания MOV R1,#0xe000e000 STR R0,[r1,#0x14] STR R0,[r1,#0x18] MOVS R0,#0x07 STR R0,[r1,#0x10] ENDP BX LR END Обработчик вызывается из main.c таким образом Код void SysTick_Handler() { scheduler(); } В scheduler() выполняются следующие действия: Код LDR r0, =TaskPointer LDR r0, [r0] LDR r0, [r0] MOV r1, r0 LDR sp, [r1,#24] LDR lr, [r1,#16] BX LR Где TaskPointer - это массив в котором содержится определенная информация о задачах, которые нужно переключать, соответственно [r1,#24] - адрес указателя стэка для задачи 1, [r1,#16] - значение pc регистра для задачи 1. После BX LR прграмма выходит на зацикленную задачу task1.c Код int task1(des1* ddd) { int i, j, x, y; ddd->temp = 0x12345678; while(1) for( i = 0; i < 30000; i++ ) for( j = 0; j < 30000; j++ ) { x = 1; y = x; x = y; } } И на ней и остается, то есть при попытке поставить breakpoint на моменте до входа в scheduler() программа не останавливается а продолжает выполнять task1.c
|
|
|
|
|
May 11 2014, 09:05
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Не помогло, на задаче он все также в handler-mode и на прерывание не возвращается.
|
|
|
|
|
May 11 2014, 09:15
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Забыл кстати упомянуть, что компилируется все это с одним ворнингом ..\scheduler.asm(40): warning: A1581W: Added 2 bytes of padding at address 0x3e, возможно в этом причина. Также в дизасемблере при входе в scheduler() выполняется команда PUSH{r4,lp} а на выходе - POP {r4,pc}. Попробовал сейчас оставить в шедулере только BX LR (то есть возврат на main) режим процессора переключился на thread, как и должно быть.
Сообщение отредактировал Omnicake - May 11 2014, 09:19
|
|
|
|
|
May 11 2014, 10:22
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Попробовал убрать загрузку указателя стэка - ничего не изменилось.
А есть ли в cortex-m3 аналог команды reti? Я поспрашивал у людей, говорят на других процессорах она помогает из прерывания выходить.
|
|
|
|
|
May 11 2014, 10:28
|
Знающий
   
Группа: Свой
Сообщений: 604
Регистрация: 24-02-06
Из: Москва
Пользователь №: 14 658

|
а вы уверены, что таймер считает, а не находится в выключенном состоянии из-за отладки или режима сна какого-нибудь? Цитата(Omnicake @ May 11 2014, 13:22)  Попробовал убрать загрузку указателя стэка - ничего не изменилось.
А есть ли в cortex-m3 аналог команды reti? Я поспрашивал у людей, говорят на других процессорах она помогает из прерывания выходить. нет. Цитата Exception return Exception return occurs when the processor is in Handler mode and executes one of the following instructions attempts to set the PC to an EXC_RETURN value: an LDM or POP instruction that loads the PC an LDR instruction with PC as the destination a BX instruction using any register. The processor saves an EXC_RETURN value to the LR on exception entry. The exception mechanism relies on this value to detect when the processor has completed an exception handler. Bits[31:4] of an EXC_RETURN value are 0xFFFFFFF. When the processor loads a value matching this pattern to the PC it detects that the operation is a not a normal branch operation and, instead, that the exception is complete. Therefore, it starts the exception return sequence. Bits[3:0] of the EXC_RETURN value indicate the required return stack and processor mode, as Table 2.17 shows. http://infocenter.arm.com/help/index.jsp?t...a/Babefdjc.htmlв связи с этим, что у вас в LR перед выполнением bx lr?
|
|
|
|
|
May 11 2014, 10:31
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Таймер точно работает и генерирует прерывания, для примера убрал вызов шедулера и поставил простейшую команду i++, он корректно увеличивает ее через равные промежутки времени. В инструкции меня смущает строка "The processor saves an EXC_RETURN value to the LR on exception entry." Получается когда я заменяю LR внутри прерывания на LR задачи, я затираю тот самый EXC_RETURN value?
|
|
|
|
|
May 11 2014, 11:00
|
Знающий
   
Группа: Свой
Сообщений: 604
Регистрация: 24-02-06
Из: Москва
Пользователь №: 14 658

|
Цитата(Omnicake @ May 11 2014, 13:31)  Таймер точно работает и генерирует прерывания, для примера убрал вызов шедулера и поставил простейшую команду i++, он корректно увеличивает ее через равные промежутки времени. В инструкции меня смущает строка "The processor saves an EXC_RETURN value to the LR on exception entry." Получается когда я заменяю LR внутри прерывания на LR задачи, я затираю тот самый EXC_RETURN value? походу так. потому как по его значению "процессор определяет, что это не простой переход, а выход из эксепшена" ... переключение контекста должно происходить только в exception, тогда в какой бы стек не попал LR и какой бы задаче он ни принадлежал, по входу в exception, и, соответственно, по выходу из него значение будет правильным и одинаковым для любой задачи. нужно только откорректировать биты режима процессора.
|
|
|
|
|
May 11 2014, 11:41
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 12-01-14
Из: Омск
Пользователь №: 80 002

|
Оно и происходит внутри прерывания, ведь scheduler() выполняется внутри SysTick_Handler. Сейчас обратил внимание на другую особенность при обработке задачи. В Cortex-M# есть регистр xPSR, которые содержит в себе под-регистр ISR в момент до прерывания значение этого регистра равно 0, при входе в прерывание оно изменяется на 15 (что как я понимаю соответствует прерыванию от системного таймера), однако при выходе на task1 ISR не обнуляется, а так и остается равным 15. Есть ли возможность ручной корректировке этого бита, и можно ли с помощью этого решить проблему?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|