Решил проблему.
Во время передачи данных должно выполнятся переключение триггера данных DATA TOGLE.
В принципе этим занимается сам хост контроллер OHCI от нас (Драйвера Хост Контроллера) требуется только правильно начать процесс передачи данных, и дальше не мешать.
Необходимо сохранять бит C (toggleCarry) поля HeadP дескриптора конечной точки ED при начале следующей транзакции.
Алгоритм работы Хост Контроллера примерно такой (очень примерно).
После выполнения транзакции (передача/прием) хост контроллер сохраняет значение последнего переключения данных в бите “C” поля HeadP дескриптора конечной точки.
При этом в старшие биты ED->HeadP записывается адрес следующего дескриптора передачи (TD) и если в дескрипторе конечной точки (ED) значения старших бит поля HeadP равно TailP, то этот ED больше не будет обрабатываться хост контроллером. Можно считать что транзакция окончена.
Так же обработанный дескриптор передачи (который до этого содержался в поле HeadP дескриптора конечной точки (ED) ) будет изъят из очереди (из этой ED) и помещен в HcDoneHead.
Если нет ошибок, которые можно подсмотреть в битах CC поля DWord0 дескриптора передачи (TD).
Об ошибке также говорит установленный бит H (Halted) в поле HeadP дескриптора конечной точки (ED).
Другими словами если СС==0 и H == 0 можно считать, что транзакция закончена успешно.
Хост контроллер больше не будет обрабатывать эту связку ED TD.
Поэтому нужно сформировать новую транзакцию, для чего необходимо обновить поля дескрипторов передачи и конечной точки.
Нужно восстановить значения в полях
1) дескриптора передачи (TD):
CBP – здесь находится адрес приемного буфера
BE – это адрес но конец буфера (обновляем если в CPB каждый раз записываем новое значение, например организовано FIFO)
NextTD – здесь указатель на следующий дескриптор передач (в нашем случае это пустой TD)
2) дескриптора конечной точки (ED):
В HeadP - необходимо прописать указатель на TD, в котором содержится адрес приемного буфера, причем необходимо сохранить бит Toggle Carry.
Примерный алгоритм показан ниже.
Обновить дескрипторы необходимо после срабатывания прерывания по изъятию TD из списка ED, с перемещением его в очередь HcDoneHead.
AT91S_UHP_ED *pInIntED;
AT91S_UHP_TD *pInIntTD[2];
Код
// Равенство HeadP и TailP означает, что pInIntED обработан хост контроллером
if((pInIntED->HeadP & 0xFFFFFFF0) == pInIntED->TailP)
{
// Запрещаем обрабатывать pInIntED
pInIntED->Control |= (1 << 14);
// Сюда помещаем начал адреса приемного буфера
pInIntTD[0]->CBP = (unsigned int)fifo.get_next_inc();
// и адрес его окончания
pInIntTD[0]->BE = pInIntTD[0]->CBP + (BuffLen) ? CurBufPtr + BuffLen - 1 : CurBufPtr;
// Адрес нулевого TD
pInIntTD[0]->NextTD = (unsigned int)pInIntTD[1];
// Присваиваем указатель на TD и сохраняем значение бита “C”
pInIntED->HeadP = (unsigned int)pInIntTD[0] | (0x0000000E & pInIntED->HeadP);
// Разрешаем обрабатывать pInIntED
pInIntED->Control &= ~(1 << 14);
flag = MOUSE_EVENT;
}
Предполагаю вопрос из первого поста должен решится правильным переключением DATA TOGLE. (Пока нет времени это проверить).
Ниже привожу, как заполнить дескрипторы конечной точки и передачи для транзакций IN.
Код
//Create a default endpoint descriptor
AT91F_CreateEd(
(unsigned int) pInIntED, // ED Address
m_nMaxPacketSize, // Max packet size
0, // TD format 0 - generic 1 - Isochronous
1, // Skip Запрешаем в будующем обрабатывать хост контроллеру этот дескриптор конечной точки
speed, // Speed = ("0" <=> "Full", "1" <=> "Low")
0x02, // Direction IN
enpN, // Номер Endpoint
m_wDeviceAddress, // Адрес устройства Func Address
(unsigned int) pInIntTD[1], // TDQTailPointer
(unsigned int) pInIntTD[0], // TDQHeadPointer
0, // ToggleCarry
0); // NextED
//Create transfer descriptor
//Data IN
AT91F_CreateGenTd(
(unsigned int) pInIntTD[0], // TD Address
0, // Data Toggle (First data packet <=> "0")
0, // DelayInterrupt
0x2, // Direction ("2" <=> IN)
1, // Buffer Rounding
(unsigned int) buffer, // Current Buffer Pointer
(unsigned int) pInIntTD[1], // Next TD
length); // Buffer Length
// Пустой дескриптор передачи
AT91F_CreateGenTd(
(unsigned int) pInIntTD[1], // TD Address
0, // Data Toggle
0, // DelayInterrupt
0, // Direction
0, // Buffer Rounding
0, // Current Buffer Pointer
0, // Next TD
0); // Buffer Length
// Размещаем ED в таблице прерываний
// При таком размещении транзакции будут генерироваться с
// периодом 8 mS
HCCA.HccaInterruptTable[4] = (unsigned int)pInIntED;
HCCA.HccaInterruptTable[12] = (unsigned int)pInIntED;
HCCA.HccaInterruptTable[20] = (unsigned int)pInIntED;
HCCA.HccaInterruptTable[28] = (unsigned int)pInIntED;
///Устанавливаем бит "PeriodicListEnable". Остальные биты не трогаем
AT91C_BASE_UHP->UHP_HcControl |= 0x04;
/* ************************************************ */
/* Generate traffic between UHP and UDP */
/* ************************************************ */
//Skip == 0, т.е. "запускаем" список TD в работу
pInIntED[idx]->Control &= ~(1 << 14);
Ну и до кучи
Код
typedef struct _AT91S_UHP_ED {
volatile unsigned int Control;
volatile unsigned int TailP;
volatile unsigned int HeadP;
volatile unsigned int NextEd;
} AT91S_UHP_ED, *AT91PS_UHP_ED;
typedef struct _AT91S_UHP_TD {
volatile unsigned int Control;
volatile unsigned int CBP;
volatile unsigned int NextTD;
volatile unsigned int BE;
} AT91S_UHP_TD, *AT91PS_UHP_TD;
typedef struct _AT91S_UHP_HCCA {
volatile unsigned int HccaInterruptTable[32];
volatile unsigned short HccaFrameNumber;
volatile unsigned short HccaPad1;
volatile unsigned int HccaDoneHead;
volatile unsigned char reserved[116];
} AT91S_UHP_HCCA, *AT91PS_UHP_HCCA;
//*----------------------------------------------------------------------------
//* Init a pre-allocated endpoint descriptor. !!!
//* ED must be aligned on a 16 bytes boundary
//*----------------------------------------------------------------------------
__inline void AT91F_CreateEd(
unsigned int EDAddr,
unsigned int MaxPacket,
unsigned int TDFormat,
unsigned int Skip,
unsigned int Speed,
unsigned int Direction,
unsigned int EndPt,
unsigned int FuncAddress,
unsigned int TDQTailPntr,
unsigned int TDQHeadPntr,
unsigned int ToggleCarry,
unsigned int NextED)
{
AT91PS_UHP_ED pED = (AT91PS_UHP_ED) EDAddr;
pED->Control = (MaxPacket << 16) | (TDFormat << 15) |
(Skip << 14) | (Speed << 13) | (Direction << 11) |
(EndPt << 7) | FuncAddress;
pED->TailP = (TDQTailPntr & 0xFFFFFFF0);
pED->HeadP = (TDQHeadPntr & 0xFFFFFFF0) | (ToggleCarry << 1);
pED->NextEd = (NextED & 0xFFFFFFF0);
}
//*----------------------------------------------------------------------------
//* Init a pre-allocated transfer descriptor. !!!
//* TD must be aligned on a 16 bytes boundary
//*----------------------------------------------------------------------------
__inline void AT91F_CreateGenTd(
unsigned int GenTdAddr,
unsigned int DataToggle,
unsigned int DelayInterrupt,
unsigned int Direction,
unsigned int BufRnding,
unsigned int CurBufPtr,
unsigned int NextTD,
unsigned int BuffLen)
{
AT91PS_UHP_TD pTD = (AT91PS_UHP_TD) GenTdAddr;
pTD->Control = (DataToggle << 24) | (DelayInterrupt << 21) | (Direction << 19) | (BufRnding << 18) | 0xF0000000;
pTD->CBP = CurBufPtr;
pTD->NextTD = (NextTD & 0xFFFFFFF0);
pTD->BE = (BuffLen) ? CurBufPtr + BuffLen - 1 : CurBufPtr;
}
Перечитал написанное, одни ED и TD, нужно их в голове упорядочить, на что у меня ушло не мало времени.
Из информации одни стандарты и примеры типа U_Boot где голову сломать можно.
Отдельное спасибо автору сайта, где есть перевод стандарта правда не полный
http://microcontrollerov.net/books/OpenHCIНу и спасибо всем откликнувшимся