This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52 SAADC Continuous sampling

Hello Dev Zone.

thanks for watching mt ask.

I need help.

I have 2 question.

1. I need use saadc continuous sampling

in SDK example, is it continuous Mode?

it looks like simple tesk Mode call by timer int every time.

if i set saadc register like this

// No automatic sampling, will trigger with TASKS_SAMPLE.
NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos;
// Sample Rate is 16 MHz / CC
// CC [80 ~ 2047] 200KHz ~ 7.816KHz
NRF_SAADC->SAMPLERATE |= 0x00000535;
is it working continuous sampling also?
2. continuous sampling buffer set
if i use all saadc channel 0 to 7
// Configure result to be put in RAM at the location of "result" variable.
NRF_SAADC->RESULT.MAXCNT = 8;
// uint16_t adc_sample
NRF_SAADC->RESULT.PTR = (uint32_t)&adc_sample;
 and uif i want to get data from ch no 4, 
 temp = adc_sample[4];
 can i use like that?
thanks for help
//+add This is my full init Code for SAADC 0 - 7 Channel
for(uint8_t i = 0; i<8; i++)
{
    // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/6 gain.
    NRF_SAADC -> CH[i].CONFIG =     (SAADC_CH_CONFIG_GAIN_Gain1_6    << SAADC_CH_CONFIG_GAIN_Pos)   |
                                    (SAADC_CH_CONFIG_MODE_SE         << SAADC_CH_CONFIG_MODE_Pos)   |
                                    (SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
                                    (SAADC_CH_CONFIG_RESN_Bypass<< SAADC_CH_CONFIG_RESN_Pos)|
                                    (SAADC_CH_CONFIG_RESP_Pulldown<< SAADC_CH_CONFIG_RESP_Pos)|
                                    (SAADC_CH_CONFIG_TACQ_10us<< SAADC_CH_CONFIG_TACQ_Pos);

// Configure the SAADC channel with VDD as positive input, no negative input(single ended).
//NRF_SAADC->CH[i].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput5 << SAADC_CH_PSELP_PSELP_Pos;
NRF_SAADC->CH[i].PSELP = (unsigned long) (i+1UL) << SAADC_CH_PSELP_PSELP_Pos;
NRF_SAADC->CH[i].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
}
// Configure the SAADC resolution.
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_12bit << SAADC_RESOLUTION_VAL_Pos;

// Configure result to be put in RAM at the location of "result" variable.
NRF_SAADC->RESULT.MAXCNT =8;
NRF_SAADC->RESULT.PTR = (uint32_t)&adc_sample;

// No automatic sampling, will trigger with TASKS_SAMPLE.
NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Timers << SAADC_SAMPLERATE_MODE_Pos;
// Sample Rate is 16 MHz / CC
// CC [80 ~ 2047] 200KHz ~ 7.816KHz
NRF_SAADC->SAMPLERATE |= 0x00000535;

Enable SAADC (would capture analog pins if they were used in CH[0].PSELP)
NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;

// Calibrate the SAADC (only needs to be done once in a while)
NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
while (NRF_SAADC->EVENTS_CALIBRATEDONE == 0);
NRF_SAADC->EVENTS_CALIBRATEDONE = 0;
while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos));

NRF_SAADC->TASKS_START = 1;

