This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDC7200: Problems reading the measurement registers

Part Number: TDC7200
Other Parts Discussed in Thread: MSP430FR5969,

Hi,

I'm using two TDC7200s to measure the ToF in a LiDAR application. Up until this moment, I've been able to correctly set the SPI interface and correctly configure the registers.The start signal is given simultaneously to both by a PWM signal at 6.5kHz.

After the interrupt is detected in the TDC pin, the msp430 reads the data from both TDCs . The problem is when I read the measurement registers. Firstly, I've confirmed and I can successfully read the configuration registers and get the result of the initial setting. Furthermore, the registers TIME1 and CALIBRATION1 and CALIBRATION2 can also be read, giving a calibrated LSB value around 56ns. However, the problem comes when I read the CLOCK_COUNTER1 and I get 0x00. The CLOCK_CNTR_OVF is set to 0x10 (MSB byte to 0x00) to count up to 1us with a 16MHz external clock signal supplied by an MSP430FR5969, while the COARSE_CNTR_OVF is set by default to 0xFFFF. Before reading this value, I read the INT_STATUS register and obtained 0x1D, meaning that the CLOCK_COUNTER1 overflowed. Whatsoever, when I try to read the value in the register before starting a new measurement, I always obtain 0x00.

The implemented code is the following:

#include <msp430fr5969.h>
#include <SPI.h>
                    
                                                  
float f_p = 5, duty_cycle = 0.65;    
float  ToF_1, ToF_2, calCount_1, calCount_2, normLSB_1, normLSB_2, range;
uint8_t restart[2] = {0b01000000, 0b10010011};
int restart_len = sizeof(restart)/sizeof(restart[0]);

uint8_t TIME1_1[3] = {}, CLOCK_COUNT_1_1[3] = {}, TIME2_1[3] = {}, CALIBRATION1_1[3] = {}, CALIBRATION2_1[3] = {};    // Buffers to load read values from TDC1
uint8_t TIME1_2[3] = {}, CLOCK_COUNT_1_2[3] = {}, TIME2_2[3] = {}, CALIBRATION1_2[3] = {}, CALIBRATION2_2[3] = {};    // Buffers to load read values from TDC1
                                 
void setup_PWM(float , float );
void setup_TDC();
void SPI_send(uint8_t *, int , int);
void SPI_receive(uint8_t *, uint8_t, int);
void ToF_read();

void setup() {                                                      // Setup the system
  PM5CTL0 &= ~LOCKLPM5;                                             // Disable the GPIO power-on default impedance mode 

  Serial.begin(115200);                                                                                             
                                                               
  P2DIR &= ~0x10;                                                   // Interrupt for TDCs                    
  P2REN |= 0x10;                                                   
  P2IES |= 0x10;                                                    
  P2IFG &= ~0x10;                                                  
  P2IE |= 0x10;                                                    
                                                               
  P3DIR |= 0x10;                                                    // Output SMCLK 
  P3SEL1 |= 0x10;                                                                                                


  setup_TDC();                                                      // Setup the TDCs
  delay(2);                                                         // Stabilize

  setup_PWM(f_p, duty_cycle); 
}

