Help with porting…

BennehBoy
Mon Feb 20, 2017 7:39 pm
I’m trying to port some pretty dated Arduino code to STM32.

I’ve managed to fix all the compilations issues firstly under Arduino/Mega – mainly due to differences in progmem stuff (code is pre 1.5).

Unfortunately the code now falls down when I try compile for Maple Mini.

There’s a bit of a rats nest of warnings and then a failure which I guess are all probably linked to pgmspace – the original code quite aggressively utilises PROGMEM to keep things running OK on smaller h/w.

Any ideas?

Source code is attached including the required libraries (except sdfat).

In file included from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WString.h:29:0,

from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/wirish.h:47,

from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/Arduino.h:30,

from sketch\td5comm.cpp:20:

sketch\td5comm.cpp: In constructor 'Td5Pid::Td5Pid(byte, byte, byte, long int)':

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/avr/pgmspace.h:31:61: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

#define pgm_read_word(addr) (*(const unsigned short *)(addr))

^

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/avr/pgmspace.h:22:50: note: in definition of macro 'memcpy_P'

#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))

^

sketch\td5comm.cpp:643:33: note: in expansion of macro 'pgm_read_word'

memcpy_P(requestFrame, (byte*)pgm_read_word(&(td5_pids[id])),reqlen);

^

In file included from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WString.h:29:0,

from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/Print.h:27,

from C:\Users\bennehboy\Documents\Arduino\libraries\LiquidCrystalEx/LiquidCrystalEx.h:5,

from sketch\td5hmi.h:23,

from sketch\td5hmi.cpp:22:

sketch\td5hmi.cpp: In member function 'void List::render(byte)':

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/avr/pgmspace.h:31:61: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

#define pgm_read_word(addr) (*(const unsigned short *)(addr))

^

sketch\td5hmi.cpp:271:45: note: in expansion of macro 'pgm_read_word'

byte len=strlcpy_P(list_buffer,(char*)pgm_read_word(item_list+i), length+1);

^

td5hmi.cpp:271: error: 'strlcpy_P' was not declared in this scope

byte len=strlcpy_P(list_buffer,(char*)pgm_read_word(item_list+i), length+1);

^

In file included from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WString.h:29:0,

from C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/Print.h:27,

from C:\Users\bennehboy\Documents\Arduino\libraries\LiquidCrystalEx/LiquidCrystalEx.h:5,

from sketch\td5hmi.h:23,

from sketch\td5hmi.cpp:22:

sketch\td5hmi.cpp: In member function 'void ParamList::render(byte)':

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/avr/pgmspace.h:31:61: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

#define pgm_read_word(addr) (*(const unsigned short *)(addr))

^

sketch\td5hmi.cpp:377:45: note: in expansion of macro 'pgm_read_word'

byte len=strlcpy_P(list_buffer,(char*)pgm_read_word(item_list+i), length_list+1);

^

td5hmi.cpp:377: error: 'strlcpy_P' was not declared in this scope

byte len=strlcpy_P(list_buffer,(char*)pgm_read_word(item_list+i), length_list+1);

^

exit status 1
'strlcpy_P' was not declared in this scope


BennehBoy
Mon Feb 20, 2017 7:50 pm
This is the definition of strlcpy_P from Arduino avr/pgmspace.h:

/** \ingroup avr_pgmspace
\fn size_t strlcpy_P(char *dst, const char *src, size_t siz)
\brief Copy a string from progmem to RAM.

Copy \p src to string \p dst of size \p siz. At most \p siz-1
characters will be copied. Always NULL terminates (unless \p siz == 0).
The strlcpy_P() function is similar to strlcpy() except that the
\p src is pointer to a string in memory space.

\returns The strlcpy_P() function returns strlen(src). If
retval >= siz, truncation occurred. */
extern size_t strlcpy_P (char *, const char *, size_t );


BennehBoy
Mon Feb 20, 2017 7:55 pm
I hacked the same definition into the maple pgmspace.h and the compiler gets further

More unpicking required.


RogerClark
Mon Feb 20, 2017 9:17 pm
I normally just remove all the progmem statements and see what compile errors I get.

