MCU calibration fails with LimeSuite

#1

Hi guys,
I am using LimeSuite for development of a custom board. When I try to use LMS_Calibrate function using Lime API I get the following error.**Rx calibration: MCU error 5 (Loopback signal weak: not connected/insufficient gain?)
**
This actually brings down the offset level but it changes some of the parameters like CGEN . Our system is very sensitive to changes in CGEN as the input signal is received from DIQ lines. How do I calibrate without changing CGEN, SXT and SXR ?
I have added my code below for reference —
#include
#include
#include <wiringPi.h>
#include “lime/LimeSuite.h”
#include “lime/LMS7002M.h”
#include “lime/Logger.h”
#include “lime/lms7_device.h”
#include
#define NDEBUG
using namespace std;
using namespace lime;
#define RFD_EXT_CLK 50e6

    enum ARGS{
      CHAN=1,
    };

    enum ERRORS{
      NO_DEV=-1,
      NOT_OPEN=-2,
      ERROR_ARG=-3
    };

    lms_device_t* device = NULL;

    int my_Init() {
        struct regVal
        {
            uint16_t adr;
            uint16_t val;
        };
        const std::vector<regVal> initVals = {
            {0x0022, 0x0FFF}, {0x0023, 0x5550}, {0x002B, 0x0038}, {0x002C, 0x0000},
            {0x002D, 0x0641}, {0x0086, 0x4101}, {0x0087, 0x5555}, {0x0088, 0x0525},
            {0x0089, 0x1078}, {0x008B, 0x218C}, {0x008C, 0x267B}, {0x00A6, 0x000F},
            {0x00A9, 0x8000}, {0x00AC, 0x2000}, {0x0108, 0x318C}, {0x0109, 0x57C1},
            {0x010A, 0x154C}, {0x010B, 0x0001}, {0x010C, 0x8865}, {0x010E, 0x0000},
            {0x010F, 0x3142}, {0x0110, 0x2B14}, {0x0111, 0x0000}, {0x0112, 0x000C},
            {0x0113, 0x03C2}, {0x0114, 0x01F0}, {0x0115, 0x000D}, {0x0118, 0x418C},
            {0x0119, 0x5292}, {0x011A, 0x3001}, {0x011C, 0x8941}, {0x011D, 0x0000},
            {0x011E, 0x0984}, {0x0120, 0xE6B4}, {0x0121, 0x3638}, {0x0122, 0x0514},
            {0x0123, 0x200F}, {0x0200, 0x00E1}, {0x0208, 0x017B}, {0x020B, 0x4000},
            {0x020C, 0x8000}, {0x0400, 0x8081}, {0x0404, 0x0006}, {0x040B, 0x1020},
            {0x040C, 0x00FB}
        };
        LMS7_Device* dev=(LMS7_Device*)device;
        for(int i=0;i<1;i++){
            LMS7002M* lms =((LMS7_Device*)device)->GetLMS() ;
           // if (lms->ResetChip() != 0)
           //     return -1;
            LMS_WriteParam(device,LMS7param(MAC), 1);
            for (auto i : initVals)
                LMS_WriteLMSReg(device,i.adr, i.val);
            LMS_WriteParam(device,LMS7param(MAC), 2);
            for (auto i : initVals)
                if (i.adr >= 0x100)
                    LMS_WriteLMSReg(device,i.adr, i.val);
            lms->EnableChannel(false, false);
            lms->EnableChannel(true, false);
            LMS_WriteParam(device,LMS7param(MAC), 1);
            if (dev->SetFrequency(true,2*i,2200e6)!=0)
                return -1;
            if (dev->SetFrequency(false,2*i,2300e6)!=0)
                return -1;
        }
        if (dev->SetRate(10e6,2)!=0)
            return -1;
        
        return 0;
    }


    int main(int argc,char** argv){
      int n;
      lms_info_str_t list[8];
      if(argc!=2){
    	cout<<"USAGE :sudo ./dcoffset_calib <channel-0,1>"<<endl;
            return -1;
      }        
    //INITIALIZE THE BOARD FOR COMMUNCATION
      //get device list
      if((n = LMS_GetDeviceList(list)) < 0){
            cout<<"Could not get devices";
            return NO_DEV;
      }
      if(LMS_Open(&device,list[0],NULL)){
            cout<<"Could not open device";
            return NOT_OPEN;
      }
      int channel = atoi(argv[CHAN]);
      
      if(channel >1 || channel <0 ){
    	cout<<"Channel must be 0 or 1"<<endl;
    	return -1;	
      }
      LMS_WriteParam(device,LMS7param(MAC),channel+1);
      LMS_SetClockFreq(device,LMS_CLOCK_REF,RFD_EXT_CLK);
      if(my_Init()){	
        cout<<" INIT FAILED"<<endl;
        return -1;
      }
      if (LMS_Calibrate(device, LMS_CH_RX,channel, 8e6, 0) != 0){
       cout<<"DC offset calibration failed for channel "<<char('A'+channel)<<endl;
      }      
    }
