‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

Category:

worklog: hardfault, busfault, bullshit


Нашёл глупый источник одной проблемы (засирал стэк неправильным использованием API FreeRTOS) и тут же упёрся в таинственную неизвестость: записав (как я думаю, правильным методом) данные в TxFIFO и разрешив передачу конечной точки, не вижу чтобы вообще что-то положительное происходило. Щас попробую сниффером глянуть, если пойму, как им пользоваться.

Документация тоже ясности не прибавляет (наоборот даже, ободряет словом "sophisticated"). В пункте 37.11 Reference Manual:
The packet FIFO controller module in the OTG_FS/OTG_HS core
organizes RAM space into Tx FIFOs into which the application pushes the data to be
temporarily stored before the USB transmission, and into a single Rx FIFO where the data
received from the USB are temporarily stored before retrieval (popped) by the application.
...
In peripheral mode an additional Tx FIFO is instructed for each active IN
endpoint.


Если я правильно понимаю бусурманский, в чём тоже всё больше сомнений, то тут сказано, что принимающий FIFO физически всего один, а передающих несколько, по числу задействованных конечных точек типа IN. Это всё - размеры и всё прочее - я вроде настроил. Дальше там сказано:

The OTG peripheral uses a single receive FIFO that receives the data directed to all OUT
endpoints. Received packets are stacked back-to-back until free space is available in the Rx
FIFO. The status of the received packet (which contains the OUT endpoint destination
number, the byte count, the data PID and the validity of the received data) is also stored by
the core on top of the data payload. When no more space is available, host transactions are
NACKed and an interrupt is received on the addressed endpoint. The size of the receive
FIFO is configured in the receive FIFO Size register (OTG_GRXFSIZ).


То есть, принятые данные со всех OUT конечных точек валятся в общий буфер. Поэтому, получив прерывание RXFLVL (сигнализирующее, что в приёмном FIFO что-то есть), мы сначала должны прочитать GRXSTSP - чтение из этого регистра автоматически выдавливает вышеупомянутую статустую информацию о принятом пакете. Проанализировав содержимое статуса, выдавливаем пакет из FIFO и затем идёт уже его обработка. Далее:

The core has a dedicated FIFO for each IN endpoint. The application configures FIFO sizes
by writing the endpoint 0 transmit FIFO size register (OTG_DIEPTXF0) for IN endpoint0 and
the device IN endpoint transmit FIFOx registers (OTG_DIEPTXFx) for IN endpoint-x.


Т.е. ясно подтверждается, что каждая IN конечная точка связана со своим TxFIFO, "геометрию" которого надо прописать в соответствующие регистры. В пункте 37.11.3 "FIFO RAM allocation" расписан шаманизм с выбором размеров этих FIFO: как их посчитать, чтобы памяти хватило и чтобы обойтись без перерасхода (ибо доступный объём - чуть больше килобайта на всё про всё).

Далее, в пункте 37.14.1, абзац "Data FIFO (DFIFO) access register map":
These registers, available in both host and device modes, are used to read or write the FIFO
space for a specific endpoint or a channel, in a given direction.
If a host channel is of type
IN, the FIFO can only be read on the channel. Similarly, if a host channel is of type OUT, the
FIFO can only be written on the channel.

Болдом я выделил то, что более интересно, т.к. режим хоста я не использую и не планирую. Что мы видим? Вернее, что я вижу. Сказано: "эти регистры позволяют читать или писать FIFO соответствующих конечных точек". И дальше там таблица 240, в которой для КАЖДОЙ конечно точки приведены свои "Device IN endpoint X write access", "Device OUT endpoint X write access", для всех имеющихся конечных точек (X от 0 до 5 в случае USB FS). То есть, сначала пишут, что RxFIFO один на все OUT конечные точки, а затем оказывается, что на каждую конечную точку свой собственный адрес доступа.

Я не понимаю, как это одно с другим сочетается? Значит ли это, что читая по любому из указанных в таблице адресов (или даже ДИАПАЗОНОВ адресов), мы на самом деле читаем один и тот же RxFIFO? Или же, чтобы прочитать нужную конечную точку, номер которой мы, получив прерывание RXFLVL, выудили из GRXSTSP, нужно читать по конкретному адресу, соответствующему этому номеру? И почему там, чёрт побери, диапазоны адресов -- они все проецируются на один и тот же регистр ("макушку" FIFO) или же можно прочитать элементы FIFO, ничего из него не выдвигая, а просто пройдясь по их адресам?

Судя по тому, как STM32 USB Device Library работает с FIFO, верно первое предположение. Вот код двух очевидных функций прям оттуда:
HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src, uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
  uint32_t count32b= 0 , i= 0;
  
  if (dma == 0)
  {
    count32b =  (len + 3) / 4;
    for (i = 0; i < count32b; i++, src += 4)
    {
      USBx_DFIFO(ch_ep_num) = *((__packed uint32_t *)src);
    }
  }
  return HAL_OK;
}

void *USB_ReadPacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *dest, uint16_t len)
{
  uint32_t i=0;
  uint32_t count32b = (len + 3) / 4;
  
  for ( i = 0; i < count32b; i++, dest += 4 )
  {
    *(__packed uint32_t *)dest = USBx_DFIFO(0);
    
  }
  return ((void *)dest);
}


USBx_DFIFO() это макрос:
#define USBx_DFIFO(i)   *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_FIFO_BASE + (i) * USB_OTG_FIFO_SIZE)


Видно, что WritePacket пишет в фиксированную позицию в памяти, конкретный адрес которой зависит от выбранной конечной точки, а ReadPacket читает из одного и того же адреса, не зависящего ни от чего.

НО ПОЧЕМУ БЛЯТЬ В ТАБЛИЦЕ ПРОПИСАНЫ ДИАПАЗОНЫ АДРЕСОВ И СТОЛЬКО РАЗНЫХ КОНЕЧНЫХ ТОЧЕК ТИПА OUT?!!!!

gj47k0




А ещё отладчик перестал показывать реальное содержимое памяти - переменных и т.п. Что изменилось - мне неведомо.

Upd а сниффер ожидаемо ничего не показал.
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 2 comments