cancel
Showing results for 
Search instead for 
Did you mean: 

Code Examples

Employee

The attached PSoC Creator projects for PSoC4S show how to get the highest sample rate on devices that do not include DMA. Direct register writes, and the SAR sequencer are used to help move data from the ADC efficiently on devices that support a 1Msps ADC but do not have DMA and require the CPU to access data. In PSoC4S and other devices without DMA it is difficult to achieve a sustained 1Msps rate since the CPU is required to move the data from the ADC and the 1Msps ADC requires the CPU clock to be dropped to 36MHz.  The workspace includes a project that samples a single channel and uses direct register access to move each sample from the ADC to achieve a continuous 500ksps ADC.  A second project uses the SAR sequencer to buffer up to 8 channels of data to achieve a continuous 1Msps with minimal CPU intervention.  Both projects are in the same workspace and can be tested on CY8CKIT-041-41XX.

4 Replies
Esteemed Contributor

Dear KevinR-san,

Nice sample!

But having "buffer_index" inside the ISR will make it difficult for other part of the program to access the acquired data.

How about making "buffer_index" as global and volatile? (and also call it buffer_write_index)

something like...

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

...

/* define custom ISR for handling ADC samples */

CY_ISR_PROTO(ADC_INTERRUPT);

uint16                sample_buffer[BUFFER_SIZE];

volatile uint16_t buffer_write_index = 0 ;

uint16_t             buffer_read_index = 0 ; // use this to access acquired data and check if it does not exceed buffer_write_index

...

CY_ISR(ADC_INTERRUPT)

{

...

    sample_buffer[buffer_write_index++] = CY_GET_REG32((reg32 *)(ADC_cy_psoc4_sar__SAR_CHAN_RESULT00)) & (ADC_RESULT_MASK);

    if (buffer_write_index >= BUFFER_SIZE) // I'd like to have = to avoid writing to sample_buffer[BUFFER_SIZE], which is out of range

    {

        buffer_write_index = 0;

        /* could set flag here to tell main loop buffer is full */

    } 

...

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

Best Regards,

2-Aug-2019

Motoo Tanaka

Employee

You are correct.  A user can setup a global variable for their final implementation.  This was just a quick example to showcase the direct register access and SAR sequencer buffering.

0 Likes
Reply
Honored Contributor II

KevinR,

Thank you for the demo. Is this correct that the maximum rate for a single channel ADC is 0.5MHz, but in sequencing mode it is 1MHz. I would expect otherwise. What could be the reason for lower rate in single-channel ADC?

/odissey1

0 Likes
Reply
Employee

The ADC itself can run at 1Msps in single channel mode.  The problem isn't the ADC the issue is how data is taken from the ADC.  In lower end PSoC devices without DMA you need to spend CPU cycles taking data from the ADC.  This is the bottle neck. 

BOTH projects only sample a single input, but in the 500ksps project the CPU grabs a sample after every conversion.  The CPU running at 36MHz takes ~1us to complete moving the data from the ADC to the variable buffer.  You MIGHT be able to improve this efficiency slightly but your still spending 100% of CPU time just servicing ADC samples.

In the 1Msps example the single input is connected to 8 ADC channels.  The SAR ADC sequencer takes care of moving data from each channel to the register automatically, if you run the ADC at 125ksps it will take 8 samples within that time.  Usually you might have different inputs on these channels but by connecting everything to the same input you essentially create an 8 sample buffer.  So you only interrupt the CPU every 8 samples / 125kHz.  Also, since you don't have to enter and exit the ISR on every sample it takes <1us per sample to move the data so you've improved the speed of your sampling as well as freed up additional CPU cycles for other tasks.

I hope that clears things up!  The magic in the 1Msps example is really the SAR sequencer and ability to connect the same input to all 8 channels.

Top labels