user83299: I have an acceleration sensor (ADXL355) that returns 20-bit data in three bytes, formatted as 2s complement :

acc3 (bits 19-12) in byte register 3 (mapped to bits 7-0)
acc2 (bits 11-4) in byte register 2 (mapped to bits 7-0)
acc1 (bits 3-0) in byte register 1 (mapped to bits 7-4 while 3-0 are unused)

the acceleration value is taken as a signed 32 bit integer from the above 3 registers as follows :
int32_t acc32 = ((uint32_t)acc3 << 12) | ((uint16_t)acc2 << 4) | (acc1 >> 4);

if (acc32 & (1UL << 19)) acc32 -= 1UL << 20;

Then, I am doing some statistical analysis on acceleration values to calculate an offset trim as a signed 32 bit integer.
int32 off32;

This offset has to be written back to sensor as a 16 bit 2s complement value as follows :

offset high byte (bits 15-8)
offset low byte (bits 7-0)

The datasheet says that "The significance of offset bits 15-0 matches the significance of acceleration bits 19-4".
I found this rather tricky so I am asking how to convert this signed 32 bit offset integer to a 16 bit offset integer that follows the above specification.
I had this idea but don't know whether it is correct :
int16_t off16[i] = (int16_t)(off32[i] / 16);

sendSPI((uint8_t)(off16 >> 8));
sendSPI((uint8_t)off16);

Any comment should be greatly appreciated !

user7508: Other than the subscript [i], which looks suspicious, what you did
seems perfectly correct to me. Now, if I go nitpicking, I may suggest:

use a bit shift, as it is way cheaper than a division
round to nearest, rather than towards zero or minus infinity.

This gives:
int16_t off16 = (off32 + 8) >> 4;

Note that the bit shift behaves like a division that rounds towards −∞
(regular division rounds towards zero). Adding 8 achieves
round-to-nearest, with ties rounded up.

83299: <p>I have an acceleration sensor (<strong>ADXL355</strong>) that returns 20-bit data in three bytes, formatted as <strong>2s complement</strong> :</p>
<ul>
<li>acc3 (bits 19-12) in byte register 3 (mapped to bits 7-0)</li>
<li>acc2 (bits 11-4) in byte register 2 (mapped to bits 7-0)</li>
<li>acc1 (bits 3-0) in byte register 1 (mapped to bits 7-4 while 3-0 are unused)</li>
</ul>
<p>the acceleration value is taken as a signed 32 bit integer from the above 3 registers as follows :</p>
<pre><code>int32_t acc32 = ((uint32_t)acc3 &lt;&lt; 12) | ((uint16_t)acc2 &lt;&lt; 4) | (acc1 &gt;&gt; 4);

if (acc32 &amp; (1UL &lt;&lt; 19)) acc32 -= 1UL &lt;&lt; 20;
</code></pre>
<p>Then, I am doing some statistical analysis on acceleration values to calculate an offset trim as a signed 32 bit integer.</p>
<pre><code>int32 off32;
</code></pre>
<p>This offset has to be written back to sensor as a 16 bit 2s complement value as follows :</p>
<ul>
<li>offset high byte (bits 15-8)</li>
<li>offset low byte (bits 7-0)</li>
</ul>
<p>The datasheet says that &quot;<em><strong>The significance of offset bits 15-0 matches the significance of acceleration bits 19-4</strong></em>&quot;.</p>
<p>I found this rather tricky so I am asking how to convert this signed 32 bit offset integer to a 16 bit offset integer that follows the above specification.</p>
<p>I had this idea but don't know whether it is correct :</p>
<pre><code>int16_t off16[i] = (int16_t)(off32[i] / 16);

sendSPI((uint8_t)(off16 &gt;&gt; 8));
sendSPI((uint8_t)off16);
</code></pre>
<p>Any comment should be greatly appreciated !</p>
 7508: <p>Other than the subscript <code>[i]</code>, which looks suspicious, what you did
seems perfectly correct to me. Now, if I go nitpicking, I may suggest:</p>
<ul>
<li>use a bit shift, as it is way cheaper than a division</li>
<li>round to nearest, rather than towards zero or minus infinity.</li>
</ul>
<p>This gives:</p>
<pre class="lang-cpp prettyprint-override"><code>int16_t off16 = (off32 + 8) &gt;&gt; 4;
</code></pre>
<p>Note that the bit shift behaves like a division that rounds towards −∞
(regular division rounds towards zero). Adding 8 achieves
round-to-nearest, with ties rounded up.</p>
