From 9a511975237e0d0bf5cc39cd0312da206490aea4 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Tue, 7 Nov 2023 13:38:50 +0100 Subject: [PATCH] drivers/foc: add support for drv8301 power-stage driver --- drivers/motor/CMakeLists.txt | 1 + drivers/motor/foc/CMakeLists.txt | 5 + drivers/motor/foc/Kconfig | 7 + drivers/motor/foc/Make.defs | 4 + drivers/motor/foc/drv8301.c | 457 ++++++++++++++++++++++++ include/nuttx/motor/{ => foc}/drv8301.h | 84 ++++- 6 files changed, 553 insertions(+), 5 deletions(-) create mode 100644 drivers/motor/foc/drv8301.c rename include/nuttx/motor/{ => foc}/drv8301.h (72%) diff --git a/drivers/motor/CMakeLists.txt b/drivers/motor/CMakeLists.txt index ef59b5ab0f..7d6990d83f 100644 --- a/drivers/motor/CMakeLists.txt +++ b/drivers/motor/CMakeLists.txt @@ -17,6 +17,7 @@ # the License. # # ############################################################################## + if(CONFIG_MOTOR_FOC) nuttx_add_subdirectory() endif() diff --git a/drivers/motor/foc/CMakeLists.txt b/drivers/motor/foc/CMakeLists.txt index 733252e0cd..9cee9bf19b 100644 --- a/drivers/motor/foc/CMakeLists.txt +++ b/drivers/motor/foc/CMakeLists.txt @@ -20,6 +20,7 @@ if(CONFIG_MOTOR_FOC) set(SRCS foc_dev.c) + if(CONFIG_MOTOR_FOC_DUMMY) list(APPEND SRCS foc_dummy.c) endif() @@ -28,6 +29,10 @@ if(CONFIG_MOTOR_FOC) list(APPEND SRCS foc_pwr.c) endif() + if(CONFIG_MOTOR_FOC_DRV8301) + list(APPEND SRCS drv8301.c) + endif() + target_include_directories(drivers PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_sources(drivers PRIVATE ${SRCS}) endif() diff --git a/drivers/motor/foc/Kconfig b/drivers/motor/foc/Kconfig index 82cd9af3a7..6b6818906d 100644 --- a/drivers/motor/foc/Kconfig +++ b/drivers/motor/foc/Kconfig @@ -41,4 +41,11 @@ config MOTOR_FOC_DUMMY config MOTOR_FOC_FOCPWR bool +config MOTOR_FOC_DRV8301 + bool "DRV8301 Three-Phase Gate Driver" + default n + select MOTOR_FOC_FOCPWR + ---help--- + Enables FOC power-stage DRV8301 driver. + endif #MOTOR_FOC diff --git a/drivers/motor/foc/Make.defs b/drivers/motor/foc/Make.defs index ae29d7e982..8d505a61bd 100644 --- a/drivers/motor/foc/Make.defs +++ b/drivers/motor/foc/Make.defs @@ -30,6 +30,10 @@ ifeq ($(CONFIG_MOTOR_FOC_FOCPWR),y) CSRCS += foc_pwr.c endif +ifeq ($(CONFIG_MOTOR_FOC_DRV8301),y) +CSRCS += drv8301.c +endif + # Include FOC driver build support DEPPATH += --dep-path motor$(DELIM)foc diff --git a/drivers/motor/foc/drv8301.c b/drivers/motor/foc/drv8301.c new file mode 100644 index 0000000000..a169fa6041 --- /dev/null +++ b/drivers/motor/foc/drv8301.c @@ -0,0 +1,457 @@ +/**************************************************************************** + * drivers/motor/foc/drv8301.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 + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if FOC_BOARDCFG_GAINLIST_LEN < 4 +# error FOC_BOARDCFG_GAINLIST_LEN < 4 not supported +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* DRV8301 device */ + +struct drv8301_priv_s +{ + /* Common FOC power-stage driver - must be first */ + + struct focpwr_dev_s dev; + + FAR struct drv8301_ops_s *ops; /* Board ops */ + + FAR struct spi_dev_s *spi; /* SPI device reference */ + FAR struct drv8301_cfg_s cfg; /* Configuration */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int drv8301_fault_isr(int irq, void *context, void *arg); + +static int drv8301_gain_set(FAR struct focpwr_dev_s *dev, int gain); +static int drv8301_gain_get(FAR struct focpwr_dev_s *dev, FAR int *gain); + +static int drv8301_setup(FAR struct focpwr_dev_s *dev); +static int drv8301_shutdown(FAR struct focpwr_dev_s *dev); +static int drv8301_calibration(FAR struct focpwr_dev_s *dev, bool state); +static int drv8301_ioctl(FAR struct focpwr_dev_s *dev, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct focpwr_ops_s g_drv8301_ops = +{ + .setup = drv8301_setup, + .shutdown = drv8301_shutdown, + .calibration = drv8301_calibration, + .ioctl = drv8301_ioctl, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: drv8301_lock + ****************************************************************************/ + +static void drv8301_lock(FAR struct drv8301_priv_s *priv) +{ + SPI_LOCK(priv->spi, 1); + SPI_SETBITS(priv->spi, 16); + SPI_SETMODE(priv->spi, SPIDEV_MODE1); + SPI_SETFREQUENCY(priv->spi, priv->cfg.freq); +} + +/**************************************************************************** + * Name: drv8301_unlock + ****************************************************************************/ + +static void drv8301_unlock(FAR struct drv8301_priv_s *priv) +{ + SPI_LOCK(priv->spi, 0); +} + +/**************************************************************************** + * Name: drv8301_read + ****************************************************************************/ + +static void drv8301_read(FAR struct drv8301_priv_s *priv, uint8_t addr, + uint16_t *data) +{ + uint16_t regval = 0; + + drv8301_lock(priv); + SPI_SELECT(priv->spi, SPIDEV_MOTOR(priv->dev.devno), true); + + /* Read command */ + + regval |= (1 << 15); + regval |= ((addr & 0x0f) << 11); + + /* Send command */ + + SPI_SEND(priv->spi, regval); + + /* Toggle CS pin, otherwise read doesn't work */ + + SPI_SELECT(priv->spi, SPIDEV_MOTOR(priv->dev.devno), false); + SPI_SELECT(priv->spi, SPIDEV_MOTOR(priv->dev.devno), true); + + /* Read output */ + + regval = 0; + SPI_RECVBLOCK(priv->spi, ®val, 1); + + /* Retrun data */ + + *data = (regval & 0x7ff); + + SPI_SELECT(priv->spi, SPIDEV_MOTOR(priv->dev.devno), false); + drv8301_unlock(priv); +} + +/**************************************************************************** + * Name: drv8301_write + ****************************************************************************/ + +static void drv8301_write(FAR struct drv8301_priv_s *priv, uint8_t addr, + uint16_t data) +{ + uint16_t regval = 0; + + drv8301_lock(priv); + SPI_SELECT(priv->spi, SPIDEV_MOTOR(priv->dev.devno), true); + + /* Write command */ + + regval |= (0 << 15); + regval |= ((addr & 0x0f) << 11); + regval |= (0x7ff & data); + + /* Send data */ + + SPI_SEND(priv->spi, regval); + + SPI_SELECT(priv->spi, SPIDEV_MOTOR(priv->dev.devno), false); + drv8301_unlock(priv); +} + +/**************************************************************************** + * Name: drv8301_fault_isr + ****************************************************************************/ + +static int drv8301_fault_isr(int irq, FAR void *context, void *arg) +{ + FAR struct drv8301_priv_s *priv = NULL; + + priv = (struct drv8301_priv_s *)arg; + DEBUGASSERT(priv != NULL); + + priv->ops->fault_handle(&priv->dev); + + return OK; +} + +/**************************************************************************** + * Name: drv8301_setup + ****************************************************************************/ + +static int drv8301_setup(FAR struct focpwr_dev_s *dev) +{ + FAR struct drv8301_priv_s *priv = (FAR struct drv8301_priv_s *)dev; + uint16_t status1 = 0; + uint16_t status2 = 0; + uint16_t ctrl1 = 0; + uint16_t ctrl2 = 0; + int ret = OK; + + /* Reset chip */ + + priv->ops->gate_enable(dev, true); + up_udelay(30); + priv->ops->gate_enable(dev, false); + up_udelay(30); + priv->ops->gate_enable(dev, true); + up_mdelay(10); + + /* Attach fault handler */ + + priv->ops->fault_attach(dev, drv8301_fault_isr, priv); + + /* Get status registers */ + + drv8301_read(priv, DRV8301_REG_STAT1, &status1); + drv8301_read(priv, DRV8301_REG_STAT2, &status2); + + /* Configure CTRL1 */ + + ctrl1 = DRV8301_CTRL1_GCURR(priv->cfg.gate_curr); + ctrl1 |= DRV8301_CTRL1_OCADJ(priv->cfg.oc_adj); + ctrl1 |= (priv->cfg.pwm_mode ? DRV8301_CTRL1_PWMMODE : 0); + drv8301_write(priv, DRV8301_REG_CTRL1, ctrl1); + + /* Configure CTRL2 */ + + ctrl2 = DRV8301_CTRL2_GAIN(priv->cfg.gain); + drv8301_write(priv, DRV8301_REG_CTRL2, ctrl2); + + return ret; +} + +/**************************************************************************** + * Name: drv8301_shutdown + ****************************************************************************/ + +static int drv8301_shutdown(FAR struct focpwr_dev_s *dev) +{ + FAR struct drv8301_priv_s *priv = (FAR struct drv8301_priv_s *)dev; + + /* Disable chip */ + + priv->ops->gate_enable(dev, false); + + /* Disable nFAULT interrupt */ + + priv->ops->fault_attach(dev, NULL, NULL); + + return OK; +} + +/**************************************************************************** + * Name: drv8301_gain_get + ****************************************************************************/ + +static int drv8301_gain_get(FAR struct focpwr_dev_s *dev, FAR int *gain) +{ + FAR struct drv8301_priv_s *priv = (FAR struct drv8301_priv_s *)dev; + uint16_t ctrl2 = 0; + int ret = OK; + + drv8301_read(priv, DRV8301_REG_CTRL2, &ctrl2); + ctrl2 &= DRV8301_CTRL2_GAIN_MASK; + + if (ctrl2 == DRV8301_CTRL2_GAIN_10) + { + *gain = 10; + } + else if (ctrl2 == DRV8301_CTRL2_GAIN_20) + { + *gain = 20; + } + else if (ctrl2 == DRV8301_CTRL2_GAIN_40) + { + *gain = 40; + } + else if (ctrl2 == DRV8301_CTRL2_GAIN_80) + { + *gain = 80; + } + else + { + ret = -EINVAL; + } + + return ret; +} + +/**************************************************************************** + * Name: drv8301_gain_set + ****************************************************************************/ + +static int drv8301_gain_set(FAR struct focpwr_dev_s *dev, int gain) +{ + FAR struct drv8301_priv_s *priv = (FAR struct drv8301_priv_s *)dev; + uint16_t ctrl2 = 0; + int ret = OK; + + drv8301_read(priv, DRV8301_REG_CTRL2, &ctrl2); + + ctrl2 &= ~DRV8301_CTRL2_GAIN_MASK; + + if (gain == 10) + { + ctrl2 |= DRV8301_CTRL2_GAIN_10; + } + else if (gain == 20) + { + ctrl2 |= DRV8301_CTRL2_GAIN_20; + } + else if (gain == 40) + { + ctrl2 |= DRV8301_CTRL2_GAIN_40; + } + else if (gain == 80) + { + ctrl2 |= DRV8301_CTRL2_GAIN_80; + } + else + { + ret = -EINVAL; + goto errout; + } + + /* Write CTRL2 */ + + drv8301_write(priv, DRV8301_REG_CTRL2, ctrl2); + +errout: + return ret; +} + +/**************************************************************************** + * Name: drv8301_calibration + ****************************************************************************/ + +static int drv8301_calibration(FAR struct focpwr_dev_s *dev, bool state) +{ + FAR struct drv8301_priv_s *priv = (FAR struct drv8301_priv_s *)dev; + uint16_t regval = 0; + + drv8301_read(priv, DRV8301_REG_CTRL2, ®val); + + if (state == true) + { + regval |= DRV8301_CTRL2_DCCALCH1; + regval |= DRV8301_CTRL2_DCCALCH2; + } + else + { + regval &= ~DRV8301_CTRL2_DCCALCH1; + regval &= ~DRV8301_CTRL2_DCCALCH2; + } + + drv8301_write(priv, DRV8301_REG_CTRL2, regval); + + return OK; +} + +/**************************************************************************** + * Name: drv8301_ioctl + ****************************************************************************/ + +static int drv8301_ioctl(FAR struct focpwr_dev_s *dev, int cmd, + unsigned long arg) +{ + int ret = OK; + + switch (cmd) + { + case MTRIOC_SET_BOARDCFG: + { + struct foc_set_boardcfg_s *cfg = + (struct foc_set_boardcfg_s *)arg; + + ret = drv8301_gain_set(dev, cfg->gain); + break; + } + + case MTRIOC_GET_BOARDCFG: + { + struct foc_get_boardcfg_s *cfg = + (struct foc_get_boardcfg_s *)arg; + + ret = drv8301_gain_get(dev, &cfg->gain); + + cfg->gain_list[0] = 10; + cfg->gain_list[1] = 20; + cfg->gain_list[2] = 40; + cfg->gain_list[3] = 80; + + break; + } + + default: + { + ret = -ENOTTY; + break; + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: drv8301_register + ****************************************************************************/ + +int drv8301_register(FAR const char *path, + FAR struct foc_dev_s *dev, + FAR struct drv8301_board_s *board) +{ + FAR struct drv8301_priv_s *priv = NULL; + int ret = OK; + + /* Allocate driver */ + + priv = kmm_zalloc(sizeof(struct drv8301_priv_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + /* Register FOC device */ + + ret = foc_register(path, dev); + if (ret < 0) + { + return ret; + } + + /* Store board data */ + + priv->ops = board->ops; + priv->spi = board->spi; + + /* Store configuration */ + + memcpy(&priv->cfg, board->cfg, sizeof(struct drv8301_cfg_s)); + + /* Initialize FOC power stage */ + + return focpwr_initialize(&priv->dev, board->devno, dev, &g_drv8301_ops); +} diff --git a/include/nuttx/motor/drv8301.h b/include/nuttx/motor/foc/drv8301.h similarity index 72% rename from include/nuttx/motor/drv8301.h rename to include/nuttx/motor/foc/drv8301.h index 9d1d5bebf4..99272b12de 100644 --- a/include/nuttx/motor/drv8301.h +++ b/include/nuttx/motor/foc/drv8301.h @@ -1,5 +1,5 @@ /**************************************************************************** - * include/nuttx/motor/drv8301.h + * include/nuttx/motor/foc/drv8301.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __INCLUDE_NUTTX_MOTOR_DRV8301_H -#define __INCLUDE_NUTTX_MOTOR_DRV8301_H +#ifndef __INCLUDE_NUTTX_MOTOR_FOC_DRV8301_H +#define __INCLUDE_NUTTX_MOTOR_FOC_DRV8301_H /**************************************************************************** * Included Files @@ -27,6 +27,8 @@ #include +#include + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -65,6 +67,7 @@ # define DRV8301_CTRL1_GCURR_1p7A (0x0 << DRV8301_CTRL1_GCURR_SHIFT) # define DRV8301_CTRL1_GCURR_0p7A (0x1 << DRV8301_CTRL1_GCURR_SHIFT) # define DRV8301_CTRL1_GCURR_0p25A (0x2 << DRV8301_CTRL1_GCURR_SHIFT) +#define DRV8301_CTRL1_GCURR(x) ((x) << DRV8301_CTRL1_GCURR_SHIFT & DRV8301_CTRL1_GCURR_MASK) #define DRV8301_CTRL1_GRESET (1 << 2) /* Gate reset */ #define DRV8301_CTRL1_PWMMODE (1 << 3) /* PWM input mode */ #define DRV8301_CTRL1_OCPMODE_SHIFT (4) /* Overcurrent protection mode */ @@ -75,6 +78,8 @@ # define DRV8301_CTRL1_OCPMODE_DIS (0x3 << DRV8301_CTRL1_OCPMODE_SHIFT) #define DRV8301_CTRL1_OCADJ_SHIFT (6) /* Overcurrent adjustment */ #define DRV8301_CTRL1_OCADJ_MASK (0x1f << DRV8301_CTRL1_OCADJ_SHIFT) +#define DRV8301_CTRL1_OCADJ(x) ((x) << DRV8301_CTRL1_OCADJ_SHIFT & DRV8301_CTRL1_OCADJ_MASK) +#define DRV8301_OCADJ_DEFAULT (16) /* Control 2 register */ @@ -84,7 +89,8 @@ # define DRV8301_CTRL2_OCTWMODE_OTONLY (0x1 << DRV8301_CTRL2_OCTWMODE_SHIFT) # define DRV8301_CTRL2_OCTWMODE_OCONLY (0x2 << DRV8301_CTRL2_OCTWMODE_SHIFT) #define DRV8301_CTRL2_GAIN_SHIFT (2) /* Gain of shunt amplifier */ -#define DRV8301_CTRL2_GAIN_MASK (0x2 << DRV8301_CTRL2_GAIN_SHIFT) +#define DRV8301_CTRL2_GAIN_MASK (0x3 << DRV8301_CTRL2_GAIN_SHIFT) +#define DRV8301_CTRL2_GAIN(x) ((x) << DRV8301_CTRL2_GAIN_SHIFT & DRV8301_CTRL2_GAIN_MASK) # define DRV8301_CTRL2_GAIN_10 (0x0 << DRV8301_CTRL2_GAIN_SHIFT) # define DRV8301_CTRL2_GAIN_20 (0x1 << DRV8301_CTRL2_GAIN_SHIFT) # define DRV8301_CTRL2_GAIN_40 (0x2 << DRV8301_CTRL2_GAIN_SHIFT) @@ -97,8 +103,76 @@ * Public Types ****************************************************************************/ +/* Gate current */ + +enum drv8301_gatecurr_e +{ + DRV8301_GATECURR_1p7 = 0, + DRV8301_GATECURR_0p7 = 1, + DRV8301_GATECURR_0p25 = 2 +}; + +/* Gain of shunt amplifier */ + +enum drv8301_gain_e +{ + DRV8301_GAIN_10 = 0, + DRV8301_GAIN_20 = 1, + DRV8301_GAIN_40 = 2, + DRV8301_GAIN_80 = 3 +}; + +/* PWM mode */ + +enum drv8301_pwmmode_e +{ + DRV8301_PWM_6IN = 0, + DRV8301_PWM_3IN = 1, +}; + +/* DRV8301 board ops */ + +struct drv8301_ops_s +{ + CODE int (*fault_attach)(FAR struct focpwr_dev_s *dev, xcpt_t isr, + FAR void *arg); + CODE int (*gate_enable)(FAR struct focpwr_dev_s *dev, bool enable); + CODE int (*configure)(FAR struct focpwr_dev_s *dev); + CODE void (*fault_handle)(FAR struct focpwr_dev_s *dev); +}; + +/* DRV8301 configuration */ + +struct drv8301_cfg_s +{ + /* SPI frequency */ + + uint32_t freq; + + /* Control registers settings */ + + uint8_t gain:2; /* Gain of shunt amplifier */ + uint8_t gate_curr:2; /* Gate current */ + uint8_t pwm_mode:1; /* PWM 3 input mode if set to 1 */ + uint8_t oc_adj:5; /* Overcurrent adjustment */ +}; + +/* DRV8301 board data */ + +struct drv8301_board_s +{ + FAR struct spi_dev_s *spi; + FAR struct drv8301_ops_s *ops; + FAR struct drv8301_cfg_s *cfg; + int devno; +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ -#endif /* __INCLUDE_NUTTX_MOTOR_DRV8301_H */ +int drv8301_register(FAR const char *path, + FAR struct foc_dev_s *dev, + FAR struct drv8301_board_s *board); + +#endif /* __INCLUDE_NUTTX_MOTOR_FOC_DRV8301_H */