Перейти к содержанию
    

VIC в LPC23xx

Добрый день!

У меня в процессе освоения LPC2368 возник вопрос относительно понимания работы VIC. В качестве источников информации использую даташит с сайта NXP (LPC2364/2366/2368) и книгу The insider's guide to the NXP LPC2300/2400 based microcontrollers Тревора Мартина.

Вот как происходит назначение процедуры обработки вектора прерывания по Мартину:

/* Setup Timer Counter 0 Interrupt */

VICVectAddr4 = (unsigned)tc0_isr;

VICVectCntl4 = 0x02

VICIntEnable = 1 << 4;

С VICIntEnable все понятно, это подробно и четко прописано в даташите на контроллер, тут неоднозначностей нет. А вот с адресом не совсем понятно. В данном примере, случайно или нет, бит, взведенный в VICIntEnable, совпадает с номером регистра адреса. Но из текста (особенно в даташите скудно об этом написано), следует вроде бы, что никакой связи нет, регистры равноправны и опрашиваются последовательно. Или я неправильно понял? Потому что тот же Мартин некоторые примеры приводит с регистром адреса совершенно не совпадающим с нужным битом. У меня такие примеры не работали, пока я не приводил в соответствие бит, отвечающий за источник прерывания в VICIntEnable с номером регистра адреса.

Сейчас у меня большая часть нужной периферии включилась в проект и успешно в нем трудится, но оставлять такой скользкий момент за плечами не хотелось бы. Пожалуйста, ткните меня в фразу из даташита, где это однозначно определяется!

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С VICIntEnable все понятно, это подробно и четко прописано в даташите на контроллер, тут неоднозначностей нет. А вот с адресом не совсем понятно. В данном примере, случайно или нет, бит, взведенный в VICIntEnable, совпадает с номером регистра адреса. Но из текста (особенно в даташите скудно об этом написано), следует вроде бы, что никакой связи нет, регистры равноправны и опрашиваются последовательно. Или я неправильно понял?

Не понимаю, если честно, Ваших затруднений - как иначе контроллеру знать, какой VICVectAddr использовать?

Возможно, путаница происходит из-за того, что раньше NXP использовали контроллер PL190, у которого каждый источник можно было привязать к любой паре Addr/Cntl, в то время как на новых кристаллах ставят PL192. А примеры просто забыли поправить.

Полную документацию на них можно найти здесь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще-то в нормальной технической литературе описание общих принципов работы ядра и периферии семейства МК размещают в User's Manual. А в datasheet находится уточняющая информация о конкретных характеристиках одного или нескольких кристаллов из семейства. Так что вам нужно видимо UM10211 LPC23XX User manual читать, а не только datasheet.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да нет, там и в мануале описание VIC урезано до предела, т.к. это стандартное решение от ARM. Правда, могли бы и написать, куда обращаться за расширенной информацией.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не понимаю, если честно, Ваших затруднений - как иначе контроллеру знать, какой VICVectAddr использовать?

Возможно, путаница происходит из-за того, что раньше NXP использовали контроллер PL190, у которого каждый источник можно было привязать к любой паре Addr/Cntl, в то время как на новых кристаллах ставят PL192. А примеры просто забыли поправить.

Полную документацию на них можно найти здесь.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если все так обстоит

Можете точно убедиться - прочитать user manual на какой-нибудь процессор из старой серии (например, LPC2138) и сравнить раздел VIC ;)

 

Инициализация в таком случае будет выглядеть так (LPC2138, EINT2):

    VICIntSelect &= ~BIT(16);
    VICVectAddr1 = (void*)BusyHandler;
    VICVectCntl1 = 0x20 | 16;
    VICIntEnable = BIT(16);

 

Похоже? :)

Изменено пользователем esaulenka

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можете точно убедиться - прочитать user manual на какой-нибудь процессор из старой серии (например, LPC2138) и сравнить раздел VIC ;)

 

