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

 
 
> stm32 DMA в режиме DMA_Mode_Normal, как перезапустить запись?
klen
сообщение Jul 6 2011, 07:43
Сообщение #1


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



здравствуйте.
столькнулся с тем что не понимаю как это работает.
настроенный dma канал читает данные с уарта в буффер озу в режиме DMA_Mode_Normal.
после заполнения буфера как и положено становится как вкопаный. указатель позиции соответствует размеру буфера.
как сказать ему чтоб он повторил действие. сброс указателя позиции и включение и выключение уарта и самого канала dma не приводит к началу записи в буфер.
он явно чтото друго ждет от меня

спасибо
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
prm
сообщение Jul 6 2011, 08:06
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 4-04-07
Пользователь №: 26 760



Обычно описанные действия помогают. Может проще использовать DMA в режиме записи по кольцу, организовав тем самым подобие двойного буфера?

В своем проекте использую FreeRTOS. Сделал отдельную задачу на прием информации по УАРТ. В обработчике прерывании от DMA в очередь событий (создаю отдельно) помещаю код возникшего события (буфер заполнен на половину, заполнен полностью, ошибка). В задаче приема вызываю xQueueReceive(..., ..., таймаут_ожидания_окончания_передачи). Если событие принято, обрабатываю данные буфера, запоминаю смещение (первая/вторая половина буфера, зависит от кода события). Если событие не принято (xQueueReceive завершилась по таймауту), определяю количество принятых байт с момента возникновения последнего события (знаю смещение в буфере, знаю сколько еще пришло DMA_GetCurrDataCounter(...)) и снова обрабатываю буфер.

Код
//============================================================================
/// Задача по приему данных от USART_DBG
//=============================================================================
void vDebugReceive(void *pvParameters)
{
    const portTickType  xTicksToWait = USART_DBG_RX_TIMEOUT_MS / portTICK_RATE_MS;
    uint8_t             event_code;
    uint16_t            last_data_cnt = USART_DBG_RX_BUF_SIZE;
    uint16_t            cnt = 0;
    uint8_t             offset = 0;

    //вечный цикл
    for(;;)
    {
        // ожидаю прихода события (данные считаны либо таймаут)
        if( xQueueReceive(dbg_rx_events, &event_code, xTicksToWait) == pdPASS )
        {
            //получил событие
            switch(event_code)
            {
                case DBG_RX_HALF:
                {
                    // заполнена первая половина приемного буфера
                    for (; offset < (USART_DBG_RX_BUF_SIZE+1)/2; ++offset)
                        xQueueSendToBack(dbg_rx_data, (const void*)&dbg_in_buf[offset],0);

                    last_data_cnt = (USART_DBG_RX_BUF_SIZE+1)/2;
                    break;
                }
                case DBG_RX_FULL:
                {
                    // заполнена вторая половина приемного буфера
                    for (; offset < USART_DBG_RX_BUF_SIZE; ++offset)
                        xQueueSendToBack(dbg_rx_data, (const void*)&dbg_in_buf[offset],0);

                    // смещение на начало буфера
                    offset = 0;
                    last_data_cnt = USART_DBG_RX_BUF_SIZE;
                    break;
                }
                case DBG_RX_ERR:
                {
                    // произошла ошибка при приеме данных. Заново включаем канал DMA
                    DMA_Cmd(USART_DBG_Rx_DMA_Ch, ENABLE);
                    offset = 0;
                    break;
                }
            }
        }
        else
        {
            // проверяю, может пришла часть данных
            if ( last_data_cnt != DMA_GetCurrDataCounter(USART_DBG_Rx_DMA_Ch))
            {

                // т.к. счетчик в DMA декрементируется, то вычитаем из last_data_cnt
                cnt = last_data_cnt - DMA_GetCurrDataCounter(USART_DBG_Rx_DMA_Ch);

                for (; cnt && offset < USART_DBG_RX_BUF_SIZE; ++offset, --cnt)
                    xQueueSendToBack(dbg_rx_data,(const void*)&dbg_in_buf[offset],0);

                //ОБНУЛЯТЬ offset НЕЛЬЗЯ!!! Должно генерироваться прерывание по заполнению буфера
            }

            last_data_cnt = DMA_GetCurrDataCounter(USART_DBG_Rx_DMA_Ch);
        }
    }
}
Go to the top of the page
 
+Quote Post
klen
сообщение Jul 6 2011, 08:11
Сообщение #3


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



спасибо. так у меня работает с кольцом. но хочу соптимизировать. я знаю что момент когда точно прийдет пакет и заню его длинну. поэтому чтоб не анализировать состояние кольца хочется перед приходом пакета оп уарт включить на оду запись буфера канал dma. я также знаю момент времени когла он уже пришел без прерываний. хочу обработать пакет, и сново поставить канал dma запись следующего.
данные приходят четко и синхронно - на этом хочу выйграть в коде. только вот перезапустить канал дма на следующую запись не получается smile3046.gif
Go to the top of the page
 
+Quote Post



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

 


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


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