I am using a STM32F407 discovery board for ADC and I found that the DR or the data register of the ADC can be configured in left or right alignment. What does this mean? Also, what are the advantage/disadvantages of each alignment?
Electrical – right or left alignment of data in ADC
adcembeddedmicrocontrollerstm32
Related Solutions
So it turns out that ADCXX_INYY, means that XX - the type of ADC's that you can configure to (i.e. 12 = can configure to ADC1 or ADC2). YY represents that GPIO channel where you can configure ADC.
Also, you need to do ADC_CommonInitStructure only once.
Here is the new and improved version of the code for further convenience.
static volatile Int32U TimingDelay;
int i;
__IO Int16U Adcdata[3];
__IO float Adc1=0;
float Adc1_avg=0;
__IO float Adc2=0;
float Adc2_avg=0;
__IO float Adc3=0;
float Adc3_avg=0;
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);
}
/**************************************************************************************/
void DelayResolution100us(Int32U Dly)
{
TimingDelay = Dly;
while(TimingDelay != 0);
}
/**
* @brief Decrements the TimingDelay variable.
* @param None
* @retval None
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 8 -> PB0 ADC12_IN8
ADC Channel 15 -> PC5 ADC12_IN15
ADC Channel 0 -> PA0 ADC123_IN0
*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_DeInit();
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init - COMMON - Do it once, do it first */
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // 2 half-words one by one, 1 then 2 then 3
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_6Cycles; //6 or 5?
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel - why is it DISABLE?
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Continuous Conversions
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // Ignored - why include it if ignored?
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
ADC_Init(ADC3, &ADC_InitStructure); // Mirror on ADC3
/* ADC3 regular channel 8 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_56Cycles); // PB0
/* ADC2 regular channel 5 configuration */
ADC_RegularChannelConfig(ADC2, ADC_Channel_15, 1, ADC_SampleTime_56Cycles); // PC5
/* ADC3 regular channel 0 configuration */
ADC_RegularChannelConfig(ADC3, ADC_Channel_0, 1, ADC_SampleTime_56Cycles); // PA0
/* Enable DMA request after last transfer (Multi-ADC mode) */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC2 */
ADC_Cmd(ADC2, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);
ADC_DMACmd(ADC1, ENABLE); //enable ADC1 DMA since ADC1 is the master
}
/**************************************************************************************/
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA2_Stream0); //Set DMA registers to default values
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&Adcdata;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308; // CDR_ADDRESS; Packed ADC1, ADC2
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 3; // Count of 16-bit words
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_Init(DMA2_Stream0, &DMA_InitStructure);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
}
/**************************************************************************************/
int main(void)
{
ENTR_CRT_SECTION();
if(SysTick_Config(SystemCoreClock/10000))
{
while (1);
}
EXT_CRT_SECTION();
RCC_Configuration();
GPIO_Configuration();
ADC_Configuration();
DMA_Configuration();
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
/*Turn on Backlight*/
GLCD_Backlight(BACKLIGHT_ON);
GLCD_SetFont(&Terminal_9_12_6,0x000F00,0x00FF0);
GLCD_SetWindow(10,116,131,131);
/*-------------------Display Readings-----------------------------------------*/
GLCD_PowerUpInit((pInt8U)IAR_Logo.pPicStream);
GLCD_Backlight(BACKLIGHT_ON);
while(1){
/***** Compute Gain and Phase ****/
Adc3_avg = 0;
Adc2_avg = 0;
Adc1_avg = 0;
DelayResolution100us(10000);
for(i=1;i<=20;i++)
{
DelayResolution100us(10000);
Adc1=(((float)Adcdata[0]) * 3.3)/4096; //voltage value
Adc1_avg = Adc1_avg + Adc1; //average gain
// Adc2con = (Adcdata[1] & 0x0FFF);
Adc2=(((float)Adcdata[1]) * 3.3)/4096; //voltage
Adc2_avg = Adc2_avg + Adc2;//average phase
// Adc3con = (Adcdata[1] & 0x0FFF);
Adc3=(((float)Adcdata[2]) * 3.3)/4096; //voltage
Adc3_avg = Adc3_avg + Adc3;//average phase
}
Adc1_avg = Adc1_avg/20;
Adc2_avg = Adc2_avg/20;
Adc3_avg = Adc3_avg/20;
//Write to LCD
GLCD_TextSetPos(0,0);
GLCD_print("G:%.02f", Adc3_avg);
GLCD_TextSetPos(7,0);
GLCD_print("P1:%.02f", Adc2_avg);
GLCD_TextSetPos(17,0);
GLCD_print("P2:%.02f", Adc1_avg);
}; // Don't want to exit
}
According to the schematic, there is a 10k--6.8k resistor divider in the circuit.
6.8k / (6.8k + 10k) = .4047619
1/.4047619 = 2.470588
Another place to look might be:
__lsb = float(0.0000078125) # default lsb value for 18 bit
7.8125e-6 * 2^18 = 2.048 // full-scale value?
5V / 2.048 = 2.441406
Or maybe some combination of those things.
Sorry I don't have time to analyze the whole datasheet, but both of those numbers are close to your magic number.
I encourage you to work through it step by step and try to get it figured out fully -- to the point where your results match within a few mV. There is going to be a right answer, and it will help if you keep track of your units (mV, LSBs, etc)
You can learn a lot about how digital systems talk to the real world!
Best Answer
Alignment determines how the binary will end up in the hardware register. Suppose you have a 16 bit resolution register (or 2x8 bits) but only 12 bit ADC resolution. Your option is then either to get:
or
Where "D" is your data bits and "X" is "don't care" bits (usually filled with zeroes). The form requiring the least amount of bitwise arithmetic to get to your desired format is usual the preferred one. One will contain the need to shift, the other won't.
This in turn depends on endianess - the byte order. If the ADC is using the same endianess as your CPU then you'd pick the one matching best. In case of STM32 little endian that probably means the 2nd of the two forms. Built-in ADCs in microcontrollers typically have the same endianess as the CPU. In case of external ones, it could have either big or little endian.