Continuous Mode

This sample demonstrates voltage detection using the ADC continuous sampling mode. The configuration can be modified to control whether GDMA is used for data transfer.

In continuous sampling mode, the ADC’s sampled data is stored in the ADC FIFO by default. If the GDMA transfer function is used, the GDMA transfers data from the ADC FIFO to memory.

Users can change the sampling mode of the ADC channel, input voltage range, and other information in the sample through different macro configurations. For specific macro configurations, see Configurations.

Requirements

For requirements, please refer to the Requirements.

Wiring

Use a Dupont wire to connect P2_4 to external voltage input.

Configurations

  1. The following macro can be configured to modify whether to use GDMA for transferring ADC FIFO data. 1 indicates using GDMA, 0 indicates not using GDMA.

    #define ADC_CONFIG_GDMA_MODE_EN             0                   /*< Set this macro to configure whether to use GDMA for transferring ADC FIFO data. */
    
  2. The following macro can be configured to modify the ADC input voltage range.

    #define ADC_DIVIDE_MODE                     1                   /*< Divide Mode, input voltage range is 0V~Vbat. */
    #define ADC_BYPASS_MODE                     0                   /*< Bypass Mode, input voltage range is 0V~0.9V. */
    
    #define ADC_MODE_DIVIDE_OR_BYPASS           ADC_DIVIDE_MODE     /*< Set this macro to select the ADC input voltage range. */
    
  3. The following macro can be configured to modify the pin definitions.

    #define ADC_SAMPLE_PIN_0                    P2_4
    #define ADC_SAMPLE_CHANNEL_0                ADC_Channel_Index_4
    
  4. The following macro can be configured to modify the GDMA channel-related configurations.

    // Set the following macros to modify the ADC GDMA Channel configurations.
    #define ADC_GDMA_CHANNEL_NUM                0
    #define ADC_GDMA_Channel                    GDMA_Channel0
    #define ADC_GDMA_Channel_IRQn               GDMA0_Channel0_IRQn
    #define ADC_GDMA_Channel_Handler            GDMA0_Channel0_Handler
    
  5. The following macro can be configured to modify the data transfer length for ADC GDMA.

    #define GDMA_TRANSFER_SIZE                  100                       /*< Set this macro to modify the transfer size. */
    
  6. The following macro can be configured to modify the sampling period time for ADC continuous sampling mode.

    #define ADC_CONTINUOUS_SAMPLE_PERIOD        (200-1)//20us             /*< Set this macro to modify the ADC sample period. */
    

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

  1. When the EVB starts, observe the following log within the Debug Analyzer.

    Start ADC Continuous Mode test !
    
  2. ADC Configurations:

    1. If ADC_MODE_DIVIDE_OR_BYPASS is configured as ADC_DIVIDE_MODE, the following log will be printed:

      [ADC]ADC sample mode is divide mode !
      
    2. If ADC_MODE_DIVIDE_OR_BYPASS is configured as ADC_BYPASS_MODE, the following log will be printed:

      [ADC]ADC sample mode is bypass mode !
      
  3. After initialization is complete, the ADC begins sampling. When the data in the ADC FIFO reaches the threshold, it will trigger an ADC interrupt. When the data transferred by the GDMA reaches the set value, it will trigger a GDMA interrupt. Within the interrupt function, print the raw data obtained from sampling and the converted voltage values.

    [io_adc]io_adc_voltage_calculate: ADC rawdata_0 = xxx, voltage_0 = xxxmV
    [io_adc]io_adc_voltage_calculate: ADC rawdata_1 = xxx, voltage_1 = xxxmV
    ...
    
  4. If the ADC FIFO overflows, it will trigger the ADC_INT_FIFO_OVERFLOW interrupt, and the log will print relevant information.

    ADC_INT_FIFO_OVERFLOW
    
  5. If data is read when the ADC FIFO is empty, it will trigger the ADC_INT_FIFO_RD_ERR interrupt, and the log will print relevant information.

    ADC_INT_FIFO_RD_ERR
    

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directory for project file and source code are as follows:

  • Project directory: sdk\samples\peripheral\adc\continuous_gdma\proj

  • Source code directory: sdk\samples\peripheral\adc\continuous_gdma\src

Initialization

