-->
Page 1 of 1

RAM test for ESP8266 or ATmega328P

PostPosted: Wed Nov 30, 2016 3:28 pm
by polypagan
I don't know if this is even useful. I wrote it to diagnose/confirm troubles with an Amica NodeMCU module that only reports <ROM gobbledygook>MEMORY FAULT.

It didn't find the problem (which leaves me still in the dark), but I believe it would if the tested RAM where faulty.

Anyhow, here it is. Not polished. Let me know what you think if you play with it.

Code: Select all/*************************************************************************
 * 20161129 DdelV
 *
 * Can ESP8266/ATmega328p RAM be tested?
 * Apparently so, if one is careful!
 *
 * This code was written (and cribbed) to test ESP8266 RAM
 * Also works on Arduino chips, if there's a UART.
 *
 * Allocate (just about) the largest chunk of
 * RAM that malloc() can be made to return, and tests that
 * (or most of it).
 *
 * Works! (occasionally stack dumps on ESP8266)
 */

int stackBot()
{
  int v;  // declare a dynamic variable
  return (int) &v;  // return it's address, that's stack bottom (right now..)
}

/**********************************************************************
 *
 * The following (3) routines are from:
 * http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C
 *
 **********************************************************************/
 
typedef unsigned char datum;    /* Set the data bus width to 8 bits.  */


/**********************************************************************
 *
 * Function:    memTestDataBus()
 *
 * Description: Test the data bus wiring in a memory region by
 *              performing a walking 1's test at a fixed address
 *              within that region.  The address (and hence the
 *              memory region) is selected by the caller.
 *
 * Notes:       
 *
 * Returns:     0 if the test succeeds. 
 *              A non-zero result is the first pattern that failed.
 *
 **********************************************************************/
datum
memTestDataBus(volatile datum * address)
{
    datum pattern;


    /*
     * Perform a walking 1's test at the given address.
     */
    for (pattern = 1; pattern != 0; pattern <<= 1)
    {
        /*
         * Write the test pattern.
         */
        *address = pattern;

        /*
         * Read it back (immediately is okay for this test).
         */
        if (*address != pattern)
        {
            return (pattern);
        }
    }

    return (0);

}   /* memTestDataBus() */
/**********************************************************************
 *
 * Function:    memTestAddressBus()
 *
 * Description: Test the address bus wiring in a memory region by
 *              performing a walking 1's test on the relevant bits
 *              of the address and checking for aliasing. This test
 *              will find single-bit address failures such as stuck
 *              -high, stuck-low, and shorted pins.  The base address
 *              and size of the region are selected by the caller.
 *
 * Notes:       For best results, the selected base address should
 *              have enough LSB 0's to guarantee single address bit
 *              changes.  For example, to test a 64-Kbyte region,
 *              select a base address on a 64-Kbyte boundary.  Also,
 *              select the region size as a power-of-two--if at all
 *              possible.
 *
 * Returns:     NULL if the test succeeds. 
 *              A non-zero result is the first address at which an
 *              aliasing problem was uncovered.  By examining the
 *              contents of memory, it may be possible to gather
 *              additional information about the problem.
 *
 **********************************************************************/
