Здравствуйте!
Из демопакета FreeRTOS взял драйвер Ethernet для CORTEX LPC1768 и переделал под LPC2388.
Имеем процедуру передачи данных:
Код
#define emacTX_DESC_INDEX (0)
/* EMAC variables located in ETHERNET_RAM */
#define ETHERNET_RAM 0x7FE00000UL
#define RX_DESC_BASE (ETHERNET_RAM) /* 0x7FE00000*/
#define RX_STAT_BASE (RX_DESC_BASE + NUM_RX_FRAG*(2*4)) /* =0x7FE00018, 2 * uint32_t, see RX_DESC_TypeDef */
#define TX_DESC_BASE (RX_STAT_BASE + NUM_RX_FRAG*(2*4)) /* =0x7FE00030, 2 * uint32_t, see RX_STAT_TypeDef */
#define TX_STAT_BASE (TX_DESC_BASE + NUM_TX_FRAG*(2*4)) /* =0x7FE00040, 2 * uint32_t, see TX_DESC_TypeDef */
#define ETH_BUF_BASE (TX_STAT_BASE + NUM_TX_FRAG*(1*4)) /* =0x7FE00048, 1 * uint32_t, see TX_STAT_TypeDef */
/* RX and TX descriptor and status definitions. */
#define RX_DESC_PACKET(i) (*(unsigned int *)(RX_DESC_BASE + 8*i)) /* =0x7FE00000, =0x7FE00008, =0x7FE00010 */
#define RX_DESC_CTRL(i) (*(unsigned int *)(RX_DESC_BASE+4 + 8*i)) /* =0x7FE00004, =0x7FE0000C, =0x7FE00014 */
#define RX_STAT_INFO(i) (*(unsigned int *)(RX_STAT_BASE + 8*i)) /* =0x7FE00018, =0x7FE00020, =0x7FE00028 */
#define RX_STAT_HASHCRC(i) (*(unsigned int *)(RX_STAT_BASE+4 + 8*i)) /* =0x7FE0001C, =0x7FE00024, =0x7FE0002C */
#define TX_DESC_PACKET(i) (*(unsigned int *)(TX_DESC_BASE + 8*i)) /* =0x7FE00030, =0x7FE00038 */
#define TX_DESC_CTRL(i) (*(unsigned int *)(TX_DESC_BASE+4 + 8*i)) /* =0x7FE00034, =0x7FE0003C */
#define TX_STAT_INFO(i) (*(unsigned int *)(TX_STAT_BASE + 4*i)) /* =0x7FE00040, =0x7FE00044 */
#define ETH_BUF(i) ( ETH_BUF_BASE + ETH_FRAG_SIZE*i ) /* =0x7FE00048, =0x7FE00648, =0x7FE00C48 */
#define ETH_NUM_BUFFERS ( NUM_TX_FRAG + NUM_RX_FRAG + 1 ) /* There are in fact 2 more buffers than descriptors as the two Tx descriptors use the same buffer to speed up the uip Tx. */
.......................
void vSendEMACTxData( unsigned short usTxDataLen ){
unsigned long ulAttempts = 0UL;
/* Check to see if the Tx descriptor is free, indicated by its buffer being NULL. */
while( TX_DESC_PACKET( emacTX_DESC_INDEX ) != ( unsigned long ) NULL ) {
/* Wait for the Tx descriptor to become available. */
vTaskDelay( emacBUFFER_WAIT_DELAY );
ulAttempts++;
if( ulAttempts > emacBUFFER_WAIT_ATTEMPTS ) {
/* Something has gone wrong as the Tx descriptor is still in use.
Clear it down manually, the data it was sending will probably be
lost. */
prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );
break;
}
}
/* Setup the Tx descriptor for transmission. Remember the length of the data being sent so the second descriptor can be used to send it again from within the ISR. */
usSendLen = usTxDataLen - 1;
TX_DESC_PACKET( emacTX_DESC_INDEX ) = ( unsigned long ) uip_buf;
TX_DESC_CTRL( emacTX_DESC_INDEX ) = ( usTxDataLen | TCTRL_LAST | TCTRL_INT );
EMAC->TxProduceIndex = ( emacTX_DESC_INDEX + 1 );
/* uip_buf is being sent by the Tx descriptor. Allocate a new buffer. */
uip_buf = prvGetNextBuffer();
}
и само прерывание
Код
__arm void vEMAC_ISR(){
unsigned long ulStatus;
long lHigherPriorityTaskWoken = pdFALSE;
ulStatus = EMAC->IntStatus;
/* Clear the interrupt. */
EMAC->IntClear = ulStatus;
if (ulStatus & INT_TX_ERR){
LEDSOn(_VD1);
};
if (ulStatus & INT_RX_DONE){
/* Ensure the uIP task is not blocked as data has arrived. */
xSemaphoreGiveFromISR(xEMACSemaphore, &lHigherPriorityTaskWoken);
};
if (ulStatus & INT_TX_DONE){
if (usSendLen > 0){
/* Send the data again, using the second descriptor. As there are only two descriptors the index is set back to 0. */
TX_DESC_PACKET( ( emacTX_DESC_INDEX + 1 ) ) = TX_DESC_PACKET( emacTX_DESC_INDEX );
TX_DESC_CTRL( ( emacTX_DESC_INDEX + 1 ) ) = ( usSendLen | TCTRL_LAST | TCTRL_INT );
EMAC->TxProduceIndex = ( emacTX_DESC_INDEX );
/* This is the second Tx so set usSendLen to 0 to indicate that the Tx descriptors will be free again. */
usSendLen = 0UL;
} else {
/* The Tx buffer is no longer required. */
prvReturnBuffer( ( unsigned char * ) TX_DESC_PACKET( emacTX_DESC_INDEX ) );
TX_DESC_PACKET( emacTX_DESC_INDEX ) = (unsigned long)NULL;
};
};
portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
VICADDRESS = 0;
}
При вызове
vSendEMACTxData в драйвере запоминается глобальная переменная
usSendLen, затем после
EMAC->TxProduceIndex = ( emacTX_DESC_INDEX + 1 ); вызывается прерывание с выставленным битом INT_TX_DONE в статусе. И вот здесь непонятно, почему так делается внутри "if". Ведь бит INT_TX_DONE означает, что уже все передано, но почему автор драйвера снова копирует эти же данные в следующий дескриптор и снова их передает? Ладно,если бы проверялся бит,отвечающий за ошибки передачи, и затем снова пакет бы передался заново, но тут получается так, что пакет передается повторно при каждой новой передаче.
Не понимаю смысла этой глобальной переменной
usSendLen. Она больше нигде не используется в драйвере. Может кто разъяснит?
Сообщение отредактировал M0HAX - Oct 22 2015, 08:02