📄 lpc177x_8x_emac.c
字号:
* @brief De-initializes the EMAC peripheral registers to their
* default reset values.
* @param[in] None
* @return None
**********************************************************************/
void EMAC_DeInit(void)
{
// Disable all interrupt
LPC_EMAC->IntEnable = 0x00;
// Clear all pending interrupt
LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
LPC_EMAC->Command = 0;
/* TurnOff power for Ethernet module */
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE);
}
/*********************************************************************//**
* @brief EMAC TX API modules
* @param[in] None
* @return None
**********************************************************************/
void EMAC_TxEnable( void )
{
LPC_EMAC->Command |= EMAC_CR_TX_EN;
return;
}
/*********************************************************************//**
* @brief EMAC RX API modules
* @param[in] None
* @return None
**********************************************************************/
void EMAC_TxDisable( void )
{
LPC_EMAC->Command &= ~EMAC_CR_TX_EN;
return;
}
/*********************************************************************//**
* @brief EMAC RX API modules
* @param[in] None
* @return None
**********************************************************************/
void EMAC_RxEnable( void )
{
LPC_EMAC->Command |= EMAC_CR_RX_EN;
LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
return;
}
/*********************************************************************//**
* @brief EMAC RX API modules
* @param[in] None
* @return None
**********************************************************************/
void EMAC_RxDisable( void )
{
LPC_EMAC->Command &= ~EMAC_CR_RX_EN;
LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN;
return;
}
/*********************************************************************//**
* @brief Get the status of given buffer.
* @param[in] idx Buffer index
* @return EMAC_BUFF_AVAILABLE/EMAC_BUFF_FULL/EMAC_BUFF_PARTIAL_FULL
*
**********************************************************************/
EMAC_BUFF_STATUS EMAC_GetBufferSts(EMAC_BUFF_IDX idx)
{
uint32_t consume_idx, produce_idx;
uint32_t max_frag_num;
// Get the consume index, produce index and the buffer size
if(idx == EMAC_TX_BUFF)
{
consume_idx = LPC_EMAC->TxConsumeIndex;
produce_idx = LPC_EMAC->TxProduceIndex;
max_frag_num = LPC_EMAC->TxDescriptorNumber + 1;
}
else
{
consume_idx = LPC_EMAC->RxConsumeIndex;
produce_idx = LPC_EMAC->RxProduceIndex;
max_frag_num = LPC_EMAC->RxDescriptorNumber + 1;
}
// empty
if(consume_idx == produce_idx)
return EMAC_BUFF_EMPTY;
// Full
if(consume_idx == 0 &&
produce_idx == max_frag_num - 1)
return EMAC_BUFF_FULL;
// Wrap-around
if(consume_idx == produce_idx + 1)
return EMAC_BUFF_FULL;
return EMAC_BUFF_PARTIAL_FULL;
}
/*********************************************************************//**
* @brief Allocate a descriptor for sending frame and get the coressponding buffer address
* @param[in] FrameSize The size of frame you want to send
* @return Address of the TX_DESC_PACKET buffer
**********************************************************************/
uint32_t EMAC_AllocTxBuff(uint16_t nFrameSize, uint8_t bLastFrame)
{
uint32_t idx;
uint32_t dp;
uint32_t i;
idx = LPC_EMAC->TxProduceIndex;
while(EMAC_GetBufferSts(EMAC_TX_BUFF) == EMAC_BUFF_FULL)
{
for(i = 0; i < 1000000; i++) ;
}
dp = TX_DESC_PACKET(idx);
if(bLastFrame)
TX_DESC_CTRL(idx) = ((nFrameSize-1) & EMAC_TCTRL_SIZE) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
else
TX_DESC_CTRL(idx) = ((nFrameSize-1) & EMAC_TCTRL_SIZE) | (EMAC_TCTRL_INT);
return dp;
}
/*********************************************************************//**
* @brief Increase the TxProduceIndex (after writting to the Transmit buffer
* to enable the Transmit buffer) and wrap-around the index if
* it reaches the maximum Transmit Number
* @param[in] None
* @return None
**********************************************************************/
void EMAC_UpdateTxProduceIndex(void)
{
// Get current Tx produce index
uint32_t idx = LPC_EMAC->TxProduceIndex;
/* Start frame transmission */
if (++idx == LPC_EMAC->TxDescriptorNumber + 1) idx = 0;
LPC_EMAC->TxProduceIndex = idx;
}
/*********************************************************************//**
* @brief Get current status value of receive data (due to TxProduceIndex)
* @param[in] None
* @return Current value of receive data (due to TxProduceIndex)
**********************************************************************/
uint32_t EMAC_GetTxFrameStatus(void)
{
uint32_t idx;
idx = LPC_EMAC->TxProduceIndex;
return (TX_STAT_INFO(idx));
}
/*********************************************************************//**
* @brief Write data to Tx packet data buffer at current index due to
* TxProduceIndex
* @param[in] pDataStruct store the address and the size of buffer that saves data.
* @return None
**********************************************************************/
void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
{
uint16_t* pDest;
uint16_t* pSource = (uint16_t*)pDataStruct->pbDataBuf;
uint32_t size = pDataStruct->ulDataLen;
int32_t frame_num;
uint32_t tmp;
uint32_t max_frame_size = LPC_EMAC->MAXF;
size = (size + 1) & 0xFFFE; // round Size up to next even number
frame_num = size/max_frame_size;
if(size == 0)
return;
while(frame_num >= 0)
{
tmp = (frame_num > 0)? max_frame_size:size;
if(tmp == 0)
break;
// Setup descriptors and data
if(frame_num == 0)
pDest = (uint16_t*)EMAC_AllocTxBuff(tmp, 1); // last frame
else
pDest = (uint16_t*)EMAC_AllocTxBuff(tmp, 0);
// Copy data
while (tmp > 0)
{
*pDest++ = *pSource++;
tmp -= 2;
}
frame_num--;
size -= tmp;
// Update produce index
EMAC_UpdateTxProduceIndex();
}
}
/*********************************************************************//**
* @brief Get current status value of receive data (due to RxConsumeIndex)
* @param[in] None
* @return Current value of receive data (due to RxConsumeIndex)
**********************************************************************/
uint32_t EMAC_GetRxFrameStatus(void)
{
uint32_t idx;
idx = LPC_EMAC->RxConsumeIndex;
return (RX_STAT_INFO(idx));
}
/*********************************************************************//**
* @brief Get size of current Received data in received buffer (due to
* RxConsumeIndex)
* @param[in] None
* @return Size of received data
**********************************************************************/
uint32_t EMAC_GetRxFrameSize(void)
{
uint32_t idx;
idx = LPC_EMAC->RxConsumeIndex;
return (((RX_STAT_INFO(idx)) & EMAC_RINFO_SIZE)+1);
}
/*********************************************************************//**
* @brief Get the address of TX_DESC_PACKET buffer so that user can access from application
* @param[in] None
* @return Address of the TX_DESC_PACKET buffer
**********************************************************************/
uint32_t EMAC_GetRxBuffer(void)
{
uint32_t idx;
idx = LPC_EMAC->RxConsumeIndex;
return RX_DESC_PACKET(idx);
}
/*********************************************************************//**
* @brief Increase the RxConsumeIndex (after reading the Receive buffer
* to release the Receive buffer) and wrap-around the index if
* it reaches the maximum Receive Number
* @param[in] None
* @return None
**********************************************************************/
void EMAC_UpdateRxConsumeIndex(void)
{
// Get current Rx consume index
uint32_t idx = LPC_EMAC->RxConsumeIndex;
/* Release frame from EMAC buffer */
if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
LPC_EMAC->RxConsumeIndex = idx;
}
/*********************************************************************//**
* @brief Standard EMAC IRQ Handler. This sub-routine will check
* these following interrupt and call the call-back function
* if they're already installed:
* - Overrun Error interrupt in RX Queue
* - Receive Error interrupt: AlignmentError, RangeError,
* LengthError, SymbolError, CRCError or NoDescriptor or Overrun
* - RX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
* - Receive Done interrupt: Read received frame to the internal buffer
* - Transmit Under-run interrupt
* - Transmit errors interrupt : LateCollision, ExcessiveCollision
* and ExcessiveDefer, NoDescriptor or Under-run
* - TX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
* - Transmit Done interrupt
* - Interrupt triggered by software
* - Interrupt triggered by a Wakeup event detected by the receive filter
* @param[in] None
* @return None
**********************************************************************/
void ENET_IRQHandler(void)
{
/* EMAC Ethernet Controller Interrupt function. */
uint32_t int_stat;
int32_t RxLen;
// Get EMAC interrupt status
while ((int_stat = (LPC_EMAC->IntStatus & LPC_EMAC->IntEnable)) != 0)
{
// Clear interrupt status
LPC_EMAC->IntClear = int_stat;
if(int_stat & (EMAC_INT_RX_OVERRUN |EMAC_INT_RX_ERR ))
{
uint32_t ulFrameSts = EMAC_GetRxFrameStatus();
uint32_t ulErrCode = 0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_CRC_ERR) ? EMAC_CRC_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_SYM_ERR) ? EMAC_SYMBOL_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_LEN_ERR) ? EMAC_LENGTH_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_ALIGN_ERR) ? EMAC_ALIGN_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_OVERRUN) ? EMAC_OVERRUN_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_NO_DESCR) ? EMAC_RX_NO_DESC_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_RINFO_FAIL_FILT) ? EMAC_FILTER_FAILED_ERR:0;
if(ulErrCode == 0)
{
/* Note:
* The EMAC doesn't distinguish the frame type and frame length,
* so, e.g. when the IP(0x8000) or ARP(0x0806) packets are received,
* it compares the frame type with the max length and gives the
* "Range" error. In fact, this bit is not an error indication,
* but simply a statement by the chip regarding the status of
* the received frame
*/
int_stat &= ~EMAC_INT_RX_ERR;
}
else
{
if(EMAC_Configs.pfnErrorReceive != NULL)
EMAC_Configs.pfnErrorReceive(ulErrCode);
}
}
if(int_stat & (EMAC_INT_TX_UNDERRUN|EMAC_INT_TX_ERR ))
{
uint32_t ulFrameSts = EMAC_GetTxFrameStatus();
uint32_t ulErrCode = 0;
ulErrCode |= (ulFrameSts & EMAC_TINFO_EXCESS_DEF) ? EMAC_EXCESSIVE_DEFER_ERR:0;
ulErrCode |= (ulFrameSts & EMAC_TINFO_EXCESS_COL) ? EMAC_EXCESSIVE_COLLISION_ERR:0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -