Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

A study of simple oscilloscope using ADC and DMA (CY8CKIT-044) version 1

MotooTanaka
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Hi,

Before I posted a similar sample

A Simple Oscilloscope (CY8CKIT-044) using SerialPlotter

But in a discussion below, very fast sampling was required.

May I just measure the PWM pulse with SAR_ADC(CY8CKIT-044)

As I was not familiar with DMA, I have been studying it for a while now.

This sample is the first (somewhat) working version of my simple oscilloscope using ADC and DMA.

It is supposed to be sampling 2us each.

It seems to be working OK, but I want to implement the following 2 functionalities.

Probably in the later versions.

(1) Utilize 2 descriptors to prevent time lag. (But I can not detect it, even with current version using only 1 descriptor, which wonders me.)

(2) Implement a trigger to stop the signal at certain phase. (But I'd like to challenge this after (1))

SerialPoltter Screen

001-Serial_Plot.JPG

schematic

002-Schematic.JPG

pins

003-Pins.JPG

main.c

Note: as usual I cheated by using my tty_utils.[ch] to make uart hanling easier,

but it's not the main topic of this sample anyway.

====================

#include "project.h"

#include "stdio.h"

#include "tty_utils.h"

#define RESULT_BUF_SIZE 1024

#define SAMPLING_CYCLE 2 /* us */

#define CLOCK_FREQ_MHZ 12

uint16_t result_buf[RESULT_BUF_SIZE] ;

int  num_result = RESULT_BUF_SIZE ;

volatile int measured_flag = 0 ;

CY_ISR(meaure_done_isr)

{

    measured_flag = 1 ;

}

void init_hardware(void)

{

    uint32_t dma_dsc ;

   

    CyGlobalIntEnable; /* Enable global interrupts. */   

    tty_init() ;

   

    isr_1_ClearPending() ;

    isr_1_StartEx(meaure_done_isr) ;

 

    Counter_WritePeriod(num_result) ;

    Counter_WriteCounter(0) ;

    Counter_Start() ;

    ADC_Start() ;

    DMA_Start((void *)ADC_SAR_CHAN0_RESULT_PTR, result_buf) ;

    dma_dsc = DMA_GetNextDescriptor() ;

    DMA_SetNumDataElements(dma_dsc, num_result) ;

    Timer_Init() ;

    Timer_WritePeriod(SAMPLING_CYCLE * CLOCK_FREQ_MHZ) ;

    Timer_WriteCounter(0) ;

}

void clear_buf(void)

{

    int i = 0 ;

    for (i = 0 ; i < RESULT_BUF_SIZE ; i++ ) {

        result_buf = 0 ;

    }

}

void dump_buf(void)

{

    int i = 0 ;

    for (i = 0 ; i < num_result ; i++ ) {

        snprintf(str, STR_BUF_LEN, "%d\n\r", result_buf) ;

        print(str) ;

    }

}

int main(void)

{

    int count = 0 ;

   

    init_hardware() ;

   

    splash("ADC-DMA Test") ;

   

    Timer_Start() ;

    for(;;)

    {

        if (measured_flag) {

            measured_flag = 0 ;

            dump_buf() ;

            Counter_WriteCounter(0) ;

            Timer_WriteCounter(0) ;

            Timer_Start() ;

        }

    }

}

====================

moto

8 Replies
odissey1
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Motoo,

It appears that in the example provided the DMA tr_out fires isr_1 on each and every ADC sample, that is every 2 usec! Did you find a way to fire ISR only upon completing acquisition of all 1024 samples?

/odissey1

adc_dma_test_201016SA_A.png

adc_dma_test_201016SA_D.png

0 Likes
MotooTanaka
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Dear odissey1-san,

Thank you very much for your testing!

When I tested with the debugger every time the ISR set the flag

the receive buffer was filled with the required number of data,

so I was assuming that the interrupt was fired after each descriptors.

But seeing your waveform, may be it was because the firmware was too slow

so that by the time UART prints out the last data, all the data was filled.

If DMA is generating ISR on every element transferred, I need to use the TC interrupt of the counter

which is counting the number of element (actually soc generated).

I will check it later.

Best Regards,

20-Oct-2020

Motoo Tanaka

0 Likes
MotooTanaka
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Dear odissey1-san,

Finally I could afford time and energy to test this.

And, Yes, you are right. The trigger (isr_1) is happening every 2us!

010-ADC_DMA_Trigger.JPG

Although I wonder why I can let SerialPlotter plot a reasonable wave form,

I hope that I can utilize the TC of Counter in my schematic for the original purpose.

So current my backlog is

(1) Use (or find) correct Terminal Signal for a buffer filled.

(2) To figure out how I can switch the DMA descriptor when 1 buffer is full.

     (May be I can workaround this by twisting the index of the buffer...)

Best Regards,

23-Oct-2020

Motoo Tanaka

P.S. The DMA quest seems to require much longer than I was expecting at the beginning...

0 Likes
MotooTanaka
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Dear odissey1-san,

I learned a lot today 😉

First I modified the schematic to utilize the counter's TC for the buffer print out trigger.

But the counter was not counting.

Then I noticed that the clock of the Counter must be 2x~ of the Timer to sample Timer's OV (TC).

So I changed the clock to 24MHz and in the timer I set the pre-scale to 2x.

012-schematic.JPG

Now Counter generates interrupt every 2ms instead of 2us.

011-2ms_trigger.JPG

Then I tried with a buffer size of 1024, I was expecting some gap at the trigger,

but I could not observed it. (May be there is a single data which is not quite accurate, but I could not notice it)

(adc_dma_test_201023SB)

014-buf-1024.JPG

Then I modified the program to use a buffer of 2048 and use compare and TC for the trigger

to emulate double buffer scheme. (adc_dma_test_201023SC)

015-buf-2048.JPG

So I could not observe data gap between triggers in both experiments.

Actually even in the first sample, which was not taking advantage of the buffer.

Here, Finally I ran the math 😜

The baud rate of UART is 115200, I assume 8N1 is about 10bytes/letter.

So UART can transfer about 11520 letter/sec and that is 23.04 letters/2us.

And with 12bit decimal, the value written from my program is about 2~3 letters with CR and LF,

which is total of 5 letters per line (and sample).

It seems that the UART is about 4 times faster than my program's sample.

This explains that even without buffer (the first sample), output was not corrupted.

If I was generating 4 or more channels, the result must have been different.

Anyway, let me call it a week 😉

Best Regards,

23-Oct-2020

Motoo Tanaka

AlanH_86
Employee
100 replies posted 50 replies posted 25 solutions authored
Employee

As long as you are using DMA... you could DMA it straight into the UART and not involve the CPU.

Alan

0 Likes
MotooTanaka
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Dear Alan-san,

Thanks for the suggestion!

> As long as you are using DMA... you could DMA it straight into the UART and not involve the CPU.

Probably, that is the most reasonable approach.

Especially, since SeiralPlotter accepts binary data, it should work.

But in case I'd like to read the value as ascii text,

may be I need some more hackings.

Best Regards,

20-Oct-2020

Motoo Tanaka

0 Likes
AlanH_86
Employee
100 replies posted 50 replies posted 25 solutions authored
Employee

And as long as I am thinking things up for you to do... 🙂

you could make a UDB component to transform binary -> ascii ... then you could dma from the adc into the udb into the serial port.... (I think that this should be possible)

Alan

0 Likes
MotooTanaka
Level 9
First comment on KBA 1000 replies posted 750 replies posted
Level 9

Dear Alan-san,

Although limited to 8bit value and 2 digits hex,

I hacked a way to display ascii values.

A study of simple ADC and DMA and UART (CY8CKIT-044)

Best Regards,

22-Oct-2020

Motoo Tanaka

0 Likes