Article Reference: STM32F1 ADC ADC introduction and structure analysis, STM32 — ADC details, STM32ADC + steps tips, the basic principle of STM32ADC, STM32ADC, STM32ADC configuration, STM32ADC programming method summary, the following is to talk about THE ADC application of STM32, about STM32 The baud rate of the F107RCT6 serial port with 8-meter crystal oscillator is incorrect

I. Introduction to ADC

The process of converting analog to digital quantities is called mode (A/D) conversion, and the period during which this conversion is completed becomes an analog-to-digital converter (ADC, analog to Digital Converter). ADC converter technical specifications: conversion speed, relative accuracy, resolution. According to its conversion principle, it can be divided into three types: successive approximation type, double integral type and parallel comparison type. The conversion speed and relative accuracy are compared as follows:

STM32’s ADC is a 12 – bit successive approximation analog-to-digital converter. It has up to 18 channels and can detect 16 external and 2 internal signal sources. The A/D conversion of each channel can be performed in single, continuous, scan or discontinuous mode. ADC conversion results can be left – or right-aligned and stored in 16-bit data registers. The analog watchdog feature allows an application to detect whether the input voltage exceeds a user-defined high/low threshold. Dual ADC modes are supported on chips with two or more ADC modules. Analog input channel ADC1_IN16 connects to internal temperature sensor. The ADC input clock of STM32 shall not exceed 14MHz, which is generated by PCLK2 through frequency division.

Ii. Main features of ADC

The ADC structural block diagram is divided into 7 sub-modules and briefly introduced in sequence.

1. Voltage input pin

ADC input voltage range: VREF- ≤ VIN ≤ VREF+. The electrical characteristics of VREF-, VREF+, VDDA and VSSA are determined by the four external pins. Therefore, the power supply requirements of ADC are 2.4V to 3.6V. Generally, VSSA and VREF- are grounded, and VREF+ and VDDA are connected to 3.3V. Therefore, the input voltage range of ADC is 0-3.3V. The development board ADC we use has an input voltage range of 0-3.3V.

If you want an ADC to test negative voltages or higher positive voltages, you can add a voltage conditioning circuit externally to raise or lower the required voltage to 0-3.3V so that the ADC can measure it. Do not directly connect voltage higher than 3.3V to the ADC pin, as this may burn the chip.

2. ADC input clock ADC_CLK

ADC input clock ADC_CLK is generated by APB2 through frequency division, the maximum value is 14MHz, the frequency division factor is set by the RCC clock configuration register RCC_CFGR bit 15:14 ADCPRE[1:0], can be 2/4/6/8 frequency division, note that there is no 1 frequency division here.

As you can see from the figure, the SYSCLK clock of STM32F107 has two configuration paths. The first one can use 8M external crystal oscillator and 9 times frequency to configure the system clock 72MHz, that is, PCLK2 (APB2 clock) is 72M, while the maximum working frequency of THE ADC is 14M. Therefore, the frequency division factor is generally set to 6, so that the input clock of the ADC is 12M. The second one can be configured with 25M external crystal oscillator. PLL2_CLK= (HSE / 5) * 8 = 40 MHz after PLL2 predivision factor 5, 8 times, and then PLL predivision factor 5, 7 times. PLL_CLK = (PLL2_CLK/ 5) * 7 = 56MHz, then the system clock is 56MHz, that is, PCLK2 (APB2 clock) is 56MHz, and ADC_CLK = 14 MHz through 4 frequency division of PCLK2.

ADC needs several ADC_CLK cycles to complete the sampling of the input voltage. The number of sampling cycles can be set by the SMP[2:0] bit in the ADC sampling time register ADC_SMPR1 and ADC_SMPR2. ADC_SMPR2 controls channels 0-9. ADC_SMPR1 controls channels 10-17. Each channel can be sampled at a different time. The minimum sampling period is 1.5, that is, if we want to achieve the fastest sampling, we should set the sampling period to 1.5, the period here is 1/ADC_CLK. The sampling period is shown below.

The total conversion time of ADC is related to the input clock and sampling time of ADC, and its formula is as follows: Where Tconv is the total conversion time of ADC. When ADC_CLK=14Mhz and the sampling time is set to 1.5 cycles, Tcovn=1.5+12.5=14 cycles =1us. Usually, the clock that can be divided to the maximum by the ADC predivider can only be 12M. The sampling period is set to 1.5 cycles, and the shortest conversion time is calculated to be 1.17us, which is the most commonly used one.

3. Input channel

The ADC of STM32 has up to 18 input channels, which can measure 16 external and 2 internal signal sources, among which 16 external channels are ADCx_IN0, ADCx_IN1,… , ADCx_IN15 (x=1/2/3, representing ADC number), analog signals can be collected through these 16 external channels. The 16 channels correspond to different I/O ports, as shown in the following figure. ADC1 also has two internal channels: channel 16 of ADC1 is connected to the temperature sensor inside the chip, and channel 17 is connected to the internal reference voltage VREFINT. Channels 16 and 17 of ADC2 and ADC3 are all connected to the internal VSS.

