5 years, 9 months ago.

Re-range AnalogIn from unsigned 16-bit to signed 16-bit

I would like to:

  • (a) Periodically read the AnalogIn signal as a unsigned 16-bit value in the range 0 to 65536
  • (b) offset it by -32768 so that it becomes a signed 16-bit number in the range -32768 to 32767
  • (c) read the signed number into a circular buffer.

Here's my attempt at the code:

#include "mbed.h"
#define BUFFERSIZE 0xfff  // number of data in circular buffer

AnalogIn        adc(p20);
Ticker          sampleTicker; 

short           circularBuffer[BUFFERSIZE];                   // circular buffer array
volatile int    queue = 0;
volatile int    writePointer = 0;
int             readPointer = 0;
volatile bool   recording = false;

void sampleInput(void){ 
    if (recording == true) {
        circularBuffer[writePointer] = (short)(adc.read_u16() - 0x8000);
        writePointer = writePointer + 1;
        queue = queue + 1;
        writePointer = writePointer & BUFFERSIZE; //makes pointer wrap to zero after BUFFERSIZE
    }
}
 
main {    
       recording = true;
       sampleTicker.attach(&sampleInput,0.5); // sets the sample period in seconds     
    // read signed 16-bit data from buffer and do other stuff
}

At line 7, is the short type for circularBuffer[BUFFERSIZE] correct?

To check the above, I made the following code change to the function:

void sampleInput(void){ 
    if (recording == true) {
        uint16_t wav_input = signalIn.read_u16();
        circularBuffer[writePointer] = (short)(wav_input - 0x8000);
        printf("writePtr=%i, signed=%x, unsigned=%x\r\n",   writePointer,
                                                            circularBuffer[writePointer],
                                                            wav_input);
        writePointer = writePointer + 1;
        queue = queue + 1;
        writePointer = writePointer & BUFFERSIZE; //makes pointer wrap to zero after BUFFERSIZE
    }
}

But this produces an output that doesn't match objective (b) for negative values.

Here is the output:

writePtr=0, signed=ffffeed6, unsigned=6ed6
writePtr=1, signed=2e4a, unsigned=ae4a
writePtr=2, signed=6f3e, unsigned=ef3e
writePtr=3, signed=ffffaeb2, unsigned=2eb2
writePtr=4, signed=ffffed96, unsigned=6d96
writePtr=5, signed=2d1a, unsigned=ad1a
writePtr=6, signed=6e3e, unsigned=ee3e
writePtr=7, signed=ffffad72, unsigned=2d72
writePtr=8, signed=ffffec66, unsigned=6c66
writePtr=9, signed=2bca, unsigned=abca

Why does ffff appear as a prefix for negative values? Is (short)(signalIn.read_u16() - 0x8000); incorrect for my objective (b)?

2 Answers

5 years, 9 months ago.

%x is telling printf to print the number as if it was an int. Ints are 32 bits on ARM processors which means 8 characters in hex. So for negative numbers you're going to get a prefix of ffff, that's what a negative number looks like in 2's compliment hex.

If you only want 4 characters then use %hx to print out a short in hex.

Thanks Andy A for your fast reply. Your suggestion did indeed print out the number without the ffff prefix. I understand your comment about int - I should have read https://os.mbed.com/handbook/C-Data-Types first.

I probably didn't explain myself properly.... My requirement is: When the AnalogIn value of adc is 1.0000, I want the circular buffer to read in exactly 16bits representing the value 0x7fff. When the AnalogIn value of adc is 0.0000, I want the circular buffer to read in exactly 16bits with value 0x8000. (And in between adc=0.0000 and 0.5000 I want the two's complement value in the range -32768 to 0. E.g. adc=0.2500, buffer reads 0xC000)

After a bit of experimentation, the only way I can achieve this is editing the above code as follows

line 7

uint_16	      circularBuffer[BUFFERSIZE];

line 15

circularBuffer[writePointer] = (signalIn.read_u16() - 0x8000);

line 25

fwrite(&circularBuffer[readPointer], 2, 8, fp); //8 can be smaller or larger no.

If I use short or int_16 in my line 7 declaration, I end up reading a 32-bit number (0xffff8000) into the buffer for AnalogIn=0.0000, which is not want I want.

I seem to have found a solution but I'm unclear why it works.

posted by S Francis 02 Jul 2018
5 years, 9 months ago.

Hi Francis,

As Andy said above, the reason for ffff appear in the signed number is because you are printing the 2's complement of number. Here is a link for more information about 2's compliment https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html

Please let me know if you have any questions!

- Peter, team Mbed

If this solved your question, please make sure to click the "Thanks" link below!

Thanks Peter. I appreciate the link about two's complement, which I've read. I think my problem is more to do with the width of the data written into the buffer. I've described this problem in my response to Andy A above.

By the way, if anyone's trying to do something similar, I've changed BUFFERSIZE to 0x8000 and edited line 18 as follows: writePointer = writePointer & (BUFFERSIZE - 1);

The pointer now wraps properly, I think.

posted by S Francis 02 Jul 2018