Why does optimization swap I/O port access?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
minoc_301866
Level 1
Level 1

This can be a compiler issue - I'm not sure.

Anyway here is my problem:

When setting compiler optimization to "None", the IR1 / IR2 outputs are swapped, setting the wrong output (!!!).

When setting compiler optimization to "Size", the outputs behave correctly.

When using CY_SYS_PINS_SET macros, the optimization does not have any impact and all works as intended.

IR1_DRV_Write and IR2_DRV_Write functions are auto-generated by PSOC creator:

void IR1_DRV_Write(uint8 value)

{

    uint8 drVal = (uint8)(IR1_DRV_DR & (uint8)(~IR1_DRV_MASK));

    drVal = (drVal | ((uint8)(value << IR1_DRV_SHIFT) & IR1_DRV_MASK));

    IR1_DRV_DR = (uint32)drVal;

}

(The disassembly of IR1_DRV_Write and IR2_DRV_Write functions obviously
are different with the two optimization levels mentioned. But I don't have the patience to go through the disassembly right now).

In the code snippet below I have commented the lines calling IR1_DRV_Write() and IR2_DRV_Write() functions.

Instead I put direct write to CY_PINS there which solved the problem.

Now the million dollar question is: Can I trust using the auto generated I/O support functions in PSOC creator?
What if other I/O functions get more or less trashed by the various optimization levels?

    if( ++multiplexor & 0x1 )

    {

        CY_SYS_PINS_SET_PIN( CYREG_GPIO_PRT4_DR, 0 );

//        IR1_DRV_Write( 1 );

        CyDelayUs( 50 );                                // Wait for signal to settle

        ir1Val[ ir1Sample & 1 ] = lsGetSensorValue();

        CY_SYS_PINS_CLEAR_PIN( CYREG_GPIO_PRT4_DR, 0 );

//        IR1_DRV_Write( 0 );

       

        if( ir1Val[0] < THR_ACTIVE && ir1Val[1] < THR_ACTIVE )

            latchSensorState |= UNLATCHED_SENSOR;

        else if ( ir1Val[0] > THR_INACTIVE && ir1Val[1] > THR_INACTIVE )

            latchSensorState &= ~(UNLATCHED_SENSOR);

           

        ++ir1Sample;

    }

   

    else

    {

        CY_SYS_PINS_SET_PIN( CYREG_GPIO_PRT3_DR, 7 );

//        IR2_DRV_Write( 1 );

        CyDelayUs( 50 );                                // Wait for signal to settle

        ir2Val[ ir2Sample & 1 ] = lsGetSensorValue();

        CY_SYS_PINS_CLEAR_PIN( CYREG_GPIO_PRT3_DR, 7 );

//        IR2_DRV_Write( 0 );

       

        if( ir2Val[0] < THR_ACTIVE && ir2Val[1] < THR_ACTIVE )

            latchSensorState |= LATCHED_SENSOR;

        else if ( ir2Val[0] > THR_INACTIVE && ir2Val[1] > THR_INACTIVE )

            latchSensorState &= ~(LATCHED_SENSOR);

           

        ++ir2Sample;

    }

}

0 Likes
3 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Compiler errors are quite quite rare. Can you please post your complete project so that we all can have a look at all of your settings. To do so, use

Creator->File->Create Workspace Bundle (minimal)

and attach the resulting file.

Bob

0 Likes

I have created a case with Cypress as I can't disclose a customer project in public.

You're right that compilers probles are rare, I encountered only 2 of them in 25 years time.

The question here is whether the auto generated API's from Cypress are behaving correctly with various optimization levels.

Looking at the disassembly there are quite a bit more code when using no optimization, just to set an output.
The functions that behave weird are generated by Cypress - not in my code.

1. No optimization:

0x00003354 <IR1_DRV_Write>:

107: *

108: * \funcusage

109: *  \snippet IR1_DRV_SUT.c usage_IR1_DRV_Write

