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.

TMS320F28069M: InstaSPIN - (ISSUE) Motor starts spinning automatically to full speed and becomes uncontrollable

Part Number: TMS320F28069M
Other Parts Discussed in Thread: DRV8353, MOTORWARE

Hello,

Sometimes, after a power cycle, as soon as the FOC is started and the SpinTAC Velocity Control block is regulating at 0 speed, one or more motors automatically start spinning at full speed and cannot be controlled anymore. The only way to stop the motor is to disable the FOC. "Automatically" means that the motor starts spinning even if the speed setpoint fed into the function CTRL_setSpd_ref_krpm is null.
We are running out of ideas now and we need your help to avoid having this uncontrollable behavior that is not acceptable.

Our system is composed by:

  • 6 PMSM motors (3 motors are Kollmorgen BLM4AA, 3 motors are Kollmorgen BLM2AA). Each motor is driven by its own C2000 on a separate PCB and driven using a DRV8353S.
  • Absolute encoders (iC-Haus MU150 + PVL) mounted on each motor and connected to the C2000 using SPI and to the C2000 QEP peripheral using ABZ signals.
  • TI FOC control with SpinTAC Velocity Control and SpinTAC Position Converter for position control. We directly feed the velocity controller with speed setpoints.

Here is the process that is done the first time the system is powered on in order to align the motor with the encoder:

  1. FOC controller is started with Rs Recalculation (EST_setFlag_enableRsRecalc set to true).
  2. During Rs Recalculation, the QEP POSCNT is reset continuously to 0:
    if (EST_State_Rs == EST_getState(m_ctrlHandle->estHandle))
    {
      HAL_resetQepPosnCounts(m_halHandle);
    }
  3. Once the Rs Recalculation is done, the SpinTAC Velocity Control is enabled and starts to control the system in position using QEP peripheral (steady position).
  4. At the end of the Rs Recalculation, the absolute encoder singleturn position is aligned with the QEP POSCNT (using SPI commands).
  5. At this point, the absolute encoder should be aligned to a mechanical 0 position.

Here is the normal process after each power cycle (once the encoder are aligned with the motors):

  1. Singleturn position of the absolute encoder is read and converted into a QEP POSCNT format (0..4095 in our case).
  2. The QEP POSCNT register is set to the value of the singleturn position of the absolute encoder.
  3. FOC controller is started without Rs Recalculation.
  4. At this point, the SpinTAC Velocity Control is enabled and starts to control the system in position using QEP peripheral (steady position).

Uncontrollable issues have been seen in both first time process and normal process as soon as the position control is enabled.

To already answer potential questions on your side:

  • This uncontrolled full-speed issue can occur as soon as a speed different from 0 is set. In other words, it can occur at low speeds.
  • This issue also occurs sometimes when the ST Velocity controller is regulating in position with 0 speed setpoint.
  • There are no errors reported by the FOC controller nor the ST Velocity and ST Position Converter controllers.
  • The motor can only be stopped by disabling the FOC controller. A speed setpoint of 0 using function CTRL_setSpd_ref_krpm does not stop the motor which continues spinning at full-speed.
  • This issue was also seen after motor alignment. The current used during alignment (RES_EST_CURRENT) is already more than 10% of the motor rated current.
  • This issue occurs on different motors and is thus not dependent on particular motors parameters. Motors parameters have been set using InstaSPIN identification process.
  • There is normally no ADC ISR overrun despite the fact that, sometimes, an ISR is delayed due to high-priority UART communication as shown below (PWM freq. = 18kHz, ISR execution = 6kHz, FOC controller execution = 6kHz, ST velocity + position controller execution = 1kHz) - GPIO set low at the beginning of the ISR and set high at the end of the ISR:

Could you please help us on this subject?

I have attached our user.h file. Please note that this file is shared among the two motors types this is why we have replaced MOTOR_ definitions with our own definitions (motor parameters are loaded at startup based on an address).

8512.user.h

This post has been created based on my previous question:
https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/900637

Thank you in advance.