void loop(){                                    
  // ToF calculation
  calCount_1 = (int)(CALIBRATION2_1[0]*65536+CALIBRATION2_1[1]*256+CALIBRATION2_1[2])-(CALIBRATION1_1[0]*65536+CALIBRATION1_1[1]*256+CALIBRATION1_1[2]);  //2 Calibration periods
  normLSB_1 = (float)(62500/calCount_1);    // In picoseconds or else there is not enough resolution
  ToF_1 = (float)normLSB_1*0.001*(TIME1_1[0]*65536+TIME1_1[1]*256+TIME1_1[2]-TIME2_1[0]*65536-TIME2_1[1]*256-TIME2_1[2])+(CLOCK_COUNT_1_1[1]*256+CLOCK_COUNT_1_1[2])*62.5;
  
  calCount_2 = (float)(CALIBRATION2_2[0]*65536+CALIBRATION2_2[1]*256+CALIBRATION2_2[2])-(CALIBRATION1_2[0]*65536+CALIBRATION1_2[1]*256+CALIBRATION1_2[2]);  //2 Calibration periods
  normLSB_2 = (float)(62500/calCount_2);    // In picoseconds
  ToF_2 = (float)normLSB_2*0.001*(TIME1_2[0]*65536+TIME1_2[1]*256+TIME1_2[2]-TIME2_2[0]*65536-TIME2_2[1]*256-TIME2_2[2])+(CLOCK_COUNT_1_2[1]*256+CLOCK_COUNT_1_2[2])*62.5;
  
  range = (ToF_2 - ToF_1)*0.15;                                     // range in meters (divided by 2 to account forth and back)
  if(range>100) range = 100;                                        // Limiting the system. In practice it won't even be near this range value                     
  Serial.println(ToF_1);                                            // Send distance via UART to PC
  Serial.println(ToF_2);
  Serial.println(range);

  Serial.println(STATUS[0]);
}

#pragma vector=PORT2_VECTOR
__interrupt void PORT2_ISR_HOOK(void){                              
  for(int i=0;i<8;i++) nop;                                         // Guarantee both TDCs activate Interrupt                                        
  ToF_read();                                                       // Receive data
  P2IFG &= ~0x10;                                                   
  P2IE |= 0x10;                                                     // Re-enable Interrupt                                                   
}                                                                   

void setup_PWM(float f_pwm, float dc_pwm) {                         
  P1DIR |= 0x04;                                                    // P1.2 as the PWM output (dedicated pin) 
  P1OUT &= ~0x04;                                                   
  P1SEL0 |= 0x04;                                                   
                                                                 
  TA1CTL |= TASSEL_2 | ID__1 | MC_1 | TACLR;                        
  TA1CCTL1 = OUTMOD_7;                                              
  int T_0 = int(16000 / f_pwm);                                     
  int T_1 = int(dc_pwm * T_0);                                      
  TA1CCR0 = T_0;                                                     
  TA1CCR1 = T_1;                                                                                                                      
}

void SPI_send(uint8_t *data, int len, int sel) {                                  
  (sel==1 ? P4OUT &= ~0x08 : (sel==2 ? P3OUT &= ~0x01 : P1OUT &= ~0x10));         
  while (len){                                                                     
    while(!(UCB0IFG & UCTXIFG));                                                  
    UCB0TXBUF = *(data++);                                                        
    while(!(UCB0IFG & UCTXIFG));                                   
    UCB0TXBUF = *(data++);  
    while (UCB0STAT & UCBUSY);                                                                
    len-=2;                                                                       
  }
   (sel==1 ? P4OUT |= 0x08 : (sel==2 ? P3OUT |= 0x01 : P1OUT |= 0x10));            
}

void setup_TDC(){                                                   // Configure both TDCs
  P3DIR |= 0x01;                                                    
  P3OUT |= 0x01;
  P1DIR |= 0x10;                                                    
  P1OUT |= 0x10;                                                      
  UCB0CTLW0 = UCSWRST | UCSSEL_2;                                   
  UCB0CTLW0 |= UCCKPH | UCMSB | UCSYNC | UCMST;                     
  UCB0CTLW0 &= ~UCCKPL;                                            
  P1DIR &= ~0b10000000;                                             
  P1DIR |= 0b01000000;                                              
  P1SEL1 |= 0b11000000;                                                                                        
  P1SEL0 &= ~0b11000000;
  P2DIR |= 0b00000100;                                              
  P2SEL1 |= 0b0000100;                                              
  P2SEL0 &= ~0b00000100;
  UCB0BR0 = 1;                                                                                 
  UCB0BR1 = 0;
  UCB0CTLW0 &= ~UCSWRST;    
                                                   
  uint8_t CONFIG1[] = {0b01000000, 0b10010011};                   
  uint8_t CONFIG2[] = {0b01000001, 0b00000000};                   
  uint8_t INT_MASK[] = {0b01000011, 0b00000101};                  
  uint8_t CLOCK_CNTR_OVF_H[] = {0b01000110, 0b0000000};           
  uint8_t CLOCK_CNTR_OVF_L_1[] = {0b01000111, 0b00010000};        
  uint8_t CLOCK_CNTR_OVF_L_2[] = {0b01000111, 0b00100000};        
  
  int config_len = sizeof(CONFIG1)/sizeof(CONFIG1[0]);            
                                                                   
  SPI_send(CONFIG1,config_len,2);         
  SPI_send(CONFIG1,config_len,3);  
  SPI_send(CONFIG2,config_len,2);
  SPI_send(CONFIG2,config_len,3);
  SPI_send(INT_MASK,config_len,2);      
  SPI_send(INT_MASK,config_len,3); 
  SPI_send(CLOCK_CNTR_OVF_H,config_len,2);
  SPI_send(CLOCK_CNTR_OVF_H,config_len,3);
  SPI_send(CLOCK_CNTR_OVF_L_1,config_len,2); 
  SPI_send(CLOCK_CNTR_OVF_L_2,config_len,3);                            
}

