Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: VIC в LPC23xx
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Polaris
Добрый день!
У меня в процессе освоения 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 с номером регистра адреса.
Сейчас у меня большая часть нужной периферии включилась в проект и успешно в нем трудится, но оставлять такой скользкий момент за плечами не хотелось бы. Пожалуйста, ткните меня в фразу из даташита, где это однозначно определяется!
Спасибо!
aaarrr
Цитата(Polaris @ Sep 24 2009, 00:33) *
С VICIntEnable все понятно, это подробно и четко прописано в даташите на контроллер, тут неоднозначностей нет. А вот с адресом не совсем понятно. В данном примере, случайно или нет, бит, взведенный в VICIntEnable, совпадает с номером регистра адреса. Но из текста (особенно в даташите скудно об этом написано), следует вроде бы, что никакой связи нет, регистры равноправны и опрашиваются последовательно. Или я неправильно понял?

Не понимаю, если честно, Ваших затруднений - как иначе контроллеру знать, какой VICVectAddr использовать?
Возможно, путаница происходит из-за того, что раньше NXP использовали контроллер PL190, у которого каждый источник можно было привязать к любой паре Addr/Cntl, в то время как на новых кристаллах ставят PL192. А примеры просто забыли поправить.
Полную документацию на них можно найти здесь.
rezident
Вообще-то в нормальной технической литературе описание общих принципов работы ядра и периферии семейства МК размещают в User's Manual. А в datasheet находится уточняющая информация о конкретных характеристиках одного или нескольких кристаллов из семейства. Так что вам нужно видимо UM10211 LPC23XX User manual читать, а не только datasheet.
aaarrr
Да нет, там и в мануале описание VIC урезано до предела, т.к. это стандартное решение от ARM. Правда, могли бы и написать, куда обращаться за расширенной информацией.
Polaris
Цитата(aaarrr @ Sep 24 2009, 00:08) *
Не понимаю, если честно, Ваших затруднений - как иначе контроллеру знать, какой VICVectAddr использовать?
Возможно, путаница происходит из-за того, что раньше NXP использовали контроллер PL190, у которого каждый источник можно было привязать к любой паре Addr/Cntl, в то время как на новых кристаллах ставят PL192. А примеры просто забыли поправить.
Полную документацию на них можно найти здесь.

Вот я тоже так подумал, откуда ему знать, поэтому и поправил сам везде. А примеры, наверное, действительно забыли исправить, что не есть хорошо в книге для начинающих. Если все так обстоит, то вопрос можно закрывать - разобрался smile.gif Спасибо за ответ!!!
esaulenka
Цитата(Polaris @ Sep 24 2009, 02:08) *
Если все так обстоит

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

Инициализация в таком случае будет выглядеть так (LPC2138, EINT2):
Код
    VICIntSelect &= ~BIT(16);
    VICVectAddr1 = (void*)BusyHandler;
    VICVectCntl1 = 0x20 | 16;
    VICIntEnable = BIT(16);


Похоже? smile.gif
Polaris
Цитата(esaulenka @ Sep 24 2009, 12:32) *
Можете точно убедиться - прочитать user manual на какой-нибудь процессор из старой серии (например, LPC2138) и сравнить раздел VIC wink.gif

Инициализация в таком случае будет выглядеть так (LPC2138, EINT2):
Код
    VICIntSelect &= ~BIT(16);
    VICVectAddr1 = (void*)BusyHandler;
    VICVectCntl1 = 0x20 | 16;
    VICIntEnable = BIT(16);


Похоже? smile.gif

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

Цитата(rezident @ Sep 24 2009, 00:27) *
Вообще-то в нормальной технической литературе описание общих принципов работы ядра и периферии семейства МК размещают в 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 );
...
Видимо, комментарий по поводу нахождения первого неназначенного адреса из той же оперы. Я лично никакой логической связи между ним и последующим текстом не увидел, а вот сомнения посеялись smile.gif
aaarrr
Ну дык copy-paste все любят, а вот комментарии переделывать лень.
zltigo
Цитата(Polaris @ Sep 24 2009, 12:19) *
Там в файле 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 */

Да тут и исходники уму не растяжимы sad.gif, по-человечески это так примерно выглядит:
Код
    *(ulong *)(&VICVectAddr0 + IntNumber) = (ulong)HandlerAddr;
    *(ulong *)(&VICVectPriority0 + IntNumber) = Priority;
    VICIntEnable = (1<<IntNumber);
Andy Mozzhevilov
Цитата(zltigo @ Sep 24 2009, 15:33) *
Да тут и исходники уму не растяжимы sad.gif, по-человечески это так примерно выглядит:

Мой вариант работы с VIC Нажмите для просмотра прикрепленного файла
Использование выглядит примерно так:
Код
    VIC::set_irq(VIC::TIMER2, sIsrT2);
    VIC::enable_irq(VIC::TIMER2);
zltigo
Цитата(Andy Mozzhevilov @ Sep 25 2009, 09:07) *
Мой вариант...

Использование модифицированных относительно мануала имен портов точно не есть хорошо... Остальное, остальное, типа многочисленных оберток на элементарные действия, "на любителя". Лично я не любитель такой навороченности на ровном месте.
Хватает:
Код
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
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.