Hot!switch enum problem

Page: 12 > Showing page 1 of 2
Author
luker
Senior Member
  • Total Posts : 164
  • Reward points : 0
  • Joined: 2015/04/17 06:24:04
  • Location: 0
  • Status: offline
2018/08/09 02:32:58 (permalink)
0

switch enum problem

Hi forum,
 
there is a problem in my code that communicates with a sensor over UART.
The protocol for the BNO055 9-axis-sensor doesn't provide for an indicator what data it currently sends over UART. So the PIC doesn't have a clue what some data means that is received on its UART.
Therefore the software remembers which data has been requested lately. Let's just assume we want to read acceleration data from the sensor. Send a message that contains the related Memory address and remember BNO055Addr_AccelerationData in the _pendingRequestIndex variable.
 
After receiving enough Bytes for an answer, the Software calls BNO055_InternalMessageReceivedHandler, where my problems start: In that function, the switch variable is 7 (which means BNO055Addr_AccelerationData), which is fine. But the code doesn't proceed to case BNO055Addr_AccelerationData:. Instead the function Ends immediately. There is one line after the switch Statement, but it doesn't run.
 
What am I doing wrong?
 
I'm using
MPLabX v4.10
XC32 v2.10
PIC32MZ2048EFH064
 
    typedef enum
    {
        BNO055Addr_CHIP_ID,
        ...
        BNO055Addr_AccelerationData,
        BNO055Addr_ACC_DATA_X,
        BNO055Addr_ACC_DATA_Y,
        BNO055Addr_ACC_DATA_Z,
        BNO055Addr_MagnetometerData,
        BNO055Addr_GyroscopeData,
        BNO055Addr_HeadingData,
        BNO055Addr_RollData,
        BNO055Addr_PitchData,
        ...
    }BNO055RegisterIndex_t;
 
static BNO055RegisterIndex_t _pendingRequestIndex = 0xFF;

static void BNO055_InternalMessageReceivedHandler(void)
{
    switch(_pendingRequestIndex)
    {
        case BNO055Addr_CHIP_ID:
            break;
        case BNO055Addr_OPR_MODE:
        {
            BNO055OperationModes_t* pOperationMode = BNO055_GetLastMessage();
            if(BNO055SensorModes_NDOF == *pOperationMode)
            {
                BNO055_SetCheckOperationMode(false);
            }
            else
            {
                BNO055_SetOperationMode(BNO055SensorModes_NDOF);
            }
            break;
        }
        case BNO055Addr_AccelerationData:
        {
            if(AccelerationDataReceivedHandler != NULL)
            {
                AccelerationData_t* pData = BNO055_GetLastMessage();
                AccelerationDataReceivedHandler(
                    pData->Signed.ValueX,
                    pData->Signed.ValueY,
                    pData->Signed.ValueZ
                );
            }
            break;
        }
    }
}

#1

