Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F60670765
adc.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, May 1, 20:53
Size
7 KB
Mime Type
text/x-c
Expires
Fri, May 3, 20:53 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
17394303
Attached To
R2671 HHRI-software
adc.c
View Options
#include "adc.h"
#include "../lib/basic_filter.h"
#include "../lib/utils.h"
volatile uint16_t adc_currentValuesBuffer[ADC_BUFFER_SIZE];
bfilt_BasicFilter adc_currentFilter;
uint16_t adc_currentSensOffset = 2048;
void adc_DmaInit(void);
/**
* @brief Initialize the ADC converter (2 analog inputs + current sense).
*/
void adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
adc_DmaInit();
// Periph clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_ADC2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3,ENABLE);
// GPIO configuration
GPIO_InitStructure.GPIO_Pin = ADC1_Input_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ADC1_Input_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = ADC2_Input_Pin;
GPIO_Init(ADC2_Input_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = ADC_Current_Sens_Pin;
GPIO_Init(ADC_Current_Sens_Port, &GPIO_InitStructure);
// ADC Common configuration
ADC_DeInit();
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // Useless here (only used in dual or triple interleaved modes).
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInit(&ADC_CommonInitStructure);
// ADC regular channel configuration
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = 0;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure);
// ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
// ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_TRGO;
// ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
// Synchronous sampling with the PWM replaced by a high-frequency sampling at ~300kHz (over-sampling), because of the commutation noise of the current measuring amplifier at ~120kHz.
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_Init(ADC3, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC1_Input_Chan, 1, ADC_SampleTime_56Cycles);
ADC_Cmd(ADC1, ENABLE);
ADC_SoftwareStartConv(ADC1);
ADC_RegularChannelConfig(ADC2, ADC2_Input_Chan, 1, ADC_SampleTime_56Cycles);
ADC_Cmd(ADC2, ENABLE);
ADC_SoftwareStartConv(ADC2);
ADC_RegularChannelConfig(ADC3, ADC_Current_Sens_Chan, 1, ADC_SampleTime_28Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
ADC_DMACmd(ADC3, ENABLE);
ADC_Cmd(ADC3, ENABLE);
ADC_SoftwareStartConv(ADC3);
// Setup the filter of the ADC current samples over time.
bfilt_Init(&adc_currentFilter, 0.2f, 0.0f);
}
/**
* @brief Setup the DMA that copies the current ADC samples to the RAM.
*/
void adc_DmaInit(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adc_currentValuesBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Channel = DMA_Channel_2;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream1, ENABLE);
}
/**
* @brief Compute the current sense offset.
* @note Run before enabling current regulation.
*/
void adc_CalibrateCurrentSens(void)
{
int32_t i=0;
for(i=0; i<1000; i++)
{
utils_DelayUs(400);
if(adc_currentFilter.filteredValue > 0.0f)
adc_currentSensOffset++;
else
adc_currentSensOffset--;
}
}
/**
* @brief Compute the current sense offset.
* @retval The measured current in [mA].
*/
float32_t adc_GetCurrent(void)
{
int32_t motorCurrentSum;
float32_t motorCurrentMean;
int32_t i;
// Compute the average of all the ADC values in the buffer.
motorCurrentSum = 0; // [ADC raw value].
for(i=0; i<ADC_BUFFER_SIZE; i++)
motorCurrentSum += (int32_t)(adc_currentValuesBuffer[i]);
motorCurrentMean = (float32_t)motorCurrentSum / (float32_t)ADC_BUFFER_SIZE;
// Add the offset obtained during the sense resistor calibration.
motorCurrentMean -= (float32_t) adc_currentSensOffset;
// Convert from ADC increments to mA.
motorCurrentMean /= CURRENT_SCALE;
// Use low-pass filtering to reduce the noise. This is currently only used
// during the calibration.
bfilt_Step(&adc_currentFilter, motorCurrentMean);
//return motorCurrentMean;
return adc_currentFilter.filteredValue;
}
/**
* @brief Start the ADC conversion of the selected channel.
*/
void adc_StartConversion(AdcChannel channel)
{
if(channel == ANIN1)
ADC1->CR2 |= (uint32_t)ADC_CR2_SWSTART;
else if(channel == ANIN2)
ADC2->CR2 |= (uint32_t)ADC_CR2_SWSTART;
}
/**
* @brief Get the ADC conversion status of the selected channel.
* @retval 1 if the conversion is finished, 0 otherwise.
*/
uint8_t adc_ConversionIsFinished(AdcChannel channel)
{
if(channel == ANIN1)
return (ADC1->SR & ADC_SR_EOC) != 0;
else if(channel == ANIN2)
return (ADC2->SR & ADC_SR_EOC) != 0;
else
return 0;
}
/**
* @brief Get the voltage measured by the selected ADC channel.
* @param channel: the channel of the ADC.
* @param scale: the full scale, depends of the switches position.
* @return the measured voltage, in [V], or 0.0f if the channel is invalid.
* @note make sure that the conversion is finished before calling.
*/
float32_t adc_GetConversionResult(AdcChannel channel, float32_t scale)
{
float32_t adcRawVal, voltage;
if(channel == ANIN1)
adcRawVal = (float32_t)ADC1->DR;
else if(channel == ANIN2)
adcRawVal = (float32_t)ADC2->DR;
else
adcRawVal = 0.0f;
voltage = (1.0f - (adcRawVal / (float32_t)ADC_MAX) * 2.0f) * scale;
return voltage;
}
/**
* @brief Get the voltage measured by the selected ADC channel.
* @param channel: the channel of the ADC.
* @param scale: the full scale, depends of the switches position.
* @return the measured voltage, in [V], or 0.0f if the channel is invalid.
* @note make sure that the conversion is finished before calling.
*/
float32_t adc_GetChannelVoltage(AdcChannel channel, float32_t scale)
{
int32_t conversionTime = 0;
adc_StartConversion(channel);
while(!adc_ConversionIsFinished(channel))
{
if(conversionTime < ADC_MAX_CONVERSION_TIME)
conversionTime++;
else
break;
}
return adc_GetConversionResult(channel, scale);
}
Event Timeline
Log In to Comment