blob: 4b98a7cd36a5a08eeb87ae56dd8077220008a217 [file] [log] [blame]
/****************************************************************************
* boards/arm/stm32/odrive36/src/stm32_foc.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 <nuttx/config.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
#include <nuttx/mutex.h>
#include <nuttx/signal.h>
#include <nuttx/analog/adc.h>
#include <nuttx/motor/foc/drv8301.h>
#include <nuttx/motor/motor_ioctl.h>
#include "stm32_foc.h"
#include "stm32_gpio.h"
#ifdef CONFIG_ADC
# include "stm32_adc.h"
#endif
#include "odrive.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_ODRIVE_HW_VOLTAGE_56
# error Tested only for ODrive 56V version
#endif
/* Supported FOC instances */
#ifdef CONFIG_ODRIVE_FOC_FOC0
# define ODRIVE_FOC_FOC0 1
#else
# define ODRIVE_FOC_FOC0 0
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC1
# define ODRIVE_FOC_FOC1 1
#else
# define ODRIVE_FOC_FOC1 0
#endif
#define ODRIVE_FOC_INST (ODRIVE_FOC_FOC0 + ODRIVE_FOC_FOC1)
#ifdef CONFIG_ODRIVE_FOC_FOC0
# define ODRIVE32_FOC0_DEVPATH "/dev/foc0"
# define ODRIVE32_FOC0_INST (0)
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC1
# define ODRIVE32_FOC1_DEVPATH "/dev/foc1"
# define ODRIVE32_FOC1_INST (1)
#endif
/* Must match upper-half configuration */
#if ODRIVE_FOC_INST != CONFIG_MOTOR_FOC_INST
# error Invalid configuration
#endif
/* Only 2-shunt configuration supported by board */
#if CONFIG_MOTOR_FOC_SHUNTS != 2
# error For now ony 2-shunts configuration is supported
#endif
/* Configuration specific for DRV8301:
* 1. PWM channels must have positive polarity
* 2. PWM complementary channels must have positive polarity
*/
#ifndef CONFIG_STM32_FOC_HAS_PWM_COMPLEMENTARY
# error
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC0
# if CONFIG_STM32_TIM1_CH1POL != 0
# error
# endif
# if CONFIG_STM32_TIM1_CH2POL != 0
# error
# endif
# if CONFIG_STM32_TIM1_CH3POL != 0
# error
# endif
# if CONFIG_STM32_TIM1_CH1NPOL != 0
# error
# endif
# if CONFIG_STM32_TIM1_CH2NPOL != 0
# error
# endif
# if CONFIG_STM32_TIM1_CH3NPOL != 0
# error
# endif
/* FOC0 uses ADC2 */
# ifndef CONFIG_STM32_FOC_FOC0_ADC2
# error
# endif
# if CONFIG_STM32_ADC2_RESOLUTION != 0
# error
# endif
#endif /* CONFIG_ODRIVE_FOC_FOC0 */
#ifdef CONFIG_ODRIVE_FOC_FOC1
# if CONFIG_STM32_TIM8_CH1POL != 0
# error
# endif
# if CONFIG_STM32_TIM8_CH2POL != 0
# error
# endif
# if CONFIG_STM32_TIM8_CH3POL != 0
# error
# endif
# if CONFIG_STM32_TIM8_CH1NPOL != 0
# error
# endif
# if CONFIG_STM32_TIM8_CH2NPOL != 0
# error
# endif
# if CONFIG_STM32_TIM8_CH3NPOL != 0
# error
# endif
/* FOC1 uses ADC3 */
# ifndef CONFIG_STM32_FOC_FOC1_ADC3
# error
# endif
# if CONFIG_STM32_ADC3_RESOLUTION != 0
# error
# endif
#endif /* CONFIG_ODRIVE_FOC_FOC1 */
/* Aux ADC needs DMA enabled */
#ifdef CONFIG_ADC
# ifndef CONFIG_STM32_ADC1_DMA
# error
# endif
# ifndef CONFIG_STM32_ADC1_SCAN
# error
# endif
#endif
/* TODO: */
#define PWM_DEADTIME (50)
#define PWM_DEADTIME_NS (320)
/* Board parameters:
* Current shunt resistance = 0.0005
* Current sense gain = (10/20/40/80)
* Vbus min = 12V
* Vbus max = 24V or 56V
* Iout max = 40A (no cooling for
* MOSFETs)
* IPHASE_RATIO = 1/(R_shunt*gain)
* ADC_REF_VOLTAGE = 3.3
* ADC_VAL_MAX = 4095
* ADC_TO_VOLT = ADC_REF_VOLTAGE / ADC_VAL_MAX
* IPHASE_ADC = IPHASE_RATIO * ADC_TO_VOLT = 0.02014 (gain=80)
* VBUS_RATIO = 1/VBUS_gain = 11 or 19
*/
#define ADC_VOLT_REF 3300000 /* micro volt */
#define ADC_VAL_MAX 4095
#define R_SHUNT 500 /* micro ohm */
/* Center-aligned PWM duty cycle limits */
#define MAX_DUTY_B16 ftob16(0.95f)
/* ADC configuration */
#define CURRENT_SAMPLE_TIME ADC_SMPR_3
#define VBUS_SAMPLE_TIME ADC_SMPR_15
#define TEMP_SAMPLE_TIME ADC_SMPR_15
#define ODRIVE_ADC_AUX (1)
#define ODRIVE_ADC_FOC0 (2)
#define ODRIVE_ADC_FOC1 (3)
#ifdef CONFIG_ODRIVE_FOC_VBUS
# define ODRIVE_FOC_VBUS 1
#else
# define ODRIVE_FOC_VBUS 0
#endif
#ifdef CONFIG_ODRIVE_FOC_TEMP
# define ODRIVE_FOC_TEMP 3
#else
# define ODRIVE_FOC_TEMP 0
#endif
#ifdef CONFIG_ADC
# define ODRIVE_ADC_AUX_DEVPATH "/dev/adc0"
# define ODRIVE_ADC_AUX_NCHAN (ODRIVE_FOC_VBUS + ODRIVE_FOC_TEMP)
#endif
#define ADC1_INJECTED (0)
#define ADC1_REGULAR (0)
#define ADC1_NCHANNELS (ADC1_INJECTED + ADC1_REGULAR)
#define ADC2_INJECTED (CONFIG_MOTOR_FOC_SHUNTS)
#define ADC2_REGULAR (0)
#define ADC2_NCHANNELS (ADC2_INJECTED + ADC2_REGULAR)
#define ADC3_INJECTED (CONFIG_MOTOR_FOC_SHUNTS)
#define ADC3_REGULAR (0)
#define ADC3_NCHANNELS (ADC3_INJECTED + ADC3_REGULAR)
#if ADC1_INJECTED != CONFIG_STM32_ADC1_INJECTED_CHAN
# error
#endif
#if ADC2_INJECTED != CONFIG_STM32_ADC2_INJECTED_CHAN
# error
#endif
#if ADC3_INJECTED != CONFIG_STM32_ADC3_INJECTED_CHAN
# error
#endif
/* DRV8301 configuration */
#ifndef CONFIG_STM32_SPI3
# error
#endif
#define DRV8301_0_SPI (3)
#define DRV8301_1_SPI (3)
#define DRV8301_FREQUENCY (500000)
/* Qenco configuration */
#ifdef CONFIG_SENSORS_QENCODER
# ifndef CONFIG_STM32_QENCODER_DISABLE_EXTEND16BTIMERS
# error Invalid configuration
# endif
# ifndef CONFIG_STM32_QENCODER_INDEX_PIN
# error Invalid configuration
# endif
# ifdef CONFIG_STM32_TIM3_QE
# if CONFIG_STM32_TIM3_QEPSC != 0
# error Invalid TIM3 QEPSC value
# endif
# endif
# ifdef CONFIG_STM32_TIM4_QE
# if CONFIG_STM32_TIM4_QEPSC != 0
# error Invalid TIM4 QEPSC value
# endif
# endif
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Protototypes
****************************************************************************/
static int board_foc_setup(struct foc_dev_s *dev);
static int board_foc_shutdown(struct foc_dev_s *dev);
static int board_foc_calibration(struct foc_dev_s *dev, bool state);
static int board_foc_fault_clear(struct foc_dev_s *dev);
static int board_foc_pwm_start(struct foc_dev_s *dev, bool state);
static int board_foc_current_get(struct foc_dev_s *dev, int16_t *curr_raw,
foc_current_t *curr);
static int board_foc_info_get(struct foc_dev_s *dev,
struct foc_info_s *info);
static int board_foc_ioctl(struct foc_dev_s *dev, int cmd,
unsigned long arg);
#ifdef CONFIG_MOTOR_FOC_TRACE
static int board_foc_trace_init(struct foc_dev_s *dev);
static void board_foc_trace(struct foc_dev_s *dev, int type, bool state);
#endif
static int stm32_foc_drv8301_fault_attach(struct focpwr_dev_s *dev,
xcpt_t isr, void *arg);
static int stm32_foc_drv8301_gate_enable(struct focpwr_dev_s *dev,
bool enable);
static void stm32_foc_drv8301_fault_handle(struct focpwr_dev_s *dev);
static int stm32_focdev_setup(int devno, int spino,
struct stm32_foc_board_s *board);
/****************************************************************************
* Private Data
****************************************************************************/
/* Board specific ops */
static struct stm32_foc_board_ops_s g_stm32_foc_board_ops =
{
.setup = board_foc_setup,
.shutdown = board_foc_shutdown,
.calibration = board_foc_calibration,
.fault_clear = board_foc_fault_clear,
.pwm_start = board_foc_pwm_start,
.current_get = board_foc_current_get,
.info_get = board_foc_info_get,
.ioctl = board_foc_ioctl,
#ifdef CONFIG_MOTOR_FOC_TRACE
.trace_init = board_foc_trace_init,
.trace = board_foc_trace
#endif
};
/* Board specific ADC configuration
*
* AUX (only VBUS used):
* VBUS - ADC1 - ADC1_IN6 (PA6)
* M0_TEMP - ADC1 - ADC1_IN15 (PC5)
* M1_TEMP - ADC1 - ADC1_IN4 (PA4)
* AUX_TEMP - ADC1 - ADC1_IN5 (PA5)
*
* FOC device 0:
* Phase 1 - ADC2 - ADC2_IN10 (PC0)
* Phase 2 - ADC2 - ADC2_IN11 (PC1)
*
* FOC device 1:
* Phase 1 - ADC3 - ADC3_IN13 (PC3)
* Phase 2 - ADC3 - ADC3_IN12 (PC2)
*
*/
#ifdef CONFIG_ADC
/* AUX ADC configuration */
static uint8_t g_adc_aux_chan[] =
{
#ifdef CONFIG_ODRIVE_FOC_VBUS
6,
#endif
#ifdef ODRIVE_ADC_TEMP
15,
4,
5
#endif
};
static uint32_t g_adc_aux_pins[] =
{
#ifdef CONFIG_ODRIVE_FOC_VBUS
GPIO_ADC1_IN6,
#endif
#ifdef ODRIVE_ADC_TEMP
GPIO_ADC1_IN15,
GPIO_ADC1_IN4,
GPIO_ADC1_IN5
#endif
};
static adc_channel_t g_adc_aux_stime[] =
{
#ifdef CONFIG_ODRIVE_FOC_VBUS
{
.channel = 6,
.sample_time = VBUS_SAMPLE_TIME
},
#endif
#ifdef ODRIVE_ADC_TEMP
{
.channel = 15,
.sample_time = TEMP_SAMPLE_TIME
},
{
.channel = 4,
.sample_time = TEMP_SAMPLE_TIME
},
{
.channel = 5,
.sample_time = TEMP_SAMPLE_TIME
}
#endif
};
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC0
/* Board specific ADC configuration for FOC device 0 */
static uint8_t g_adc_foc0_chan[] =
{
10,
11
};
static uint32_t g_adc_foc0_pins[] =
{
GPIO_ADC2_IN10,
GPIO_ADC2_IN11,
};
static adc_channel_t g_adc_foc0_stime[] =
{
{
.channel = 10,
.sample_time = CURRENT_SAMPLE_TIME
},
{
.channel = 11,
.sample_time = CURRENT_SAMPLE_TIME
}
};
static struct stm32_foc_adc_s g_adc_foc0_cfg =
{
.chan = g_adc_foc0_chan,
.pins = g_adc_foc0_pins,
.stime = g_adc_foc0_stime,
.nchan = ADC2_NCHANNELS,
.regch = ADC2_REGULAR,
.intf = ODRIVE_ADC_FOC0
};
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC1
/* Board specific ADC configuration for FOC device 1 */
static uint8_t g_adc_foc1_chan[] =
{
13,
12
};
static uint32_t g_adc_foc1_pins[] =
{
GPIO_ADC3_IN13,
GPIO_ADC3_IN12,
};
static adc_channel_t g_adc_foc1_stime[] =
{
{
.channel = 13,
.sample_time = CURRENT_SAMPLE_TIME
},
{
.channel = 12,
.sample_time = CURRENT_SAMPLE_TIME
}
};
static struct stm32_foc_adc_s g_adc_foc1_cfg =
{
.chan = g_adc_foc1_chan,
.pins = g_adc_foc1_pins,
.stime = g_adc_foc1_stime,
.nchan = ADC3_NCHANNELS,
.regch = ADC3_REGULAR,
.intf = ODRIVE_ADC_FOC1
};
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC0
/* Board specific data - FOC 0 */
static struct stm32_foc_board_data_s g_stm32_foc0_board_data =
{
.adc_cfg = &g_adc_foc0_cfg,
.pwm_dt = (PWM_DEADTIME),
};
/* Board specific configuration */
static struct stm32_foc_board_s g_stm32_foc0_board =
{
.data = &g_stm32_foc0_board_data,
.ops = &g_stm32_foc_board_ops,
};
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC1
/* Board specific data - FOC 1 */
static struct stm32_foc_board_data_s g_stm32_foc1_board_data =
{
.adc_cfg = &g_adc_foc1_cfg,
.pwm_dt = (PWM_DEADTIME),
};
/* Board specific configuration */
static struct stm32_foc_board_s g_stm32_foc1_board =
{
.data = &g_stm32_foc1_board_data,
.ops = &g_stm32_foc_board_ops,
};
#endif
/* DRV8301 board ops */
static struct drv8301_ops_s g_drv8301_board_ops =
{
.fault_attach = stm32_foc_drv8301_fault_attach,
.gate_enable = stm32_foc_drv8301_gate_enable,
.fault_handle = stm32_foc_drv8301_fault_handle
};
/* Global data */
static mutex_t g_common_lock = NXMUTEX_INITIALIZER;
static bool g_fault_attached = false;
static bool g_gate_enabled = false;
static struct foc_dev_s *g_foc_dev[2] =
{
NULL,
NULL
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: board_foc_setup
****************************************************************************/
static int board_foc_setup(struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
DEBUGASSERT(dev->pwr);
return dev->pwr->ops->setup(dev->pwr);
}
/****************************************************************************
* Name: board_foc_shutdown
****************************************************************************/
static int board_foc_shutdown(struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
DEBUGASSERT(dev->pwr);
return dev->pwr->ops->shutdown(dev->pwr);
}
/****************************************************************************
* Name: board_foc_calibration
****************************************************************************/
static int board_foc_calibration(struct foc_dev_s *dev, bool state)
{
DEBUGASSERT(dev);
DEBUGASSERT(dev->pwr);
return dev->pwr->ops->calibration(dev->pwr, state);
}
/****************************************************************************
* Name: board_foc_fault_clear
****************************************************************************/
static int board_foc_fault_clear(struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
UNUSED(dev);
/* TODO: clear DRV8301 faults */
return OK;
}
/****************************************************************************
* Name: board_foc_pwm_start
****************************************************************************/
static int board_foc_pwm_start(struct foc_dev_s *dev, bool state)
{
DEBUGASSERT(dev);
return OK;
}
/****************************************************************************
* Name: board_foc_current_get
****************************************************************************/
static int board_foc_current_get(struct foc_dev_s *dev, int16_t *curr_raw,
foc_current_t *curr)
{
DEBUGASSERT(dev);
DEBUGASSERT(curr_raw);
DEBUGASSERT(curr);
/* Get currents */
curr[1] = curr_raw[0];
curr[2] = curr_raw[1];
/* From Kirchhoff's current law: ia = -(ib + ic) */
curr[0] = -(curr[1] + curr[2]);
return OK;
}
/****************************************************************************
* Name: board_foc_info_get
****************************************************************************/
static int board_foc_info_get(struct foc_dev_s *dev,
struct foc_info_s *info)
{
struct foc_get_boardcfg_s cfg;
DEBUGASSERT(dev);
DEBUGASSERT(info);
UNUSED(dev);
/* PWM */
info->hw_cfg.pwm_dt_ns = PWM_DEADTIME_NS;
info->hw_cfg.pwm_max = MAX_DUTY_B16;
/* Get power stage configuration */
board_foc_ioctl(dev, MTRIOC_GET_BOARDCFG, (unsigned long)&cfg);
/* ADC Current */
info->hw_cfg.iphase_max = 40000;
info->hw_cfg.iphase_scale = ((100000ul * (ADC_VOLT_REF / ADC_VAL_MAX)) /
(cfg.gain * R_SHUNT));
return OK;
}
/****************************************************************************
* Name: board_foc_ioctl
****************************************************************************/
static int board_foc_ioctl(struct foc_dev_s *dev, int cmd, unsigned long arg)
{
DEBUGASSERT(dev);
DEBUGASSERT(dev->pwr);
return dev->pwr->ops->ioctl(dev->pwr, cmd, arg);
}
#ifdef CONFIG_MOTOR_FOC_TRACE
/****************************************************************************
* Name: board_foc_trace_init
****************************************************************************/
static int board_foc_trace_init(struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
UNUSED(dev);
/* Not supported */
return -1;
}
/****************************************************************************
* Name: board_foc_trace
****************************************************************************/
static void board_foc_trace(struct foc_dev_s *dev, int type, bool state)
{
DEBUGASSERT(dev);
UNUSED(dev);
}
#endif
/****************************************************************************
* Name: stm32_foc_drv8301_fault_attach
****************************************************************************/
static int stm32_foc_drv8301_fault_attach(struct focpwr_dev_s *dev,
xcpt_t isr, void *arg)
{
int ret = OK;
nxmutex_lock(&g_common_lock);
/* nFAULT is common for both FOC instances */
if (g_fault_attached != (bool) isr)
{
ret = stm32_gpiosetevent(GPIO_DRV8301_NFAULT, false, true, false,
isr, arg);
g_fault_attached = (bool) isr;
}
nxmutex_unlock(&g_common_lock);
return ret;
}
/****************************************************************************
* Name: stm32_foc_drv8301_gate_enable
****************************************************************************/
static int stm32_foc_drv8301_gate_enable(struct focpwr_dev_s *dev,
bool enable)
{
/* ENGATE is common for both FOC instances */
nxmutex_lock(&g_common_lock);
if (enable != g_gate_enabled)
{
stm32_gpiowrite(GPIO_DRV8301_ENGATE, enable);
g_gate_enabled = enable;
}
nxmutex_unlock(&g_common_lock);
return OK;
}
/****************************************************************************
* Name: stm32_foc_drv8301_fault_handle
****************************************************************************/
static void stm32_foc_drv8301_fault_handle(struct focpwr_dev_s *dev)
{
UNUSED(dev);
/* Set fault state for both instances */
#ifdef CONFIG_ODRIVE_FOC_FOC0
g_foc_dev[0]->state.fault |= FOC_FAULT_BOARD;
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC1
g_foc_dev[1]->state.fault |= FOC_FAULT_BOARD;
#endif
/* Disable gates for both instances */
stm32_gpiowrite(GPIO_DRV8301_ENGATE, false);
}
/****************************************************************************
* Name: stm32_focdev_setup
****************************************************************************/
static int stm32_focdev_setup(int devno, int spino,
struct stm32_foc_board_s *board)
{
struct drv8301_cfg_s drv8301_cfg;
struct drv8301_board_s drv8301_board;
struct spi_dev_s *spi = NULL;
struct foc_dev_s *foc = NULL;
int ret = OK;
char devpath[20];
/* Initialize arch specific FOC 0 lower-half */
foc = stm32_foc_initialize(devno, board);
if (foc == NULL)
{
ret = -errno;
mtrerr("Failed to initialize STM32 FOC: %d\n", ret);
goto errout;
}
DEBUGASSERT(foc->lower);
/* Get devpath */
snprintf(devpath, sizeof(devpath), "/dev/foc%d", devno);
/* Get SPI device */
spi = stm32_spibus_initialize(spino);
if (spi == NULL)
{
ret = -errno;
goto errout;
}
/* DRV8301 configuration */
drv8301_cfg.freq = DRV8301_FREQUENCY;
drv8301_cfg.gate_curr = DRV8301_GATECURR_1p7;
drv8301_cfg.gain = DRV8301_GAIN_80;
drv8301_cfg.pwm_mode = DRV8301_PWM_6IN;
drv8301_cfg.oc_adj = DRV8301_OCADJ_DEFAULT;
/* DRV8301 board data */
drv8301_board.spi = spi;
drv8301_board.ops = &g_drv8301_board_ops;
drv8301_board.cfg = &drv8301_cfg;
drv8301_board.devno = devno;
/* Register DRV8301 device */
ret = drv8301_register(devpath, foc, &drv8301_board);
if (ret < 0)
{
mtrerr("Failed to register drv8301 device: %d\n", ret);
goto errout;
}
errout:
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_foc_setup
*
* Description:
* Setup FOC devices
*
* This function should be call by board_app_initialize().
*
* Returned Value:
* 0 on success, a negated errno value on failure
*
****************************************************************************/
int stm32_foc_setup(void)
{
int ret = OK;
/* Configure common EN_GATE */
stm32_configgpio(GPIO_DRV8301_ENGATE);
#ifdef CONFIG_ODRIVE_FOC_FOC0
ret = stm32_focdev_setup(0, DRV8301_0_SPI, &g_stm32_foc0_board);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: stm32_focdev_setup 0 failed: %d\n", ret);
goto errout;
}
#endif
#ifdef CONFIG_ODRIVE_FOC_FOC1
ret = stm32_focdev_setup(1, DRV8301_1_SPI, &g_stm32_foc1_board);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: stm32_focdev_setup 1 failed: %d\n", ret);
goto errout;
}
#endif
errout:
return ret;
}
#ifdef CONFIG_ADC
/****************************************************************************
* Name: stm32_adc_setup
*
* Description:
* Initialize ADC and register the ADC driver.
*
****************************************************************************/
int stm32_adc_setup(void)
{
struct adc_dev_s *adc = NULL;
struct stm32_adc_dev_s *stm32_adc = NULL;
struct adc_sample_time_s stime;
int i = 0;
int ret = OK;
/* Configure pins */
for (i = 0; i < ODRIVE_ADC_AUX_NCHAN; i += 1)
{
stm32_configgpio(g_adc_aux_pins[i]);
}
/* Initialize ADC */
adc = stm32_adcinitialize(ODRIVE_ADC_AUX, g_adc_aux_chan,
ODRIVE_ADC_AUX_NCHAN);
if (adc == NULL)
{
aerr("ERROR: Failed to get ADC interface %d\n", ODRIVE_ADC_AUX);
ret = -ENODEV;
goto errout;
}
/* Regsiter ADC */
ret = adc_register(ODRIVE_ADC_AUX_DEVPATH, adc);
if (ret < 0)
{
aerr("ERROR: adc_register %s failed: %d\n",
ODRIVE_ADC_AUX_DEVPATH, ret);
goto errout;
}
/* Get lower-half ADC */
stm32_adc = (struct stm32_adc_dev_s *)adc->ad_priv;
DEBUGASSERT(stm32_adc);
/* Configure ADC sample time */
memset(&stime, 0, sizeof(struct adc_sample_time_s));
stime.channels_nbr = ODRIVE_ADC_AUX_NCHAN;
stime.channel = g_adc_aux_stime;
STM32_ADC_SAMPLETIME_SET(stm32_adc, &stime);
STM32_ADC_SAMPLETIME_WRITE(stm32_adc);
ret = OK;
errout:
return ret;
}
#endif