4. Channel selection

The external 16 channels can be divided into two groups of channels during transformation: regular channel group and injection channel group.

Rule group: Consists of up to 16 transformation channels. Convert a set of specified channels one by one in the specified order. After the conversion is complete, the loop is repeated from the beginning. This specified channel group is called a rule group, and the rule channels and their conversion order are selected in the ADC_SQRx register. The total number of conversions in the rule group should be written to bit L[3:0] of the ADC_SQR1 register. Normal ADC conversions are implemented using regular channels.

Injection group: consists of up to 4 transformation channels. In practical applications, it may be necessary to temporarily interrupt the conversion of the rule group, for some channels to be converted, these need to interrupt the rule group for conversion of the channel group, called injection group. The injection channels and their conversion order are selected in the ADC_JSQR register. The total number of conversions in the injected group should be written to bit L[1:0] of the ADC_JSQR register.

Note: When an ADC module converts a rule set, it is asked to temporarily convert some channels outside the rule set, as if the set of channels were temporarily injected in the original order, so it is vividly called an injection group. When an injection channel needs to be converted, the conversion of the regular channel will stop, and the injection channel conversion will be performed first. When the injection channel conversion is completed, the previous regular channel will be converted, which is equivalent to interruption, as shown in the following figure.

A series of transformations on any number of channels in any order constitutes a group transformation. For example, you can complete the conversion in the following order: Channel 3, channel 8, channel 2, channel 2, channel 0, channel 2, channel 2, channel 15.

There are three regular channel group sequence registers, namely SQR3, SQR2 and SQR1, which control the transformation sequence in regular channel, as shown in the figure below. As long as the corresponding channel is written in the corresponding register bit SQx, this channel is the x transformation. For example, if channel 3 wants the first conversion, write 3 in SQ1[4:0]. The specific number of channels to be used is determined by the bit L[3:0] of SQR1, up to 16 channels.

There is only one injection channel group sequence register, which is JSQR. It supports up to four channels, as determined by JSQR’s JL[1:0]. Note:

When JL[1:0] = 3 (with four injection conversions), ADC converts channels in the following order: JSQ1[4:0], JSQ2[4:0], JSQ3[4:0], and JSQ4[4:0].

When JL[1:0] = 2 (with three injection conversions), ADC converts channels in the following order: JSQ2[4:0], JSQ3[4:0], and JSQ4[4:0].

When JL[1:0] = 1 (with two injection conversions), the sequence of ADC conversion channels is JSQ3[4:0] and then JSQ4[4:0].

When JL[1:0] = 0 (with one injection conversion), ADC will only convert JSQ4[4:0] channels.

If the ADC_SQRx or ADC_JSQR registers are modified during the conversion, the current conversion is reset and a new start pulse is sent to the ADC to convert the newly selected channel set.

5. Data register

The data after conversion is stored in the data register, but the storage of data is also divided into regular channel conversion data and injection channel conversion data.

Regular data register

The regular data register is responsible for storing regular channel conversion data, which is stored in the 32-bit register ADC_DR.

When using ADC independent mode (that is, only one ADC can use multiple channels), the data is stored in the lower 16 bits; When using ADC multi-mode, the high 16 bits hold ADC2 data. Since the STM32F1 ADC has a 12-bit conversion accuracy and a 16-bit data register, the ADC has left and right alignment when storing data. If left-aligned, the data is stored in bit [15:4] of the ADC_DR register. If it is right-aligned, it is stored in bit [11:0] of the ADC_DR register. To select the specific storage mode, set the 11-bit ALIGN of ADC_CR2.

In the rule group, there are 16 channels and only 1 register corresponding to the storage of the rule data. If multi-channel conversion is used, all the converted data will be crowded into the ADC_DR register. The channel data converted at the previous time point will be overwritten by the data converted at another channel at the next time point. Therefore, when the channel conversion is completed, the data should be removed, or DMA mode should be enabled to transfer the data to memory, otherwise the data will be overwritten. The most common approach is to turn on DMA transfers. If DMA transfer is not used, we usually obtain the progress status of the current ADC conversion through the ADC status register ADC_SR for program control.

Injection data register

There are four data registers in the injection channel conversion. Since there are at most four injection channels, the data in the injection channel conversion has a fixed storage location and will not have the problem of data overwriting as in the regular register. ADC_JDRx is 32 bits, the lower 16 bits are valid, the higher 16 bits are reserved, the data is also divided into left and right alignment, which is stored by the 11-bit ALIGN of ADC_CR2.

6. The trigger source

