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

 
 
 
Reply to this topicStart new topic
> 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
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
prm
сообщение Jul 6 2011, 08:26
Сообщение #4


Участник
*

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



Понял. Я подобным образом работаю с DS18b20. Вот рабочий кусок кода(лишнее можно выбросить, я подстраховался):

Код
    USART_Cmd(USART_DS18B20, DISABLE);
    //USART_DS18B20
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate            = 115200;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART_DS18B20, &USART_InitStructure);

    // конфигурирую DMA
    DMA_InitTypeDef DMA_InitStructure;

    DMA_DeInit(USART_DS18B20_Rx_DMA_Ch);
    DMA_InitStructure.DMA_PeripheralBaseAddr    = (uint32_t)&USART_DS18B20_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr        = (uint32_t)rx_data_buf;
    DMA_InitStructure.DMA_DIR                   = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize            = 1000;
    DMA_InitStructure.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc             = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize        = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode                  = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority              = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M                   = DMA_M2M_Disable;
    DMA_Init(USART_DS18B20_Rx_DMA_Ch, &DMA_InitStructure);

    DMA_DeInit(USART_DS18B20_Tx_DMA_Ch);
    DMA_InitStructure.DMA_PeripheralBaseAddr   = (uint32_t)&USART_DS18B20_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr       = (uint32_t)tx_data_buf;
    DMA_InitStructure.DMA_DIR                  = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize           = cnt;
    DMA_InitStructure.DMA_PeripheralInc        = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc            = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize   = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize       = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode                 = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority             = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M                  = DMA_M2M_Disable;
    DMA_Init(USART_DS18B20_Tx_DMA_Ch, &DMA_InitStructure);

    USART_ClearFlag(USART_DBG,USART_IT_TC);
    USART_Cmd(USART_DS18B20, ENABLE);
    USART_DMACmd(USART_DS18B20,           USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
    DMA_ITConfig(USART_DS18B20_Tx_DMA_Ch, DMA_IT_TC | DMA_IT_TE,             ENABLE);
    DMA_ITConfig(USART_DS18B20_Rx_DMA_Ch, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, DISABLE);

    // запускаю передачу
    DMA_Cmd(USART_DS18B20_Rx_DMA_Ch, ENABLE);
    DMA_Cmd(USART_DS18B20_Tx_DMA_Ch, ENABLE);

    // засыпаю до завершения передачи

    USART_Cmd(USART_DS18B20, DISABLE);
    DMA_Cmd(USART_DS18B20_Rx_DMA_Ch, DISABLE);
    DMA_Cmd(USART_DS18B20_Tx_DMA_Ch, DISABLE);

    DMA_ClearITPendingBit(DMA1_IT_GL2);
    DMA_ClearITPendingBit(DMA1_IT_GL3);
Go to the top of the page
 
+Quote Post
klen
сообщение Jul 6 2011, 08:32
Сообщение #5


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

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



и так пробывал - работает. но меня сильно напрягает что ВСЕ нада выключить и снова ПРОИНИТИТЬ и ВКЛЮЧИТЬ - этож бред. на мой вггляд достаточно былобы установить позицию записи сбросить флаг завершения передачи как сигнал того что нужно писать заново .....

если в се переинициализировать - это косяг, на это время тратится... наверно мы не понимаем как правильно. для передатчика я пробывал - кажется достаточно по окончании передачи сбросить разрешение работы для канала и сразу установить его и он зановов выдает буфер в переферию...... с приемником также должно быть по идее
Go to the top of the page
 
+Quote Post
prm
сообщение Jul 6 2011, 08:38
Сообщение #6


Участник
*

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



может тогда причина не в DMA, а в УАРТ? с другой периферией не пробовали?
Go to the top of the page
 
+Quote Post
klen
сообщение Jul 6 2011, 08:41
Сообщение #7


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

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



Цитата(prm @ Jul 6 2011, 12:38) *
может тогда причина не в DMA, а в УАРТ? с другой периферией не пробовали?

ну мне же уарт нужен wink.gif

с полной выключением переинициализацией и включением работает - но это явно через жёппу. если так работает у stm работает dma - то он хуже чем я думал, но не думаю что там дураки сидять.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 6 2011, 09:41
Сообщение #8


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Вот здесь вроде что-то по теме. (последний пост)
Вроде всё логично: отключили DMA, сбросили адрес и количество байт, запустили DMA.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
klen
сообщение Jul 6 2011, 11:07
Сообщение #9


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

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



коечто наковырял...
делать нада так;
1. выключить канал dma
2. записать в CNDTR размер буфера
3. включить dma

работает. может возникнуть вопрос а че я тут всем мозги парю? оказывается если по ходу работы отлачик остановится на точке прерывания - то! все отваливается. при отладке с остановами работаеттолько такой код:

1a. выключить uart
1. выключить канал dma
2. записать в CNDTR размер буфера
2.a записать CCR то что писалось при инициализации
3. включить dma
3a. включить uart

возможно это ревизия кристала такая или еще чтото но поведение меняется если отладчик останавливате и потом пускает процессор. ктонибудб знает как эту 'фичу' помножить на ноль?
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 9th August 2025 - 18:56
Рейтинг@Mail.ru


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