Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Правильно отключить прерывания
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
athlon64
Портирую прошивку с AVR на ARM SAM7X512. В прошивке для AVR во время вывода в порты UART0, UART1 глобально запрещались и разрешались прерывания командами CLI и SEI.
В проекте для SAM7 добавил одноимённые функции:
Код
unsigned char SREG;
////unsigned long int IMR;
/*===============================================
  Процедуры CLI и SEI заменяют соответствующие АВР-овские,
  выключают и включают все прерывания
  ===============================================
*/
void CLI(){                                        //// Отключает все прерывания
AT91C_BASE_AIC->AIC_IDCR=0xFFFFFFFF;
SREG=0x00;
}

void SEI(){                                        //// Включает все прерывания
AT91C_BASE_AIC->AIC_IDCR=0;
SREG=0x80;
}


Процедура отправки очередного байта в ком-порт выглядит так:
Код
void Out2COM(){
char i;

if (AT91C_BASE_US0->US_CSR & AT91C_US_TXEMPTY){             //// регистр к передаче готов
        CLI();
        if(OutBufCOMIdxWR==OutBufCOMIdxRD){                   // буфер пуст
            OutBufCOMIdxWR=OutBufCOMIdxRD=0;
            
            if (AT91C_BASE_US0->US_CSR & AT91C_US_ENDTX){   //// Если передача закончена // Разрешаем прием по COM
                USART_ReadBuffer(AT91C_BASE_US0, &i, 1);
                COM_mode &= ~0x83;      // нет пилотов и нет принятых пакетов и нет Tx
                AT91C_BASE_US0->US_IER = AT91C_US_RXBUFF;   //// разрешаем прерывания приема СОМ
            }
        }
        else{
            AT91C_BASE_US0->US_THR = OutBufCOM[OutBufCOMIdxRD++]; //// выдали в порт
        }

        COMWaitCnt=0;
        SEI();
    }
    else if(COMWaitCnt++>5000){LedErrorOn(); while(1);}  // по WatchDog'у должны сброситься
}


В итоге МК пытаясь при инициализации отправить свой адрес в порт (адрес приходит нормально и МК не виснет, крутится в главном цикле main), в обработчик PIT он так и не попадает. Если убрать из процедуры отправки байта вызов CLI, то PIT работает, но вместо посылки (адреса устройства приходит байт 0x0D), видимо передачу прерывает PIT
aaarrr
В IDCR писать нули совершенно бесполезно, для разрешения прерываний существует регистр IECR.
Глобально запрещать прерывания гораздо удобнее установкой бита I регистра CPSR ядра.
MrYuran
Цитата(athlon64 @ Jun 11 2010, 16:43) *
В прошивке для AVR во время вывода в порты UART0, UART1 глобально запрещались и разрешались прерывания командами CLI и SEI.

Зачем?!!
demiurg_spb
И правда зачем?
athlon64
Цитата(aaarrr @ Jun 11 2010, 18:50) *
В IDCR писать нули совершенно бесполезно, для разрешения прерываний существует регистр IECR.
Глобально запрещать прерывания гораздо удобнее установкой бита I регистра CPSR ядра.

Как менять биты регистра CPSR в IAR я так и не понял. В at91sam7x512.h этот регистр не объявлен
Дальше разбираюсь, возможно проблема не в запрещении/разрешении прерываний. Как выясню, отпишу smile.gif

Цитата(MrYuran @ Jun 11 2010, 18:52) *
Зачем?!!

Цитата(demiurg_spb @ Jun 12 2010, 16:53) *
И правда зачем?

Ну как зачем. Как иначе исключить возможность прерывания передачи периодическим таймером или ещё чем то?
igorenja
Цитата(athlon64 @ Jun 15 2010, 12:07) *
Как менять биты регистра CPSR в IAR я так и не понял. В at91sam7x512.h этот регистр не объявлен
Дальше разбираюсь, возможно проблема не в запрещении/разрешении прерываний. Как выясню, отпишу smile.gif


В 4ом IARе было так:
CODE
#include "intrinsics.h"

....
__disable_interrupt();
....
__enable_interrupt();
...


как в 5ом не разбирался
MrYuran
Цитата(athlon64 @ Jun 15 2010, 09:07) *
Ну как зачем. Как иначе исключить возможность прерывания передачи периодическим таймером или ещё чем то?

А как таймер может прервать передачу? Не понимаю...
Как раз наоборот, прерывания по опустошению передающего буфера очень облегчают жизнь.
Достаточно указать на буфер сообщения и выдать первый байт, и остальные выскочат совершенно без никакого участия со стороны основной программы. А в это время можно заниматься полезными делами (вместо того чтобы тупо караулить тормозной УАРТ)
athlon64
Начал отключать прерывания по одному, выяснилось что если выключить прерывание от PIT - посылка по USART проходит без проблем.
В обработчике прерывания PIT сделал мигалку светодиода и посмотрел осциллографом что происходит на ножке. Независимо от задаваемого периода PIT, в обработчик PIT попадаю раз в 5мкс.
Инициализация PIT:
Код
    PIT_Init(1000, 48); // period 1ms

    // Configure interrupt on PIT
    IRQ_DisableIT(AT91C_ID_SYS);
    IRQ_ConfigureIT(AT91C_ID_SYS, AT91C_AIC_PRIOR_LOWEST, IRQ_PIT);
    IRQ_EnableIT(AT91C_ID_SYS);
    PIT_EnableIT();

    // Enable the pit
    PIT_Enable();

Обработчик PIT:
Код
void IRQ_PIT(){ //1 msek
unsigned int status;

status = PIT_GetStatus() & AT91C_PITC_PITS;
if (status != 0) {
        Led_blink2();
}


PS: пробовал читать PIT_PIVR в обработчике прерывания, тогда ножка МК вообще перестаёт дрыгаться
MrYuran
Цитата(athlon64 @ Jun 15 2010, 14:08) *
Независимо от задаваемого периода PIT, в обработчик PIT попадаю раз в 5мкс.

Не знаю, что такое PIT sad.gif
но жизненный опыт подсказывает, что наверняка в обработчике прерывания надо какой-то флажок загасить
aaarrr
Цитата(athlon64 @ Jun 15 2010, 14:08) *
PS: пробовал читать PIT_PIVR в обработчике прерывания, тогда ножка МК вообще перестаёт дрыгаться

PIVR читать необходимо, иначе прерывание не будет сброшено. Если выполнить это чтение до чтения статуса, то PITS, естественно, будет сброшен, и ничего мигать не будет.
athlon64
Заработала отправка в USART и периодический 1мс таймер smile.gif Спасибо
В последнем случае проблема была в том что я на время отсылки в ком-порт отключал прерывания от PIT, в это время PIT переполнялся но прерывание сгенерить не мог.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.