After selecting the input channel and setting the conversion order, you can begin the conversion. To enable ADC conversion, you can directly set the ADON bit of the ADC control register ADC_CR2 to 1, even if the ADC can be converted. Of course, ADC also supports external event trigger conversion. There are many trigger sources. The specific selection of trigger sources is controlled by the ADC control register 2 (ADC_CR2) EXTSEL[2:0] and JEXTSEL[2:0] bits. EXTSEL[2:0] is used to select a regular channel trigger source, and JEXTSEL[2:0] is used to select an injection channel trigger source. After selecting the trigger source, whether to activate the trigger source will be activated by the ADC control register ADC_CR2’s 20-bit EXTTRIG and 15-bit JEXTTRIG.

Interruption of 7.

When the following events occur and the corresponding interrupt flag bit is enabled, the ADC can generate interrupt.

1) End of conversion (rule conversion) and end of injection conversion

After the end of data conversion, if the interrupt conversion end flag is enabled, the end of conversion will be interrupted once the conversion is over, you can read rules or inject the value of the data register in the interrupt function.

2) Simulated watchdog incident

When the analog voltage converted by the ADC falls below the low threshold or above the high threshold, an interrupt occurs and the AWD analog watchdog status bit is set to 1. The threshold is in the lowest 12 significant bits of the ADC_HTR and ADC_LTR registers. Set the AWDIE bit of the ADC_CR1 register to allow corresponding interrupts.

8. DMA requests

Both rule conversion and injection conversion have external triggering options. During rule channel conversion, a DMA request is made to transfer the converted data from the ADC_DR register to the destination address specified by the user. Injection transforms, on the other hand, have no DMA requests and need to be queried or interrupted to save the transformed data.

Because the values of regular channel transformations are stored in a single data register, DMA is required when converting multiple regular channels, which avoids losing data already stored in the ADC_DR register.

Note that only ADC1 and ADC3 can make DMA requests. The data converted from ADC2 can be transmitted in dual ADC mode using THE DMA function of ADC1.

9. Switch modes

The conversion modes of each channel of STM32’s ADC include single conversion mode, continuous conversion mode, scan mode and interrupt mode.

Single conversion mode: The ADC performs only one conversion. It can be started either by the ADON bit of the ADC_CR2 register (for regular channels only) or by an external trigger (for regular channels and injection channels), where the CONT bit is 0.

Once the conversion of the selected channel is complete: 1) If a regular channel is converted: the conversion data is stored in the 16-bit ADC_DR register; The EOC flag is set; If EOCIE is set, an interrupt occurs; 2) If an injection channel is converted: the converted data is stored in register 16 of ADC_DRJ1; The JEOC flag bit is set; If the JEOCIE bit is set, an interrupt is generated. Then the ADC stops;

Continuous conversion mode: The ADC starts a new conversion immediately after completing a conversion. When CONT bit is 1, this mode can be started externally by triggering or by placing ADON position 1 in the ADC_CR2 register (for regular channels only). Note that this mode does not continuously transform injection channels. The only exception in continuous mode is when the injection channel is configured to automatically convert after the regular channel (using the JAUTO bit).

After each conversion: 1) If a regular channel is converted: the conversion data is stored in the 16-bit ADC_DR register; The EOC flag is set; If EOCIE is set, an interrupt occurs; 2) If an injection channel is converted: the converted data is stored in register 16 of ADC_DRJ1; The JEOC flag bit is set; If the JEOCIE bit is set, an interrupt is generated. Then the ADC stops;

Scan mode: Used to scan a set of analog channels. The SCAN mode can be selected by setting the SCAN bit of the ADC_CR1 register. Once this bit is set, ADC scans all channels selected by the ADC_SQRX register (for regular channels) or ADC_JSQR(for injected channels). Perform a single conversion on each channel of each group. At the end of each conversion, the next channel of the same group is automatically converted. If the CONT bit is set, the transformation does not stop at the last channel of the selection group, but continues again from the first channel of the selection group. If DMA bits are set, after each EOC, the DMA controller transfers the transformation data for the rule group channel to the SRAM. The data injected into the channel conversion is always stored in the ADC_JDRx register.

Discontinuous mode: Every trigger, n channels in the conversion sequence, there are a variety of trigger modes.

Rule group: This mode is activated by setting the DISCEN bit on the ADC_CR1 register. It can be used to perform a short sequence of n conversions (n<=8) that is part of the sequence of conversions selected by the ADC_SQRx register. The value n is given by the DISCNUM[2:0] bit of the ADC_CR1 register. An external trigger signal can initiate the next round of n conversions described in the ADC_SQRx register until all conversions in this sequence are complete. The total sequence length is defined by L[3:0] of the ADC_SQR1 register.

Injection group: This mode is activated by setting the JDISCEN bit of the ADC_CR1 register. After an external trigger event, the pattern converts the selected sequence in the ADC_JSQR register one by one in channel order. An external trigger signal can initiate the conversion of the next channel sequence selected by the ADC_JSQR register until all conversions in the sequence are complete. The total sequence length is defined by the JL[1:0] bits of the ADC_JSQR register.

