1
\$\begingroup\$

its been a while. Back at it again with another question.

My ADC sampling rate is set to 20kHZ. I took pictures of the ouput DAC at three different frequencies

  1. at 770Hz * 2 = 1540Hz (Nyquist Frequency)
  2. at 10Hz * 2 = 20Hz (Nyquist Frequency)
  3. at 58Hz * 2 = 116Hz (Nyquist Frequency)

I am sampling at 20kHz, thats higher than all these nyquist frequency but yet anything higher than 10Hz gives me some sort of aliasing or distortion, I have no idea. I am using the STM32L432KC has the MCU if that matters

Yellow is the DAC output.

Any ideas what might be going on?

enter image description here Frequency = 770Hz

Amplitude = 1.00Vpp

Offset = 1.00V enter image description here Frequency = 10Hz

Amplitude = 1.00Vpp

Offset = 1.00V enter image description here Frequency = 58Hz

Amplitude = 1.00Vpp

Offset = 1.00V

enter image description here Essentially, I have it that every rising edge output 10000 samples. Thats why I zoomed in so you can see the wave that outputs within 0.5ms.

Code:

    #include "main.h"
#include <stdint.h>

void init_Interrupt(void);
void init_Clock(void);
void init_Interrupt(void);
void init_DAC(void);
void init_ADC(void);
void init_GPIO_Test(void);
void init_Debug(void);
void print_ADC(short);

char buffer[20] = "ADC Value:     \n\r";

typedef struct PLL{
    uint8_t PLLN;
    uint8_t PLLR;
    uint8_t PLLM;
    uint8_t PLLSAI1N;
    uint8_t PLLSAI1R;
} PLL;

PLL find_PLL(uint32_t, uint32_t);
PLL CFGR;

uint8_t escape = 0;
uint8_t half_transfer_complete = 0;
uint8_t transfer_complete = 0;
uint32_t PLLN_MAX = 86;
uint32_t PLLSAI1N_MAX = 86;
uint32_t PLLR_MAX = 8;
uint32_t PLLSAI1R_MAX = 8;
uint32_t PLLM_MAX = 8;
uint32_t CPU_Speed = 80000000;
uint32_t ADC_Speed = 13000000;
uint16_t ADC_Value[20000]; // Samples

void DMA2_Channel3_IRQHandler(void){

    if (((DMA2->ISR) & (DMA_ISR_HTIF3)) != 0){
        half_transfer_complete = 1;
        DMA2->IFCR |= DMA_IFCR_CHTIF3;
    } else if (((DMA2->ISR) & (DMA_ISR_TCIF3)) != 0){
        transfer_complete = 1;
        DMA2->IFCR |= DMA_IFCR_CTCIF3;
    }
}

int main(void) {

  init_Clock();
  //init_Debug();
  init_ADC();
  init_DAC();
  init_GPIO_Test();
  init_Interrupt();

    while (1) {

            if (half_transfer_complete == 1){
                GPIOA->BSRR |= GPIO_BSRR_BS0;
                for (int i = 0; i < 10000; i++){
                    DAC1->DHR12R1 = ADC_Value[i];
                }

                half_transfer_complete = 0;
            }

            if (transfer_complete == 1){
                GPIOA->BSRR |= GPIO_BSRR_BR0;

                transfer_complete = 0;
            }
    };
}

