реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> UART0 LPC2468, Работа по прерыванию
mempfis_
сообщение Jun 3 2009, 21:36
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Всем доброй ночи.
Пытаюсь наладить работу с UART0 по прерыванию.

За основу взял рабочий пример из IARa и слегка переделал его по-своему (в основном только инициализация UART0).

Основной цикл программы:
CODE
#include "common/target.h"
#include "common/target.c"

#include "uart_lpc2468.h"
#include "uart_lpc2468.c"

void main(void)
{
//power on target init
TargetResetInit();

//uart0 initialization
uart0_lpc2468_init(9600);


for(;;)
{
//putchar(getchar());
//continue;
/* Loop forever */
if ( UART0Count != 0 )
{
U0IER = IER_THRE | IER_RLS; /* Disable RBR */
UARTSend( (BYTE *)UART0Buffer, UART0Count );
UART0Count = 0;
U0IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */
};
}
}


Нстройка UART0:
CODE
/**************************************************/
//uart0 initialization
WORD uart0_lpc2468_init(DWORD baudrate)
{
DWORD Fdiv;

//set PCUART0 - UART0 power/clock control bit.
PCONP |=(1<<PCUART0);

//set PCLK_UART0=0x01 (PCLK_UART0 = CCLK) - Peripheral clock selection for UART0.
PCLKSEL0 |= PCLK_UART0;

//UART pins and pin modes
PINSEL0 = RXPinON|TXPinON;
PINMODE0 = RXPinPullUP|TXPinPullUP;

//UART0 Line Control Register U0LCR
U0LCR = WordLenth8|StopBit1|ParityDis|BreakDis|DLABEna;

//UART0 baudrate
Fdiv = ( Fpclk / 16 ) / baudrate ; /*baud rate */
U0DLM = Fdiv / 256;
U0DLL = Fdiv % 256;
U0LCR = WordLenth8|StopBit1|ParityDis|BreakDis|DLABDis;

//UARTn FIFO Control Register U0FCR
U0FCR = FIFOEna|RXFIFORes|TXFIFORes|TriggerLevel0;

//install uart0 irq
if ( install_irq( UART0_INT, (void *)UART0Handler, HIGHEST_PRIORITY ) == FALSE )
{
return (FALSE);
}

U0IER = RBR_IE | THRE_IE | IER_RLS; /* Enable UART0 interrupt */

return TRUE;
}
/**************************************************/


Инсталяция прерывания:
CODE
DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority )
{
DWORD *vect_addr;
DWORD *vect_cntl;

VICINTENCLEAR = 1 << IntNumber; /* Disable Interrupt */
if ( IntNumber >= VIC_SIZE )
{
return ( FALSE );
}
else
{
/* find first un-assigned VIC address for the handler */
vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4);
vect_cntl = (DWORD *)(VIC_BASE_ADDR + VECT_CNTL_INDEX + IntNumber*4);
*vect_addr = (DWORD)HandlerAddr; /* set interrupt vector */
*vect_cntl = Priority;
VICINTENABLE = 1 << IntNumber; /* Enable Interrupt */
return( TRUE );
}
}


И сам обработчик:
CODE
__irq __arm void UART0Handler(void)
{
BYTE IIRValue, LSRValue;
volatile BYTE Dummy;

//__enable_interrupt(); /* handles nested interrupt */

IIRValue = U0IIR;
IIRValue >>= 1; /* skip pending bit in IIR */
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
{
LSRValue = U0LSR;
/* Receive Line Status */
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
{
/* There are errors or break interrupt */
/* Read LSR will clear the interrupt */
UART0Status = LSRValue;
Dummy = U0RBR; /* Dummy read on RX to clear interrupt, then bail out */
VICADDRESS = 0; /* Acknowledge Interrupt */
return;
}
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
{
/* If no error on RLS, normal ready, save into the data buffer. */
/* Note: read RBR will clear the interrupt */
//Dummy = U0RBR;
UART0Buffer[UART0Count] = U0RBR;
UART0Count++;
if ( UART0Count == BUFSIZE )
{
UART0Count = 0; /* buffer overflow */
}
}
}
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
{
/* Receive Data Available */
UART0Buffer[UART0Count] = U0RBR;
UART0Count++;
if ( UART0Count == BUFSIZE )
{
UART0Count = 0; /* buffer overflow */
}
}
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
{
/* Character Time-out indicator */
UART0Status |= 0x100; /* Bit 9 as the CTI error */
}
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = U0LSR; /* Check status in the LSR to see if valid data in U0THR or not */
if ( LSRValue & LSR_THRE )
{
UART0TxEmpty = 1;
}
else
{
UART0TxEmpty = 0;
}
}