9. The calibration

The ADC has a built-in self-calibration mode. Calibration can greatly reduce the quasi-precision error caused by the change of the internal capacitor bank. During calibration, an error correction code (numeric value) is calculated on each capacitor, which is used to eliminate errors generated on each capacitor during subsequent conversions. Start the calibration by setting the CAL bit of the ADC_CR2 register. Once calibration is complete, the CAL bits are reset by the hardware and normal conversion can begin. It is recommended to perform an ADC calibration during power-on. At the end of the calibration phase, the calibration code is stored in ADC_DR.

Note: It is recommended to perform a calibration after each power-on.

Before starting calibration, the ADC must be powered off (ADON= ‘0’) for at least two ADC clock cycles.

10. Dual ADC mode

In products with two or more ADC modules, dual ADC modes can be used.

There are six possible modes: synchronous injection mode, synchronous rule mode, fast crossover mode, slow crossover mode, alternate trigger mode, and independent mode.

The above modes can also be combined in the following ways: synchronous injection mode + synchronous rule mode, synchronous rule mode + alternate trigger mode, synchronous injection mode + cross mode.

11. Temperature sensor

A temperature sensor can be used to measure the temperature (TA) around the device. The temperature sensor is connected internally to the ADC1_IN16 input channel, which converts the voltage output from the sensor into a digital value. Temperature sensor analog input recommended sampling time is 17.1μs, that is, ADC_CLK=14MHz, sampling time is 239.5 cycles = 239.5/14m =17.1μs.

For the use of sensors: Select the ADC1_IN16 input channel, select the sampling time, set the TSVREFE bit of ADC control register 2(ADC_CR2) to wake up the temperature sensor in power off mode, start the ADC conversion (or use external trigger) by setting the ADON bit, read the VSENSE data result on the ADC data register. Using the following formula to get the temperature,

Temperature (°C) = {(v25-vsense)/Avg_Slope} + 25

Here: V25 = VSENSE at 25°C

Avg_Slope = Average slope of temperature and VSENSE curve (mV/ °C or μV/ °C)

So the temperature conversion result is (1.43-(float)(ADCConvertedValue)/4096*3.3)*1000/4.3+25.

Iii. ADC experiment

1. Implemented functions

This example program demonstrates how to continuously transfer ADC1 conversion data from ADC1 to storage space using ADC1 and DMA. The ADC1 is configured to continuously convert data from channel 16 of the ADC. Each end of an ADC conversion triggers a DMA transfer, which continuously transfers data from the DR data register of ADC1 to the ADC_ConvertedValue variable in DMA loop mode. The LCD then displays the temperature value.

2. Connect the hardware

As can be seen from the figure above, PC4 is connected to a resistance regulator, and PC4 acts as an acquisition channel for the ADC, so the analog signal is obtained here and then passed through the CHANNEL PC4.

3. Establishment of project

Hardware: STM32F107VC(Cortex-M3)

Software: Keil μVision4, JLINK

Create folders and subfiles to add to the project.

4. Program flow chart

4.1 Configuring the System Clock

Select the orange route in the figure above to configure the system clock and get the ADCCLK clock. HSE (25MHz) as the system clock source, PLL2_CLK= (HSE / 5) * 8 = 40 MHz through PLL2’s 5 split and 8 times, and PLL’s 5 split and 7 times, PLL_CLK = (PLL2_CLK/ 5) * 7 = 56MHz, then the system clock is 56MHz, that is, PCLK2 (APB2 clock) is 56MHz, and ADC_CLK = 14 MHz through 4 frequency division of PCLK2.

