This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Compiler issues interfacing sensor with nRF52840-DK

Hello!  I'm interfacing a sensor with an nRF52840 development board and have run into a few issues:

1)  I have a check status function as shown below:

bool ADXL_check_status(int address)
{
   ret_code_t err_code;

    m_xfer_done = false;

    uint8_t reg[1] = {WHO_AM_I_Register};
    err_code = nrf_drv_twi_tx(&m_twi, address, reg, sizeof(reg), false);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);

    m_xfer_done = false;

    err_code = nrf_drv_twi_rx(&m_twi, address, &m_sample, sizeof(m_sample));
    APP_ERROR_CHECK(err_code);

    if(m_sample==(uint8_t)WHO_AM_I_RESPONSE)
    {
        NRF_LOG_INFO("Device Detected");
        return true;
    }
    else
    {
        NRF_LOG_INFO("Device Not Detected");
        return false;
    }
}

If I place a breakpoint on the following line:

     if(m_sample==(uint8_t)WHO_AM_I_RESPONSE)

The code will run fine.  Obviously, this works fine with debug mode.  However, if I take away this debug statement (or I try and program the board, which obviously has no breakpoints), the code goes to the following line in app_error_weak.c:

     NRF_BREAKPOINT_COND;

Below is my call stack:

I've tried everything I can think of, including setting the optimization setting to "none" and nothing seems to resolve this issue.  Any ideas what might be causing the issue and how to resolve it?

2)  I'm trying to scale some sensor data using the following equation:

x * 5 *(2^4) / (2^20-1)

I've tried a number of different methods to get this to work but I think there might be an issue with the pow() function?

This line returns a value of 0:

     double scaling_factor = (5*(pow(2,range_val+1)))/(pow(2,20)-1);

This solution returns an infinite value (where x enters the equation with a value of around -9600 or so):

        x *= 5;
        x *= pow(2,4);
        x /= (pow(2,20)-1);

The result is infinite though (multiplying the value by 5 works correctly, multiplying it by 2^4 has no change and the final division sets the value to infinite). 

I even tried just multiplying it by the following line:

        x *= pow(7.6294,-5);

The value of x in this case doesn't change. 

I've tried setting x to be float and double and neither have yielded any changes.  Is there something I can do to achieve the desired math function described?

Any help you can give me would be greatly appreciated.  Thanks!