110: *******************************************************************************/

111: void IR1_DRV_Write(uint8 value)

112: {

0x00003354 push {r7, lr}

0x00003356 sub sp, #10

0x00003358 add r7, sp, #0

0x0000335A movs r2, r0

0x0000335C adds r3, r7, #7

0x0000335E strb r2, [r3, #0]

113:     uint8 drVal = (uint8)(IR1_DRV_DR & (uint8)(~IR1_DRV_MASK));

0x00003360 ldr r3, [pc, #34] ; (3398 <IR1_DRV_Write+0x44>)

0x00003362 ldr r3, [r3, #0]

0x00003364 uxtb r2, r3

0x00003366 movs r3, #f

0x00003368 adds r3, r7, r3

0x0000336A movs r1, #7f ; 0x7f

0x0000336C ands r2, r1

0x0000336E strb r2, [r3, #0]

114:     drVal = (drVal | ((uint8)(value << IR1_DRV_SHIFT) & IR1_DRV_MASK));

0x00003370 adds r3, r7, #7

0x00003372 ldrb r3, [r3, #0]

0x00003374 lsls r3, r3, #7

0x00003376 uxtb r1, r3

0x00003378 movs r3, #f

0x0000337A adds r3, r7, r3

0x0000337C movs r2, #f

0x0000337E adds r2, r7, r2

0x00003380 ldrb r2, [r2, #0]

0x00003382 orrs r2, r1

0x00003384 strb r2, [r3, #0]

115:     IR1_DRV_DR = (uint32)drVal;

0x00003386 ldr r3, [pc, #10] ; (3398 <IR1_DRV_Write+0x44>)

0x00003388 movs r2, #f

0x0000338A adds r2, r7, r2

0x0000338C ldrb r2, [r2, #0]

0x0000338E str r2, [r3, #0]

116: }

0x00003390 nop ; (mov r8, r8)

0x00003392 mov sp, r7

0x00003394 add sp, #10

0x00003396 pop {r7, pc}

0x00003398 .word 0x40040300

0x0000339C <IR2_DRV_Write>:

107: *

108: * \funcusage

109: *  \snippet IR2_DRV_SUT.c usage_IR2_DRV_Write

110: *******************************************************************************/

111: void IR2_DRV_Write(uint8 value)

112: {

0x0000339C push {r7, lr}

0x0000339E sub sp, #10

0x000033A0 add r7, sp, #0

0x000033A2 movs r2, r0

0x000033A4 adds r3, r7, #7

0x000033A6 strb r2, [r3, #0]

113:     uint8 drVal = (uint8)(IR2_DRV_DR & (uint8)(~IR2_DRV_MASK));

0x000033A8 ldr r3, [pc, #38] ; (33e4 <IR2_DRV_Write+0x48>)

0x000033AA ldr r3, [r3, #0]

0x000033AC uxtb r2, r3

0x000033AE movs r3, #f

0x000033B0 adds r3, r7, r3

0x000033B2 movs r1, #1

0x000033B4 bics r2, r1

0x000033B6 strb r2, [r3, #0]

114:     drVal = (drVal | ((uint8)(value << IR2_DRV_SHIFT) & IR2_DRV_MASK));

0x000033B8 adds r3, r7, #7

0x000033BA ldrb r3, [r3, #0]

0x000033BC movs r2, #1

0x000033BE ands r3, r2

0x000033C0 uxtb r1, r3

0x000033C2 movs r3, #f

0x000033C4 adds r3, r7, r3

0x000033C6 movs r2, #f

0x000033C8 adds r2, r7, r2

0x000033CA ldrb r2, [r2, #0]

0x000033CC orrs r2, r1

0x000033CE strb r2, [r3, #0]

115:     IR2_DRV_DR = (uint32)drVal;

0x000033D0 ldr r3, [pc, #10] ; (33e4 <IR2_DRV_Write+0x48>)

0x000033D2 movs r2, #f

0x000033D4 adds r2, r7, r2

0x000033D6 ldrb r2, [r2, #0]

0x000033D8 str r2, [r3, #0]

116: }

0x000033DA nop ; (mov r8, r8)

0x000033DC mov sp, r7

0x000033DE add sp, #10

0x000033E0 pop {r7, pc}

0x000033E2 nop ; (mov r8, r8)

0x000033E4 .word 0x40040400

2. Size optimization:

0x00001B50 <IR1_DRV_Write>:

107: * \funcusage

108: *  \snippet IR1_DRV_SUT.c usage_IR1_DRV_Write

109: *******************************************************************************/

110: void IR1_DRV_Write(uint8 value)

111: {

112:     uint8 drVal = (uint8)(IR1_DRV_DR & (uint8)(~IR1_DRV_MASK));

0x00001B50 movs r3, #7f ; 0x7f

0x00001B52 ldr r2, [pc, #10] ; (1b64 <IR1_DRV_Write+0x14>)

114:     drVal = (drVal | ((uint8)(value << IR1_DRV_SHIFT) & IR1_DRV_MASK));

115:     IR1_DRV_DR = (uint32)drVal;

0x00001B54 lsls r0, r0, #7

108: * \funcusage

109: *  \snippet IR1_DRV_SUT.c usage_IR1_DRV_Write

110: *******************************************************************************/

111: void IR1_DRV_Write(uint8 value)

112: {

113:     uint8 drVal = (uint8)(IR1_DRV_DR & (uint8)(~IR1_DRV_MASK));

0x00001B56 ldr r1, [r2, #0]

0x00001B58 ands r3, r1

114:     drVal = (drVal | ((uint8)(value << IR1_DRV_SHIFT) & IR1_DRV_MASK));

115:     IR1_DRV_DR = (uint32)drVal;

0x00001B5A orrs r0, r3

0x00001B5C uxtb r0, r0

0x00001B5E str r0, [r2, #0]

116: }

0x00001B60 bx lr

0x00001B62 nop ; (mov r8, r8)

0x00001B64 .word 0x40040300

0x00001B68 <IR2_DRV_Write>:

107: * \funcusage

108: *  \snippet IR2_DRV_SUT.c usage_IR2_DRV_Write

109: *******************************************************************************/

110: void IR2_DRV_Write(uint8 value)

111: {

112:     uint8 drVal = (uint8)(IR2_DRV_DR & (uint8)(~IR2_DRV_MASK));

0x00001B68 movs r3, #1

0x00001B6A ldr r1, [pc, #10] ; (1b7c <IR2_DRV_Write+0x14>)

0x00001B6C ldr r2, [r1, #0]

0x00001B6E bics r2, r3

0x00001B70 uxtb r2, r2

114:     drVal = (drVal | ((uint8)(value << IR2_DRV_SHIFT) & IR2_DRV_MASK));

115:     IR2_DRV_DR = (uint32)drVal;

0x00001B72 ands r3, r0

0x00001B74 orrs r3, r2

0x00001B76 str r3, [r1, #0]

116: }

0x00001B78 bx lr

0x00001B7A nop ; (mov r8, r8)

0x00001B7C .word 0x40040400

0 Likes
minoc_301866
Level 1
Level 1

Just for the record.
After some digging, the I/O ports seem to be ok.

The problem is actually related to the ADC.
When using optimization "None" the ADC reports measured voltage level correctly.

When using optimization "Size" the ADC "inverts" the read value.
Reading 3.3V returns zero while reading 0V returns value 2048.

While keeping optimization set to size, I then added "#pragma GCC optimize("O0")" for each file related to ADC.

And then everything works fine.

Only remaining issue now is how to make these #pragmas stay when rebuilding the whole project, since Creator re-generates these ADC files and trashes my changes.

0 Likes