Всем привет.
Помогите понять мой микроконтроллер AT91SAM9G45!
Смысл проблемы в следующем:
пытаюсь поднять изохронные передачи от своего МК в сторону ПК, программирую на IAR. В библиотечке IARа есть соответствующая функция USBD_MblWrite() из файла USBD_UDPHS.c.
Моя проблема состоит в том, что, передавая контроллеру DMA список из N дескрипторов на отправку, я вижу в снифере USB следующий результат:
- в порт выводится действительно N фреймов
- первый фрейм выводится от прошлых посылок (не важно каких, но тоже осуществлялись с помощью USBD_MblWrite() )
- второй и следующие фреймы соответствуют моим передаваемым первому и последующим...
Такое впечатление, что контроллер насинает передавать какую-то где-то буферизированную ерунду "что в закромах осталось" еще до того как успевает подгрузить вежливо предложенные дескрипторы передачи DMA.
В моем случае используется передача с DMA, поэтому я выкину все лишнее и приведу текст этой функции со своим видением её содеРЖАния...
Цитата
итак... планета!... киборги...
CODE
char USBD_MblWrite( unsigned char bEndpoint,
void *pMbl,
unsigned short wListSize,
unsigned char bCircList,
unsigned short wStartNdx,
MblTransferCallback fCallback,
void *pArgument )
{
Endpoint *pEndpoint = &(endpoints[bEndpoint]); //выбрали указатель на нужную конечную точку
MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); //выбрали указатель на дескриптор передачи этой точки
unsigned short i;
// Check that the endpoint is in Idle state //проверка состояния точки, нам не важно...
if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
return USBD_STATUS_LOCKED;
}
// Setup state
pEndpoint->state = UDP_ENDPOINT_SENDINGM; // установка состояния точки, тоже не важно
// Start from first if not circled list //если передача не зацикленная, то старт с первой (синдексом 0) посылки
if (!bCircList) wStartNdx = 0;
if (UDP_IsDmaUsed(bEndpoint)) { //именно в эту ветку алгоритма и заходим, так как у нас DMA используется
DmaLlTransfer *pDmallt = (DmaLlTransfer*)&(pEndpoint->transfer); //еще один указатель на дескриптор передачи конечной точки
USBDDmaDescriptor * pDi = (USBDDmaDescriptor*)pMbl;//текущий указатель на каждый дескриптор передачи DMA (наращивается дальше)
// DMA config // остановили передачу, сконфигурировали DMA
AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0;
AT91C_BASE_UDPHS->UDPHS_IEN &= ~((1 << SHIFT_DMA) << bEndpoint);
// Setup the transfer descriptor //тут мы просто заполняем дескриптор передачи конечной точки
pDmallt->pMbl = (USBDDmaDescriptor*)pMbl;
pDmallt->listSize = wListSize;
pDmallt->fCallback = fCallback;
pDmallt->pArgument = pArgument;
pDmallt->circList = bCircList;
pDmallt->allUsed = 0;
// Check all buffers, fill settings // для всех дескрипоров передачи DMA (кроме последнего) заполняем настройки
for (i = 0; i < wListSize - 1; i ++) {
if (pDi->bufferLength > DMA_MAX_FIFO_SIZE) //проверка на длину буфера, не важно
return (USBD_STATUS_INVALID_PARAMETER);
// Channel control value
pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
| AT91C_UDPHS_LDNXT_DSC /* - вот этот бит интересен. он говорит о том, */
/* что после загрузки ЭТОГО дескриптора DMA */
/* и его передачи следует автоматом грузануть */
/* следующий из списка */
| AT91C_UDPHS_END_TR_EN
//| AT91C_UDPHS_END_TR_IT//
| AT91C_UDPHS_END_B_EN
| AT91C_UDPHS_END_BUFFIT
| AT91C_UDPHS_DESC_LD_IT
;
pDi->used = 0;
pDi = pDi->pNxtDesc;
}
// Circled list check //тут оформляются поля последнего дескриптора DMA
/* последний дескриптор примечателен только тем, что в случае, */
/* если список надо зациклить, то устанавливается бит AT91C_UDPHS_LDNXT_DSC, */
/* чтобы после передачи последнего дескриптора DMA автоматом гружился снова первый*/
pDi->used = 0;
if (bCircList) {
pDi->pNxtDesc = pDmallt->pMbl;
pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
| AT91C_UDPHS_LDNXT_DSC
| AT91C_UDPHS_END_TR_EN
//| AT91C_UDPHS_END_TR_IT//
| AT91C_UDPHS_END_B_EN
| AT91C_UDPHS_END_BUFFIT
//| AT91C_UDPHS_DESC_LD_IT//
;
}
else {
отличается только тем
pDi->pNxtDesc = 0;
pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
//| AT91C_UDPHS_LDNXT_DSC//
| AT91C_UDPHS_END_TR_EN
//| AT91C_UDPHS_END_TR_IT//
| AT91C_UDPHS_END_B_EN
| AT91C_UDPHS_END_BUFFIT
//| AT91C_UDPHS_DESC_LD_IT//
;
}
// Start from 'wStartNdx'th descriptor //выбираем указатель на нужный по счету дескриптор DMA... нам не важно, у нас с 0 идут
pDi = (USBDDmaDescriptor*)pMbl;
for (;wStartNdx; wStartNdx --) {
pDi = pDi->pNxtDesc;
}
pDmallt->pCurrBuffer = (USBDDmaDescriptor*)pDi;
pDmallt->pFreedBuffer = (USBDDmaDescriptor*)pDi;
// Disable DMA when interrupt happenned
AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_INTDIS_DMA;
// Clear unwanted interrupts
AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
// Enable DMA endpoint interrupt
// И вот тут мы включаем очень хитро DMA (!!!), а делаем это установкой битика LDNXT_DSC...
// По установке этого бита контроллер понимет, что должен загрузить и выполнить очередной дескриптор DMA,
// то есть, первый же дескриптор их нашего сформированного списка
AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC = (unsigned int)pMbl;
AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = AT91C_UDPHS_LDNXT_DSC;
// и тут такие радые, что все сделали правильно, выходим с гордо поднятым... подбородком
return USBD_STATUS_SUCCESS;
}
}
Помогите пожалста сделать так, чтобы при передаче функции нужного числа своих нужных дескриптоов эта штука слала именно мои данные, а не всякие "с прошлого раза"... Где ошибка, не пойму?...
Заранее спасибо за ответы. =)
Сообщение отредактировал IgorKossak - Sep 22 2011, 09:42
Причина редактирования: [codebox]