The initialization flow for peripherals can refer to Initialization Flow in General Introduction.

  1. Call Pad_Config() and Pinmux_Config() to configure the PAD and PINMUX of the corresponding pins. Please ensure that the PAD is configured in Shutdown mode to prevent leakage.

    void board_adc_init(void)
    {
        Pad_Config(ADC_SAMPLE_PIN_0, PAD_SW_MODE, PAD_NOT_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_LOW);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the ADC clock.

  3. Initialize the ADC peripheral:

    1. Define the ADC_InitTypeDef type ADC_InitStruct, and call ADC_StructInit() to pre-fill ADC_InitStruct with default values.

    2. Modify the ADC_InitStruct parameters as needed. When ADC_CONFIG_GDMA_MODE_EN is configured with different values, the initialization configuration will be different. The ADC initialization parameter configuration is shown in the table below.

    3. Call ADC_Init() to initialize the ADC peripheral.

ADC Initialization Parameters

ADC Hardware Parameters

Setting in the ADC_InitStruct

ADC_CONFIG_GDMA_MODE_EN=0

ADC_CONFIG_GDMA_MODE_EN=1

Sample Time

ADC_InitTypeDef::ADC_SampleTime

199

199

Schedule Index

ADC_InitTypeDef::ADC_SchIndex

Index 0 is set to EXT_SINGLE_ENDED(4)

Index 0 is set to EXT_SINGLE_ENDED(4)

Bit Map

ADC_InitTypeDef::ADC_Bitmap

0x01

0x01

Data Write to FIFO

ADC_InitTypeDef::ADC_DataWriteToFifo

ENABLE

ENABLE

ADC Water Level

ADC_InitTypeDef::ADC_WaterLevel

-

4

FIFO Threshold Level

ADC_InitTypeDef::ADC_FifoThdLevel

16

-

Power Always On

ADC_InitTypeDef::ADC_PowerAlwaysOnEn

ENABLE

ENABLE

  1. If ADC_MODE_DIVIDE_OR_BYPASS is configured as ADC_BYPASS_MODE, the function ADC_BypassCmd() must be called to enable the Bypass mode for the corresponding pin.

  2. Call ADC_INTConfig() to configure the ADC interrupt and NVIC. For NVIC configurations, refer to Interrupt Configuration.

    1. If ADC_CONFIG_GDMA_MODE_EN is configured as 0, configure the ADC FIFO threshold interrupt ADC_INT_FIFO_THD.

    2. If ADC_CONFIG_GDMA_MODE_EN is configured as 1, configure the ADC FIFO overflow interrupt ADC_INT_FIFO_OVERFLOW and ADC FIFO read error interrupt ADC_INT_FIFO_RD_ERR.

  3. Before the ADC begins sampling, it is necessary to call ADC_CalibrationInit() for ADC voltage calibration. If the return value is false, it indicates that the IC has not been calibrated and cannot accurately convert voltage values, but raw data can still be read.

  4. If ADC_CONFIG_GDMA_MODE_EN is configured as 1, initialize the GDMA peripheral:

    1. Define a GDMA_InitTypeDef type GDMA_InitStruct, and call GDMA_StructInit() to pre-fill GDMA_InitStruct with default values.

    2. Modify the GDMA_InitStruct parameters as needed. The initialization parameters for the GDMA channel are configured as shown in the table below. Call GDMA_Init() to initialize the GDMA peripheral.

    3. Configure the GDMA total transfer complete interrupt GDMA_INT_Transfer and NVIC. For NVIC configurations, refer to Interrupt Configuration.

    4. Call GDMA_Cmd() to enable the corresponding GDMA channel transfer.

GDMA Initialization Parameters

GDMA Hardware Parameters

Setting in the GDMA_InitStruct

GDMA Channel

Channel Num

GDMA_InitTypeDef::GDMA_ChannelNum

0

Transfer Direction

GDMA_InitTypeDef::GDMA_DIR

GDMA_DIR_PeripheralToMemory

Buffer Size

GDMA_InitTypeDef::GDMA_BufferSize

100

Source Address Increment or Decrement

GDMA_InitTypeDef::GDMA_SourceInc

DMA_SourceInc_Fix

Destination Address Increment or Decrement

GDMA_InitTypeDef::GDMA_DestinationInc

DMA_DestinationInc_Inc

Source Data Size

GDMA_InitTypeDef::GDMA_SourceDataSize

GDMA_DataSize_HalfWord

Destination Data Size

GDMA_InitTypeDef::GDMA_DestinationDataSize

GDMA_DataSize_HalfWord

Source Burst Transaction Length

GDMA_InitTypeDef::GDMA_SourceMsize

GDMA_Msize_4

Destination Burst Transaction Length

GDMA_InitTypeDef::GDMA_DestinationMsize

GDMA_Msize_4

Source Address

GDMA_InitTypeDef::GDMA_SourceAddr

(&(ADC->ADC_FIFO_READ))

Destination Address

GDMA_InitTypeDef::GDMA_DestinationAddr

ADC_Recv_Buffer

Source Handshake

GDMA_InitTypeDef::GDMA_SourceHandshake

GDMA_Handshake_ADC_RX

Functional Implementation

ADC Sampling Data Without Using GDMA Transfer

When ADC sampling data is not transferred using GDMA, the flow for continuous mode sampling is as shown in the figure:

Here should be ADC continuous not GDMA flow

ADC Continuous Sampling Flow (Without Using GDMA Transfer)

  1. Call ADC_ClearFIFO() to clear the data in the ADC FIFO before sampling.

  2. Call ADC_Cmd() to start continuous ADC sampling.

  3. When the sampled data in the FIFO reaches the set threshold, trigger the ADC ADC_INT_FIFO_THD interrupt. Within the interrupt function, call ADC_GetFIFODataLen() to read the data length in the FIFO; call ADC_ReadFIFOData() function to read the data in the FIFO; call ADC_GetVoltage() function, input the corresponding sampling mode, and convert the sampled data to voltage values.

  4. After data processing is completed, call ADC_ClearFIFO() to clear the data in the ADC FIFO.

    void SAR_ADC_Handler(void)
    {
        ...
        if (ADC_GetINTStatus(ADC, ADC_INT_FIFO_THD) == SET)
        {
            ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, DISABLE);
    
            data_len = ADC_GetFIFODataLen(ADC);
            ADC_ReadFIFOData(ADC, sample_data, data_len);
    
            ADC_ClearFIFO(ADC);
            ADC_ClearINTPendingBit(ADC, ADC_INT_FIFO_THD);
    
            for (uint8_t i = 0; i < data_len; i++)
            {
                sample_voltage[i] = ADC_GetVoltage(DIVIDE_SINGLE_MODE, (int32_t)sample_data[i], &error_status);
                ...
            }
        }
        for (uint32_t i = 0; i < 1000000; i++) {};
        ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, ENABLE);
    
    }
    

