Post Go back to editing

Error code returned by API calls

I have been seeing some instances where API functions return a nonzero error code, and then the SPI interface (I assume) gets into a bad state, such that all further API calls fail. At that point, the board needs to be power cycled to get back into a working state (reloading code with the debugger does not work).

In the first instance, I saw this intermittently when calling adi_adrv9001_Rx_InterfaceGain_Set() manually from a serial command line interface. After executing the command several times in succession, I would occasionally see this issue.

Now I am seeing this more regularly with some new code that has been implemented. Every 1.25 ms frame, there is a function that calls adi_adrv9001_Rx_Gain_Get() to read the current RX gain table setting. After 4 or 5 frames, an error_code = -3 is returned, and the system is then in a bad state as described above. According to the adrv9001 device structure, the error occurs at line 593 in adi_adrv9001_rx.c:

    ADI_EXPECT(adrv9001_NvsRegmapRxb_AgcGainIndex_Get, device, baseAddr, gainIndex);

The API code is a bit difficult for me to follow, so I didn't investigate in more detail, but if there are any suggestions for debugging the code, I would be happy to give them a try. Is there any issue with the rate I am calling the API function (every 1.25 ms)? If so, what is the requirement/limitation? 

  • Some additional information:

    My code had 2 tasks that were both calling adi_adrv9001_Rx_Gain_Get(), and I suspect that one API call was being preempted by another during the middle of its processing. Once I moved the API calls to the same task, so that they would run sequentially, I no longer saw the error code. I assume this should not be allowed, but please confirm whether or not that is a constraint, if it only applies to certain API calls, etc. 

    A second issue I am now seeing is that a call to adi_adrv9001_Radio_Carrier_Inspect() to get the carrier frequency is now taking an exceptionally long time to return (on the order of 1 ms). This only started happening as a result of moving some code around, so something about the relative timing appears to have triggered this. Since I now have all my API calls in a single task, I don't see why this API call should have an issue. Is there anything in adi_adrv9001_Radio_Carrier_Inspect() that would result in a long wait just to return the carrier frequency value?

  • Hi,

    Thank you for providing additional information.

    Not sure it is documented somewhere, but all API functions should not be preempted and your observation is correct. Therefore care should be taken if the software is multi-threaded.

    Regarding the time taken to execute the adi_adrv9001_Radio_Carrier_Inspect() function, it is not obvious if there is any reason for additional delay. I don't believe it is related to the relative timing, but can't be sure because ARM sub system inside the chip is quite complex. So it'd be helpful you could narrow down the case such as a particular sequence of commands that produces a delay. I suppose it returns correct value even when it takes longer.



  • When you state that API functions should not be preempted, does that mean they should not be preempted by another API call, or should not be preempted by anything?

    I was able to capture some profiling data on our system, and it appears that the call to adi_adrv9001_Radio_Carrier_Inspect() takes about 400 us to complete. Because it takes so long to return, I suspect that it is being preempted by another task in our application (one that does not have any API calls, if that matters).

    Does it sound right that this API call is taking 400 us or more to complete? Fortunately we can work around this (it's not necessary to call the API every frame), because our system cannot tolerate masking interrupts and precluding preemption for a 400 us period. 

  • Hi,

    What I meant was that you need to wait until the current API call returns before calling another API call.

    In general we don't specify the time it takes to return for each API. It took slightly longer than 400 us in our testing for this particular API call, so your data makes sense to me. 

    This function may not have to be called so often and it sounds that your system can handle this delay. So I suppose this case can be closed. Please let me know otherwise.



  • Sorry that my answer above was a bit misleading--I am able to work around the issue by hard-coding the carrier frequency and never calling the API function. Calling the API is still problematic.

    I went back and was able to capture more data, and what I saw was that after being called a few times, eventually the API takes much longer to return: around 1.2 ms. At this point, our software task is no longer able to keep up with our real-time frame rate.

    Can you think of anything that might cause the API to require such a long time to return? Would you be able to test the API in a similar manner to how we are using it (calling multiple times about every 1 ms) and see if you get the same results?

  • Hello,
    Sorry it took some time to get back to you on this. I needed to make sure.

    Please search "ADI_ADRV9001_GETCARRIER_FREQUENCY_INTERVAL_US" in your source code. The response time seems to be gated by this delay and currently it is set to 1000 us, so changing this value to smaller (ZERO) would solve your problem. I believe it is OK to set this value to 0. Please try this out and let us know if you encounter any other issue.



  • Sorry for the delay, but I would like to resume the discussion here. I did finally try setting the value specified above to 0, and while it does help, the results are still not great. After the change, I consistently see about 350 us of latency for the adi_adrv9001_Radio_Carrier_Inspect() API call. 

    I don't want to lose sight of the bigger question here. Why do several of the API calls take a very long time to return? At this point I have only tried using a subset of the available APIs, and my concern is that we might run into other issues down the road, if we were to build a more complex product.

    There appear to be many other definitions in the adi_adrv9001_user.h file that might also impact the performance of anything using the SPI. However, I don't think it would be productive for me to start testing different values without having some understanding of what is going on over the SPI and what might be limiting the performance of the APIs. Would you be able to provide any insight on this?

  • Hi,

    Thank you for the feedback.

    The firmware running inside the ADRV9002 chip runs some kind of RTOS and it processes the commands coming from SPI port based on the priority of each command. Priorities of the API commands are defined in the "\adi_adrv9001_timing.h" as shown below.
    * \file
    * \brief Description of message types and timing characteristics
    * \page timing Timing information
    * API calls fall into groups based on the message type used:
    * - \subpage timing_direct
    * - \subpage timing_mailbox
    * - \subpage timing_prioritymailbox
    * - \subpage timing_fastmessaging
    * - \subpage timing_interrupt
    * \page timing_direct Direct ADRV9001 register access
    * API calls that bypass the ADRV9001 processor and directly write or read SPI registers
    * \page timing_mailbox ADRV9001 mailbox commands
    * API calls that communicate via normal mailbox commands to the ADRV9001 onboard processor
    * \page timing_prioritymailbox High-priority ADRV9001 mailbox commands
    * API calls that communicate via high-priority mailbox commands to the ADRV9001 onboard processor
    * \page timing_fastmessaging Fast-messaging
    * API calls that communicate via fast message to the ADRV9001 onboard processor for more deterministic timing
    * \page timing_interrupt Software interrupt
    * API calls that communicate via software interrupt to the ADRV9001 onboard processor

    Every API has listed its message type in the source code, for example the adi_adrv9001_Radio_Carrier_Inspect() function is "Mailbox command" type. So users would roughly expect the API response time from the API types. “timing_direct” type API response time is mainly determined by SPI rate and how many SPI operations are performed in the API. “timing_mailbox” response time depends on the Navassa RTOS tasks, response time could be hundreds us to several ms as previous mentioned. The last three types, timing_prioritymailbox, timing_fastmessaging, timing_interrupt utilize software interrupt from BBIC to Navassa to interrupt Navassa processor, the response time could vary from API to API, but those APIs are for timing sensitive operations like the FH, fast profile switching, etc. I’m guessing the response time should be us class.

    Hope this answers your questions and addresses your concerns.
    In typical application, we did not expect you to call adi_adrv9001_Radio_Carrier_Inspect() function frequently and that's why the priority is low. It'd be helpful for us if you could tell us the reason why you have to call this API often?



  • I had meant to post this previously, but forgot to do is some data I had taken on the API response times:

    • adi_adrv9001_Rx_Gain_Set(): 9.5 us
    • adi_adrv9001_Rx_Gain_Get(): 7.8 us
    • adi_adrv9001_Tx_Attenuation_Set(): 37 us
    • adi_adrv9001_Tx_Attenuation_Get(): 140 us
    • adi_adrv9001_AuxDac_Code_Set(): 22.7 us
    • adi_adrv9001_Radio_Carrier_Inspect(): 400-1200 us

    As I stated earlier, it was not necessary for us to be calling adi_adrv9001_Radio_Carrier_Inspect() every frame, so that was a simple workaround, and I'd like to focus on some other questions.

    For the functions that set/read RX gain and TX attenuation, I'm guessing that these are direct register access from looking at the code. Is that correct? If so, then I am wondering why the TX attenuation functions are significantly more than the RX functions.

    In particular, the 140 us delay to read TX attenuation is somewhat concerning. Upon inspection of the code, I saw that there was a hard-coded 100 us delay inserted in the function:

    /* A delay is needed between set and get function */
    waitInterval_us = 100;

    halError = adi_common_hal_Wait_us(&device->common, waitInterval_us);

    Is 100us of delay really needed in this function, or could it possibly be reduced? Are there other API functions where there are similar delays inserted?

  • Hi,

    Thank you for additional data. 

    APIs classified as "direct register access" are handled with higher priority but it doesn't mean and they return immediately. It is not quite equivalent to accessing real hardware registers. So some APIs (TX attenuation in this case) may take longer than others.

    Regarding the 100 us delay that is enforced to the adi_adrv9001_Tx_Attenuation_Get() function, it might be possible to optimize the delay in the future release but it is safe to keep the delay in the current release. 

    As you noticed, some of APIs are not optimized for the response time and we hope that they are not too much trouble for you. Our team is currently looking into a possibility to optimize the response time, but it is not committed at the moment.