Jump to content

    
Sign in to follow this  
Lyrri

STM32 USB и FreeRTOS

Recommended Posts

Есть плата с STM32F207. USB используется как виртуальный com порт (точнее, эмуляция ft4232). Библиотека USB - стандартная USB-Host-Device_Lib_V2.0.0 от STM. При подключении к ПК устройство видится как 4 com порта, принимает данные и возвращает их в эхо-режиме. Все ок.

Запускаю FreeRTOS без использования USB. Для простоты создал одну задачу, которая каждую секунду сбрасывает в UART тестовую строку. Тоже все работает. Но при попытке обьединить эти два действия возникла проблема: при подключении по USB к ПК, та частьу программы, которая отвечает за обработку USB продолжает работать (поскольку там вся работа проходит в прерывании USB) а rtos падает где-то через 5 секунд после подключения.

После падения rtos, перестает сбрасываться тестовая строка в порт. Попытка остановится на брекпоинте в vApplicationIdleHook() тоже ни к чему не привела. vApplicationStackOverflowHook() переполнения не находит. Выделил по максимуму стека для idle и своей задачи - все равно не работает. Нашел описание подобной проблеммы на форуме STM. Там решение свелось к понижению приоритета прерывания USB ниже системного таймера. Попробовал у себя, хотя в прерывании USB не используются api вызовы rtos. Но и это не спасло отца русской демократии (((. И вот теперь назрело несколько вопросов:

1 Кто-нибуть использовал FreeRTOS совместно с usb device на stm32?

2 В какую сторону копать?

 

Share this post


Link to post
Share on other sites
2 В какую сторону копать?

Вытаскивать всю обработку USB из прерываний и загонять это в отдельную задачу/задачи.

В прерывания оставлять только формирование сообщений и (возможно) копирование принятых данных куда-нить в буферы.

Разбор всего добра вести только в задаче.

Суть - с применением RTOS в прерываниях только минимум работы и как можно быстрее, а всю остальную работу выполнять в фоне задач.

Задачи ессно просто ждуть неких событий, т.е. работают по событиям.

Share this post


Link to post
Share on other sites
Попробовал у себя, хотя в прерывании USB не используются api вызовы rtos.

В функциях EPx_Callback используются вызовы rtos? Эти функции вызываются из дебрей обработчика прерывания USB.

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

 

 

Share this post


Link to post
Share on other sites

А с приоритетами прерываний раобрались? Все грабли, которые я когда-либо собирал во FreeRTOS были из-за

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
и
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = (uint8_t)(configKERNEL_INTERRUPT_PRIORITY >> 4);

.

Точнее, из-за их отсутствия.

Share this post


Link to post
Share on other sites
В функциях EPx_Callback используются вызовы rtos?

В функциях EPx_Callback вызовы rtos не используются. Данные принятые от ПК отправляются обратно.

 

А с приоритетами прерываний раобрались?

При инициализации USB использую следующий код:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitStructure.NVIC_IRQChannel = OTG_HS_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 10;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

Поскольку вызовы rtos в прерывании не используются, приоритет прерывания выше чем

#define configMAX_SYSCALL_INTERRUPT_PRIORITY     191 /* equivalent to 0xb0, or priority 11. */

Мои рассуждения по поводу прерываний верны? Или я где-то ошибся?

Share this post


Link to post
Share on other sites

Нашел в чем проблема, может для кого-то будет актуально.

 

Как только производится запись в ненулевую IN endpoint (функция DCD_EP_Tx()), вызывается функция USB_OTG_EPStartXfer() и устанавливает

DREGS->DIEPEMPMSK в 1 для заданого endpoint. После этого, когда TX FIFO окажется пустым, получим прерывание "empty FIFO", флаг которого нигде в библиотеке не сбрасывается. В итоге получаем прерывание, обработчик которого выполняется постоянно.

 

Как исправить:

- в файле usb_dcd_init.c находим функцию DCD_WriteEmptyTxFifo()

- в этой функции находим следующие строки

ep->xfer_buff  += len;
ep->xfer_count += len;

- и после этих строк добавляем следующий код

if( ep->xfer_count >= ep->xfer_len){
        uint32_t fifoemptymsk = 1 << ep->num;
        USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0);
        break;
}

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this