Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dm9000.c Source File

dm9000.c

Go to the documentation of this file.
00001 /**
00002  * @file dm9000.c
00003  * @brief DM9000A/B Ethernet controller
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "core/ethernet.h"
00035 #include "drivers/dm9000.h"
00036 #include "debug.h"
00037 
00038 
00039 /**
00040  * @brief DM9000 driver
00041  **/
00042 
00043 const NicDriver dm9000Driver =
00044 {
00045    NIC_TYPE_ETHERNET,
00046    ETH_MTU,
00047    dm9000Init,
00048    dm9000Tick,
00049    dm9000EnableIrq,
00050    dm9000DisableIrq,
00051    dm9000EventHandler,
00052    dm9000SendPacket,
00053    dm9000SetMulticastFilter,
00054    NULL,
00055    NULL,
00056    NULL,
00057    TRUE,
00058    TRUE,
00059    TRUE,
00060    FALSE
00061 };
00062 
00063 
00064 /**
00065  * @brief DM9000 controller initialization
00066  * @param[in] interface Underlying network interface
00067  * @return Error code
00068  **/
00069 
00070 error_t dm9000Init(NetInterface *interface)
00071 {
00072    uint_t i;
00073    uint16_t vendorId;
00074    uint16_t productId;
00075    uint8_t chipRevision;
00076    Dm9000Context *context;
00077 
00078    //Debug message
00079    TRACE_INFO("Initializing DM9000 Ethernet controller...\r\n");
00080 
00081    //Initialize external interrupt line
00082    interface->extIntDriver->init();
00083 
00084    //Point to the driver context
00085    context = (Dm9000Context *) interface->nicContext;
00086 
00087    //Initialize driver specific variables
00088    context->queuedPackets = 0;
00089 
00090    //Allocate TX and RX buffers
00091    context->txBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
00092    context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
00093 
00094    //Failed to allocate memory?
00095    if(context->txBuffer == NULL || context->rxBuffer == NULL)
00096    {
00097       //Clean up side effects
00098       memPoolFree(context->txBuffer);
00099       memPoolFree(context->rxBuffer);
00100 
00101       //Report an error
00102       return ERROR_OUT_OF_MEMORY;
00103    }
00104 
00105    //Retrieve vendorID, product ID and chip revision
00106    vendorId = (dm9000ReadReg(DM9000_REG_VIDH) << 8) | dm9000ReadReg(DM9000_REG_VIDL);
00107    productId = (dm9000ReadReg(DM9000_REG_PIDH) << 8) | dm9000ReadReg(DM9000_REG_PIDL);
00108    chipRevision = dm9000ReadReg(DM9000_REG_CHIPR);
00109 
00110    //Check vendor ID and product ID
00111    if(vendorId != DM9000_VID || productId != DM9000_PID)
00112       return ERROR_WRONG_IDENTIFIER;
00113    //Check chip revision
00114    if(chipRevision != DM9000A_CHIP_REV && chipRevision != DM9000B_CHIP_REV)
00115       return ERROR_WRONG_IDENTIFIER;
00116 
00117    //Power up the internal PHY by clearing PHYPD
00118    dm9000WriteReg(DM9000_REG_GPR, 0x00);
00119    //Wait for the PHY to be ready
00120    sleep(10);
00121 
00122    //Software reset
00123    dm9000WriteReg(DM9000_REG_NCR, NCR_RST);
00124    //Wait for the reset to complete
00125    while(dm9000ReadReg(DM9000_REG_NCR) & NCR_RST);
00126 
00127    //PHY software reset
00128    dm9000WritePhyReg(DM9000_PHY_REG_BMCR, BMCR_RST);
00129    //Wait for the PHY reset to complete
00130    while(dm9000ReadPhyReg(DM9000_PHY_REG_BMCR) & BMCR_RST);
00131 
00132    //Debug message
00133    TRACE_INFO("  VID = 0x%04" PRIX16 "\r\n", vendorId);
00134    TRACE_INFO("  PID = 0x%04" PRIX16 "\r\n", productId);
00135    TRACE_INFO("  CHIPR = 0x%02" PRIX8 "\r\n", chipRevision);
00136    TRACE_INFO("  PHYIDR1 = 0x%04" PRIX16 "\r\n", dm9000ReadPhyReg(DM9000_PHY_REG_PHYIDR1));
00137    TRACE_INFO("  PHYIDR2 = 0x%04" PRIX16 "\r\n", dm9000ReadPhyReg(DM9000_PHY_REG_PHYIDR2));
00138 
00139    //Enable loopback mode?
00140 #if (DM9000_LOOPBACK_MODE == ENABLED)
00141    dm9000WriteReg(DM9000_REG_NCR, DM9000_LBK_PHY);
00142    dm9000WritePhyReg(DM9000_PHY_REG_BMCR, BMCR_LOOPBACK | BMCR_SPEED_SEL | BMCR_AN_EN | BMCR_DUPLEX_MODE);
00143 #endif
00144 
00145    //Set host MAC address
00146    for(i = 0; i < 6; i++)
00147       dm9000WriteReg(DM9000_REG_PAR0 + i, interface->macAddr.b[i]);
00148 
00149    //Initialize hash table
00150    for(i = 0; i < 8; i++)
00151       dm9000WriteReg(DM9000_REG_MAR0 + i, 0x00);
00152 
00153    //Always accept broadcast packets
00154    dm9000WriteReg(DM9000_REG_MAR7, 0x80);
00155 
00156    //Enable the Pointer Auto Return function
00157    dm9000WriteReg(DM9000_REG_IMR, IMR_PAR);
00158    //Clear NSR status bits
00159    dm9000WriteReg(DM9000_REG_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
00160    //Clear interrupt flags
00161    dm9000WriteReg(DM9000_REG_ISR, ISR_LNKCHG | ISR_UDRUN | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR);
00162    //Enable interrupts
00163    dm9000WriteReg(DM9000_REG_IMR, IMR_PAR | IMR_LNKCHGI | IMR_PTI | IMR_PRI);
00164    //Enable the receiver by setting RXEN
00165    dm9000WriteReg(DM9000_REG_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
00166 
00167    //Accept any packets from the upper layer
00168    osSetEvent(&interface->nicTxEvent);
00169 
00170    //Force the TCP/IP stack to poll the link state at startup
00171    interface->nicEvent = TRUE;
00172    //Notify the TCP/IP stack of the event
00173    osSetEvent(&netEvent);
00174 
00175    //Successful initialization
00176    return NO_ERROR;
00177 }
00178 
00179 
00180 /**
00181  * @brief DM9000 timer handler
00182  * @param[in] interface Underlying network interface
00183  **/
00184 
00185 void dm9000Tick(NetInterface *interface)
00186 {
00187 }
00188 
00189 
00190 /**
00191  * @brief Enable interrupts
00192  * @param[in] interface Underlying network interface
00193  **/
00194 
00195 void dm9000EnableIrq(NetInterface *interface)
00196 {
00197    //Enable interrupts
00198    interface->extIntDriver->enableIrq();
00199 }
00200 
00201 
00202 /**
00203  * @brief Disable interrupts
00204  * @param[in] interface Underlying network interface
00205  **/
00206 
00207 void dm9000DisableIrq(NetInterface *interface)
00208 {
00209    //Disable interrupts
00210    interface->extIntDriver->disableIrq();
00211 }
00212 
00213 
00214 /**
00215  * @brief DM9000 interrupt service routine
00216  * @param[in] interface Underlying network interface
00217  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
00218  **/
00219 
00220 bool_t dm9000IrqHandler(NetInterface *interface)
00221 {
00222    bool_t flag;
00223    uint8_t status;
00224    uint8_t mask;
00225    Dm9000Context *context;
00226 
00227    //This flag will be set if a higher priority task must be woken
00228    flag = FALSE;
00229 
00230    //Point to the driver context
00231    context = (Dm9000Context *) interface->nicContext;
00232 
00233    //Read interrupt status register
00234    status = dm9000ReadReg(DM9000_REG_ISR);
00235 
00236    //Link status change?
00237    if(status & ISR_LNKCHG)
00238    {
00239       //Read interrupt mask register
00240       mask = dm9000ReadReg(DM9000_REG_IMR);
00241       //Disable LNKCHGI interrupt
00242       dm9000WriteReg(DM9000_REG_IMR, mask & ~IMR_LNKCHGI);
00243 
00244       //Set event flag
00245       interface->nicEvent = TRUE;
00246       //Notify the TCP/IP stack of the event
00247       flag |= osSetEventFromIsr(&netEvent);
00248    }
00249 
00250    //Packet transmission complete?
00251    if(status & ISR_PT)
00252    {
00253       //Check TX complete status bits
00254       if(dm9000ReadReg(DM9000_REG_NSR) & (NSR_TX2END | NSR_TX1END))
00255       {
00256          //The transmission of the current packet is complete
00257          if(context->queuedPackets > 0)
00258             context->queuedPackets--;
00259 
00260          //Notify the TCP/IP stack that the transmitter is ready to send
00261          flag |= osSetEventFromIsr(&interface->nicTxEvent);
00262       }
00263 
00264       //Clear interrupt flag
00265       dm9000WriteReg(DM9000_REG_ISR, ISR_PT);
00266    }
00267 
00268    //Packet received?
00269    if(status & ISR_PR)
00270    {
00271       //Read interrupt mask register
00272       mask = dm9000ReadReg(DM9000_REG_IMR);
00273       //Disable PRI interrupt
00274       dm9000WriteReg(DM9000_REG_IMR, mask & ~IMR_PRI);
00275 
00276       //Set event flag
00277       interface->nicEvent = TRUE;
00278       //Notify the TCP/IP stack of the event
00279       flag |= osSetEventFromIsr(&netEvent);
00280    }
00281 
00282    //A higher priority task must be woken?
00283    return flag;
00284 }
00285 
00286 
00287 /**
00288  * @brief DM9000 event handler
00289  * @param[in] interface Underlying network interface
00290  **/
00291 
00292 void dm9000EventHandler(NetInterface *interface)
00293 {
00294    error_t error;
00295    uint8_t status;
00296 
00297    //Read interrupt status register
00298    status = dm9000ReadReg(DM9000_REG_ISR);
00299 
00300    //Check whether the link status has changed?
00301    if(status & ISR_LNKCHG)
00302    {
00303       //Clear interrupt flag
00304       dm9000WriteReg(DM9000_REG_ISR, ISR_LNKCHG);
00305       //Read network status register
00306       status = dm9000ReadReg(DM9000_REG_NSR);
00307 
00308       //Check link state
00309       if(status & NSR_LINKST)
00310       {
00311          //Get current speed
00312          if(status & NSR_SPEED)
00313             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00314          else
00315             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00316 
00317          //Read network control register
00318          status = dm9000ReadReg(DM9000_REG_NCR);
00319 
00320          //Determine the new duplex mode
00321          if(status & NCR_FDX)
00322             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00323          else
00324             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00325 
00326          //Link is up
00327          interface->linkState = TRUE;
00328       }
00329       else
00330       {
00331          //Link is down
00332          interface->linkState = FALSE;
00333       }
00334 
00335       //Process link state change event
00336       nicNotifyLinkChange(interface);
00337    }
00338 
00339    //Check whether a packet has been received?
00340    if(status & ISR_PR)
00341    {
00342       //Clear interrupt flag
00343       dm9000WriteReg(DM9000_REG_ISR, ISR_PR);
00344 
00345       //Process all pending packets
00346       do
00347       {
00348          //Read incoming packet
00349          error = dm9000ReceivePacket(interface);
00350 
00351          //No more data in the receive buffer?
00352       } while(error != ERROR_BUFFER_EMPTY);
00353    }
00354 
00355    //Re-enable LNKCHGI and PRI interrupts
00356    dm9000WriteReg(DM9000_REG_IMR, IMR_PAR | IMR_LNKCHGI | IMR_PTI | IMR_PRI);
00357 }
00358 
00359 
00360 /**
00361  * @brief Send a packet to DM9000
00362  * @param[in] interface Underlying network interface
00363  * @param[in] buffer Multi-part buffer containing the data to send
00364  * @param[in] offset Offset to the first data byte
00365  * @return Error code
00366  **/
00367 
00368 error_t dm9000SendPacket(NetInterface *interface,
00369    const NetBuffer *buffer, size_t offset)
00370 {
00371    size_t i;
00372    size_t length;
00373    uint16_t *p;
00374    Dm9000Context *context;
00375 
00376    //Point to the driver context
00377    context = (Dm9000Context *) interface->nicContext;
00378 
00379    //Retrieve the length of the packet
00380    length = netBufferGetLength(buffer) - offset;
00381 
00382    //Check the frame length
00383    if(length > ETH_MAX_FRAME_SIZE)
00384    {
00385       //The transmitter can accept another packet
00386       osSetEvent(&interface->nicTxEvent);
00387       //Report an error
00388       return ERROR_INVALID_LENGTH;
00389    }
00390 
00391    //Copy user data
00392    netBufferRead(context->txBuffer, buffer, offset, length);
00393 
00394    //A dummy write is required before accessing FIFO
00395    dm9000WriteReg(DM9000_REG_MWCMDX, 0);
00396    //Select MWCMD register
00397    DM9000_INDEX_REG = DM9000_REG_MWCMD;
00398 
00399    //Point to the beginning of the buffer
00400    p = (uint16_t *) context->txBuffer;
00401 
00402    //Write data to the FIFO using 16-bit mode
00403    for(i = length; i > 1; i -= 2)
00404       DM9000_DATA_REG = *(p++);
00405 
00406    //Odd number of bytes?
00407    if(i > 0)
00408       DM9000_DATA_REG = *((uint8_t *) p);
00409 
00410    //Write the number of bytes to send
00411    dm9000WriteReg(DM9000_REG_TXPLL, LSB(length));
00412    dm9000WriteReg(DM9000_REG_TXPLH, MSB(length));
00413 
00414    //Clear interrupt flag
00415    dm9000WriteReg(DM9000_REG_ISR, ISR_PT);
00416    //Start data transfer
00417    dm9000WriteReg(DM9000_REG_TCR, TCR_TXREQ);
00418 
00419    //The packet was successfully written to FIFO
00420    context->queuedPackets++;
00421 
00422    //Successful processing
00423    return NO_ERROR;
00424 }
00425 
00426 
00427 /**
00428  * @brief Receive a packet
00429  * @param[in] interface Underlying network interface
00430  * @return Error code
00431  **/
00432 
00433 error_t dm9000ReceivePacket(NetInterface *interface)
00434 {
00435    error_t error;
00436    size_t i;
00437    size_t n;
00438    size_t length;
00439    volatile uint8_t status;
00440    volatile uint16_t data;
00441    Dm9000Context *context;
00442 
00443    //Point to the driver context
00444    context = (Dm9000Context *) interface->nicContext;
00445 
00446    //A dummy read is required before accessing the 4-byte header
00447    data = dm9000ReadReg(DM9000_REG_MRCMDX);
00448 
00449    //Select MRCMDX1 register
00450    DM9000_INDEX_REG = DM9000_REG_MRCMDX1;
00451    //Read the first byte of the header
00452    status = LSB(DM9000_DATA_REG);
00453 
00454    //The first byte indicates if a packet has been received
00455    if(status == 0x01)
00456    {
00457       //Select MRCMD register
00458       DM9000_INDEX_REG = DM9000_REG_MRCMD;
00459       //The second byte is the RX status byte
00460       status = MSB(DM9000_DATA_REG);
00461 
00462       //Retrieve packet length
00463       length = DM9000_DATA_REG;
00464       //Limit the number of data to read
00465       n = MIN(length, ETH_MAX_FRAME_SIZE);
00466 
00467       //Point to the beginning of the buffer
00468       i = 0;
00469 
00470       //Make sure no error occurred
00471       if(!(status & (RSR_LCS | RSR_RWTO | RSR_PLE | RSR_AE | RSR_CE | RSR_FOE)))
00472       {
00473          //Read data from FIFO using 16-bit mode
00474          while((i + 1) < n)
00475          {
00476             data = DM9000_DATA_REG;
00477             context->rxBuffer[i++] = LSB(data);
00478             context->rxBuffer[i++] = MSB(data);
00479          }
00480 
00481          //Odd number of bytes to read?
00482          if((i + 1) == n)
00483          {
00484             data = DM9000_DATA_REG;
00485             context->rxBuffer[i] = LSB(data);
00486             i += 2;
00487          }
00488 
00489          //Valid packet received
00490          error = NO_ERROR;
00491       }
00492       else
00493       {
00494          //The received packet contains an error
00495          error = ERROR_INVALID_PACKET;
00496       }
00497 
00498       //Flush remaining bytes
00499       while(i < length)
00500       {
00501          data = DM9000_DATA_REG;
00502          i += 2;
00503       }
00504    }
00505    else
00506    {
00507       //No more data in the receive buffer
00508       error = ERROR_BUFFER_EMPTY;
00509    }
00510 
00511    //Check whether a valid packet has been received
00512    if(!error)
00513    {
00514       //Pass the packet to the upper layer
00515       nicProcessPacket(interface, context->rxBuffer, n);
00516    }
00517 
00518    //Return status code
00519    return error;
00520 }
00521 
00522 
00523 /**
00524  * @brief Configure multicast MAC address filtering
00525  * @param[in] interface Underlying network interface
00526  * @return Error code
00527  **/
00528 
00529 error_t dm9000SetMulticastFilter(NetInterface *interface)
00530 {
00531    uint_t i;
00532    uint_t k;
00533    uint32_t crc;
00534    uint8_t hashTable[8];
00535    MacFilterEntry *entry;
00536 
00537    //Debug message
00538    TRACE_DEBUG("Updating DM9000 hash table...\r\n");
00539 
00540    //Clear hash table
00541    memset(hashTable, 0, sizeof(hashTable));
00542    //Always accept broadcast packets regardless of the MAC filter table
00543    hashTable[7] = 0x80;
00544 
00545    //The MAC filter table contains the multicast MAC addresses
00546    //to accept when receiving an Ethernet frame
00547    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00548    {
00549       //Point to the current entry
00550       entry = &interface->macMulticastFilter[i];
00551 
00552       //Valid entry?
00553       if(entry->refCount > 0)
00554       {
00555          //Compute CRC over the current MAC address
00556          crc = dm9000CalcCrc(&entry->addr, sizeof(MacAddr));
00557          //Calculate the corresponding index in the table
00558          k = crc & 0x3F;
00559          //Update hash table contents
00560          hashTable[k / 8] |= (1 << (k % 8));
00561       }
00562    }
00563 
00564    //Write the hash table to the DM9000 controller
00565    for(i = 0; i < 8; i++)
00566       dm9000WriteReg(DM9000_REG_MAR0 + i, hashTable[i]);
00567 
00568    //Debug message
00569    TRACE_DEBUG("  MAR = %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " "
00570       "%02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8 "\r\n",
00571       dm9000ReadReg(DM9000_REG_MAR0), dm9000ReadReg(DM9000_REG_MAR1),
00572       dm9000ReadReg(DM9000_REG_MAR2), dm9000ReadReg(DM9000_REG_MAR3),
00573       dm9000ReadReg(DM9000_REG_MAR4), dm9000ReadReg(DM9000_REG_MAR5),
00574       dm9000ReadReg(DM9000_REG_MAR6), dm9000ReadReg(DM9000_REG_MAR7));
00575 
00576    //Successful processing
00577    return NO_ERROR;
00578 }
00579 
00580 
00581 /**
00582  * @brief Write DM9000 register
00583  * @param[in] address Register address
00584  * @param[in] data Register value
00585  **/
00586 
00587 void dm9000WriteReg(uint8_t address, uint8_t data)
00588 {
00589    //Write register address to INDEX register
00590    DM9000_INDEX_REG = address;
00591    //Write register value to DATA register
00592    DM9000_DATA_REG = data;
00593 }
00594 
00595 
00596 /**
00597  * @brief Read DM9000 register
00598  * @param[in] address Register address
00599  * @return Register value
00600  **/
00601 
00602 uint8_t dm9000ReadReg(uint8_t address)
00603 {
00604    //Write register address to INDEX register
00605    DM9000_INDEX_REG = address;
00606    //Read register value from DATA register
00607    return DM9000_DATA_REG;
00608 }
00609 
00610 
00611 /**
00612  * @brief Write DM9000 PHY register
00613  * @param[in] address PHY register address
00614  * @param[in] data Register value
00615  **/
00616 
00617 void dm9000WritePhyReg(uint8_t address, uint16_t data)
00618 {
00619    //Write PHY register address
00620    dm9000WriteReg(DM9000_REG_EPAR, 0x40 | address);
00621    //Write register value
00622    dm9000WriteReg(DM9000_REG_EPDRL, LSB(data));
00623    dm9000WriteReg(DM9000_REG_EPDRH, MSB(data));
00624 
00625    //Start the write operation
00626    dm9000WriteReg(DM9000_REG_EPCR, EPCR_EPOS | EPCR_ERPRW);
00627    //PHY access is still in progress?
00628    while(dm9000ReadReg(DM9000_REG_EPCR) & EPCR_ERRE);
00629 
00630    //Wait 5us minimum
00631    usleep(5);
00632    //Clear command register
00633    dm9000WriteReg(DM9000_REG_EPCR, EPCR_EPOS);
00634 }
00635 
00636 
00637 /**
00638  * @brief Read DM9000 PHY register
00639  * @param[in] address PHY register address
00640  * @return Register value
00641  **/
00642 
00643 uint16_t dm9000ReadPhyReg(uint8_t address)
00644 {
00645    //Write PHY register address
00646    dm9000WriteReg(DM9000_REG_EPAR, 0x40 | address);
00647 
00648    //Start the read operation
00649    dm9000WriteReg(DM9000_REG_EPCR, EPCR_EPOS | EPCR_ERPRR);
00650    //PHY access is still in progress?
00651    while(dm9000ReadReg(DM9000_REG_EPCR) & EPCR_ERRE);
00652 
00653    //Clear command register
00654    dm9000WriteReg(DM9000_REG_EPCR, EPCR_EPOS);
00655    //Wait 5us minimum
00656    usleep(5);
00657 
00658    //Return register value
00659    return (dm9000ReadReg(DM9000_REG_EPDRH) << 8) | dm9000ReadReg(DM9000_REG_EPDRL);
00660 }
00661 
00662 
00663 /**
00664  * @brief CRC calculation
00665  * @param[in] data Pointer to the data over which to calculate the CRC
00666  * @param[in] length Number of bytes to process
00667  * @return Resulting CRC value
00668  **/
00669 
00670 uint32_t dm9000CalcCrc(const void *data, size_t length)
00671 {
00672    uint_t i;
00673    uint_t j;
00674 
00675    //Point to the data over which to calculate the CRC
00676    const uint8_t *p = (uint8_t *) data;
00677    //CRC preset value
00678    uint32_t crc = 0xFFFFFFFF;
00679 
00680    //Loop through data
00681    for(i = 0; i < length; i++)
00682    {
00683       //Update CRC value
00684       crc ^= p[i];
00685       //The message is processed bit by bit
00686       for(j = 0; j < 8; j++)
00687       {
00688          if(crc & 0x00000001)
00689             crc = (crc >> 1) ^ 0xEDB88320;
00690          else
00691             crc = crc >> 1;
00692       }
00693    }
00694 
00695    //Return CRC value
00696    return crc;
00697 }
00698