datum *
memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes)
{
    unsigned long addressMask = (nBytes/sizeof(datum) - 1);
    unsigned long offset;
    unsigned long testOffset;

    datum pattern     = (datum) 0xAAAAAAAA;
    datum antipattern = (datum) 0x55555555;


    /*
     * Write the default pattern at each of the power-of-two offsets.
     */
    for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
    {
        baseAddress[offset] = pattern;
    }

    /*
     * Check for address bits stuck high.
     */
    testOffset = 0;
    baseAddress[testOffset] = antipattern;

    for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
    {
        if (baseAddress[offset] != pattern)
        {
            return ((datum *) &baseAddress[offset]);
        }
    }

    baseAddress[testOffset] = pattern;

    /*
     * Check for address bits stuck low or shorted.
     */
    for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
    {
        baseAddress[testOffset] = antipattern;

    if (baseAddress[0] != pattern)
    {
      return ((datum *) &baseAddress[testOffset]);
    }

        for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
        {
            if ((baseAddress[offset] != pattern) && (offset != testOffset))
            {
                return ((datum *) &baseAddress[testOffset]);
            }
        }

        baseAddress[testOffset] = pattern;
    }

    return (NULL);

}   /* memTestAddressBus() */
/**********************************************************************
 *
 * Function:    memTestDevice()
 *
 * Description: Test the integrity of a physical memory device by
 *              performing an increment/decrement test over the
 *              entire region.  In the process every storage bit
 *              in the device is tested as a zero and a one.  The
 *              base address and the size of the region are
 *              selected by the caller.
 *
 * Notes:       
 *
 * Returns:     NULL if the test succeeds.
 *
 *              A non-zero result is the first address at which an
 *              incorrect value was read back.  By examining the
 *              contents of memory, it may be possible to gather
 *              additional information about the problem.
 *
 **********************************************************************/
datum *
memTestDevice(volatile datum * baseAddress, unsigned long nBytes) 
{
    unsigned long offset;
    unsigned long nWords = nBytes / sizeof(datum);

    datum pattern;
    datum antipattern;


    /*
     * Fill memory with a known pattern.
     */
    for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
    {
        baseAddress[offset] = pattern;
    }

    /*
     * Check each location and invert it for the second pass.
     */
    for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
    {
        if (baseAddress[offset] != pattern)
        {
            return ((datum *) &baseAddress[offset]);
        }

        antipattern = ~pattern;
        baseAddress[offset] = antipattern;
    }

    /*
     * Check each location for the inverted pattern and zero it.
     */
    for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
    {
        antipattern = ~pattern;
        if (baseAddress[offset] != antipattern)
        {
            return ((datum *) &baseAddress[offset]);
        }
    }

    return (NULL);

}   /* memTestDevice() */

// select an impossible RAM size based on processor
// (choosing too large a value confuses malloc() on Atmel chip.)
#if defined (__AVR_ATmega328P__)
  unsigned int fR=2048;      // 100% of physical RAM
#else
  unsigned long fR=81920L;    // default to ESP8266
#endif

void *hT;         // these are global (static) because shared between setup() & loop()
// following constant tuned via trial & error.
const int callStack = 20; // allows called test routines to have an absolutely minimal stackframe.

void setup() {

  Serial.begin(115200);

// fR begins very large
  while ((hT = malloc(fR)) == NULL) {
    fR -= 32;   // gradually get real
  }
 
  Serial.println();
  Serial.print(fR,DEC);
  Serial.print(F(" (0x"));
  Serial.print(fR,HEX);
  Serial.println(F(") bytes of RAM free."));
 
  Serial.print(F("Heap top is 0x"));
  Serial.println((int)hT, HEX);
 
  Serial.print(F("Stack bottom is 0x"));
  Serial.println(stackBot(), HEX);
 
  Serial.print(F("Testing 0x"));
  Serial.print(fR-callStack, HEX);    // alloc size less stackframe
  Serial.print(F(" bytes from 0x"));
  Serial.print((int)hT, HEX);         // base of RAM to test
  Serial.print(F(" to 0x"));
  Serial.println(stackBot()-callStack, HEX); // limit of testing

}
unsigned char i=0;  // global to preserve stack space during testing
void loop() {
 
  datum* bad;
  datum f;

  if ((f=memTestDataBus((datum *)hT)) != 0) {
    Serial.print(F("memTestDataBus(0x"));
    Serial.print((int)hT, HEX);
    Serial.print(F(") fails with error 0x"));
    Serial.println(f, HEX);
  } else if ((bad = memTestAddressBus((datum *)hT, (unsigned long)(fR-callStack))) != NULL) {
    Serial.print(F("memTestAddressBus(0x"));
    Serial.print((int)hT, HEX);
    Serial.print(F(") fails at address 0x"));
    Serial.println((int)bad, HEX);
  } else if ((bad = memTestDevice((datum *)hT, (unsigned long)(fR-callStack))) != NULL) {
    Serial.print(F("memTestDevice(0x"));
    Serial.print((int)hT, HEX);
    Serial.print(F(") fails at address 0x"));
    Serial.println((int)bad, HEX);
  } else {    // print milestones (so we know we didn't eat ourselves alive)
    Serial.print('.');
    ++i;
    if ((i % 128) == 0) Serial.println();
  }
}


