Sporadic errors when timer captures

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
JoNe_4268451
Level 2
Level 2
First like received First like given

I re-post my question from  "Software Forums > PSoC Creator & Designer SoftwareDiscusiones"

Hello, I'm doing a proyect where I have to measure the angular speed of a BLDC motor. It has hall sensors, so I measure the electrical frequency through them, then I calculate the rotary speed knowing the number of poles of the motor. But this is not my problem. I measure the electrical frequency using a timer component, which is continuosly running, when it does a capture it means an electrical turn is achieved, so I only have to calculate the difference between two consecutive captures.

The following image shows the blocks that I'm using:

bloques.png

The next image shows how I've configured the timer:

conftimer.png

Then, an interrupt occurs when the timer gets a capture or finishs a period (on TC), in the code, I have to differentiate the two cases. In the first case, I have to store the value of the capture if it is the first time, or (if it isn't the first capture) calculate the "delay" between the last capture value and get a new value of angular speed. In the second option, I have to take into account that the timer has finished a period, so I increment a variable called "n_periodos" which measure the number of timer periods between two consecutive captures, the following image could clear up this method:

w_real.png

T0 is the last capture, T1 is the current capture, when it uses the value of actual T1, it is stored in T0 until the next capture.

w_real_diagrama.png

  1. /************************************* SPEED MEASUREMENT ************************************/ 
  2.  
  3. CY_ISR(ISR_SPEED_MEASURE_HANDLER)  
  4.     /*=================================================================================
  5.     *                       Averiguar causa de la interrupción
  6.     *                       Figure out the interrupt origin
  7.     =================================================================================*/ 
  8.      
  9.      
  10.     status_register = Timer_speed_ReadStatusRegister();     //Se lee el registro y se limpia la interrupción 
  11.     //Read the status register, and clear the interrupt 
  12.      
  13.  
  14.     /*============================== INTERRUPCIÓN DEBIDA A TC =========================================
  15.      *                               INTERRUPT DUE TO TC
  16.      * Si la interrupción es porque ha llegado al final de la cuenta, y además el motor está en marcha
  17.      * de esta forma evitamos que el timer cuente cuando esté el motor parado y la variable se desborde
  18.      ================================================================================================*/ 
  19.      
  20.     if ((status_register & Timer_speed_STATUS_TC_INT_MASK) && SYSTEM_STATE.run){ 
  21.         n_periodos++;                                   //Incrementamos variable que almacena el número de períodos transcurridos 
  22.         //Variable which store the number of periods 
  23.     } 
  24.      
  25.      
  26.     /*========================== INTERRUPCIÓN DEBIDA A CAPTURA ======================================*/ 
  27.     /*                              INTERRUPT DUE TO CAPTURE    */ 
  28.      
  29.     if ((status_register & Timer_speed_STATUS_CAPTURE_INT_MASK) && SYSTEM_STATE.run){ 
  30.         
  31.         if (first_turn){                                /* Es la primera vez */ 
  32.             n_periodos = 0;                             //Reseteamos cuenta de los períodos 
  33.             first_turn = FALSE;                         //Cambiamos variable para mostrar que la próxima vez ya no será la primera 
  34.             T0 = Timer_speed_ReadCapture();             //Guardamos la captura, está en n*bits 
  35.              
  36.         }else if (!first_turn){                                             /* No es la primera vez */ 
  37.             T1 = Timer_speed_ReadCapture();                                 //Almacenamos el valor de T1   
  38.             delay = (T0+n_periodos*TIMER_SPD_PERIOD-T1);                    //Calculamos el nº de ciclos ocurridos 
  39.             T0 = T1;                                                        //Actualizamos T0  
  40.             n_periodos = 0;                                                 //Limpiamos variable que cuenta los períodos almacenados        
  41.             w_real = 60/(MOTOR.NPolePairs*delay*CLCK_SPD_PERIOD*1e-9);      //Calculate the angular speed 
  42.         } 
  43.          
  44.     } 
  45.      
  46. }

