Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
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 02 Jul 20185 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 02 Jul 2018