- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I'm using PSoC 4 in a BLE application. The specific device is CY8C4247LQI-BL473.
I have the following piece of code:
int32 passwd;
uint8 cypher[16];
/*
some code here, cypher buffer is loaded
*/
passwd= cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;
if(passwd < (int32) 0){
passwd = passwd * (int32)(-1);
}
I'm facing the following issue: depending on the optimization level I choose, the test at 10th line is always false.
Optimization levels None, Debug and Minimal work fine. But with level High, Speed and Size the "if" command result is always false, even with valid values.
I'm setting the optimization level via "Build -> Build Settings -> Configuration: Release -> ARM GCC 5.4-2016-q2-update -> Optimization -> Optimization Level".
Can someone please help me understand what is going on here? Is there something I'm missing?
Here follows some further details:
Environment:
PSoC Creator 4.3 (4.3.0.1445)
Culture: Portuguese (Brazil)
OS Version: Microsoft Windows NT 10.0.18362.0
CLR Version: 4.0.30319.42000
Installed CyInstaller Products:
Peripheral Driver Library 3.0.1
Peripheral Driver Library 3.1.1
PSoC Programmer 3.28.7
PSoC Creator 4.3
Loaded Plugins:
Name: Toolchain Manager
Version: 4.3.0.1445
Company: Cypress Semiconductor
Description: PSoC Creator Toolchain Manager
Name: ARM GCC Generic
Version: 4.3.0.1445
Company: Cypress Semiconductor
Description: ARM GNU Generic
Name: ARM MDK Generic
Version: 4.3.0.1445
Company: Cypress Semiconductor
Description: ARM MDK Generic
Name: ARM IAR Generic
Version: 4.3.0.1445
Company: Cypress Semiconductor
Description: ARM IAR Generic
Name: DP8051 Keil Generic
Version: 4.3.0.1445
Company: Cypress Semiconductor
Description: DP8051 Keil Generic
Thank you very much.
Cheers,
Yuri
Solved! Go to Solution.
- Labels:
-
BLE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I'm just curious, but I wonder if you add volatile to passwd, will it help?
> int32 passwd
< volatile int32 passwd
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi yuar_3514996,
I modified your code slightly to test it. I added an LED pin and if the 'if condition' is true, I toggle the LED. Please let me know if there is any issue with the test code.
int32 passwd;
uint8 cypher[16];
cypher[0] = 0xFF;
cypher[1] = 0xFF;
cypher[2] = 0xFF;
cypher[3] = 0xFF;
passwd= cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;
for(;;)
{
/* Place your application code here. */
if(passwd < (int32) 0)
{
LED_Write(1);
CyDelay(500);
LED_Write(0);
CyDelay(500);
LED_Write(1);
CyDelay(500);
LED_Write(0);
CyDelay(500);
}
else
{
LED_Write(1);
}
}
I programmed this code using all optimization levels and irrespective of the optimization level the LED was toggling. Could it be possible that the issue is with other code in your project? If I am missing something, please let me know.
Thanks and Regards,
Rakshith M B
Rakshith M B
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi RakshithM_16! Thank you for the help.
The piece of code I've posted it's part of a pretty straight forward function. It just generates a random password based on some input parameters.
I just made some testing and figured out that if I load "cypher" array manually as you did the code works fine for any optimization level.
In my original code, "cypher" array is loaded by an AES encrpytion function. Depending on the optimization level, even with the encryption value loaded into "cypher[3:0]" being negative the test "passwd < (int32) 0" returns always FALSE. The odd thing here is if I get the value returned by the AES function and recompile the code loading it manually into "cypher", the code then works.
Here follows the actual code I'm running:
uint32 bleGeneratePasskey(uint8 random, uint8 *addr1, uint8 *addr2)
{
uint8 key[16];
uint8 plain[16];
uint8 cypher[16];
int32 passwd;
/* init KEY array with constant values and "random" var at one position */
/* init PLAIN array with both "addr1[6]" and "addr2[6]" content plus 4 constants */
CyBle_AesEncrypt(plain, key, cypher);
passwd = cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;
#ifdef DEBUG_PRINT
char temp[128];
uint8 i;
sprintf(temp, "-> P: ");
for(i = 0; i < 16; i++)
sprintf(temp, "%s%02X ", temp, plain);
debugPrint(temp);
sprintf(temp, "-> K: ");
for(i = 0; i < 16; i++)
sprintf(temp, "%s%02X ", temp, key);
debugPrint(temp);
sprintf(temp, "-> C: ");
for(i = 0; i < 16; i++)
sprintf(temp, "%s%02X ", temp, cypher);
debugPrint(temp);
sprintf(temp, "-> 1: %ld (0x%08lX)", passwd, passwd);
debugPrint(temp);
#endif
if(passwd < (int32) 0)
{
passwd = passwd * (int32)(-1);
#ifdef DEBUG_PRINT
sprintf(temp, "******** < 0 ********\n");
debugPrint(temp);
#endif
}
#ifdef DEBUG_PRINT
sprintf(temp, "-> 2: %ld (0x%08lX)", passwd, passwd);
debugPrint(temp);
#endif
if(passwd > (int32)999999)
passwd &= 0x7FFFF;
#ifdef DEBUG_PRINT
sprintf(temp, "-> 3: %ld (0x%08lX)", passwd, passwd);
debugPrint(temp);
#endif
return ((uint32) passwd);
}
And here some outputs I got from my debug terminal:
Optimization level: SIZE, loading CYPHER from AES
[07388] -> C: 88 59 94 A2 FA 86 56 A4 5C 9C A9 BF F5 72 FA D2
[07396] -> 1: -1567336056 (0xA2945988)
[07400] -> 2: -1567336056 (0xA2945988)
[07404] -> 3: -1567336056 (0xA2945988)
[07408] -> PASSKEY: 2727631240
Optimization level: SIZE, loading CYPHER manually
[09731] -> C: 88 59 94 A2 FA 86 56 A4 5C 9C A9 BF F5 72 FA D2
[09739] -> 1: -1567336056 (0xA2945988)
[09743] ******** < 0 ********
[09746] -> 2: 1567336056 (0x5D6BA678)
[09750] -> 3: 239224 (0x0003A678)
[09753] -> PASSKEY: 239224
Optimization level: SIZE, loading CYPHER from AES
[36946] -> C: D3 F1 4F FB 73 AF E9 3D CA B6 C2 92 FA 06 97 2D
[36954] -> 1: -78646829 (0xFB4FF1D3)
[36958] -> 2: -78646829 (0xFB4FF1D3)
[36962] -> 3: -78646829 (0xFB4FF1D3)
[36966] -> PASSKEY: 4216320467
Optimization level: SIZE, loading CYPHER manually
[03803] -> C: D3 F1 4F FB 73 AF E9 3D CA B6 C2 92 FA 06 97 2D
[03811] -> 1: -78646829 (0xFB4FF1D3)
[03815] ******** < 0 ********
[03818] -> 2: 78646829 (0x04B00E2D)
[03822] -> 3: 3629 (0x00000E2D)
[03825] -> PASSKEY: 3629
Optimization level: MINIMAL, loading CYPHER from AES
[08129] -> C: 84 89 FF BA A0 1F 2A 43 90 0A 28 1F AB D7 A3 85
[08137] -> 1: -1157658236 (0xBAFF8984)
[08141] ******** < 0 ********
[08144] -> 2: 1157658236 (0x4500767C)
[08148] -> 3: 30332 (0x0000767C)
[08151] -> PASSKEY: 30332
Optimization level: MINIMAL, loading CYPHER manually
[06334] -> C: 84 89 FF BA A0 1F 2A 43 90 0A 28 1F AB D7 A3 85
[06342] -> 1: -1157658236 (0xBAFF8984)
[06346] ******** < 0 ********
[06349] -> 2: 1157658236 (0x4500767C)
[06353] -> 3: 30332 (0x0000767C)
[06356] -> PASSKEY: 30332
I could workaround this in other ways, like declaring "passwd" as volatile as MoTa_728816 suggested. But I'd like to know why this is happening.
Cheers,
Yuri
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Yuri,
Would it be okay for you to share the entire project or at least a minimalistic version of your project in which you are facing the issue so that we can test it out?
Also, can you try changing the datatype of cypher from uint8 to int16 and let me know if that makes any difference?
Thanks and Regards,
Rakshith M B
Rakshith M B
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Rakshith,
I've made a minimal project with the problem still going on. I removed all my source code and all componentes not needed to show the problem.
It just initializes the BLE stack to use the encryption function and calls my password function once in a second.
With optimization enabled, the above mentioned test returns always false. Without optimizations it works well.
By the way, changing "uint8" arrays to "uint16" was of no success.
Cheers,
Yuri
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Yuri,
We tried debugging and placing a breakpoint to check the result of the if condition and with high optimization the if statement was skipped. So, we believe the compiler is optimizing out the if condition.
One thought was that, because the cypher is an unsigned int and the passwd is a sum of unsigned int the compiler might be assuming that passwd will not be less than 0. So, we tried declaring cypher as int8 and typecasting it as shown and this worked. We had to typecast it while printing too.
CyBle_AesEncrypt(plain, key, (uint8*) cypher);
Can you please let me know if this works?
I think using volatile as suggested by MoTa_728816-san is a better solution in this case.
Thanks and Regards,
Rakshith M B
Rakshith M B
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Yuri,
I don't know if it applies to your program, but I'll talk about optimization in general.
An ANSI C compliant compiler compiles with optimization options to eliminate unnecessary code and data. The compiler deletes all variables except those related to I/O. The input and output variables here are global variables, function arguments and return value variables. The compiler considers removing local variables by optimization. To prevent this, the programmer must explicitly declare "This variable is necessary". It consists in using global variables and arguments. Even local variables can be survived from optimization if they have a relationship with them. Conversely, if you create a function with only local variables, a function with no contents will be created.
In addition to this, if optimization progresses, variables located in memory will be replaced by registers inside the CPU, and it will become impossible to access peripheral registers. "volatile" is declared to mean that the specified address is always accessed.
You can get more detailed information by searching for "gcc optimization option" on the Web.
I hope this information is useful for you.
Best Regards,
Kenshow
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Thank you MoTa_728816 and RakshithM_16 for the help.
I knew basically how optimization works in microcontrollers. Very often when using a debugger (mostly in other architechtures), if I place a breakpoint in some lines it just doesn't stop because of the optimization (usually when the variable being loaded in that line is not used anymore inside the same function). To workaround that, I just declare the related variable as "volatile" (telling the compiler "compile this line, no matter what"). This works fine for my debugging purposes.
In this case, I didn't think it would be a problem because after the variable "passwd" being loaded first time, it is tested, modified and returned as function value. I thought this process would be considered "important enough" by the compiler.
Anyway, I'll stick with the volatile solution (it works fine for me). I'd like to understand what happens under the hood of gcc, but to really clear this out I'd had to go through compiler's internals and that should not be my focus by now.
Thank you guys!
Cheers,
Yuri
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I'm just curious, but I wonder if you add volatile to passwd, will it help?
> int32 passwd
< volatile int32 passwd
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi! Declaring "int32 passwd" as volatile works fine. Thank you.