/**************************************************************************** * 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 #include #include #include #include #include #include #include #include /**************************************************************************** * 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); }