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.

Using external isolated ADC

Other Parts Discussed in Thread: TMS320F28027F

Hello, i am using Instaspin MCU TMS320F28027F and want to use small MCU to sample voltages and currents on a hot side, i have an idea how to make it, but i want someone more experienced to check it.  PWM will generate interrupt instead of SOC, in interrupt i notify ADC to start conversion by setting GPIO pin high, waiting 2uS (to complete conversion) and then start receiving 16 bytes by SPI, but i dont know how to implement it better, because DMA doesnt work with SPI and SPI FIFO is only 4 half-words deep. I have an idea to receive each byte in interrupt until we receive all 16, and then run FOC.

Here is what i changed. Changes in main()

HAL_enableAdcInts(halHandle);
to
HAL_enablePwmInt(halHandle);

In HAL_setupPwms()

PWM_disableInt(obj->pwmHandle[PWM_Number_1]);
PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualZero);
PWM_enableSocAPulse(obj->pwmHandle[PWM_Number_1]);
to
PWM_disableSocAPulse(obj->pwmHandle[PWM_Number_1]);
PWM_enableInt(obj->pwmHandle[PWM_Number_1]);
PWM_setIntMode(obj->pwmHandle[PWM_Number_1], PWM_IntMode_CounterEqualZero);

Changed HAL_SetTrigger() 

static inline void HAL_setTrigger(HAL_Handle handle,const SVGENCURRENT_IgnoreShunt_e ignoreShunt,const int16_t minwidth, const int16_t cmpOffset)
{
  HAL_Obj *obj = (HAL_Obj *)handle;

  PWM_Obj *pwm1 = (PWM_Obj *)obj->pwmHandle[PWM_Number_1];
  PWM_Obj *pwm2 = (PWM_Obj *)obj->pwmHandle[PWM_Number_2];
  PWM_Obj *pwm3 = (PWM_Obj *)obj->pwmHandle[PWM_Number_3];
  PWM_Obj *pwm;

  uint16_t nextPulse1 = (pwm1->CMPA + pwm1->CMPAM) / 2;
  uint16_t nextPulse2 = (pwm2->CMPA + pwm2->CMPAM) / 2;
  uint16_t nextPulse3 = (pwm3->CMPA + pwm3->CMPAM) / 2;
  uint16_t pwmCMPA1 = pwm1->CMPA;
  uint16_t pwmCMPA2 = pwm2->CMPA;
  uint16_t pwmCMPA3 = pwm3->CMPA;

  int16_t offset;

  if(ignoreShunt == use_all)
    {
      if((nextPulse1 <= nextPulse2) && (nextPulse1 <= nextPulse3))
        {
          pwm = pwm1;
        }
      else if((nextPulse2 <= nextPulse1) && (nextPulse2 <= nextPulse3))
        {
          pwm = pwm2;
        }
      else
        {
          pwm = pwm3;
        }
    }
  else if(ignoreShunt == ignore_a)
    {
      offset = pwmCMPA1 + cmpOffset;
    }
  else if(ignoreShunt == ignore_b)
    {
      offset = pwmCMPA2 + cmpOffset;
    }
  else if(ignoreShunt == ignore_c)
    {
      offset = pwmCMPA3 + cmpOffset;
    }
  else if(ignoreShunt == ignore_ab)
    {
      if(pwmCMPA1 > pwmCMPA2)
        {
          offset = pwmCMPA1 + cmpOffset;
        }
      else
        {
          offset = pwmCMPA2 + cmpOffset;
        }
    }
  else if(ignoreShunt == ignore_ac)
    {
      if(pwmCMPA1 > pwmCMPA3)
        {
          offset = pwmCMPA1 + cmpOffset;
        }
      else
        {
          offset = pwmCMPA3 + cmpOffset;
        }
    }
  else // when ignoreShunt == ignore_bc
    {
      if(pwmCMPA2 > pwmCMPA3)
        {
          offset = pwmCMPA2 + cmpOffset;
        }
      else
        {
          offset = pwmCMPA3 + cmpOffset;
        }
    }


  if(ignoreShunt == use_all)
    {
      if(pwm->CMPAM >= (pwm->CMPA + pwm->DBFED))
        {
          pwm1->CMPB = (pwm->CMPAM - (pwm->CMPA + pwm->DBFED)) / 2 + 1;
          //PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualCmpBDecr);
          PWM_setIntMode(obj->pwmHandle[PWM_Number_1], PWM_IntMode_CounterEqualCmpBDecr);
        }
      else
        {
          pwm1->CMPB = ((pwm->CMPA + pwm->DBFED) - pwm->CMPAM ) / 2 + 1;
          //PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualCmpBIncr);
          PWM_setIntMode(obj->pwmHandle[PWM_Number_1], PWM_IntMode_CounterEqualCmpBIncr);
        }
    }
  else
    {
      pwm1->CMPB = offset;
      //PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualCmpBIncr);
      PWM_setIntMode(obj->pwmHandle[PWM_Number_1], PWM_IntMode_CounterEqualCmpBIncr);
    }

  return;
}

Added PWM interrupt vector

static inline void HAL_initIntVectorTable(HAL_Handle handle)
 {
  HAL_Obj *obj = (HAL_Obj *)handle;
  PIE_Obj *pie = (PIE_Obj *)obj->pieHandle;


  ENABLE_PROTECTED_REGISTER_WRITE_MODE;

  //pie->ADCINT1 = &mainISR; // Dont know yet what will trigger mainISR
  pie->EPWM1_INT = &startConvISR;

  DISABLE_PROTECTED_REGISTER_WRITE_MODE;

  return;
 }