Have fun!

Re: RAM test for ESP8266 or ATmega328P

PostPosted: Thu Mar 10, 2022 2:26 pm
by H3wastooshort
I have made some small changes to the code.
[list=]
[*]Your typedef for the datum was not working for some reason so i just omitted it.
[*]The builtin LED now blinks every newline.
[*]ESP32 RAM size was added.
[*]The dot and newline dividers can be adjusted bet MCU to try and speed up testing.
[/list]
Otherwise very nice. Thank you.

My Sketch:
Code: Select all/*************************************************************************
   20161129 DdelV

   Can ESP8266/ATmega328p RAM be tested?
   Apparently so, if one is careful!

   This code was written (and cribbed) to test ESP8266 RAM
   Also works on Arduino chips, if there's a UART.

   Allocate (just about) the largest chunk of
   RAM that malloc() can be made to return, and tests that
   (or most of it).

   Works! (occasionally stack dumps on ESP8266)
*/

int stackBot()
{
  int v;  // declare a dynamic variable
  return (int) &v;  // return it's address, that's stack bottom (right now..)
}

/**********************************************************************

   The following (3) routines are from:
   http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C

 **********************************************************************/

/**********************************************************************

   Function:    memTestDataBus()

   Description: Test the data bus wiring in a memory region by
                performing a walking 1's test at a fixed address
                within that region.  The address (and hence the
                memory region) is selected by the caller.

   Notes:

   Returns:     0 if the test succeeds.
                A non-zero result is the first pattern that failed.

 **********************************************************************/
unsigned char memTestDataBus(volatile unsigned char * address)
{
  unsigned char pattern;


  /*
     Perform a walking 1's test at the given address.
  */
  for (pattern = 1; pattern != 0; pattern <<= 1)
  {
    /*
       Write the test pattern.
    */
    *address = pattern;

    /*
       Read it back (immediately is okay for this test).
    */
    if (*address != pattern)
    {
      return (pattern);
    }
  }

  return (0);

}   /* memTestDataBus() */
/**********************************************************************

   Function:    memTestAddressBus()

   Description: Test the address bus wiring in a memory region by
                performing a walking 1's test on the relevant bits
                of the address and checking for aliasing. This test
                will find single-bit address failures such as stuck
                -high, stuck-low, and shorted pins.  The base address
                and size of the region are selected by the caller.

   Notes:       For best results, the selected base address should
                have enough LSB 0's to guarantee single address bit
                changes.  For example, to test a 64-Kbyte region,
                select a base address on a 64-Kbyte boundary.  Also,
                select the region size as a power-of-two--if at all
                possible.

   Returns:     NULL if the test succeeds.
                A non-zero result is the first address at which an
                aliasing problem was uncovered.  By examining the
                contents of memory, it may be possible to gather
                additional information about the problem.

 **********************************************************************/
