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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> LPC_UART (550-совместимый)
_Артём_
сообщение Sep 16 2012, 22:02
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Вечер добрый.

Пытаюсь посылать данные через UART, использую fifo.
Непонятно как правильно это делать.
Код
extern "C" void UART_IRQ_Handler()
{
    LedBlink();
}

volatile uint16_t index;
const uint8_t TestStr[]="0123456789\n";
void main()
{
    InitUART();
    LPC_UART->IER=1<<LPC_UART_IER_THRE;
    NVIC_EnableIRQ(UART_IRQn);
    for (index=0; TestStr[index]; index++)
        LPC_UART->THR=TestStr[index];
    while (1);
}


Поставил breakpoint в UART_IRQ_Handler, программа попала в него, когда данные уже пришли в терминал.

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

Попытка записывать данные в THR и проверять состояние флага LSR.THRE приводит к тому, что посылается только 1 байт - буфер не пуст, если в нём есть хотя бы 1 байт. Получается нет нормальной индикации, того что есть ещё место в буфере?

Нет ли у кого-нибудь примера передачи с использованием FIFO и прерываний?

Спасибо.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 17 2012, 06:12
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Ну вот такой этот УАСПП загадочный, хотя zltigo нравится. Да, для начала передачи надо положить байт в THR. И увеличить счетчик на 1. Если счетчик меньше глубины FIFO, то можно докладывать данные. Если обнаружили LSR.THRE - счетчик сбрасываем на 0. Ну нету у него флага fifo.not_full, есть только empty. Где-то тут было обсуждение, где zltigo объяснял прелести этого, но не убедил.

Добавлено: нашел раз и два


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Sep 17 2012, 06:31
Сообщение #3


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (Сергей Борщ @ Sep 17 2012, 14:12) *
Да, для начала передачи надо положить байт в THR.

Да, часик помучался, пока смог отправить пакет через прерывания) Сейчас уже недельку стабильно работает прием и передача по прерываниям. Этот момент, ИМХО, в документации мутновато отражен. Но если прочитать несколько раз, то доходит rolleyes.gif rolleyes.gif rolleyes.gif


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 17 2012, 14:42
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Спасиба за ссылки.

В первом приближении получился такой код
Код
#define TX_FIFO_SIZE 128
struct TUartTxBuffer {
    volatile uint8_t TxBuffer[TX_FIFO_SIZE];
    volatile uint8_t TxNext;
    volatile uint8_t TxFirst;
    volatile int8_t IntEnabled;
    INLINE_FUNCTION    void Send_Handler() {
        uint32_t iir=LPC_UART->IIR;
        uint8_t tx_next=TxNext, tx_first=TxFirst;
        uint_fast8_t fifo_free_size=16;
        while (tx_next!=tx_first && fifo_free_size) {
            LPC_UART->THR=TxBuffer[tx_first++];
            fifo_free_size--;
            if (tx_first==TX_FIFO_SIZE)
                tx_first=0;
        }
        TxFirst=tx_first;
        if (tx_next==tx_first) {
            LPC_UART->IER=0;
            IntEnabled=0;
        }
    }
    void SendBuffer(const uint8_t *data_for_send, uint8_t byte_count);
};
void TUartTxBuffer::SendBuffer(const uint8_t *data_for_send, uint8_t byte_count) {
    uint8_t tx_next=TxNext;
    for (uint_fast8_t i=0; i<byte_count; i++) {
        TxBuffer[tx_next++]=*data_for_send++;
        if (tx_next>=TX_FIFO_SIZE)
            tx_next=0;
    }
    NVIC_DisableIRQ(UART_IRQn);
    TxNext=tx_next;
    if (IntEnabled==0) {
        uint8_t tx_first=TxFirst;
        LPC_UART->THR=TxBuffer[tx_first++];
        if (tx_first==TX_FIFO_SIZE)
            tx_first=0;
        TxFirst=tx_first;
        LPC_UART->IER=1<<LPC_UART_IER_THRE;
        IntEnabled=1;
    }
    NVIC_EnableIRQ(UART_IRQn);
}
TUartTxBuffer UartTxBuffer;
extern "C" void UART_IRQ_Handler()
{
    UartTxBuffer.Send_Handler();
}