PLL find_PLL(uint32_t CPU_Speed, uint32_t ADC_Speed) {

    PLL settings;

     for (int PLLN = 8; PLLN <= PLLN_MAX; PLLN ++){
        if (escape == 1){
            break;
        }
         for (int PLLM = 1; PLLM <= PLLM_MAX; PLLM ++){
             if (escape == 1){
                 break;
             }
            for (int PLLR = 2; PLLR <= PLLR_MAX ; PLLR +=2){
                if ((((4000000/PLLM) * PLLN) >= 64000000) & (((4000000/PLLM) * PLLN) <= 344000000)){
                    if (((4000000/PLLM) >= 4000000) & ((4000000/PLLM) <= 16000000)) {
                        if (((((4000000/PLLM)*PLLN)/PLLR) >= 8000000) & ((((4000000/PLLM)*PLLN)/PLLR) <= 80000000)){
                           uint32_t PLL_CALC = (((4000000/PLLM)*PLLN)/PLLR);
                            if (PLL_CALC == CPU_Speed){
                              settings.PLLM = PLLM;
                              settings.PLLR = PLLR;
                              settings.PLLN = PLLN;
                              escape = 1;
                              break;
                            }
                        }
                    }
                }

                }
            }
        }

        escape = 0;

        for (int PLLSAI1N = 8; PLLSAI1N <= PLLSAI1N_MAX; PLLSAI1N ++){
            if (escape == 1){
                 break;
        }
            for (int PLLSAI1R = 2; PLLSAI1R <= PLLSAI1R_MAX; PLLSAI1R += 2){
                if ((((4000000/settings.PLLM) * PLLSAI1N) >= 64000000) & (((4000000/settings.PLLM) * PLLSAI1N) <= 344000000)){
                   if (((((4000000/settings.PLLM)*PLLSAI1N)/PLLSAI1R) >= 8000000) & ((((4000000/settings.PLLM)*PLLSAI1N)/PLLSAI1R) <= 80000000)){
                       uint32_t PLLSAI1_CALC = (((4000000/settings.PLLM)*PLLSAI1N)/PLLSAI1R);
                       if (PLLSAI1_CALC == ADC_Speed){
                        settings.PLLSAI1R = PLLSAI1R;
                        settings.PLLSAI1N = PLLSAI1N;
                        escape = 1;
                        break;
                    }
                   }

                }
            }
          }
                return settings;
        }

void init_ADC(){

        RCC -> AHB2ENR |= RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_ADCEN;
        RCC -> AHB1ENR |= RCC_AHB1ENR_DMA2EN;
        RCC -> CCIPR |= RCC_CCIPR_ADCSEL_1;

        GPIOA -> MODER &= ~GPIO_MODER_MODE7;
        GPIOA -> MODER |=  GPIO_MODER_MODE7_Analog; //PIN A6

        // |------------------- ADC VALUE ----------------------|
        // 16-bit @ 44.1kHZ
        // 16-bit = 2 byte * 20khz =  40 kB
        DMA2_Channel3 -> CCR |= (DMA_CCR_PSIZE_16_Bit) |
                              (DMA_CCR_MSIZE_16_Bit)   |
                              (DMA_CCR_MINC)           |
                              (DMA_CCR_CIRC)           |
                              (DMA_CCR_TCIE)           |
                              (DMA_CCR_HTIE)           |
                              (DMA_CCR_PL_Very_High);
        DMA2_CSELR -> CSELR &= ~DMA_CSELR_C3S;
        DMA2_Channel3 -> CNDTR |= 0x4E20;
        DMA2_Channel3 -> CMAR = (uint32_t)ADC_Value; //Memory Address
        DMA2_Channel3 -> CPAR = (uint32_t)&ADC1->DR; //Peripheral Addres
        DMA2_Channel3 -> CCR |= DMA_CCR_EN;

        ADC1 -> CR &= ~ADC_CR_DEEPPWD;
        ADC1 -> CR |= ADC_CR_ADVREGEN;
        ADC1 -> CR &= ~ADC_CR_ADCALDIF;
        ADC1 -> CR |= ADC_CR_ADCAL;
        while((ADC1->CR & ADC_CR_ADCAL) != 0) //Wait for Calibration to be done
        ;

        ADC1 -> CFGR |= ADC_CFGR_CONT | ADC_CFGR_DMACFG;
        ADC1 -> CFGR &= ~ADC_CFGR_ALIGN_RIGHT | ADC_CFGR_RES_12_Bit;
        ADC1 -> SMPR2 |= ADC_SMPR2_SMP12_640_ADC_CYCLES;
        ADC1 -> SQR1 |= ADC_SQR1_SQ1_12;

        ADC1 -> ISR |= ADC_ISR_ADRDY;
        ADC1 -> CR |= ADC_CR_ADEN; //Enable: ADC

        while((ADC1->ISR & ADC_ISR_ADRDY) == 0) //Wait for the ADC to be ready
        ;

        ADC1 -> ISR |= ADC_ISR_ADRDY; //Clear the ARDYFlAG
        ADC1 -> CR |= ADC_CR_ADSTART; //Start the ADC
        ADC1 -> CFGR |= ADC_CFGR_DMAEN;

}