20 Replies Related Threads

    qɥb
    Monolothic Member
    • Total Posts : 3329
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: switch enum problem 2018/08/09 02:43:25 (permalink)
    0
    What writes to _pendingRequestIndex ?
    Is it happening inside an interrupt service?
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #2
    luker
    Senior Member
    • Total Posts : 164
    • Reward points : 0
    • Joined: 2015/04/17 06:24:04
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/09 04:02:58 (permalink)
    0
    No interrupts involved.
    The following code writes to _pendingRequestIndex. It is called from the main loop depending on different conditions.

    BNO055RetVal_t BNO055_RequestData(BNO055RegisterIndex_t registerIndex)
    {
        // Responses don't bear information what request they do belong to.
        //   so remember the last request.
        if(
            BNO055_IsRequestPending()
         && registerIndex != _pendingRequestIndex
        )
        {
            return(BNO055RetVal_ErrRequestPending);
        }
        _pendingRequestIndex = registerIndex;    // Here _pendingRequestIndex is being written
        
        // Requests are always four bytes long
        uint8_t request[] = {
            SpecialByte_StartRequest,
            MessageDirection_ReadRequest,
            BNO055Registers[registerIndex].Address,
            BNO055Registers[registerIndex].Size
        };
        
        UART_WriteBuffer(&_uartObj, request, sizeof(request));
        
        return(BNO055RetVal_Ok);
    }

     
    But even if there may be a bug in here, what drives me nuts is that the debugger says that a switch variable has some value repeatedly, and the correct case is never executed.
    #3
    luker
    Senior Member
    • Total Posts : 164
    • Reward points : 0
    • Joined: 2015/04/17 06:24:04
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/09 04:04:38 (permalink)
    +1 (1)
    Oh, thank you for your footer.
    #4
    muellernick
    Super Member
    • Total Posts : 444
    • Reward points : 0
    • Joined: 2015/01/06 23:58:23
    • Location: Germany
    • Status: offline
    Re: switch enum problem 2018/08/09 04:08:43 (permalink)
    0
    I'd add the default: to the case (always a good habit) and look what you get there.
     
    Nick
    #5
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    Re: switch enum problem 2018/08/09 04:31:02 (permalink)
    0
    I'd actually also avoid "break" statements inside sub-blocks...
    it *may* confuse things

    GENOVA :D :D ! GODO
    #6
    muellernick
    Super Member
    • Total Posts : 444
    • Reward points : 0
    • Joined: 2015/01/06 23:58:23
    • Location: Germany
    • Status: offline
    Re: switch enum problem 2018/08/09 04:43:44 (permalink)
    0
     I'd actually also avoid "break" statements inside sub-blocks...

     
    No, that works. It is just a question of style.
    The missing default state also is just a question of style. But it often enough helps to find problems. By default I have a default-state (pun intended) that prints out the state to the debug console. I always treat the default state as an exception.
     
    Nick
    #7
    luker
    Senior Member
    • Total Posts : 164
    • Reward points : 0
    • Joined: 2015/04/17 06:24:04
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/09 05:02:11 (permalink)
    +1 (1)
    Neither the addition of a default case nor moving the breaks out of the brackets changed anything.
     
    The code still doesn't enter case BNO055Addr_AccelerationData. I don't get it.
    #8
    aschen0866
    Super Member
    • Total Posts : 4356
    • Reward points : 0
    • Joined: 2006/01/08 22:18:32
    • Location: San Diego
    • Status: offline
    Re: switch enum problem 2018/08/09 07:29:11 (permalink)
    +1 (1)
    If optimization is enabled, and the compiler is able to figure out that AccelerationDataReceivedHandler is always a NULL, conceivably that particular case block could be removed altogether. Can you give us a small project that demonstrates the problem? 
    #9
    twelve12pm
    Overseer
    • Total Posts : 322
    • Reward points : 0
    • Joined: 2012/04/09 17:27:24
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/09 08:10:10 (permalink)
    0
    muellernick
     I'd actually also avoid "break" statements inside sub-blocks...

     
    No, that works. It is just a question of style.
    The missing default state also is just a question of style. But it often enough helps to find problems. By default I have a default-state (pun intended) that prints out the state to the debug console. I always treat the default state as an exception.
     
    Nick



    Some coding standards (e.g., MISRA C) require a switch to have a default case at the end. However when using switch with enumerations, my preference is not to put a default unless it is needed for some other reason, because GCC reports a warning if the switch does not include a case for each enum value. This is useful when, for example, you add more items to the enum and forget to add the corresponding cases to the switch. However this point can be hotly debated and there are advantages and disadvantages to using or not using a default case. So, yes, this is a matter of style. :-)
    #10
    twelve12pm
    Overseer
    • Total Posts : 322
    • Reward points : 0
    • Joined: 2012/04/09 17:27:24
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/09 08:17:21 (permalink)
    0
    aschen0866
    If optimization is enabled, and the compiler is able to figure out that AccelerationDataReceivedHandler is always a NULL, conceivably that particular case block could be removed altogether. Can you give us a small project that demonstrates the problem? 



    The other possibility (if you're single-stepping through the code) is that it appears the function is not executed when in fact it is. I've suffered all sorts of weirdness with single-stepping, mostly due to instruction reordering and the like. Compiling with -O0 to eliminate all optimizations helps -- but note that I prefer to always develop and work with -Os until I need to debug and single step, and then I rebuild with -O0. The reason is that I prefer to "test what you fly, fly what you test" so I don't like to develop with -O0 and then get nasty surprises later.
     
    Also, note that AccelerationDataReceivedHandler could be initialized correctly but then clobbered by software code at some later time after initialization but before the switch executes. That could happen if you use a memset() with a bad pointer or size, or if some misconfigured DMA transfer is overwriting your program memory, etc. You have to place a breakpoint at the switch itself or (even better) at the call to the function that contains the switch, and then examine the contents of AccelerationDataReceivedHandler immediately before the switch will execute.
     
    #11
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    Re: switch enum problem 2018/08/09 08:18:31 (permalink)
    0
    I agree on this "default" stuff Smile
    But the "break" issue... could be different. Not much in the above posted code, I agree, but for example when there's an if... break... condition inside the switch. I remember a long discussion from some years ago...

    GENOVA :D :D ! GODO
    #12
    Jim Nickerson
    User 452
    • Total Posts : 5445
    • Reward points : 0
    • Joined: 2003/11/07 12:35:10
    • Location: San Diego, CA
    • Status: offline
    Re: switch enum problem 2018/08/09 09:04:00 (permalink)
    0
    twelve12pm
     I prefer to always develop and work with -Os until I need to debug and single step, and then I rebuild with -O0. The reason is that I prefer to "test what you fly, fly what you test" so I don't like to develop with -O0 and then get nasty surprises later.
     

    I find sometimes when I switch to -O0 to debug things no longer fit, this of course typically happens when I really need to switch to a PIC with more flash to accommodate all the "stuff" I have put in there.
    #13
    NKurzman
    A Guy on the Net
    • Total Posts : 16556
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: online
    Re: switch enum problem 2018/08/09 09:11:35 (permalink)
    +2 (2)
    try placing the Nop(); macro where you want the break points. twelve12pm maybe right.  the optimizer can do funny things to the code.  (all legal and correct, but confusing to debug)
    #14
    cvm
    Super Member
    • Total Posts : 186
    • Reward points : 0
    • Joined: 2011/09/16 05:16:15
    • Location: 0
    • Status: online
    Re: switch enum problem 2018/08/09 11:38:11 (permalink)
    +1 (1)
    I would check the asm output of the BNO055_InternalMessageReceivedHandler function- either that 'case' code is there, or the compiler 'knows' that code cannot be reached and has optimized it away (which appears to be the case). If optimized away, there looks to be only one reason it would do that, as has already been stated.
     
    #15
    DarioG
    Allmächtig.
    • Total Posts : 54081
    • Reward points : 0
    • Joined: 2006/02/25 08:58:22
    • Location: Oesterreich
    • Status: offline
    Re: switch enum problem 2018/08/09 11:40:58 (permalink)
    0
    and just to--- double-double check :)
    are you sure that BNO055Addr_AccelerationData = 7 ?
    it's not shown in the snippet above

    GENOVA :D :D ! GODO
    #16
    luker
    Senior Member
    • Total Posts : 164
    • Reward points : 0
    • Joined: 2015/04/17 06:24:04
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/10 02:13:02 (permalink)
    +1 (1)
    Yes, BNO055Addr_AccelerationData == 7 for sure:
        typedef enum
        {
            BNO055Addr_CHIP_ID,
            BNO055Addr_ACC_CHIP_ID,
            BNO055Addr_MAG_CHIP_ID,
            BNO055Addr_GYRO_CHIP_ID,
            BNO055Addr_SoftwareRevision,
            BNO055Addr_BootloaderRevision,
            BNO055Addr_Page_ID,
            BNO055Addr_AccelerationData,
            BNO055Addr_ACC_DATA_X,

    #17
    luker
    Senior Member
    • Total Posts : 164
    • Reward points : 0
    • Joined: 2015/04/17 06:24:04
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/10 04:08:50 (permalink)
    +1 (1)
    The assembly listing is interesting. When stoppend at a breakpoint on the first switch statement and then selecting "Window"->"Debugging"->"Disassembly", BNO055_InternalMessageReceivedHandler itself is not shown at all, but the code that should call it instead. Have a look at the assembly:
    !void BNO055_ManageReception(void)
    !{
    0x9D022DF4: ADDIU SP, SP, -40
    0x9D022DF8: SW RA, 36(SP)
    0x9D022DFC: SW S3, 32(SP)
    0x9D022E00: SW S2, 28(SP)
    0x9D022E04: SW S1, 24(SP)
    0x9D022E08: SW S0, 20(SP)
    !    while(!UART_ReceiveBufferIsEmpty(&_uartObj))
    0x9D022E0C: LUI S0, -32763
    0x9D022E10: ADDIU S0, S0, -14236
    0x9D022E20: J .LBE33, .LBE46, .LBE53
    0x9D022E24: ADDIU S3, S3, 12016
    0x9D022FE8: JAL UART_ReceiveBufferIsEmpty
    0x9D022FEC: ADDU A0, S0, ZERO
    0x9D022FF0: BEQ V0, ZERO, .LBB47
    0x9D022FF4: LW RA, 36(SP)
    !    {
    !        uint8_t oneByte = UART_Read(&_uartObj);
    0x9D022E28: JAL UART_Read
    0x9D022E2C: ADDU A0, S0, ZERO
    !        switch(_receiveState)
    0x9D022E30: LW V1, -32316(GP)
    0x9D022E34: ADDIU A0, ZERO, 2
    0x9D022E38: BEQ V1, A0, 0x9D022E80
    0x9D022E3C: ADDIU A0, ZERO, 3
    0x9D022E40: BEQ V1, A0, .LVL25
    0x9D022E44: ADDIU A0, ZERO, 1
    0x9D022E48: BEQ V1, A0, .LVL23, .LBB48
    0x9D022E4C: ADDIU V1, ZERO, 238
    !        {
    !            default:
    !            case ReceiveState_WaitForStart:
    !            {
    !                if(SpecialByte_StartError == oneByte)
    0x9D022E50: BNE V0, V1, .LVL21
    0x9D022E54: ADDIU V1, ZERO, 187
    !                {
    !                    _receiveState = ReceiveState_WaitForErrorCode;
    0x9D022E58: ADDIU V0, ZERO, 1
    0x9D022E5C: J .LBE33, .LBE46, .LBE53
    0x9D022E60: SW V0, -32316(GP)
    !                }
    !                else if(SpecialByte_StartResponse == oneByte)
    0x9D022E64: BNE V0, V1, .LBE33, .LBE46, .LBE53
    0x9D022E68: ADDIU V0, ZERO, 2
    !                {
    !                    _receiveState = ReceiveState_WaitForLength;
    0x9D022E6C: J .LBE33, .LBE46, .LBE53
    0x9D022E70: SW V0, -32316(GP)
    !                }
    !                break;
    !            }
    !            case ReceiveState_WaitForErrorCode:
    !            {
    !                _inputMessageLastError = oneByte;
    0x9D022E74: SW V0, -32320(GP)
    !                _receiveState = ReceiveState_WaitForStart;
    !#warning Todo: Communicate error.
    !                //retVal = BNO055RetVal_ReceivedError;
    !                break;
    0x9D022E78: J .LBE33, .LBE46, .LBE53
    0x9D022E7C: SW ZERO, -32316(GP)
    !            }
    !            case ReceiveState_WaitForLength:
    !            {
    !                _inputMessageLength = oneByte;
    0x9D022E80: SB V0, -32323(GP)
    !                _inputMessagePosition = 0;
    0x9D022E84: SB ZERO, -32324(GP)
    !                _receiveState = ReceiveState_Record;
    0x9D022E88: ADDIU V0, ZERO, 3
    !                break;
    0x9D022E8C: J .LBE33, .LBE46, .LBE53
    0x9D022E90: SW V0, -32316(GP)
    !            }
    !            case ReceiveState_Record:
    !            {
    !                if(_inputMessagePosition >= sizeof(_inputMessageBuffer))
    0x9D022E94: LBU V1, -32324(GP)
    0x9D022E98: SEB A0, V1
    0x9D022E9C: BGEZ A0, 0x9D022EAC
    0x9D022EA0: ADDIU A0, V1, 1
    0x9D022EA4: J .LBE33, .LBE46, .LBE53
    0x9D022EA8: SW ZERO, -32316(GP)
    !                // Messages larger than 128 byte
    !                //   violate BNO055 communication protocol.
    !                {
    !                    _receiveState = ReceiveState_WaitForStart;
    !                }
    !                else
    !                {
    !                    _inputMessageBuffer[_inputMessagePosition++] = oneByte;
    0x9D022E14: LUI S2, -32763
    0x9D022E18: ADDIU S1, S2, -14196
    0x9D022EAC: ANDI A0, A0, 255
    0x9D022EB0: SB A0, -32324(GP)
    0x9D022EB4: ADDU V1, V1, S1
    0x9D022EB8: SB V0, 0(V1)
    !                    if(_inputMessagePosition >= _inputMessageLength)
    0x9D022EBC: LBU V0, -32323(GP)
    0x9D022EC0: SLTU A0, A0, V0
    0x9D022EC4: BNE A0, ZERO, .LBE33, .LBE46, .LBE53
    0x9D022EC8: NOP
    !                    // That's enough bytes for this message.
    !                    {
    !                        _receiveState = ReceiveState_WaitForStart;
    0x9D022ECC: SW ZERO, -32316(GP)
    !                        BNO055_InternalMessageReceivedHandler();
    !                    }
    !                }
    !                break;
    !            }
    !        }
    !    }
    !}
    0x9D022FF8: LW S3, 32(SP)
    0x9D022FFC: LW S2, 28(SP)
    0x9D023000: LW S1, 24(SP)
    0x9D023004: LW S0, 20(SP)
    0x9D023008: JR RA
    0x9D02300C: ADDIU SP, SP, 40
    Far down, 14 lines from the end, is the call. But it doesn't seem to have an equivalent in assembler. How can that be? Does compiler think the whole function is of no use and optimizes it away?
     
    I checked in debugger, AccelerationDataReceivedHandler has a value, 0x9D030A3C.
     
    #18
    andersm
    Super Member
    • Total Posts : 2478
    • Reward points : 0
    • Joined: 2012/10/07 14:57:44
    • Location: 0
    • Status: offline
    Re: switch enum problem 2018/08/10 05:25:06 (permalink)
    +2 (2)
    lukerThe assembly listing is interesting. When stoppend at a breakpoint on the first switch statement and then selecting "Window"->"Debugging"->"Disassembly"

    The IDE's disassembly view tries to rearrange the assembly into something resembling source code order, which is not very useful at all. Note how the addresses are not contiguous. Instead use objdump from the command line.
    #19
    cvm
    Super Member
    • Total Posts : 186
    • Reward points : 0
    • Joined: 2011/09/16 05:16:15
    • Location: 0
    • Status: online
    Re: switch enum problem 2018/08/10 10:32:31 (permalink)
    0
    you can also have objdump create an asm 'listing' after the build- project properties, building, execute this line after build-
    ${MP_CC_DIR}/xc32-objdump -d ${ImageDir}/${PROJECTNAME}.${IMAGE_TYPE}.elf > list.txt
    using -d here, but you can tailor to your preferences
    also, I don't know if the MK requires a special -m switch (the MM does require -m mips:micromips, because that's all it can do)
     
    also, a quick way to see if the compiler is optimizing away code, is to just comment out pieces of code in the suspected function- the build size will either change or not change
    for example, comment out the 'if(AccelerationDataReceivedHandler != NULL)' test, if the build size remains the same, its already being optimized away (look elsewhere), if the the build size increases then figure out why that commented out code is causing the compiler to optimize the code away
    #20
    Page: 12 > Showing page 1 of 2
    Jump to:
    © 2018 APG vNext Commercial Version 4.5