Also created ISR for PWM int

interrupt void startConvISR(void)
{
  HAL_acqPwmInt(halHandle, PWM_Number_1);
  // Notify external ADC
  return;
}

  • I forgot to ask about possible delays because of transmitting ADC data over SPI. Do i have to compensate about 10uS of delay ?
    And is there an instaspin MCU with SPI FIFO >= 16 bytes or SPI+DMA capability ?
  • Hi Viktor,

    Your idea can work. The key to the timing is to get the ADC sampling to be consistently triggered at the same point, the sample point is where you want it, and the phases simultaneously sampled. Once you have this then the delay in the SPI transmission can be managed,

    A couple thoughts for you:
    - Consider making the ADC trigger 100% HW. You can do this and still have the delay by synchronizing another ePWM with the (3) that you use for the motor. This 4th ePWM can then have its period or compare register set to wherever you want the ADC trigger print to be. You can use ADCSOCA0 or ADCSOCB0.
    - For the SPI communication you could use a short SPI ISR to manage the FIFO. You should be able to receive the transmitted data before the start of your next PWM cycle, time enough to load the next set of duty cycles. It will be important to verify this timing.

    Jeff
  • Hi Viktor,

    Do you have an update?

    Thanks,
    Jeff
  • Yes, i have changed an algorithm. I trigger ADC by routing SOC signal to GPIO pin, we waiting around 3uS for conversion complete and use an interrupt on another PWM channel compare.

      // Configure hardware SOC pulse
      PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualZero);
      PWM_enableSocAPulse(obj->pwmHandle[PWM_Number_1]);
    
      // Configure interrupt for ADC reading over SPI
      PWM_setIntMode(obj->pwmHandle[PWM_Number_2], PWM_IntMode_CounterEqualCmpBIncr);
      obj->pwmHandle[PWM_Number_2]->CMPB = HAL_EXTERNAL_ADC_DELAY;
      PWM_enableInt(obj->pwmHandle[PWM_Number_2]);
    interrupt void startConvISR(void) {
    	volatile uint16_t adcData[8]={0};
    	volatile uint16_t i=0;
    
    	// For timing check only
    	ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    	halHandle->gpioHandle->GPASET = (uint32_t)1 << GPIO_Number_19;
    	DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
    	halHandle->pwmHandle[PWM_Number_1]->ETCLR = PWM_ETCLR_SOCA_BITS;
    	halHandle->pwmHandle[PWM_Number_2]->ETCLR = PWM_ETCLR_INT_BITS;
    	halHandle->pieHandle->PIEACK = (1 << PIE_GroupNumber_3);
    
    	halHandle->spiAHandle->SPIFFRX &= (~SPI_SPIFFRX_FIFO_RESET_BITS);
    	halHandle->spiAHandle->SPIFFRX |= SPI_SPIFFRX_FIFO_RESET_BITS;
    	halHandle->spiAHandle->SPIFFTX &= (~SPI_SPIFFTX_FIFO_RESET_BITS);
    	halHandle->spiAHandle->SPIFFTX |= SPI_SPIFFTX_FIFO_RESET_BITS;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	while(halHandle->spiAHandle->SPIFFRX&SPI_SPIFFRX_FIFO_ST_BITS < SPI_FifoStatus_4_Words) {};
    	adcData[0]=halHandle->spiAHandle->SPIRXBUF;
    	adcData[1]=halHandle->spiAHandle->SPIRXBUF;
    	adcData[2]=halHandle->spiAHandle->SPIRXBUF;
    	adcData[3]=halHandle->spiAHandle->SPIRXBUF;
    
    	halHandle->spiAHandle->SPIFFRX &= (~SPI_SPIFFRX_FIFO_RESET_BITS);
    	halHandle->spiAHandle->SPIFFRX |= SPI_SPIFFRX_FIFO_RESET_BITS;
    	halHandle->spiAHandle->SPIFFTX &= (~SPI_SPIFFTX_FIFO_RESET_BITS);
    	halHandle->spiAHandle->SPIFFTX |= SPI_SPIFFTX_FIFO_RESET_BITS;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	halHandle->spiAHandle->SPITXBUF = 0x0000;
    	while(halHandle->spiAHandle->SPIFFRX&SPI_SPIFFRX_FIFO_ST_BITS < SPI_FifoStatus_4_Words) {};
    	adcData[4]=halHandle->spiAHandle->SPIRXBUF;
    	adcData[5]=halHandle->spiAHandle->SPIRXBUF;
    	adcData[6]=halHandle->spiAHandle->SPIRXBUF;
    	adcData[7]=halHandle->spiAHandle->SPIRXBUF;
    
    	HAL_readAdcData(halHandle, &gAdcData);
    
    	// run the controller
    	CTRL_run(ctrlHandle, halHandle, &gAdcData, &gPwmData);
    
    	// write the PWM compare values
    	HAL_writePwmData(halHandle, &gPwmData);
    
    	// setup the controller
    	CTRL_setup(ctrlHandle);
    
    	GPIO_setLow(halHandle->gpioHandle, GPIO_Number_19);
    
    	return;
    }

  • Great, thanks for the update.