Well, after this vast explanation, finally I can present my problem. All looks work propertly, but sometimes, the timer looks like skip a capture, then the time measured is double, this produces an error in the velocity, showing the half of the real. The next images (get from the bridge control panel) show this errors:

errores1.png errores2.png

The high frequency noise is easily removed with a low pass filter, but I can't eliminate these sporadic errors. If I decrease the frequency of the clock connected to the timer, these errors are more frequently. For example, with a "speed_clock = 1kHz" I get the following result:

errores3.png errores3_1.png

And if I increase the frequency of the clock, the errors also are more frequently. I don't know why these errors are produced, I suspect like the timer omit one capture sometimes, because it show exactly the half of the real velocity. Somebody could help me to find a solution?

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
Swathi
Moderator
Moderator
Moderator
25 replies posted 25 sign-ins 10 solutions authored

Hello JoNe_4268451

When the function Timer_speed_ReadStatusRegister() is executed, it reads the status register and clears all pending interrupts. So, if in case, the capture interrupt and the TC interrupt occurs at the same time, then it is possible that the function Timer_speed_ReadStatusRegister() clears the pending capture interrupt while clearing the TC interrupt. This might be the reason for missing some capture interrupts.

The TCPWM timer can be used instead. The TCPWM timer has APIs to clear the interrupts in specific. Please refer the attached youtube links and the example project on using TCPWM Timer. Let me know if it works.

Cypress Academy: PSoC 101- Lesson 7: Timer, Counter and PWM Component - YouTube

Cypress Academy: PSoC 101- Lesson 9: Timer - YouTube

Regards,

Swathi

View solution in original post

9 Replies
lock attach
Attachments are accessible only for community members.
Swathi
Moderator
Moderator
Moderator
25 replies posted 25 sign-ins 10 solutions authored

Hello JoNe_4268451

When the function Timer_speed_ReadStatusRegister() is executed, it reads the status register and clears all pending interrupts. So, if in case, the capture interrupt and the TC interrupt occurs at the same time, then it is possible that the function Timer_speed_ReadStatusRegister() clears the pending capture interrupt while clearing the TC interrupt. This might be the reason for missing some capture interrupts.

The TCPWM timer can be used instead. The TCPWM timer has APIs to clear the interrupts in specific. Please refer the attached youtube links and the example project on using TCPWM Timer. Let me know if it works.

Cypress Academy: PSoC 101- Lesson 7: Timer, Counter and PWM Component - YouTube

Cypress Academy: PSoC 101- Lesson 9: Timer - YouTube

Regards,

Swathi

Hi!

Thanks a lot, I've changed my proyect to use the block TCPWM configured as a timer and now this sporadic errors have disapeared, but I have a new problem, after a while running, the program BCP freezes, and also the PSoC and the shield that I'm using (CY8CKIT-042 PSoC 4 pionner kit and CY8CKIT-037 PSoC 4 motor control evaluation kit) and I can not stop the motor by pressing the buttom, like in a correct running. It looks like the program gets block. This is the new code:

CY_ISR(ISR_SPEED_MEASURE_HANDLER)

