- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I re-post my question from "Software Forums > PSoC Creator & Designer Software > Discusiones"
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:
The next image shows how I've configured the timer:
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:
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.
- /************************************* SPEED MEASUREMENT ************************************/
- CY_ISR(ISR_SPEED_MEASURE_HANDLER)
- {
- /*=================================================================================
- * Averiguar causa de la interrupción
- * Figure out the interrupt origin
- =================================================================================*/
- status_register = Timer_speed_ReadStatusRegister(); //Se lee el registro y se limpia la interrupción
- //Read the status register, and clear the interrupt
- /*============================== INTERRUPCIÓN DEBIDA A TC =========================================
- * INTERRUPT DUE TO 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 ((status_register & Timer_speed_STATUS_TC_INT_MASK) && SYSTEM_STATE.run){
- n_periodos++; //Incrementamos variable que almacena el número de períodos transcurridos
- //Variable which store the number of periods
- }
- /*========================== INTERRUPCIÓN DEBIDA A CAPTURA ======================================*/
- /* INTERRUPT DUE TO CAPTURE */
- if ((status_register & Timer_speed_STATUS_CAPTURE_INT_MASK) && SYSTEM_STATE.run){
- if (first_turn){ /* Es la primera vez */
- 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
- T0 = Timer_speed_ReadCapture(); //Guardamos la captura, está en n*bits
- }else if (!first_turn){ /* No es la primera vez */
- T1 = Timer_speed_ReadCapture(); //Almacenamos el valor de T1
- delay = (T0+n_periodos*TIMER_SPD_PERIOD-T1); //Calculamos el nº de ciclos ocurridos
- T0 = T1; //Actualizamos T0
- n_periodos = 0; //Limpiamos variable que cuenta los períodos almacenados
- w_real = 60/(MOTOR.NPolePairs*delay*CLCK_SPD_PERIOD*1e-9); //Calculate the angular speed
- }
- }
- }
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:
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:
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?
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Regards,
Jose Antonio
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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:
I'm so grateful for your patience and dedication to my problem,
Jose Antonio.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
The motor state changes only if (!SYSTEM_STATE.error) is 1, i.e only if there is no error.
So, let's see what causes the error!
The function check_errors() is called in the main function's for(;;) loop.
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.
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.
Please check for the above-mentioned errors.
Regards,
Swathi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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