Void RCC_Configuration(void) {/* RCC system reset(for debug purpose) */ / RCC_DeInit(); /* Enable HSE */ / Enable external crystal vibration, STM32F107 series development board with 8M RCC_HSEConfig(RCC_HSE_ON); HSEStartUpStatus = RCC_WaitForHSEStartUp(); If (HSEStartUpStatus == SUCCESS) {/* Enable Prefetch Buffer */ / Enable FLASH Prefetch Buffer FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * / / * HSE = 25 MHZ, HCLK = 56 MHZ, PCLK2 = 56 MHZ, PCLK1 = 28 MHZ, ADCCLK=14MHz */ /****************************************************************/ /* Flash 2 wait state */ // SYSCLK // SYSCLK is set to 0 or 1, and if the SYSCLK is set to 0 or 1, the system will enter a hardware error and the program will die. 0 < SYSCLK <= 24M // 1:24 < SYSCLK <= 48M // 2:48 < SYSCLK <= 72M // FLASH_SetLatency(FLASH_Latency_2); /* HCLK = SYSCLK */ / HCLK = SYSCLK RCC_HCLKConfig(RCC_SYSCLK_Div1) PCLK2 = HCLK RCC_PCLK2Config(RCC_HCLK_Div1); PCLK2 = hclk2config (RCC_HCLK_Div1); /* PCLK1 = HCLK/2 */ / PCLK1 = HCLK/2 RCC_PCLK1Config(RCC_HCLK_Div2) /* ADCCLK = PCLK2/4 */ RCC_ADCCLKConfig(RCC_PCLK2_Div4); // If STM32F10X_CL is not defined by macro, define STM32F10X_CL, #ifndef STM32F10X_CL /* PLLCLK = 8MHz * 7 = 56mhz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); //STM32F10X_CL is defined by macro, Enter the # else program segment # else / * Configure PLLs * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * / / * PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ RCC_PREDIV2Config(RCC_PREDIV2_Div5); RCC_PLL2Config(RCC_PLL2Mul_8); /* Enable PLL2 */ RCC_PLL2Cmd(ENABLE); /* Wait till PLL2 is ready */ while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET) {} /* PLL configuration: PLLCLK = (PLL2 / 5) * 7 = 56 MHz */ RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5); RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7); #endif /* Enable PLL */ / Enable PLL RCC_PLLCmd(Enable); /* Wait till PLL is ready */ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /* Select PLL as system clock source */ / Switch the PLL clock to SYSCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); While (RCC_GetSYSCLKSource()) Wait till PLL is used as system clock source */ = 0x08) { } } /* Enable peripheral clocks --------------------------------------------------*/ /* Enable DMA1 clock */ // ENABLE the DMA1 clock RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); / * the Enable ADC1 and GPIOC clock * / / / can make ADC1, GPIOC clock RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE); }Copy the code

4.2 Configuring GPIO Pins

Analog signals are transmitted to the development board through GPIO pin PC4. The pin mode must be analog input.

void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Configure PC.04 (ADC Channel14) as analog input -------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC, &GPIO_InitStructure); }Copy the code

4.3 Initializing the LCD

void LCD_Configuration(void)
{ /* Initialize the LCD */ 
 STM3210C_LCD_Init();
  /* Clear the LCD */ 
  LCD_Clear(White);
  /* Set the LCD Text Color */
  LCD_SetTextColor(Black);
}
Copy the code

4.4 DMA initialization

The DMA_InitTypeDef structure variable is defined in stm32f10X_dma. h.

/** * @brief DMA Init structure definition */ typedef struct { uint32_t DMA_PeripheralBaseAddr; / *! < Specifies the peripheral base address for DMAy Channelx. */ uint32_t DMA_MemoryBaseAddr; / *! < Specifies the memory base address for DMAy Channelx. */ uint32_t DMA_DIR; / *! < Specifies if the peripheral is the source or destination. This parameter can be a value of @ref DMA_data_transfer_direction */ uint32_t DMA_BufferSize; / *! < Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in the transfer direction. */ uint32_t DMA_PeripheralInc; / *! < Specifies whether the Peripheral address register is incremented or not. This parameter can be a value of @ref DMA_peripheral_incremented_mode */ uint32_t DMA_MemoryInc; / *! < Specifies whether the memory address register is incremented or not. This parameter can be a value of @ref DMA_memory_incremented_mode */ uint32_t DMA_PeripheralDataSize; / *! < Specifies the Peripheral data width. This parameter can be a value of @ref DMA_peripheral_data_size */ uint32_t DMA_MemoryDataSize; / *! < Specifies the Memory data width. This parameter can be a value of @ref DMA_memory_data_size */ uint32_t DMA_Mode; / *! < Specifies the operation mode of the DMAy Channelx. This parameter can be a value of @ref DMA_circular_normal_mode. @note: The circular buffer mode cannot be used if the memory-to-memory data transfer is configured on the selected Channel */ uint32_t DMA_Priority; / *! < Specifies the software priority for the DMAy Channelx. This parameter can be a value of @ref DMA_priority_level */ uint32_t DMA_M2M; / *! < Specifies if the DMAy Channelx will be used in memory-to-memory transfer. This parameter can be a value of @ref DMA_memory_to_memory */ }DMA_InitTypeDef;Copy the code

1) DMA_PeripheralBaseAddr: address of the peripheral

DMA_MemoryBaseAddr: indicates the memory address

When using the DMA transfers data need to set up a peripheral address and storage, peripherals address is the address of the ADC, and the address of the memory, if use 8 bits of data storage must be defined for eight buffers, if use 16 bits data, must be defined as a 16-bit memory buffers, is defined as a 32-bit or more, otherwise the data will go wrong.

2) DMA_DIR: transmission direction selection, optional peripheral to memory, memory to peripherals.

#define DMA_DIR_PeripheralDST              ((uint32_t)0x00000010)
#define DMA_DIR_PeripheralSRC              ((uint32_t)0x00000000)
Copy the code

3) DMA_BufferSize: Set the number of data to be transmitted