ADC Sampling Data Using GDMA Transfer

When ADC sampling data is transferred using GDMA, the flow for continuous mode sampling is as shown in the figure:

Here should be ADC continuous GDMA flow

ADC Continuous Sampling Flow (Using GDMA Transfer)

  1. After enabling the GDMA transfer, when the sampled data in the ADC FIFO reaches the set threshold, it will trigger a GDMA transfer, and the GDMA will move the data from (&(ADC->ADC_FIFO_READ)) to ADC_Recv_Buffer.

  2. After the GDMA data transfer is complete, it triggers the GDMA GDMA_INT_Transfer interrupt.

    1. In the interrupt function, call ADC_Cmd() to enable the ADC continuous sampling mode to prevent continued sampling during interrupt processing from causing ADC FIFO overflow.

    2. Call the ADC_GetVoltage() function to convert the sampled data into voltage values.

    3. Re-enable the source address and destination address of GDMA, and re-enable GDMA transfer.

    4. Call ADC_ClearFIFO() to clear the data in the ADC FIFO, and call ADC_Cmd() to re-enable the ADC continuous sampling mode.

      void ADC_GDMA_Channel_Handler(void)
      {
          ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, DISABLE);
          DBG_DIRECT("into ADC_GDMA_Channel_Handler");
          float sample_voltage = 0;
          ADC_ErrorStatus error_status = NO_ERROR;
      
          for (uint32_t i = 0; i < GDMA_TRANSFER_SIZE; i++)
          {
              uint16_t sample_data = ADC_Recv_Buffer[i];
              sample_voltage = ADC_GetVoltage(DIVIDE_SINGLE_MODE, (int32_t)sample_data, &error_status);
              ...
          }
      
          platform_delay_ms(1000);
      
          /* Restart dma and adc */
          GDMA_SetSourceAddress(ADC_GDMA_Channel, (uint32_t)(&(ADC->ADC_FIFO_READ)));
          GDMA_SetDestinationAddress(ADC_GDMA_Channel, (uint32_t)(ADC_Recv_Buffer));
          GDMA_SetBufferSize(ADC_GDMA_Channel, GDMA_TRANSFER_SIZE);
          GDMA_ClearINTPendingBit(ADC_GDMA_CHANNEL_NUM, GDMA_INT_Transfer);
          GDMA_Cmd(ADC_GDMA_CHANNEL_NUM, ENABLE);
      
          ADC_ClearFIFO(ADC);
          ADC_Cmd(ADC, ADC_CONTINUOUS_MODE, ENABLE);
      
      }
      
  3. When the ADC FIFO overflows, trigger the ADC_INT_FIFO_OVERFLOW interrupt, clear the ADC FIFO data within the ADC interrupt function, and print the relevant information.

    void SAR_ADC_Handler(void)
    {
        if (ADC_GetINTStatus(ADC, ADC_INT_FIFO_RD_ERR) == SET)
        {
            DBG_DIRECT("ADC_INT_FIFO_RD_ERR!");
            ADC_ClearINTPendingBit(ADC, ADC_INT_FIFO_RD_ERR);
        }
        if (ADC_GetINTStatus(ADC, ADC_INT_FIFO_OVERFLOW) == SET)
        {
            ADC_WriteFIFOCmd(ADC, DISABLE);
            DBG_DIRECT("ADC_INT_FIFO_OVERFLOW");
    
            ADC_ClearFIFO(ADC);
            ADC_WriteFIFOCmd(ADC, ENABLE);
            ADC_ClearINTPendingBit(ADC, ADC_INT_FIFO_OVERFLOW);
        }
    }