2013-10-27 6 views
1

Я провел последние несколько дней, отлаживая небольшую программу, которая не прерывает символы SMBUS. Я, наконец, отследил его до нереализованного обработчика прерываний. Дело не в том, что мне нужен обработчик, а в 8051F330 неправильно настроен для аппаратного прерывания, и не было обработчика прерываний, чтобы поймать прерывание.Неполноценное поведение обработчика прерываний

Теперь это для меня удивительно. Если нет обработчика, я ожидал бы NOP, но, по-моему, отсутствующий RETI заставляет блокировать IRQ? Основной цикл, казалось, работал в этом состоянии. Я знаю, что нужно сбросить флаг прерывания, но IRQ таймера 0 не имел ничего общего с моим IRB SMBUS.

Я правильно интерпретирую это? Будет ли непреднамеренное включение IRQ причиной прерывания работы IRQ?

ответ

0

Ссылка the C8051F330 datasheet, Таблица 15.1.

Каждый источник прерываний (сброс, переполнение таймера 0, SMB0 и т. Д.) Имеет адрес вектора прерываний с жестко запрограммированным кодом. Когда прерывание утверждается, микрогенератор генерирует команду LCALL этому адресу вектора. SMB0 равен 0x003B, например, переполнение таймера 0 - 0x000B. Когда вы кодируете обработчик прерываний (ключевое слово в Keil, см. this question для других примеров), ваш компоновщик обычно ставит какую-то инструкцию JMP по векторному адресу, чтобы добраться до вашего обработчика.

Если вы пренебрегаете записью обработчика для включенного прерывания, микро будет по-прежнему векторным для этого адреса. То, что происходит тогда, зависит от того, что компоновщик помещает где-то в кодовом пространстве. Я нахожу, что небольшие функции, как правило, заполняются между векторными адресами, особенно если вы не используете много прерываний и есть несколько смежных векторных адресов, которые не используются. Вы можете узнать, просмотрев пространство кода в 0x003B (векторный адрес SMB0) в дизассемблере.

Если вы случайно попали в середину некоторой такой функции, расположенной в неправильном месте в нужное время, вы получите какие-либо побочные эффекты от части выполняемой функции, а затем RET в конце функция вернет вас туда, где вы были до прерывания. Кроме того, поскольку вы не прошли через RETI, прерывание не очищается. Любые будущие прерывания с таким же или более низким приоритетом будут заблокированы, так как микро думает, что вы все еще обслуживаете прерывание SMB0.

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

0

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

я просто был проблема использования неправильных масок в то время как повторное включение Timer4 IT, так что timer5 ИТ был включен вместо (C8051F580 в моем случае)

Так я заканчиваю вверх запись файла, как показано ниже.

Этого недостаточно, как сказано в других ответах, потому что я не сбрасываю конкретное прерывание в каждом обработчике (например, очищая TF5 для прерывания Timer5), но он позволяет быстро найти, что не так.

Макрос SPEC_INT (x) позволяет мне создать обработчик для каждого прерывания в одной строке. Прокомментированные строки соответствуют прерыванию, которое я действительно использую в своем коде приложения. Каждый обработчик вызова одной функции, int_general_function()

Заботьтесь, 8051 не любит функцию возвратного (нет стека в обычном смысле этого слова). Поскольку каждый обработчик вызывает ту же функцию, компоновщик (Keil C51/BL51) предупреждает вас предупреждением L15. Вы должны добавить к опции компоновщика, категория Overlay, следующее утверждение

int_general_function! *

в целях предотвращения (потенциальных) локальных переменных и (потенциальных) аргументы не разделяемой свои места в памяти.

#define ALLINTERRUPT_C 

#include <my_types.h> 
#include <my_platform.h> //contains #include "C8051F580.h" 

//A global var 
u8 global_unexp_int = 0; 

void int_general_function(u8 int_nb) 
{ 
    global_unexp_int = int_nb; 

    //Do here other useful things 
    //at least place a breakpoint 
    //if you are in debug 
} 

#define SPEC_INT(x) \ 
void i##x (void) interrupt x    \ 
{           \ 
    int_general_function(x);    \ 
} 

//C8051F580 
SPEC_INT(INTERRUPT_INT0) 
SPEC_INT(INTERRUPT_TIMER0) 
SPEC_INT(INTERRUPT_INT1) 
SPEC_INT(INTERRUPT_TIMER1) 
//SPEC_INT(INTERRUPT_UART0) 
SPEC_INT(INTERRUPT_TIMER2) 
SPEC_INT(INTERRUPT_SPI0) 
SPEC_INT(INTERRUPT_SMBUS0) 
SPEC_INT(INTERRUPT_ADC0_WINDOW) 
SPEC_INT(INTERRUPT_ADC0_EOC) 
//SPEC_INT(INTERRUPT_PCA0) 
SPEC_INT(INTERRUPT_COMPARATOR0) 
SPEC_INT(INTERRUPT_COMPARATOR1) 
SPEC_INT(INTERRUPT_TIMER3) 
SPEC_INT(INTERRUPT_LIN0) 
SPEC_INT(INTERRUPT_VREG) 
//SPEC_INT(INTERRUPT_CAN0) 
SPEC_INT(INTERRUPT_PORT_MATCH) 
SPEC_INT(INTERRUPT_UART1) 
SPEC_INT(INTERRUPT_PCA1) 
SPEC_INT(INTERRUPT_COMPARATOR2) 
//SPEC_INT(INTERRUPT_TIMER4) 
SPEC_INT(INTERRUPT_TIMER5) 

Надеется, что это помогает ...

Смежные вопросы