4) DMA_PeripheralInc: If the parameter is set to DMA_PeripheralInc_Enable, the function of automatically increasing peripheral addresses is enabled. Peripherals usually have only one data register, so this bit will not be enabled.

#define DMA_PeripheralInc_Enable           ((uint32_t)0x00000040)
#define DMA_PeripheralInc_Disable          ((uint32_t)0x00000000)
Copy the code

5) DMA_MemoryInc: if it is configured as DMA_MemoryInc_Enable, the function of memory address auto-increment is enabled. Our self-defined storage area generally stores multiple data, so the function of memory address auto-increment should be enabled.

#define DMA_MemoryInc_Enable               ((uint32_t)0x00000080)
#define DMA_MemoryInc_Disable              ((uint32_t)0x00000000)
Copy the code

6) DMA_PeripheralDataSize: peripheral data width, optional bytes (8 bits), half word (16 bits), and word (32 bits)

#define DMA_PeripheralDataSize_Byte        ((uint32_t)0x00000000)
#define DMA_PeripheralDataSize_HalfWord    ((uint32_t)0x00000100)
#define DMA_PeripheralDataSize_Word        ((uint32_t)0x00000200)
Copy the code

7) DMA_MemoryDataSize: Memory data width, optional bytes (8 bits), half word (16 bits) and word (32 bits). When data is transferred between peripheral and memory, the width of data on both sides should be set to the same size.

#define DMA_MemoryDataSize_Byte            ((uint32_t)0x00000000)
#define DMA_MemoryDataSize_HalfWord        ((uint32_t)0x00000400)
#define DMA_MemoryDataSize_Word            ((uint32_t)0x00000800)
Copy the code

8) DMA_Mode: DMA transmission mode selection, which can be single transmission or circular transmission. Our ADC acquisition is carried out continuously in a cycle, so the circular transmission mode is used.

#define DMA_Mode_Circular                  ((uint32_t)0x00000020)
#define DMA_Mode_Normal                    ((uint32_t)0x00000000)
Copy the code

9) DMA_Priority: the priority of the channel set by the software. There are four optional priorities: very high, high, medium and low. The DMA channel priority is meaningful only if multiple DMA channels are used at the same time; if it is a single channel, the priority can be set arbitrarily.

#define DMA_Priority_VeryHigh              ((uint32_t)0x00003000)
#define DMA_Priority_High                  ((uint32_t)0x00002000)
#define DMA_Priority_Medium                ((uint32_t)0x00001000)
#define DMA_Priority_Low                   ((uint32_t)0x00000000)
Copy the code

10) DMA_M2M: Memory-to-memory mode, used when using memory-to-memory.

#define DMA_M2M_Enable                     ((uint32_t)0x00004000)
#define DMA_M2M_Disable                    ((uint32_t)0x00000000)
Copy the code

The final initialization code looks like this:

DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA1_Channel1); // Enable the first channel of DMA1 dma_initstructure. DMA_PeripheralBaseAddr = ADC1_DR_Address; DMA_MemoryBaseAddr = (Uint32_t)&ADCConvertedValue; //DMA corresponding memory base address dma_initstructure. DMA_DIR = DMA_DIR_PeripheralSRC; //DMA transfers dMA_initstructure. DMA_BufferSize = 1; //DMA buffer size, 1 dma_initstructure. DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_MemoryInc_Enable; DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_Mode = DMA_Mode_Circular; DMA_Mode = DMA_Mode_Circular; DMA_Mode = DMA_Mode_Circular; DMA_Priority = DMA_Priority_High; DMA_Priority = DMA_Priority_High; //DMA priority, high DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //M2M mode is disabled, DMA_Init(DMA1_Channel1, &DMA_InitStructure); /* Enable DMA1 channel1 */ DMA_Cmd(DMA1_Channel1, ENABLE);Copy the code

4.5 ADC Initialization

The ADC_InitTypeDef structure variable is defined in stm32f10X_adC.h.

typedef struct { uint32_t ADC_Mode; / *! < Configures the ADC to operate in independent or dual mode. This parameter can be a value of @ref ADC_mode */ FunctionalState ADC_ScanConvMode; / *! < Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel) mode. This parameter can  be set to ENABLE or DISABLE */ FunctionalState ADC_ContinuousConvMode; / *! < Specifies whether the conversion is performed in Continuous or Single mode. This parameter can be set to ENABLE or DISABLE. */ uint32_t ADC_ExternalTrigConv; / *! < Defines the external trigger used to start the analog to digital conversion of regular channels. This parameter can be  a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */ uint32_t ADC_DataAlign; / *! < Specifies whether the ADC data alignment is left or right. This parameter can be a value of @ref ADC_data_align */ uint8_t ADC_NbrOfChannel; / *! < Specifies the number of ADC channels that will be converted using the sequencer for regular channel group. This parameter must range from 1 to 16. */ }ADC_InitTypeDef;Copy the code

