📜 ⬆️ ⬇️

Connecting STM32 to radio control equipment


It took me to realize the remote control of several DC motors.
Ready-made radio control kits are available in stores for various flying-flying toys and non-toys, and there is a desire to use just such a control.
The signals at the receiver output of such a set are pulses for controlling servos,
and the task is to measure the pulse duration of 0.8 ..2.3 ms in each of the six channels, spending as little as possible of the controller's resources.
The following describes how the measurement of the pulse duration from six channels is implemented using the features of the peripherals of the STM32 microcontrollers.


The iron on which the debugging was performed is the HobbyKing HK-T6A radio control equipment and the STM32F100C8T controller.

At the receiver output, we have the following signals:

')
The obvious solution is to run 6 timers and measure each channel with a separate timer.
On the leading edge of the pulse, reset the timer, start the countdown. On the falling edge we see how much the timer counted from the moment of reset, this will be the duration of the pulse.

To reduce the number of involved timers, we try to start several channels on one timer, but so that there is as little software processing as possible.

We will use the timer mode to work with the Hall sensor.
Brushless motors sometimes have three hall sensors installed with offset as the rotor position sensor. The picture below gives a visual image of how this happens.


To process the hallless brushless motor sensor, some timers in the STM32 can be configured in such a way that:
- on the leading edge of any of the three inputs CC1, CC2, CC3, the timer is reset,
- on the falling edge, on any of these inputs, in the capture compare CCMR1 register, the value of the timer counter is latched - in fact, the pulse duration.

Thus, in one register, we consistently have the values ​​of the pulse duration over three channels.

Programmatically, you can somehow divide these values, but it is easier to leave only two channels ch2 and ch3, the values ​​from them will be latched in the CCR2 and CCR3 registers, and the timer will be reset on the leading edge on any of these channels.
Pin, which is assigned to the input ch1, configure the output, so as not to interfere with unused input.

In the figure below: the red arrow shows the way of the timer reset signal, the green arrows show the way of the time signal value snapping.


As a result, for reading 6 channels we will use 3 timers , and without additional software tweaks, in the registers of CCR timers will have the required values.

A little surprise.
When all this has already been implemented, but I once again forgot the pinout of the receiver output, I came across an interesting picture while searching on the Internet.

Taken from here

Having studied the Internet, I made a discovery for myself.
It turned out that the input used to power and bind the receiver to the transmitter, the output has a signal that combines all 6 outputs.

Only it is necessary to measure not the duration of the pulses, but the time between the pulses.


It is called PPM and is widely used to connect radio control equipment to a computer as a joystick for a simulator (via an adapter, of course).
There are different versions of adapters, and even based on a cheap USBasp programmer.

If there is a PPM output, the task is simplified: to measure the time between six consecutive pulses, the beginning of the measurement will be a long enough pause.
On the leading edge of the pulse, we save the timer value and immediately reset the timer.
When the pulses do not arrive, an overflow interrupt occurs on the timer, at this moment we are preparing to receive the pulses, adjusting the DMA to add 7 values ​​to an array.
The first pulse synchronizes the measurement process, the value of the timer at this moment does not interest us, the next 6 values ​​will store the time between pulses.
At each subsequent pulse, the timer value is latched, the timer is reset, the latched DMA value is stored in the array.

We display all the measurement results in the first and second way in the UART, we see what works, reacts to the deviations of the handles.


At a deviation of handles of value change in the range of 3200..5700 units
Only here the values ​​measured by the first and second method are different, but the logic analyzer shows the same thing, so these are the hardware features.

Rakes, which managed to attack in the development process.
The behavior of the program looks like this - when the power is turned on, the program works, but when working with the debugger, it crashes to HardFault_Handler. The programmer is connected via the SWD line (SWDIO, SWIO, GND).

It turned out:
- when resetting by the programmer, the TIM1-> SR timer status register is not cleared, the interrupt request flags remain there,
- during timer initialization, an interrupt from TIM1 is enabled,
- an interruption for TIM1 and TIM15 is common, and when we turn to the htim15 structure, it is not yet defined, so we fly away to HardFault_Handler.

Here is the interrupt procedure
void TIM1_BRK_TIM15_IRQHandler (void)
{
/ * USER CODE BEGIN TIM1_BRK_TIM15_IRQn 0 * /

/ * USER CODE END TIM1_BRK_TIM15_IRQn 0 * /
HAL_TIM_IRQHandler (& htim1);
HAL_TIM_IRQHandler (& htim15);
/ * USER CODE BEGIN TIM1_BRK_TIM15_IRQn 1 * /

/ * USER CODE END TIM1_BRK_TIM15_IRQn 1 * /
}

All this code was generated by Cub automatically, so I had to add the line htim15.Instance = TIM15 before all the initialization.

Applications:
1. Project for Cube
2. Data of 6 channels + PPM saved with Logic-U logic analyzer USB

Source: https://habr.com/ru/post/273879/


All Articles