diff --git a/Kconfig b/Kconfig index 6b7d2a47ad631..c563b830bdc57 100644 --- a/Kconfig +++ b/Kconfig @@ -2034,6 +2034,39 @@ config DEBUG_MOTOR_INFO endif # DEBUG_MOTOR +config DEBUG_STEPPER + bool "Stepper Motor Debug Features" + default n + depends on STEPPER + ---help--- + Enable motor debug features. + +if DEBUG_STEPPER + +config DEBUG_STEPPER_ERROR + bool "Stepper Motor Error Output" + default n + depends on DEBUG_ERROR + ---help--- + Enable motor error output to SYSLOG. + +config DEBUG_STEPPER_WARN + bool "Stepper Motor Warnings Output" + default n + depends on DEBUG_WARN + ---help--- + Enable motor warning output to SYSLOG. + +config DEBUG_STEPPER_INFO + bool "Stepper Motor Informational Output" + default n + depends on DEBUG_INFO + ---help--- + Enable motor informational output to SYSLOG. + +endif # DEBUG_STEPPER + + config DEBUG_VIDEO bool "Video Debug Features" default n diff --git a/drivers/motor/CMakeLists.txt b/drivers/motor/CMakeLists.txt index affaad616ee7a..b3f58bdbc9b4c 100644 --- a/drivers/motor/CMakeLists.txt +++ b/drivers/motor/CMakeLists.txt @@ -24,3 +24,11 @@ endif() if(CONFIG_MOTOR_UPPER) target_sources(drivers PRIVATE motor.c) endif() + +if(CONFIG_STEPPER_UPPER) + target_sources(drivers PRIVATE stepper.c) +endif() + +if(CONFIG_STEPPER_A4988) + target_sources(drivers PRIVATE a4988.c) +endif() diff --git a/drivers/motor/Kconfig b/drivers/motor/Kconfig index 7c220916b421c..8cfe8171ea209 100644 --- a/drivers/motor/Kconfig +++ b/drivers/motor/Kconfig @@ -62,3 +62,23 @@ endif source "drivers/motor/foc/Kconfig" endif # MOTOR + +menuconfig STEPPER + bool "Stepper control drivers" + default n + +if STEPPER + +config STEPPER_UPPER + bool "Stepper Motor Generic upper-half driver" + default n + ---help--- + Enables building of a stepper generic upper half driver. + +config STEPPER_A4988 + bool "A4988 Stepper Motor Driver" + default n + ---help--- + Enables A4988 stepper driver. + +endif # STEPPER diff --git a/drivers/motor/Make.defs b/drivers/motor/Make.defs index f10953159257a..b415e79295599 100644 --- a/drivers/motor/Make.defs +++ b/drivers/motor/Make.defs @@ -30,6 +30,17 @@ ifeq ($(CONFIG_MOTOR_UPPER),y) CSRCS += motor.c endif +# Stepper upper half and lower halfs + +ifeq ($(CONFIG_STEPPER_UPPER),y) +CSRCS += stepper.c +endif + +ifeq ($(CONFIG_STEPPER_A4988),y) +CSRCS += a4988.c +endif + + # Include motor drivers in the build MOTOR_DEPPATH := --dep-path motor diff --git a/drivers/motor/a4988.c b/drivers/motor/a4988.c new file mode 100644 index 0000000000000..b5a3bbe390890 --- /dev/null +++ b/drivers/motor/a4988.c @@ -0,0 +1,310 @@ +/**************************************************************************** + * drivers/motor/a4988.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct a4988_dev_s +{ + FAR struct a4988_ops_s *ops; /* A4988 ops */ + int32_t position; + uint8_t auto_idle; /* If true, go in idle mode between movement */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int a4988_setup(FAR struct stepper_lowerhalf_s *dev); +static int a4988_shutdown(FAR struct stepper_lowerhalf_s *dev); +static int a4988_work(FAR struct stepper_lowerhalf_s *dev, + FAR struct stepper_job_s const *param); +static int a4988_state(FAR struct stepper_lowerhalf_s *dev, + FAR struct stepper_state_s *state); +static int a4988_clear(FAR struct stepper_lowerhalf_s *dev, uint8_t fault); +static int a4988_idle(FAR struct stepper_lowerhalf_s *dev, uint8_t idle); +static int a4988_microstepping(FAR struct stepper_lowerhalf_s *dev, + uint16_t resolution); +static int a4988_ioctl(FAR struct stepper_lowerhalf_s *dev, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct stepper_ops_s g_a4988_ops = +{ + a4988_setup, /* setup */ + a4988_shutdown, /* shutdown */ + a4988_work, /* work */ + a4988_state, /* state */ + a4988_clear, /* clear */ + a4988_idle, /* idle */ + a4988_microstepping, /* microstepping */ + a4988_ioctl /* ioctl */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int a4988_setup(FAR struct stepper_lowerhalf_s *dev) +{ + FAR struct a4988_dev_s *priv = (FAR struct a4988_dev_s *)dev->priv; + priv->ops->idle(false); + priv->ops->enable(true); + + return 0; +} + +static int a4988_shutdown(FAR struct stepper_lowerhalf_s *dev) +{ + FAR struct a4988_dev_s *priv = (FAR struct a4988_dev_s *)dev->priv; + priv->ops->idle(true); + priv->ops->enable(false); + + return 0; +} + +static int a4988_work(FAR struct stepper_lowerhalf_s *dev, + FAR struct stepper_job_s const *job) +{ + FAR struct a4988_dev_s *priv = (FAR struct a4988_dev_s *)dev->priv; + int delay; + int count; + + if (job->steps == 0) + { + /* Nothing to do */ + + return 0; + } + + /* Compute delay between pulse */ + + delay = USEC_PER_MSEC / job->speed; + if (delay < 1) + { + delay = 1; + } + + /* Set direction */ + + if (job->steps > 0) + { + priv->ops->direction(true); + count = job->steps; + } + else + { + priv->ops->direction(false); + count = -job->steps; + } + + if (priv->auto_idle) + { + priv->ops->idle(false); + usleep(USEC_PER_MSEC); + } + + for (int32_t i = 0; i < count; ++i) + { + priv->ops->step(true); + up_udelay(1); + priv->ops->step(false); + up_udelay(delay); + } + + if (priv->auto_idle) + { + priv->ops->idle(true); + } + + /* Update position */ + + priv->position += job->steps; + + return 0; +} + +static int a4988_state(FAR struct stepper_lowerhalf_s *dev, + FAR struct stepper_state_s *state) +{ + FAR struct a4988_dev_s *priv = (FAR struct a4988_dev_s *)dev->priv; + state->position = priv->position; + + return 0; +} + +static int a4988_clear(FAR struct stepper_lowerhalf_s *dev, uint8_t fault) +{ + return -ENOSYS; +} + +static int a4988_idle(FAR struct stepper_lowerhalf_s *dev, uint8_t idle) +{ + FAR struct a4988_dev_s *priv = (FAR struct a4988_dev_s *)dev->priv; + + if (idle == STEPPER_AUTO_IDLE) + { + priv->auto_idle = true; + return 0; + } + + priv->auto_idle = false; + + if (idle == STEPPER_ENABLE_IDLE) + { + priv->ops->idle(true); + } + else + { + priv->ops->idle(false); + usleep(USEC_PER_MSEC); + } + + return 0; +} + +static int a4988_microstepping(FAR struct stepper_lowerhalf_s *dev, + uint16_t resolution) +{ + FAR struct a4988_dev_s *priv = (FAR struct a4988_dev_s *)dev->priv; + + switch (resolution) + { + case 1: + { + priv->ops->microstepping(false, false, false); + } + break; + + case 2: + { + priv->ops->microstepping(true, false, false); + } + break; + + case 4: + { + priv->ops->microstepping(false, true, false); + } + break; + + case 8: + { + priv->ops->microstepping(true, true, false); + } + break; + + case 16: + { + priv->ops->microstepping(true, true, true); + } + break; + + default: + { + return -EINVAL; + } + } + + return 0; +} + +static int a4988_ioctl(FAR struct stepper_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int a4988_register(FAR const char *devpath, FAR struct a4988_ops_s *ops) +{ + FAR struct a4988_dev_s *priv; + FAR struct stepper_lowerhalf_s *lower; + int ret = 0; + + /* Sanity check */ + + DEBUGASSERT(ops != NULL); + + /* Initialize the a4988 dev structure */ + + priv = kmm_malloc(sizeof(struct a4988_dev_s)); + if (priv == NULL) + { + stperr("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->ops = ops; + priv->position = 0; + + lower = kmm_malloc(sizeof(struct stepper_lowerhalf_s)); + if (priv == NULL) + { + stperr("Failed to allocate instance\n"); + kmm_free(priv); + return -ENOMEM; + } + + lower->priv = priv; + lower->state.fault = STEPPER_FAULT_CLEAR; + lower->state.state = STEPPER_STATE_INIT; + lower->state.position = 0; + lower->ops = &g_a4988_ops; + + /* Initialize lower layer (only once) */ + + priv->ops->initialize(); + + /* Register the character driver */ + + ret = stepper_register(devpath, lower); + if (ret < 0) + { + stperr("Failed to register driver: %d\n", ret); + kmm_free(priv); + kmm_free(lower); + return ret; + } + + stpinfo("a4988 registered at %s\n", devpath); + return ret; +} diff --git a/drivers/motor/stepper.c b/drivers/motor/stepper.c new file mode 100644 index 0000000000000..f1e64978a76fc --- /dev/null +++ b/drivers/motor/stepper.c @@ -0,0 +1,337 @@ +/**************************************************************************** + * drivers/motor/stepper.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Upper-half, character driver for stepper control */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of the upper half driver */ + +struct stepper_upperhalf_s +{ + FAR struct stepper_lowerhalf_s *lower; /* lower half driver */ + int refs; /* Reference count */ + mutex_t lock; /* Only one thread can access at a time */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int stepper_open(FAR struct file *filep); +static int stepper_close(FAR struct file *filep); +static ssize_t stepper_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t stepper_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int stepper_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_stepper_fops = +{ + stepper_open, /* open */ + stepper_close, /* close */ + stepper_read, /* read */ + stepper_write, /* write */ + NULL, /* seek */ + stepper_ioctl, /* ioctl */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stepper_open + * + * Description: + * This function is called whenever the stepper device is opened. + * + ****************************************************************************/ + +static int stepper_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct stepper_upperhalf_s *stepper = inode->i_private; + FAR struct stepper_lowerhalf_s *lower = stepper->lower; + int ret; + + ret = nxmutex_lock(&stepper->lock); + if (ret < 0) + { + return ret; + } + + /* Increment the count of references to the device. If this the first + * time that the driver has been opened for this device, then + * initialize the device. + */ + + stepper->refs++; + if (stepper->refs == 1) + { + ret = lower->ops->setup(lower); + if (ret < 0) + { + stepper->refs--; /* Something bad happened: open failure */ + } + } + + nxmutex_unlock(&stepper->lock); + return ret; +} + +/**************************************************************************** + * Name: stepper_close + * + * Description: + * This routine is called when the stepper device is closed. + * + ****************************************************************************/ + +static int stepper_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct stepper_upperhalf_s *stepper = inode->i_private; + FAR struct stepper_lowerhalf_s *lower = stepper->lower; + int ret; + + ret = nxmutex_lock(&stepper->lock); + if (ret < 0) + { + return ret; + } + + /* Decrement the references to the driver. If the reference count will + * decrement to 0, then uninitialize the driver. + */ + + stepper->refs--; + if (stepper->refs == 0) + { + ret = lower->ops->shutdown(lower); /* Disable the stepper */ + } + + nxmutex_unlock(&stepper->lock); + + return ret; +} + +/**************************************************************************** + * Name: stepper_read + ****************************************************************************/ + +static ssize_t stepper_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct stepper_upperhalf_s *stepper = inode->i_private; + FAR struct stepper_lowerhalf_s *lower = stepper->lower; + FAR struct stepper_state_s *state; + int ret; + + if (buflen != sizeof(struct stepper_state_s)) + { + return -EINVAL; + } + + state = (FAR struct stepper_state_s *)buffer; + ret = lower->ops->state(lower, state); + if (ret < 0) + { + stperr("Get stepper state failed: %d\n", ret); + return ret; + } + + return sizeof(struct stepper_state_s); +} + +/**************************************************************************** + * Name: stepper_write + ****************************************************************************/ + +static ssize_t stepper_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct stepper_upperhalf_s *stepper = inode->i_private; + FAR struct stepper_lowerhalf_s *lower = stepper->lower; + FAR struct stepper_job_s const *job; + int ret; + + if (buflen != sizeof(struct stepper_job_s)) + { + return -EINVAL; + } + + job = (FAR struct stepper_job_s const *)buffer; + ret = lower->ops->work(lower, job); + if (ret < 0) + { + stperr("Stepper work failed: %d\n", ret); + return ret; + } + + return sizeof(struct stepper_job_s); +} + +/**************************************************************************** + * Name: stepper_ioctl + ****************************************************************************/ + +static int stepper_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct stepper_upperhalf_s *stepper = inode->i_private; + FAR struct stepper_lowerhalf_s *lower = stepper->lower; + int ret = 0; + + switch (cmd) + { + case STEPIOC_IDLE: + { + uint8_t idle = (uint8_t)arg; + + ret = lower->ops->idle(lower, idle); + if (ret < 0) + { + stperr("STEPIOC_IDLE failed: %d\n", ret); + } + } + break; + + case STEPIOC_CLEAR_FAULT: + { + uint8_t fault = (uint8_t)arg; + + ret = lower->ops->clear(lower, fault); + if (ret < 0) + { + stperr("STEPIOC_CLEAR_FAULT failed: %d\n", ret); + } + } + break; + + case STEPIOC_MICROSTEPPING: + { + uint16_t resolution = (uint16_t)arg; + + ret = lower->ops->microstepping(lower, resolution); + } + break; + + default: + { + ret = lower->ops->ioctl(lower, cmd, arg); + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stepper_register + * + * Description: + * This function binds an instance of a "lower half" stepper driver with + * the "upper half" stepper device and registers that device so that can + * be used by application code. + * + * We will register the character device with specified path. + * + * Input Parameters: + * path - The user specifies path name. + * lower - A pointer to an instance of lower half stepper driver. This + * instance is bound to the stepper driver and must persists + * as long as the driver persists. + * + * Returned Value: + * OK if the driver was successfully register; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int stepper_register(FAR const char *path, + FAR struct stepper_lowerhalf_s *lower) +{ + FAR struct stepper_upperhalf_s *stepper; + int ret = 0; + + /* Sanity check */ + + DEBUGASSERT(lower != NULL); + + /* Initialize the upper-half data structure */ + + stepper = kmm_zalloc(sizeof(struct stepper_upperhalf_s)); + if (stepper == NULL) + { + stperr("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + /* Initialize mutex */ + + nxmutex_init(&stepper->lock); + + /* Connect stepper driver with lower level interface */ + + stepper->lower = lower; + stepper->refs = 0; + + /* Register the stepper character driver */ + + ret = register_driver(path, &g_stepper_fops, 0666, stepper); + if (ret < 0) + { + nxmutex_destroy(&stepper->lock); + kmm_free(stepper); + } + + return ret; +} diff --git a/include/debug.h b/include/debug.h index 5b5cf4ddef428..e6b9163cd7ce2 100644 --- a/include/debug.h +++ b/include/debug.h @@ -830,6 +830,24 @@ # define mtrinfo _none #endif +#ifdef CONFIG_DEBUG_STEPPER_ERROR +# define stperr _err +#else +# define stperr _none +#endif + +#ifdef CONFIG_DEBUG_STEPPER_WARN +# define stpwarn _warn +#else +# define stpwarn _none +#endif + +#ifdef CONFIG_DEBUG_STEPPER_INFO +# define stpinfo _info +#else +# define stpinfo _none +#endif + #ifdef CONFIG_DEBUG_VIDEO_ERROR # define verr _err #else diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 210f56e2a258e..b4aaca0b2674d 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -98,6 +98,7 @@ #define _MIPIDSIBASE (0x3900) /* Mipidsi device ioctl commands */ #define _SEIOCBASE (0x3a00) /* Secure element ioctl commands */ #define _SYSLOGBASE (0x3c00) /* Syslog device ioctl commands */ +#define _STEPIOBASE (0x3d00) /* Stepper device ioctl commands */ #define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */ /* boardctl() commands share the same number space */ @@ -612,6 +613,11 @@ #define _MTRIOCVALID(c) (_IOC_TYPE(c) == _MTRIOBASE) #define _MTRIOC(nr) _IOC(_MTRIOBASE, nr) +/* Stepper drivers **********************************************************/ + +#define _STEPIOCVALID(c) (_IOC_TYPE(c) == _STEPIOBASE) +#define _STEPIOC(nr) _IOC(_STEPIOBASE, nr) + /* MATH drivers *************************************************************/ #define _MATHIOCVALID(c) (_IOC_TYPE(c) == _MATHIOBASE) diff --git a/include/nuttx/motor/a4988.h b/include/nuttx/motor/a4988.h new file mode 100644 index 0000000000000..aee48c6bcc4c0 --- /dev/null +++ b/include/nuttx/motor/a4988.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * include/nuttx/motor/a4988.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_MOTOR_A4988_H +#define __INCLUDE_NUTTX_MOTOR_A4988_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_STEPPER_A4988) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct a4988_ops_s +{ + /* Initialize the control, called at register step */ + + CODE void (*initialize)(void); + + /* Control step output */ + + CODE void (*step)(int level); + + /* Direction */ + + CODE void (*direction)(int level); + + /* Configure microstepping */ + + CODE void (*microstepping)(int ms1, int ms2, int ms3); + + /* Enable control */ + + CODE void (*enable)(int level); + + /* Idle control */ + + CODE void (*idle)(int level); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: a4988_register + * + * Description: + * Register the a4988 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/pwrmntr0" + * Returned Value: + * ops - operations on the concrete hardware + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int a4988_register(FAR const char *devpath, FAR struct a4988_ops_s *ops); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_STEPPER_A4988 */ +#endif /* __INCLUDE_NUTTX_DRIVERS_MOTOR_A4988_H */ diff --git a/include/nuttx/motor/stepper.h b/include/nuttx/motor/stepper.h new file mode 100644 index 0000000000000..1577c33e01845 --- /dev/null +++ b/include/nuttx/motor/stepper.h @@ -0,0 +1,212 @@ +/***************************************************************************** + * include/nuttx/motor/stepper.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + *****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_MOTOR_STEPPER_H +#define __INCLUDE_NUTTX_MOTOR_STEPPER_H + +/* The motor driver is split into two parts: + * + * 1) An "upper half", generic driver that provides the common motor + * interface to application level code, and + * 2) A "lower half", platform-specific driver that implements the low-level + * functionality eg.: + * - timer controls to implement the PWM signals, + * - analog peripherals configuration such as ADC, DAC and comparators, + * - control algorithm for motor driver (eg. FOC control for BLDC) + * + * This 'upper-half' driver has been designed with flexibility in mind + * to support all kinds of electric motors and their applications. + */ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include +#include +#include + +#include + +#ifdef CONFIG_STEPPER_UPPER + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +/***************************************************************************** + * Public Types + *****************************************************************************/ + +/* Stepper driver state */ + +enum stepper_state_e +{ + STEPPER_STATE_INIT = 0, /* Initial state */ + STEPPER_STATE_IDLE = 1, /* IDLE state */ + STEPPER_STATE_RUN = 2, /* Run state */ + STEPPER_STATE_FAULT = 3 /* Fault state */ +}; + +/* Stepper driver fault type */ + +enum stepper_fault_e +{ + STEPPER_FAULT_CLEAR = 0, /* No fault */ + STEPPER_FAULT_OVERCURRENT = (1 << 0), /* Over-current Fault */ + STEPPER_FAULT_OVERVOLTAGE = (1 << 1), /* Over-voltage Fault */ + STEPPER_FAULT_OVERPOWER = (1 << 2), /* Over-power Fault (electrical) */ + STEPPER_FAULT_OVERTEMP = (1 << 3), /* Over-temperature Fault */ + STEPPER_FAULT_OVERLOAD = (1 << 4), /* Stepper overload Fault (mechanical) */ + STEPPER_FAULT_LOCKED = (1 << 5), /* Stepper locked Fault */ + STEPPER_FAULT_INVAL_PARAM = (1 << 6), /* Invalid parameter Fault */ + STEPPER_FAULT_OTHER = (1 << 7) /* Other Fault */ +}; + +/* Stepper IDLE control */ + +enum stepper_idle_e +{ + STEPPER_ENABLE_IDLE = 0, /* Enable IDLE mode */ + STEPPER_DISABLE_IDLE = 1, /* Disable IDLE mode */ + STEPPER_AUTO_IDLE = 2, /* Set automaticaly IDLE when stepper not in movement */ +}; + +/* Stepper driver state */ + +struct stepper_state_s +{ + uint8_t state; /* Stepper driver state */ + uint8_t fault; /* Stepper driver faults */ + int32_t position; /* Feedback from motor - absolute position */ +}; + +/* Stepper parameters. */ + +struct stepper_job_s +{ + int32_t steps; /* Steps to do. Position: CW, Negative: CCW */ + uint16_t speed; /* Stepper speed in step/ms */ +}; + +/* Stepper operations used to call from the upper-half, generic stepper driver + * into lower-half, platform-specific logic. + */ + +struct stepper_lowerhalf_s; +struct stepper_ops_s +{ + /* Setup stepper for operational mode */ + + CODE int (*setup)(FAR struct stepper_lowerhalf_s *dev); + + /* Disable stepper */ + + CODE int (*shutdown)(FAR struct stepper_lowerhalf_s *dev); + + /* work */ + + CODE int (*work)(FAR struct stepper_lowerhalf_s *dev, + FAR struct stepper_job_s const *param); + + /* Get motor state */ + + CODE int (*state)(FAR struct stepper_lowerhalf_s *dev, + FAR struct stepper_state_s *state); + + /* Clear fault state */ + + CODE int (*clear)(FAR struct stepper_lowerhalf_s *dev, uint8_t fault); + + /* Configure IDLE mode */ + + CODE int (*idle)(FAR struct stepper_lowerhalf_s *dev, uint8_t idle); + + /* Configure stepping resolution mode */ + + CODE int (*microstepping)(FAR struct stepper_lowerhalf_s *dev, + uint16_t resolution); + + /* Lower-half logic may support platform-specific ioctl commands */ + + CODE int (*ioctl)(FAR struct stepper_lowerhalf_s *dev, int cmd, + unsigned long arg); +}; + +/* This structure is the generic form of state structure used by lower half + * motor driver. + */ + +struct stepper_lowerhalf_s +{ + FAR const struct stepper_ops_s *ops; /* Arch-specific operations */ + struct stepper_job_s param; /* Motor settings */ + struct stepper_state_s state; /* Motor state */ + FAR void *priv; /* Private data */ +}; + +/***************************************************************************** + * Public Data + *****************************************************************************/ + +/***************************************************************************** + * Public Function Prototypes + *****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/***************************************************************************** + * Name: stepper_register + * + * Description: + * This function binds an instance of a "lower half" stepper driver with the + * "upper half" stepper device and registers that device so that can be used + * by application code. + * + * We will register the character device with specified path. + * + * Input Parameters: + * path - The user specifies path name. + * lower - A pointer to an instance of lower half stepper driver. This + * instance is bound to the stepper driver and must persists as long + * as the driver persists. + * + * Returned Value: + * OK if the driver was successfully register; A negated errno value is + * returned on any failure. + * + *****************************************************************************/ + +int stepper_register(FAR const char *path, + FAR struct stepper_lowerhalf_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_STEPPER_UPPER */ +#endif /* __INCLUDE_NUTTX_DRIVERS_MOTOR_STEPPER_H */ diff --git a/include/nuttx/motor/stepper_ioctl.h b/include/nuttx/motor/stepper_ioctl.h new file mode 100644 index 0000000000000..dc20f65866c8c --- /dev/null +++ b/include/nuttx/motor/stepper_ioctl.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * include/nuttx/motor/stepper_ioctl.h + * NuttX Motor-Related IOCTLs definitions + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_MOTOR_STEPPER_IOCTL_H +#define __INCLUDE_NUTTX_MOTOR_STEPPER_IOCTL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STEPIOC_IDLE _STEPIOC(1) +#define STEPIOC_CLEAR_FAULT _STEPIOC(2) +#define STEPIOC_MICROSTEPPING _STEPIOC(3) + +#endif /* __INCLUDE_NUTTX_MOTOR_STEPPER_IOCTL_H */