nuttx/drivers/motor/foc/foc_dummy.c

714 lines
18 KiB
C

/****************************************************************************
* drivers/motor/foc/foc_dummy.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 <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/motor/foc/foc_dummy.h>
#include <nuttx/motor/foc/foc_lower.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_MOTOR_FOC
# error Upper-half FOC driver must be enabled
#endif
/* Board HW configuration */
#define FOC_DUMMY_HW_PWM_NS (500)
#define FOC_DUMMY_HW_PWM_MAX (0.95f)
#define FOC_DUMMY_HW_BEMF_SCALE (1000)
#define FOC_DUMMY_HW_IPHASE_SCALE (1000)
#define FOC_DUMMY_HW_IPHASE_MAX (40000)
/* Helper macros ************************************************************/
#define FOC_DUMMY_DATA_FROM_DEV_GET(d) \
((FAR struct foc_dummy_data_s *)(d)->lower->data)
/****************************************************************************
* Private Types
****************************************************************************/
/* SIM FOC board data */
struct foc_dummy_board_s
{
uint32_t reserved;
};
/* SIM FOC specific data */
struct foc_dummy_data_s
{
/* Upper-half FOC controller callbacks */
FAR const struct foc_callbacks_s *cb;
/* SIM FOC board data */
FAR struct foc_dummy_board_s *board;
/* Phase currents */
foc_current_t current[CONFIG_MOTOR_FOC_PHASES];
#ifdef CONFIG_MOTOR_FOC_BEMF_SENSE
/* BEMF voltage */
foc_voltage_t volt[CONFIG_MOTOR_FOC_PHASES];
#endif
/* FOC worker loop helpers */
bool state;
uint32_t notifier_cntr;
uint32_t pwm_freq;
uint32_t notifier_freq;
uint32_t notifier_div;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Lower-half FOC operations */
static int foc_dummy_configure(FAR struct foc_dev_s *dev,
FAR struct foc_cfg_s *cfg);
static int foc_dummy_setup(FAR struct foc_dev_s *dev);
static int foc_dummy_shutdown(FAR struct foc_dev_s *dev);
static int foc_dummy_start(FAR struct foc_dev_s *dev, bool state);
static int foc_dummy_pwm_duty_set(FAR struct foc_dev_s *dev,
FAR foc_duty_t *duty);
static int foc_dummy_pwm_off(FAR struct foc_dev_s *dev, bool off);
static int foc_dummy_info_get(FAR struct foc_dev_s *dev,
FAR struct foc_info_s *info);
static int foc_dummy_ioctl(FAR struct foc_dev_s *dev, int cmd,
unsigned long arg);
static int foc_dummy_bind(FAR struct foc_dev_s *dev,
FAR struct foc_callbacks_s *cb);
static int foc_dummy_fault_clear(FAR struct foc_dev_s *dev);
#ifdef CONFIG_MOTOR_FOC_TRACE
static void foc_dummy_trace(FAR struct foc_dev_s *dev, int type, bool state);
#endif
/* Handlers */
static void foc_dummy_notifier_handler(FAR struct foc_dev_s *dev);
/* Helpers */
static int foc_dummy_notifier_cfg(FAR struct foc_dev_s *dev, uint32_t freq);
static int foc_dummy_pwm_setup(FAR struct foc_dev_s *dev, uint32_t freq);
static int foc_dummy_pwm_start(FAR struct foc_dev_s *dev, bool state);
static int foc_dummy_adc_setup(FAR struct foc_dev_s *dev);
static int foc_dummy_adc_start(FAR struct foc_dev_s *dev, bool state);
/****************************************************************************
* Private Data
****************************************************************************/
/* SIM FOC specific data */
static struct foc_dummy_data_s g_foc_dummy_data[CONFIG_MOTOR_FOC_INST];
static struct foc_dummy_board_s g_foc_dummy_board[CONFIG_MOTOR_FOC_INST];
/* SIM specific FOC ops */
static struct foc_lower_ops_s g_foc_dummy_ops =
{
foc_dummy_configure,
foc_dummy_setup,
foc_dummy_shutdown,
foc_dummy_pwm_duty_set,
foc_dummy_pwm_off,
foc_dummy_start,
foc_dummy_info_get,
foc_dummy_ioctl,
foc_dummy_bind,
foc_dummy_fault_clear,
#ifdef CONFIG_MOTOR_FOC_TRACE
foc_dummy_trace
#endif
};
/* FOC lower-half */
static struct foc_lower_s g_foc_dummy_lower[CONFIG_MOTOR_FOC_INST];
/* FOC upper-half device data */
static struct foc_dev_s g_foc_dev[CONFIG_MOTOR_FOC_INST];
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: foc_dummy_pwm_setup
*
* Description:
* Setup PWM for FOC controller
*
****************************************************************************/
static int foc_dummy_pwm_setup(FAR struct foc_dev_s *dev, uint32_t freq)
{
FAR struct foc_dummy_data_s *sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
DEBUGASSERT(dev);
DEBUGASSERT(sim);
mtrinfo("[PWM_SETUP] freq=%d\n", freq);
DEBUGASSERT(freq > 0);
/* Store frequency */
sim->pwm_freq = freq;
return OK;
}
/****************************************************************************
* Name: foc_dummy_start
*
* Description:
* Start/stop PWM for the FOC controller
*
****************************************************************************/
static int foc_dummy_start(FAR struct foc_dev_s *dev, bool state)
{
FAR struct foc_dummy_data_s *sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
irqstate_t flags;
int ret = OK;
mtrinfo("[FOC_START] state=%d\n", state);
/* Start PWM */
ret = foc_dummy_pwm_start(dev, state);
if (ret < 0)
{
mtrerr("foc_dummy_pwm_start failed %d\n", ret);
goto errout;
}
/* Start ADC */
ret = foc_dummy_adc_start(dev, state);
if (ret < 0)
{
mtrerr("foc_dummy_adc_start failed %d\n", ret);
goto errout;
}
/* Store FOC worker state */
flags = enter_critical_section();
sim->state = state;
leave_critical_section(flags);
errout:
return ret;
}
/****************************************************************************
* Name: foc_dummy_pwm_start
*
* Description:
* Start/stop PWM for the FOC controller
*
****************************************************************************/
static int foc_dummy_pwm_start(FAR struct foc_dev_s *dev, bool state)
{
DEBUGASSERT(dev);
mtrinfo("[PWM_START] state=%d\n", state);
return OK;
}
/****************************************************************************
* Name: foc_dummy_adc_setup
*
* Description:
* Setup ADC for the FOC controller
*
****************************************************************************/
static int foc_dummy_adc_setup(FAR struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
mtrinfo("[ADC_SETUP]\n");
return OK;
}
/****************************************************************************
* Name: foc_dummy_adc_start
*
* Description:
* Start/stop ADC conversion for the FOC controller
*
****************************************************************************/
static int foc_dummy_adc_start(FAR struct foc_dev_s *dev, bool state)
{
DEBUGASSERT(dev);
mtrinfo("[ADC_START] state=%d\n", state);
return OK;
}
/****************************************************************************
* Name: foc_dummy_notifier_cfg
*
* Description:
* Configure FOC notifier
*
****************************************************************************/
static int foc_dummy_notifier_cfg(FAR struct foc_dev_s *dev, uint32_t freq)
{
FAR struct foc_dummy_data_s *sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
int ret = OK;
DEBUGASSERT(dev);
DEBUGASSERT(sim);
mtrinfo("[NOTIFIER_CFG] freq=%d\n", freq);
DEBUGASSERT(freq > 0);
if (sim->pwm_freq % freq != 0)
{
ret = -EINVAL;
goto errout;
}
/* Call FOC notifier on every update */
sim->notifier_freq = freq;
sim->notifier_div = 1;
errout:
return ret;
}
/****************************************************************************
* Name: foc_dummy_configure
*
* Description:
* Arch-specific FOC controller configuration
*
****************************************************************************/
static int foc_dummy_configure(FAR struct foc_dev_s *dev,
FAR struct foc_cfg_s *cfg)
{
FAR struct foc_dummy_data_s *sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
int ret = OK;
DEBUGASSERT(dev);
DEBUGASSERT(sim);
DEBUGASSERT(cfg->pwm_freq > 0);
DEBUGASSERT(cfg->notifier_freq > 0);
mtrinfo("[FOC_SETUP]\n");
/* Configure ADC */
ret = foc_dummy_adc_setup(dev);
if (ret < 0)
{
mtrerr("foc_dummy_adc_setup failed %d\n", ret);
goto errout;
}
/* Configure PWM */
ret = foc_dummy_pwm_setup(dev, cfg->pwm_freq);
if (ret < 0)
{
mtrerr("foc_dummy_pwm_setup failed %d\n", ret);
goto errout;
}
/* Configure notifier */
ret = foc_dummy_notifier_cfg(dev, cfg->notifier_freq);
if (ret < 0)
{
mtrerr("foc_dummy_notifier_cfg failed %d\n", ret);
goto errout;
}
/* Reset some data */
sim->notifier_cntr = 0;
errout:
return ret;
}
/****************************************************************************
* Name: foc_dummy_setup
*
* Description:
* Arch-specific FOC controller setup
*
****************************************************************************/
static int foc_dummy_setup(FAR struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
mtrinfo("[FOC_SETUP]\n");
return OK;
}
/****************************************************************************
* Name: foc_dummy_shutdown
*
* Description:
* Arch-specific FOC controller shutdown
*
****************************************************************************/
static int foc_dummy_shutdown(FAR struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
mtrinfo("[FOC_SHUTDOWN]\n");
return OK;
}
/****************************************************************************
* Name: foc_dummy_ioctl
*
* Description:
* Arch-specific FOC controller ioctl
*
****************************************************************************/
static int foc_dummy_ioctl(FAR struct foc_dev_s *dev, int cmd,
unsigned long arg)
{
int ret = OK;
DEBUGASSERT(dev);
mtrinfo("[FOC_IOCTL]cmd=%d\n", cmd);
switch (cmd)
{
default:
{
ret = -1;
break;
}
}
return ret;
}
/****************************************************************************
* Name: foc_dummy_notifier_handler
*
* Description:
* Handle ADC conversion and notofiy user-space
*
****************************************************************************/
static void foc_dummy_notifier_handler(FAR struct foc_dev_s *dev)
{
FAR struct foc_dummy_data_s *sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
DEBUGASSERT(dev);
DEBUGASSERT(sim);
mtrinfo("[FOC_NOTIFIER_HANDLER] cntr=%d\n", sim->notifier_cntr);
/* Call FOC notifier handler */
if (sim->notifier_cntr % sim->notifier_div == 0)
{
/* Call FOC notifier */
#ifdef CONFIG_MOTOR_FOC_BEMF_SENSE
sim->cb->notifier(dev, sim->current, sim->volt);
#else
sim->cb->notifier(dev, sim->current, NULL);
#endif
}
/* Increase counter */
sim->notifier_cntr += 1;
}
/****************************************************************************
* Name: sim_duty_set
*
* Description:
* Set 3-phase PWM duty cycle
*
****************************************************************************/
static int foc_dummy_pwm_duty_set(FAR struct foc_dev_s *dev,
FAR foc_duty_t *duty)
{
int i = 0;
DEBUGASSERT(dev);
DEBUGASSERT(duty);
for (i = 0; i < CONFIG_MOTOR_FOC_PHASES; i += 1)
{
DEBUGASSERT(duty[i] >= 0);
}
mtrinfo("[PWM_DUTY_SET]\n");
#if CONFIG_MOTOR_FOC_PHASES == 2
mtrinfo("[%d %d]\n", duty[0], duty[1]);
#elif CONFIG_MOTOR_FOC_PHASES == 3
mtrinfo("[%d %d %d]\n", duty[0], duty[1], duty[2]);
#elif CONFIG_MOTOR_FOC_PHASES == 4
mtrinfo("[%d %d %d %d]\n", duty[0], duty[1], duty[2], duty[3]);
#else
# error
#endif
return OK;
}
/****************************************************************************
* Name: foc_dummy_pwm_off
*
* Description:
* Set the 3-phase bridge switches in off state.
*
****************************************************************************/
static int foc_dummy_pwm_off(FAR struct foc_dev_s *dev, bool off)
{
mtrinfo("[PWM_OFF] %d\n", off);
return OK;
}
/****************************************************************************
* Name: foc_dummy_info_get
*
* Description:
* Get HW configuration for FOC device
*
****************************************************************************/
static int foc_dummy_info_get(FAR struct foc_dev_s *dev,
FAR struct foc_info_s *info)
{
/* Get HW configuration */
info->hw_cfg.pwm_dt_ns = FOC_DUMMY_HW_PWM_NS;
info->hw_cfg.pwm_max = ftob16(FOC_DUMMY_HW_PWM_MAX);
#ifdef CONFIG_MOTOR_FOC_BEMF_SENSE
info->hw_cfg.bemf_scale = FOC_DUMMY_HW_IPHASE_SCALE;
#endif
info->hw_cfg.iphase_max = FOC_DUMMY_HW_IPHASE_MAX;
info->hw_cfg.iphase_scale = FOC_DUMMY_HW_IPHASE_SCALE;
return OK;
}
/****************************************************************************
* Name: foc_dummy_bind
*
* Description:
* Bind lower-half FOC controller with upper-half FOC logic
*
****************************************************************************/
static int foc_dummy_bind(FAR struct foc_dev_s *dev,
FAR struct foc_callbacks_s *cb)
{
FAR struct foc_dummy_data_s *sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
int ret = OK;
DEBUGASSERT(dev);
DEBUGASSERT(cb);
DEBUGASSERT(sim);
mtrinfo("[FOC_BIND]\n");
/* Bind upper-half FOC controller callbacks */
sim->cb = cb;
return ret;
}
/****************************************************************************
* Name: foc_dummy_fault_clear
*
* Description:
* Arch-specific fault clear
*
****************************************************************************/
static int foc_dummy_fault_clear(FAR struct foc_dev_s *dev)
{
DEBUGASSERT(dev);
mtrinfo("[FAULT_CLEAR]\n");
return OK;
}
#ifdef CONFIG_MOTOR_FOC_TRACE
/****************************************************************************
* Name: foc_dummy_trace
*
* Description:
* SIM FOC trace
*
****************************************************************************/
static void foc_dummy_trace(FAR struct foc_dev_s *dev, int type, bool state)
{
DEBUGASSERT(dev);
mtrinfo("[FOC_TRACE] type=%d state=%d\n", type, state);
}
#endif /* CONFIG_MOTOR_FOC_TRACE */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: foc_dummy_initialize
*
* Description:
* Initialize the FOC controller lower-half support.
*
****************************************************************************/
FAR struct foc_dev_s *foc_dummy_initialize(int inst)
{
FAR struct foc_lower_s *foc_lower = NULL;
FAR struct foc_dev_s *dev = NULL;
mtrinfo("[FOC_INITIALIZE] inst=%d\n", inst);
/* Reset data */
memset(&g_foc_dummy_data[inst], 0, sizeof(struct foc_dummy_data_s));
/* Get SIM FOC arch-specific driver */
foc_lower = &g_foc_dummy_lower[inst];
/* Connect ops, data and dev with arch-specific FOC driver */
foc_lower->data = &g_foc_dummy_data[inst];
foc_lower->ops = &g_foc_dummy_ops;
/* Connect board data */
g_foc_dummy_data[inst].board = &g_foc_dummy_board[inst];
/* Get FOC device */
dev = &g_foc_dev[inst];
/* Connect lower half FOC with FOC device */
dev->lower = (FAR void *)foc_lower;
/* Return lower-half driver instance */
return dev;
}
/****************************************************************************
* Name: foc_dummy_update
*
* Description:
* Called periodically from the IDLE loop to simulate FOC driver interrupts
*
****************************************************************************/
void foc_dummy_update(void)
{
FAR struct foc_dev_s *dev = NULL;
FAR struct foc_dummy_data_s *sim = NULL;
int i = 0;
irqstate_t flags;
flags = enter_critical_section();
/* Update all FOC instances */
for (i = 0; i < CONFIG_MOTOR_FOC_INST; i += 1)
{
/* Get FOC device */
dev = &g_foc_dev[i];
/* Update dummy driver state only if device opened */
if (dev->ocount > 0)
{
/* Get SIM data */
sim = FOC_DUMMY_DATA_FROM_DEV_GET(dev);
if (sim->state == true)
{
foc_dummy_notifier_handler(dev);
}
}
}
leave_critical_section(flags);
}