Вроде работает.
Go to the top of the page
 
+Quote Post
SII
сообщение Sep 17 2012, 15:10
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 549
Регистрация: 13-07-10
Из: Солнечногорск-7
Пользователь №: 58 414



Цитата(_Артём_ @ Sep 17 2012, 02:02) *
Получается, что нужно в основной программе послать хотя бы один байт в THR, чтобы возникло прерывание по опустошению буфера передачи?


По моему опыту выходит так, что запрос прерывания по наличию места в буфере передачи выдаётся не по самому факту наличия свободного места, а лишь по факту завершения передачи очередного байта из буфера. Таким образом, если разрешить прерывания при заведомо пустом буфере, прерывание так и не произойдёт -- передачи-то не было; однако, если разрешить прерывание и после этого пихнуть в буфер хотя бы один байт -- произойдёт, когда он будет передан (или когда будет переписан из буфера в сдвиговый регистр передатчика).

Лично у меня впечатление, что изначальной причиной такого странного поведения послужила аппаратная ошибка, которую не заметили и растиражировали, а дальше тянут из-за совместимости. Ведь куда логичней, если прерывание по наличию места будет "висеть" постоянно, пока в буфере есть хотя бы один свободный байт и само это прерывание разрешено.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Sep 17 2012, 15:56
Сообщение #6


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (SII @ Sep 18 2012, 00:10) *
Ведь куда логичней, если прерывание по наличию места будет "висеть" постоянно, пока в буфере есть хотя бы один свободный байт и само это прерывание разрешено.

В AVR, например, так и сделано. Нужно что-то передать - подготовил буфер, разрешил прерывание "по пустому FIFO", и все. Буфер передался. А по завершению передачи последнего байта прерывание можно выключить...


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 17 2012, 19:08
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(SII @ Sep 17 2012, 18:10) *
По моему опыту выходит так, что запрос прерывания по наличию места в буфере передачи выдаётся не по самому факту наличия свободного места, а лишь по факту завершения передачи очередного байта из буфера.

Похоже так, только не очередного, а последнего байта. И байт при этом уже передался в RS (программно можно RS485 делать).


Цитата(SII @ Sep 17 2012, 18:10) *
Таким образом, если разрешить прерывания при заведомо пустом буфере, прерывание так и не произойдёт -- передачи-то не было;

Выглядит именно так.

Цитата(SII @ Sep 17 2012, 18:10) *
По моему опыту выходит так, что запрос прерывания по наличию места в буфере передачи выдаётся не Лично у меня впечатление, что изначальной причиной такого странного поведения послужила аппаратная ошибка, которую не заметили и растиражировали

Может быть.

Цитата(haker_fox @ Sep 17 2012, 18:56) *
В AVR, например, так и сделано. Нужно что-то передать - подготовил буфер, разрешил прерывание "по пустому FIFO", и все. Буфер передался. А по завершению передачи последнего байта прерывание можно выключить...

Не только в АВР так сделано, думаю.
Но в общем работает, зато писать можно не байт как в АВР, а аж 16.

Go to the top of the page
 
+Quote Post
haker_fox
сообщение Sep 17 2012, 23:39
Сообщение #8


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (_Артём_ @ Sep 18 2012, 04:08) *
Но в общем работает, зато писать можно не байт как в АВР, а аж 16.

В AVR FIFO двухуровневый)
Кстати, Вы так и делаете (я имею ввиду по прерыванию THRE сразу 16 байт отправляете)? rolleyes.gif Работает? rolleyes.gif Я пока машинально на каждый байт прерывание дергаю, на скорую руку писал обработчик)

Обработчик в контексте scmRTOS, но думаю, не суть важно...
CODE
OS_INTERRUPT void uart0ISRHandler()
{
    OS::TISRW ISRW;
    uint32_t iir;

    // While there are pending interrupts
    while( !( ( iir = U0IIR ) & 1 ) )
    {
        switch( ( iir >> 1 ) & 7UL )
        {
        case 2:
            // Receive data available
        case 6:
            // CTI
            rx_isr_byte = U0RBR;
            getPacketEF.signal_isr();
            break;

        case 1:
            // THRE Interrupt
            U0THR = *pOutBuffer++;
            if( pOutBuffer == pEndBuffer )
            {
                // Disable THRE Interrupt
                U0IER &= ~THRE_IE;
                pOutBuffer = outBuffer;
                sendFinishedEF.signal_isr();
            }
            break;
        }
    }

    IRQ_DONE();
}

