<?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 to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/4517/how-to-calibrate-the-nrf51-adc-to-correct-offset-and-gain-error</link><description>According to the nRF51822 PS v3.1, table 51, offset error for the internal ADC is up to 2% and the gain error can be up to 2%. Is it possible to correct this error to obtain better accuracy for the ADC?</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Mon, 22 May 2023 13:10:04 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/4517/how-to-calibrate-the-nrf51-adc-to-correct-offset-and-gain-error" /><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/426583?ContentTypeID=1</link><pubDate>Mon, 22 May 2023 13:10:04 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:de2cf9a2-69ef-4a93-9b01-45fd593ea9a3</guid><dc:creator>AHaug</dc:creator><description>&lt;p&gt;Thank you,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;It will be assigned to an engineer within the following business day&lt;/p&gt;
&lt;p&gt;Kind regards,&lt;br /&gt;Andreas&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/426560?ContentTypeID=1</link><pubDate>Mon, 22 May 2023 12:28:34 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:7c6b392f-3652-46eb-af0a-9b62d72e8ae3</guid><dc:creator>PhilipSTT</dc:creator><description>&lt;p&gt;Hi Andreas,&lt;br /&gt;&lt;br /&gt;sure, thanks!&lt;br /&gt;&lt;a title="Correct calibration of the nRF51 ADC to correct offset and gain error" href="https://devzone.nordicsemi.com/f/nordic-q-a/99981/correct-calibration-of-the-nrf51-adc-to-correct-offset-and-gain-error" rel="noopener noreferrer" target="_blank"&gt;https://devzone.nordicsemi.com/f/nordic-q-a/99981/correct-calibration-of-the-nrf51-adc-to-correct-offset-and-gain-error&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Kind regards,&lt;br /&gt;Philip&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/426557?ContentTypeID=1</link><pubDate>Mon, 22 May 2023 12:25:50 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:e2bfe2bd-6b3e-4c44-bd70-98ebcf238550</guid><dc:creator>AHaug</dc:creator><description>&lt;p&gt;Hi Philip,&lt;/p&gt;
&lt;p&gt;Could you please open a new case for your topic? This will both increase the likelihood of someone on the forum answering your question, as it shows up as a new case, and help us with case separation of old and new cases.&lt;/p&gt;
&lt;p&gt;Kind regards,&lt;br /&gt;Andreas&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/426281?ContentTypeID=1</link><pubDate>Fri, 19 May 2023 11:50:56 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:6d7c7ba9-4e58-47cb-87b5-64e1c5197fcf</guid><dc:creator>Edvin</dc:creator><description>&lt;p&gt;Hello,&lt;br /&gt;I am sorry, but we are short staffed this week due to Public Holidays in Norway. We will be back on Monday 22nd and hope to be able to answer all incoming requests within a couple of days, depending on the backlog. I am sorry for the inconvenience.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;br /&gt;Edvin&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/425867?ContentTypeID=1</link><pubDate>Tue, 16 May 2023 12:55:54 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:069b45ad-dc5d-4fc7-a9eb-756e9a49377f</guid><dc:creator>PhilipSTT</dc:creator><description>&lt;p&gt;Hello,&lt;br /&gt;&lt;br /&gt;after this thread is already 8 years old, have there been some changes with offset and gain error calculations?&lt;br /&gt;Does ADC already work with the stored error values automatically or does it still be have to be applied manually?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am asking this because measurement seems to be more accurate if the errors are not calibrated to the measurement calculation.&lt;br /&gt;&lt;br /&gt;for explanation:&lt;br /&gt;&lt;br /&gt;I have a signal to be measured, it is in the range of 10-30mV. Depends a little bit on the PCBA and components used,&lt;br /&gt;as we are measuring the voltage drop across a MOSFET device. We apply 1A to the output and measure the Voltage&lt;br /&gt;across the MOSFET (same goes for a measurement of a voltage drop over a resistor).&lt;br /&gt;&lt;br /&gt;So if I use our FLUE TRMS, I can read values of ~23-24mV on the PCB Testpoints.&lt;br /&gt;&lt;br /&gt;A) Now if I use this code to measure the voltage, it gets me a value of ~32mV. (already tried to implement a TRMS calculation)&lt;br /&gt;&lt;br /&gt;note: &amp;quot;1.171875&amp;quot; is the calculated value of the ADC to mV conversion (1200/1024). the voltages are measured, calculated,&lt;br /&gt;squared (voltage_squared) and summed until the &amp;quot;SAMPLES_IN_BUFFER&amp;quot; value is reached - in this case 20. Then the sum (sum_squares)&lt;br /&gt;is divided through the amount of samples taken (&lt;span&gt;SAMPLES_IN_BUFFER) and from this value the square root is calculated:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void get_fetstate_voltage(void)
{
	 U_STATE = 0;
	 float voltage = 0;
	 float sum_squares = 0;
	 float voltage_squared = 0;
	 float mean_squares = 0;

for (int i = 0; i &amp;lt; SAMPLES_IN_BUFFER; i++) {
	nrf_delay_ms(1);
	nrf_drv_adc_sample_convert(&amp;amp;ADC_U_STATE, &amp;amp;adc_buffer[i]);
	voltage = adc_buffer[i] * 1.171875;
	voltage_squared = voltage * voltage;
	sum_squares += voltage_squared;
}

mean_squares = sum_squares / SAMPLES_IN_BUFFER;
U_STATE = sqrt(mean_squares);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;B) If I use this code it gets me this value: 38mV&lt;br /&gt;now this is basically the same code, only with additional gain &amp;amp; offset error calculation&lt;br /&gt;&lt;br /&gt;note: here I have implemented the code shown here from 27.10.2015, I have also read out the code via nrfprogj,&lt;br /&gt;same values - so it seems to be correct. Values from memory address show 0x10000024: FFFF0105 (GAIN=1, OFFSET=5).&amp;nbsp;&lt;br /&gt;ADC_RES_10BIT = 1024.&lt;br /&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void get_fetstate_voltage(void)
{
	 U_STATE = 0;
	 float voltage = 0;
	 float sum_squares = 0;
	 float voltage_squared = 0;
	 float mean_squares = 0;

	 static uint32_t ficr_value_32;
	 static int8_t offset_error;
	 static int8_t gain_error;

	 ficr_value_32 = *(uint32_t*)0x10000024;
	 offset_error = ficr_value_32;
	 gain_error = ficr_value_32 &amp;gt;&amp;gt; 8;


for (int i = 0; i &amp;lt; SAMPLES_IN_BUFFER; i++) {
	nrf_delay_ms(1);
	nrf_drv_adc_sample_convert(&amp;amp;ADC_U_STATE, &amp;amp;adc_buffer[i]);
	voltage = adc_buffer[i] * (ADC_RES_10BIT + gain_error) / ADC_RES_10BIT + offset_error - 0.5;
	voltage = voltage * 1.171875;
	voltage_squared = voltage * voltage;
	sum_squares += voltage_squared;

}
    mean_squares = sum_squares / SAMPLES_IN_BUFFER;
    U_STATE = sqrt(mean_squares);

}&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;C) If I use a standard code to read the ADC (no TRMS), I get this value: 36mV (with gain/offset error calculation)&lt;br /&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void get_fetstate_voltage(void)
{
	 U_STATE = 0;
	 float voltage = 0;

	 static uint32_t ficr_value_32;
	 static int8_t offset_error;
	 static int8_t gain_error;

	 ficr_value_32 = *(uint32_t*)0x10000024;
	 offset_error = ficr_value_32;
	 gain_error = ficr_value_32 &amp;gt;&amp;gt; 8;

				
	 nrf_drv_adc_sample_convert(&amp;amp;ADC_U_STATE,  &amp;amp;adc_buffer[0]);  // get HE current
  
 	 U_STATE = adc_buffer[0] * (ADC_RES_10BIT + gain_error) / ADC_RES_10BIT + offset_error - 0.5;
	 U_STATE = U_STATE * 1.171875;
}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;D) If I use the most simple code for this, I get this value: 30mV (no gain/offset error calculation)&lt;br /&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void get_fetstate_voltage(void)
{
	 U_STATE = 0;
	 float voltage = 0;

	 nrf_drv_adc_sample_convert(&amp;amp;ADC_U_STATE,  &amp;amp;adc_buffer[0]);
	 U_STATE = adc_buffer[0] * 1.171875;
}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So it looks like the gain and offset error calibration somehow fails on my side, I am not sure why,&lt;br /&gt;but measurement A) is taken without error calibration and is more accurate then measurement B)&lt;br /&gt;also measurement D) (no error calibration) is more accurate then measurement C)&lt;br /&gt;&lt;br /&gt;****************************************************************************************************************&lt;br /&gt;&lt;br /&gt;If I do the same examples with a different PCB (and a different nrf51802 device):&lt;br /&gt;mem read shows&amp;nbsp;0x10000024: FFFF0001 (&lt;span&gt;(GAIN=0, OFFSET=1),&lt;br /&gt;&lt;br /&gt;FLUKE TRMS = ~22mV&lt;br /&gt;&lt;br /&gt;Measurement A) = 25mV&lt;br /&gt;Measurement&amp;nbsp;B) = 26mV&lt;br /&gt;Measurement&amp;nbsp;C) = 24mV&lt;br /&gt;Measurement&amp;nbsp;D) = 23mV&lt;br /&gt;&lt;br /&gt;same on this measurement, with error calibration the output seems to have more error then without.&lt;br /&gt;Could someone please have a look into this, am i somehow calibrating additional error to my measurement?&lt;br /&gt;&lt;br /&gt;Thanks, Philip&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/137190?ContentTypeID=1</link><pubDate>Fri, 22 Jun 2018 04:00:50 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:34505187-a47b-41c9-9d52-bf60af5c79ab</guid><dc:creator>XavierYin</dc:creator><description>&lt;p&gt;The above sample code doesn&amp;#39;t look good to me. I suspect it falls to the 3rd case below.&lt;br /&gt;C99&amp;nbsp;6.3.1.3 Signed and unsigned integers&lt;/p&gt;
&lt;div class="page" title="Page 55"&gt;
&lt;div class="layoutArea"&gt;
&lt;div class="column"&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;span&gt;When a value with integer type is converted to another integer type other than &lt;/span&gt;&lt;span&gt;_Bool&lt;/span&gt;&lt;span&gt;, if the value can be represented by the new type, it is unchanged.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span&gt;Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.&lt;/span&gt;&lt;span&gt;49)&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span&gt;Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span&gt;A proposed alternative:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;int8_t offset_error = *(int8_t*)0x10000024;&lt;br /&gt;int8_t gain_error = *(int8_t*)0x10000025;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/16027?ContentTypeID=1</link><pubDate>Thu, 03 Aug 2017 08:55:02 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:cc4109a8-e48b-48a8-ad0d-ae20677a18fd</guid><dc:creator>jason</dc:creator><description>&lt;p&gt;Hi stefan,
Does the nRF52840 have a memory address that can be read the gain error and offset error numbers for ADC calibration?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/16028?ContentTypeID=1</link><pubDate>Mon, 26 Oct 2015 11:58:18 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:410a15c8-0f48-4755-9885-f338ec57b86c</guid><dc:creator>Luis</dc:creator><description>&lt;p&gt;Very useful info. Two related questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Why that &amp;quot;-0.5&amp;quot; in the formula? I have an example (yours I guess) where that value is ommited.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Is there any way we can automatically read this calibration value from code? For example a function that only runs once at the beggining, or similar. So we don&amp;#39;t have to manually get the value with nrfjprog.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/16026?ContentTypeID=1</link><pubDate>Tue, 20 Oct 2015 16:51:13 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:c355c59d-5a34-4aa2-a8fd-2d79ea0a6ae4</guid><dc:creator>Luis</dc:creator><description>&lt;p&gt;Very useful info.
Two related questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Why that &amp;quot;-0.5&amp;quot; in the formula? I have an example (yours I guess) where that value is ommited.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Is there any way we can automatically read this calibration value from code? For example a function that only runs once at the beggining, or similar. So we don&amp;#39;t have to manually get the value with nrfjprog.
Thanks&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/16025?ContentTypeID=1</link><pubDate>Mon, 19 Oct 2015 11:07:24 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:d175026f-dab4-4fea-b2ec-a150dfd88feb</guid><dc:creator>Stefan Birnir Sverrisson</dc:creator><description>&lt;p&gt;Hi Philip&lt;/p&gt;
&lt;p&gt;There is unfortunately no official document that contains this information. This information is made public only here on this thread. At this point I am not sure for the reasons for it not to be in official documentation but perhaps because it is limited information, since it only applies for 10 bit sampling. If this information will be in official documentation it will be in a future release of the nRF51 Series Reference Manual.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/16024?ContentTypeID=1</link><pubDate>Fri, 16 Oct 2015 23:32:10 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:7bdddc0a-177b-4ef0-b6a5-ec51307e14ca</guid><dc:creator>Philip Freidin</dc:creator><description>&lt;p&gt;Stephan, which document contains the above table with the offset and gain error values at offset 0x0024 of the FICR?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: How to calibrate the nRF51 ADC to correct offset and gain error</title><link>https://devzone.nordicsemi.com/thread/16023?ContentTypeID=1</link><pubDate>Wed, 19 Nov 2014 14:08:35 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:f4f2dcb5-a7ea-4b80-9843-5d0175edbae6</guid><dc:creator>Stefan Birnir Sverrisson</dc:creator><description>&lt;p&gt;The offset and gain error is different from IC to IC and may therefore be calibrated for each IC to obtain acceptable accuracy. On nRF51 third revision IC&amp;#39;s the offset and gain error has been measured and written into non-volatile memory for 10-bit ADC resolution, see update on this thread from 10.4.2015. To otherwise generally correct the offset and gain error, perform the following steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure the ADC to use 1.2VBG reference voltage and to sample from an analog input pin, use e.g. &lt;a href="https://github.com/NordicSemiconductor/nrf51-ADC-examples/tree/master/adc_no_drivers_rtc_driven"&gt;this code&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Connect a voltage source to the configured input pin that provides a steady 0.1V. Read the ADC output (actual ADC output at 0.1V)&lt;/li&gt;
&lt;li&gt;Set the voltage source to 1.1V and read the ADC output (actual ADC output at 1.1V)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The transfer function is:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devzone.nordicsemi.com/cfs-file/__key/communityserver-discussions-components-files/4/Capture-_2D00_-ADC-calibration-formula.JPG" alt="image description" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 10.4.2015&lt;/strong&gt;
An easier way to apply ADC calibration for third revision nRF51 is to read the gain error and offset error numbers available in memory address 0x10000024. This information is not available for first or second nRF51 revision ICs. For third revision nRF51 devices, the offset and gain error values have been measured for each nRF51 chip after production and have been written to memory address 0x10000024. The register at this memory address is listed below and the gain error and offset error values are valid for 10-bit sampling only. For 8-bit and 9-bit sampling, there are no  values available:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://devzone.nordicsemi.com/cfs-file/__key/communityserver-discussions-components-files/4/Capture-_2D00_-ADC-offset-and-gain-errror-values-in-FICR.JPG" alt="image description" /&gt;&lt;/p&gt;
&lt;p&gt;The ADC offset and gain error are read with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nrfjprog --memrd 0x10000024 --n 4
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If e.g. the perceived value is
&amp;quot;0x10000024: FFFF0102&amp;quot; then
GAIN_ERROR=1 and OFFSET_ERROR=2.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The offset and gain values are two&amp;#39;s
complement numbers. This means that
if e.g. the observed value is
0xFFFF03FF, then GAIN_ERROR=3 and
OFFSET_ERROR=-1&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Similarly, if the observed value is
0xFFFFFEFC, then GAIN_ERROR=-2 and
OFFSET_ERROR=-3&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The calibrated value y is obtained for 10-bit ADC sample x with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;y = x * (1024+GAIN_ERROR) / 1024 + OFFSET_ERROR - 0.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where 0.5 LSB is subtracted to compensate for ADC quantization error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 27.10.2015&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To obtain the offset error and gain error at runtime the FICR value can be read with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	static uint32_t ficr_value_32;
	static int8_t offset_error;
	static int8_t gain_error;

	ficr_value_32 = *(uint32_t*)0x10000024;
	offset_error = ficr_value_32;
	gain_error = ficr_value_32 &amp;gt;&amp;gt; 8;
&lt;/code&gt;&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>