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

 
 
 
Reply to this topicStart new topic
> USART2(приём по прерывании RXNE)+USART3(DMA на передачу), STM32F2+FreeRTOS
Volldemar
сообщение Jun 21 2016, 11:28
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342



Прошу помощи у сообщества.
Понимаю, что тема избитая, перечитал, что нашёл на этом форуме, но увы, не работает как задумано.
Вкратце алгоритм работы такой:
- приём из USART2 работает по прерыванию RXNE в массив;
- по прерыванию IDLE определяю, что приём закончен и переключаю на второй массив (что бы первый неспешно обработать, в данной реализации, для отработки алгоритма, просто выдать в USART3);
- накопленный массив выдаю в USART3 по DMA.

И вот тут грабли, выдача происходит рваная:
Код
$GPGGA,111415.00,4952.1238,E,1,11,01.2,120.4,M,26.7,M,SV,00,40,29,15018*79
$GLGSV,231,73,65,152,38,14,040,35*66
$GLGSV,2,2,06,83,720,32*66
$GNGSA,29,32,,,,,,,01.$GNGSA,A,3,83,73,0
                                        $PORZD,A,004.1*39
1A
$PORZD,A,004.1*39
$GPGGA,111417.00,49,M,,*55
$GPRMC,111417.00,A,4912.361,8
$GPGSV,3,28*,00,40,29,1501806,66,10,006,,1,29,38,240,37,18,235,00,37,33,1V,2
,2,06,83,720,32*66
$GNGSALG,32,,,,,,,01.$GNGSA,A,3,83,73,2938
.0*38
0,038,39,84,50,2,A,3,02,06,12,259,01.,M,,*5A
$GPRMC,111418.00,A,4912.3692,N,03152.1238,E,00.00,000.5,210616,,,A*58
$GPGSV,3,1,10,02,54,108,36,06,31,051,33,12,75,081,38,25,61,300,38*7E
$GPGSV,3,2,10,29,38,240,37,32,14,274,31,33,18,235,00,37,33,193,00*7E
$GPGSV,3,3,10,39,33,189,00,40,29,150,00*79
$GLGSV,2,1,06,66,10,006,30,73,65,152,38,75,05,323,01,82,14,040,34*66
$GLGSV,2,2,06,83,70,038,38,84,50,220,31*64
$GNGSA,A,3,02,06,12,25,29,32,,,,,,,01.9,01.2,01.5*19
$GNGSA,A,3,83,73,84,82,66,,,,,,,,01.9,01.2,01.5*1A
$PORZD,A,004.0*38

а теперь код, собственно как это всё у меня реализовано:
Код
//=============================================================================
    if ( USART_GetITStatus ( USART2, USART_IT_IDLE ) == SET )
    {
        DMA_Cmd ( DMA1_Stream3, DISABLE );

        USART_ReceiveData ( USART2 );// сброс PE,FE,NE,ORE,IDLE bits in USART_SR

        if ( BufIDLE.currentBuf == buf1 )
        {
            BufIDLE.currentBuf = buf2;
        }
        else
        {
            BufIDLE.currentBuf = buf1;
        }

        xSemaphoreGiveFromISR ( xSemaphore_usart2IDLE, &xHigherPriorityTaskWoken );
    }

//=============================================================================
    if ( USART_GetITStatus ( USART2, USART_IT_RXNE ) == SET )
    {
        ISRcChar2 = ( uint8_t ) ( ( USART_ReceiveData ( USART2 ) ) & (uint8_t)0xFF );

        if ( BufIDLE.currentBuf == buf1 )
        {
            BufIDLE.buf1 [BufIDLE.buf1_idx++] = ISRcChar2;
        }
        else
        {
            BufIDLE.buf2 [BufIDLE.buf2_idx++] = ISRcChar2;
        }
    }

void DMA1_Stream3_IRQHandler ( void )
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    /* Test on DMA Stream Transfer Complete interrupt */
    if ( DMA_GetITStatus ( DMA1_Stream3, DMA_IT_TCIF3 ) == SET )
    {
        /* Clear DMA Stream Transfer Complete interrupt pending bit */
        DMA_ClearITPendingBit ( DMA1_Stream3, DMA_IT_TCIF3 );

        DMA_Cmd ( DMA1_Stream3, DISABLE );

        xSemaphoreGiveFromISR ( xSemaphore_usart3TX, &xHigherPriorityTaskWoken );
    }
}