void ToF_read(){                                                    // Read data from TDC whenever an interrupt is detected in P2.4
  // Receive data for TDC1 and TDC2
  SPI_receive(TIME1_1,0x10,2);
  SPI_receive(TIME1_2,0x10,3);
  SPI_receive(CLOCK_COUNT_1_1,0x11,2);
  SPI_receive(CLOCK_COUNT_1_2,0x11,3);
  SPI_receive(TIME2_1,0x12,2);
  SPI_receive(TIME2_2,0x12,3);
  SPI_receive(CALIBRATION1_1,0x1B,2);
  SPI_receive(CALIBRATION1_2,0x1B,3);
  SPI_receive(CALIBRATION2_1,0x1C,2);
  SPI_receive(CALIBRATION2_2,0x1C,3);

  // Restart measurement
  SPI_send(restart,restart_len,2);
  SPI_send(restart,restart_len,3);
}

void SPI_receive(uint8_t *buffer, uint8_t addr, int sel){      
  (sel==2 ? P3OUT &= ~0x01 : P1OUT &= ~0x10);                                                                                                                   
  while(!(UCB0IFG & UCTXIFG));                                         
  UCB0TXBUF = addr;                                              
  for(int w=0;w<3;w++){                                                
    while(!(UCB0IFG & UCTXIFG));
    UCB0TXBUF = 0x00;                                                    
    while (UCB0STAT & UCBUSY);                                          
    buffer[w] = UCB0RXBUF;                                                 
  }
  while (UCB0STAT & UCBUSY);                                                                   
  (sel==2 ? P3OUT |= 0x01 : P1OUT |= 0x10);    
}

I've noticed another thing that may help. When I try the measurement in MODE 2, the register TIME1 does measure some values and I can read values other than 0. However, if I choose mode 1 I still can obtain a interrupt for COARSE_CNTR_OVF on INT_STATUS but when I read TIME1 I can only obtain 0x00 every time.

Another question, the input STOP pulse I'm having has a shape like below and I'm setting the STOP on the falling edge. Is there any problem ? Or the TDC automatically assumes a STOP if the STOP is kept at a high level?

Can anyone help?

Thanks in advance,

Joaquim

  • Joaquim,

    I will respond to your question within the next 2 days.
  • Joaquim,

    Your STOP pulse setting with the shape shown above, should work.

    In measurement mode 1 as shown in Figure 16 in the TDC7200 datasheet, the TDC7200 performs the entire counting from START to the last STOP using its internal ring oscillator plus coarse counter. This method is recommended for measuringshorter time durations of < 500 ns.

    Time measurements by the TDC7200 rely on two counters: the Coarse Counter and the Clock Counter. The Coarse Counter counts the number of times the ring oscillator (the TDC7200’s core time measurement mechanism) wraps, which is used to generate the results in the TIME1 to TIME6 registers. The Clock Counter counts the number of integer clock cycles between START and STOP events and is used in Measurement Mode 2 only.

    In case you need further clarification, please send me a registry map of your setting on the various mode you are measuring and the issue you see on the corresponding setting.