Parents
  • Hello,

    Any ideas what might be causing the issue and how to resolve it?

    Assuming you have SES in debug mode and remove the breakpoint, what error is generated?

    If I place a breakpoint on the following line:

         if(m_sample==(uint8_t)WHO_AM_I_RESPONSE)

    The code will run fine.

    What is the value of both m_sample and your typecasted (uint8_t)WHO_AM_I_RESPONSE variables?

    2)  I'm trying to scale some sensor data using the following equation:

    If this is a static conversion, I would recommend calculating this only once, and just defining a macro to input the numbers.
    In your case, something like:

    #define SOME_CONVERSION(RESULT)\
                                (RESULT * 16 / 209715)
     

    The value of x in this case doesn't change. 

    I've tried setting x to be float and double and neither have yielded any changes.  Is there something I can do to achieve the desired math function described?



    How are you verifying the output values?
    I did a small test of the pow function, and it functions as expected for me.
    If you are printing out the output using the logger module, how are you formatting the output?
    It might be that the chosen format does not match the provided value.

    For future reference, be advised that the nRF52840 Floating Point Unit(FPU) only supports float type - 32 bit, and thus not double.
    An exempt from the documentation reads:

            Important: Remember that the floating point unit that is used in nRF52 supports only the float type. The double type is not supported by this architecture and can generate slow and inefficient code.

    Best regards,
    Karl
     

  • Karl,

    Thanks for the quick response!

    First off, the suggestion in #2 worked.  I implemented it a bit differently (as i wanted to be able to process a few different scenarios) but the suggestion to do it as a #define was a great idea!

    The issue with #1 still persists though, unfortunately. 

    If I place a breakpoint on the following line:

        if(m_sample==(uint8_t)WHO_AM_I_RESPONSE)

    and add both variables to watch, I get the correct values. 

    If I then step through/run the code, it works fine.  However, if I start the code without said breakpoint (or if I remove it from the code when it's working correctly), it fails again.  If I look at what is being output on putty, I get the following on repeat:

    <error> app: Fatal error
    <warning> app: System reset
    <info> app:

    It then runs to the NRF_BREAKPOINT_COND in the app_error_weak.c as described above. 

    I've actually continued to write code and the "solution" is still the same as before (with placing the breakpoint at that location).  The place it's going to the NRF_BREAKPOINT_COND is a bit different now.  Below is the code I'm running:

    bool ADXL_check_status(int address)
    {
       ret_code_t err_code;

        m_xfer_done = false;

        uint8_t reg[1] = {WHO_AM_I_Register};
        err_code = nrf_drv_twi_tx(&m_twi, address, reg, sizeof(reg), false);
        APP_ERROR_CHECK(err_code);
        while (m_xfer_done == false);

        m_xfer_done = false;

        err_code = nrf_drv_twi_rx(&m_twi, address, &m_sample, sizeof(m_sample));
        APP_ERROR_CHECK(err_code);

        if(m_sample==(uint8_t)WHO_AM_I_RESPONSE)
        {
            /* Logging not currently needed here */
            //NRF_LOG_INFO("Device Detected");
            return true;
        }
        else
        {
            /* Logging not currently needed here */
            //NRF_LOG_INFO("Device Not Detected");
            return false;
        }
    }

    static void read_adx357_sensor_data(int address, int range_val)
    {
        ret_code_t err_code;
        uint8_t return_data[9];
        float scaling_factor;

        if(ADXL_check_status(address))
        {
            m_xfer_done = false;
            uint32_t x_in, y_in, z_in = 0;
            int32_t x, y, z = 0;
            float x_out, y_out, z_out;

            uint8_t reg[1] = {Xdata3_Register};
            err_code = nrf_drv_twi_tx(&m_twi, address, reg, sizeof(reg), false);
            APP_ERROR_CHECK(err_code);
            while (m_xfer_done == false);

            m_xfer_done = false;

            err_code = nrf_drv_twi_rx(&m_twi, address, &return_data, sizeof(return_data));
            APP_ERROR_CHECK(err_code);

            //Other code here

    */

    Here's where it's breaking, as well as the call stack:

    I'm not sure if I need to have some sort of delay (which is effectively what that breakpoint could be doing?) or if there's an issue with how I'm using the nrf_drv_twi_tx command. 

    Hopefully, this is enough information to resolve the issue.  I actually have my application working correctly with the breakpoint enabled, but I can't program the device because, obviously, there would be no breakpoint and the chip constantly resets itself. 

    Thanks for all your help!

  • Hello again,

    JayDev said:
    Thanks for the quick response!

     No problem at all, I am happy to help!

    JayDev said:
    First off, the suggestion in #2 worked.  I implemented it a bit differently (as i wanted to be able to process a few different scenarios) but the suggestion to do it as a #define was a great idea!

    I am glad you found my suggestion useful, and that you were able to resolve the issue.

    JayDev said:
    The issue with #1 still persists though, unfortunately.

    All right, lets see if we can not solve this one together as well.

    JayDev said:
    Here's where it's breaking, as well as the call stack:

    Could you tell me exactly which error the nrf_drv_twi_tx is generating?
    You can see the possible errors in the function API Reference documentation.

    As a sidenote, I would recommend using the nrfx_TWIM driver directly instead of the nrf_drv, since this is the legacy layer.
    Depending on your configuration, you can see that it is what is being called by your nrf_drv_* call anyways.

    JayDev said:
    I actually have my application working correctly with the breakpoint enabled, but I can't program the device because, obviously, there would be no breakpoint and the chip constantly resets itself.

    That is great to hear! I hope we will resolve this issue quickly. 

    For future reference, I would highly recommend using the "Insert -> Code" option when including code in your ticket/comment, so that it is formatted properly and easy to read.

    Looking forward to solving this issue together,

    Best regards,
    Karl

  • Sorry about that, I was trying to think of the best way to be able to provide you an error code without using a breakpoint but, it turns out, when it gets stuck at that NRF_BREAKPOINT_COND, I can still read the error code (I tried having it output using the NRF_LOG_INFO command but it didn't actually output anything for one reason or another).  Well, I hovered over the error code and it gave me error code 17:

    I assume this means it's busy?

    I guess it would make sense to me that it suddenly started working if I put the break point, it's giving it a delay that could give it enough time to complete. 

    I placed a delay of 230 us (had to play around with it to minimize the time) and that seemed to work.  I could also play with the function handling of the error but I don't really understand how it coming back as busy would halt the entire program and generate that failure code.  Do you have any insight on why this might be?

    Is the TWIM driver a bit more robust?  Would it provide better handling of this situation that wouldn't break the code in this way?  If so, does the nRF SDK have any good examples you would point me to?  I assume TWIM is setup a bit differently from TWI_DRV.

    Any insight you can give me would be very helpful!  Thanks again for all your help!

  • Hello,

    JayDev said:
    Sorry about that

    No problem at all.

    JayDev said:
    (I tried having it output using the NRF_LOG_INFO command but it didn't actually output anything for one reason or another)

    You did not specify any formatting argument to your string. To print the value of an uint32_t, you could for example use the %lu with a typecast:

    NRF_LOG_INFO("Error code: %lu", (unsigned long)err_code);

    Or similar.

    JayDev said:
    I could also play with the function handling of the error but I don't really understand how it coming back as busy would halt the entire program and generate that failure code.  Do you have any insight on why this might be?

    Have you made any modification to the error handler function?
    The default handler for _any_ error(anything else then NRF_SUCCESS) is to reset the device, however you are free to implement any error handling you see fit.
    In your particular case, the error code is generates by the call to nrf_drv_twi_tx and the different possible reasons can be read about in the functions API Reference documentation.
    The BUSY error indicates that the driver is not ready for another transfer, which leads me to believe that you are toggling your transfer_finished flag too soon.

    For example, adding a delay might not be the best solution - at least not implemented using the us_delay function - since it wastes CPI cycles, and prevents the rest of the program from running.
    Perhaps instead you could have the error handler for TWI BUSY state could start a timer for 230 us, that does not allow other TWI operations to occur before the timer has run out - or something similar. Keep in mind that I do not know the full extent of your application, and as such this might be a sub-par solution for your project.
    As a general tip, I would not recommend using CPU NOP cycles to solve any timing related problems during operation.
    You could also make use of repeated transfers, as detailed by my colleague in this ticket, but it is a bit more complicated to set up properly.

    JayDev said:
    Is the TWIM driver a bit more robust?  Would it provide better handling of this situation that wouldn't break the code in this way?  If so, does the nRF SDK have any good examples you would point me to?  I assume TWIM is setup a bit differently from TWI_DRV.

    You are correct that the new nrfx driver is set up differently than the old one, but as you can see in the source code - the legacy function calls are being forwarded to the nrfx function calls.
    So, in essence you are using the nrfx driver already - which brings back my initial suggestion that you could make use of the nrfx drivers directly, to avoid future work of porting the code to nrfx.
    Is your code based on the TWI Sensor example

    Best regards,
    Karl

  • Karl,

    Sorry for the delay, didn't get a chance to respond until today!

    I did try your suggestion for the log:

    NRF_LOG_INFO("Error code: %lu", (unsigned long)err_code);

    It definitely output the error code but it took about 2.5 ms to run, so that will probably need to be saved for diagnostics rather than regular output!

    I didn't realize that any unhandled error defaults to resetting the device!  That's good to know!

    I ended up finding a solution that cut down the time considerably!  Instead of the 260 us (which, oddly enough, only seemed to add something like 160 us, according to the scope . . . which I won't lie, was a bit concerning.  Could be part of the reason for the error, I'm guessing.  It's likely exiting out of the code prior to it being completed so the hardware was playing catchup). 

    I ended up going with the following solution:

    while(nrf_drv_twi_tx(&m_twi, address, reg, sizeof(reg), false)!=0);
    //nrf_delay_us(230);
    //err_code = nrf_drv_twi_tx(&m_twi, address, reg, sizeof(reg), false);
    
    /* Removed - Takes about 2.5 ms */
    //NRF_LOG_INFO("Error code: %lu", (unsigned long)err_code);
    //APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);

    This code allows it to check constantly without sending anything.  Once it's ready, the data will send.  The delay is only around 16 us now, which is a pretty good timing improvement!

    Good learning experience though!  I'll have to go back and follow the code through and see what it's calling to set everything up using the TWIM mode though.  But you are correct, I did base the project around the TWI Sensor project!

    Thanks for all your help!

  • Hello,

    JayDev said:
    Sorry for the delay, didn't get a chance to respond until today!

    No problem at all, take all the time you need.

    JayDev said:
    It definitely output the error code but it took about 2.5 ms to run, so that will probably need to be saved for diagnostics rather than regular output!

    That seems a bit excessive - but logging will always add a delay to your program - what you can do however, such as in this case, is to use the deferred logging feature, which allows you to cache logs without processing them, and then instead running the process when you would be idling. You can see this done in many of our examples as part of the idle_state_handle() function call in the for(;;) loop.

    JayDev said:
    I didn't realize that any unhandled error defaults to resetting the device!  That's good to know!

    Great, I am glad that was helpful. You should also know that you may change this error handling, in the case that an error can be handled without resetting the device.

    JayDev said:
    Instead of the 260 us (which, oddly enough, only seemed to add something like 160 us, according to the scope . . . which I won't lie, was a bit concerning.  Could be part of the reason for the error, I'm guessing.  It's likely exiting out of the code prior to it being completed so the hardware was playing catchup).

    What the function does is schedule a given number of NOP cycles to achieve roughly the delay that is requested - but if a higher priority task comes along(such as the SoftDevice) then its execution time will be added to the delay, since the number of scheduled NOP cycles remains the same. This is one of the reasons why it is not recommended to use NOP(delay_ms/us) cycles for timing delays and scheduling. I agree with your reasoning that it sounds like the code moved on to the next sending before finishing the previous one, probably causing the error you received.

    JayDev said:
    This code allows it to check constantly without sending anything.  Once it's ready, the data will send.  The delay is only around 16 us now, which is a pretty good timing improvement!

    This is a good solution, and a huge time improvement on your previous delay, great!

    JayDev said:
    Good learning experience though!  I'll have to go back and follow the code through and see what it's calling to set everything up using the TWIM mode though.

    I am glad to hear that you see it this way, that is a great way of looking at it!
    Do not hesitate to open a new ticket about the TWIM if you should encounter any issues or questions.

    JayDev said:
    Thanks for all your help!

    No problem at all, I am happy to help.

    Good luck with your development!

    Best regards,
    Karl

Reply
  • Hello,

    JayDev said:
    Sorry for the delay, didn't get a chance to respond until today!

    No problem at all, take all the time you need.

    JayDev said:
    It definitely output the error code but it took about 2.5 ms to run, so that will probably need to be saved for diagnostics rather than regular output!

    That seems a bit excessive - but logging will always add a delay to your program - what you can do however, such as in this case, is to use the deferred logging feature, which allows you to cache logs without processing them, and then instead running the process when you would be idling. You can see this done in many of our examples as part of the idle_state_handle() function call in the for(;;) loop.

    JayDev said:
    I didn't realize that any unhandled error defaults to resetting the device!  That's good to know!

    Great, I am glad that was helpful. You should also know that you may change this error handling, in the case that an error can be handled without resetting the device.

    JayDev said:
    Instead of the 260 us (which, oddly enough, only seemed to add something like 160 us, according to the scope . . . which I won't lie, was a bit concerning.  Could be part of the reason for the error, I'm guessing.  It's likely exiting out of the code prior to it being completed so the hardware was playing catchup).

    What the function does is schedule a given number of NOP cycles to achieve roughly the delay that is requested - but if a higher priority task comes along(such as the SoftDevice) then its execution time will be added to the delay, since the number of scheduled NOP cycles remains the same. This is one of the reasons why it is not recommended to use NOP(delay_ms/us) cycles for timing delays and scheduling. I agree with your reasoning that it sounds like the code moved on to the next sending before finishing the previous one, probably causing the error you received.

    JayDev said:
    This code allows it to check constantly without sending anything.  Once it's ready, the data will send.  The delay is only around 16 us now, which is a pretty good timing improvement!

    This is a good solution, and a huge time improvement on your previous delay, great!

    JayDev said:
    Good learning experience though!  I'll have to go back and follow the code through and see what it's calling to set everything up using the TWIM mode though.

    I am glad to hear that you see it this way, that is a great way of looking at it!
    Do not hesitate to open a new ticket about the TWIM if you should encounter any issues or questions.

    JayDev said:
    Thanks for all your help!

    No problem at all, I am happy to help.

    Good luck with your development!

    Best regards,
    Karl

Children
No Data
Related