Сломал голову на проблеме при отправке ethernet фреймов.
Работа ведется на отладочной плате и код из CubeMX на ней работает.
Прием в моем коде тоже корректно работает.
Для проверки сократил код до минимума. Вот его кусок:
Код
uint8_t testData[128];
uint8_t dest_mac[]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t my_mac[]={0x00,0x80,0xE1,0x00,0x57,0x23};
int main ()
{
InitHw();
while (ethernetif_init(my_mac)!=ETH_SUCCESS);
for(uint8_t a=0; a< 128; a++)
testData[a]=a;
memcpy(testData,dest_mac,6);
memcpy(testData+6,my_mac,6);
for (;;)
{
ethernetif_output(testData, 128);
volatile uint32_t i;
for(i=0; i<10000000;i++);
}
}
uint8_t dest_mac[]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t my_mac[]={0x00,0x80,0xE1,0x00,0x57,0x23};
int main ()
{
InitHw();
while (ethernetif_init(my_mac)!=ETH_SUCCESS);
for(uint8_t a=0; a< 128; a++)
testData[a]=a;
memcpy(testData,dest_mac,6);
memcpy(testData+6,my_mac,6);
for (;;)
{
ethernetif_output(testData, 128);
volatile uint32_t i;
for(i=0; i<10000000;i++);
}
}
Функции ethernetif_init и ethernetif_output - это переделанные функции из апнота AN3966 (LwIP TCP/IP stack demonstration for STM32F4x7 microcontrollers) с сайта ST. Библиотека STM32F4x7_ETH_Driver от туда же без переделок.
На компе в WireShark вижу следующее:
Некоторые ошибки пометил. Почему так получается никак не могу понять. Код практически идентичен различным примерам. Где закралась ошибка не вижу своим замыленым взглядом. Прослеживал отладчиком до самой отправки. Данные целые и в буфере testData и потом в буферах Tx_Buff из библиотеки.
Вот код функций
Код
uint32_t ethernetif_init(uint8_t* mac)
{
Clock::EthMacClock::Enable();
Clock::EthMacTxClock::Enable();
Clock::EthMacRxClock::Enable();
Clock::SyscfgClock::Enable();
// Select MII or RMII
uint32_t temp = (SYSCFG->PMC&(~SYSCFG_PMC_MII_RMII_SEL))|SYSCFG_PMC_MII_RMII_SEL;
SYSCFG->PMC|= temp;
EthPins::SetConfiguration(EthPins::Configuration::AltFunc);
EthPins::AltFuncNumber(11);
// Enable ethernet interrupts
NVIC_EnableIRQ(ETH_IRQn);
return low_level_init(mac);
}
{
Clock::EthMacClock::Enable();
Clock::EthMacTxClock::Enable();
Clock::EthMacRxClock::Enable();
Clock::SyscfgClock::Enable();
// Select MII or RMII
uint32_t temp = (SYSCFG->PMC&(~SYSCFG_PMC_MII_RMII_SEL))|SYSCFG_PMC_MII_RMII_SEL;
SYSCFG->PMC|= temp;
EthPins::SetConfiguration(EthPins::Configuration::AltFunc);
EthPins::AltFuncNumber(11);
// Enable ethernet interrupts
NVIC_EnableIRQ(ETH_IRQn);
return low_level_init(mac);
}
Код
static uint32_t low_level_init(uint8_t* mac)
{
int i;
ETH_SoftwareReset();
ETH_StructInit(ð_init);
eth_init.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
// ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable;
// ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
// ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
eth_init.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
eth_init.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
eth_init.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
eth_init.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
eth_init.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
eth_init.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
eth_init.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
eth_init.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
#ifdef CHECKSUM_BY_HARDWARE
eth_init.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
#endif
/*------------------------ DMA -----------------------------------*/
/* When we use the Checksum offload feature, we need to enable the Store and Forward mode:
the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum,
if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
eth_init.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;
eth_init.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
eth_init.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
eth_init.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;
eth_init.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;
eth_init.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
eth_init.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;
eth_init.ETH_FixedBurst = ETH_FixedBurst_Enable;
eth_init.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;
eth_init.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
eth_init.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
while (ETH_GetSoftwareResetStatus() == SET);
if (ETH_Init(ð_init, 1)==ETH_ERROR)return ETH_ERROR;
/* initialize MAC address in ethernet MAC */
ETH_MACAddressConfig(ETH_MAC_Address0, mac);
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
for(i=0; i<ETH_RXBUFNB; i++)
{
ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);
}
#ifdef CHECKSUM_BY_HARDWARE
/* Enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
for(i=0; i<ETH_TXBUFNB; i++)
{
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
}
#endif
//
/* Note: TCP, UDP, ICMP checksum checking for received frame are enabled in DMA config */
/* Enable the Ethernet Rx Interrupt */
ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);
/* Enable MAC and DMA transmission and reception */
ETH_Start();
return ETH_SUCCESS;
}
{
int i;
ETH_SoftwareReset();
ETH_StructInit(ð_init);
eth_init.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
// ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable;
// ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
// ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
eth_init.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
eth_init.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
eth_init.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
eth_init.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
eth_init.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
eth_init.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
eth_init.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
eth_init.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
#ifdef CHECKSUM_BY_HARDWARE
eth_init.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
#endif
/*------------------------ DMA -----------------------------------*/
/* When we use the Checksum offload feature, we need to enable the Store and Forward mode:
the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum,
if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
eth_init.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;
eth_init.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
eth_init.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
eth_init.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;
eth_init.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;
eth_init.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
eth_init.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;
eth_init.ETH_FixedBurst = ETH_FixedBurst_Enable;
eth_init.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;
eth_init.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
eth_init.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
while (ETH_GetSoftwareResetStatus() == SET);
if (ETH_Init(ð_init, 1)==ETH_ERROR)return ETH_ERROR;
/* initialize MAC address in ethernet MAC */
ETH_MACAddressConfig(ETH_MAC_Address0, mac);
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
for(i=0; i<ETH_RXBUFNB; i++)
{
ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);
}
#ifdef CHECKSUM_BY_HARDWARE
/* Enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
for(i=0; i<ETH_TXBUFNB; i++)
{
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
}
#endif
//
/* Note: TCP, UDP, ICMP checksum checking for received frame are enabled in DMA config */
/* Enable the Ethernet Rx Interrupt */
ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);
/* Enable MAC and DMA transmission and reception */
ETH_Start();
return ETH_SUCCESS;
}
Код
void ethernetif_output(uint8_t* buf, uint16_t len )
{
uint8_t *buffer;
__IO ETH_DMADESCTypeDef *DmaTxDesc;
uint16_t framelength = 0;
uint32_t byteslefttocopy = 0;
uint32_t payloadoffset = 0;
// if (txMutex.try_lock(netifGUARD_BLOCK_TIME))
{
DmaTxDesc = DMATxDescToSet;
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
// bufferoffset = 0;
if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
{
goto error;
}
/* Get bytes in current lwIP buffer */
byteslefttocopy = len;
payloadoffset = 0;
/* Check if the length of data to copy is bigger than Tx buffer size*/
while( byteslefttocopy > ETH_TX_BUF_SIZE )
{
/* Copy data to Tx buffer*/
memcpy(buffer , buf + payloadoffset, (ETH_TX_BUF_SIZE ) );
/* Point to next descriptor */
DmaTxDesc = (ETH_DMADESCTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
/* Check if the buffer is available */
if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
{
goto error;
}
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - ETH_TX_BUF_SIZE;
payloadoffset = payloadoffset + ETH_TX_BUF_SIZE;
framelength = framelength + ETH_TX_BUF_SIZE;
}
/* Copy the remaining bytes */
memcpy( buffer , buf + payloadoffset, byteslefttocopy );
// bufferoffset = bufferoffset + byteslefttocopy;
framelength = framelength + byteslefttocopy;
/* Prepare transmit descriptors to give to DMA*/
ETH_Prepare_Transmit_Descriptors(framelength);
/* Give semaphore and exit */
error:
// txMutex.unlock();
}
}
{
uint8_t *buffer;
__IO ETH_DMADESCTypeDef *DmaTxDesc;
uint16_t framelength = 0;
uint32_t byteslefttocopy = 0;
uint32_t payloadoffset = 0;
// if (txMutex.try_lock(netifGUARD_BLOCK_TIME))
{
DmaTxDesc = DMATxDescToSet;
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
// bufferoffset = 0;
if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
{
goto error;
}
/* Get bytes in current lwIP buffer */
byteslefttocopy = len;
payloadoffset = 0;
/* Check if the length of data to copy is bigger than Tx buffer size*/
while( byteslefttocopy > ETH_TX_BUF_SIZE )
{
/* Copy data to Tx buffer*/
memcpy(buffer , buf + payloadoffset, (ETH_TX_BUF_SIZE ) );
/* Point to next descriptor */
DmaTxDesc = (ETH_DMADESCTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
/* Check if the buffer is available */
if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
{
goto error;
}
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - ETH_TX_BUF_SIZE;
payloadoffset = payloadoffset + ETH_TX_BUF_SIZE;
framelength = framelength + ETH_TX_BUF_SIZE;
}
/* Copy the remaining bytes */
memcpy( buffer , buf + payloadoffset, byteslefttocopy );
// bufferoffset = bufferoffset + byteslefttocopy;
framelength = framelength + byteslefttocopy;
/* Prepare transmit descriptors to give to DMA*/
ETH_Prepare_Transmit_Descriptors(framelength);
/* Give semaphore and exit */
error:
// txMutex.unlock();
}
}