1) ADC_Mode is the ADC working mode selection, with the following 10 options. If no ADC synchronization is required or only one ADC is used, it should be set to standalone mode. In this mode, the two ADCs cannot be synchronized and each ADC interface works independently.

#define ADC_Mode_Independent                       ((uint32_t)0x00000000)
#define ADC_Mode_RegInjecSimult                    ((uint32_t)0x00010000)
#define ADC_Mode_RegSimult_AlterTrig               ((uint32_t)0x00020000)
#define ADC_Mode_InjecSimult_FastInterl            ((uint32_t)0x00030000)
#define ADC_Mode_InjecSimult_SlowInterl            ((uint32_t)0x00040000)
#define ADC_Mode_InjecSimult                       ((uint32_t)0x00050000)
#define ADC_Mode_RegSimult                         ((uint32_t)0x00060000)
#define ADC_Mode_FastInterl                        ((uint32_t)0x00070000)
#define ADC_Mode_SlowInterl                        ((uint32_t)0x00080000)
#define ADC_Mode_AlterTrig                         ((uint32_t)0x00090000)
Copy the code

2) ADC_ScanConvMode is an ADC scan (multi-channel) or single-channel (single-channel) mode option, which can be set to ENABLE or DISABLE. DISABLE works if only one channel is used, and ENABLE if multiple channels are used.

3) ADC_ContinuousConvMode is a single conversion or continuous conversion option for ADC, and can be set to ENABLE or DISABLE. The difference between the two is that the continuous conversion does not stop until all data has been converted, while the single conversion only stops after the data has been converted once, and the conversion must be triggered again. If a lot of data needs to be collected at once, continuous conversion is used.

4) ADC_ExternalTrigConv is ADC conversion trigger signal selection, that is, select external trigger mode. There are three main categories:

The first is a software trigger with the parameter ADC_ExternalTrigConv_None. Once set up, call the library function ADC_SoftwareStartConvCmd(ADC1, ENABLE); Before it triggers.

The second is timer channel output trigger, The external triggers of ADC1 and ADC2 for regular channels are ADC_ExternalTrigConv_T1_CC1, ADC_ExternalTrigConv_T1_CC2, ADC_ExternalTrigConv_T2_CC2, and ADC_ExternalTri GConv_T3_TRGO, ADC_ExternalTrigConv_T4_CC4. ADC3 external triggers for regular channels include ADC_ExternalTrigConv_T3_CC1, ADC_ExternalTrigConv_T2_CC3, ADC_ExternalTrigConv_T8_CC1, ADC_ExternalTrigConv_T8_TRGO, ADC_ExternalTrigConv_T5_CC1, ADC_ExternalTrigConv_T5_CC3. ADC1, ADC2, ADC3 external triggers for regular channels are ADC_ExternalTrigConv_T1_CC3. Timer output trigger is troublesome, and the corresponding timer needs to be set.

The third type is external pin triggering. For regular channels, EXTI line 11 and TIM8_TRGO (only available in high-volume products) are selected as external triggering events. For the injection channel group, EXTI line 15 and TIM8_CC4 are selected as external trigger events.

#define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000) /*! < For ADC1 and ADC2 */ #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000) /*! < For ADC1 and ADC2 */ #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000) /*! < For ADC1 and ADC2 */ #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000) /*! < For ADC1 and ADC2 */ #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000) /*! < For ADC1 and ADC2 */ #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000) /*! < For ADC1 and ADC2 */ #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) /*! < For ADC1, ADC2 and ADC3 */ #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) /*! < For ADC1, ADC2 and ADC3 */ #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000) /*! < For ADC3 only */ #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000) /*! < For ADC3 only */ #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000) /*! < For ADC3 only */ #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000) /*! < For ADC3 only */ #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000) /*! < For ADC3 only */ #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000) /*! < For ADC3 only */Copy the code

5) ADC_DataAlign is ADC data register alignment format, including right alignment and left alignment. Right alignment is recommended because it facilitates data processing. If data is transmitted from high, left-aligned is used.

#define ADC_DataAlign_Right                        ((uint32_t)0x00000000)
#define ADC_DataAlign_Left                         ((uint32_t)0x00000800)
Copy the code

6) ADC_NbrOfChannel is the number of ADC acquisition channels, ranging from 1 to 16. You need to set this parameter if you are collecting data from multiple channels.

Initial configuration of ADC:

ADC_InitTypeDef ADC_InitStructure; /* ADC1 configuration ------------------------------------------------------*/ ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // Use only one ADC, independent mode adc_initstructure. ADC_ScanConvMode = ENABLE; ADC_ContinuousConvMode = ENABLE; ADC_ContinuousConvMode = ENABLE; // Scan mode adc_initstructure. ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // Use software to trigger adc_initstructure. ADC_DataAlign = ADC_DataAlign_Right; ADC_NbrOfChannel = 1; ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure);Copy the code