unsigned char * memTestAddressBus(volatile unsigned char * baseAddress, unsigned long nBytes)
{
  unsigned long addressMask = (nBytes / sizeof(unsigned char) - 1);
  unsigned long offset;
  unsigned long testOffset;

  unsigned char pattern     = (unsigned char) 0xAAAAAAAA;
  unsigned char antipattern = (unsigned char) 0x55555555;


  /*
     Write the default pattern at each of the power-of-two offsets.
  */
  for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
  {
    baseAddress[offset] = pattern;
  }

  /*
     Check for address bits stuck high.
  */
  testOffset = 0;
  baseAddress[testOffset] = antipattern;

  for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
  {
    if (baseAddress[offset] != pattern)
    {
      return ((unsigned char *) &baseAddress[offset]);
    }
  }

  baseAddress[testOffset] = pattern;

  /*
     Check for address bits stuck low or shorted.
  */
  for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
  {
    baseAddress[testOffset] = antipattern;

    if (baseAddress[0] != pattern)
    {
      return ((unsigned char *) &baseAddress[testOffset]);
    }

    for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
    {
      if ((baseAddress[offset] != pattern) && (offset != testOffset))
      {
        return ((unsigned char *) &baseAddress[testOffset]);
      }
    }

    baseAddress[testOffset] = pattern;
  }

  return (NULL);

}   /* memTestAddressBus() */
/**********************************************************************

   Function:    memTestDevice()

   Description: Test the integrity of a physical memory device by
                performing an increment/decrement test over the
                entire region.  In the process every storage bit
                in the device is tested as a zero and a one.  The
                base address and the size of the region are
                selected by the caller.

   Notes:

   Returns:     NULL if the test succeeds.

                A non-zero result is the first address at which an
                incorrect value was read back.  By examining the
                contents of memory, it may be possible to gather
                additional information about the problem.

 **********************************************************************/
unsigned char * memTestDevice(volatile unsigned char * baseAddress, unsigned long nBytes)
{
  unsigned long offset;
  unsigned long nWords = nBytes / sizeof(unsigned char);

  unsigned char pattern;
  unsigned char antipattern;


  /*
     Fill memory with a known pattern.
  */
  for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
  {
    baseAddress[offset] = pattern;
  }

  /*
     Check each location and invert it for the second pass.
  */
  for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
  {
    if (baseAddress[offset] != pattern)
    {
      return ((unsigned char *) &baseAddress[offset]);
    }

    antipattern = ~pattern;
    baseAddress[offset] = antipattern;
  }

  /*
     Check each location for the inverted pattern and zero it.
  */
  for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
  {
    antipattern = ~pattern;
    if (baseAddress[offset] != antipattern)
    {
      return ((unsigned char *) &baseAddress[offset]);
    }
  }

  return (NULL);

}   /* memTestDevice() */

// select an impossible RAM size based on processor
// (choosing too large a value confuses malloc() on Atmel chip.)
#if defined (__AVR_ATmega328P__)
unsigned int fR = 2048;    // 100% of physical RAM
#define DOT_DIV 1
#define NL_DIV 128

#elif defined (ESP8266)
unsigned long fR = 81920L;  // ESP8266
#define DOT_DIV 4
#define NL_DIV 512

#elif defined (ESP32)
unsigned long fR = 327680L;  // ESP32
#ifndef LED_BUILTIN //Is not defined by default so....
#define LED_BUILTIN 2
#endif
#define DOT_DIV 4
#define NL_DIV 512

#else
#error Uh sorry I have no idea what MCU this is compiling for... Please add it around line 230 together with its RAM size.

#endif

void *hT;         // these are global (static) because shared between setup() & loop()
// following constant tuned via trial & error.
const int callStack = 20; // allows called test routines to have an absolutely minimal stackframe.

//uint32_t pass = 0;
static bool led_state = false;

void setup() {

  Serial.begin(1000000);
  pinMode(LED_BUILTIN, OUTPUT);

  // fR begins very large
  while ((hT = malloc(fR)) == NULL) {
    fR -= 32;   // gradually get real
  }

  Serial.println();
  Serial.print(fR, DEC);
  Serial.print(F(" (0x"));
  Serial.print(fR, HEX);
  Serial.println(F(") bytes of RAM free."));

  Serial.print(F("Heap top is 0x"));
  Serial.println((int)hT, HEX);

  Serial.print(F("Stack bottom is 0x"));
  Serial.println(stackBot(), HEX);

  Serial.print(F("Testing 0x"));
  Serial.print(fR - callStack, HEX);  // alloc size less stackframe
  Serial.print(F(" bytes from 0x"));
  Serial.print((int)hT, HEX);         // base of RAM to test
  Serial.print(F(" to 0x"));
  Serial.println(stackBot() - callStack, HEX); // limit of testing

}
unsigned char i = 0; // global to preserve stack space during testing

