It shouldn't overflow like that. If you look at the ADC value as a raw count of 0 to 4095, which is just 12 bits, and you shift it over 16 bits, it shouldn't take more than 28 bits to hold the result.
I would bet that what's happening is that you are treating the value as an integer, rather than a fraction. Numbers are very slippery things with the ezDSP compiler, it's easy to accidentally do this. Remember that Q numbers represent fractional values using the number of bits after the Q for fractions. So the value of unity in Q15 is 0x0000_8000, while in Q31 it is 0x4000_0000. The value of 4095 in Q15 is 0x07ff_8000, not 0x0000_0FFF; if you shift the latter value left 16 places, you have no problem, but shift the other one the same and you lose bits. So what you need to do is represent the ADC reading as a fraction in the range of 0 to 1, rather than as a raw integer.
If you innocently try to read the ADC value and massage it into a Q30 all in one expression, the compiler is apt to do some intermediate casts that will surprise you. It may be ugly, but with the ezDSP and in particular with ADC code on the ezDSP, I've found it best to break such conversions into small steps. Something like so ..
int adc_raw; // a plain int representation _iq15 adc_q15; // Q15 holder for the same data _iq31 adc_q31; // Q31 holder for same adc_raw = however_youre_reading_the_ADC(); adc_q15 = (_iq15)(adc_raw << (15 - 12)); // the tricky bit. read below.. adc_q31 = adc_q15 << (31 - 15);
The key here is the the line 'adc_q15 = ...' - you may be tempted to say instead 'adc_q15 = _IQ15(adc_raw);', but that will change an ADC count of 1 into 0x0000_8000, 2 into 0x0001_0000, etc, which is not what you want! Instead, you have to produce a Q15 value that represents the ADC reading in the range of 0 to 1, with half scale at 0.5, etc; this you do by sliding the value left so that the ADC's MSB lines up just to the right of the binary point. As the binary point in Q15 is to the right of bit 15, and the MSB of the ADC is to the right of bit 12, left shift that amount and voila, a normalized ADC value, you just have to cast it to the _iq15 type and you're halfway there! One more shift and you have the same fraction in Q31 format.
Suffixing the variable names like that is just a convention I've found helpful when I have the same data lying around in a bunch of different formats. There may be a macro to do the Q15 to Q31 conversion, something like adc_q31 = IQ15toIQ31(adc_q15), check your IQmathLib.h header file. It can also be done with macros in two steps, as adc_q31 = IQtoIQ31(IQ15toIQ(adc_q15)), though this uses the 'global Q setting', which again could give you incorrect intermediate results if it's not set correctly. The form given in the code snippet is succinct and relatively clear, at least with the Q values explicitly stated as 15 - 12, and 31 - 15, rather than the somewhat more mysterious 3 and 16.
upvotedby us? $\endgroup$