задача, выдающая в юсарт3:
Код
void EchoTask_usart2 ( void *pvParameters )
{
#define size_local buf_SIZE

    uint8_t *USART2_Buf_local;

    USART2_Buf_local = pvPortMalloc ( size_local );

    uint16_t USART2_Idx_local = 0;

    for(;; )
    {
        xSemaphoreTake ( xSemaphore_usart2IDLE, portMAX_DELAY );

//обнуляем локальный буфер
        memset ( USART2_Buf_local, 0, size_local );
        USART2_Idx_local = 0;

        if ( BufIDLE.currentBuf == buf1 )
        {
            USART2_Idx_local = BufIDLE.buf2_idx;
            memcpy ( USART2_Buf_local, BufIDLE.buf2, USART2_Idx_local );
            memset ( BufIDLE.buf2, 0, buf_SIZE );
            BufIDLE.buf2_idx = 0;
        }
        else
        {
            USART2_Idx_local = BufIDLE.buf1_idx;
            memcpy ( USART2_Buf_local, BufIDLE.buf1, USART2_Idx_local );
            memset ( BufIDLE.buf1, 0, buf_SIZE );
            BufIDLE.buf1_idx = 0;
        }

        xSemaphoreTake ( xSemaphore_usart3TX, portMAX_DELAY );

        DMA1toUSART3TX_Put ( USART2_Buf_local, USART2_Idx_local );
    }
}


Буду благодарен за конструктивные советы.
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Jun 23 2016, 09:16
Сообщение #2


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

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



Плохо задумано, к сожалению.

Idle - это пауза >= одному байту.
Я никогда не интересовался, как обстоят дела с паузами у GNSS приёмников, но предположим, что плохо - паузы могут быть в произвольный момент времени.

Например, приходят пакеты 10 байт, пауза, 2 байта, пауза.
Принимаем в буфер 1 10 байт (где проверка на переполнение, кстати?!), запускаем передачу. Принимаем в буфер 2 пару байт, запускаем передачу. Сколько чего отправилось из буфера 1, неизвестно - вероятнее всего, несколько байт уйти не успели.


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Jun 29 2016, 11:31
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342



Изменил приём по IDLE+DMA, приём не происходит, хотя в прерывание ИДЛЕ - заходит с каждым принятым фреймом данных. Количество принятых байтов вычисляю вот так:
Код
//            USART2IDLE2_Idx = buf_SIZE - DMA1_Stream5->NDTR;
            USART2IDLE2_Idx = buf_SIZE - DMA_GetCurrDataCounter ( DMA1_Stream5 );

Но USART2IDLE2_Idx - всегда нулевой, подскажите пожалуйста, где косяк?
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Jul 4 2016, 11:52
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342



Зашевелилось.
приём по ДМА+ИДЛЕ, передача ДМА.

В прерывании ИДЛЕ происходит переключение принимающих массивов, а в задаче выдачи уже копирование из накопленного массива, в в локальный массив, который уже выдаётся наружу.

Но к сожалению сбои не исчезли, что я делаю не так?
Код
void DMA1_Stream3_IRQHandler ( void )
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    /* Test on DMA Stream Transfer Complete interrupt */
    if ( DMA_GetITStatus ( DMA1_Stream3, DMA_IT_TCIF3 ) == SET )
    {
        /* Clear DMA Stream Transfer Complete interrupt pending bit */
        DMA_ClearITPendingBit ( DMA1_Stream3, DMA_IT_TCIF3 );

        DMA_Cmd ( DMA1_Stream3, DISABLE );

        xSemaphoreGiveFromISR ( xSemaphore_usart3TX, &xHigherPriorityTaskWoken );
    }
}

Код
if ( USART_GetITStatus ( USART2, USART_IT_IDLE ) == SET )
    {
        USART_ReceiveData ( USART2 );// сброс PE,FE,NE,ORE,IDLE bits in USART_SR

        DMA_Cmd ( DMA1_Stream5, DISABLE );

        if ( CurrentBuf == buf1 )
        {
            USART2IDLE1_Idx = buf_SIZE - DMA1_Stream5->NDTR;

            CurrentBuf = buf2;
        }
        else
        {
            USART2IDLE2_Idx = buf_SIZE - DMA1_Stream5->NDTR;

            CurrentBuf = buf1;
        }

        RxDMA1_Stream5 ();

        xSemaphoreGiveFromISR ( xSemaphore_usart2IDLE, &xHigherPriorityTaskWoken );
    }

