arch/arm/src/stm32/stm32_foc.c: add workaround for an issue found in STM32G4 family
From G4 erratas: "ADC channel 0 converted instead of the required ADC channel"
This commit is contained in:
parent
7c47f32a19
commit
d76f8ea04a
@ -10902,4 +10902,19 @@ config STM32_FOC_USE_ADC4
|
|||||||
select STM32_ADC4
|
select STM32_ADC4
|
||||||
select STM32_ADC3_JEXTSEL
|
select STM32_ADC3_JEXTSEL
|
||||||
|
|
||||||
|
config STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
bool "FOC G4 ADC channel 0 unwanted conversion workaround"
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
Some STM32G4 family chips have an issue that causes unwanted ADC channel 0
|
||||||
|
conversion when a regular conversion is interrupted by an injected conversion.
|
||||||
|
This FOC implementation uses injected conversion to sample phase currents
|
||||||
|
and allows user to use regular conversion as an auxiliary analog conversion.
|
||||||
|
In this case, there is a certain probability that regular conversion will be
|
||||||
|
interrupted by an injected conversion that will lead to an incorrect reading
|
||||||
|
of phase currents.
|
||||||
|
|
||||||
|
This workaround inserts a dummy conversion at the beginning of the injected
|
||||||
|
sequence. For more details look at the chip errata documents.
|
||||||
|
|
||||||
endif #STM32_FOC
|
endif #STM32_FOC
|
||||||
|
@ -377,6 +377,14 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The number of required injected channels */
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
# define FOC_ADC_INJ_CHAN_REQUIRED (CONFIG_MOTOR_FOC_SHUNTS + 1)
|
||||||
|
#else
|
||||||
|
# define FOC_ADC_INJ_CHAN_REQUIRED (CONFIG_MOTOR_FOC_SHUNTS)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Validate ADC configuration:
|
/* Validate ADC configuration:
|
||||||
* 1. ADC must be supported by chip,
|
* 1. ADC must be supported by chip,
|
||||||
* 2. ADC support for injected channels must be enabled,
|
* 2. ADC support for injected channels must be enabled,
|
||||||
@ -393,7 +401,7 @@
|
|||||||
# if CONFIG_STM32_ADC1_ANIOC_TRIGGER != 1
|
# if CONFIG_STM32_ADC1_ANIOC_TRIGGER != 1
|
||||||
# error CONFIG_STM32_ADC1_ANIOC_TRIGGER must be 1
|
# error CONFIG_STM32_ADC1_ANIOC_TRIGGER must be 1
|
||||||
# endif
|
# endif
|
||||||
# if CONFIG_STM32_ADC1_INJECTED_CHAN != CONFIG_MOTOR_FOC_SHUNTS
|
# if CONFIG_STM32_ADC1_INJECTED_CHAN != FOC_ADC_INJ_CHAN_REQUIRED
|
||||||
# error Invalid configuration for ADC1 injected channles
|
# error Invalid configuration for ADC1 injected channles
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -407,7 +415,7 @@
|
|||||||
# if CONFIG_STM32_ADC2_ANIOC_TRIGGER != 1
|
# if CONFIG_STM32_ADC2_ANIOC_TRIGGER != 1
|
||||||
# error CONFIG_STM32_ADC2_ANIOC_TRIGGER must be 1
|
# error CONFIG_STM32_ADC2_ANIOC_TRIGGER must be 1
|
||||||
# endif
|
# endif
|
||||||
# if CONFIG_STM32_ADC2_INJECTED_CHAN != CONFIG_MOTOR_FOC_SHUNTS
|
# if CONFIG_STM32_ADC2_INJECTED_CHAN != FOC_ADC_INJ_CHAN_REQUIRED
|
||||||
# error Invalid configuration for ADC2 injected channles
|
# error Invalid configuration for ADC2 injected channles
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -421,7 +429,7 @@
|
|||||||
# if CONFIG_STM32_ADC3_ANIOC_TRIGGER != 1
|
# if CONFIG_STM32_ADC3_ANIOC_TRIGGER != 1
|
||||||
# error CONFIG_STM32_ADC3_ANIOC_TRIGGER must be 1
|
# error CONFIG_STM32_ADC3_ANIOC_TRIGGER must be 1
|
||||||
# endif
|
# endif
|
||||||
# if CONFIG_STM32_ADC3_INJECTED_CHAN != CONFIG_MOTOR_FOC_SHUNTS
|
# if CONFIG_STM32_ADC3_INJECTED_CHAN != FOC_ADC_INJ_CHAN_REQUIRED
|
||||||
# error Invalid configuration for ADC3 injected channles
|
# error Invalid configuration for ADC3 injected channles
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -435,11 +443,19 @@
|
|||||||
# if CONFIG_STM32_ADC4_ANIOC_TRIGGER != 1
|
# if CONFIG_STM32_ADC4_ANIOC_TRIGGER != 1
|
||||||
# error CONFIG_STM32_ADC4_ANIOC_TRIGGER must be 1
|
# error CONFIG_STM32_ADC4_ANIOC_TRIGGER must be 1
|
||||||
# endif
|
# endif
|
||||||
# if CONFIG_STM32_ADC4_INJECTED_CHAN != CONFIG_MOTOR_FOC_SHUNTS
|
# if CONFIG_STM32_ADC4_INJECTED_CHAN != FOC_ADC_INJ_CHAN_REQUIRED
|
||||||
# error Invalid configuration for ADC4 injected channles
|
# error Invalid configuration for ADC4 injected channles
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Max 3 shunts supported if STM32G4 ADC CHAN0 workaround enabled */
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
# if CONFIG_MOTOR_FOC_SHUNTS > 3
|
||||||
|
# error
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Combine JEXTSEL with JEXTEN default */
|
/* Combine JEXTSEL with JEXTEN default */
|
||||||
|
|
||||||
#ifdef CONFIG_STM32_FOC_FOC0
|
#ifdef CONFIG_STM32_FOC_FOC0
|
||||||
@ -767,6 +783,8 @@ static int stm32_foc_worker_handler(FAR struct foc_dev_s *dev);
|
|||||||
|
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
|
|
||||||
|
static void stm32_foc_curr_get(FAR struct foc_dev_s *dev,
|
||||||
|
FAR int16_t *curr, int shunts);
|
||||||
static int stm32_foc_notifier_cfg(FAR struct foc_dev_s *dev, uint32_t freq);
|
static int stm32_foc_notifier_cfg(FAR struct foc_dev_s *dev, uint32_t freq);
|
||||||
static int stm32_foc_pwm_cfg(FAR struct foc_dev_s *dev, uint32_t freq);
|
static int stm32_foc_pwm_cfg(FAR struct foc_dev_s *dev, uint32_t freq);
|
||||||
static int stm32_foc_adc_cfg(FAR struct foc_dev_s *dev);
|
static int stm32_foc_adc_cfg(FAR struct foc_dev_s *dev);
|
||||||
@ -1521,21 +1539,16 @@ static int stm32_foc_ioctl(FAR struct foc_dev_s *dev, int cmd,
|
|||||||
static int stm32_foc_adc_calibration_handler(FAR struct foc_dev_s *dev)
|
static int stm32_foc_adc_calibration_handler(FAR struct foc_dev_s *dev)
|
||||||
{
|
{
|
||||||
FAR struct stm32_foc_priv_s *priv = STM32_FOC_PRIV_FROM_DEV_GET(dev);
|
FAR struct stm32_foc_priv_s *priv = STM32_FOC_PRIV_FROM_DEV_GET(dev);
|
||||||
FAR struct stm32_adc_dev_s *adc = ADC_FROM_FOC_DEV_GET(dev);
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
DEBUGASSERT(dev);
|
DEBUGASSERT(dev);
|
||||||
DEBUGASSERT(priv);
|
DEBUGASSERT(priv);
|
||||||
DEBUGASSERT(adc);
|
|
||||||
|
|
||||||
if (priv->data.adcint_cntr < CAL_SAMPLES)
|
if (priv->data.adcint_cntr < CAL_SAMPLES)
|
||||||
{
|
{
|
||||||
/* Get raw currents */
|
/* Get raw current samples */
|
||||||
|
|
||||||
for (i = 0; i < CONFIG_MOTOR_FOC_SHUNTS; i += 1)
|
stm32_foc_curr_get(dev, priv->data.curr_raw, CONFIG_MOTOR_FOC_SHUNTS);
|
||||||
{
|
|
||||||
priv->data.curr_raw[i] = (int16_t)STM32_ADC_INJDATA_GET(adc, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get sum */
|
/* Get sum */
|
||||||
|
|
||||||
@ -1677,7 +1690,6 @@ static int stm32_foc_worker_handler(FAR struct foc_dev_s *dev)
|
|||||||
FAR struct stm32_foc_priv_s *priv = STM32_FOC_PRIV_FROM_DEV_GET(dev);
|
FAR struct stm32_foc_priv_s *priv = STM32_FOC_PRIV_FROM_DEV_GET(dev);
|
||||||
FAR struct stm32_foc_board_s *board = STM32_FOC_BOARD_FROM_DEV_GET(dev);
|
FAR struct stm32_foc_board_s *board = STM32_FOC_BOARD_FROM_DEV_GET(dev);
|
||||||
FAR struct stm32_adc_dev_s *adc = ADC_FROM_FOC_DEV_GET(dev);
|
FAR struct stm32_adc_dev_s *adc = ADC_FROM_FOC_DEV_GET(dev);
|
||||||
int i = 0;
|
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
||||||
DEBUGASSERT(dev);
|
DEBUGASSERT(dev);
|
||||||
@ -1689,16 +1701,9 @@ static int stm32_foc_worker_handler(FAR struct foc_dev_s *dev)
|
|||||||
|
|
||||||
if (priv->data.adcint_cntr % priv->data.notifier_div == 0)
|
if (priv->data.adcint_cntr % priv->data.notifier_div == 0)
|
||||||
{
|
{
|
||||||
for (i = 0; i < CONFIG_MOTOR_FOC_SHUNTS; i += 1)
|
/* Get raw current samples */
|
||||||
{
|
|
||||||
/* Get raw current samples.
|
|
||||||
* We have ADC offset enabled for injected channels so this
|
|
||||||
* gives us signed values.
|
|
||||||
* NOTE: ADC value is 11 bits + sign.
|
|
||||||
*/
|
|
||||||
|
|
||||||
priv->data.curr_raw[i] = (int16_t)STM32_ADC_INJDATA_GET(adc, i);
|
stm32_foc_curr_get(dev, priv->data.curr_raw, CONFIG_MOTOR_FOC_SHUNTS);
|
||||||
}
|
|
||||||
|
|
||||||
/* Get phase currents */
|
/* Get phase currents */
|
||||||
|
|
||||||
@ -1922,6 +1927,44 @@ static void stm32_foc_hw_config_get(FAR struct foc_dev_s *dev)
|
|||||||
dev->info.hw_cfg.pwm_max = board->data->duty_max;
|
dev->info.hw_cfg.pwm_max = board->data->duty_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_foc_curr_get
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Get current samples from ADC
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void stm32_foc_curr_get(FAR struct foc_dev_s *dev,
|
||||||
|
FAR int16_t *curr, int shunts)
|
||||||
|
{
|
||||||
|
FAR struct stm32_foc_priv_s *priv = STM32_FOC_PRIV_FROM_DEV_GET(dev);
|
||||||
|
FAR struct stm32_adc_dev_s *adc = ADC_FROM_FOC_DEV_GET(dev);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
DEBUGASSERT(dev);
|
||||||
|
DEBUGASSERT(priv);
|
||||||
|
DEBUGASSERT(adc);
|
||||||
|
DEBUGASSERT(curr);
|
||||||
|
|
||||||
|
for (i = 0; i < shunts; i += 1)
|
||||||
|
{
|
||||||
|
/* Get raw current samples.
|
||||||
|
* We have ADC offset enabled for injected channels so this
|
||||||
|
* gives us signed values.
|
||||||
|
* NOTE: ADC value is 11 bits + sign.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
/* Ignore first channel */
|
||||||
|
|
||||||
|
curr[i] = (int16_t)STM32_ADC_INJDATA_GET(adc, (i + 1));
|
||||||
|
#else
|
||||||
|
curr[i] = (int16_t)STM32_ADC_INJDATA_GET(adc, i);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: stm32_foc_notifier_cfg
|
* Name: stm32_foc_notifier_cfg
|
||||||
*
|
*
|
||||||
@ -2112,7 +2155,11 @@ stm32_foc_initialize(int inst, FAR struct stm32_foc_board_s *board)
|
|||||||
uint8_t pwm_inst = 0;
|
uint8_t pwm_inst = 0;
|
||||||
uint8_t adc_inst = 0;
|
uint8_t adc_inst = 0;
|
||||||
uint32_t pwmfzbit = 0;
|
uint32_t pwmfzbit = 0;
|
||||||
int j = 0;
|
int i = 0;
|
||||||
|
#ifdef CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
FAR uint8_t *adc_chan = NULL;
|
||||||
|
uint8_t adc_nchan = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
DEBUGASSERT(board != NULL);
|
DEBUGASSERT(board != NULL);
|
||||||
DEBUGASSERT(board->ops != NULL);
|
DEBUGASSERT(board->ops != NULL);
|
||||||
@ -2237,9 +2284,9 @@ stm32_foc_initialize(int inst, FAR struct stm32_foc_board_s *board)
|
|||||||
DEBUGASSERT(adc_cfg->pins != NULL);
|
DEBUGASSERT(adc_cfg->pins != NULL);
|
||||||
DEBUGASSERT(adc_cfg->chan != NULL);
|
DEBUGASSERT(adc_cfg->chan != NULL);
|
||||||
|
|
||||||
for (j = 0; j < adc_cfg->nchan; j++)
|
for (i = 0; i < adc_cfg->nchan; i++)
|
||||||
{
|
{
|
||||||
stm32_configgpio(adc_cfg->pins[j]);
|
stm32_configgpio(adc_cfg->pins[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that we are using the appropriate ADC interface */
|
/* Make sure that we are using the appropriate ADC interface */
|
||||||
@ -2252,11 +2299,55 @@ stm32_foc_initialize(int inst, FAR struct stm32_foc_board_s *board)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* STM32G4 ADC channel 0 unwanted conversion workaround */
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
/* Add one dummy channel to conversion */
|
||||||
|
|
||||||
|
adc_nchan = (adc_cfg->nchan + 1);
|
||||||
|
|
||||||
|
/* Allocate memory for the extended list of channels */
|
||||||
|
|
||||||
|
adc_chan = zalloc(adc_nchan);
|
||||||
|
if (adc_chan == NULL)
|
||||||
|
{
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy regular channels first */
|
||||||
|
|
||||||
|
for (i = 0; i < adc_cfg->regch; i += 1)
|
||||||
|
{
|
||||||
|
adc_chan[i] = adc_cfg->chan[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add dummy channel at the beginning of injected channels */
|
||||||
|
|
||||||
|
adc_chan[adc_cfg->regch] = 0;
|
||||||
|
|
||||||
|
/* Copy injected channels */
|
||||||
|
|
||||||
|
for (i = (adc_cfg->regch + 1); i < adc_nchan; i += 1)
|
||||||
|
{
|
||||||
|
adc_chan[i] = adc_cfg->chan[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND */
|
||||||
|
|
||||||
/* Get the ADC interface */
|
/* Get the ADC interface */
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32_FOC_G4_ADCCHAN0_WORKAROUND
|
||||||
|
foc_dev->adc_dev = stm32_adcinitialize(adc_inst,
|
||||||
|
adc_chan,
|
||||||
|
adc_nchan);
|
||||||
|
|
||||||
|
free(adc_chan);
|
||||||
|
#else
|
||||||
foc_dev->adc_dev = stm32_adcinitialize(adc_inst,
|
foc_dev->adc_dev = stm32_adcinitialize(adc_inst,
|
||||||
adc_cfg->chan,
|
adc_cfg->chan,
|
||||||
adc_cfg->nchan);
|
adc_cfg->nchan);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (foc_dev->adc_dev == NULL)
|
if (foc_dev->adc_dev == NULL)
|
||||||
{
|
{
|
||||||
mtrerr("Failed to get ADC%d interface\n", adc_cfg->intf);
|
mtrerr("Failed to get ADC%d interface\n", adc_cfg->intf);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user