Но это, конечно, у меня не оптимальный вариант. Создавался как тестовый вариант разбора полетов с USART ISR...


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 18 2012, 07:05
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Вот мои страх и ужас (которые, как известно, всего лишь спутники Марса - Демос и Фобос). Да, использую FIFO. Но насколько все это можно было бы написать проще, если бы был флаг "FIFO не полное"...

CODE
template<uint_fast8_t rx_size, uint_fast8_t tx_size>
void buffered_uart<rx_size, tx_size>::send(uint8_t byte)
{
    TCritSect cs;
    if(!Tx_buffer.get_count())
    {
        uint_fast8_t FIFO_counter_cache = Tx_fifo_counter;
        if(pUART->LSR & UART_LSR_THRE)    // FIFO empty
            FIFO_counter_cache = 0;

        if(FIFO_counter_cache < 16)
        {
            if(pUART->LSR & UART_LSR_THRE)    // FIFO empty
                FIFO_counter_cache = 0;
            pUART->THR = byte;
            Tx_fifo_counter = FIFO_counter_cache + 1;
            return;
        }
    }
    Tx_buffer.push(byte);
    pUART->IER = UART_IER_RBRINT_EN | UART_IER_THREINT_EN;
}

template<uint_fast8_t rx_size, uint_fast8_t tx_size>
void buffered_uart<rx_size, tx_size>::send(char const* string)
{
    TCritSect cs;
    if(!Tx_buffer.get_count())
    {
        uint_fast32_t FIFO_counter_cache = Tx_fifo_counter;
        if(pUART->LSR & UART_LSR_THRE)    // FIFO empty
            FIFO_counter_cache = 0;
        while(FIFO_counter_cache < 16)
        {
            char c = *string++;
            if(!c)
            {
                Tx_fifo_counter = FIFO_counter_cache;
                return;
            }
            if(pUART->LSR & UART_LSR_THRE)    // FIFO empty
                FIFO_counter_cache = 0;

            pUART->THR = c;
            ++FIFO_counter_cache;
        }
        Tx_fifo_counter = FIFO_counter_cache;
    }

    while(char c = *string++)
    {
        Tx_buffer.push(c);
        pUART->IER = UART_IER_RBRINT_EN | UART_IER_THREINT_EN;
    }
}

template<uint_fast8_t rx_size, uint_fast8_t tx_size>
void buffered_uart<rx_size, tx_size>::handler()
{
    uint_fast32_t Tmp = pUART->IIR;
    while (!(Tmp & UART_IIR_INTSTAT_PEND))
    {
        switch((Tmp & UART_IIR_INTID_MASK) >> 1)
        {
        case UART_IIR_INTID_CTI >> 1:
        case UART_IIR_INTID_RDA >> 1:
            while (pUART->LSR & UART_LSR_RDR)       // while bytes in RX FIFO
            {
                uint8_t Data = pUART->RBR;          // read anyway
                if(Rx_buffer.get_free_size())
                    Rx_buffer.push(Data);           // if overflow - sorry
            }
            break;

        case UART_IIR_INTID_THRE >> 1:              // Tx interrupt
            {
                uint_fast16_t Queued_bytes = Tx_buffer.get_count();
                if(Queued_bytes)
                {
                    if(Queued_bytes > 16)
                        Queued_bytes = 16;
                    do
                    {
                        uint8_t Data;
                        Tx_buffer.pop(Data, 1);
                        pUART->THR = Data;
                    }
                    while(--Queued_bytes);
                    Tx_fifo_counter = Queued_bytes;
                }
                else
                {
                    Tx_fifo_counter = 0;
                    pUART->IER = UART_IER_RBRINT_EN;

                }
            }
            break;

        case UART1_IIR_INTID_MODEM >> 1:
        case UART_IIR_INTID_RLS >> 1:             // Rx error (OE, PE, FE)
        default:
                break;
        }
        Tmp = pUART->IIR;
    }
}


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 18 2012, 12:30
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(haker_fox @ Sep 18 2012, 02:39) *
В AVR FIFO двухуровневый)