{

    /* Hay que averiguar por qué se ha dado la interrupción */

   

    /* Problema -> si leemos el registro se borra, entonces lo vamos a almacenar        *

     * en una variable intermedia de 8 bits para que, aunque se borre, podemos comparar *

     * su valor en el segundo if                                                        *

     */

   

    uint32 Interrupt_source;

    uint16 a = 950;                                         //Filtro, fix point 2^10, cero cercano a la circunf unidad

   

    Interrupt_source = Timer_speed_GetInterruptSourceMasked();  

   

    /*============================== INTERRUPCIÓN DEBIDA A TC =========================================

     * Si la interrupción es porque ha llegado al final de la cuenta, y además el motor está en marcha

     * de esta forma evitamos que el timer cuente cuando esté el motor parado y la variable se desborde

     ================================================================================================*/

   

    if (Interrupt_source == Timer_speed_INTR_MASK_TC)

    {

        Timer_speed_ClearInterrupt(Timer_speed_INTR_MASK_TC); //Limpiamos interrupción debida a TC

        if (SYSTEM_STATE.run)

        {

            n_periodos++;                                   //Incrementamos variable que almacena el número de períodos transcurridos, sólo si el motor está en marcha

        }

    }

   

   

    /*========================== INTERRUPCIÓN DEBIDA A CAPTURA ======================================*/

   

    if (Interrupt_source == Timer_speed_INTR_MASK_CC_MATCH){

      

        Timer_speed_ClearInterrupt(Timer_speed_INTR_MASK_CC_MATCH); //Limpiamos interrupción debida a captura

                   

        if (first_turn){                                /* Es la primera vez */

            T0 = Timer_speed_ReadCapture();             //Guardamos la captura, está en n*bits

            n_periodos = 0;                             //Reseteamos cuenta de los períodos

            first_turn = FALSE;                         //Cambiamos variable para mostrar que la próxima vez ya no será la primera

        }else if (!first_turn){                                             /* No es la primera vez */

            T1 = Timer_speed_ReadCapture();

            delay = (T0+n_periodos*TIMER_SPD_PERIOD-T1);                    //Calculamos el nº de ciclos ocurridos

            n_periodos = 0;                                                 //Limpiamos variable que cuenta los períodos almacenados

            T0 = T1;                                //Actualizamos T0

            //w_real = 60/(MOTOR.NPolePairs*delay*CLCK_SPD_PERIOD*1e-9);    //Vel obtenida [rpm]

            w_real[0] = a*w_real[1] + (1024-a)*60/(MOTOR.NPolePairs*delay*CLCK_SPD_PERIOD*1e-9);   //Filtro paso baja y cálculo de la velocidad real de rotación, mecánica (rpm)

            w_real[0] = w_real[0] >> 10;                                    //Dividimos por 2^10, ya que 'a' está multiplicado por 2^10

            w_real[1] = w_real[0];                                          //Actualizamos valor pasado para el filtro

        }

       

    }

   

}

I have added a filter, but it doesn't interfere because I have tested without it and I get the same result.

Anotación 2020-07-28 182745.png Anotación 2020-07-28 182729.png

Regards,

Jose Antonio

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Since CC and TC can happen at the same time,

how about changing the if condition like below?

> if (Interrupt_source == Timer_speed_INTR_MASK_TC)

< if (Interrupt_source & Timer_speed_INTR_MASK_TC)

> if (Interrupt_source == Timer_speed_INTR_MASK_CC_MATCH){ 

< if (Interrupt_source & Timer_speed_INTR_MASK_CC_MATCH){ 

moto

0 Likes
Swathi
Moderator
Moderator
Moderator
25 replies posted 25 sign-ins 10 solutions authored

Hello JoNe_4268451

I need a few more details about the issue.

1) Does the status LED on the motor control evaluation kit blink while the motor is running? If yes, how many times does it blink?

2) Did you make any software or hardware changes right before this problem occurred?

3) Does it happen every time you run the motor?

Regards,

Swathi

lock attach
Attachments are accessible only for community members.

Hello, the LED is configured to remain ON while the motor is running, and another red LED blinks with different frequencies depend on the error that ocurrs, the following code shows the fuction which set the status of the LED, this fuction is called in the main loop:

void update_LED_status(void)

{

    if (SYSTEM_STATE.run)           //Motor en marcha

    {

      Pin_LED_Green_Write(0);            //Encendemos LED verde

      Pin_LED_Red_Write(1);             //Apagamos LED rojo

    }

    if (!SYSTEM_STATE.run)          //Motor parado

    {

      Pin_LED_Green_Write(1);            //Apagamos LEDs

      Pin_LED_Red_Write(1);

    }

    if (SYSTEM_STATE.error)         //Hay un error, LED rojo intermitente

    {

      int16 ts= check_errors()*100;

      Pin_LED_Green_Write(1);

      Pin_LED_Red_Write(~Pin_LED_Red_Read());

      CyDelay(ts);

      Pin_LED_Red_Write(~Pin_LED_Red_Read());

      CyDelay(ts);

    }

}

