Author Topic: 52235 and Ethernet buffers  (Read 5182 times)

Offline Predielis

  • Newbie
  • *
  • Posts: 16
    • View Profile
52235 and Ethernet buffers
« on: February 02, 2012, 10:50:23 AM »
Hello, I'm experimenting with an old M52235EVB board.
It seems my application is dropping UDP packets, so I'm trying to raise NUMBER_OF_RX_BUFFERS_IN_ETHERNET_DEVICE.
It seems it works only if at the same time I reduce LAN_BUFFER_SIZE, it seems that their product should be less than a certain threshold. Eg I can double NUMBER_OF... only if  LAN_BUFFER_SIZE is set to one half.
Is my impression correct? How can I overcome the problem?
uTasker 1.3sp8 with Codewarrior 7.2.

Is this older CPU still worth, or is it better to switch to something newer? I'm seeing the compiler doing nasty errors, even with optimization off.

Thanks.
« Last Edit: February 02, 2012, 04:30:31 PM by Predielis »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3060
    • View Profile
    • uTasker
Re: 52235 and Ethernet buffers
« Reply #1 on: February 03, 2012, 12:15:31 AM »
Hi

I suspect that the problem with raising the NUMBER_OF_RX_BUFFERS_IN_ETHERNET is because each added buffer requires another (approx.) 1500 bytes of memory and possibly the heap is being exhausted. As you have noticed, it is Ok when you reduce the LAN_BUFFER_SIZE since this then compensations the total amount of memory required (NUMBER_OF_RX_BUFFERS_IN_ETHERNET x LAN_BUFFER_SIZE).

Check the RAM size used in the project since the M5225x project tends to be configured for 32k RAM (the idea is that the project can generally run on the smallest foot-print parts) and change it to 64k to make full use of the SRAM. In addition you will need to increase the size for OUR_HEAP_SIZE so that the greater quantity of LAN buffers have place in it.

If you have a lot of fast UDP frames being received it can help to configure with USE_MULTIPLE_BUFFERS. This will reserve a higher quantity of 256 byte long reception buffers which are then combined to receive longer frames when necessary. There are however a lot of buffers available for bursts of fast short frames and so an overrun is much less likely. The down side is that there needs to be an additional long buffer for reconstructing a linear buffer when longer reception frames straddle multiple ones, plus the copy time, but it can have useful advantages in some situations.

It is difficult to say whether the M5225x has a future or not. I think that it may still be a little cheaper than the Kinetis but the Kinetis do have smaller code size and generally have more, and faster, peripherals packed in to them (not mentioning additional lower power modes).

Codewarrior 7.2 may cause some problems but I though only with optimisation. I still use CW7.1.1 because it works very well.

Regards

Mark




Offline Predielis

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: 52235 and Ethernet buffers
« Reply #2 on: February 03, 2012, 11:53:50 AM »
I raised OUR_HEAP_SIZE from 19*1024 to 25*1024,  SIZE_OF_RAM from 32*1024 to 64*1024 but I can't have a single buffer more than with the default parameters.
Anyway USE_MULTIPLE_BUFFERS seems to solve my problem, so for now I'm happy with it.
Of course, if you are interested in this issue and need me to make some more tests, please ask.

Thanks again.

Edit: 52235 only have 32K of RAM, so SIZE_OF_RAM can't be touched. I'll redo my test with a smaller heap increase.
Edit2: set OUR_HEAP_SIZE to 21 but still can't allocate one more buffer.
« Last Edit: February 03, 2012, 12:15:01 PM by Predielis »

Offline Predielis

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: 52235 and Ethernet buffers
« Reply #3 on: October 08, 2012, 02:26:36 PM »
From time to time I get back to this old project.
The program crashes when USE_MULTIPLE_BUFFERS is defined and a packet longer than LAN_BUFFER_SIZE is received.
I made a quick fix in fnExtractNextRx(void), but there is certainly a better way.