void init_Clock() {

    CFGR = find_PLL(CPU_Speed, ADC_Speed);

        // |----------------------------------- WAIT STATE: 0 -----------------------------------|
        if (CPU_Speed <= 16000000) {

            FLASH -> ACR &= ~FLASH_ACR_LATENCY_Msk;
            FLASH -> ACR |= FLASH_ACR_LATENCY_0WS;

            if ((FLASH -> ACR & FLASH_ACR_LATENCY_0WS) != FLASH_ACR_LATENCY_0WS){
                //ERROR: System didn't change wait states properly
            } else{
                //Success
            }

        // |----------------------------------- WAIT STATE: 1 -----------------------------------|
        } else if (CPU_Speed <= 32000000){

            FLASH -> ACR &= ~FLASH_ACR_LATENCY_Msk;
            FLASH -> ACR |= FLASH_ACR_LATENCY_1WS;

            if ((FLASH -> ACR & FLASH_ACR_LATENCY_1WS) != FLASH_ACR_LATENCY_1WS){
                //ERROR: System didn't change wait states properly
            } else{
                //Success
        }


        // |----------------------------------- WAIT STATE: 2 -----------------------------------|
        } else if (CPU_Speed <= 48000000){

            FLASH -> ACR &= ~FLASH_ACR_LATENCY_Msk;
            FLASH -> ACR |= FLASH_ACR_LATENCY_2WS;

            if ((FLASH -> ACR & FLASH_ACR_LATENCY_2WS) != FLASH_ACR_LATENCY_2WS){
                //ERROR: System didn't change wait states properly
            } else{
                //Success
            }


        // |----------------------------------- WAIT STATE: 3 -----------------------------------|
        } else if (CPU_Speed <= 64000000){

            FLASH -> ACR &= ~FLASH_ACR_LATENCY_Msk;
            FLASH -> ACR |= FLASH_ACR_LATENCY_3WS;

            if ((FLASH -> ACR & FLASH_ACR_LATENCY_3WS) != FLASH_ACR_LATENCY_3WS){
                //ERROR: System didn't change wait states properly
            } else{
                //Success
            }


        // |----------------------------------- WAIT STATE: 4 -----------------------------------|
        } else if (CPU_Speed <= 80000000){

            FLASH -> ACR &= ~FLASH_ACR_LATENCY_Msk;
            FLASH -> ACR |= FLASH_ACR_LATENCY_4WS;

            if ((FLASH -> ACR & FLASH_ACR_LATENCY_4WS) != FLASH_ACR_LATENCY_4WS){
                //ERROR: System didn't change wait states properly
            } else{
                //Success
            }

        } else{
            //Error: Clock Speed too high
        }

        RCC -> CFGR |= RCC_CFGR_SW_PLL;
        PWR -> CR1 &= ~PWR_CR1_VOS_Msk;
        PWR -> CR1 |= PWR_CR1_VOS_0;
        RCC -> CR |= RCC_CR_MSIRGSEL | RCC_CR_MSIRANGE_6;

        // |----------------------------------- PLLCFGR: R -----------------------------------|
        if (CFGR.PLLR == 2){
            RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLLR_Msk;
            RCC -> PLLCFGR |= RCC_PLLCFGR_PLLR_2;
        } else if (CFGR.PLLR == 4){
            RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLLR_Msk;
            RCC -> PLLCFGR |= RCC_PLLCFGR_PLLR_4;
        } else if (CFGR.PLLR == 6){
            RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLLR_Msk;
            RCC -> PLLCFGR |= RCC_PLLCFGR_PLLR_6;
        } else if (CFGR.PLLR == 8){
            RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLLR_Msk;
            RCC -> PLLCFGR |= RCC_PLLCFGR_PLLR_8;
        }

        // |----------------------------------- PLLCFGR: M -----------------------------------|
        if (CFGR.PLLM == 1){
            RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
        } else {
            RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
            RCC -> PLLCFGR |= (CFGR.PLLM-1) << RCC_PLLCFGR_PLLM_Pos;
        }

        // |----------------------------------- PLLCFGR: N -----------------------------------|
        RCC -> PLLCFGR &= ~(RCC_PLLCFGR_PLLN_Msk);
        RCC -> PLLCFGR |= ((CFGR.PLLN) << RCC_PLLCFGR_PLLN_Pos) | (RCC_PLLCFGR_PLLREN) | (RCC_PLLCFGR_PLLSRC_MSI);

        // |----------------------------------- PLLSAI1CFGR: R -----------------------------------|
        if (CFGR.PLLSAI1R == 2){
            RCC -> PLLSAI1CFGR &= ~RCC_PLLSAI1CFGR_PLLSAI1R_Msk;
            RCC -> PLLSAI1CFGR |= RCC_PLLSAI1CFGR_PLLSAI1R_2;
        } else if (CFGR.PLLSAI1R == 4){
            RCC -> PLLSAI1CFGR &= ~RCC_PLLSAI1CFGR_PLLSAI1R_Msk;
            RCC -> PLLSAI1CFGR |= RCC_PLLSAI1CFGR_PLLSAI1R_4;
        } else if (CFGR.PLLSAI1R == 6){
            RCC -> PLLSAI1CFGR &= ~RCC_PLLSAI1CFGR_PLLSAI1R_Msk;
            RCC -> PLLSAI1CFGR |= RCC_PLLSAI1CFGR_PLLSAI1R_6;
        } else if (CFGR.PLLSAI1R == 8){
            RCC->PLLSAI1CFGR &= ~RCC_PLLSAI1CFGR_PLLSAI1R_Msk;
            RCC->PLLSAI1CFGR |= RCC_PLLSAI1CFGR_PLLSAI1R_8;
        }

        // |----------------------------------- PLLSAI1CFGR: N -----------------------------------|
        RCC -> PLLSAI1CFGR &= ~(RCC_PLLSAI1CFGR_PLLSAI1N_Msk);
        RCC -> PLLSAI1CFGR |= RCC_PLLSAI1CFGR_PLLSAI1REN | (CFGR.PLLSAI1N << RCC_PLLSAI1CFGR_PLLSAI1N_Pos);

        RCC -> CR |= RCC_CR_PLLON;
        while ((RCC->CR & RCC_CR_PLLRDY) == 0)
        ;
        RCC -> CR |= RCC_CR_PLLSAI1ON;
        while ((RCC -> CR & RCC_CR_PLLSAI1RDY) == 0)
        ;
        if ((RCC -> CFGR & RCC_CFGR_SWS_PLL) != RCC_CFGR_SWS_PLL ) {
            //Error: Clock Didn't switch
        }
}