With regard to the changes, I've only changed the block "timer" to "TCPWM" configured as Timer counter. And the software related with the speed measurement. I would say that when this strange error happens the motor continues running, and the LED lights, but I can't stop the motor with the button, nor control the velocity through the potentiometer, it looks like the system stucks, and I have to press the "reset button". This doesn't happen every time I run the motor, It happens when the motor has been running for a while, even after I've stopped and run again the motor several times.

This is the code and blocks related with the button that controls the run/stop of the motor:

/***** BOTÓN SW2 *****/

CY_ISR(RUN_STOP){

   

    if(!SYSTEM_STATE.error){

        SYSTEM_STATE.run = !SYSTEM_STATE.run; //Al pulsarlo cambiamos el estado del sistema, siempre y cuando no haya errores

        //UART_UartPutString("Button press");

     }

    //La detección de un error parará el motor hasta que este no desaparezca. No se puede poner en marcha el motor hasta que no haya errores.

}

It is only an interrupt which changes the state of the system.

pastedImage_1.png

And this is all that I consider interesting. I suspect the problem might be related with the priority of the interrupts, but actually I don't have idea

I attach the full program, and I also give you an url to my project in case it can be more comfortable to you have a look by this mean:

https://gitlab.com/Josantonio/tfg/-/tree/master/CY8CKIT-037_Documentacion/CONTROLBRUSHLESS/Sensored/...

I'm so grateful for your patience and dedication to my problem,

Jose Antonio.

0 Likes
Swathi
Moderator
Moderator
Moderator
25 replies posted 25 sign-ins 10 solutions authored

Hello,

The motor state changes only if (!SYSTEM_STATE.error) is 1, i.e only if there is no error.

pastedImage_1.png

So, let's see what causes the error!

The function check_errors() is called in the main function's for(;;) loop.

pastedImage_2.png

There are two causes for the error.

1) The voltage 'vin' on channel 1 of ADC_SAR is above or below the threshold: The function ADC_SAR_CountsTo_mVolts(1,vin_bits) returns the voltage at channel 1 of ADC_SAR in milliVolts. This is assigned to the variable 'vin'. If this voltage is not in the threshold limit, then there is an error. In your project, the threshold limits are 15V and 27V.

pastedImage_4.png

2) Error in the hall sensor reading: The function Hall_Error_Read() reads the Hall_Error status register. When the hall sensor values are either 000 or 111 then the output of the LUT, 'out0' is 1. Thus, the status register reads 1. There is an error when the function Hall_Error_Read() returns 1.

pastedImage_6.png

Please check for the above-mentioned errors.

Regards,

Swathi

0 Likes

Hello,

There was a confusion because you thought that I don't understand the code, but actually the code is mine, I created it (so I'm not sure it is correct)

It looks like the error that occurs doesn't have to do with the voltage nor the hall sensors, because the variable SYSTEM_STATE.error isn't 1, in adittion the variable SYSTEM_STATE.run continue being 1 while this strange error happens. The motor continue running, it doesn't stop, but the system get freeze in this state and stop sending data to the PC.

Regards,

Jose Antonio

0 Likes
Swathi
Moderator
Moderator
Moderator
25 replies posted 25 sign-ins 10 solutions authored

Hi,

I understood that there are no errors in the hardware. So, to find the software bug that's causing the malfunction, please use the 'debug' tool in the PSoC Creator. Insert breakpoints in the code. Please observe which part of the code is in execution right before or when the system is frozen. You can use 'Step Into' to get into the function definition while debugging.

Regards,

Swathi

0 Likes

Hi!

I'm going to do that, and if I find more problems I'll create another question, I think you answered me respect to the main problem. Thanks a lot for your advice and help to solve it.

Regards,

José Antonio

0 Likes