PSoC 6 - SAR ADC with Multiple Configs (2)

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

cross mob
TeMa_1467596
Level 5
Level 5
5 sign-ins 5 likes given First like received

I have a project in which is running on the CY8CKIT-062-BLE eveal PCB and I'm using PSoC Creator 4.2

My project has an SAR ADC which I've configured with 2 configurations (see picture) but I'm having problems getting it to run (I don't get any change in the readings).  I think it's because the setup isn't done properly but it's very confusing because none of the examples seem to reflect the API stuff given after a build.

SAR_ADC1.PNG

I tried to set up an ISR called SAR_Interrupt and I set up the ADC as follows

// TM ADC_1 SAR setup

    ADC_1_StartEx(SAR_Interrupt);                  // Start the ADC and point to the ISR routine called on EOC

    ADC_1_SelectConfig(0,0);                        // select config 0 and do not restart the ADC

    ADC_1_IRQ_Enable();                             // enable interrupts to occur at the end of conversion

   

    // TM initialize Interrupt(s)

    __enable_irq();

But I'm not even sure that 0 is valid for the config selection and I'm not clear what to put in as a mask to clear the interrupt assuming it was ever called.

    ADC_1_SetEosMask(ADC_1???);

Has anyone got a sample project that uses the commands that are shown in the datasheet for this component?

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.

I understand your problem. I have created a simple CE for you. Please find the attachment.

The project implements SAR ADC with 2 configurations. Connect the pin 10.5 to gnd on the board and pin 10.6  to 3.3V on the board. The RED led should start blinking. "Config 0" reads Zero volts from pin 10.5 and "config 1" reads 3.3V from pin 10.6. If the read voltage is less than 1.6V, RED led turns ON and if the voltage is greater than 1.6V, RED led turns OFF. The configuration is switched every time a data is read.

The program is simple, if you have any doubts please feel free to ask.

Regards,

Yeshwanth

View solution in original post

11 Replies
Yeshwanth_KT
Employee
Employee
50 replies posted 25 replies posted 10 likes received

Hello Ted,

You can go through this code example: http://www.cypress.com/documentation/code-examples/ce220974-psoc-6-mcu-multi-config-scanadc-example​.This should solve most of your problems.

If you get any doubts regarding the API usage and what parameters to pass, you can always refer to the PDL documentation which comes with the creator.

community.png

0 Likes

Yekt,

Thanks for the response but I have studied CE220974 extensively, it doesn't show the 2 configurations of the SAR ADC in TopDesign.cysch and all the different configuration definitions are in code - by build seems to have auto-generated those configurations from the info I put into the dialogue box.  Also it doesn't use the ADC_Start() API command etc...  It's like all the examples were written for an earlier version of the SAR ADC component.

So I'm still stuck with no actual example of how to use the API commands that are in the datasheet.  I have studied the PDL documentation but there are areas that are still not clear and my code doesn't work

0 Likes
lock attach
Attachments are accessible only for community members.

I understand your problem. I have created a simple CE for you. Please find the attachment.

The project implements SAR ADC with 2 configurations. Connect the pin 10.5 to gnd on the board and pin 10.6  to 3.3V on the board. The RED led should start blinking. "Config 0" reads Zero volts from pin 10.5 and "config 1" reads 3.3V from pin 10.6. If the read voltage is less than 1.6V, RED led turns ON and if the voltage is greater than 1.6V, RED led turns OFF. The configuration is switched every time a data is read.

The program is simple, if you have any doubts please feel free to ask.

Regards,

Yeshwanth

Yekt,

Thanks, I'll check that project out and get back with you.

Ted

0 Likes

yekt, thanks so much, that code works really well.

0 Likes

Sure Ted, pleasure to help you out. If you get any more problems feel free to ask.

Regards,

Yeshwanth

0 Likes

OK, I have one more issue with this, it's to do with the timing of switching from one configuration to another (and back).  My requirement is to sample 4 channels 21,600 per second and then, every 10th of a second, switch to another set of 3, take those samples, and then get back again in time for the first set to get the next sample window.  I set up a timer for the interrupts...

//  Timer1 ISR is fired 43,200 times per second so is called every 23.148 uS

// config 0 / config 1 takes about 8 uS / 29 uS to complete to scan all 4/6 ADC inputs respectively whcich causes an overlap issue

// consider making this higher priority than the ADC EOC interrupt (the results can wait to be read a few uS)

// but we can do 150 commands in 1 uS so it probably is irrelevant

void Timer1_Isr(void)

{

    static uint16 count;

    count++;

    if (count & 0x0001) { // even

        Cy_GPIO_Write(RX_AmbLED_PORT, RX_AmbLED_NUM, 1);

        ADC_1_StartConvert();           // start ADC conversion, ISR will be triggered at EOC

    }

    else { // odd

        if (count >= 432) {   // only do this every 432 counts (100 Hz) - make sure the 432 value is even if changed

            Cy_GPIO_Write(TX_RedLED_PORT, TX_RedLED_NUM, 1);

            ADC_1_SelectConfig(1,1);    // set to config 1 for periodic, additional alternate readings

            activeConfig = 1;           // flag that config 1 is active

            count = 0;                  // zero out count

            ADC_1_StartConvert();       // start ADC conversion, ISR will be triggered at EOC

        }

    }

    Cy_TCPWM_ClearInterrupt(Timer1_HW, Timer1_CNT_NUM, CY_TCPWM_INT_ON_TC);

}

and I set up the ISR as follows...

void SAR_Interrupt(void)

{

    uint32_t intr_status = 0u;

    /* Read interrupt status register. */

    intr_status = Cy_SAR_GetInterruptStatus(SAR);

    /* Check what triggered the interrupt. */

    if ((intr_status & (uint32_t) CY_SAR_INTR_EOS_MASK) == (uint32_t) CY_SAR_INTR_EOS_MASK)

    {

        /* An end of scan occured, retrieve the ADC result and do something with it here. */

        if (activeConfig == config0) { // capture results for Config 0

            voltsTransient = Cy_SAR_GetResult16(SAR, vTrans);

            ampsTransient = Cy_SAR_GetResult16(SAR, aTrans);

            ssVoltsArray[1] = Cy_SAR_GetResult16(SAR, v60Hz); // put v/a60Hz results in index 1 for now but later, we'll run mainIndex like this...

            // ssVoltsArray[mainIndex] = Cy_SAR_GetResult16(SAR, v60Hz);

            ssAmpsArray[1] = Cy_SAR_GetResult16(SAR, a60Hz);

            Cy_GPIO_Write(RX_AmbLED_PORT, RX_AmbLED_NUM, 0);

            xchngArray[mainIdx] = mainIndex++;

            if (mainIndex > 12599) {

                mainIndex = 0;

            }

        }

        else // it must be config1

        {

            // capture reults for Config 1

            xchngArray[vRms] = Cy_SAR_GetResult16(SAR, vRms);

            xchngArray[aRms] = Cy_SAR_GetResult16(SAR, aRms);

            xchngArray[ambTemp] = Cy_SAR_GetResult16(SAR, ambTemp);

            xchngArray[soLar] = Cy_SAR_GetResult16(SAR, soLar);

            xchngArray[condTemp] = Cy_SAR_GetResult16(SAR, condTemp);

            xchngArray[vrefSamp] = Cy_SAR_GetResult16(SAR, vrefSamp);

            Cy_GPIO_Write(TX_RedLED_PORT, TX_RedLED_NUM, 0); // switch off monitor LED

            ADC_1_SelectConfig(0,1);        // and then switch back to Config 0

            activeConfig = 0;

        }

        //

    }

    /* Check for the saturation detection status, if enabled. */

    /* Check for the range detection status, if enabled. */

    /* Clear the handled interrupt. */

    Cy_SAR_ClearInterrupt(SAR, intr_status);

}

but the switch over to config1 (and back to config0) seems to take a long time and I end up not finishing my 10th second sample before the next sample is due.  See scope screen below, the blue pulses are the config0 (RX_AmbLED) activity and the yellow is the config1 (TX_RedLED). 

Is my problem in trying to change back to config 0 within the ADC ISR?

What would be the implication of not restarting the ADC after a configuration change?

Any ideas?

DS1Z_QuickPrint1.png

0 Likes

As far as I understand you want to sample config 1 at 1/10th of a second, but the code is doing it at 1/100 of a second which is very confusing. Could you explain your requirement one more time and also attach you project so that I can debug it easily.

Thanks,

Yeshwanth

0 Likes
lock attach
Attachments are accessible only for community members.

Yeshwanth,

You're right that I'm sampling at 100 Hz and I said 10 Hz, sorry for that confusion but I could make it 10 Hz or 50 Hz and the issue would be the same. 

The requirement is that four ADC inputs need to be sampled every 46.296 uS (21,600 Hz) and these are sampled in config0.  I have a second set of six ADC inputs that need to be sampled way less frequently (10 or 100 Hz) so I put them in config1 and then ran a timer system that triggers the ADC every 23.148 uS.  I then run a count within the timer ISR to trigger a sample from config0 when the count is odd (my comment on line 110 of code says even, it's wrong) and then trigger config1 when count is even (and has reached some arbitrary number) with the concept that the less frequent config 1 will only be done every X counts and will be done in the middle of two of the config0 samples.  The problem is that the config1 samples seem to run into the next config0 sample and reason for this appears to be that the m4 core seems to taking around 20 uS to switch from config0 to config1 (see the scope picture above) and then needs additional time to take the samples.

I have attached my project as requested but am going to try putting all my ADC channels in one config and only copying the readings I need into my RAM variables thus avoiding the need to switch configurations.

0 Likes

I observe that both config 0 and config 1 have same type of configuration and there is no need for 2 different configurations. Use only one configuration to sample all the 10 channels at once. There are lot of optimizations you can do to make the process faster and simpler. Follow the below steps:

1) Use only one configuration and sample all the 10 samples. Set "Sample Mode" to "Continuous" and fix the sample speed to 21600 in the config tab. This will automatically set the ADC to sample at that speed, you won't be needing any timer or code to do that.

2) Use a DMA to transfer the data to some memory location based on the EOS signal. This will ensure that sample data is automatically copied to the desired location for every sampling without the CPU intervention.

3) You can set the DMA to transfer sample data for only 4 channels for the first 215 samples it takes. In the 216th sample copy sample data for all the 10 channels. This can be done by using 2 DMA descriptors and chaining them.

This is probably the optimized way of getting the task done. It also does not use any CPU time.

This will also make sure that you don't miss any sample in between.

You can use the below references to see how to use DMA to copy data:

http://www.cypress.com/documentation/code-examples/ce97089-psoc-4-adc-memory-buffer-dma-transfer

http://www.cypress.com/documentation/code-examples/ce220924-psoc-6-mcu-vdac-sine-wave-generator-usin...

Regards,

Yeshwanth

Yeshwanth,

Thanks for the suggestions; I tried the single configuration option today and it takes 14.3 uS to capture all 10 samples and write 4 of them to the array, when I periodically write an additional 6 results to the array, it adds 3 uS to the period so I have between 29 and 32 uS to perform processing actions on every set of data received which I think is enough, if I need more time than that, I'll look into the DMA option to free up some processor time.

Thanks so much for your help.

Ted