cancel
Showing results for 
Search instead for 
Did you mean: 

How to control delays in non-blocking ways?

hchienti
Associate II

I am using H563ZI to develop a motor control project. I have several motors in my project. Motor control commands will be sent to the board with ethernet cable(I have finished this part). Once the board get the command, it should then make the motor with given index run for given period of time, and then stop the motor. I created a function that toggles the GPIO pins and calls HAL_Delay to control the period. After the delay, the function then toggle the GPIO pins back. The problem is that when one motor is in the HAL_Delay, the whole process is blocked. Is there any way that I can turn on several motors and stop them after their given period individually? For example, if [200, 300] is given, motor0 and motor1 should be turned on at (at least nearly) the same time. Motor0 should be turned off after 200ms, and motor1 should be turned off after 300ms.

I guess one idea is to use ThreadX, which I also used for the Ethernet part (https://github.com/STMicroelectronics/STM32CubeH5/tree/main/Projects/NUCLEO-H563ZI/Applications/NetXDuo/Nx_UDP_Echo_Client). However, I have at least 14 motors, should I create a thread for each motor? Or is there a better way to implement this?

Here is my function to control the motors now, which leads to blocking issue.

 

void stopMotor(int motor_idx) {
HAL_GPIO_WritePin(motors[motor_idx].IN1.GPIO_Port,
motors[motor_idx].IN1.GPIO_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(motors[motor_idx].IN2.GPIO_Port,
motors[motor_idx].IN2.GPIO_Pin, GPIO_PIN_RESET);
}
void controlMotor(int motor_idx, uint32_t duration, int direction) {
GPIO_PinState in1_state = direction == 0 ? GPIO_PIN_RESET : GPIO_PIN_SET;
GPIO_PinState in2_state = direction == 0 ? GPIO_PIN_SET : GPIO_PIN_RESET;
HAL_GPIO_WritePin(motors[motor_idx].IN1.GPIO_Port,
motors[motor_idx].IN1.GPIO_Pin, in1_state);
HAL_GPIO_WritePin(motors[motor_idx].IN2.GPIO_Port,
motors[motor_idx].IN2.GPIO_Pin, in2_state);
HAL_Delay(duration);
stopMotor(motor_idx);
}
1 ACCEPTED SOLUTION

Accepted Solutions
LCE
Principal

Why so complicated?

Add a counter variable to your motor struct, and use an STM timer set to required resolution, with interrupt.

When start command is received, start the motors and set .counter = time.

In timer interrupt: for( i++ until < number of motors ) if( motor[i].counter ) { motor[i].counter--; if( 0 == motor[i].counter ) set motor[i].stopflag }

In main (or some OS thread): for( i++ until < number of motors ) if motor[i].stopflag then stop motor

 

Great C code! ;)

View solution in original post

7 REPLIES 7

>>Or is there a better way to implement this?

Make a queued list of things to change/manage with time stamps, and advance through it at every 1ms SysTick ?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
PGump.1
Senior III

Hi,

You could use OTP timers to control the motor(s)... Either in hardware, or firmware...

I hope that helps.

Kind regards
Pedro

 

 

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.

Say a linked list, with a ms target time, and a 32-bit vector one for Motor On events, and another for Motor Off events. Search list for existing events, and either insert a new one, in order, or tag the on/off motor flags.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi @Tesla DeLorean ,

Thanks for reply. This method sounds good. However, I guess this will tie the control to all motors together? For example, when [200, 600, 200] is executing, I can't control motor0 at 300 ms right? In the method of using different thread, I guess I can control any of them once it is not working at that time. Is there any reason that you suggest this method over threadX? For example, is 14 threads too large for the system?

Best regards

LCE
Principal

Why so complicated?

Add a counter variable to your motor struct, and use an STM timer set to required resolution, with interrupt.

When start command is received, start the motors and set .counter = time.

In timer interrupt: for( i++ until < number of motors ) if( motor[i].counter ) { motor[i].counter--; if( 0 == motor[i].counter ) set motor[i].stopflag }

In main (or some OS thread): for( i++ until < number of motors ) if motor[i].stopflag then stop motor

 

Great C code! ;)


@hchienti wrote:

I guess this will tie the control to all motors together?


Don't see why it should be?

Just have a motor identifier in your list entries?

Hi @LCE ,

Thanks for providing this cool idea. I just implemented it and the result is just what I needed!

Thanks a lot!