Regards,
Johann

  • I think you should add much more codes in the control ISR, is it possible to move some codes to the main background loop and use a higher ISR frequency like 9kHz, even 18kHz. It seems like 6Khz is too low for current control to achieve good velocity and position control, the control interrupt should be set to the highest priority and nest other interrupts without delay to complete the current close loop control.

    You may disable other interrupts, just enable the control ISR and debug the project with CCS to monitor some control variables like feedback speed and currents. I suppose the feedback speed should be not correct.

    You might have a look at the following two links that should be helpful for you.

    https://e2e.ti.com/support/microcontrollers/c2000/f/171/p/526272/1917534

    https://e2e.ti.com/support/microcontrollers/c2000/f/171/p/378088/1871253

  • I think you should add much more codes in the control ISR, is it possible to move some codes to the main background loop

    Here is the code of the motor control ISR. As you can see, we use current reconstruction since we have high-speed motors.

    interrupt void
    motorCtrl_isr (void)
    {
      SVGENCURRENT_MeasureShunt_e measShunt = immeasureable;
      static uint16_t stCnt = 0U;
      static uint16_t stPosCnt = 0U;
      uint32_t posCnt = 0U;
    
      IER |= 0x0100;
      IER &= 0x0100;
      asm(" NOP");
      EINT;
    
      posCnt = HAL_getQepPosnCounts(m_halHandle);
      measShunt = SVGENCURRENT_getMode(m_svGenCurHandle);
    
      calcAbsPos(posCnt);
    
      // Compute the electrical angle.
      ENC_calcElecAngle(m_encHandle, posCnt);
    
      // Acknowledge the ADC interrupt.
      HAL_acqAdcInt(m_halHandle, ADC_IntNumber_1);
    
      // Convert the ADC data.
      HAL_readAdcData(
        m_halHandle,
        &m_adcData,
        (sdw_adcData_t *)&m_sdwAdcData,
        m_adcFullScaleCurrent
      );
    
      // Check for an overcurrent on the motor.
      checkMotOvercurrent();
    
      if (stCnt++ >= ISR_TICKS_PER_SPINTAC_TICK)
      {
        ST_runPosConv(m_stHandle, m_encHandle, m_ctrlHandle);
        ST_runVelCtl(m_stHandle, m_ctrlHandle);
        stCnt = 1U;
      }
    
      // Run the current reconstruction algorithm.
      SVGENCURRENT_RunRegenCurrent(
        m_svGenCurHandle,
        (MATH_vec3 *)(m_adcData.I.value)
      );
    
      m_iAvg.value[0] += (m_adcData.I.value[0] - m_iAvg.value[0]) >> m_iAvgShift;
      m_iAvg.value[1] += (m_adcData.I.value[1] - m_iAvg.value[1]) >> m_iAvgShift;
      m_iAvg.value[2] += (m_adcData.I.value[2] - m_iAvg.value[2]) >> m_iAvgShift;
    
      if (measShunt > two_phase_measurable)
      {
        m_adcData.I.value[0] = m_iAvg.value[0];
        m_adcData.I.value[1] = m_iAvg.value[1];
        m_adcData.I.value[2] = m_iAvg.value[2];
      }
    
      // Run the controller.
      CTRL_run(
        m_ctrlHandle,
        m_halHandle,
        &m_adcData,
        &m_pwmData,
        ENC_getElecAngle(m_encHandle)
      );
    
      // Run the PWM compensation and ignore current algorithm.
      SVGENCURRENT_compPwmData(
        m_svGenCurHandle,
        &(m_pwmData.Tabc),
        &m_prevPwmData
      );
    
      // Set PWMs.
      HAL_writePwmData(m_halHandle, &m_pwmData);
    
      {
        SVGENCURRENT_IgnoreShunt_e ignoreShuntNextCycle =
          SVGENCURRENT_getIgnoreShunt(m_svGenCurHandle);
        SVGENCURRENT_VmidShunt_e midVolShunt =
          SVGENCURRENT_getVmid(m_svGenCurHandle);
    
        // Set trigger point in the middle of the low side pulse
        HAL_setTrigger(m_halHandle, ignoreShuntNextCycle, midVolShunt);
      }
    
      // Setup the controller.
      CTRL_setup(m_ctrlHandle);
    
      if (EST_State_Rs == EST_getState(m_ctrlHandle->estHandle))
      {
        HAL_resetQepPosnCounts(m_halHandle);
      }
    
      DINT;
    }
    
    static void
    calcAbsPos (const uint32_t qepPos)
    {
      int32_t encTurnCnt = m_oldEncTurnCnt;
    
      if ((m_oldEncCnt > 3800) && (qepPos < 200))
      {
        // Rollover detected (overflow).
        encTurnCnt++;
      }
      else if ((m_oldEncCnt < 200) && (qepPos > 3800))
      {
        // Rollover detected (underflow).
        encTurnCnt--;
      }
      else
      {
        ;
      }
    
      m_absPos += (encTurnCnt - m_oldEncTurnCnt) * (int32_t)m_encCntPerTurn;
      m_absPos += qepPos - m_oldEncCnt;
    
      m_oldEncTurnCnt = encTurnCnt;
      m_oldEncCnt = qepPos;
    }
    
    static void
    checkMotOvercurrent (void)
    {
      float_t ovcThresholdA_neg = -m_ovcThresholdA;
      _iq iq = _IQ(0.0f);
      float_t iq_A = 0.0f;
    
      iq = _IQmpy(
             CTRL_getIq_in_pu(m_ctrlHandle),
             _IQ(m_iqFullScaleCurrent)
           );
      iq_A = _IQ24toF(iq);
    
      if ((iq_A > m_ovcThresholdA) || (iq_A < ovcThresholdA_neg))
      {
        if (true == mb_ovcThresholdReached)
        {
          m_ovcTimeCnt++;
        }
        else
        {
          mb_ovcThresholdReached = true;
        }
      }
      else
      {
        if ((m_ovcTimeCnt > 0) && (false == mb_ovcThresholdReached))
        {
          m_ovcTimeCnt--;
        }
        else
        {
          mb_ovcThresholdReached = false;
        }
      }
    }
    
    void
    ST_runPosConv (
      ST_Handle handle,
      ENC_Handle encHandle,
      CTRL_Handle ctrlHandle
    )
    {
      ST_Obj *stObj = (ST_Obj *)handle;
    
      // Get the electrical angle from the ENC module.
      STPOSCONV_setElecAngle_erev(
        stObj->posConvHandle,
        ENC_getElecAngle(m_encHandle)
      );
    
      // Run the SpinTAC Position Converter.
      STPOSCONV_run(stObj->posConvHandle);
    }
    
    void
    ST_runVelCtl (ST_Handle handle, CTRL_Handle ctrlHandle)
    {
      _iq speedFeedback, iqReference;
      ST_Obj *stObj = (ST_Obj *)handle;
      CTRL_Obj *ctrlObj = (CTRL_Obj *)m_ctrlHandle;
    
      // Get the mechanical speed in pu.
      speedFeedback = STPOSCONV_getVelocityFiltered(stObj->posConvHandle);
    
      // Run the SpinTAC Controller
      // Note that the library internal ramp generator is used to set the speed reference
      STVELCTL_setVelocityReference(
        stObj->velCtlHandle,
        TRAJ_getIntValue(ctrlObj->trajHandle_spd)
      );
      // Internal ramp generator does not provide Acceleration Reference
      STVELCTL_setAccelerationReference(stObj->velCtlHandle, _IQ(0.0));
      STVELCTL_setVelocityFeedback(stObj->velCtlHandle, speedFeedback);
      STVELCTL_run(stObj->velCtlHandle);
    
      // select SpinTAC Velocity Controller
      iqReference = STVELCTL_getTorqueReference(stObj->velCtlHandle);
    
      if (MOT_OP_MODE_Current != m_curMode)
      {
        // Set the Iq reference that came out of SpinTAC Velocity Control.
        CTRL_setIq_ref_pu(m_ctrlHandle, iqReference);
      }
    }
    • Q1: What functions used by InstaSPIN can be safely moved to the main background loop?

    ...use a higher ISR frequency like 9kHz, even 18kHz. It seems like 6Khz is too low for current control to achieve good velocity and position control, the control interrupt should be set to the highest priority and nest other interrupts without delay to complete the current close loop control.

    The problem is that our system relies on a high-speed communication UART (3.75Mbps) that cannot be interrupted by any other interrupt otherwise overrun errors occur (this is the reason why EINT/DINT instructions are used in the motor control ISR). 18 bytes are received followed by 12 bytes sent every 2ms. This is why we had to slow down the motor control timings in order to be sure that we do not miss an ADC sample because of the communication interrupts.

    We plan in the near future to use McBSP with DMA in order to avoid interrupting the motor control ISR anymore.

    Regarding the InstaSPIN execution frequency which is 6kHz, we followed the following recommendation from the InstaSPIN user guide:

    The highest frequency among our motors is 333.33Hz, which means that with 6kHz we are far above the recommendations.

    • Q2: To make things clear, you fear that we are running the InstaSPIN controller + current control too slowly (= CTRL_Run) or also the SpinTAC Velocity Controller and/or SpinTAC Position Converter?
    • Q3: What are your recommendations of execution frequency for the SpinTAC Velocity Controller and the SpinTAC Position Converter? There is not much information about these blocks in the user guide.

    The duration of the motor control interruption without SpinTAC is already almost 90us (this time is mainly equal to the CTRL execution time) which would cause overruns at 18kHz. We saw that when the code is executed exclusively from RAM using the debugger, this time is reduced from about 90us to about 40us.

    • Q4: Is there anything else in "Flash" mode than copying the motor control ISR into RAM at runtime using the instruction #pragma CODE_SECTION(motorCtrl_isr, "ramfuncs"); in order to reduce the motor control ISR execution time drastically?

    You might have a look at the following two links that should be helpful for you.

    I've already seen these post and they haven't helped me to solve the issue. The first post is talking about a certain speed above which the motor has the same uncontrollable behavior as we have. However, in our case, the issue occurs when the motor is not spinning at all.

  • Q1: What current sensor are you using on your board? 1. Define all of the functions in ISR to inline to reduce the function calling branch time. 2. Copy all ISR codes from flash to RAM during running by using "#pragma CODE_SECTION(function_name,"ramfuncs");" and call "memCopy()" as the example lab. 3. Move or remove checkMotOvercurrent() that seems like the function is useless to implement the over-current protection.

    The recommended control frequency (at least 10 times electric frequency) is just for typical InstaSPIN-FOC control, it's better to use a far higher frequency for fast response, high speed, and position control.

    Don't set the USER_MAX_VS_MAG_PU to a value is higher than 0.5774 unless the current sensing is using an inline shunt resistor or hall sensor.

    Q2: All are too slow since the performances of the speed and position loop are based on the frequency of the current loop.

    Q3: That depends on the control bandwidth and required performance. I don't think the bandwidth for SpinTAC Control can be achieved by using such current loop and speed loop frequency. Generally, the frequency of the current loop should be at least 10 times the speed loop.

    Q4: As answers to Q1.

     

  • Hi Seydoux,

    Any updates? Do you have a chance to optimize the ISR code to use a higher frequency ISR for motor control?

  • Hi Yanming,

    What current sensor are you using on your board?

    Do you mean the HW configuration of the phases currents measurement? If so, we are measuring the current using 3 low-side resistors through a DRV8353 connected to three ADC channels.

    We finally did optimize the communication link (we did fight a lot with McBSP SPI DMA implementation until now to make it work).

    I am now able to focus on the motor control ISR execution time optimization.

    I'll come back to you as soon as I do progress on that subject. 

  • Hi Yanming,

    As discussed, can you please:

    Q1. Check why the following code is taking 365 cycles (~4us @90MHz) and how can I reduce this execution time (or improve it)? By the way, counts were measured using timer 0 as shown in the code snippet below. For your information, _IQmpy takes 305 cycles (~3.4us) of the 365 cycles.

      float_t ovcThresholdA_neg = -m_ovcThresholdA;
      _iq iq = _IQ(0.0f);
      float_t iq_A = 0.0f;
    
      m_halHandle->timerHandle[0]->TCR |= (uint16_t)TIMER_TCR_TRB_BITS;
      iq = _IQmpy(
             CTRL_getIq_in_pu(m_ctrlHandle),
             _IQ(m_iqFullScaleCurrent)
           );
      iq_A = _IQ24toF(iq);
      g_dbgIsrExecTimeCnt = 0xFFFFFFFF - m_halHandle->timerHandle[0]->TIM;

    Assembly code is below:

     342      iq = _IQmpy(
    008aa4:   5CAD        MOVZ         AR4, @SP
     341      m_halHandle->timerHandle[0]->TCR |= (uint16_t)TIMER_TCR_TRB_BITS;
    008aa5:   8B12        MOVL         XAR1, @0x12
    008aa6:   D07E        MOVB         XAR0, #0x7e
     342      iq = _IQmpy(
    008aa7:   DC8C        SUBB         XAR4, #12
     341      m_halHandle->timerHandle[0]->TCR |= (uint16_t)TIMER_TCR_TRB_BITS;
    008aa8:   8391        MOVL         XAR5, *+XAR1[AR0]
     342      iq = _IQmpy(
    008aa9:   88A4        MOVZ         AR6, @AR4
    008aaa:   E2AF0024    MOV32        R0H, @0x24, UNCF
     337      float_t ovcThresholdA_neg = -m_ovcThresholdA;
    008aac:   E2AF0426    MOV32        R4H, @0x26, UNCF
     341      m_halHandle->timerHandle[0]->TCR |= (uint16_t)TIMER_TCR_TRB_BITS;
    008aae:   1AE50020    OR           *+XAR5[4], #0x0020
     342      iq = _IQmpy(
    008ab0:   767F5997    LCR          FS$$TOFD
    008ab2:   5CAD        MOVZ         AR4, @SP
    008ab3:   88AD        MOVZ         AR6, @SP
    008ab4:   8F7F5CE8    MOVL         XAR5, #0x3f5ce8
    008ab6:   DC8C        SUBB         XAR4, #12
    008ab7:   DE88        SUBB         XAR6, #8
    008ab8:   5CA4        MOVZ         AR4, @AR4
    008ab9:   88A6        MOVZ         AR6, @AR6
    008aba:   767F52B6    LCR          FD$$MPY
    008abc:   5CAD        MOVZ         AR4, @SP
    008abd:   DC88        SUBB         XAR4, #8
    008abe:   5CA4        MOVZ         AR4, @AR4
    008abf:   767F5902    LCR          FD$$TOL
    008ac1:   761F0240    MOVW         DP, #0x240
    008ac3:   1EA6        MOVL         @XAR6, ACC
    008ac4:   02B4        MOVB         ACC, #180
    008ac5:   0714        ADDL         ACC, @0x14
    008ac6:   8AA9        MOVL         XAR4, @ACC
     346      g_dbgIsrExecTimeCnt = 0xFFFFFFFF - m_halHandle->timerHandle[0]->TIM;
    008ac7:   D07E        MOVB         XAR0, #0x7e
     342      iq = _IQmpy(
    008ac8:   87C4        MOVL         XT, *+XAR4[0]
    008ac9:   560500A6    IMPYL        P, XT, @XAR6
    008acb:   566300A6    QMPYL        ACC, XT, @XAR6
     346      g_dbgIsrExecTimeCnt = 0xFFFFFFFF - m_halHandle->timerHandle[0]->TIM;
    008acd:   8A91        MOVL         XAR4, *+XAR1[AR0]
     342      iq = _IQmpy(
    008ace:   56A7        LSL64        ACC:P, 8
    008acf:   1EA6        MOVL         @XAR6, ACC
     346      g_dbgIsrExecTimeCnt = 0xFFFFFFFF - m_halHandle->timerHandle[0]->TIM;
    008ad0:   0200        MOVB         ACC, #0
    008ad1:   1901        SUBB         ACC, #1
    008ad2:   03C4        SUBL         ACC, *+XAR4[0]
    008ad3:   1E3E        MOVL         @0x3e, ACC
    008ad4:   06A6        MOVL         ACC, @XAR6
     348      iq_A = _IQ24toF(iq);
    008ad5:   764084C8    LCR          $..\src\IQNtoF_fpu32.asm:118:261$

    Q2. Check why function HAL_readAdcData cannot be inlined in the motor control ISR even if #pragam FUNC_ALWAYS_INLINE(HAL_readAdcData) is used and compiler optimization level is set to 2?

    I also measured with timer0 the execution time of function STPOSCONV_run and STVELCTL_run while the SpinTAC is OFF (RES = 0, ENB = 0) and compared the measurements with the ones in Table 8-23 of InstaSPIN User's Guide.

    According to the user guide:

    • STVELCTL_run should execute in a maximum of 158 cycles while OFF
    • STPOSCONV_run should execute in a maximum of 110 cycles while OFF

    In my case:

    • STVELCTL_run executes in 193 cycles while OFF
    • STPOSCONV_run executes in 319 cycles while OFF

    Q3. Why are those functions executed so slowly compared to the values in the User's Guide (STPOSCONV_run is about 3 times slower)? In my case, those functions are running from RAM.

    Q4. We are using the function CTRL_setSpd_ref_krpm outside the motor control ISR as it is done in the labs. There is a probability that the motor control ISR triggers while this function is being executed by the background code: in other words, spd_ref variable could be corrupted and used in the motor control ISR leading to a potential misbehavior.
    How can we protect the access to this function? Why is it not protected in the labs?

    Q5. We need to share variables between the motor control ISR which has the highest priority and low priority interrupt. In the low priority interrupt which nests motor control ISR, is it safe to disable global interrupts while accessing shared variables as follows if we make sure that variables access are as atomic as possible? Or is there a better way to avoid reading potentially "corrupted" variables in the low priority interrupt?

    interrupt void
    lowPriorityInterrupt (void)
    {
      int16_t speed;
      uint32_t position;
      float_t speedRef;
    
      // Nest higher priority interrupt (INT1.1).
      IER |= 0x0001;
      IER &= 0x0001;
      asm(" NOP");
      EINT;
    
      //...
      
      // getMotSpeed() is inline and returns a variable set by higher priority ISR (INT1.1).
      DINT
      speed = getMotSpeed();
      EINT
    
      //...
    
      // getMotPosition() is inline and returns a variable set by higher priority ISR (INT1.1).
      DINT
      position = getMotPosition();
      EINT
    
      // Compute new speed reference.
      speedRef = ...;
    
      // Apply speedRef safely to the FOC controller executed in the higher priority ISR (INT1.1).
      DINT
      CTRL_setSpd_ref_krpm(...);
      EINT
    
      // exit low priority interrupt
      PIE_clearInt(...);
      DINT
    }

  • Q1. What type is m_iqFullScaleCurrent? A variable? or a constant? The _IQ() will take a lot of CPU cycles if the m_iqFullScaleCurrent is a variable.

    Q2. The HAL_readAdcData can be embedded into the motor control ISR if using the inline definition in the example lab of motorWare. Maybe, there are some configuration are not right in your project.

    Q3. The executing time in User's guide is based on using SpinTAC.lib with fixed point IQMath library, we don't have the benchmarks for SpinTAC_fpu32.lib which still needs to use the fixed point IQMath library.

    You might use the SpinTAC.lib with fixed point IQMath library if there are not too many floating-point operations in your project.

    Q4. The frequency of the speed loop is far lower than the current loop, so it should be fine for InstaSPIN-FOC if this variable is updated in background loop. You can execute this function in ISR if you use the spinTAC.

    Q5. You might enable nesting interrupt after these variables are updated. 

  • Q1. What type is m_iqFullScaleCurrent? A variable? or a constant? The _IQ() will take a lot of CPU cycles if the m_iqFullScaleCurrent is a variable.

    Yes, this is a floating point variable (static float_t m_iqFullScaleCurrent).

    Q2. The HAL_readAdcData can be embedded into the motor control ISR if using the inline definition in the example lab of motorWare. Maybe, there are some configuration are not right in your project.

    The project has been shared with you so that you can check on your side.

    Q3. The executing time in User's guide is based on using SpinTAC.lib with fixed point IQMath library, we don't have the benchmarks for SpinTAC_fpu32.lib which still needs to use the fixed point IQMath library. You might use the SpinTAC.lib with fixed point IQMath library if there are not too many floating-point operations in your project.

    SDW_Q1: For my understanding, if I enable the FPU32 support (--float_support=fpu32), can I use a mix of FPU32 and non-FPU32 libraries?

    For example, can I use:

    • rts2800_fpu32.lib
    • IQmath.lib
    • SpinTAC.lib

    As I understand, as soon as the FPU32 is enabled, we need to use FPU32 libraries. But maybe I am wrong.

    Q4. The frequency of the speed loop is far lower than the current loop, so it should be fine for InstaSPIN-FOC if this variable is updated in background loop. You can execute this function in ISR if you use the spinTAC.

    Maybe my question was not clear enough.

    The function to set the speed reference used by the SpinTAC Velocity Controller (which runs in the motor control ISR) is the following:

    void CTRL_setSpd_ref_krpm(CTRL_Handle handle,const _iq spd_ref_krpm)
    {
      CTRL_Obj *obj = (CTRL_Obj *)handle;
    
      _iq krpm_to_pu_sf = EST_get_krpm_to_pu_sf(obj->estHandle);
    
      _iq spd_ref_pu = _IQmpy(spd_ref_krpm,krpm_to_pu_sf);
    
      obj->spd_ref = spd_ref_pu;
    
      return;
    } // end of CTRL_setSpd_ref_krpm() function

    Since this function run in the background code, it could be a situation where the motor control ISR occurs during instruction obj->spd_ref = spd_ref_pu which could potentially corrupt spd_ref (this variable is used by the SpinTAC Velocity Controller).

    SDW_Q2: Am I right?

    SDW_Q3: How can I protect this access?

    Q5. You might enable nesting interrupt after these variables are updated. 

    SDW_Q4: You mean that, before each EINT, I need to write this instructions, right?

    IER |= 0x0001;
    IER &= 0x0001;
    asm(" NOP");
    According to the TMS320 reference manual, I thought that DINT/EINT only disables/enables global interrupts and does not affect IER register. 
  • Q1: Yes, you can only use _fpu32.lib if you enable the FPU32 support (--float_support=fpu32), otherwise, you need to use the non-fpu32 library.

    Q2: The data/pointer type of the arguments of the function must be the same in its definition and calling code. It's not better to use the "volatile" variables as the arguments.  Maybe the static and volatile definitions are necessary for almost all variables in a project.

    Q3. Executing obj->spd_ref = spd_ref_pu just needs one CPU cycle if the variable is 32-bit. And the SpinTAC Velocity Controller doesn't use the reference value of obj->spd_ref directly, which uses the value from the speed trajectory (ctrlObj->trajHandle_spd). Of course, the target value of the speed trajectory is the obj->spd_ref.

    Q5. Maybe, you don't need to enable nesting interrupt immediately, which depends on the control logic you want. I don't think you need to add the EINT/DINT for theses code to read/write the variables if these variables are 32-bit and are defined in a struct object. 

  • Any updates?  It's been a week since we heard from you, so I am assuming you no longer need clarification for your question that will be marking this thread as closed. You can reply with a post or create a new thread if you have any further questions on this topic. Thanks.

     

  • So, if I summarize, writing 32-bit variables should be atomic - 1 CPU cycle - (as described in C2000 C28x Optimization Guide, Section 5.3).

    Q1: Is this the same for reading a 32-bit variable? Is it atomic?

    Q2: How can I ensure in assembly code that the access is atomic? Do you have any example?

  • Q1: Yes.

    Q2: You have to check the related assembly instructions or codes to ensure that. Or you might use EINT&DINT if there are not too many variables for reading/writing and you don't want to check it.