jiongsheng

jiongsheng

MSPM0 Learning, ADC Timer Trigger, DMA Transfer

Preface#

If you have not read the author's previous articles "Step One Configuration" and "MSPM0 Tutorial on Calling SYSCONFIG and Configuring GPIO Output and Input," it is strongly recommended that you read these two articles first to avoid configuration errors. If you have completed the SYSCONFIG configuration, please continue reading.

Chuangyi Stack MSPM0 Development Board Reference Voltage Selection#

image-20230606194556451

According to the user manual of Chuangyi Stack, the onboard VREF is 2.5V. We just need to switch the dip switch on the board to ON.

image-20230606195417792

SYSCONFIG Configuration#

Open empty.syscfg in Keil, then call the SYSCONFIG tool.

image-20230606184519254

In SYSCONFIG, we will add ADC and first take a look at its introduction.

image-20230607184911524

In the basic configuration, users can:

  • Configure the sampling clock and sampling mode: These parameters affect the ADC's sampling rate, which is the number of times the input signal is sampled per second.
  • Configure ADC conversion memory: Store the digital data obtained from the conversion of the analog signal.
  • Enable/disable the following functions:
    • Hardware averaging mode: Reduces the impact of random noise by averaging multiple sampling results.
    • Use a burned current source: May be used to provide a stable reference voltage during ADC conversion.
    • Window comparator mode: ADC conversion only occurs when the input signal is within a specified range.
    • Trigger mode: ADC conversion can be set to start only upon receiving a specific trigger signal.

In the advanced configuration, users can:

  • Configure conversion frequency/resolution: Affects the accuracy and speed of ADC conversion.
  • Enable FIFO mode: In this mode, the ADC can continuously perform multiple conversions and store the results in a first-in-first-out (FIFO) queue for subsequent processing.
  • Configure power-down mode: The power of the ADC module can be reduced when ADC conversion is not needed to save energy.
  • Specify sampling time: For rapidly changing analog signals, shorter sampling times may be required.

ADC Parameters#

image-20230607185752720

As shown in the reference manual, the conversion cycle of this ADC at different resolutions.

image-20230607190449924

If we use ULPCLK, we can bypass this sampling delay.

Check the repeated sampling mode.

image-20230608203635086

Configure the trigger source in SYSCONFIG. I set it to event-triggered, with the event published by the timer.

image-20230607191152249

In the Conversion Data Format option, select unsigned right-aligned.

In the advanced settings, we can determine the sampling rate by setting the acquisition time (the upper limit for 12bit is 1.45M). The sampling rate equals 32 (clock frequency)/(1/sampling time + conversion time (12bit resolution is 14 clock cycles)). By calculation, setting the sampling time to 250ns (i.e., eight (32M) clock cycles), the sampling rate will be 32/(8+14)=1.45M.

image-20230610201941717

Next, we will configure the timer. The timer configuration is shown in the figure; ensure that the corresponding trigger event is set correctly.

image-20230610195248506

Then return to the ADC configuration page and set up the subscription event.

image-20230610195517210

Then enable DMA transfer and set the DMA parameters, including trigger source, data length, address mode settings, and transfer mode.

image-20230610195613677

The transfer mode defines how data is transferred from the source address to the destination address. There are four modes:

  1. Single Transfer: In this mode, each transfer requires a trigger signal. After the number of transfers set by "Transfer Size" is completed, the DMA will be disabled.

  2. Block Transfer: In this mode, a single trigger signal can transfer a complete block of data, with the block size determined by "Transfer Size." The DMA will be disabled after each transfer.

  3. Repeated Single Transfer: In this mode, each transfer requires a trigger signal, but the DMA remains enabled after all transfers are completed.

  4. Repeated Block Transfer: In this mode, a single trigger signal can transfer a complete block of data, with the block size determined by "Transfer Size." Like "Repeated Single Transfer," the DMA remains enabled after all transfers are completed.

The choice of transfer mode depends on your specific needs. For example, if you need to continuously transfer large amounts of data, you can choose "Block Transfer" or "Repeated Block Transfer" mode; if you need fine control over each data transfer, you can choose "Single Transfer" or "Repeated Single Transfer" mode.

image-20230608204512192

Click FILE-save, then compile in Keil and import the configuration.

#define ADCSize 128

typedef enum ADCFlag

{

  ADCFlagDmaStart = 0,

  ADCFlagDmaDone,

  ADCFlagConversionDone,

  ADCFlagConversionStart

}ADCFlag;

unsigned short ADCResult[ADCSize];// Define ADC reception buffer
ADCFlag adcflag;// Define enumeration variable adcflag

