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, 10 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, 10 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, 10 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