Инициализация в таком случае будет выглядеть так (LPC2138, EINT2):

    VICIntSelect &= ~BIT(16);
    VICVectAddr1 = (void*)BusyHandler;
    VICVectCntl1 = 0x20 | 16;
    VICIntEnable = BIT(16);

 

Похоже? :)

Очень похоже!!! Значит, Мартин проглядел этот момент, адаптируя книгу под LPC23xx/24xx. Спасибо за разъяснения!

 

Вообще-то в нормальной технической литературе описание общих принципов работы ядра и периферии семейства МК размещают в User's Manual. А в datasheet находится уточняющая информация о конкретных характеристиках одного или нескольких кристаллов из семейства. Так что вам нужно видимо UM10211 LPC23XX User manual читать, а не только datasheet.

Я извиняюсь за неточность в определениях, но под даташитом подразумевал именно User manual, потому что сколько-нибудь достойной информации кроме обзора возможностей в даташите вообще нет, и рассматривать его в качестве руководства по контроллеру вряд ли стоит.

 

Кстати, такой же момент есть и в подборке code bundle for lpc23xx/lpc24xx с сайта NXP. Там в файле irq.c, где собраны макросы для работы с прерываниями, на которые ссылаются практически все примеры из набора, в функции install_irq есть следующий кусок:

...

/* find first un-assigned VIC address for the handler */

vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4);

vect_prio = (DWORD *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + IntNumber*4);

*vect_addr = (DWORD)HandlerAddr; /* set interrupt vector */

*vect_prio = Priority;

VICIntEnable = 1 << IntNumber; /* Enable Interrupt */

return( TRUE );

...

Видимо, комментарий по поводу нахождения первого неназначенного адреса из той же оперы. Я лично никакой логической связи между ним и последующим текстом не увидел, а вот сомнения посеялись :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там в файле irq.c, где собраны макросы для работы с прерываниями, на которые ссылаются практически все примеры из набора, в функции install_irq есть следующий кусок:

...

/* find first un-assigned VIC address for the handler */

vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4);

vect_prio = (DWORD *)(VIC_BASE_ADDR + VECT_PRIO_INDEX + IntNumber*4);

*vect_addr = (DWORD)HandlerAddr; /* set interrupt vector */

*vect_prio = Priority;

VICIntEnable = 1 << IntNumber; /* Enable Interrupt */

Да тут и исходники уму не растяжимы :(, по-человечески это так примерно выглядит:

    *(ulong *)(&VICVectAddr0 + IntNumber) = (ulong)HandlerAddr;
    *(ulong *)(&VICVectPriority0 + IntNumber) = Priority;
    VICIntEnable = (1<<IntNumber);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да тут и исходники уму не растяжимы :(, по-человечески это так примерно выглядит:

Мой вариант работы с VIC vic.zip

Использование выглядит примерно так:

    VIC::set_irq(VIC::TIMER2, sIsrT2);
    VIC::enable_irq(VIC::TIMER2);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мой вариант...

Использование модифицированных относительно мануала имен портов точно не есть хорошо... Остальное, остальное, типа многочисленных оберток на элементарные действия, "на любителя". Лично я не любитель такой навороченности на ровном месте.

Хватает:

int install_irq( bint inum, void *handler, bint priority, bint irq_enable )
{
    if( ( inum >= 32 )||( (priority ) >= VIC_SIZE ) )
        return( -1 );

    VICIntEnClear = (1<<inum);          // Disable Interrupt
    VICIntSelect &= (~(1<<inum));     // Classifies as IRQ
#if defined LPC2300
    *(ulong *)(&VICVectAddr0 + inum) = (ulong)handler;    // Set Handler
    *(ulong *)(&VICVectPriority0 + inum) = priority;
#else
    *(ulong *)(&VICVectAddr0 + priority ) = (ulong)handler;
    *(ulong *)(&VICVectCntl0 + priority ) = ( 0x20 | inum );    // Enable vector interrupt
#endif
    if( irq_enable )
        VICIntEnable = (1<<inum);    // Enable Interrupt
    return( 0 );
}

Заодно годится для PL190 и PL192

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...