1
\$\begingroup\$

Just had a quick question as to why the output of the DAC looks different at varying frequencies.

Using a STM32L432KC that has a 12-bit ADC and 12-bit DAC.

enter image description here Figure 1. Initial Start

enter image description here

Figure 2. I just zoomed in just to show what it looks like for later on

enter image description here

Figure 3. Almost looks like figure one but at a much higher frequency

enter image description here

Figure 4. If zoomed in looks like Figure 2

My point is I guess, using the same time sample why does it go from looking nice to pretty bad back to nice at certain frequencies?

\$\endgroup\$
7
  • \$\begingroup\$ What's the frequency of the DAC? \$\endgroup\$ Apr 26, 2020 at 18:07
  • \$\begingroup\$ Hey! Thanks for the reply. I am not entirety sure is there a way I can find out? Thought dacs are made from R2R ladders? \$\endgroup\$
    – Leoc
    Apr 26, 2020 at 18:15
  • \$\begingroup\$ In the datasheet they should be mentioning the sampling/interpolating rates of the ADCs and DACs respectively, because what could be happening here is "Aliasing". A term popular is DSP \$\endgroup\$ Apr 26, 2020 at 18:17
  • \$\begingroup\$ The ADC is sampling at 266kHz. I found some DAC specs could it be the settling time? Otherwise theres nothing in it that references Frequency nor time \$\endgroup\$
    – Leoc
    Apr 26, 2020 at 18:23
  • \$\begingroup\$ How is the data fed to the DAC? Where does it come from? Post your code. \$\endgroup\$
    – Justme
    Apr 26, 2020 at 18:54

2 Answers 2

2
\$\begingroup\$

I found the problem. The problem was aliasing. I had a sprintf function. That was causing the overhead. Thats crazy. the clock is at 4mHz, ADC clock was at 266kHz I was alising around 3kHz does the sprintf really have that much of an over head?

Using a

ADC Clocked @ 266kHz

System Clocked @ 4mHz

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "custom.h"
char buffer[20];
short adcValue = 0;

void DMA2_Channel3_IRQHandler(void){

    if (((DMA2->ISR) & (1<<9)) != 0){
        DAC1->DHR12R1 = adcValue;
        //printADC(adcValue); // Causing the problem
    }

}


int main(void)
{

    //initDebug();
    initADC();
    initDAC();
    initInterrupt();

  while (1)
  {


  }


}


void printADC(int adcValue){

    sprintf(buffer, "ADC VALUE: [%d]\n\r", adcValue);
}

void initDebug(){

    RCC->APB1ENR1 |= (1<<17); // Enable USART2 Clock
    RCC->AHB1ENR |= (1<<0); // Enable DMA1 Clock
    RCC->AHB2ENR |= (1<<0); //Enable GPIOA Clock
    RCC->CCIPR = (1<<2); //Use the System Clock for USART2

    GPIOA->MODER &= ~(1<<4); //Enable Alt Function for PA_2
    GPIOA->MODER |= (1<<5);
    GPIOA->AFR[0] |= ((1<<10) | (1<<9) | (1<<8)); //Enable USART2_Tx for PA_2

    USART2->CR1 |= (1<<3); //Enable Transmitter
    USART2->CR3 |= (1<<7); //Enable DMA Transmission
    USART2->BRR = 0x1A0; //9600 baudrate

    DMA1_Channel7->CCR |= (1<<13); //Prio Level High
    DMA1_Channel7->CCR |= (1<<7); //MINC
    DMA1_Channel7->CCR |= (1<<5); //Circ
    DMA1_Channel7->CCR |= (1<<4); //DIR
    DMA1_Channel7->CNDTR = 20;
    DMA1_Channel7->CMAR = (uint32_t)buffer;
    DMA1_Channel7->CPAR = (uint32_t)&USART2->TDR;
    DMA1_CSELR->CSELR = (1<<25);

    DMA1_Channel7->CCR |= (1<<0);
    USART2->CR1 |= (1<<0); //Enable USART2
}

