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
/** \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 );
More unpicking required.
( 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)
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);
Its defined in /STM32F1/cores/maple/wirish.h for us
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.
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).
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.
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);
}
}
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.
![]()
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};
btns->sense()
Also got rid of the strlcpy usage:
strlcpy(list_buffer,(char*)(menu_header+current_header), 21);
By using
menu_header[current_header]
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
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)
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);
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);
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)
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