Parents Reply Children
  • Hello,
    Thanks for reply Karl

    so, when making "saadc" continuous mode we don't need "PPI" must

    is it right? i will re-check Reference again

    in +add code Part, i want to check is it right to save & call data  

    // Configure result to be put in RAM at the location of "result" variable.
    // adc_sample is array type value, int16_t, adc_sample[8]
    
            NRF_SAADC->RESULT.MAXCNT = 8;
            NRF_SAADC->RESULT.PTR = (uint32_t)&adc_sample;
            
    // when we need to read saadc value 0,1,4,5 to check IR 
    
            temp = adc_sample[0];
            temp = adc_sample[1];
            ...
            ...
    

    next time i will try to use "insert code" option

    thanks for information.

    Best regards,

    Empe.

  • Hello Empe,

    Empe said:

    so, when making "saadc" continuous mode we don't need "PPI" must

    is it right? i will re-check Reference again

    Yes, you can either use SAADC in continuous mode with its own internal timer, or you could use PPI.
    Note that using the internal timer is only available for a single channel. From the initial code snippet you posted it seems you would like to have multiple inputs, which means you must use the PPI for continuous mode. Setting up the SAADC to work with PPI is demonstrated in the SAADC example in the SDK.
    Have you seen this section about the continuous mode for the SAADC?

    Empe said:
    in +add code Part, i want to check is it right to save & call data  

    Not quite, it depends on the configuration of your SAADC. The samples are stored using 16 bits, so you may not just increment a 32 bit pointer.
    Please see this section about how the SAADC results are stored for different SAADC configurations. If you are going to use the RESULT.PTR value directly, you will have to increment it according to the memory usage described in that section.

    Empe said:
    next time i will try to use "insert code" option

    Thank you for formatting your code, it is much easier to read and much appreciated! :)

    Empe said:
    thanks for information.

    No problem at all, I am happy to help!

    Best regards,
    Karl

  • Hello Karl,

    Thanks for kind reply.

    you posted it seems you would like to have multiple inputs, which means you must use the PPI for continuous mode.

    That's why my code is not work well.

    I need study more about "PPI". Thanks.

    you are going to use the RESULT.PTR value directly, you will have to increment it according to the memory usage described in that section.

    oh, That is another reason why data can not read well. Thanks@

    Then, Karl i have another question.

    In timing chart, After "STARTED" event generated, need to set next buffer to "RESULT.PTR"

    When using "PPI" function for continuous mode of "SAADC",

    if i don't pointed next buffer, DMA will overwrite data automatic to buffer that before pointed? or Stop to converting?

    Why do I ask this ... because of i have one more question.

    assume that i make my model like that,

        // Init channel 1 SAADC
        // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/6 gain.
        ...
        
        // Configure the SAADC resolution. (12Bit)
        ...
        
        // Configure result to be put in RAM at the location of "result" variable.
        NRF_SAADC->RESULT.MAXCNT = 1;
        NRF_SAADC->RESULT.PTR = (uint32_t)&adc_CH1_sample;
        
        // Init channel 2 SAADC
            // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/4 gain.
        ...
        
        // Configure the SAADC resolution. (10Bit)
        ...
        
        // Configure result to be put in RAM at the location of "result" variable.
        NRF_SAADC->RESULT.MAXCNT = 1;
        NRF_SAADC->RESULT.PTR = (uint32_t)&adc_CH2_sample;

    can I allocate a different storage buffer address and different resolution set for each channel?

    Thanks for help. : )

    Best regards,
    Empe.

  • Hello Empe,

    Empe said:
    Thanks for kind reply.

    No problem at all, I am happy to help!

    Empe said:

    That's why my code is not work well.

    I need study more about "PPI". Thanks.

    Yes, that might be the reason. Let me know if this resolves your issue!
    If you want to read more about PPI, you could do so here. PPI is really just a way to connect two peripherals so that they may function together, without requiring CPU intervention at every sample. What you would like to do is to connect a timer to your SAADC, using PPI. That way, the SAADC will continuously work in the background.
    The SAADC example demonstrates how you can connect a timer to your SAADC using PPI.

    Empe said:
    if i don't pointed next buffer, DMA will overwrite data automatic to buffer that before pointed? or Stop to converting?

    If the buffer is filled up, then the NRF_SAADC_EVENT_END event is triggered and you will stop converting, since there is no more space to store samples in.
    The pointer will NOT reset to the start of the buffer by itself, you will have to do this yourself if you want this to happen.
    However, if you are concerned with possibly loosing samples during processing of the buffer, you might be interested in using the double buffering functionality.
    This will set up two equal buffers, and when the first one fill up it will immediately start filling into the second buffer - without missing samples.
    This functionality is also demonstrated in the SAADC example I linked earlier, as seen in the saadc_init() functions double call to nrf_saadc_buffer_convert.

    Empe said:

    Why do I ask this ... because of i have one more question.

    assume that i make my model like that,

    RESULT.MAXCNT is the size of the buffer provided to store samples in, so if you only set it to 1, the SAADC will only do 1 conversion before the NRF_SAADC_EVENT_END is triggered and conversion is stopped. You would have to restart the SAADC again for each sample, if you were to do it like this.
    Instead, I would recommend that you iterate over or directly access the result buffer with an offset equal to the number of channels you have, to retrieve the conversions.

    Is there a specific reason for why you would like to manipulate the registers directly, instead of using the SAADC driver?

    Empe said:
    oh, That is another reason why data can not read well. Thanks@

    Yes, this might very well be a reason for incorrect readouts. Let me know if you are able to get proper readings using memory map.

    Empe said:
    Thanks for help. : )

    No problem at all!
    Thank you for formatting your code with the insert code option, and having edited it into your original question - it is highly appreciated! :)
    Best of luck with your development, and let me know if you should have any other questions or issues!

    Best regards,
    Karl

  • Hello, Karl.

    Thanks very much.

    now i'm solve all problem and working well.

    Is there a specific reason for why you would like to manipulate the registers directly, instead of using the SAADC driver?

    this is why now i'm try to porting the function to another platform,

    however SDK example is not working well in there. 

    that's why need to understand register and working process.

    Best regards,

    Empe.

Related