4.6 Configuring an ADC Channel, enabling the temperature sensor, and enabling the ADC

ADC_RegularChannelConfig(ADC1,16, 1, ADC_SampleTime_55Cycles5); /* Enable the temperature sensor and vref internal channel */ ADC_TempSensorVrefintCmd(ENABLE); /* Enable ADC1 DMA */ / ADC_DMACmd(ADC1, Enable); /* Enable ADC1 */ / Enable ADC_Cmd(ADC1, Enable);Copy the code

4.7 calibration ADC

/* Enable ADC1 reset calibaration register */ / reset ADC_ResetCalibration(ADC1); / * Check the end of ADC1 reset calibration register * / / / wait for ADC to reset the calibration completed while (ADC_GetResetCalibrationStatus (ADC1)); /* Start ADC1 calibaration */ / Start ADC_StartCalibration; /* Check the end of calibration */ / while(ADC_GetCalibrationStatus(ADC1));Copy the code

4.8 Enabling the ADC Channel on the Software

ADC_SoftwareStartConvCmd(ADC1, ENABLE); /* Start ADC1 Software Conversion */Copy the code

4.9 Obtaining the ADC Conversion value

The converted data is a 12-bit binary number, and the analog quantity (voltage) represented by this binary number needs to be represented digitally. For example, the measured voltage range is 0~3.3V, and the converted binary number is X. Since the 12-bit ADC converts the voltage range (i.e. 3.3) into 4096 (2^12) parts, the converted binary number X represents the real voltage by calculating y=3.3* x / 4096.

While (1) {printf("Chip Temp: %3.1fC\r",(1.42-(float)(ADCConvertedValue)/4096*3.21)*1000/4.35+25); while (1) {printf("Chip Temp: %3.1fC\r",(1.42-(float)(ADCConvertedValue)/4096*3.21)*1000/4.35+25); }Copy the code

5. Complete code

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm3210c_eval_lcd.h"
#include "stm32_eval.h"
#include <stdio.h>




/** @addtogroup STM32F10x_StdPeriph_Examples
  * @{
  */

/** @addtogroup ADC_ADC1_DMA
  * @{
  */ 


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_Address    ((uint32_t)0x4001244C)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
__IO uint16_t ADCConvertedValue;
ErrorStatus HSEStartUpStatus;
    
/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
  
/* Private functions ---------------------------------------------------------*/

/**
  * @brief   Main program
  * @param  None
  * @retval None
  */
/*******************请在此函数中完成为实现温度传感器配置ADC功能函数*************************/
int main(void)
{
  /* System clocks configuration ---------------------------------------------*/
  RCC_Configuration();
  
  /* GPIO configuration ------------------------------------------------------*/
  //GPIO_Configuration();
    /* Initialize the LCD */
  STM3210C_LCD_Init();
  /* Clear the LCD */ 
  LCD_Clear(White);
  /* Set the LCD Text Color */
  LCD_SetTextColor(Black);
  printf("   STM3210C-EVAL    \n");
  printf("  Example on how to use the ADC with ChipTemp\n");

  /* DMA1 channel1 configuration ----------------------------------------------*/
  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //add lwzhang 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_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  
  /* Enable DMA1 channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE);
     
  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1,16, 1, ADC_SampleTime_55Cycles5);

  /* Enable the temperature sensor and vref internal channel */ 
    ADC_TempSensorVrefintCmd(ENABLE); 

  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
  
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibaration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
     
  /* Start ADC1 Software Conversion */ 
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);

  printf("\r\n chip temp test \r\n");
  printf("\r\n                           \r\n");

  while (1)
  {
   printf("Chip temp: %3.1fC\r",(1.42-(float)(ADCConvertedValue)/4096*3.21)*1000/4.35+25);

  }
}
/*************************************************************************/
/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void RCC_Configuration(void)
{
    /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
  
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
  
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); 

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div4); 
  
#ifndef STM32F10X_CL  
    /* PLLCLK = 8MHz * 7 = 56 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);

#else
    /* Configure PLLs *********************************************************/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    RCC_PREDIV2Config(RCC_PREDIV2_Div5);
    RCC_PLL2Config(RCC_PLL2Mul_8);

    /* Enable PLL2 */
    RCC_PLL2Cmd(ENABLE);

    /* Wait till PLL2 is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
    {}

    /* PLL configuration: PLLCLK = (PLL2 / 5) * 7 = 56 MHz */ 
    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
#endif

    /* Enable PLL */ 
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }

/* Enable peripheral clocks --------------------------------------------------*/
  /* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /* Enable ADC1 and GPIOC clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
}

/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval None
  */
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Configure PC.04 (ADC Channel14) as analog input -------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
}


#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */ 

/**
  * @}
  */ 

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
Copy the code