Addressing on the Redboard-Turbo - what's the deal?

I got a Redboard-Turbo from my daughter for Christmas. I am trying to port my FORTH system to it, but I am running into an issue.

The addresses seem … well … curious. If I do this:

char buf[32];

long longInt = 0x12345678;

long *p = &longInt;

sprintf(“0x%lx\n”, p);

SerialUSB.print(buf);

The output is a large number that looks like this: 0x20000071. This does not appear to be a valid address, because when I do:

*p = 0x11112222;

SerialUSB.print(“got to here”);

it stops responding, and I never get the “got to here” message.

What am I missing?

Tried on a SAMD51 board :

uses the same Arduino core, but is using Serial instead of SerialUSB. But also tried on another SAMD board the used SerialUSB… same outcome

Setup() {
  Serial.begin(115200);
  delay(5000);

  char buf[32];
  long longInt = 0x12345678;
  long *p = &longInt;
  Serial.println("Here");
  sprintf(buf, "0x%lx\n", p);
  Serial.print(buf);
}

using long *p = &longInt; it gives 0x2002ffc4

using long p = 0x11112222; invalid conversion from ‘int’ to 'long int’ [-fpermissive]

using long *p = (long *) 0x11112222; it gives 0x11112222

Try using type-casting with to (long *)

Apologies, my example was not a good representation of the problem, it was a much simplified version of what I am actually doing. As such, it didn’t accurately reflect the problem.

After playing with it more, I think I understand what is going on.

I am porting my byte-code based implementation of Forth to the Redboard. In this system, the value at any address can be interpreted by the system as desired … a byte, a 2-byte (16-bit) number, a 4 byte (32-bit) number, variable-length string, it doesn’t matter. On PC, you can cast any address to a (long *), an it behaves as expected, even when the ‘pointed-to’ address is odd.

On the other Arduino-board (ATMEGA-2560) to which I have ported my Forth, it is also not a problem.

On the Redboard-Turbo, that doesn’t appear to be the case. If you have a (long *), it needs to point to an address that is aligned to a 4-byte boundary, otherwise when you de-reference it, it hangs.

I can work around it by building the 2- and 4- byte values by hand, but that would be a pain, and it would be specific to the RedBoard (and other boards that I come across with the same restriction), so I’d like to not have to do that is I can avoid it.

Here is my example code … this is a better illustration of the problem:

// #define ARDUINO_R3
// #define ATMEGA_2560
#define REDBOARD_TURBO

#ifdef REDBOARD_TURBO
#define SERIAL SerialUSB
#define MEM_SZ 32*1024
#define MEM_RESERVE 4*1024
#endif

#ifdef ATMEGA_2560
#define SERIAL Serial
#define MEM_SZ 8*1024
#define MEM_RESERVE 2*1024
#endif

#ifdef ARDUINO_R3
#define SERIAL Serial
#define MEM_SZ 2*1024
#define MEM_RESERVE 3*256
#endif

#define sendOutput(str) SERIAL.print(str)

void sizeIs(const char *what, long addr, int sz);

byte mem[(MEM_SZ)-(MEM_RESERVE)];
byte *here = &mem[0];

void sizeIs(const char *what, long addr, int sz) {
    char buf[64];
    sprintf(buf, "%s: [%08lx -> %08lx], %d bytes\n", what, addr, (addr+sz-1), sz);
    sendOutput(buf);
}

void cComma(byte val) {
    char buf[32];
    *here = val;
    sprintf(buf, "here is 0x%08lx, (0x%02x),", here, *here);
    sendOutput(buf);
    here += sizeof(val);
    sprintf(buf, " now 0x%08lx\n", here);
    sendOutput(buf);
}

void lComma(long val) {
    char buf[32];
    *(long *)here = val;
    sprintf(buf, "here is 0x%08lx, (0x%08lx),", here, *(long *)here);
    sendOutput(buf);
    here += sizeof(val);
    sprintf(buf, " now 0x%08lx\n", here);
    sendOutput(buf);
}

void setup() {
  SERIAL.begin(19200);

  while (!SERIAL);
  while (SERIAL.available() > 0) SERIAL.read();
    sendOutput(F("\n"));
    long lInt = 0x01020304;
    short sInt = 0x2233;
    int iInt;
    byte *pByte;
    sizeIs("long",   (long)&lInt,   sizeof(lInt));
    sizeIs("short",  (long)&sInt,   sizeof(sInt));
    sizeIs("int",    (long)&iInt,   sizeof(iInt));
    sizeIs("byte *", (long)&pByte,  sizeof(pByte));
    sizeIs("mem",    (long)&mem[0], sizeof(mem));
    sizeIs("here",   (long)&here,   sizeof(here));

    // this works, because there are 4 cCommas(), so when it gets
    // to the lComma(), *here points to a 4-byte boundary
    cComma(0x08);
    cComma(0x09);
    cComma(0x10);
    cComma(0x11);
    lComma(0x04030201);
    cComma(0x12);
    cComma(0x13);
    cComma(0x14);
    cComma(0x15);

    // This does not work
    cComma(0x16);
    lComma(0x11223344); // it hangs here
    cComma(0x17);
}

void loop() {
}

Output:

12:58:02.257 -> 
12:58:02.257 -> long: [20007fd4 -> 20007fd7], 4 bytes
12:58:02.257 -> short: [20007fd2 -> 20007fd3], 2 bytes
12:58:02.257 -> int: [20007fd8 -> 20007fdb], 4 bytes
12:58:02.257 -> byte *: [20007fdc -> 20007fdf], 4 bytes
12:58:02.257 -> mem: [20000120 -> 2000711f], 28672 bytes
12:58:02.257 -> here: [20000000 -> 20000003], 4 bytes
12:58:02.257 -> here is 0x20000120, (0x08), now 0x20000121
12:58:02.257 -> here is 0x20000121, (0x09), now 0x20000122
12:58:02.257 -> here is 0x20000122, (0x10), now 0x20000123
12:58:02.257 -> here is 0x20000123, (0x11), now 0x20000124
12:58:02.257 -> here is 0x20000124, (0x04030201), now 0x20000128
12:58:02.257 -> here is 0x20000128, (0x12), now 0x20000129
12:58:02.257 -> here is 0x20000129, (0x13), now 0x2000012a
12:58:02.257 -> here is 0x2000012a, (0x14), now 0x2000012b
12:58:02.257 -> here is 0x2000012b, (0x15), now 0x2000012c
12:58:02.257 -> here is 0x2000012c, (0x16), now 0x2000012d

Many 32-bit processors require memory accesses to be aligned on 4-byte boundaries. The compiler knows how to pack smaller size variables into a 32-bit word and can hide this from you.

/mike

Understood. Apparently, the RedBoard-Turbo has one such processor. :slight_smile:

Unfortunately, that’s correct for any of the Cortex M0 processors…

https://developer.arm.com/documentation … -alignment

/mike

There it is … the documentation that explains my findings. thanks. Sigh … such is life … I’ll have to work around it. i’ll use #ifdefs to handle the different cases.