VICADDRESS = 0; /* Acknowledge Interrupt */
return;
}
/**************************************************/


Если собрать всё до кучи то по прерываниям не работает sad.gif
Кажется прерывания не возникают вообще. Если вместо прерывания использовать ф-ции getchar/putchar которые просто ожидают/отправляют символы то видно что сам UART0 работает (проверяю работу в терминале).
Т.к. это первое прерывание которое я пытаюсь использовать то сразу уловить не могу в чём тут загвоздка.
Подскажите где что я не так сделал.

Дополнительно прикладываю свой проект и рабочий пример из IARa.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 4 2009, 07:23
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Совет - напишите просто что нибудь свое, пусть это бужет для начала 10 строчек, но это будут Ваши 10 строчек и Вы будете понимать, как оно все работает. Только потом уже переходите к использованию 10 чужих подпрограмм и бога ради относитесь ко всяким исходникаи их интернету скептически. Я все, что Вы выложили просто не читал, но так взглядом зацепился за шедевр безвестного "мастера" install_irq(). Ну хотя-бы так.
Код
DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority )
{
/*
Ненужности
DWORD *vect_addr;
DWORD *vect_cntl;
*/

/* Сначала запретили, потом думать начали :(
VICINTENCLEAR = 1 << IntNumber; // Disable Interrupt
*/
  if ( IntNumber >= VIC_SIZE )
  {
    return ( FALSE );
  }
  else
  {
    VICINTENCLEAR = 1 << IntNumber; /* Disable Interrupt */
// А об этом забыли :(, мелочь, но при перепрограмировании может вылезти боком
    VICINTSELECT &= (~(1<<IntNumber));     // Classifies as IRQ

// Мрачновато :(
// DWORD *vect_addr;
// DWORD *vect_cntl;
//    /* find first un-assigned VIC address for the handler */
//    vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber*4);
//    vect_cntl = (DWORD *)(VIC_BASE_ADDR + VECT_CNTL_INDEX + IntNumber*4);
//    *vect_addr = (DWORD)HandlerAddr;  /* set interrupt vector */
//    *vect_cntl = Priority;

// На Cи это пишется так

    *(DWORD *)(&VICVECTADDR0     + inum) = (DWORD)HandlerAddr;
    *(DWORD *)(&VICVECTPRIORITY0 + inum) = Priority;


    VICINTENABLE = 1 << IntNumber;  /* Enable Interrupt */
    return( TRUE );
  }
}


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
mempfis_
сообщение Jun 4 2009, 19:49
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Переписал интсалляцию IRQ (после прочтения документации на VIC-контроллер интуитивно определил регистры которые нужно инициализировать).
К сожалению эхо не возвращается (c putchar/getchar эхо рботает).

Код
DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority )
{
  //очищаем все программные прерывания (ну на всякий случай)
  VICSOFTINTCLEAR = 0xffffffff;
  
  //перед изменением запрещаем соотв. прерывание
  VICINTENCLEAR = (1<<IntNumber);
  
  //определяем соотв. прерывание как IRQ
  VICINTSELECT &= ~(1<<IntNumber);
  
  //устанавливаем приоритет прерывания
  *(DWORD *)(&VICVECTPRIORITY0 + IntNumber) = Priority&0xF;
  
  //сохраняем адрес прерывания
  *(DWORD *) (&VICVECTADDR0 + IntNumber) = (DWORD) HandlerAddr;

  //разрешаем соотв прерывание
    VICINTENABLE = (1 << IntNumber);  /* Enable Interrupt */
    return( TRUE );
}


