Перейти к содержанию
    

Продолжаю неспеша тупить с STM32. С Setup пакетами разобрался. Нужно вычитывать RX буфер сразу по приходу прерывания RXFLVL: RxFIFO non-empty.

Прикрутил свою либу верхнего уровня с реализованным протоколом USB CDC. Все работает за исключением обработки запроса от хоста SET LINE CODING.

 

В этом запросе две фазы.

Первая SETUP - хост присылает 8 байт собственно запрос.

Вторая DATA, где устройтсво должно принять собственно данные для установки порта - битрейт, четность и т.п. - 7 байт.

Принятие данных организовываю так же в прерывании RXFLVL. Читаю OTG_FS->GRXSTSP.

Количество байт - 7, статус - 0x02: /* OUT data packet received */. Все вроде четко. Вычитываю данные из FIFO, но вижу что данные не те, что нужно.

 

В чем подвох?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

OTG_FS_DOEPCTL0.EPENA установлен?

 

Прерывание по RXFLVL у меня построено сейчас вот так:

static void ISRH_RxFifoNonEmpty(void)
{
    UINT32 status = OTG_FS->GRXSTSP;    /* Get the Status from the top of the FIFO */
    UINT8 ep_num = ((status & OTG_FS_GRXSTSP_EPNUM_MSK) >> OTG_FS_GRXSTSP_EPNUM_POS);
    INT data_len = ((status & OTG_FS_GRXSTSP_BCNT_MSK) >> OTG_FS_GRXSTSP_BCNT_POS);
    g_EP_Desc[0].data_len = data_len;
    UINT8 packet_status = ((status & OTG_FS_GRXSTSP_PKTSTS_MSK) >> OTG_FS_GRXSTSP_PKTSTS_POS);
    
    switch(packet_status)
    {
        case 0x01:    /* Global OUT NAK (triggers an interrupt) */
            break;
                    
        case 0x02:    /* OUT data packet received */
            if(0 == ep_num)
            {
                USBD_CTRL_STATE usbd_state = USBD_DataOut();    /* Process the setup request parse */
                if(USBD_CTRL_STAGE_DATA_IN == usbd_state)    /* DATA_IN stage */
                    OTG_FS->DIEPEMPMSK |= (UINT32)1;    /* Enable TX FIFO empy intr. from EP0 */
            }
            break;
                
        case 0x03:    /*  OUT transfer completed (triggers an interrupt) */
            break;
        
        case 0x04:    /* SETUP transaction completed (triggers an interrupt) */
            break;
                
        case 0x06:    /* SETUP data packet received */
            if(0 == ep_num)
            {
                USBD_CTRL_STATE usbd_state = USBD_Setup();    /* Process the setup request parse */
                if(USBD_CTRL_STAGE_DATA_IN == usbd_state)    /* DATA_IN stage */
                    OTG_FS->DIEPEMPMSK |= (UINT32)1;    /* Enable TX FIFO empy intr. from EP0 */
            }
            break;
                
        default:
            break;
    }
}

 

Функции верхнего уровня: USBD_Setup() и USBD_DataOut() для чтения из RX буфера используют одну и ту же функцию чтения:

USBD_RESULT IUSBD_EP0_Read(P_UINT8 data, INT data_len, P_INT xfer)
{    
    if(data_len > g_EP_Desc[0].data_len)
        data_len = g_EP_Desc[0].data_len;
    g_EP_Desc[0].data_len = 0;
    
    EP_OUT_FIFO_SW_Get((void *)IUSBD_FIFO_BASE, (void *)data, data_len);    /* Read data from FIFO */
    
    OTG_FS->DOEPTSIZ0 =    /* Setup transfer size for ready to receive */
        OTG_FS_DOEPTSIZ0_XFRSIZ(USBD_CFG_DEVICE_EP0_SIZE * IUSBD_CFG_EP0_DOEPTSIZ_STUPCNT) |
        OTG_FS_DOEPTSIZ0_PKTCNT |
        OTG_FS_DOEPTSIZ0_STUPCNT(IUSBD_CFG_EP0_DOEPTSIZ_STUPCNT);
    OTG_FS->DOEPCTL0 |= (OTG_FS_DOEPCTL0_CNAK | OTG_FS_DOEPCTL0_EPENA);
    
    *xfer = data_len;
    return USBD_RES_OK;    /* OK */
}

 

Т.е. NAK и EPENA программируются сразу после вычитывания буфера.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.е. NAK и EPENA программируются сразу после вычитывания буфера.

Так выходит, что до получения первого пакета EPENA не установлен?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так выходит, что до получения первого пакета EPENA не установлен?

 

Вот эта часть кода:

OTG_FS->DOEPTSIZ0 =    /* Setup transfer size for ready to receive */
        OTG_FS_DOEPTSIZ0_XFRSIZ(USBD_CFG_DEVICE_EP0_SIZE * IUSBD_CFG_EP0_DOEPTSIZ_STUPCNT) |
        OTG_FS_DOEPTSIZ0_PKTCNT |
        OTG_FS_DOEPTSIZ0_STUPCNT(IUSBD_CFG_EP0_DOEPTSIZ_STUPCNT);
    OTG_FS->DOEPCTL0 |= (OTG_FS_DOEPCTL0_CNAK | OTG_FS_DOEPCTL0_EPENA);

Так же исполняется по приходу прерывания USB Bus Reset. Так что точка всегда готова к приему пакетов.

И, когда приходит прерывание о новом пакете, и это DATA OUT stage - количество данных в GRXSTSP верное - 7 байт.

Только данные почему то не те, которые послал хост...

В остальном все работает нормально.

 

