void adc_start (void) { uint32_t config[4]; get_adc_config (config); /* Use DMA channel 1. */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE; DMA1->IFCR = 0xffffffff; RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN); ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0 | ADC_CR1_SCAN); ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON); ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1; ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2; ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS); ADC1->SQR2 = 0; ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3; ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0 | ADC_CR1_SCAN); ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON; ADC2->SMPR1 = config[0]; ADC2->SMPR2 = config[1]; ADC2->SQR1 = config[2]; ADC2->SQR2 = 0; ADC2->SQR3 = config[3]; #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP /* * We could just let ADC run continuously always and only enable DMA * to receive stable data from ADC. But our purpose is not to get * correct data but noise. In fact, we can get more noise when we * start/stop ADC each time. */ ADC2->CR2 = 0; ADC1->CR2 = 0; #else /* Start conversion. */ ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON; ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON); #endif }
static void get_adc_config (uint32_t config[4]) { config[2] = ADC_SQR1_NUM_CH(2); switch (SYS_BOARD_ID) { case BOARD_ID_FST_01: config[0] = 0; config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5) | ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5); config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9); break; case BOARD_ID_OLIMEX_STM32_H103: case BOARD_ID_STBEE: config[0] = ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5) | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5); config[1] = 0; config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11); break; case BOARD_ID_STBEE_MINI: config[0] = 0; config[1] = ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5) | ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5); config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2); break; case BOARD_ID_CQ_STARM: case BOARD_ID_FST_01_00: case BOARD_ID_MAPLE_MINI: case BOARD_ID_STM32_PRIMER2: case BOARD_ID_STM8S_DISCOVERY: case BOARD_ID_ST_DONGLE: case BOARD_ID_ST_NUCLEO_F103: case BOARD_ID_NITROKEY_START: default: config[0] = 0; config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5) | ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5); config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1); break; } }
/** * @brief Starts an ADC conversion. * * @param[in] adcp pointer to the @p ADCDriver object * * @notapi */ void adc_lld_start_conversion(ADCDriver *adcp) { uint32_t mode; uint32_t cr2; const ADCConversionGroup *grpp = adcp->grpp; /* DMA setup.*/ mode = adcp->dmamode; if (grpp->circular) { mode |= STM32_DMA_CR_CIRC; if (adcp->depth > 1) { /* If circular buffer depth > 1, then the half transfer interrupt is enabled in order to allow streaming processing.*/ mode |= STM32_DMA_CR_HTIE; } } dmaStreamSetMemory0(adcp->dmastp, adcp->samples); dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * (uint32_t)adcp->depth); dmaStreamSetMode(adcp->dmastp, mode); dmaStreamEnable(adcp->dmastp); /* ADC setup.*/ adcp->adc->SR = 0; adcp->adc->SMPR1 = grpp->smpr1; adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SQR1 = grpp->sqr1 | ADC_SQR1_NUM_CH(grpp->num_channels); adcp->adc->SQR2 = grpp->sqr2; adcp->adc->SQR3 = grpp->sqr3; /* ADC configuration and start.*/ adcp->adc->CR1 = grpp->cr1 | ADC_CR1_OVRIE | ADC_CR1_SCAN; /* Enforcing the mandatory bits in CR2.*/ cr2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_ADON; /* The start method is different dependign if HW or SW triggered, the start is performed using the method specified in the CR2 configuration.*/ if ((cr2 & ADC_CR2_SWSTART) != 0) { /* Initializing CR2 while keeping ADC_CR2_SWSTART at zero.*/ adcp->adc->CR2 = (cr2 | ADC_CR2_CONT) & ~ADC_CR2_SWSTART; /* Finally enabling ADC_CR2_SWSTART.*/ adcp->adc->CR2 = (cr2 | ADC_CR2_CONT); } else adcp->adc->CR2 = cr2; }
// From libopencm3 static void adc_regular_sequence(uint32_t *sqr1, uint32_t *sqr2, uint32_t *sqr3, uint8_t length, const uint8_t channel[]) { uint32_t first6 = 0; uint32_t second6 = 0; uint32_t third6 = ADC_SQR1_NUM_CH(length); uint8_t i = 0; for (i = 1; i <= length; i++) { if (i <= 6) { first6 |= (channel[i - 1] << ((i - 1) * 5)); } if ((i > 6) & (i <= 12)) { second6 |= (channel[i - 1] << ((i - 6 - 1) * 5)); } if ((i > 12) & (i <= 18)) { third6 |= (channel[i - 1] << ((i - 12 - 1) * 5)); } } *sqr3 = first6; *sqr2 = second6; *sqr1 = third6; }
NULL, // error callback NULL, // Resent fields are stm32 specific. They contain ADC control registers data. // Please, refer to ST manual RM0008.pdf to understand what we do. // CR1 register content, set to zero for begin 0, // CR2 register content, set to zero for begin 0, // SMRP1 register content, channels 10, 11, 12, 13 to 71.5 cycles 0xB6D, // SMRP2 register content, channels 0, 1, 2, 3 to 71.5 cycles 0xB6D, // SQR1 register content. Set channel sequence length ADC_SQR1_NUM_CH(ADC_CH_NUM), // SQR2 register content, set to zero for begin (ADC_SQR2_SQ7_N(ADC_CHANNEL_IN10) | ADC_SQR2_SQ8_N(ADC_CHANNEL_IN11)), // SQR3 register content. First 6 channels (ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0 ) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1 ) | ADC_SQR3_SQ3_N(ADC_CHANNEL_IN2 ) | ADC_SQR3_SQ4_N(ADC_CHANNEL_IN3 ) | ADC_SQR3_SQ5_N(ADC_CHANNEL_IN12) | ADC_SQR3_SQ6_N(ADC_CHANNEL_IN13)), }; /*-----------------------------------------------------------------------------*/ /** @brief Initialize the ADC1 sub system */ /*-----------------------------------------------------------------------------*/
static const ADCConversionGroup adcgrpcfg3 = { FALSE, //circular enable ADC_ADC3_NUM_CHANNELS, //num_channels adccallback, // end_conversion_cb adcerrorcallback, //error_cb 0, /* CR1 */ ADC_CR2_SWSTART, /* CR2 */ ADC_SMPR1_SMP_AN14(ADC_OVERSAMPLING) | ADC_SMPR1_SMP_AN15(ADC_OVERSAMPLING), // SMPR1 ADC_SMPR2_SMP_AN4(ADC_OVERSAMPLING) | ADC_SMPR2_SMP_AN5(ADC_OVERSAMPLING) | /* SMPR2 */ ADC_SMPR2_SMP_AN6(ADC_OVERSAMPLING) | ADC_SMPR2_SMP_AN7(ADC_OVERSAMPLING) | /* SMPR2 */ ADC_SMPR2_SMP_AN9(ADC_OVERSAMPLING), /* SMPR2 */ ADC_SQR1_NUM_CH(ADC_ADC3_NUM_CHANNELS), // SQR1 0, //SQR2 ADC_SQR3_SQ1_N(GPIOF_ADC_CMD_TURRET_CHANNEL) | //SQR3 ADC_SQR3_SQ2_N(GPIOF_ADC_CMD_ELBOW_CHANNEL) | //SQR3 ADC_SQR3_SQ3_N(GPIOF_ADC_CMD_SHOULDER_CHANNEL) | //SQR3 ADC_SQR3_SQ4_N(GPIOF_ADC_CMD_WRIST_CHANNEL) | //SQR3 ADC_SQR3_SQ5_N(GPIOF_ADC_CMD_CLAMP_CHANNEL) //SQR3 }; #ifndef __COVERITY__ _Static_assert(CMD_TURRET_ADC_IDX == 3, "ADC mismatch"); _Static_assert(CMD_SHOULDER_ADC_IDX == 3, "ADC mismatch"); _Static_assert(CMD_ELBOW_ADC_IDX == 3, "ADC mismatch"); _Static_assert(CMD_WRIST_ADC_IDX == 3, "ADC mismatch"); _Static_assert(CMD_CLAMP_ADC_IDX == 3, "ADC mismatch");
//#define TS_CAL1_TMP (25.0f) //#define TS_AVG_SLOPE (2.5f * (4096 / 3300)) static const ADCConversionGroup core_temp_conv_grp = { .circular = FALSE, .num_channels = 1, .end_cb = NULL, .error_cb = NULL, /* HW dependent part.*/ .cr1 = 0, // 12-bit resolution .cr2 = ADC_CR2_SWSTART, // software triggered .smpr1 = ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_480), .smpr2 = 0, .sqr1 = ADC_SQR1_NUM_CH(1), .sqr2 = 0, .sqr3 = ADC_SQR3_SQ1_N(ADC_CHANNEL_SENSOR), }; /** * @brief PAL setup. * @details Digital I/O ports static configuration as defined in @p board.h. * This variable is used by the HAL when initializing the PAL driver. */ #if HAL_USE_PAL || defined(__DOXYGEN__) const PALConfig pal_default_config = { {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH},
void AdcDevice::init(void) { hwConfig->num_channels = size(); hwConfig->sqr1 += ADC_SQR1_NUM_CH(size()); }
} /* * ADC conversion group. * Mode: Linear buffer, 8 samples of 1 channel, SW triggered. * Channels: IN10. */ static const ADCConversionGroup adcgrpcfg1 = { FALSE, ADC_GRP1_NUM_CHANNELS, NULL, adcerrorcallback, 0, 0, /* CR1, CR2 */ ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5), 0, /* SMPR2 */ ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS), 0, /* SQR2 */ ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) }; /* * ADC conversion group. * Mode: Continuous, 16 samples of 8 channels, SW triggered. * Channels: IN10, IN11, IN10, IN11, IN10, IN11, Sensor, VRef. */ static const ADCConversionGroup adcgrpcfg2 = { TRUE, ADC_GRP2_NUM_CHANNELS, adccallback, adcerrorcallback, 0, ADC_CR2_TSVREFE, /* CR1, CR2 */
//The ADC2 configuration for the pressure monitoring /* * ADC conversion group. * Mode: Linear buffer, 1 sample of 1 channel, SW triggered. * Channels: IN11. */ static const ADCConversionGroup adcgrpcfg1 = { FALSE, PRESSURE_ADC_NUM_CHANNELS, NULL, adcerrorcallback, 0, /* CR1 */ ADC_CR2_SWSTART, /* CR2 */ ADC_SMPR1_SMP_AN14(ADC_SAMPLE_480), 0, /* SMPR2 */ ADC_SQR1_NUM_CH(PRESSURE_ADC_NUM_CHANNELS), 0, /* SQR2 */ ADC_SQR3_SQ1_N(ADC_PRESSURE_CHANNEL) }; //The PWM configuration for the solenoid control static PWMConfig PWM_Config_Solenoid = { 1000000, /* 1MHz PWM clock frequency. */ 250, /* Initial PWM period 4KHz. */ NULL, /* No cyclic callback */ { {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* Have to define the channel to enable here - channel 1=solenoid*/ {PWM_OUTPUT_DISABLED, NULL}, {PWM_OUTPUT_DISABLED, NULL}, {PWM_OUTPUT_DISABLED, NULL} },
/* * ADC conversion group. * Mode: Linear buffer, 1 sample of 1 channel, SW triggered. * Channels: IN1. */ static const ADCConversionGroup adcZeroSense = { FALSE, 1, &cbAdcZeroSense, NULL, 0, /* CR1 */ ADC_CR2_SWSTART, /* CR2 */ 0, ADC_SMPR2_SMP_AN1(ADC_SAMPLE_15), /* SMPR2 */ ADC_SQR1_NUM_CH(1), 0, /* SQR2 */ ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1) }; /* * PWM Scheme: High PWM, Lo ON * Time0 Time1 */ static uint8_t pwmScheme[6][3] = {{PWM_UP|PWM_VN, PWM_VN, !PWM_EXPECT_ZERO}, //UP PWM, VN ON {PWM_UP|PWM_WN, PWM_WN, PWM_EXPECT_ZERO}, //UP PWM, WN ON {PWM_VP|PWM_WN, PWM_WN, !PWM_EXPECT_ZERO}, //VP PWM, WN ON {PWM_VP|PWM_UN, PWM_UN, PWM_EXPECT_ZERO}, //VP PWM, UN ON {PWM_WP|PWM_UN, PWM_UN, !PWM_EXPECT_ZERO}, //WP PWM, UN ON {PWM_WP|PWM_VN, PWM_VN, PWM_EXPECT_ZERO} //WP PWM, VN ON
0 // DIER }; /* Instrument conversion group */ static const ADCConversionGroup adc_con_group_1 = { TRUE, /* circular mode */ 1, /* number of channels in this con_group */ adc_inst_callback, adc_error_callback, 0, /* ADC_CR1 */ /* cr2: Clock the ADC to timer 8 TRGO event*/ ADC_CR2_EXTSEL_SRC(14) | ADC_CR2_EXTEN_0, /* smpr1+2: set all channels to 40 cycles per conversion (28+12) */ ADC_SMPR1_SMP_AN11(2)| ADC_SMPR1_SMP_AN12(2)| ADC_SMPR1_SMP_AN13(2), ADC_SMPR2_SMP_AN0(2) | ADC_SMPR2_SMP_AN1(2) | ADC_SMPR2_SMP_AN2(2), ADC_SQR1_NUM_CH(1), /* sqr1: set 1 channel in the group */ 0, /* sqr2: no higher channels being sampled */ /* sqr3: set the two channels to sample */ ADC_SQR3_SQ1_N(INST_IN_CHN) }; /* FX inputs conversion group */ static const ADCConversionGroup adc_con_group_2 = { TRUE, /* circular mode */ 3, /* number of channels in this con group */ adc_fx_callback, adc_error_callback, 0, /* cr1 */ /* cr2: Clock the ADC to timer 3 TRGO event*/ ADC_CR2_EXTSEL_SRC(8) | ADC_CR2_EXTEN_0, /* smpr1+2: set all channels to 40 cycles per conversion (28+12) */
* ADC conversion group. * Mode: Continuous, circular, 32 samples of 2 channels. * Channels: IN12, IN13. */ static const ADCConversionGroup adcgrpcfg = { TRUE, /* Circular buffer mode enabled. */ ADC_GRP_NUM_CHANNELS, /* Number of channels in the group. */ adccb, /* Callback function of the group. */ NULL, /* Error callback function. */ /* STM32F1xx dependent part: */ 0, /* CR1. */ 0, /* CR2. */ ADC_SMPR1_SMP_AN12(ADC_SAMPLE_239P5) | ADC_SMPR1_SMP_AN13(ADC_SAMPLE_239P5), /* SMPR1. */ 0, /* SMPR2. */ ADC_SQR1_NUM_CH(ADC_GRP_NUM_CHANNELS), /* SQR1. */ 0, /* SQR2. */ ADC_SQR3_SQ2_N(ADC_CHANNEL_IN13) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN12) /* SQR3. */ }; /** * Input capture configuration for ICU2 driver. * * @note ICU drivers used in the firmware are modified ChibiOS * drivers for extended input capture functionality. */ static const ICUConfig icucfg2 = { ICU_INPUT_TYPE_PWM, /* Driver input type (EDGE, PULSE, PWM). */ 1000000, /* 1MHz ICU clock frequency. */ { /* ICU channel configuration. */
#include "m3pyro_continuity.h" #include "m3pyro_status.h" static const ADCConversionGroup adc_grp = { .circular = false, .num_channels = 5, .end_cb = NULL, .error_cb = NULL, .cr1 = 0, .cr2 = ADC_CR2_SWSTART, .smpr1 = ADC_SMPR1_SMP_AN11(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN13(ADC_SAMPLE_480), .smpr2 = ADC_SMPR2_SMP_AN1(ADC_SAMPLE_480) | ADC_SMPR2_SMP_AN2(ADC_SAMPLE_480) | ADC_SMPR2_SMP_AN8(ADC_SAMPLE_480), .sqr1 = ADC_SQR1_NUM_CH(5), .sqr2 = 0, .sqr3 = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN2) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1) | ADC_SQR3_SQ3_N(ADC_CHANNEL_IN11) | ADC_SQR3_SQ4_N(ADC_CHANNEL_IN13) | ADC_SQR3_SQ5_N(ADC_CHANNEL_IN8), }; /* 12bit ADC reading of PYRO_CONTINUITY into 2ohm/LSB uint8t */ static uint8_t adc_to_resistance(adcsample_t reading) { float r = 0.5 * (1000.0f * (float)reading) / (4096.0f - (float)reading); if(r >= 255.0f) { return 255; } else { return (uint8_t)r;
/* * ADC conversion group. * Mode: Continuous, 16 samples of 2 channels, HS triggered by * GPT4-TRGO. * Channels: Sensor, VRef. */ static const ADCConversionGroup adcgrpcfg1 = { true, ADC_GRP1_NUM_CHANNELS, adccallback, adcerrorcallback, 0, /* CR1 */ ADC_CR2_EXTEN_RISING | ADC_CR2_EXTSEL_SRC(12), /* CR2 */ ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_144) | ADC_SMPR1_SMP_VREF(ADC_SAMPLE_144), 0, /* SMPR2 */ ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS), /* SQR1 */ 0, /* SQR1 */ ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) | ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT) }; /*===========================================================================*/ /* Application code. */ /*===========================================================================*/ /* * This is a periodic thread that does absolutely nothing except flashing * a LED attached to TP1. */ static THD_WORKING_AREA(waThread1, 128); static THD_FUNCTION(Thread1, arg) {
/** * @brief Starts an ADC conversion. * * @param[in] adcp pointer to the @p ADCDriver object * * @notapi */ void adc_lld_start_conversion(ADCDriver *adcp) { uint32_t dmamode, ccr, cfgr; const ADCConversionGroup *grpp = adcp->grpp; osalDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0), "odd number of channels in dual mode"); /* Calculating control registers values.*/ dmamode = adcp->dmamode; ccr = grpp->ccr | (adcp->adcc->CCR & (ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK)); cfgr = grpp->cfgr | ADC_CFGR_DMAEN; if (grpp->circular) { dmamode |= STM32_DMA_CR_CIRC; #if STM32_ADC_DUAL_MODE ccr |= ADC_CCR_DMACFG_CIRCULAR; #else cfgr |= ADC_CFGR_DMACFG_CIRCULAR; #endif if (adcp->depth > 1) { /* If circular buffer depth > 1, then the half transfer interrupt is enabled in order to allow streaming processing.*/ dmamode |= STM32_DMA_CR_HTIE; } } /* DMA setup.*/ dmaStreamSetMemory0(adcp->dmastp, adcp->samples); #if STM32_ADC_DUAL_MODE dmaStreamSetTransactionSize(adcp->dmastp, ((uint32_t)grpp->num_channels/2) * (uint32_t)adcp->depth); #else dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * (uint32_t)adcp->depth); #endif dmaStreamSetMode(adcp->dmastp, dmamode); dmaStreamEnable(adcp->dmastp); /* Configuring the CCR register with the static settings ORed with the user-specified settings in the conversion group configuration structure.*/ adcp->adcc->CCR = ccr; /* ADC setup, if it is defined a callback for the analog watch dog then it is enabled.*/ adcp->adcm->ISR = adcp->adcm->ISR; adcp->adcm->IER = ADC_IER_OVR | ADC_IER_AWD1; adcp->adcm->TR1 = grpp->tr1; #if STM32_ADC_DUAL_MODE adcp->adcm->SMPR1 = grpp->smpr[0]; adcp->adcm->SMPR2 = grpp->smpr[1]; adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2); adcp->adcm->SQR2 = grpp->sqr[1]; adcp->adcm->SQR3 = grpp->sqr[2]; adcp->adcm->SQR4 = grpp->sqr[3]; adcp->adcs->SMPR1 = grpp->ssmpr[0]; adcp->adcs->SMPR2 = grpp->ssmpr[1]; adcp->adcs->SQR1 = grpp->ssqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2); adcp->adcs->SQR2 = grpp->ssqr[1]; adcp->adcs->SQR3 = grpp->ssqr[2]; adcp->adcs->SQR4 = grpp->ssqr[3]; #else /* !STM32_ADC_DUAL_MODE */ adcp->adcm->SMPR1 = grpp->smpr[0]; adcp->adcm->SMPR2 = grpp->smpr[1]; adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels); adcp->adcm->SQR2 = grpp->sqr[1]; adcp->adcm->SQR3 = grpp->sqr[2]; adcp->adcm->SQR4 = grpp->sqr[3]; #endif /* !STM32_ADC_DUAL_MODE */ /* ADC configuration.*/ adcp->adcm->CFGR = cfgr; /* Starting conversion.*/ adcp->adcm->CR |= ADC_CR_ADSTART; }
ADC_SMPR1_SMP_AN11(MY_SAMPLING_SLOW) | ADC_SMPR1_SMP_AN12(MY_SAMPLING_SLOW) | ADC_SMPR1_SMP_AN13(MY_SAMPLING_SLOW), // sample times for channels 10...18 ADC_SMPR2_SMP_AN0(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN1(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN3(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN4(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN5(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN6(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN7(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN8(MY_SAMPLING_SLOW) | ADC_SMPR2_SMP_AN9(MY_SAMPLING_SLOW) , // In this field must be specified the sample times for channels 0...9 ADC_SQR1_NUM_CH(EFI_ADC_SLOW_CHANNELS_COUNT), // Conversion group sequence 13...16 + sequence length 0 // | ADC_SQR2_SQ7_N(ADC_CHANNEL_IN12) /* PC2 - green */ // | ADC_SQR2_SQ8_N(ADC_CHANNEL_IN13) /* PC3 - yellow maf? */ ,// Conversion group sequence 7...12 0 // | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN6) /* PA6 - white */ // | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN7) /* PA7 - blue */ // | ADC_SQR3_SQ3_N(ADC_CHANNEL_IN14) /* PC4 - green */ // | ADC_SQR3_SQ4_N(ADC_CHANNEL_IN15) /* PC5 - yellow */ // | ADC_SQR3_SQ5_N(ADC_CHANNEL_IN8) /* PB0 - blue */ // | ADC_SQR3_SQ6_N(ADC_CHANNEL_IN9) /* PB1 - white */ // Conversion group sequence 1...6 };
/** * @brief Starts an ADC conversion. * * @param[in] adcp pointer to the @p ADCDriver object * * @notapi */ void adc_lld_start_conversion(ADCDriver *adcp) { uint32_t mode; const ADCConversionGroup* grpp = adcp->grpp; /* DMA setup.*/ mode = adcp->dmamode; if (grpp->circular) { mode |= STM32_DMA_CR_CIRC; if (adcp->depth > 1) { /* If circular buffer depth > 1, then the half transfer interrupt is enabled in order to allow streaming processing.*/ mode |= STM32_DMA_CR_HTIE; } } dmaStreamSetMemory0(adcp->dmastp, adcp->samples); dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * (uint32_t)adcp->depth); dmaStreamSetMode(adcp->dmastp, mode); dmaStreamEnable(adcp->dmastp); #if STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC if (adcp->adc != NULL) #endif /* STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC */ #if STM32_ADC_USE_ADC { uint32_t cr2 = adcp->adc->CR2 & ADC_CR2_TSVREFE; cr2 |= grpp->u.adc.cr2 | ADC_CR2_DMA | ADC_CR2_ADON; if ((cr2 & ADC_CR2_SWSTART) != 0) cr2 |= ADC_CR2_CONT; adcp->adc->CR2 = cr2; /* ADC setup.*/ adcp->adc->SR = 0; adcp->adc->LTR = grpp->u.adc.ltr; adcp->adc->HTR = grpp->u.adc.htr; adcp->adc->SMPR1 = grpp->u.adc.smpr[0]; adcp->adc->SMPR2 = grpp->u.adc.smpr[1]; adcp->adc->SQR1 = grpp->u.adc.sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels); adcp->adc->SQR2 = grpp->u.adc.sqr[1]; adcp->adc->SQR3 = grpp->u.adc.sqr[2]; /* ADC conversion start, the start is performed using the method specified in the CR2 configuration, usually ADC_CR2_SWSTART.*/ adcp->adc->CR1 = grpp->u.adc.cr1 | ADC_CR1_AWDIE | ADC_CR1_SCAN; adcp->adc->CR2 = adcp->adc->CR2; /* Triggers the conversion start.*/ } #endif /* STM32_ADC_USE_ADC */ #if STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC else if (adcp->sdadc != NULL) #endif /* STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC */ #if STM32_ADC_USE_SDADC { uint32_t cr2 = (grpp->u.sdadc.cr2 & ~SDADC_FORBIDDEN_CR2_FLAGS) | SDADC_CR2_ADON; if ((grpp->u.sdadc.cr2 & SDADC_CR2_JSWSTART) != 0) cr2 |= SDADC_CR2_JCONT; /* Entering initialization mode.*/ adcp->sdadc->CR1 |= SDADC_CR1_INIT; while ((adcp->sdadc->ISR & SDADC_ISR_INITRDY) == 0) ; /* SDADC setup.*/ adcp->sdadc->JCHGR = grpp->u.sdadc.jchgr; adcp->sdadc->CONFCHR1 = grpp->u.sdadc.confchr[0]; adcp->sdadc->CONFCHR2 = grpp->u.sdadc.confchr[1]; /* SDADC trigger modes, this write must be performed when SDADC_CR1_INIT=1.*/ adcp->sdadc->CR2 = cr2; /* Leaving initialization mode.*/ adcp->sdadc->CR1 &= ~SDADC_CR1_INIT; /* Special case, if SDADC_CR2_JSWSTART is specified it has to be written after SDADC_CR1_INIT has been set to zero. Just a write is performed, any other bit is ingore if not in initialization mode.*/ adcp->sdadc->CR2 = cr2; } #endif /* STM32_ADC_USE_SDADC */ #if STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC else { chDbgAssert(FALSE, "adc_lld_start_conversion(), #1", "invalid state"); } #endif /* STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC */ }
static const ADCConversionGroup adcgrpcfg1 = {FALSE, //circular buffer mode ADC_GRP1_NUM_CHANNELS, //Number of the analog channels NULL, //Callback function (not needed here) 0, //Error callback 0, /* CR1 */ ADC_CR2_SWSTART, /* CR2 */ ADC_SMPR1_SMP_AN10(ADC_SAMPLE_84) | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_84) | ADC_SMPR1_SMP_AN12(ADC_SAMPLE_84) | ADC_SMPR1_SMP_AN13(ADC_SAMPLE_84) | ADC_SMPR1_SMP_AN14(ADC_SAMPLE_84) | ADC_SMPR1_SMP_AN15(ADC_SAMPLE_84), //sample times ch10-18 ADC_SMPR2_SMP_AN0(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN1(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN2(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN3(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN4(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN5(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN6(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN7(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN8(ADC_SAMPLE_84) | ADC_SMPR2_SMP_AN9(ADC_SAMPLE_84), //sample times ch0-9 ADC_SQR1_SQ13_N(ADC_CHANNEL_IN12) | ADC_SQR1_SQ14_N(ADC_CHANNEL_IN13) | ADC_SQR1_SQ15_N(ADC_CHANNEL_IN14) | ADC_SQR1_SQ16_N(ADC_CHANNEL_IN15) | ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS), //SQR1: Conversion group sequence 13...16 + sequence length ADC_SQR2_SQ7_N(ADC_CHANNEL_IN6) | ADC_SQR2_SQ8_N(ADC_CHANNEL_IN7) | ADC_SQR2_SQ9_N(ADC_CHANNEL_IN8) | ADC_SQR2_SQ10_N(ADC_CHANNEL_IN9) | ADC_SQR2_SQ11_N(ADC_CHANNEL_IN10) | ADC_SQR2_SQ12_N(ADC_CHANNEL_IN11), //SQR2: Conversion group sequence 7...12 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1) | ADC_SQR3_SQ3_N(ADC_CHANNEL_IN2) | ADC_SQR3_SQ4_N(ADC_CHANNEL_IN3) | ADC_SQR3_SQ5_N(ADC_CHANNEL_IN4) | ADC_SQR3_SQ6_N(ADC_CHANNEL_IN5) //SQR3: Conversion group sequence 1...6 }; void adc_convert(void) { adcStopConversion(&ADCD1); adcStartConversion(&ADCD1, &adcgrpcfg1, adcvalues, ADC_GRP1_BUF_DEPTH); }
*/ static const ADCConversionGroup adccg = { TRUE, ADC_NUM_CHANNELS, adccallback, adcerrorcallback, 0, /* CR1 */ ADC_CR2_SWSTART, /* CR2 */ ADC_SMPR1_SMP_AN10(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN12(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN13(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN14(ADC_SAMPLE_480) | ADC_SMPR1_SMP_AN15(ADC_SAMPLE_480), 0, /* SMPR2 */ ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), 0, (ADC_SQR3_SQ6_N(ADC_AN33_2) | ADC_SQR3_SQ5_N(ADC_AN33_1) | ADC_SQR3_SQ4_N(ADC_AN33_0) | ADC_SQR3_SQ3_N(ADC_6V_SUPPLY) | ADC_SQR3_SQ2_N(ADC_MAIN_SUPPLY) | ADC_SQR3_SQ1_N(ADC_CURRENT_SENS)) }; /* ******************************************************************************* ******************************************************************************* * LOCAL FUNCTIONS ******************************************************************************* ******************************************************************************* */ /* пересчет из условных единиц АЦП в mV */
namespace r2p { /*===========================================================================*/ /* Motor calibration. */ /*===========================================================================*/ static int pwm = 0; #define ADC_NUM_CHANNELS 1 #define ADC_BUF_DEPTH 1 static float meanLevel = 0.0f; static adcsample_t adc_samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; static void current_callback(ADCDriver *adcp, adcsample_t *buffer, size_t n); /* * ADC conversion group. * Mode: Circular buffer, 1 sample of 1 channel, triggered by pwm channel 3 * Channels: IN10. */ static const ADCConversionGroup adcgrpcfg = { TRUE, // circular ADC_NUM_CHANNELS, // num channels current_callback, // end callback NULL, // error callback 0, // CR1 ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL_1, // CR2 0, // SMPR1 ADC_SMPR2_SMP_AN3(ADC_SAMPLE_1P5)/*ADC_SMPR2_SMP_AN3(ADC_SAMPLE_239P5)*/, // SMPR2 ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), // SQR1 0, // SQR2 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN3) // SQR3 }; static void current_callback(ADCDriver *adcp, adcsample_t *buffer, size_t n) { (void) adcp; (void) n; palTogglePad(LED2_GPIO, LED2); chSysLockFromIsr() ; meanLevel = buffer[0]; if (tp_motor != NULL) { chSchReadyI(tp_motor); tp_motor = NULL; } chSysUnlockFromIsr(); } static PWMConfig pwmcfg = { STM32_SYSCLK, // 72MHz PWM clock frequency. 4096, // 12-bit PWM, 17KHz frequency. NULL, // pwm callback { { PWM_OUTPUT_ACTIVE_HIGH | PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH, NULL }, // { PWM_OUTPUT_ACTIVE_HIGH | PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH, NULL }, // { PWM_OUTPUT_ACTIVE_LOW, NULL }, // { PWM_OUTPUT_DISABLED, NULL } }, // 0, // #if STM32_PWM_USE_ADVANCED 72, /* XXX 1uS deadtime insertion */ #endif 0 }; static calibration_pub_node_conf defaultPubConf = { "motor_calibration_node", "bits" }; msg_t motor_calibration_node(void * arg) { //Configure current node calibration_pub_node_conf* conf; if (arg != NULL) conf = (calibration_pub_node_conf *) arg; else conf = &defaultPubConf; Node node(conf->name); Publisher<FloatMsg> current_pub; FloatMsg * msgp; chRegSetThreadName(conf->name); node.advertise(current_pub, conf->topic); // Start the ADC driver and conversion adcStart(&ADC_DRIVER, NULL); adcStartConversion(&ADC_DRIVER, &adcgrpcfg, adc_samples, ADC_BUF_DEPTH); // Init motor driver palSetPad(DRIVER_GPIO, DRIVER_RESET); chThdSleepMilliseconds(500); pwmStart(&PWM_DRIVER, &pwmcfg); // wait some time chThdSleepMilliseconds(500); // start pwm float voltage = 24.0; const float pwm_res = 4096.0f / 24.0f; pwm = static_cast<int>(voltage * pwm_res); if (pwm > 0) { pwm_lld_enable_channel(&PWM_DRIVER, 1, pwm); pwm_lld_enable_channel(&PWM_DRIVER, 0, 0); pwm_lld_enable_channel(&PWM_DRIVER, 2, pwm/2); } else { pwm_lld_enable_channel(&PWM_DRIVER, 1, 0); pwm_lld_enable_channel(&PWM_DRIVER, 0, -pwm); pwm_lld_enable_channel(&PWM_DRIVER, 2, -pwm/2); } // Start publishing current measures for (;;) { // Wait for interrupt chSysLock() ; tp_motor = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); chSysUnlock(); // publish current if (current_pub.alloc(msgp)) { msgp->value = meanLevel; current_pub.publish(*msgp); } } return CH_SUCCESS; } }