Ну, это он двухуровневый, пока в него не пишешь долго, а потом всё равно в прерывании по одному байту пишешь.


Цитата(haker_fox @ Sep 18 2012, 02:39) *
Кстати, Вы так и делаете (я имею ввиду по прерыванию THRE сразу 16 байт отправляете)? rolleyes.gif Работает? rolleyes.gif Я пока машинально на каждый байт прерывание дергаю, на скорую руку писал обработчик)

Работоспособность буфера сомнений не вызывает.

Цитата(haker_fox @ Sep 18 2012, 02:39) *
IRQ_DONE();

P.S. А это кто? IRQ_DONE в смысле.

Цитата(Сергей Борщ @ Sep 18 2012, 10:05) *
Да, использую FIFO. Но насколько все это можно было бы написать проще, если бы был флаг "FIFO не полное"...

Спасибо за пример.

Да уж, трёхэтажно получилось, а всего лишь бит незаполненности фифо зажали.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Sep 18 2012, 13:40
Сообщение #11


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (_Артём_ @ Sep 18 2012, 21:30) *
P.S. А это кто? IRQ_DONE в смысле.

А это VICVectAddr = 0 в данном случае. Просто инлайн-функция операционной системы.

А отправка и прием организованы примерно так
CODE
void sendBuffer()
{
    pEndBuffer = pOutBuffer;
    pOutBuffer = outBuffer;

    U0THR = *pOutBuffer++;
    sendFinishedEF.clear();
    // Enable THRE interrupt
    U0IER |= THRE_IE;
    sendFinishedEF.wait();

    getPacketEF.clear();
}

bool wakePHYGet( uint8_t* byte )
{
    if( !getPacketEF.wait( FWAKE_ONE_BYTE_RX_TIMEOUT ) )
        return false;

    *byte = rx_isr_byte;
    return true;
}


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 18 2012, 13:50
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(haker_fox @ Sep 18 2012, 16:40) *
А это VICVectAddr = 0 в данном случае. Просто инлайн-функция операционной системы.

Оно на выходе каждого прерывания вызывается?
Если так, то что бы его не запихнуть в ~TISRW?
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Sep 18 2012, 14:35
Сообщение #13


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (_Артём_ @ Sep 18 2012, 22:50) *
Оно на выходе каждого прерывания вызывается?
Если так, то что бы его не запихнуть в ~TISRW?

Да, на выходе каждого. Наверно можно. Это нужно у авторов операционной системы консультироваться)

Поскольку у меня полудуплекс, и более, чем 16 байт за раз не передается, то сделал в прерывании совсем просто
CODE
        case 1:
            // THRE Interrupt
            while( pOutBuffer < pEndBuffer )
                U0THR = *pOutBuffer++;

            // Disable THRE Interrupt
            U0IER &= ~THRE_IE;
            pOutBuffer = outBuffer;
            sendFinishedEF.signal_isr();
            break;

Вроде полет нормальный)


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
pitt
сообщение Oct 21 2012, 16:23
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672



К моему глубокому сожалению, ожидаю ту же проблему (прерывание по фронту, а не поуровню) с CAN sad.gif. Похоже это ТМ Phillips.
http://electronix.ru/forum/index.php?showt...p;#entry1104240

Сообщение отредактировал pitt - Oct 21 2012, 16:23


--------------------
Прокричал немой глухому:"...Спасибо за внимание!"
http://www.youtube.com/watch?v=3Nnj4ky4Z_g
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Oct 21 2012, 18:31
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(pitt @ Oct 21 2012, 19:23) *
ожидаю ту же проблему (прерывание по фронту, а не поуровню) с CAN sad.gif.

Не знаю, как там с lpc17 с CAN, но с UART-ом проблема не в прерываниях, а в некотором неудобстве работы с ним из-за отсутствия флага, показывающего что FIFO не до конца заполнено.
Это решается добавлением в программу пары десятков строк (ну может чуть больше).

Цитата(pitt @ Oct 21 2012, 19:23) *
Похоже это ТМ Phillips.

Думаете у других производителей будет качественно лучше? Скажите тогда кто эти производители.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 15:17
Рейтинг@Mail.ru


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