Данные по OUT BULK точке я еще принимать не пробовал. Пока хочу разобраться почему в буфере не то что передал хост.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так же исполняется по приходу прерывания USB Bus Reset. Так что точка всегда готова к приему пакетов.

EPENA сбрасывается при каждом SETUP'е, устанавливать надо непосредственно перед приемом пакета.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

EPENA сбрасывается при каждом SETUP'е, устанавливать надо непосредственно перед приемом пакета.
Не понял, что значит "устанавливать надо непосредственно перед приемом пакета".

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не понял, что значит "устанавливать надо непосредственно перед приемом пакета".

Получили SETUP - узнали из него, что будет "продолжение" в виде OUT-транзакции - тут же на месте взвели EPENA.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Получили SETUP - узнали из него, что будет "продолжение" в виде OUT-транзакции - тут же на месте взвели EPENA.

Но я вроде так и делаю. В функции IUSBD_EP0_Read получаю SETUP: Вычитываю данные из RX FIFO и тут же взвожу EPENA и CNAK

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но я вроде так и делаю. В функции IUSBD_EP0_Read получаю SETUP: Вычитываю данные из RX FIFO и тут же взвожу EPENA и CNAK

Перенесите обработку SETUP сюда:

case 0x04:    /* SETUP transaction completed (triggers an interrupt) */

Именно в этот момент EPENA и снимается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Перенесите обработку SETUP сюда:

case 0x04:    /* SETUP transaction completed (triggers an interrupt) */

Именно в этот момент EPENA и снимается.

Спасибо. Как всегда помогли быстро разобраться. :a14: :beer:

 

Правда взвод точки я воткнул не в том месте кода, как Вы сказали, а в обработчике от OUT точки по флагу STUP (SETUP phase done) в регистре DOEPINT0. Перечитал даташит про EPENA в DOEPCTL0:

Bit 31EPENA:Endpoint enable

The application sets this bit to start transmitting data on endpoint 0.

The core clears this bit before setting any ofthe following interrupts on this endpoint:

– SETUP phase done

– Endpoint disabled

– Transfer completed

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Правда взвод точки я воткнул
Неа, не туда воткнул :) В общем сделал как советовали. Теперь код прерывания по RXFLVL выглядит вот так:

static void ISRH_RxFifoNonEmpty(void)
{
    UINT32 status = OTG_FS->GRXSTSP;    /* Get the Status from the top of the FIFO */
    UINT8 ep_num = ((status & OTG_FS_GRXSTSP_EPNUM_MSK) >> OTG_FS_GRXSTSP_EPNUM_POS);
    INT data_len = ((status & OTG_FS_GRXSTSP_BCNT_MSK) >> OTG_FS_GRXSTSP_BCNT_POS);
    g_EP_Desc[0].data_len = data_len;
    UINT8 packet_status = ((status & OTG_FS_GRXSTSP_PKTSTS_MSK) >> OTG_FS_GRXSTSP_PKTSTS_POS);
    
    switch(packet_status)
    {
        case 0x01:    /* Global OUT NAK (triggers an interrupt) */
            break;
                    
        case 0x02:    /* OUT data packet received */
            if(0 == ep_num)
            {
                USBD_CTRL_STATE usbd_state = USBD_DataOut();    /* Process the setup request parse */
                if(USBD_CTRL_STAGE_DATA_IN == usbd_state)    /* DATA_IN stage */
                    OTG_FS->DIEPEMPMSK |= (UINT32)1;    /* Enable TX FIFO empy intr. from EP0 */
            }
            break;
                
        case 0x03:    /*  OUT transfer completed (triggers an interrupt) */
            break;
        
        case 0x04:    /* SETUP transaction completed (triggers an interrupt) */
            if(0 == ep_num)
            {
                OTG_FS->DOEPTSIZ0 =    /* Setup transfer size for ready to receive */
                    OTG_FS_DOEPTSIZ0_XFRSIZ(USBD_CFG_DEVICE_EP0_SIZE * IUSBD_CFG_EP0_DOEPTSIZ_STUPCNT) |
                    OTG_FS_DOEPTSIZ0_PKTCNT |
                    OTG_FS_DOEPTSIZ0_STUPCNT(IUSBD_CFG_EP0_DOEPTSIZ_STUPCNT);
                OTG_FS->DOEPCTL0 |= (OTG_FS_DOEPCTL0_CNAK | OTG_FS_DOEPCTL0_EPENA);
            }
            break;
                
        case 0x06:    /* SETUP data packet received */
            if(0 == ep_num)
            {
                USBD_CTRL_STATE usbd_state = USBD_Setup();    /* Process the setup request parse */
                if(USBD_CTRL_STAGE_DATA_IN == usbd_state)    /* DATA_IN stage */
                    OTG_FS->DIEPEMPMSK |= (UINT32)1;    /* Enable TX FIFO empy intr. from EP0 */
            }
            break;
                
        default:
            break;
    }
}

 

Из функции IUSBD_EP0_Read код разрешения точки вообще убрал

 

 

 

 

Пожалуйста :) Правда, веселый контроллер USB у STM?
Ага веселый, но изучать все равно нужно - тренд.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне сейчас интересно посмотреть, какая будет производительность у это OTG_FS ядра. Вижу, что ни о каком двойном буферировании BULK точек в мануале речи не идет - надеюсь оно там есть на уровне ядра?

Уровень буферизации зависит от количества памяти, выделенной в FIFO на прием для точки: если выделить на два пакета максимального размера, то будет как раз двойная.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уровень буферизации зависит от количества памяти, выделенной в FIFO на прием для точки
Это то понятно. Памяти в буфере можно выделить даже на 4 размера конечной точки BULK, при чем в обе стороны.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...