P.S. чтож тут так всё сложно и запутанно sad.gif
ATmeg-у освоил за неделю. А с ARM столько проблем...
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 4 2009, 20:20
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(mempfis_ @ Jun 4 2009, 22:49) *
Переписал интсалляцию IRQ (после прочтения документации на VIC-контроллер

Теперь читайте документ на UART в части инициализации его, как источника прерываний. Заодно подумайте, какие источники прерываний от UART Вам нужны.
P.S.
Останется только глобально разрешить прерывания контролеру и как минммум один раз в обработчик попадете smile.gif
Цитата
P.S. чтож тут так всё сложно и запутанно
ATmeg-у освоил за неделю. А с ARM столько проблем...

Если только под "столько проблем" подразумевается скопипастил какой-то исходник и он заработал, а для другого контроллера не заработал....
А вообще LPC периферия, как и ядро, весьма проста и функциональна, а UART вообще (как и I2C) вообще избитая классика smile.gif
Код
__irq __arm  void uart_isr( void )
{
int ch;

    while( !((ch = (U0IIR&IIR_MASK)) & IIR_IP) )        // Check Pending Bit
    {
        // What caused the interrupt?
        switch( ch )
        {

        case IIR_THRE:    // The THRE+TEMPT+FIFO is empty. If there is another
                        //    characters in the TX buffer, load its now to FIFO->THRE.
            break;

        case IIR_RX_TIMEOUT:
           case IIR_RX:

            ch = U0RBR;

//.....
            U0THR = ch;    // Echo

        break;

    default:
                          ;


    }
    // Clear the ISR in the VIC.
       VICAddress = 0;
}


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jun 4 2009, 20:27
Сообщение #5


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(mempfis_ @ Jun 4 2009, 23:49) *
P.S. чтож тут так всё сложно и запутанно sad.gif
ATmeg-у освоил за неделю. А с ARM столько проблем...

Боюсь спросить... rolleyes.gif но все же спрошу, а прерывания в самом АРМ ядре вы не забыли включить ?
Настройка VIC это конечно хорошо, но если прерывания запрещены то можно было и не настраивать smile.gif
Go to the top of the page
 
+Quote Post
mempfis_
сообщение Jun 5 2009, 05:47
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Про UART0 я прочитал в самую первую очередь. Он у меня даже работает (без прерываний) smile.gif
To zltigo спасибо за код и по VIC и по UART.

To zltigo and singlskv по поводу глобального разрешения прерываний - встроенноя в иар функция __enable_interrupt() позволяет это сделать? Или это необходимо делать вручную например так CPSR |=(1<<I) ?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 5 2009, 07:23
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(mempfis_ @ Jun 5 2009, 08:47) *
Он у меня даже работает (без прерываний) smile.gif

Это давно понятно, а прерывания генерить UART разрешено-то?
Код
    // Setup the divisor.
    U0LCR |= LCR_DLAB;
    U0DLL = (uchar)( divisor );
    U0DLM = (uchar)( divisor >> 8 );
    // Turn on the FIFO's and clear the buffers.
    U0FCR = FCR_FCRE|FCR_CLEAR_FIFO;
    // Setup transmission format.
    U0LCR = LCR_NO_PARITY|LCR_1STOP_BIT|LCR_8BIT_CHARS;
    install_irq( VIC_UART0, (void *)uart_isr, VIC_UART0_PRIOR );
    // Enable UART0 interrupts
    U0IER = IER_RDAIE|IER_THREIE;

Цитата
__enable_interrupt() позволяет это сделать?

Разумеется да,тем более, что руками могут и не дать.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
mempfis_
сообщение Jun 5 2009, 07:34
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



В моём коде настройки UART есть такая строчка:
Код
U0IER = RBR_IE | THRE_IE | IER_RLS; /* Enable UART0 interrupt */


Проверю может чтото с битами напутал.
Спасибо за ответы, вечером буду со всем этим разбираться smile.gif
Go to the top of the page
 
+Quote Post
alvy
сообщение Jun 5 2009, 08:42
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 67
Регистрация: 8-05-09
Из: Томск
Пользователь №: 48 809



Цитата(mempfis_ @ Jun 5 2009, 14:34) *
В моём коде настройки UART есть такая строчка:
Код
U0IER = RBR_IE | THRE_IE | IER_RLS; /* Enable UART0 interrupt */


Это разрешение прерываний уарта. Для того, чтобы они срабатывали должен быть выставлен флаг глобального разрешения прерываний - так же как и в атмегах.

А не по теме: перестал пользоваться примерами от IAR'а вообще - действительно проще все самому написать, да хорошенько снабдить комментариями, чтобы потом ничего не забыть

Сообщение отредактировал alvy - Jun 5 2009, 08:46
Go to the top of the page
 
+Quote Post
mempfis_
сообщение Jun 7 2009, 09:53
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Разобрался в чём было дело smile.gif
Программа упорно не хотеля входить в прерывание хотя в основном цикле крутилась.
Перелопатил весь код не нашёл ничего подозрительного. Посмотрел в книге Мартина Тревора организацию векторного прерывания и заметил что в стартапе для исключительной ситуации IRQ необходимо заносить адрес вектора прерывания из VIC. Начал копать в эту сторону и выяснил что адрес VIC-контроллера LPC2468 отличается от адреса в LPC21xx. И в стартапе поменялась строчка с LDR PC,[PC,#-0xFF0] на LDR PC,[PC,#-0x0120] (там где определён вектор для IRQ).
Вобщем после подключения корректного стартапа из примера для LPC2468 заработал мой код для UART0.

Всем спасибо за консультации smile.gif Разобрался в регистрах UART0, в том как он работает, как создавть векторные прерывания и как их обслуживать smile.gif
Буду дальше разбираться с этим чудом техники smile.gif
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 11:08
Рейтинг@Mail.ru


Страница сгенерированна за 0.01555 секунд с 7
ELECTRONIX ©2004-2016