void loop() {

  unsigned char* bad;
  unsigned char f;

  if ((f = memTestDataBus((unsigned char *)hT)) != 0) {
    Serial.print(F("memTestDataBus(0x"));
    Serial.print((int)hT, HEX);
    Serial.print(F(") fails with error 0x"));
    Serial.println(f, HEX);
  } else if ((bad = memTestAddressBus((unsigned char *)hT, (unsigned long)(fR - callStack))) != NULL) {
    Serial.print(F("memTestAddressBus(0x"));
    Serial.print((int)hT, HEX);
    Serial.print(F(") fails at address 0x"));
    Serial.println((int)bad, HEX);
  } else if ((bad = memTestDevice((unsigned char *)hT, (unsigned long)(fR - callStack))) != NULL) {
    Serial.print(F("memTestDevice(0x"));
    Serial.print((int)hT, HEX);
    Serial.print(F(") fails at address 0x"));
    Serial.println((int)bad, HEX);
  } else {    // print milestones (so we know we didn't eat ourselves alive)
    ++i;
    if ((i % DOT_DIV) == 0) {
      Serial.print('.');
    }
    if ((i % NL_DIV) == 0) {
      Serial.println();
      led_state = !led_state;
      digitalWrite(LED_BUILTIN, led_state);
    }
  }
}


