Skip to content

Commit

Permalink
ETH_SendFrame works in linear mode. Auto mode breaks after a several …
Browse files Browse the repository at this point in the history
…hundred packets, FIFO is still broken completely.

Suffering from code style was unbearable so I completely refactored it. Linear mode was tested (with different delimiter values) with LwIP and ping -f --- no packet loss.
refs eldarkg#41
  • Loading branch information
Amomum committed Mar 20, 2018
1 parent ad6a677 commit 412f4dc
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 77 deletions.
13 changes: 11 additions & 2 deletions MDR32F9Qx_StdPeriph_Driver/inc/MDR32F9Qx_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ typedef struct {
* @brief MAC General Config
*/

uint32_t ETH_Delimiter; /*!< Defines the boundaries of the transmitter and receiver buffers.
uint32_t ETH_Delimiter; /*!< Defines the boundaries of the transmitter and receiver buffers.
This parameter can be a value from 0 to 0x1FFF. */
uint32_t ETH_DBG_Mode; /*!< Select the mode of operation in debug mode.
This parameter can be a value of @ref ETH_DBG_MODE. */
Expand Down Expand Up @@ -204,6 +204,15 @@ typedef union {
* @{
*/


/** @defgroup ETH_Buf_Size
* @{
*/

#define ETH_BUFFER_SIZE_IN_BYTES ((uint32_t)0x2000)

/** @} */ /* End of group ETH_Buf_Size */

/** @defgroup ETH_MODE ETH_MODE
* @{
*/
Expand Down Expand Up @@ -552,7 +561,7 @@ FlagStatus ETH_GetPHYStatus(MDR_ETHERNET_TypeDef * ETHERNETx, uint16_t ETH_PHY_F
uint16_t ETH_ReadPHYRegister(MDR_ETHERNET_TypeDef * ETHERNETx, uint16_t PHYAddress, uint16_t PHYReg);
uint32_t ETH_WritePHYRegister(MDR_ETHERNET_TypeDef * ETHERNETx, uint16_t PHYAddress, uint16_t PHYReg, uint16_t PHYValue);
uint32_t ETH_ReceivedFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_InputBuffer);
void ETH_SendFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_OututBuffer, uint32_t BufLen);
uint32_t ETH_SendFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_OututBuffer, uint32_t BufLen);
void ETH_DMAPrepare(void);
void ETH_DMAFrameRx(uint32_t * DstBuf, uint32_t BufferSize, uint32_t * SrcBuf);
void ETH_DMAFrameTx(uint32_t * DstBuf, uint32_t BufferSize, uint32_t * SrcBuf);
Expand Down
197 changes: 122 additions & 75 deletions MDR32F9Qx_StdPeriph_Driver/src/MDR32F9Qx_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ extern DMA_CtrlDataTypeDef DMA_ControlTable[DMA_Channels_Number * (1 + DMA_Alter
#define IS_ETH_RETRY_COUNTER(COUNTER) (COUNTER <= 0x0F)
#define IS_ETH_DELIMITER(DELIMITER) ((DELIMITER >= 0x5EA) && (DELIMITER <= 0x1A16))

#define ETH_BUFFER_SIZE ((uint32_t)0x2000)


/** @} */ /* End of group ETH_Private_Defines */

Expand Down Expand Up @@ -261,7 +261,7 @@ void ETH_DeInit(MDR_ETHERNET_TypeDef * ETHERNETx )
/* PHY reset */
ETH_PHY_Reset(ETHERNETx);

ETHERNETx->ETH_Delimiter = 0x0800;
ETHERNETx->ETH_Delimiter = 0x0800;
ETHERNETx->ETH_MAC_T = 0x78AB;
ETHERNETx->ETH_MAC_M = 0x3456;
ETHERNETx->ETH_MAC_H = 0x0012;
Expand Down Expand Up @@ -299,7 +299,7 @@ void ETH_StructInit(ETH_InitTypeDef * ETH_InitStruct)
ETH_InitStruct->ETH_PHY_Interface = ETH_PHY_INTERFACE_ETHERNET_802_3;

/* General config*/
ETH_InitStruct->ETH_Delimiter = 0x0800;
ETH_InitStruct->ETH_Delimiter = 0x0800;
/* Set the DBG Mode */
ETH_InitStruct->ETH_DBG_Mode = ETH_DBG_MODE_FREE_RUN;
/* Enable automatically change the transmitter FIFO pointers in DBG Mode. */
Expand Down Expand Up @@ -414,7 +414,7 @@ void ETH_Init(MDR_ETHERNET_TypeDef * ETHERNETx, ETH_InitTypeDef * ETH_InitStruct
/* Check the parameters */
assert_param(IS_ETH_ALL_PERIPH(ETHERNETx));

assert_param(IS_ETH_DELIMITER(ETH_InitStruct->ETH_Delimiter));
assert_param(IS_ETH_DELIMITER(ETH_InitStruct->ETH_Delimiter));
assert_param(IS_ETH_PHY_ADDRESS(ETH_InitStruct->ETH_PHY_Address));
assert_param(IS_ETH_PHY_MODE(ETH_InitStruct->ETH_PHY_Mode));
assert_param(IS_ETH_DBG_MODE(ETH_InitStruct->ETH_DBG_Mode));
Expand Down Expand Up @@ -454,7 +454,7 @@ void ETH_Init(MDR_ETHERNET_TypeDef * ETHERNETx, ETH_InitTypeDef * ETH_InitStruct
assert_param(IS_FUNCTIONAL_STATE(ETH_InitStruct->ETH_Source_Addr_HASH_Filter));

/* Set the buffer size of transmitter and receiver */
ETHERNETx->ETH_Delimiter = ETH_InitStruct->ETH_Delimiter;
ETHERNETx->ETH_Delimiter = ETH_InitStruct->ETH_Delimiter;

/* Config the PHY control register */
tmpreg_PHY_Control = (ETH_InitStruct->ETH_PHY_Address << ETH_PHY_CONTROL_PHYADD_Pos) | (ETH_InitStruct->ETH_PHY_Mode) | (ETH_InitStruct->ETH_PHY_Interface);
Expand Down Expand Up @@ -975,7 +975,7 @@ uint32_t ETH_ReceivedFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_Inpu
ETH_StatusPacketReceptionStruct.Status = (uint32_t)*ptr_InputFrame++;
PacketLength = (ETH_StatusPacketReceptionStruct.Fields.Length + 3)/4;
/* Read the input frame */
EthReceiverFreeBufferSize = (uint32_t) (ETHERNETx->ETH_Delimiter - Rhead) - PacketLength*4;
EthReceiverFreeBufferSize = (uint32_t) (ETHERNETx->ETH_Delimiter - Rhead) - PacketLength*4;
if(EthReceiverFreeBufferSize > 0){
/* Read the input frame */
for(i = 0; i < PacketLength; i++){
Expand Down Expand Up @@ -1009,7 +1009,7 @@ uint32_t ETH_ReceivedFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_Inpu
/* Set the Length of receiving paket */
PacketLength = ((ETH_StatusPacketReceptionStruct.Fields.Length & 0x0003) != 0) + ETH_StatusPacketReceptionStruct.Fields.Length/4;
/* Get the size of recever buffer */
EthReceiverFreeBufferSize = (uint32_t) (ETHERNETx->ETH_Delimiter - Rhead) - PacketLength*4;
EthReceiverFreeBufferSize = (uint32_t) (ETHERNETx->ETH_Delimiter - Rhead) - PacketLength*4;
if(EthReceiverFreeBufferSize > 0){
/* Read the input frame */
for(i = 0; i < PacketLength; i++){
Expand Down Expand Up @@ -1054,84 +1054,131 @@ uint32_t ETH_ReceivedFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_Inpu
* MDR_ETHERNET1, MDR_ETHERNET2 for MDR1986VE3 and
* MDR_ETHERNET1 for MDR1986VE1T.
* @param ptr_OututBuffer: pointer to the sending frame.
* @param BufLen: the size of the sending frmae.
* @retval None
* @param BufLen: the size of the sending frame in bytes.
* @retval ETH_ERROR if there is an error (not enough space in output buffer)
* ETH_SUCCESS otherwise
*/
void ETH_SendFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_OutputBuffer, uint32_t BufLen)

uint32_t ETH_SendFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_BufferToSend, uint32_t BufLenInBytes)
{
uint32_t BufferMode, i, Xtail, tmp;
uint32_t * ptr_OutputFrame;
int32_t EthReceiverFreeBufferSize;
uint32_t BufferMode;
uint32_t Xtail_InBytes;
uint32_t Xhead_InBytes;
uint32_t * ptr_PeriphDataBuffer;
uint32_t WordsAvailable[2];

/* Since output buffer is uint32_t, it should be safe to round up its length in bytes to word boundary */
/* We have to do it because ethernet peripheral buffer only supports word access */
const uint32_t BufLenInWords = (BufLenInBytes + 3)/4;

/* Buffer length in bytes, rounded up to word boundary, plus word for length at the beginning */
/* plus reserved word at the end */
const uint32_t OutputLenInWords = BufLenInWords + 2;

/* Check the parameters */
assert_param(IS_ETH_ALL_PERIPH(ETHERNETx));

Xtail_InBytes = ETHERNETx->ETH_X_Tail;
Xhead_InBytes = ETHERNETx->ETH_X_Head;

/* Read the buffer mode */
BufferMode = (ETHERNETx->ETH_G_CFGl & ETH_G_CFGl_BUFF_MODE_Msk);
/* Send packet */
Xtail = ETHERNETx->ETH_X_Tail;

switch (BufferMode){
case ETH_BUFFER_MODE_LINEAR:
/* Set pointer to output buffer */
ptr_OutputFrame = (uint32_t *)((((uint32_t)ETHERNETx) + 0x08000000) + Xtail);
/* Send frame */
EthReceiverFreeBufferSize = (ETH_BUFFER_SIZE - Xtail) / 4;
/* Put size of the frame first*/
*ptr_OutputFrame++ = BufLen;
EthReceiverFreeBufferSize--;
if(((BufLen + 3) / 4 + 2) < (uint32_t)EthReceiverFreeBufferSize){
for( i = 0; i < (BufLen + 3)/4 + 2; i++ ){
*ptr_OutputFrame++ = ptr_OutputBuffer[i];
}
}
else{
for( i = 0; i < (uint32_t)EthReceiverFreeBufferSize; i++ ){
*ptr_OutputFrame++ = ptr_OutputBuffer[i];
}
tmp = i;
ptr_OutputFrame = (uint32_t *)((((uint32_t)ETHERNETx) + 0x08000000) + ETHERNETx->ETH_Delimiter);
for(i = 0; i < (((BufLen + 3)/4 + 2) - EthReceiverFreeBufferSize); i++){
*ptr_OutputFrame++ = ptr_OutputBuffer[i+tmp];
}
}
Xtail = (uint32_t)ptr_OutputFrame&0x1FFC;
if(Xtail >= ETH_BUFFER_SIZE)
Xtail = ETHERNETx->ETH_Delimiter;
/* Write the new value of the ETH_X_Tail register */
ETHERNETx->ETH_X_Tail = Xtail;
break;
case ETH_BUFFER_MODE_AUTOMATIC_CHANGE_POINTERS:
/* Set pointer to output buffer */
ptr_OutputFrame = (uint32_t *)((((uint32_t)ETHERNETx) + 0x08000000) + Xtail);
/* Send frame */
EthReceiverFreeBufferSize = (ETH_BUFFER_SIZE - Xtail) / 4;
/* Put size of the frame first*/
*ptr_OutputFrame++ = BufLen;
EthReceiverFreeBufferSize--;
if(((BufLen + 3) / 4 + 2) < (uint32_t)EthReceiverFreeBufferSize){
for( i = 0; i < (BufLen + 3)/4 + 2; i++ ){
*ptr_OutputFrame++ = ptr_OutputBuffer[i];
}
}
else{
for( i = 0; i < (uint32_t)EthReceiverFreeBufferSize; i++ ){
*ptr_OutputFrame++ = ptr_OutputBuffer[i];
}
tmp = i;
ptr_OutputFrame = (uint32_t *)((((uint32_t)ETHERNETx) + 0x08000000) + ETHERNETx->ETH_Delimiter);
for(i = 0; i < (((BufLen + 3)/4 + 2) - EthReceiverFreeBufferSize); i++){
*ptr_OutputFrame++ = ptr_OutputBuffer[i+tmp];
}
}
break;
case ETH_BUFFER_MODE_FIFO:
/* Set the pointer to input frame */
ptr_OutputFrame = (uint32_t *) ((uint32_t)ETHERNETx + 0x08000004);
/* Send frame */
ETH_DMAFrameTx(ptr_OutputFrame, ((BufLen+3)/4 + 2), ptr_OutputBuffer);
break;
if( BufferMode == ETH_BUFFER_MODE_FIFO ){
/* Set the pointer to input frame */
ptr_PeriphDataBuffer = (uint32_t *) (MDR_ETHERNET1_BUF_BASE + 4);
/* Send frame */
ETH_DMAFrameTx(ptr_PeriphDataBuffer, OutputLenInWords, ptr_BufferToSend);

return ETH_SUCCESS;
}

/* Set pointer to output buffer */
ptr_PeriphDataBuffer = (uint32_t *)(MDR_ETHERNET1_BUF_BASE + Xtail_InBytes);

/* Calculate available space, it can be split in two pieces */
if( Xhead_InBytes > Xtail_InBytes )
{
WordsAvailable[0] = (Xhead_InBytes - Xtail_InBytes) / 4;
WordsAvailable[1] = 0;
}
else
{
WordsAvailable[0] = (ETH_BUFFER_SIZE_IN_BYTES - Xtail_InBytes) / 4;
WordsAvailable[1] = (Xhead_InBytes - ETHERNETx->ETH_Delimiter) / 4;
}

/* If there is not enough space in the peripheral buffer - return error */
if( OutputLenInWords > WordsAvailable[0] + WordsAvailable[1] )
{
return ETH_ERROR;
}

/* Put size of the frame in bytes first, if there is a space for it */
if( WordsAvailable[0] >= 1){

*ptr_PeriphDataBuffer = BufLenInBytes;
ptr_PeriphDataBuffer++;
WordsAvailable[0]--;
Xtail_InBytes += 4;
}
else{
ptr_PeriphDataBuffer = (uint32_t *)(MDR_ETHERNET1_BUF_BASE + ETHERNETx->ETH_Delimiter);
Xtail_InBytes = ETHERNETx->ETH_Delimiter;

*ptr_PeriphDataBuffer = BufLenInBytes;
ptr_PeriphDataBuffer++;
WordsAvailable[1]--;
Xtail_InBytes += 4;
}

/* Put frame body to the peripheral buffer plus reserved word for tx status */
/* We can't use memcpy because we have to ensure word access to peripheral buffer */
if( BufLenInWords + 1 <= WordsAvailable[0]){

uint32_t i;
for( i=0; i < BufLenInWords; i++ )
{
ptr_PeriphDataBuffer[i] = ptr_BufferToSend[i];
}
/* reserve word for tx status, required in auto mode*/
ptr_PeriphDataBuffer[i] = 0;

Xtail_InBytes += (BufLenInWords + 1)*4;
}
else{
uint32_t i;
/* Put what we can fit into first piece */
for( i=0; i < WordsAvailable[0]; i++ )
{
ptr_PeriphDataBuffer[i] = ptr_BufferToSend[i];
}

ptr_PeriphDataBuffer = (uint32_t *)(MDR_ETHERNET1_BUF_BASE + ETHERNETx->ETH_Delimiter);
ptr_BufferToSend += WordsAvailable[0];

/* Put the rest of it in the second piece. It should be big enough, we checked it before */
for( i=0; i < BufLenInWords - WordsAvailable[0]; i++ )
{
ptr_PeriphDataBuffer[i] = ptr_BufferToSend[i];
}

Xtail_InBytes = ETHERNETx->ETH_Delimiter + (BufLenInWords - WordsAvailable[0]) * 4;

/* reserve word for tx status, required in auto mode*/
ptr_PeriphDataBuffer[i] = 0;
Xtail_InBytes += 4;
}

if( BufferMode == ETH_BUFFER_MODE_LINEAR ){
if(Xtail_InBytes >= ETH_BUFFER_SIZE_IN_BYTES) {
Xtail_InBytes -= (ETH_BUFFER_SIZE_IN_BYTES - ETHERNETx->ETH_Delimiter);
}
/* Write the new value of the ETH_X_Tail register */
ETHERNETx->ETH_X_Tail = Xtail_InBytes;
}

return ETH_SUCCESS;
}

/**
Expand Down

0 comments on commit 412f4dc

Please sign in to comment.