Add general- and UAPI documentation for the Linux Motion Control subsystem. Signed-off-by: David Jander <david@xxxxxxxxxxx> --- Documentation/motion/index.rst | 18 + Documentation/motion/motion-uapi.rst | 555 +++++++++++++++++++++++++++ Documentation/subsystem-apis.rst | 1 + 3 files changed, 574 insertions(+) create mode 100644 Documentation/motion/index.rst create mode 100644 Documentation/motion/motion-uapi.rst diff --git a/Documentation/motion/index.rst b/Documentation/motion/index.rst new file mode 100644 index 000000000000..eee1c180478d --- /dev/null +++ b/Documentation/motion/index.rst @@ -0,0 +1,18 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================== +Linux Motion Control Subsystem +============================== + +.. toctree:: + :maxdepth: 1 + + motion-uapi + motion-drivers + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/motion/motion-uapi.rst b/Documentation/motion/motion-uapi.rst new file mode 100644 index 000000000000..f57d62bcacb3 --- /dev/null +++ b/Documentation/motion/motion-uapi.rst @@ -0,0 +1,555 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +Linux Motion Control Subsystem UAPI +=================================== + +The User-space API for the Linux Motion Control (LMC) subsystem consists of +a device node ioctl() interface and driver-specific sysfs attributes. The +devnodes use dynamically allocated MAJOR numbers and are named /dev/motionX +by default, where X is the ordinal of the device in probe order starting at +zero. The entries in /sys/class/motion/... can be used to further identify +each device. + +If CONFIG_IIO is defined, then also a IIO trigger device is created, that +can be accessed via /sys/bus/iio/devices/iiotriggerX and the usual IIO API. + +Motion Control Background +========================= + +A motion controller device can control one or more actuators (motors), that +can move individually or synchronously. To accommodate for that, the API +has two distinct ways of specifying the actuator channel a specific function +applies to. Some structs take a single channel number as an unsigned integer, +while others apply to a set of channels represented in the form of a bitmask. +A "motion" in general can be any type of mechanical movement or displacement. +This can be carried out by any sort of motor or linear actuator. Types of +motors can be (but not limited to) brushed- or brushless DC motors, induction +motors, switched-reluctance motors, stepper motors, etc... +The mechanical movement can be coupled directly to a position sensor, such as +a linear encoder for example. Some actuators (such as stepper motors) can be +absolutely positioned without the need of a sensor. +A mechanical movement (motion) can be described by a (multi-dimensional-) +position and its two common time-derivatives, speed and acceleration. +Depending on the motion controller's capabilities, these can be specified in +more or less detail. For example a motor connected to a simple on-off switch +can only be conrolled at zero or maximum speed. If an encoder is present, +position control becomes possible. A stepper motor controller OTOH, can +often precisely control all three, position, speed and acceleration, and +sometimes even higher order time-derivatives, such as jerk. + +.. _motion-profiles: + +Motion profiles +=============== + +Some motion controllers have means of specifying a motion (or acceleration) +profile. This is generally represented by a curve of speed versus time. The +most common types of such a curve are triangular, trapezoidal, dual-slope and +S-curve (or an 8-point approximation thereof). +A triangular profile is in essence a special case of the trapezoidal profile, +where constant maximum speed is never reached. LMC supports the following 3 +types of motion profiles: + +1. Trapezoidal +-------------- + +A trapezoidal profile is comprised of 3 speed values: Start-, maximum- and +stop speed. 2 acceleration values determine the start and ending slopes of +the trapezoid. Start- and stop speed need not be zero, nor equal. Specific +constraints may depend on the underlying conroller, but often speed below +a certain value is hard to attain for example with a stepper motor controller +if the interval time between steps is limited. In addition to the 3 speed +and 2 acceleration values, a value for minimum constant speed time can also +be specified. This time value determines the minimum time the movement needs +to have a constant speed after acceleration, before deceleration begins. + +2. Dual-slope +------------- + +A dual-slope profile, is similar to a trapezoidal profile, but both the +acceleration and deceleration phase is split in two sections. The transition +point is determined by a 4th speed value which lies between max(Vs, Ve) +and Vmax, where Vs, Vmax and Ve are the trapezoidal profile values for +Start-, maximum- and stop speed respectively. Since there are two segments +to each acceleration phase, this profile has 4 acceleration values. + +3. S-curve (8-point) profile +---------------------------- + +An 8-point profile (approximation of an S-curve) takes the dual-slope profile +one step further by adding a second intermediate speed value, which results +in acceleration and deceleration phases split into 3 segments each. This +profile type thus has 5 speed values and 6 acceleration values. + +Units +===== + +The LMC subsystem measures all time values in nanoseconds, in the format +mot_time_t (signed 64-bit integer). This is similar to the current +imoplementation of ktime_t, so conversion to/from mot_time_t is simple. +Internally ktime_t is used, but since ktime_t cannot be interfaced to +user-space directly, the mot_time_t type is defined for use in the user- +space API, but it currently is equivalent to ktime_t. + +All position, speed and acceleration values are assumed in machine-units by +the kernel. +Machine-units are defined by the respective motion controller hardware. +For example for a stepper motor controller with 1/256 microstepping, +one unit of distance is equivalent to one microstep. Each driver can specify +scaling factors to convert units in user-space if needed. Since speed and +acceleration values have an implied time component, these conversion factors +also have an implied time conversion from machine-time units to nanoseconds. +These conversion factors are each specified by a rational number represented +by a numerator and a denominator. Both are unsigned 32bit integers. + +Machine units for position, speed and acceleration are signed 32-bit integers, +but have a type definition as pos_raw_t, speed_raw_t and accel_raw_t +respectively. + +Convention of signed position, speed and acceleration: +Movement of one channel is unidimensional, meaning position can be above or +below the origin (positive or negative respecively). Consequently, given +a positive position, a positive speed represents a movement further away +from the origin (position 0), while a negative speed value represents a +movement towards the origin. The opposite is valid when starting from a +negative position value. +Analogous to what speed does to position, is what acceletation does to speed: +Given positive speed, positive acceleration increments the speed, and given +"negative" speed, negative acceleration decrements the speed (increments its +absolute value). +For movement profiles, the convention is that profile (acceleration-, speed-) +values are strictly positive. The direction of movement is solely determined +by the relative position (i.e. "positive" or "negative" displacement). + + +IOCTL based interface description +================================= + +API capabilities interrogation +------------------------------ + +``ioctl(fd, MOT_IOCTL_APIVER, null)`` + Function return value is the LMC API version number, or -1 on error. + +``ioctl(fd, MOT_IOCTL_GET_CAPA, struct mot_capabilities *capa)`` + Returns a struct mot_capabilities filled in. + +Basic motion control +-------------------- + +``ioctl(fd, MOT_IOCTL_GET_STATUS, struct mot_status *st)`` + Takes a struct mot_status with the channel parameter filled in and + specifying the channel number for which to retrieve the status. + Returns the current speed and position (if supported) in the same + struct. + +``ioctl(fd, MOT_IOCTL_BASIC_RUN, struct mot_speed_duration *s)`` + Takes a struct mot_speed_duration with the channel number, the speed and + optionally either a non-zero value of duration or a non-zero value of + distance. Note that one of these two values *must* be zero, otherwise + an error is returned. If both are zero, then a movement is started + with speed abs(speed) and direction the sign of speed for an indefinite + amount of time. If duration is non-zero, then the movement is stopped + at most after duration (in nanoseconds). + +``ioctl(fd, MOT_IOCTL_BASIC_STOP, u32 chmsk)`` + Takes an unsigned 32-bit integer argument chmsk, which represents a bit-mask + of channels. All current movements of all specified channels are stopped at + once. + +Feedback control +---------------- + +``ioctl(fd, MOT_IOCTL_CONFIG_INPUT, struct mot_input *inp)`` + Takes a struct mot_input with an index number, a function value and a channel + bit-mask among other flags. This configures one of the internal or external + feedback inputs of the motion controller for a certain function to act on a + set of channels as specified by the chmask bit-mask. A common type of feedback + input for example are end-stop switches on a 3D printer. If the function + parameter is set to MOT_INP_FUNC_NONE (0) then the specified input is + deconfigured. + +Profile-based control +--------------------- + +``ioctl(fd, MOT_IOCTL_SET_PROFILE, struct mot_profile *p)`` + Adjust a motion profile for the specified slot index to the values supplied + by this struct. (MOT_MAX_PROFILES-1) is the highest accepted value for index. + The only values allowed for na (number of acceleration values) are 2, 4 or 6. + The only values allowed for nv (number of speed values) are 3, 4 or 5. A + specific driver can restrict these parameters even further. This is + communicated in the struct mot_capabilities data. + +``ioctl(fd, MOT_IOCTL_GET_PROFILE, struct mot_profile *p)`` + Takes the index from the provided struct mot_profile and returns a the same + struct with the profile values filled in for that index. Returns an erro if + the index does not point to a valid profile. + +``ioctl(fd, MOT_IOCTL_START, struct mot_start *s)`` + Takes a struct mot_start, that programs a motion to start immediately or + triggered by an event. The motion can be time-based if the duration parameter + is non-zero - in this case also the direction parameter is taken into + account - or distance-base. In the latter case the duration value must be + zero and in the former case, the distance value must be zero. The parameter + index specifies a motion profile to use for this movement. + +``ioctl(fd, MOT_IOCTL_START, struct mot_start *s)`` + Takes a struct mot_stop. This struct contains a channel mask parameter chmask, + which contains a bit-mask of all channels this command applis to. All motions + of selected channels are stopped or prepared to be stopped by an event, + following the deceleration path of the selected motion profile that started + each respective motion or immediately, depending on the function of the + trigger input that has been armed for each respective channel (if applicable). + +Unimplemented future functionality +---------------------------------- + +``ioctl(fd, MOT_IOCTL_TORQUE_LIMITS, struct mot_torque *t)`` + Analogous to motion profiles, torque limit curves can augment a motion profile + with a time-sectioned or position-sectioned profile of torque limit values. + Background for torque limit curves: In some cases, it is desired to limit the + torque (or force) of a movement depending on the position. For example when + hitting an end-stop. In the case of a sliding door for example, one might + require higher torque initially, while limiting torque during the reminder of + the movement, in order to detect stalls due to a person standing in the way + of the door without causing injuries. Torque control isn't always possible, + and sometimes only in a limited fashion. For example, on AC motors, the + controller could vary the gain of the V/f curve to reduce or increase the + stall or slip limit. Stepper- or BLDC motor could vary the run current limit, + or stall detect threshold. + +``ioctl(fd, MOT_IOCTL_VECTOR_START, struct mot_vector *v)`` + Takes a struct mot_vector, that defines a multi-channel coordinated multi- + dimensional linear movement along an n-dimensional space vector following a + motion profile and optional torque curve. The chmask bit-mask specifies the + channels that participate in this movement. The vector dist[] has the same + size as the number of bits set in chmask and specifies the nth coordinate + of the vector. This would be the prime application for controlling 3D + printers, where tight coordination of several axes is required. + +Constants used in the ioctl API +------------------------------- + +The following constants are used in different field of the structs provided +to or returned by the ioctl API: + +.. code-block:: C + + /* Trigger inputs and End Stop functions */ + enum { + MOT_INP_FUNC_NONE = 0, + MOT_INP_FUNC_STOP, + MOT_INP_FUNC_STOP_POS, + MOT_INP_FUNC_STOP_NEG, + MOT_INP_FUNC_DECEL, + MOT_INP_FUNC_DECEL_POS, + MOT_INP_FUNC_DECEL_NEG, + MOT_INP_FUNC_START, + MOT_INP_FUNC_SIGNAL, + MOT_INP_FUNC_LAST + }; + +These constants are used in for the field function of struct mot_input. +This field specicies the function that a specified trigger input or end-stop +should have on the selected channels. FUNC_STOP means immediately set the +speed to zero, not following an acceleration curve, whereas FUNC_DECEL means +stopping by folowwing the deceleration slope(s) specified in the motion +profile that started the motion. _NEG and _POS restrict the action of the +trigger to act on backwards (_NEG, into negative distance) or forwards (_POS, +into positive distance) motion. If this is specified and the controller +supports this, this will avoid a situation in which an actuator that has +two end-stops for example at each extreme of the actuation range will stop +a movement to "the left" when the "right" end-stop is accidentally triggered. +MOT_INP_FUNC_SIGNAL will only generate an event to user-space or the IIO +trigger and not affect the motion directly. + +.. code-block:: C + + /* Config trigger input edge */ + #define MOT_EDGE_RISING 0 + #define MOT_EDGE_FALLING 1 + +These constants are used for the edge parameter in ioctl structs. It specifies +the trigger input to be high-active (MOT_EDGE_RISING) or low-active +(MOT_EDGE_FALLING). + +.. code-block:: C + + /* Start/Stop conditions */ + enum { + MOT_WHEN_IMMEDIATE = 0, + MOT_WHEN_INT_TRIGGER, + MOT_WHEN_EXT_TRIGGER, + MOT_WHEN_NEXT, + MOT_WHEN_LAST + }; + +Each parameter called "when" in the ioctl structs can potentially take one +of the MOT_WHEN_xxx values. INT_TRIGGER will execute the corresponding action +on an internal trigger signal, while EXT_TRIGGER will execute the +corresponding action on an external trigger signal (GPIO specified in fwnode). +MOT_WHEN_NEXT makes it possible to prepare a new motion that will start when +the currently active motion ends. By listening to poll() events of type +MOT_EVENT_TARGET and then sending the next motion start command with +MOT_WHEN_NEXT, it is possible to produce an uninterrupted stream of +consecutive movements. In that case MOT_EVENT_TARGET correspondes to the +end of the preceding motion that ended when the current "next" motion is +started, freeing the slot for the new "next" motion after that. + +.. code-block:: C + + /* Event types */ + enum { + MOT_EVENT_NONE = 0, + MOT_EVENT_TARGET, + MOT_EVENT_STOP, + MOT_EVENT_INPUT, + MOT_EVENT_STALL, + MOT_EVENT_ERROR, + MOT_EVENT_LAST + }; + +These are constants for the event field of struct mot_event. See below for +a description of events ingeneral. The type of events reported to user space +are "target reached" (MOT_EVENT_TARGET), "stopped by internal trigger" +(MOT_EVENT_STOP), "external trigger" (MOT_EVENT_INPUT) or different fault +conditions (stall or generic error event). MOT_EVENT_STALL can be produced by +some motion controllers that can react to motor stalls in a natural way, for +example in the case of force-based obstacle- or end stop detection. + +.. code-block:: C + + #define MOT_DIRECTION_LEFT 0 + #define MOT_DIRECTION_RIGHT 1 + +These constants are used for specifying direction of movement. LEFT in this +case means decreasing position value, while RIGHT is increasing position +value. + +Structs used in the ioctl API +----------------------------- + +.. code-block:: C + + #define MOT_FEATURE_SPEED BIT(0) + #define MOT_FEATURE_ACCEL BIT(1) + #define MOT_FEATURE_ENCODER BIT(2) + #define MOT_FEATURE_PROFILE BIT(3) + #define MOT_FEATURE_VECTOR BIT(4) + + enum motion_device_type { + MOT_TYPE_DC_MOTOR, + MOT_TYPE_AC_MOTOR, + MOT_TYPE_STEPPER, + MOT_TYPE_BLDC, + MOT_TYPE_SRM, + MOT_TYPE_LINEAR, + MOT_TYPE_LAST + }; + + struct mot_capabilities { + __u32 features; + __u8 type; + __u8 num_channels; + __u8 num_int_triggers; + __u8 num_ext_triggers; + __u8 max_profiles; + __u8 max_vpoints; + __u8 max_apoints; + __u8 reserved1; + __u32 subdiv; + __u32 speed_conv_mul; + __u32 speed_conv_div; + __u32 accel_conv_mul; + __u32 accel_conv_div; + __u32 reserved2; + }; + +The field ``features`` is a bit-mask of MOT_FEATURE_XX flags. The feature +SPEED means that the motion controller supports adjustable speed. All but the +most simple (on/off switch) controllers will have this bit set. +ACCEL means that the motion controller supports specifying acceleration +values. Not that this is not sufficient to indicate that motion profiles can +be used. +ENCODER meaans that the motion controller has a built-in or fixed connected +position encoder. If this bit is set, the position values returned by +MOT_IOCTL_GET_STATUS can be assumed to be accurate. I.e. slip and/or skipped +steps are properly taken into account. +PROFILE means that the motion controller supports setting motion profiles. +How many profiles, and how many speed and/or acceleration values are supported +is inticated by the fields ``max_profiles``, ``max_vpoints`` and +``max_apoints``. +The field ``type`` can take any of the values MOT_TYPE_XX and is only +informative. The fields ``num_channels``, ``num_int_triggers`` and +``num_ext_triggers`` specify the supported number of channels, internal +triggers and configured external triggers respectively. +The field ``subdiv`` can have a different meaning, depending on the type of +motion controller. For example for stepper motors, this typically indicates +the microstepping divider. If this number is not 1, this means that the value +of distance divided by ``subdiv`` will give the amount of machine-natural +mechanical units of distance (whole steps in case of a stepper motor). +The 4 different ``_conv_`` fields specify two rational conversion factors for +speed and acceleration respectively. All unit conversions of speed and +acceleration are done in user-space. The kernel only provides these numbers +to user-space as part of physical characteristics of the motion controller. +If the driver does not specify these values, or they lack a defined meaning, +all four of these fields will have a value of 1, so no zero-division can +happen and the conversion is just 1:1. + +.. code-block:: C + + struct mot_speed_duration { + __u32 channel; + speed_raw_t speed; + mot_time_t duration; + pos_raw_t distance; + __u32 reserved[3]; + }; + +This struct is used int the ioctl MOT_IOCTL_BASIC_RUN to start a new motion. +There are different ways of using BASIC_RUN: + + 1. Specify only ``channel`` and ``speed``. All other fields are zero. This + starts a new motion for indefinte amount of time. + + 2. Additionally to 1. specify non-zero ``duration``. Starts a timed motion + that will stop after the specified time. + + 3. Additionally to 1. specify non-zero ``distance``. Starts a motion until + the position specified by distance from starting point is reached. + +Non zero values for both ``duration`` and ``distance`` will result in an +error (-EINVAL). + +.. code-block:: C + + struct mot_status { + __u32 channel; + pos_raw_t position; + speed_raw_t speed; + __u32 local_inputs; + }; + +This struct is used for the ioctl MOT_IOCTL_GET_STATUS. The caller needs to +set the field ``channel`` to the channel number it wants to request status +information from. After a successful call, the field ``speed`` will contain +the current speed of movement of the channel, and ``position`` will contain +the actual position if this is supported by the hardware. The field +``local_inputs`` contains a bit-mask of the state of all internal trigger +inputs. + +.. code-block:: C + + struct mot_input { + __u32 index; + __u8 external; + __u8 edge; + __u8 reserved[2]; + __u32 function; + channel_mask_t chmask; + }; + +This struct is used for configuring internal or external trigger inputs. The +input ``index`` is specific to the flag ``external``. This means that internal +and external trigger inputs can have the same ``index`` value. The exact +``index`` value for internal inputs is determined by the driver and should be +enumerated from 0 onwards. For external GPIO intputs the index number is the +order in which they appear in the fwnode (DT property "motion,gpios"). +``edge`` indicates the polarity of the input electrical signal, +MOT_EDGE_FALLING or MOT_EDGE_RISING. Please note, that any GPIO polarity is +also applied. So if a GPIO input is GPIO_ACTIVE_LOW and ``edge`` is +MOT_EDGE_FALLING, the resulting trigger will occur on the rising edge of the +electrical input signal. +``function`` takes any of the MOT_INP_FUNC_XX values mentioned above. +``chmask`` is a bit-mask of all motion channels this input will affect. + +.. code-block:: C + + struct mot_profile { + __u32 index; + mot_time_t tvmax; + mot_time_t tvzero; + __u8 na; + __u8 nv; + __u8 reserved[2]; + accel_raw_t acc[MOT_MAX_ACCELPTS]; + speed_raw_t vel[MOT_MAX_SPEEDPTS]; + }; + +Used to define a motion profile. See :ref:`motion-profiles` for a general +explanation of motion profiles. ``nv`` and ``na`` are the number of valid +entries in the ``velp[]`` and ``acc[]`` arrays respectively. ``tvmax`` is the +minimum amount of time the constant (maximum) speed needs to be maintained +after ending the acceleration phase, and before beginning the deceleration +phase. ``tvzero`` is the minimum amount of time the speed needs to be 0, +before a new motion is started in the same direction as the preceding motion. +In other words, analogous to ``tvmax``, a new acceleration with opposite sign +of the preceding deceleration. This time value is not applied if the next +motion is into the opposite direction, since there will be no change in the +sign of the resulting acceleration. + +.. code-block:: C + + struct mot_start { + __u32 channel; + __u8 direction; + __u8 index; + __u8 when; + __u8 reserved1; + mot_time_t duration; + pos_raw_t distance; + __u32 reserved2; + }; + +Used for the MOT_IOCTL_START ioctl. The ``index`` parameter is the index +number of the motion profile that will be used for the motion. ``when`` +determines when (under which condition) the motion is started, and takes +the value of any of the MOT_WHEN_XX constants. Like in the case of struct +mot_speed_duration, here also ``duration`` and ``distance`` are mutually +exclusive, meaning that one of both must always be zero. + +.. code-block:: C + + struct mot_stop { + channel_mask_t chmask; + __u8 when; + __u8 reserved[3]; + }; + +This struct is used to schedule a deceleration of a running motion of all +channels specified by ``chmask``, by following the deceleration part of their +respecive motion profiles. ``when`` takes any of the MOT_WHEN_XX constants and +determines the condition that triggers the deceleration. + +Event handling with (e)poll/select +---------------------------------- + +When user-space opens the devnode for reading, (e)poll() can be used to wait +for motion events, using the (E)POLLIN flag. These events can then be read by +calling read() on the file-descriptor with a buffer size equal to the size of +struct mot_event. Make sure the file is opened in non-blocking mode for +for reliable event processing. read() will return -EAGAIN in this case. + +.. code-block:: C + + struct mot_event { + __u32 channel; + __u8 event; + __u8 reserved1[3]; + pos_raw_t position; + speed_raw_t speed; + mot_time_t timestamp; + __u32 input_index; + __u32 reserved2; + }; + +``event`` can take any of the MOT_EVENT_XX constants, and is used to determine +the type of event. The values of ``position``, ``speed`` and ``timestamp`` are +the corresponding motion position, speed and time at which the event ocurred. +Not all drivers support reporting a position value. If they don't that field +will always be zero. ``input_index`` is the index number of the external input +(in the case of a MOT_EVENT_INPUT event), or the index number of the internal +input (in the case of a MOT_EVENT_STOP event), that caused the event. For +other event types than MOT_EVENT_INPUT or MOT_EVENT_STOP, this field has no +meaning and will be zero. diff --git a/Documentation/subsystem-apis.rst b/Documentation/subsystem-apis.rst index b52ad5b969d4..0707b297f150 100644 --- a/Documentation/subsystem-apis.rst +++ b/Documentation/subsystem-apis.rst @@ -90,3 +90,4 @@ Other subsystems peci/index wmi/index tee/index + motion/index -- 2.47.2