Diff:
Code: Select all2,15c2,15
<  * 20161129 DdelV
<  *
<  * Can ESP8266/ATmega328p RAM be tested?
<  * Apparently so, if one is careful!
<  *
<  * This code was written (and cribbed) to test ESP8266 RAM
<  * Also works on Arduino chips, if there's a UART.
<  *
<  * Allocate (just about) the largest chunk of
<  * RAM that malloc() can be made to return, and tests that
<  * (or most of it).
<  *
<  * Works! (occasionally stack dumps on ESP8266)
<  */
---
>    20161129 DdelV
>
>    Can ESP8266/ATmega328p RAM be tested?
>    Apparently so, if one is careful!
>
>    This code was written (and cribbed) to test ESP8266 RAM
>    Also works on Arduino chips, if there's a UART.
>
>    Allocate (just about) the largest chunk of
>    RAM that malloc() can be made to return, and tests that
>    (or most of it).
>
>    Works! (occasionally stack dumps on ESP8266)
> */
24,30d23
<  *
<  * The following (3) routines are from:
<  * http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C
<  *
<  **********************************************************************/
<
< typedef unsigned char datum;    /* Set the data bus width to 8 bits.  */
31a25,28
>    The following (3) routines are from:
>    http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C
>
>  **********************************************************************/
34,46c31,43
<  *
<  * Function:    memTestDataBus()
<  *
<  * Description: Test the data bus wiring in a memory region by
<  *              performing a walking 1's test at a fixed address
<  *              within that region.  The address (and hence the
<  *              memory region) is selected by the caller.
<  *
<  * Notes:
<  *
<  * Returns:     0 if the test succeeds.
<  *              A non-zero result is the first pattern that failed.
<  *
---
>
>    Function:    memTestDataBus()
>
>    Description: Test the data bus wiring in a memory region by
>                 performing a walking 1's test at a fixed address
>                 within that region.  The address (and hence the
>                 memory region) is selected by the caller.
>
>    Notes:
>
>    Returns:     0 if the test succeeds.
>                 A non-zero result is the first pattern that failed.
>
48,49c45
< datum
< memTestDataBus(volatile datum * address)
---
> unsigned char memTestDataBus(volatile unsigned char * address)
51c47
<     datum pattern;
---
>   unsigned char pattern;
53a50,54
>   /*
>      Perform a walking 1's test at the given address.
>   */
>   for (pattern = 1; pattern != 0; pattern <<= 1)
>   {
55,57c56,63
<      * Perform a walking 1's test at the given address.
<      */
<     for (pattern = 1; pattern != 0; pattern <<= 1)
---
>        Write the test pattern.
>     */
>     *address = pattern;
>
>     /*
>        Read it back (immediately is okay for this test).
>     */
>     if (*address != pattern)
59,70c65
<         /*
<          * Write the test pattern.
<          */
<         *address = pattern;
<
<         /*
<          * Read it back (immediately is okay for this test).
<          */
<         if (*address != pattern)
<         {
<             return (pattern);
<         }
---
>       return (pattern);
71a67
>   }
73c69
<     return (0);
---
>   return (0);
77,99c73,95
<  *
<  * Function:    memTestAddressBus()
<  *
<  * Description: Test the address bus wiring in a memory region by
<  *              performing a walking 1's test on the relevant bits
<  *              of the address and checking for aliasing. This test
<  *              will find single-bit address failures such as stuck
<  *              -high, stuck-low, and shorted pins.  The base address
<  *              and size of the region are selected by the caller.
<  *
<  * Notes:       For best results, the selected base address should
<  *              have enough LSB 0's to guarantee single address bit
<  *              changes.  For example, to test a 64-Kbyte region,
<  *              select a base address on a 64-Kbyte boundary.  Also,
<  *              select the region size as a power-of-two--if at all
<  *              possible.
<  *
<  * Returns:     NULL if the test succeeds.
<  *              A non-zero result is the first address at which an
<  *              aliasing problem was uncovered.  By examining the
<  *              contents of memory, it may be possible to gather
<  *              additional information about the problem.
<  *
---
>
>    Function:    memTestAddressBus()
>
>    Description: Test the address bus wiring in a memory region by
>                 performing a walking 1's test on the relevant bits
>                 of the address and checking for aliasing. This test
>                 will find single-bit address failures such as stuck
>                 -high, stuck-low, and shorted pins.  The base address
>                 and size of the region are selected by the caller.
>
>    Notes:       For best results, the selected base address should
>                 have enough LSB 0's to guarantee single address bit
>                 changes.  For example, to test a 64-Kbyte region,
>                 select a base address on a 64-Kbyte boundary.  Also,
>                 select the region size as a power-of-two--if at all
>                 possible.
>
>    Returns:     NULL if the test succeeds.
>                 A non-zero result is the first address at which an
>                 aliasing problem was uncovered.  By examining the
>                 contents of memory, it may be possible to gather
>                 additional information about the problem.
>
101,102c97
< datum *
< memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes)
---
> unsigned char * memTestAddressBus(volatile unsigned char * baseAddress, unsigned long nBytes)
104,106c99,104
<     unsigned long addressMask = (nBytes/sizeof(datum) - 1);
<     unsigned long offset;
<     unsigned long testOffset;
---
>   unsigned long addressMask = (nBytes / sizeof(unsigned char) - 1);
>   unsigned long offset;
>   unsigned long testOffset;
>
>   unsigned char pattern     = (unsigned char) 0xAAAAAAAA;
>   unsigned char antipattern = (unsigned char) 0x55555555;
108,109d105
<     datum pattern     = (datum) 0xAAAAAAAA;
<     datum antipattern = (datum) 0x55555555;
110a107,113
>   /*
>      Write the default pattern at each of the power-of-two offsets.
>   */
>   for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
>   {
>     baseAddress[offset] = pattern;
>   }
112,115c115,123
<     /*
<      * Write the default pattern at each of the power-of-two offsets.
<      */
<     for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
---
>   /*
>      Check for address bits stuck high.
>   */
>   testOffset = 0;
>   baseAddress[testOffset] = antipattern;
>
>   for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
>   {
>     if (baseAddress[offset] != pattern)
117c125
<         baseAddress[offset] = pattern;
---
>       return ((unsigned char *) &baseAddress[offset]);
118a127
>   }
120,123c129,135
<     /*
<      * Check for address bits stuck high.
<      */
<     testOffset = 0;
---
>   baseAddress[testOffset] = pattern;
>
>   /*
>      Check for address bits stuck low or shorted.
>   */
>   for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
>   {
126c138
<     for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
---
>     if (baseAddress[0] != pattern)
128,131c140
<         if (baseAddress[offset] != pattern)
<         {
<             return ((datum *) &baseAddress[offset]);
<         }
---
>       return ((unsigned char *) &baseAddress[testOffset]);
134,143c143
<     baseAddress[testOffset] = pattern;
<
<     /*
<      * Check for address bits stuck low or shorted.
<      */
<     for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
<     {
<         baseAddress[testOffset] = antipattern;
<
<     if (baseAddress[0] != pattern)
---
>     for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
145c145,148
<       return ((datum *) &baseAddress[testOffset]);
---
>       if ((baseAddress[offset] != pattern) && (offset != testOffset))
>       {
>         return ((unsigned char *) &baseAddress[testOffset]);
>       }
148,157c151,152
<         for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
<         {
<             if ((baseAddress[offset] != pattern) && (offset != testOffset))
<             {
<                 return ((datum *) &baseAddress[testOffset]);
<             }
<         }
<
<         baseAddress[testOffset] = pattern;
<     }
---
>     baseAddress[testOffset] = pattern;
>   }
159c154
<     return (NULL);
---
>   return (NULL);
163,181c158,176
<  *
<  * Function:    memTestDevice()
<  *
<  * Description: Test the integrity of a physical memory device by
<  *              performing an increment/decrement test over the
<  *              entire region.  In the process every storage bit
<  *              in the device is tested as a zero and a one.  The
<  *              base address and the size of the region are
<  *              selected by the caller.
<  *
<  * Notes:
<  *
<  * Returns:     NULL if the test succeeds.
<  *
<  *              A non-zero result is the first address at which an
<  *              incorrect value was read back.  By examining the
<  *              contents of memory, it may be possible to gather
<  *              additional information about the problem.
<  *
---
>
>    Function:    memTestDevice()
>
>    Description: Test the integrity of a physical memory device by
>                 performing an increment/decrement test over the
>                 entire region.  In the process every storage bit
>                 in the device is tested as a zero and a one.  The
>                 base address and the size of the region are
>                 selected by the caller.
>
>    Notes:
>
>    Returns:     NULL if the test succeeds.
>
>                 A non-zero result is the first address at which an
>                 incorrect value was read back.  By examining the
>                 contents of memory, it may be possible to gather
>                 additional information about the problem.
>
183,184c178
< datum *
< memTestDevice(volatile datum * baseAddress, unsigned long nBytes)
---
> unsigned char * memTestDevice(volatile unsigned char * baseAddress, unsigned long nBytes)
186,187c180,181
<     unsigned long offset;
<     unsigned long nWords = nBytes / sizeof(datum);
---
>   unsigned long offset;
>   unsigned long nWords = nBytes / sizeof(unsigned char);
189,190c183,184
<     datum pattern;
<     datum antipattern;
---
>   unsigned char pattern;
>   unsigned char antipattern;
193,199c187,193
<     /*
<      * Fill memory with a known pattern.
<      */
<     for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
<     {
<         baseAddress[offset] = pattern;
<     }
---
>   /*
>      Fill memory with a known pattern.
>   */
>   for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
>   {
>     baseAddress[offset] = pattern;
>   }
201,204c195,200
<     /*
<      * Check each location and invert it for the second pass.
<      */
<     for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
---
>   /*
>      Check each location and invert it for the second pass.
>   */
>   for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
>   {
>     if (baseAddress[offset] != pattern)
206,212c202
<         if (baseAddress[offset] != pattern)
<         {
<             return ((datum *) &baseAddress[offset]);
<         }
<
<         antipattern = ~pattern;
<         baseAddress[offset] = antipattern;
---
>       return ((unsigned char *) &baseAddress[offset]);
215,218c205,215
<     /*
<      * Check each location for the inverted pattern and zero it.
<      */
<     for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
---
>     antipattern = ~pattern;
>     baseAddress[offset] = antipattern;
>   }
>
>   /*
>      Check each location for the inverted pattern and zero it.
>   */
>   for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
>   {
>     antipattern = ~pattern;
>     if (baseAddress[offset] != antipattern)
220,224c217
<         antipattern = ~pattern;
<         if (baseAddress[offset] != antipattern)
<         {
<             return ((datum *) &baseAddress[offset]);
<         }
---
>       return ((unsigned char *) &baseAddress[offset]);
225a219
>   }
227c221
<     return (NULL);
---
>   return (NULL);
234c228,244
<   unsigned int fR=2048;      // 100% of physical RAM
---
> unsigned int fR = 2048;    // 100% of physical RAM
> #define DOT_DIV 1
> #define NL_DIV 128
>
> #elif defined (ESP8266)
> unsigned long fR = 81920L;  // ESP8266
> #define DOT_DIV 4
> #define NL_DIV 512
>
> #elif defined (ESP32)
> unsigned long fR = 327680L;  // ESP32
> #ifndef LED_BUILTIN //Is not defined by default so....
> #define LED_BUILTIN 2
> #endif
> #define DOT_DIV 4
> #define NL_DIV 512
>
236c246,247
<   unsigned long fR=81920L;    // default to ESP8266
---
> #error Uh sorry I have no idea what MCU this is compiling for... Please add it around line 230 together with its RAM size.
>
242a254,256
> //uint32_t pass = 0;
> static bool led_state = false;
>
245c259,260
<   Serial.begin(115200);
---
>   Serial.begin(1000000);
>   pinMode(LED_BUILTIN, OUTPUT);
247c262
< // fR begins very large
---
>   // fR begins very large
251c266
<
---
>
253c268
<   Serial.print(fR,DEC);
---
>   Serial.print(fR, DEC);
255c270
<   Serial.print(fR,HEX);
---
>   Serial.print(fR, HEX);
257c272
<
---
>
260c275
<
---
>
263c278
<
---
>
265c280
<   Serial.print(fR-callStack, HEX);    // alloc size less stackframe
---
>   Serial.print(fR - callStack, HEX);  // alloc size less stackframe
269c284
<   Serial.println(stackBot()-callStack, HEX); // limit of testing
---
>   Serial.println(stackBot() - callStack, HEX); // limit of testing
272c287,288
< unsigned char i=0;  // global to preserve stack space during testing
---
> unsigned char i = 0; // global to preserve stack space during testing
>
274,276d289
<
<   datum* bad;
<   datum f;
278c291,294
<   if ((f=memTestDataBus((datum *)hT)) != 0) {
---
>   unsigned char* bad;
>   unsigned char f;
>
>   if ((f = memTestDataBus((unsigned char *)hT)) != 0) {
283c299
<   } else if ((bad = memTestAddressBus((datum *)hT, (unsigned long)(fR-callStack))) != NULL) {
---
>   } else if ((bad = memTestAddressBus((unsigned char *)hT, (unsigned long)(fR - callStack))) != NULL) {
288c304
<   } else if ((bad = memTestDevice((datum *)hT, (unsigned long)(fR-callStack))) != NULL) {
---
>   } else if ((bad = memTestDevice((unsigned char *)hT, (unsigned long)(fR - callStack))) != NULL) {
294d309
<     Serial.print('.');
296c311,318
<     if ((i % 128) == 0) Serial.println();
---
>     if ((i % DOT_DIV) == 0) {
>       Serial.print('.');
>     }
>     if ((i % NL_DIV) == 0) {
>       Serial.println();
>       led_state = !led_state;
>       digitalWrite(LED_BUILTIN, led_state);
>     }