-
Notifications
You must be signed in to change notification settings - Fork 476
CPU hangs when using pgm_read_word with an odd address #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The problem is that a byte array has been created but then a 16 bit word access is being requested with an 8 bit pointer that may not be aligned to 16 bit boundaries. This is bad programming practice for FLASH which frequently requires type aligned data access pointers. So the data should always be accessed with the pointer type that it is stored in. So the bytes should be concatenated in the program. The sketch below will work as the address of the first byte is forced to be on a
Note that &Config[1], being a byte address is now clearly not word aligned and thus will crash the Pico, hence the change to &Config[2]. Hence only even indexes are legal. Note also the word at &Config[8] will give an indeterminate value as there are an odd number of bytes in the array. |
Hi Bodmer, concerning "This is bad programming practice for FLASH which frequently" concerning "only even indexes are legal" concerning "will work as the address of the first byte is forced to..." concerning "...word aligned and thus will crash the Pico..." concerning "Note also the word at &Config[8] will give an indeterminate" I would expect a compatible implementation of these functions. |
I can understand the frustration, maybe this helps since the ESP8266 has exactly the same problem. Essentially AVR processors read the FLASH as 8 bits (instruction size) and 32 bit processors pull out 32bits at a time (this is a hardware level behaviour) even if the FLASH itself if byte wide. Unfortunately #define macros do not do type checking so the compiler does not spot the problem. There are ways around this of course, e.g. throw an error or (for strict legacy compatibility) assemble words/dwords byte by byte byte and accept the undesirable performance penalty. |
I'm not frustrated, I know how to,workaround this issue :-) |
OK, but bear in mind the workaround then breaks the reading of 16 bit words. The results will be different according to the pointer type used (8, 16, 32 etc), so a new problem is created that will confuse anyone who tries to use that approach. Type casting the pointer will fix this:
The Arduino environment does hide some problems from programmers and thus creates pitfalls later unfortunately. I have added brackets around the (addr) since that may be a muliple parameter expression and hence the (const uint8_t*) type cast wouldotherwise only apply to the first parameter in that expression. Unfortunately there is atill another problem introduced, the result will depend on the endianess (byte order) used by the processor... |
@Jueff we ran into this same issue on the ESP8266 Arduino core I help maintain, too. Thanks @Bodmer (also, FWIW the Basically on the ARM M0+ you can't read a value off of its natural alignment. Let me pull in the macros like you suggested. It's a little more complicated than your example because sometimes G++ is too smart for its own good and will do things like convert your nicely written 2-individual-byte-reads-and-shifts into a read-short. But we already solved it on the 8266 so I'll just steal that. :) |
Noted. It certainly would be good to not just "hang" and need a hard reset. |
I did not realise this had been fixed for the ESP8266 as discussed here, a good solution. I had avoided the problem as it existed for so long. This also explains the performance drop I noticed at one point due to the default unaligned access, but just accepted it at the time. I can see there is an aligned access macro so I can now use that in future to get the performance back. Thanks, glad this came up! Have corrected the aligned pragma, my brain was on a coffee break there! |
Update the ArduinoAPI with new macros/inlines that allow accessing values that are not naturally aligned (i.e. an int at address 0x0001). Fixes #79
Update the ArduinoAPI with new macros/inlines that allow accessing values that are not naturally aligned (i.e. an int at address 0x0001). Fixes #79
when running this code the CPU freezes after writing "word@1" to the serial port.
when changing
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
to
#define pgm_read_word(addr) (pgm_read_byte(addr)+(pgm_read_byte(addr+1)<<8))
program works fine.
Maybe this is also an issue with
The text was updated successfully, but these errors were encountered: