<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/106833/how-do-i-get-the-current-value-ac-using-a-timer-ppi-saadc-and-freertos-on-the-nrf52833</link><description>Hi all. 
 Could you help me with an example or some ideas about how to create an application that allows me to measure the AC current through an Analog Pin like AIN1 from the nRF52833 ? 
 I mean, I want to create an application that allows me to print</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Mon, 08 Jan 2024 21:54:42 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/106833/how-do-i-get-the-current-value-ac-using-a-timer-ppi-saadc-and-freertos-on-the-nrf52833" /><item><title>RE: How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/thread/463239?ContentTypeID=1</link><pubDate>Mon, 08 Jan 2024 21:54:42 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:9eb8a40f-389f-4d1e-b23d-a2d4c8afa037</guid><dc:creator>Fernando Mercado</dc:creator><description>&lt;p&gt;Hello Naeem, yes, please.&lt;/p&gt;
&lt;p&gt;You can close this ticket, thank you.&lt;/p&gt;
&lt;p&gt;Regards.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/thread/462928?ContentTypeID=1</link><pubDate>Fri, 05 Jan 2024 14:27:30 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8ebae5bf-fe09-4fc1-a4cd-8c74fcc9e566</guid><dc:creator>Naeem Maroof</dc:creator><description>&lt;p&gt;Hi Fermando,&lt;/p&gt;
&lt;p&gt;As Susheel has responded to you on the same question in your other ticket, please let me know if I could close this one.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Naeem&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/thread/462374?ContentTypeID=1</link><pubDate>Tue, 02 Jan 2024 21:21:34 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b4827fff-96b2-4806-9d73-7c490f876649</guid><dc:creator>Fernando Mercado</dc:creator><description>&lt;p&gt;&lt;span style="font-size:150%;"&gt;Hi Hieu, thanks for the answer,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:150%;"&gt;Right now, I have developed a code that allows me to measure ADC samples, but I&amp;#39;m not sure if this is correct because, through these ADC samples, I get an RMS value, but I&amp;#39;m not very positive if this RMS value is correct. Can you help me verify if my code is okay, please.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:150%;"&gt;I&amp;#39;ll leave my code below, whatever advice you leave, it&amp;#39;ll be received. Thanks.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size:150%;"&gt;Notes: I&amp;#39;m using FreeRTOS (One Task, One Queue to save the ADC samples), SAADC (enable interrupt for event END), TIMER1 (1.68 ms), PPI.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;main.c
=========================================================================================
int main(void){
    ret_code_t err_code;
    /* Initialize clock driver for better time accuracy in FREERTOS */
    err_code = nrf_drv_clock_init(); // If we forget to initialize the clock, the timer is not going to work
    APP_ERROR_CHECK(err_code);

    /* Create task for print_task_function with priority set to 2 */
    UNUSED_VARIABLE(xTaskCreate(print_task_function, &amp;quot;print_task_function&amp;quot;, (configMINIMAL_STACK_SIZE + 200), NULL, 2, &amp;amp;print_task_handle));
    
    // Create the queue
    xQueue = xQueueCreate(QUEUE_LENGTH, sizeof(samplesADC));
    if( xQueue == NULL ){        
        /* Queue was not created and must not be used. */      
        SEGGER_RTT_printf(0, &amp;quot;Queue was not created\r\n&amp;quot;);
    }         

    /* Activate deep sleep mode */
    SCB-&amp;gt;SCR |= SCB_SCR_SLEEPDEEP_Msk;
    
    /* Start FreeRTOS scheduler. */
    vTaskStartScheduler();

    while(true){
        /* FreeRTOS should not be here... FreeRTOS goes back to the start of stack
         * in vTaskStartScheduler function. */
    }
}

static void print_task_function(void *pvParameter){
    UNUSED_PARAMETER(pvParameter);  
      
    ADC_initBufferSamples(ISRsamplesValuesADC);
    ADC_InitSAADC_PPI_TIMER(ADC_read);
    
    int16_t cont_Frames = 0;
   
    // Receive data from the queue
    samplesADC samplesValuesADCfromQueue[NRF_SAADC_RESULT_MAXCNT];

    while(1){
        SEGGER_RTT_printf(0, &amp;quot;print_task_function: xQueueReceive &amp;lt;-- Blocking...\r\n&amp;quot;); 
        double alpha = 0.25;
        ADC_processADCsamples(&amp;amp;xQueue, samplesValuesADCfromQueue, &amp;amp;cont_Frames, &amp;amp;contadorFramesISR, ISRsamplesValuesADC, true, &amp;amp;alpha);     
    }
}

void SAADC_IRQHandler(void){
    if(NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE == 1){
        SEGGER_RTT_printf(0, &amp;quot;SAADC event: CALIBRATEDONE\r\n&amp;quot;);        
    }
    /* This IRQHandler must be executed each 1.68 ms, then 1 Frame = 1.68ms */
    else if(NRF_SAADC-&amp;gt;EVENTS_END == 1){ // EVENTS_END = The SAADC has filled up the result buffer
        
        ADC_copySamplesToBuffer(&amp;amp;contadorFramesISR, TOTAL_SAMPLES_EACH_CYCLE, ADC_read, ISRsamplesValuesADC, &amp;amp;xQueue, &amp;amp;xHigherPriorityTaskWoken);
        
        NRF_SAADC-&amp;gt;EVENTS_END = 0;                                                                  
    }
    else{
        ;
    }
}
=========================================================================================
adc.c
void ADC_saadc_init(int16_t *ADC_read){
    ////////////////////////////// NRF_SAADC_CH_0
    // Configure SAADC singled-ended channel, Internal reference (0.6V) and 1/4 gain.    
    NRF_SAADC-&amp;gt;CH[NRF_SAADC_CH_0].CONFIG = (SAADC_CH_CONFIG_RESP_Pullup     &amp;lt;&amp;lt; SAADC_CH_CONFIG_RESP_Pos)   | // Pull-up to VDD
                                           (SAADC_CH_CONFIG_RESN_Pulldown   &amp;lt;&amp;lt; SAADC_CH_CONFIG_RESN_Pos)   | // Pull-down to GND 
                                           (SAADC_CH_CONFIG_GAIN_Gain1_4    &amp;lt;&amp;lt; SAADC_CH_CONFIG_GAIN_Pos)   | // Gain1_4                                           
                                           (SAADC_CH_CONFIG_REFSEL_Internal &amp;lt;&amp;lt; SAADC_CH_CONFIG_REFSEL_Pos) | // Internal reference (0.6 V)
                                           (SAADC_CH_CONFIG_TACQ_40us       &amp;lt;&amp;lt; SAADC_CH_CONFIG_TACQ_Pos)   | // Acquisition time, the time the SAADC uses to sample the input voltage, 40us 
                                           (SAADC_CH_CONFIG_MODE_SE         &amp;lt;&amp;lt; SAADC_CH_CONFIG_MODE_Pos)   | // Single-ended, PSELN will be ignored, negative input to SAADC shorted to GND
                                           (SAADC_CH_CONFIG_BURST_Disabled  &amp;lt;&amp;lt; SAADC_CH_CONFIG_BURST_Pos);   // Burst mode is disabled (normal operation)

    /* Configure the SAADC channel with AIN1 as positive input, no negative input(single ended). */
    // Input positive pin selection for CH[0]
    NRF_SAADC-&amp;gt;CH[NRF_SAADC_CH_0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput1 &amp;lt;&amp;lt; SAADC_CH_PSELP_PSELP_Pos; // AnalogInput1, AIN1 (Pin P0.03) --&amp;gt; AC_SENSOR

    // Input negative pin selection for CH[0]
    NRF_SAADC-&amp;gt;CH[NRF_SAADC_CH_0].PSELN = SAADC_CH_PSELN_PSELN_NC  &amp;lt;&amp;lt; SAADC_CH_PSELN_PSELN_Pos; // NC, Not connected

    // Configure the SAADC resolution.
    NRF_SAADC-&amp;gt;RESOLUTION = SAADC_RESOLUTION_VAL_10bit &amp;lt;&amp;lt; SAADC_RESOLUTION_VAL_Pos; // 10 bits
    
    // Configure result to be put in RAM at the location of &amp;quot;ADC_read&amp;quot; variable.
    // Maximum number of 16-bit samples to be written to output RAM buffer    
    NRF_SAADC-&amp;gt;RESULT.MAXCNT = NRF_SAADC_RESULT_MAXCNT; // (RESULT EasyDMA channel)    
    //NRF_SAADC-&amp;gt;RESULT.PTR = (uint32_t)&amp;amp;ADC_read; // Data pointer (2to16 = 65,536), (65,536/2 = 32,768) --&amp;gt; [-327687, 32767]
    NRF_SAADC-&amp;gt;RESULT.PTR = (uint32_t)ADC_read; // Data pointer (2to16 = 65,536), (65,536/2 = 32,768) --&amp;gt; [-327687, 32767]
    
    // No automatic sampling, will trigger with TASKS_SAMPLE.
    NRF_SAADC-&amp;gt;SAMPLERATE = SAADC_SAMPLERATE_MODE_Task &amp;lt;&amp;lt; SAADC_SAMPLERATE_MODE_Pos; // Rate is controlled from SAMPLE task

    // // Enable SAADC (would capture analog pins if they were used in CH[0].PSELP)
    /* When enabled, the SAADC will acquire access to analog input pins specified in registers CH[0].PSELP and CH[0].PSELN */
    NRF_SAADC-&amp;gt;ENABLE = SAADC_ENABLE_ENABLE_Enabled &amp;lt;&amp;lt; SAADC_ENABLE_ENABLE_Pos;
    
    // INTENSET = Enable interrupt
    // Read: Enabled
    NRF_SAADC-&amp;gt;INTENSET = SAADC_INTENSET_END_Enabled &amp;lt;&amp;lt; SAADC_INTENSET_END_Pos; // Write &amp;#39;1&amp;#39; to enable interrupt for event END
    NRF_SAADC-&amp;gt;EVENTS_END = 0;
    NVIC_EnableIRQ(SAADC_IRQn);
    
    // Calibrate the SAADC (only needs to be done once in a while)
    NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE = 0; // Calibration is complete, NotGenerated = 0 = Event not generated, Generated = 1 = Event generated
    NRF_SAADC-&amp;gt;TASKS_CALIBRATEOFFSET = 1; // Starts offset auto-calibration, 1 = Trigger task
    while(NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE == 0)
        vTaskDelay(pdMS_TO_TICKS(1));
    NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE = 0;    

    // Ready = 0 = SAADC is ready. No on-going conversions.
    // Busy  = 1 = SAADC is busy. Conversion in progress.
    while (NRF_SAADC-&amp;gt;STATUS == (SAADC_STATUS_STATUS_Busy &amp;lt;&amp;lt; SAADC_STATUS_STATUS_Pos)) // if status = busy
        vTaskDelay(pdMS_TO_TICKS(1));
    SEGGER_RTT_printf(0, &amp;quot;NRF_SAADC-&amp;gt;STATUS = 0, Ready, No on-going conversions.\r\n&amp;quot;);    
}

void ADC_timers_ppi_init(void){
    // Configure PPI channel with connection between (TIMER-&amp;gt;EVENTS_COMPARE[0]) = 1 and NRF_SAADC-&amp;gt;TASKS_SAMPLE
    // Channel &amp;quot;PPI_CHANNEL&amp;quot; event endpoint
    NRF_PPI-&amp;gt;CH[PPI_CHANNEL].EEP = (uint32_t)&amp;amp;NRF_TIMER1-&amp;gt;EVENTS_COMPARE[0];  // wire timer compare, Pointer to event register. Accepts only addresses to registers
       
    // Channel &amp;quot;PPI_CHANNEL&amp;quot; task endpoint
    // NRF_SAADC-&amp;gt;TASKS_START -&amp;gt; Starts the SAADC and prepares the result buffer in RAM
    NRF_PPI-&amp;gt;CH[PPI_CHANNEL].TEP = (uint32_t)&amp;amp;NRF_SAADC-&amp;gt;TASKS_START; // Pointer to task register. Accepts only addresses to registers

    /* 
      Each TEP implements a fork mechanism that enables a second task to be triggered at the same time as
      the task specified in the TEP is triggered.
    */
    // Channel &amp;quot;PPI_CHANNEL&amp;quot; task endpoint
    // NRF_SAADC-&amp;gt;TASKS_SAMPLE -&amp;gt; Takes one SAADC sample
    NRF_PPI-&amp;gt;FORK[PPI_CHANNEL].TEP = (uint32_t)&amp;amp;NRF_SAADC-&amp;gt;TASKS_SAMPLE; // Sub-task, Do a SAADC sample, will put the result in the configured RAM buffer.
    
    // Channel enable set register, Enable PPI channel
    //NRF_PPI-&amp;gt;CHENSET = PPI_CHENSET_CH0_Enabled &amp;lt;&amp;lt; PPI_CHENSET_CH0_Pos;
    NRF_PPI-&amp;gt;CHENSET = PPI_CHENSET_CH0_Enabled &amp;lt;&amp;lt; PPI_CHANNEL;
}

void ADC_timers_init(void){   
    NRF_TIMER1-&amp;gt;TASKS_STOP = 1; // (@ 0x00000004) Stop Timer 
    
    // 0 = Select Timer mode, In Timer mode, the TIMER&amp;#39;s internal Counter register is incremented by one for every tick of the timer frequency fTIMER
    // TIMER_MODE_MODE_Timer = 0UL
    NRF_TIMER1-&amp;gt;MODE        = TIMER_MODE_MODE_Timer;
    
    // Configure the number of bits used by the TIMER, 32 bit timer bit width (3 = 0b11), 
    NRF_TIMER1-&amp;gt;BITMODE = TIMER_BITMODE_BITMODE_32Bit &amp;lt;&amp;lt; TIMER_BITMODE_BITMODE_Pos; // Check for what it is.

    //NRF_TIMER1-&amp;gt;PRESCALER   = 7; // 125KHz = 8us timer period 
    NRF_TIMER1-&amp;gt;PRESCALER   = 4; // 1MHz = 1us timer period 
    NRF_TIMER1-&amp;gt;TASKS_CLEAR = 1; // (@ 0x0000000C) Clear time 
    
    // When the Counter value becomes equal to the value specified in a capture compare register CC[n], the corresponding compare event COMPARE[n] is generated.
    //NRF_TIMER1-&amp;gt;CC[0] = 210; // Compare event on CC[0] match, ---&amp;gt; 1,680 us = 1.68 ms compare value, generates EVENTS_COMPARE[0]
    NRF_TIMER1-&amp;gt;CC[0] = VALUE_CAPTURE_COMPARE_REGISTER; // Compare event on CC[0] match, ---&amp;gt; 1,680 us = 1.68 ms compare value, generates EVENTS_COMPARE[0]

    // Enable shortcut, Clear the timer when COMPARE[0] event is triggered
    // Shortcut between event COMPARE[A], A = BitPos 0 = (i = 0) and task CLEAR
    NRF_TIMER1-&amp;gt;SHORTS      = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled &amp;lt;&amp;lt; TIMER_SHORTS_COMPARE0_CLEAR_Pos); // Shortcuts between local events and tasks

    NRF_TIMER1-&amp;gt;TASKS_START = 1;  // (@ 0x00000000) Start Timer    
}

float ADC_convertValueRMSToValueVoltage(float rms_voltageDigital, uint8_t channel){   
      /*
      - RESULT = DIGITAL VALUE OBTAINED FROM THE SAADC

      - The digital output value from the SAADC is calculated using a formula.
      - RESULT = (V(P) - V(N)) * (GAIN/REFERENCE) * 2(RESOLUTION - m)     , m = 0 for single-ended channels
      - Result = [V(p) - V(n)] * GAIN/REFERENCE * 2^(RESOLUTION)
      - Result = (VDD - 0) * ((1/4) / 0.6) * (2^10)
      - Result = (VDD) * (0.4166) * (2^10)
      - Result = VDD * 426.66
      - VDD = Result / 426.7
 
      - VDD(0V)    * 426.6 = 0(Digital)
      - VDD(1V)    * 426.6 = 427(Digital)
      - VDD(2.3V)  * 426.6 = 981(Digital)
      - VDD(2.38V) * 426.6 = 1019(Digital)
      - VDD(2.39V) * 426.6 = 1022(Digital)
      - VDD(2.4V)  * 426.6 = 1023(Digital) = (2^10) - 1 = 1023
      
      - Input range (maximum and minimum ADC input) = (0.6V)/(1/4) = 2.4 [0V to 2.4V]

      - Gain = Input range / Vref = (2.4 / 0.6) = 4

      - Resolution = Vuc/2^(n-1)
      - Resolution = (2.4)/(2^(10-1)) = 0.00234375V (Es la diferencia entre cada valor Digital convertido a Voltage)
   */ 
    if(channel == NRF_SAADC_CH_0){ // AIN1 (Pin P0.03) --&amp;gt; AC_SENSOR
      return ((float)rms_voltageDigital / 426.7f);
   }
}  

double ADC_calculateRMS(uint8_t channel, samplesADC *adcSamples, int16_t num_samples, bool applyFilterBefore, double *alpha){
    /* Low-pass filter parameter (adjust alpha based on your requirements) */
    if(applyFilterBefore){
        if(alpha != NULL){
            ADC_applyLowPassFilter(channel, adcSamples, num_samples, *alpha);
        }
        else{
            SEGGER_RTT_printf(0, &amp;quot;alpha == NULL, Filter applied with alpha = [DEFAULT_ALPHA_FILTER]\r\n&amp;quot;);
            ADC_applyLowPassFilter(channel, adcSamples, num_samples, DEFAULT_ALPHA_FILTER);            
        }   
    }    
    int16_t i;
    double sum_of_squares = 0.0;

    for(i = 0; i &amp;lt; num_samples; i++){
        sum_of_squares += adcSamples[channel].sample[i].adcValue * adcSamples[channel].sample[i].adcValue;
    }

    double mean_squared = sum_of_squares / num_samples;

    double voltage_rms = sqrt(mean_squared);

    return voltage_rms;

}

void ADC_printBufferSamples_ADC_value(uint8_t channel, samplesADC *ValuesADC){
    SEGGER_RTT_printf(0, &amp;quot;+++++++++++++++++++++++++++++++++\r\n&amp;quot;);
    for(int16_t sample = 0; sample &amp;lt; TOTAL_SAMPLES_EACH_CYCLE; sample++){        
        SEGGER_RTT_printf(0, &amp;quot;sample No. [%d], Value_ADC CH_%d = [%d]\r\n&amp;quot;, sample, channel, (int16_t)ValuesADC[channel].sample[sample].adcValue);                
    }
    SEGGER_RTT_printf(0, &amp;quot;+++++++++++++++++++++++++++++++++\r\n&amp;quot;);
}

void ADC_initBufferSamples(samplesADC *samplesValuesADC){    
    for(int16_t channel = 0; channel &amp;lt; NRF_SAADC_RESULT_MAXCNT; channel++){
        for(int16_t sample = 0; sample &amp;lt; TOTAL_SAMPLES_EACH_CYCLE; sample++){
            samplesValuesADC[channel].sample[sample].adcValue = 0;
            //samplesValuesADC[channel].sample[sample].voltageValue = 0.0;
        }
    }
}

void ADC_printInDecimalVoltage(float limitVoltagePrint, float voltageValue){
    int16_t intPart = 0;
    int16_t decimalPart = 0;

    intPart = limitVoltagePrint;
    decimalPart = (limitVoltagePrint - intPart) * PRECISION;
    SEGGER_RTT_printf(0, &amp;quot;[0V to %d.%dV]: &amp;quot;, intPart, decimalPart);           

    intPart = voltageValue;
    decimalPart = (voltageValue - intPart) * PRECISION;
    SEGGER_RTT_printf(0, &amp;quot;CH_%d = [%d.%dV]&amp;quot;, NRF_SAADC_CH_0, intPart, decimalPart);           
    SEGGER_RTT_printf(0, &amp;quot;\r\n&amp;quot;);
}

void ADC_processADCsamples(QueueHandle_t *xQueue, samplesADC *samplesValuesADCfromQueue, int16_t *cont_Frames, 
                              int16_t *contadorFramesISR, samplesADC *ISRsamplesValuesADC, bool applyFilterBefore, double *alpha){
    if(xQueueReceive(*xQueue, samplesValuesADCfromQueue, portMAX_DELAY) == pdPASS) {   
        if(*cont_Frames &amp;lt; MAX_INT16_T){                                                          
            SEGGER_RTT_printf(0, &amp;quot;====================================================\r\n&amp;quot;); 
            SEGGER_RTT_printf(0, &amp;quot;FRAME [%d], NUM_SAMPLES by FRAME = [%d]\r\n&amp;quot;, *cont_Frames, TOTAL_SAMPLES_EACH_CYCLE);                 
            *cont_Frames += 1;
            // For NRF_SAADC_CH_0
#if 0
            printBufferSamples_ADC_value(NRF_SAADC_CH_0, &amp;amp;samplesValuesADCfromQueue);           
#endif                           
                
#if 1                         
            double rms_voltageDigital = ADC_calculateRMS(NRF_SAADC_CH_0, samplesValuesADCfromQueue, TOTAL_SAMPLES_EACH_CYCLE, applyFilterBefore, alpha);
            SEGGER_RTT_printf(0, &amp;quot;RMS_Voltage_Digital CH_%d = [%d]\r\n&amp;quot;, NRF_SAADC_CH_0, (int16_t)rms_voltageDigital);
                              
            float voltageValue = ADC_convertValueRMSToValueVoltage(rms_voltageDigital, NRF_SAADC_CH_0);
                            
            ADC_printInDecimalVoltage(2.4f, voltageValue);
            
            //float realVoltageAC = (113.2822 * voltageValue) - 10.8775;            
            float realVoltageAC = (169.70563 * voltageValue) - 10.8775;  // sqrt(2)*120     
            //float realVoltageAC = (178.19090 * voltageValue) - 10.8775;  // sqrt(2)*126     
            //float Vpico = (float)sqrt(2) * realVoltageAC;
            SEGGER_RTT_printf(0, &amp;quot;VALUE_AC_REAL: CH_%d = [%dV AC]\r\n&amp;quot;, NRF_SAADC_CH_0, (int16_t)realVoltageAC);
                            
            ADC_printInDecimalVoltage(120.0f, realVoltageAC); // 126V             
#endif 
            *contadorFramesISR = 0;

            ADC_initBufferSamples(ISRsamplesValuesADC);

            SEGGER_RTT_printf(0, &amp;quot;====================================================\r\n&amp;quot;);
            vTaskDelay(pdMS_TO_TICKS(200));                
        }
        else{
            *cont_Frames = 0;
        }              
    }
}

void ADC_copySamplesToBuffer(int16_t *contadorFrames, int16_t total_samples_each_cycle, int16_t *ADC_read,
                              samplesADC *_samplesValuesADC, QueueHandle_t *xQueue, BaseType_t *xHigherPriorityTaskWoken){
#if (!PRINT_DEBUG_ADC)
    SEGGER_RTT_printf(0, &amp;quot;SAADC event: DONE\r\n&amp;quot;);
    SEGGER_RTT_printf(0, &amp;quot;Sample buffer address == [%p]\r\n&amp;quot;, ADC_read);
    SEGGER_RTT_printf(0, &amp;quot;Sample buffer address == [%p]\r\n&amp;quot;, NRF_SAADC-&amp;gt;RESULT.PTR);
    uint16_t samples_number = NRF_SAADC-&amp;gt;RESULT.AMOUNT;
    SEGGER_RTT_printf(0, &amp;quot;samples_number = [%d]\r\n&amp;quot;, (uint16_t)samples_number);     
    uint16_t max_samples_number = NRF_SAADC-&amp;gt;RESULT.MAXCNT;
    SEGGER_RTT_printf(0, &amp;quot;max_samples_number = [%d]\r\n&amp;quot;, (uint16_t)max_samples_number);
#endif        
    //SEGGER_RTT_printf(0, &amp;quot;contadorFrames = [%u]\r\n&amp;quot;, (uint16_t)*contadorFrames);
    if(*contadorFrames &amp;lt; total_samples_each_cycle){            
        _samplesValuesADC[NRF_SAADC_CH_0].sample[*contadorFrames].adcValue = ADC_read[NRF_SAADC_CH_0]; // AC-Sensor
        _samplesValuesADC[NRF_SAADC_CH_1].sample[*contadorFrames].adcValue = ADC_read[NRF_SAADC_CH_1];
        _samplesValuesADC[NRF_SAADC_CH_2].sample[*contadorFrames].adcValue = ADC_read[NRF_SAADC_CH_2];
        _samplesValuesADC[NRF_SAADC_CH_3].sample[*contadorFrames].adcValue = ADC_read[NRF_SAADC_CH_3];            
        *contadorFrames += 1; 
    }
    else{
        xHigherPriorityTaskWoken = pdFALSE;
                              
        // Send data to the queue
        if(xQueueSendToFrontFromISR(*xQueue, _samplesValuesADC, xHigherPriorityTaskWoken) == pdPASS){
#if (!PRINT_DEBUG_ADC)
            SEGGER_RTT_printf(0, &amp;quot;Sent form ISR\r\n&amp;quot;);
#endif
        }
                   
        // If the ISR unblocks a higher-priority task, request a context switch
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}&lt;/pre&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/thread/461770?ContentTypeID=1</link><pubDate>Wed, 27 Dec 2023 10:19:38 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:47441cde-d1af-432c-8796-dad5395a14d9</guid><dc:creator>Hieu</dc:creator><description>&lt;p&gt;Hello Fer,&lt;/p&gt;
&lt;p&gt;The&amp;nbsp;example that Naeem linked in his previous reply is&amp;nbsp;on the nRF5 SDK, where the peripherals are controlled directly by drivers, and there is no OS involved. That&amp;#39;s really bare-metal. The initialization of the TIMER, PPI, and SAADC are all covered in the&amp;nbsp;example.&lt;/p&gt;
&lt;p&gt;If you&amp;nbsp;feel you don&amp;#39;t understand why the TIMER, PPI, or SAADC are setup in certain ways, I strongly recommend you to go over the documentation for those peripherals. It isn&amp;#39;t very long. Here are the links for the nRF52833:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://infocenter.nordicsemi.com/topic/ps_nrf52833/timer.html?cp=5_1_0_5_27"&gt;TIMER — Timer/counter&lt;/a&gt;&lt;br /&gt;&lt;a href="https://infocenter.nordicsemi.com/topic/ps_nrf52833/ppi.html?cp=5_1_0_5_14"&gt;PPI — Programmable peripheral interconnect&lt;br /&gt;&lt;/a&gt;&lt;a href="https://infocenter.nordicsemi.com/topic/ps_nrf52833/saadc.html?cp=5_1_0_5_20"&gt;SAADC — Successive approximation analog-to-digital converter&lt;/a&gt;&lt;a href="https://infocenter.nordicsemi.com/topic/ps_nrf52833/ppi.html?cp=5_1_0_5_14"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If that is not suitable for you,&amp;nbsp;could you please explain in details what you need, and why?&lt;/p&gt;
&lt;p&gt;By the way, the nRF5 SDK however is in &lt;a href="https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/nrf-connect-sdk-and-nrf5-sdk-statement"&gt;maintenance mode&lt;/a&gt;. Our newer SDK, the nRF Connect SDK, is based on the Zephyr RTOS, so it might not be as bare-metal as you would like. We recommend it anyway.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The equivalent SAADC controlled directly with nrfx driver is available at:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For NCS v2.5.0:&amp;nbsp;&lt;a href="https://github.com/zephyrproject-rtos/hal_nordic/tree/nrfx-3.0.0/nrfx/samples"&gt;hal_nordic/nrfx/samples at nrfx-3.0.0 · zephyrproject-rtos/hal_nordic (github.com)&lt;br /&gt;&lt;/a&gt;For NCS v2.4.x:&amp;nbsp;&lt;a href="https://github.com/zephyrproject-rtos/hal_nordic/tree/nrfx-2.11.0/nrfx/samples"&gt;hal_nordic/nrfx/samples at nrfx-2.11.0 · zephyrproject-rtos/hal_nordic (github.com)&lt;br /&gt;&lt;/a&gt;For NCS v2.2.0-v2.3.0:&amp;nbsp;&lt;a href="https://github.com/zephyrproject-rtos/hal_nordic/tree/nrfx-2.10.0/nrfx/samples"&gt;hal_nordic/nrfx/samples at nrfx-2.10.0 · zephyrproject-rtos/hal_nordic (github.com)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally,&amp;nbsp;our apologies for&amp;nbsp;the long wait time during this period.&amp;nbsp;It has been the Christmas-New Year holiday time, and we have been understaffed. The situation should start to improve from late next week.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Hieu&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/thread/461479?ContentTypeID=1</link><pubDate>Thu, 21 Dec 2023 15:28:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8e8868a4-83a5-470b-bfcf-a6c036584590</guid><dc:creator>Fernando Mercado</dc:creator><description>&lt;p&gt;Hello Naeem,&lt;/p&gt;
&lt;p&gt;Thanks for the answer. The thing is, I need to program everything &amp;quot;bare-metal.&amp;quot; I refer to the initialization of the TIMER, the PPI, and the SAADC,&amp;nbsp;but I don&amp;#39;t know how to start. Can you help with one example in &amp;quot;bare-metal&amp;quot;, or where can I find some examples, please?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;/Mercado, Fer.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How do I get the current value AC using a TIMER, PPI, SAADC and FreeRTOS on the nRF52833?</title><link>https://devzone.nordicsemi.com/thread/461472?ContentTypeID=1</link><pubDate>Thu, 21 Dec 2023 15:08:13 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:01138b29-aa04-4d11-b191-2499361187bd</guid><dc:creator>Naeem Maroof</dc:creator><description>&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;Thank you for contacting DevZone at NordicSemi.&lt;/p&gt;
&lt;p&gt;I think you can use ADC with your hardware setup to measure current.&lt;/p&gt;
&lt;p&gt;Please have a look at this ticket that deals with the same query:&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/f/nordic-q-a/52562/ac-240v-current-measurement-using-a-ct-with-nrf52832"&gt;Current Measurement with NRF using CT&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For SAADC example, please have a look a &lt;a href="https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/nrf_dev_saadc_example.html?cp=9_1_4_6_35"&gt;SAADC Sample&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;/BR, Naeem&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>