Код
void EchoTask_usart2 ( void *pvParameters )
{
#define size_local 4096

    uint8_t USART2_Buf_local [ size_local ];

    volatile uint16_t USART2_Idx_local = 0;

    for(;; )
    {
        xSemaphoreTake ( xSemaphore_usart2IDLE, portMAX_DELAY );

//обнуляем локальный буфер
        memset ( USART2_Buf_local, 0, size_local );
        USART2_Idx_local = 0;

        if ( CurrentBuf == buf1 )
        {
            USART2_Idx_local = USART2IDLE2_Idx;

            memcpy ( USART2_Buf_local, USART2_Buf2_IDLE, USART2_Idx_local );

            memset ( USART2_Buf2_IDLE, 0, buf_SIZE );
            USART2IDLE2_Idx = 0;
        }
        else
        {
            USART2_Idx_local = USART2IDLE1_Idx;

            memcpy ( USART2_Buf_local, USART2_Buf1_IDLE, USART2_Idx_local );

            memset ( USART2_Buf1_IDLE, 0, buf_SIZE );
            USART2IDLE1_Idx = 0;
        }

        xSemaphoreTake ( xSemaphore_usart3TX, portMAX_DELAY );

        DMA1toUSART3TX_Put  ( USART2_Buf_local, USART2_Idx_local );
    }
}
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Jul 4 2016, 16:55
Сообщение #5


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

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



Почитал-почитал, и ничего не понял.

Я бы сделал:
- буфер FIFO с методами Put(байт) и Get(байт).
- прерывание Usart2_RXNE, которое делает Put()
- прерывание Usart3_TXE, которое делает Get()

Дальше немного магии с разрешением прерывания от уарта3:
- в обработчике Usart3_TXE, если FIFO пустой, TXE выключаем;
- в обработчике Usart2_RXNE всегда включаем TXE

И никаких переливаний из пустого в порож..., простите, я хотел сказать "никаких memcpy".
Ах, да, freertos'а в моём решении тоже нет :-)


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Jul 4 2016, 19:15
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342



Цитата(esaulenka @ Jul 4 2016, 19:55) *
Почитал-почитал, и ничего не понял.

Я бы сделал:
- буфер FIFO с методами Put(байт) и Get(байт).
- прерывание Usart2_RXNE, которое делает Put()
- прерывание Usart3_TXE, которое делает Get()

Дальше немного магии с разрешением прерывания от уарта3:
- в обработчике Usart3_TXE, если FIFO пустой, TXE выключаем;
- в обработчике Usart2_RXNE всегда включаем TXE

И никаких переливаний из пустого в порож..., простите, я хотел сказать "никаких memcpy".
Ах, да, freertos'а в моём решении тоже нет :-)

По прерываниям RXNE+TXE у меня работает, но задача состоит в том, что бы не прерываться на каждый принятый байт, а всю посылку целиком принять. Псоле приёма неспешно обработать и выдать в другой порт тоже по ДМА, так как есть ещё чем занятся процессору, да и скорости в 921600 бод тоже к этому подталкивают.
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Jul 6 2016, 08:53
Сообщение #7


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

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



Ну хорошо, решение на DMA. Но с тем же FIFO.

- настраиваем DMA на приём USART2 в circular mode, постоянно складывать данные в буфер. Этот DMA будет работать вечно.
- делаем в FIFO указатель put (из регистра приёмного DMA->NDTR) и указатель get (программный).
- делаем функцию запуска DMA на передачу в USART3. Надо рассмотреть два варианта: put "впереди" get - обычная передача, и get впереди put - буфер "закольцевался", надо передать данные двумя кусочками.
- периодически проверяем, что указатели FIFO не равны, и запускаем передающий DMA (если не запущен). Простейший вариант - по таймауту (не более времени заполнения FIFO). Более сложно - по флагам из прерываний "Tx DMA complete" и "Rx Idle".

А манипуляции аж с тремя буферами выглядят странно...
И опрос NDTR надо вылечить. Как-то очень подозрительно, что туда пишется USART2_Idx_local (который всегда разный, но меньше buf_SIZE), а читается всегда buf_SIZE.


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 19th July 2025 - 07:48
Рейтинг@Mail.ru


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