Porting code from 8 bit AVR to 32bit ARM arduinos

Hi,

I need to port existing code developed for 8 bit arduinos (MEGA,micro and 1284p) to arduino zero clone based on SAMD21 chip.

In doing so I had to replace int and unsigned int variables with int16_t and uint16_t respectively to ensure proper operation since int variables are now represented with 4 bytes instead of 2.

Same for functions that return or accept a value .

My question: are there any other types of variables that need to be changed to maintain compatibility? (byte, long, unsigned long, etc)

What the best practice in doing so ? Just do find and replace?

Thanks!

Hello,

Pending on the type of code, it is very well possible that the code simply works.
Of course if there are casts and pointer math, then it is something else.
Have you analyzed the code to see if there is a problem anyway?

Sharing the code on the forum (if it is not too much) might help the Members to provide more detailed advice.

Best regards,
Johi.

Thanks for your reply.

Yes. The first thing I did was to try the code as it is and it didnt work.
After replacing int s with int16_t most things (!) now work... but I am wondering if anything else must be fixed to ensure compatibility both now and in the future.

Is it an option to share the code on the forum?
Can you be more speficific about the issues that do not work?

Will these all need changing:
byte, char, bool, long, unsigned long, maybe bool too?

into versions of int8_t, uint8_t, int32_t and uint32_t ...

“Double” on ARM will be an actual double precision floating point value (8 bytes), while it’s the same as “float” (4 bytes) on AVR.

It’s the intent that the actual size of “int “ and etc be irrelevant, but as you’ve found, that isn’t always true.

In general, this shouldn't have been necessary, except for "external data."
But you didn't post the broken code, so it's hard to say...

Below are some functions that were affected :slight_smile:

bool Check_crc(uint8_t *ptr ) {

  uint16_t crc; 
  uint8_t dat; 
  crc=0; 
  uint8_t len=ptr[0]-2;
  while(len--!=0) 
  { 
    dat=crc>>8; 
    crc<<=8; 
#ifdef __AVR__
    crc^= pgm_read_word_near (&CRC_TAB [dat^*ptr]); 
#endif   
    
#ifdef ARDUINO_ARCH_SAMD   
    crc^= CRC_TAB [dat^*ptr]; // Original statement when array is stored in RAM
#endif  
    ptr++; 
  } 
  dat=crc; 
  if((*ptr==(crc>>8))&&(*(ptr+1)==dat)) 
  { 
    return(true);
  } 
  else 
  { 
    return(false);
  } 
}

 CRC_TAB []=const uint16_t CRC_TAB[] = { 
  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 
  0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 
  0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 
  0x9339, 0x8318, 0xb37b, 0xa35a,0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 
  0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, ......}

CRC_TAB was a const word [] and also stored in PROGMEM which on ARM is not supported.

Before changing variables to int16_t etc all CRC checks failed.
Likewise the opposite function which calculates CRC (not shown) also calculated wrong CRCs

I wonder if the following would be affected :

word opCode= word(IncPacket[5],IncPacket[6]);
if (opCode==0xF065) 
{
....
..

}

Or this :

void setupBusPacket(word opCode ){
 OutPacket[1]=DeviceSubNet;
 OutPacket[2]=DeviceID; 
 OutPacket[3]=highByte(DeviceType);   
 OutPacket[4]=lowByte(DeviceType); 
 OutPacket[5]=highByte(opCode+1);
 OutPacket[6]=lowByte (opCode+1);
 OutPacket[7]=IncPacket[1];  
 OutPacket[8]=IncPacket[2];
}

In general, I wonder if I should do a find & replace of all variable types to their "explicit length equivalent" just to make sure that functionality is not affected.
For exapmle I have some other functions that take float measurements, split them into individual bytes - 4 bytes were expected - and then send them serially over RS485.
For now and given the level of testing I did, everything seems to be working by just replacing "int"s .

Yes, see below my reply to Westfw

You can't just change the variable declarations and fix all the issues. On the AVR 8 bit processors the default type for int expressions is 16 bit, whereas its 32 on the ARM ones.

Thus the types assigned to intermediate results in an integer expression will be different
and sometimes this will make a difference - you'll mainly come across this in bit field
manipulations where you may have to add some extra masking with 0xFFFF on a 32 bit
processor.

Yes I now realise that.
So the only way to make sure that everything works as intended is to code through the whole code and try to "predict" what the consequences would be when the code is re-compiled for an ARM processor?
I wish there was a faster way to do this... preferably automatic!

Alas C/C++ are ill-defined in this regard - you have to program defensively and
be careful with expressions than implicitly widen. Quirks of ancient technology.

So would you say that building a habit to use int8-t, int16_t etc instead of byte, int, float etc is advisable ?

Ah; communications. THE major example of "external data."


So would you say that building a habit to use int8-t, int16_t etc instead of byte, int, float etc is advisable ?

You want to build up an idea of when they are important, and when they're not.
There are supposedly "minor" performance issues from using short data types on ARM (it doesn't have short math, so it may have to insert instructions to truncate results at some point.) There would obviously be major performance issues if you had "int32_t" all over a program that originated on ARM/X86 (the default "real" type of "int", after all) and tried to port it to an 8bit chip. Perhaps you should be using uint_fast16_t, but ... code can get ugly pretty quickly.

Absolutely, it makes up for some of the sloppiness in the definition of C/C++
Its interesting to note that in the original paper introducing the Java language
the author specifically makes a point about datatypes being cast in iron so that
code is completely portable whatever the hardware. In Java not only are the
int and float types of defined size and signed-ness, but the endianness of the
underlying machine is not visible in the programming model.

Thanks Mark!
Are there any other consequences of using int16_t instead of int for a 32bit micro?
eg time overheads, memory usage, etc

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.