if (iBuffers*256 < LAN_BUFFER_SIZE - 256)  // line added
              while (iBuffers--) {
                uMemcpy(ptrInputBuffer, ptrRxBd->ptrBD_Data, 256);
                ptrInputBuffer += 256;
                usFrameLength += 256;
#ifdef USE_IP_STATS
                if (ptrRxBd->usBDControl & OVERRUN_FRAME) {
                    fnIncrementEthernetStats(TOTAL_LOST_RX_FRAMES);      // we lost a frame due to RX overrun so count the event
                }

and

if((ptrRxBd->usBDLength - usFrameLength) < 256)  //line added
    uMemcpy(ptrInputBuffer, ptrRxBd->ptrBD_Data, (ptrRxBd->usBDLength - usFrameLength)); 

Regards

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3060
    • View Profile
    • uTasker
Re: 52235 and Ethernet buffers
« Reply #4 on: October 10, 2012, 10:44:37 PM »
Hi

Many thanks for pointing this out.

It is correct that the linear buffer is really not protected against overflow as it was so any unexpectedly long frames in the network (or reduced LAN_BUFFER_SIZE) could indeed cause buffer overflow to take place (with the possible nasty side-effects that go with it).

I did a bit of thinking and decided on the following correction:

Code: [Select]
#ifdef USE_MULTIPLE_BUFFERS
static unsigned char ucEthernetInput[LAN_BUFFER_SIZE + 4];               // {166} linear buffer for collecting a complete Ethernet reception frame

// We are more or less forced to copy a number of input buffers to a linear input buffer so that it can be handled by standard routines
// Therefore we step through one or a number of receive buffer descriptors, receiving a complete frame spread out within them
//
static unsigned short fnExtractNextRx(void)
{
    unsigned short usFrameLength = 0;
    int iBuffers = 0;
    volatile M5223X_FEC_BD *rx_bd = ptrRxBd;

    while (1) {
        if (!(rx_bd->usBDLength)) {
            break;                                                       // frame reception not complete
        }
        if (rx_bd->usBDControl & LAST_IN_FRAME) {                        // complete message available
            unsigned char *ptrInputBuffer = ucEthernetInput;
            while (iBuffers--) {
                usFrameLength += 256;                                    // frame size after the copy
                if (usFrameLength <= sizeof(ucEthernetInput)) {          // {166} only copy if there is space for it in the linear buffer
                    uMemcpy(ptrInputBuffer, ptrRxBd->ptrBD_Data, 256);
                }
                ptrInputBuffer += 256;
    #ifdef USE_IP_STATS
                if (ptrRxBd->usBDControl & OVERRUN_FRAME) {
                    fnIncrementEthernetStats(TOTAL_LOST_RX_FRAMES);      // we lost a frame due to RX overrun so count the event
                }
    #endif
                ptrRxBd->usBDLength = 0;
                fnFreeEthernetBuffer(-1);
            }
            if (ptrRxBd->usBDLength <= sizeof(ucEthernetInput)) {        // {166} only copy if there is space for it in the linear buffer
                uMemcpy(ptrInputBuffer, ptrRxBd->ptrBD_Data, (ptrRxBd->usBDLength - usFrameLength)); // final copy or remaing content
              //usFrameLength += ptrRxBd->usBDLength;                    // {166} - correct frame reception length
                usFrameLength = ptrRxBd->usBDLength;                     // complete frame length
                usFrameLength -= 4;                                      // {124} remove the CRC32 which is saved at the end of a received frame
            }
            else {
                usFrameLength = 0;                                       // since the received frame didn't fit in the linear buffer we silently drop it
            }
    #ifdef USE_IP_STATS
            if (ptrRxBd->usBDControl & OVERRUN_FRAME) {
                fnIncrementEthernetStats(TOTAL_LOST_RX_FRAMES);          // we lost a frame due to RX overrun so count the event
            }
    #endif
            ptrRxBd->usBDLength = 0;
            fnFreeEthernetBuffer(-1);
            break;
        }
        else {
            iBuffers++;                                                  // count the number of full buffers
            if (rx_bd->usBDControl & WRAP_BIT) {
                rx_bd = (M5223X_FEC_BD*)ERDSR;                           // set to first BD
            }
            else {
                rx_bd++;                                                 // increment to next
            }
        }
    }
    return usFrameLength;
}
#endif

This will protect the linear buffer and also silently drop a frame that doesn't fit into it (by returning 0). I increased the buffer size to allow also the CRC-32 at the end of the Ethernet frame to have space since this device always include it. Furthermore I noticed that the value of usFrameLength was not correct (see corrected line - change marked with {166}). This is generaly not of significance to IP since the protocol handles length details but could possibly cause problems if bridging Ethernet content.

Regards

Mark

Offline Predielis

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: 52235 and Ethernet buffers
« Reply #5 on: October 21, 2012, 09:09:12 PM »
It works, many thanks.