void initADC(){

    RCC->AHB2ENR |= ((1<<0) | (1<<13)); //Enable GPIOA Clock & ADC Clock
    RCC->AHB1ENR |= (1<<1); //Enable DMA2 Clock
    RCC->CCIPR |= ((1<<29) | (1<<28)); //Uses System Clock for ADC

    GPIOA->MODER |= ((1<<15) | (1<<14)); //Enable Analog Mode for PA_7

    DMA2_Channel3->CCR |= ((1<<13) | (1<<12)); //Prio = Very High
    DMA2_Channel3->CCR |= (1<<10); //16 Bit Memory Size (Can't do 12)
    DMA2_Channel3->CCR |= (1<<8); //16 Bit Peripheral Size (Cant do 12)
    DMA2_Channel3->CCR |= (1<<5); //Enable Circ mode
    DMA2_Channel3->CCR |= (1<<1); //Enable TCE
    DMA2_Channel3->CNDTR = 0x01; //Counter
    DMA2_Channel3->CMAR = (uint32_t)&adcValue;
    DMA2_Channel3->CPAR = (uint32_t)&ADC1->DR;

    ADC1->CR &= ~(1<<29); //Disable Deep power ode
    ADC1->CR |= (1<<28); //Enable Voltage Regulator
    ADC1->CFGR |= (1<<13); //Enable Continuous
    ADC1->CFGR |= (1<<1); //Enable DMA Circular Mode
    ADC1->CFGR |= (1<<0); // Enable DMA
    ADC1->CR |= (1<<31); //Start Calbi
    while(((ADC1->CR) & (1<<31)) != 0); //Wait for Calbi to be done
    ADC1->SQR1 |= ((1<<9) | (1<<8)); //First Seq: Channel 12
    ADC1->CR |= (1<<0); //Enable ADC
    while(((ADC1->ISR) & (1<<0)) == 0); //Wait for the ADC to be ready
    ADC1->ISR |= (1<<0); //Clear the ARDYFlAG

    DMA2_Channel3->CCR |= (1<<0); //Enable DMA2
    ADC1->CR |= (1<<2); //ADSTART
}

void initDAC(){

    RCC->APB1ENR1 |= (1<<29); // Enable Dac
    RCC->AHB2ENR |= (1<<0);
    GPIOA->MODER |= ((1<<9) | (1<<8));
    DAC1->CR |= (1<<0);

}

void initInterrupt(){

    NVIC_EnableIRQ(DMA2_Channel3_IRQn);
    NVIC_SetPriority(DMA2_Channel3_IRQn,0);
}
\$\endgroup\$
17
  • 3
    \$\begingroup\$ depends what you're printing to, but yes, I would generally avoid any printing functions in timing critical code, almost anything that doesnt need user input. If you absolutely have to print data, i would try to make it not block anything else \$\endgroup\$
    – BeB00
    Apr 26, 2020 at 23:04
  • \$\begingroup\$ I was printing to the UART. Can you maybe explain it more to me? If I had the ADC sampling at 266kHz is this its own clock are did we tone down the system clock? Let see it was its own clock would the sprintf still run on the system clock of 4mHz? I used a DMA for the ADC so the 4mHz should be dedicated to the printing no? \$\endgroup\$
    – Leoc
    Apr 26, 2020 at 23:07
  • \$\begingroup\$ Ill update the body with the code. \$\endgroup\$
    – Leoc
    Apr 26, 2020 at 23:07
  • \$\begingroup\$ the initial problem is likely nothing to do with the ADC or the DAC. You are blocking the interrupt with your printing. When you enter the interrupt, the DAC will be updated with the adc value, but the printf is delaying the next interrupt (looks like it takes about 400us, which is very reasonable). You may want to also check if you are able to drive the dac so fast, but again that is not your main problem. \$\endgroup\$
    – BeB00
    Apr 26, 2020 at 23:24
  • \$\begingroup\$ The DMA is only for the result of the ADC. Your problem is updating the value of the DAC. \$\endgroup\$
    – BeB00
    Apr 26, 2020 at 23:27
-1
\$\begingroup\$

Those wide flat regions are because of the sinusoidal peak occurred in between the samples.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.