( as you know, PROGMEM is AVR specific and is unnecessary on ARM processors as static strings and data are either automatically put in flash, or you can help the compiler to know which strings etc dont change by declaring them as const)


BennehBoy
Mon Feb 20, 2017 9:39 pm
Actually I didn’t know that.

BennehBoy
Mon Feb 20, 2017 10:25 pm
I hacked out all the progmem stuff and replaced the pgmspace functions with what I think is their equivalents (rightly or wrongly).

now the compiler is saying that true & false are undeclared lol???

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WCharacter.h: In function 'isAlphaNumeric':

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WCharacter.h:54:30: error: 'false' undeclared (first use in this function)

return ( isalnum(c) == 0 ? false : true);

^

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WCharacter.h:54:30: note: each undeclared identifier is reported only once for each function it appears in

C:\Users\bennehboy\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\cores\maple/WCharacter.h:54:38: error: 'true' undeclared (first use in this function)

return ( isalnum(c) == 0 ? false : true);


RogerClark
Mon Feb 20, 2017 10:48 pm
There are some differences in where things like “true” are defined

Its defined in /STM32F1/cores/maple/wirish.h for us


BennehBoy
Mon Feb 20, 2017 10:51 pm
Yup, found the issue anyway, that MemoryFree library was breaking a lot of definitions. Removed.

Got it to compile.

Need to spend some time looking at exactly what those pgmspace functions do, they look to just substitute bits of strings so shouldn’t be too difficult to figure out.


BennehBoy
Tue Feb 21, 2017 9:53 am
Compiles and runs until it attempts to process any button inputs – suspect this is either because the pointers to what was the progmem stuff has become broken with my edits, or because there are some unhandled button states when no actual button circuitry is connected.

Anyhow, thanks for the help Roger.

If it turns out to be the pointer code I may ask for some help again, it’s not an area of strength for me (particularly when strings are being read into buffers and referenced as arrays of chars & all while referenced via pointers).


RogerClark
Tue Feb 21, 2017 8:26 pm
Old libraries can be a pain to port.

What does the library do?

Quite often, I end up throwing most if the library away and writing it again myself.

Unfortunately just because someone has written something as a library, it doesn’t guarantee that the code was well written.

As a case in point, I needed code for the BME280 ( pressure / temperature / humidity sensor), so used the Adafruit lib as a starting point. But after I while I realised that the library was very inefficient, as it does multiple reads to the temperature register when it should only be read once ( this potentially gave small errors in the pressure reading and generally slows things down, and also in my case means it takes more power and flattens the battery)

So I have ended up rewriting most of the code, to give better accuracy, faster operation, and less battery drain.


BennehBoy
Tue Feb 21, 2017 9:57 pm
Don’t need the memory library, it’s binned.

Got much further in the debug, and basically the code that uses the strlcpy_P function is the bit that’s crashing the STM32.

I need to invest some braincells into how to do what it’s doing with bog standard fucntions…

Essentially it’s copying the contents of a string definition referenced by way of a custom List class into a buffer. I’m just nowhere near as good with pointers to figure out how to de-obfuscate it.

I’ll get there, but so far it’s been wild trial and error without any success… commenting out the offending lines prevents the crashes but obviously the menu items don’t get displayed lol.

The offending code: strlcpy_P is the bit which crashes (probably in conjunction with that pgm_read_word that’s not required.

for (byte i=_first_item;i<_first_item+item_per_screen;i++)
{
if (i<=_last_item) // Copy item
{
byte len=strlcpy_P(list_buffer,(char*)pgm_read_word(item_list+i), length+1);
if (len<length)
{
for (byte k=len;k<length;k++)
{
list_buffer[k]=' ';
}
list_buffer[length]=0;
}
}
else // Fill blank
{
byte j;
for (j=0;j<length;j++)
{
list_buffer[j]=' ';
}
list_buffer[j]=0;
}

//Display item on LCD
lcd.setCursor(col+((i-_first_item)/item_rows)*(length+1), row+(i-_first_item)%item_rows);

if (i<=_last_item)
{
lcd.write((i==item_selected)?indicator:' ');// Show " " or a dot
}
else
{
lcd.write(' ');
}

lcd.print(list_buffer);
}
}