void init_DAC(){

    RCC -> APB1ENR1 |= RCC_APB1ENR1_DAC1EN;
    RCC -> AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
    GPIOA -> MODER &= ~GPIO_MODER_MODE4;
    GPIOA -> MODER |= GPIO_MODER_MODE4_Analog;
    DAC1 -> CR |= DAC_CR_EN1;
}

void init_Interrupt(){

    NVIC_EnableIRQ(DMA2_Channel3_IRQn);
    NVIC_SetPriority(DMA2_Channel3_IRQn,0);
}

void init_GPIO_Test(){

    RCC -> AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
    GPIOA -> MODER &= ~GPIO_MODER_MODE0;
    GPIOA -> MODER |= GPIO_MODER_MODE0_Gen_Purpose;
}

void print_ADC(short adcValue){

    short counter = 0;

    while (adcValue > 0){
        buffer[14-counter] = (adcValue % 10) + '0';
        adcValue = adcValue / 10;
        counter++;
    }

    if (counter == 0){

        buffer[14] = adcValue + '0';
        buffer[13] = ' ';
        buffer[12] = ' ';
        buffer[11] = ' ';

    } else if (counter == 1){
         buffer[13] = ' ';
         buffer[12] = ' ';
         buffer[11] = ' ';

    } else if (counter == 2){
         buffer[12] = ' ';
         buffer[11] = ' ';

    } else if (counter == 3){
         buffer[11] = ' ';
  }

    counter = 0;
}