void UART1SendString(char *str)
{
    while(*str != '\0')
    {
        DL_UART_transmitDataBlocking(UART1_INST, *str);
        str++;
    }
}
void UART1SendChar(char c)
{
    DL_UART_transmitDataBlocking(UART1_INST, c);
}

void strreverse(char* begin, char* end) {
   char aux;
   while(end>begin)
       aux=*end, *end--=*begin, *begin++=aux;
}
/**

 * @brief  Converts an integer value to a null-terminated string of a specified base and stores the result in the array given by the str parameter.
   *

 * @param  value: The value to convert to a string.

 * @param  str: The array for storing the result as a null-terminated string. This array should be long enough to hold the result string (including the null character).

 * @param  base: The base of the number to convert. It must be in the range [2, 36]. For bases greater than 10, this function uses lowercase letters.
   *

 * @note   If the base is 10 and value is negative, the result string will be prefixed with a negative sign (-). For any other base, value is always treated as unsigned.
   *

 * @note   If the base is not in the range [2, 36], the function will perform no operations, and str will be an empty string.
   *

 * @note   This function does not handle "unsigned long" numbers - it will treat them as "long." Therefore, for values greater than 2147483647, this function does not work for bases greater than 10.
   *

 * @return None.
   */
   void itoa(int value, char* str, int base) {
   static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
   char* wstr = str;
   int sign;

   // Validate base
   if (base < 2 || base > 35) { *wstr = '\0'; return; }

   // Take care of sign
   if ((sign=value) < 0) value = -value;

   // Conversion. Number is reversed.
   do *wstr++ = num[value%base]; while(value/=base);

   if(sign<0) *wstr++='-';
   *wstr='\0';

   // Reverse string
   strreverse(str,wstr-1);
   }


/**

 * @brief  Function to process ADC results
   *
 * @param  adcflag: Pointer to the ADC flag, which will be set to ADCFlagDmaDone when the ADC completes data conversion
 * @param  ADCResult: Pointer to the array storing ADC results
 * @param  resultSize: Size of the ADC result array
   *
 * @note   When the value pointed to by adcflag is ADCFlagDmaDone, the function stops the timer and ADC data conversion, then iterates through the ADCResult array,
 * and uses the itoa function to convert each result to a string, which is then sent via UART. After sending all results, the function sets the value pointed to by adcflag to ADCFlagConversionStart,
 * indicating that the ADC can start a new round of data conversion. Note that when sending strings, a newline character is sent after each result so that the receiving end can correctly identify the boundaries of each result.
    *
 * @return None.
   */
   void processADCResults(ADCFlag* adcflag, unsigned short* ADCResult, int resultSize) 
   {
   if (*adcflag == ADCFlagDmaDone) 
   {
       DL_Timer_stopCounter(TIMER_0_INST);
       DL_ADC12_stopConversion(ADC12_0_INST);
       volatile int i;
       for ( i = 0; i < resultSize; i++) 
       {
          char buffer[12]; // Buffer for integer to string conversion, max size for int32 is 11 characters + null terminator
            itoa(ADCResult[i], buffer, 10);
            UART1SendString(buffer);
            UART1SendString("\r\n");
       }
       *adcflag = ADCFlagConversionStart;
       i = 0;
   }
   }
   void setupDMA(DMA_Regs *dma, uint8_t channelNum, unsigned int srcAddr, unsigned int destAddr, unsigned int transferSize)
   {
    DL_DMA_setSrcAddr(dma, channelNum, (unsigned int) srcAddr);
    DL_DMA_setDestAddr(dma, channelNum, (unsigned int) destAddr);
    DL_DMA_setTransferSize(dma, channelNum, transferSize);
    DL_DMA_enableChannel(dma, channelNum);
   }

int main(void)
{
    SYSCFG_DL_init();
    NVIC_EnableIRQ(UART1_INT_IRQn);
    NVIC_EnableIRQ(ADC0_INT_IRQn);
    adcflag = ADCFlagConversionStart;
    setupDMA(DMA,DMA_CH0_CHAN_ID,(unsigned int) & (ADC0->ULLMEM.MEMRES[0]),(unsigned int) &ADCResult,ADCSize);

    if(adcflag == ADCFlagConversionStart)
   {
       DL_Timer_startCounter(TIMER_0_INST);
       DL_ADC12_startConversion(ADC12_0_INST);
   }
   while (1) 
    {
   processADCResults(&adcflag, ADCResult, ADCSize);
    }
}

Actual Demonstration#

Since I only sample 128 points each time and do not sample continuously, each time I reset, the sampled signal will definitely not be continuous with the last time, resulting in the sharp points shown below. From the perspective of a continuous signal, the effect is still quite good.

image-20230610192450348

Please indicate the source when reprinting.

by <a href=https://www.cnblogs.com/jiongsheng > QDU_jiongsheng

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.