#2

To calibrate, Rx needs to be able to receive test signal from Tx, and the maximum frequency difference between them to be able to do it depends on CGEN.
So in your code case, Rx:2200MHz Tx:2300MHz, Fs:10MHz calibration would not be possible without changing at least one of them.

#3

Ok, @ricardas. Forgive my ignorance .I am rather new to RF stuff. I get it now . I have to set SXT, SXR and CGEN for calibration .
But when I do LMS_Calibrate I get the followind error
Rx calibration: MCU error 5 (Loopback signal weak: not connected/insufficient gain?) .
I have set all gains to maximum in the TX and RX(LNA,TIA,PGA) path . Do I also have to set the loopback path and loopback gain manually or is it done by the MCU ?

#4

All you have to do is to configure the chip to your desired working state, everything else needed during calibration is set by the MCU and after the calibration finishes it restores your configuration and just updates the calibration values.

In your case the Rx calibration fails because receiver cannot see the test signal or it is very low near the noise floor. Only your rx settings affects this, I’m not sure about other factors that could affect that.

#5

@ricardas.Do you think setting turning ON or OFF the LDOs will have an effect ?

#6

@ricardas,
I was able to program the MCU without any errors . It seems I wasn’t setting the RX path (LNAH) and TX path(BAND2) correctly and LMS_Init does not configure RX or TX path . In my program, there is an initialization script(init) which is setting CGEN(400 MHz),SXR(2250 MHz) and SXT(2250 MHz) and filter bandwidth(50 MHz). Also it sets the LimeLight Port for Data Acquisition among other things . I am calling the following script(dcoffset_calib) for offset and IQ imbalance calibration.

     int main(int argc,char** argv){
      int n;
      lms_info_str_t list[8];
      if(argc!=3){
            cout<<"USAGE :sudo ./dcoffset_calib <channel-0,1> <dir-RX or TX>"<<endl;
            return -1;
      }
    //INITIALIZE THE BOARD FOR COMMUNCATION
      //get device list
      if((n = LMS_GetDeviceList(list)) < 0){
            cout<<"Could not get devices";
            return NO_DEV;
      }
      if(LMS_Open(&device,list[0],NULL)){
            cout<<"Could not open device";
            return NOT_OPEN;
      }
      int channel = atoi(argv[CHAN]);
      string dir  = argv[DIR];
      if(channel >1 || channel <0 ){
            cout<<"Channel must be 0 or 1"<<endl;
            return -1;
      }
      cout<<"Calibrating for channel "<<char('A'+channel)<<endl;
      LMS_WriteParam(device,LMS7param(MAC),channel+1);
      LMS_SetClockFreq(device,LMS_CLOCK_REF,RFD_EXT_CLK);
      LMS_SetAntenna(device, LMS_CH_RX, channel, 2);//select LNAH
      LMS_SetAntenna(device, LMS_CH_TX, channel, 2);//select Band2
      if(dir == "RX"){
        if (LMS_Calibrate(device, LMS_CH_RX,channel, 8e6, 0) != 0){
            cout<<"DC offset calibration failed for channel "<<char('A'+channel)<<endl;
            return -1;
         }
       }
      else if(dir == "TX"){
         if (LMS_Calibrate(device, LMS_CH_TX,channel, 8e6, 0) != 0){
            cout<<"DC offset calibration failed for channel "<<char('A'+channel)<<endl;
            return -1;
          }
      }

While DC offset calibration is correct . This script messes up the gains set by init1 and does nothing to improve I,Q imbalance . How can I fix this issue ?

#7

Calibration is not suppose to change your gains, something else is doing that. I don’t know how your “scripts” are suppose to work together, but my guess is that the problem in this code is that there could be register values mismatch of what is in chip registers and what values are known in the software. After you do LMS_Open() only the connection is established to the chip, at that point software is in default values state and does not know what values are currently in the chip’s registers. You need to call LMS_Synchronize(device, false) to readback the registers before you can continue to change settings.