void init_Debug(){

    RCC -> APB1ENR1 |= RCC_APB1ENR1_USART2EN;
    RCC -> AHB1ENR  |= RCC_AHB1ENR_DMA1EN;
    RCC -> AHB2ENR  |= RCC_AHB2ENR_GPIOAEN;
    RCC -> CCIPR    |= RCC_CCIPR_USART2SEL_System_Clock;

    GPIOA -> MODER  &= ~GPIO_MODER_MODE2;
    GPIOA -> MODER  |= GPIO_MODER_MODE2_Alt_Function;
    GPIOA -> AFR[0] |= GPIO_AFRL_AFSEL2_USART2;

    DMA1_Channel7 -> CCR  |= DMA_CCR_PL_High     |
                             DMA_CCR_MSIZE_8_Bit |
                             DMA_CCR_PSIZE_8_Bit |
                             DMA_CCR_MINC        |
                             DMA_CCR_CIRC        |
                             DMA_CCR_DIR;
    DMA1_CSELR    -> CSELR |= DMA_CSELR_C7S_USART2;
    DMA1_Channel7 -> CNDTR  = 0x14; // 20
    DMA1_Channel7 -> CMAR   = (uint32_t)buffer;
    DMA1_Channel7 -> CPAR   = (uint32_t)&USART2 -> TDR;
    DMA1_Channel7 -> CCR  |= DMA_CCR_EN;

    USART2 -> CR1 &= ~USART_CR1_M1 | ~USART_CR1_OVER16;
    USART2 -> CR1 |= USART_CR1_TE;
    USART2 -> CR3 |= USART_CR3_DMAT;
    USART2 -> BRR = 0x208D;
    USART2 -> CR1 |= USART_CR1_UE;
}
\$\endgroup\$
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$ – Voltage Spike Jul 17 at 5:05
  • 1
    \$\begingroup\$ ADC may not be the problem, but instead DAC could be. Have you tried to buffer one period of the sampled signal and look at it through Serial on a PC ? In order to be sure that ADC is the culprit ? \$\endgroup\$ – Mathieu G. Jul 17 at 5:42
  • 1
    \$\begingroup\$ Perhaps your scope is reducing its sample rate when you zoom out the time axis? Notice how the green trace is always high and does not show a square wave either. \$\endgroup\$ – user253751 Jul 17 at 10:42
  • \$\begingroup\$ So talking to Bruce about this, it’s due to the sampling of my scope. It looks like I don’t know how use it properly. \$\endgroup\$ – Leoc Jul 17 at 12:28
4
\$\begingroup\$

Okay, so the issue was the oscilloscope and not the MCU. I realized as mentioned above was the zooming and how it affected the scope's sampling rate. As you zoom out the sample rate goes down and vice versa when zooming in.

How I obtain those pictures was I pressed the Run/Stopped button and zoomed in the still image. Since it was stopped at such a low sampling rate it make sense why my wave looks like that.

The work around is now I use a trigger. The trigger allows the scope to sample close to the maximum sample rate. Trigger is the key on a rising edge on input 1 (Yellow). I zoom in and acquire the sampling rate I want, start the trigger and wait for it. It will then display the wave form on the rising edge with the maximum sampling rate.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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