stevestrong
Tue Feb 21, 2017 10:08 pm
Use strlcpy and delete pgm_read_word.

BennehBoy
Tue Feb 21, 2017 10:21 pm
We have a winner, thanks Steve!

Now to convert it from using the LCD library to an OLED so I can see what’s actually going on, should be pretty simple.

8-)


BennehBoy
Thu Feb 23, 2017 3:56 pm
Having some trouble with this, I think the button reading code might have an 8bit to 32bit issue because it’s returning random values for the buttons being pressed.

Reading the pins directly shows their correct state so it’s not a wiring up issue.

Anyhow, here’s the constructor for the buttons which uses an external library:

Button btn_up(KPbtn_up, LOW);
Button btn_down(KPbtn_down, LOW);
Button btn_left(KPbtn_left, LOW);
Button btn_right(KPbtn_right, LOW);
Button btn_enter(KPbtn_enter, LOW);
Button btn_quit(KPbtn_quit, LOW);
Button btn_powerup(keyPadPowerPin, LOW);
Button *btns[]={&btn_up, &btn_down, &btn_left, &btn_right, &btn_enter, &btn_quit, &btn_powerup};


BennehBoy
Thu Feb 23, 2017 4:55 pm
OK sorted….

btns->sense()

Also got rid of the strlcpy usage:

strlcpy(list_buffer,(char*)(menu_header+current_header), 21);

By using

menu_header[current_header]


BennehBoy
Sat Feb 25, 2017 5:43 pm
Hit another issue that I’m struggling with.

I think the code is stuffing up how it’s handling the writing out of serial data.

What I think is going wrong is that it temporarily stores the data to be written in a custom class which malloc’s some buffer memory

My suspicion is that this buffer is directly referenced, ie I need to change something to take into account that we’re on STM32.

Anyhow, this is what should be getting spat out of the serial port:

0x81 0x13 0xF7 0x81 0x0C

And this is what actually exits:

0xC3 0x42 0x01 0x08 0x0E

Here’s how that data is defined
#define INIT_FRAME 0x00

const unsigned char pid_0x00[] = { 0x81, 0x13, 0xF7, 0x81, 0x0C }; // INIT_FRAME


BennehBoy
Sat Feb 25, 2017 7:31 pm
Compiling the original code on a 2560 results in working comms to an ECU :(

RogerClark
Sat Feb 25, 2017 8:15 pm
I cant see any similarity or pattern of difference between what you should see and what you actually get.

It doesnt look like byte swapping / endian-ness

All the code should be doing is putting the CRC into the last byte.

I would recommend you write a function which prints the buffer to debug, so you can see the contents.

Then call that function at various stages if the code to see when the buffer gets messed up.

Its quite possible the buffer is getting overwritten my some completely different part of you code.

PS.
For classes its good practice to name member variables in some way to make it obvious they are a member ( property) of the class e.g. I normally use underscores at the start of member vars, as this is a common nomenclature ( there are of course other nomenclatures)


BennehBoy
Sat Feb 25, 2017 8:24 pm
OK, got it working….

The memcpy line was the problem, removal of the progmem code altered the state of the data being fed in…

memcpy(requestFrame, td5_pids[id],reqlen);


RogerClark
Sat Feb 25, 2017 8:29 pm
BennehBoy wrote:OK, got it working….

The memcpy line was the problem, removal of the progmem code altered the state of the data being fed in…

memcpy(requestFrame, td5_pids[id],reqlen);


BennehBoy
Sat Feb 25, 2017 8:30 pm
RogerClark wrote:
For classes its good practice to name member variables in some way to make it obvious they are a member ( property) of the class e.g. I normally use underscores at the start of member vars, as this is a common nomenclature ( there are of course other nomenclatures)

BennehBoy
Sat Feb 25, 2017 8:34 pm
RogerClark wrote:
Btw.

I didnt see any progmem statements in the code you posted.

I think we probably all sound like suck records, but its best to remove all progmem statements from the code, because they are an AVR only legacy item, and although the STM32 has some macros to try to allow their use; the macros dont work for every possible way that pointers can be used in C


Leave a Reply

Your email address will not be published. Required fields are marked *