Storing values from ADC

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
CaDu_3933941
Level 4
Level 4
50 replies posted 25 replies posted 10 replies posted

Hi all,

For my project, I require to store values form an ADC into some variable. I am kinda new to C so I do not really know how datatypes work. I am trying to implement a PID controller, and from what i have read, the math is better done in 16 to 32 bits, however, the SAR ADC cannot go above 12 bits. Is there a way to change a uint8_t variable into a uint16_t? Or is there any other way around it.

0 Likes
1 Solution
ScottA_91
Employee
Employee
10 solutions authored 100 replies posted 50 replies posted

So I'm going to start with some basics and work from there.

In c, we have a lot of data types, but for this case we'll consider 3.

uint8_t

uint16_t

int16_t

Now each of these are integer types (whole numbers).  The "u" on the front stands for unsigned (meaning no negative numbers).  The number indicates the number of bits that can be stored in the data type.  (I said I was starting with basics.)

The SAR ADC (Successive approximation ADC) reads values and gives you an answer in a specified bit range.  The maximum number of bits it can give you is 12.  (Not really, but we're not going to go into special ways to use the ADC to get more bits today.)  But wait, I hear you say, 12 is less than 16 and more than 8.  To which I reply you are correct, because that's how math works.  So what happens if I try to stuff 12 bits into an 8 bit data structure?  The top 4 bits are dropped on the floor, and your PID goes nuts as the most significant data is lost.  Well that's not good.  (Incidentally, you can configure the ADC to give you 8 bits of data instead and nothing would be dropped on the floor, but you might have trouble near max/min values which I'll go into in a minute.)

So if you have the ADC configured for 12 bits, you probably want a 16 bit data structure to hold it.  Furthermore, with PSoC5, the counts are always signed.  In PSoC4 the result can be configured to be either signed or unsigned.  Basically this just moves the midpoint of the resulting data.

P4SAR.png

Because there are so many ways to configure this, I've found it easier to just use a kit, put a pot on the ADC pin and go between min and max in the debugger to find your min and max values.  Note: you minimum may be a little lower and the maximum a little higher than what you expect due to the nature of a SAR ADC.  This is the reason using an 8 bit value may be more difficult, as there is some wrap around at the extremes.

Getting back to the question at hand, let's say we do our calculations based on the range we expect (and special case any values beyond your expected range) how do we move from this 12 bit value, stored in a 16 bit data structure to be an 8 bit value.

Well, basically, you want to chop off the bottom 4 bits, to get an 8 bit value.  Right shift by 4 and cast as an int8_t/uint8_t.  If you're going from int16_t to uint8_t and you can have values in the 0xFxx range, make sure you deal with 2's compliment before doing the cast (add 0x800).

Something like:

int16_t foo = 0x7ff;

uint8_t bar;

bar = uint8_t((foo +0x800)>>4);

Assuming foo was signed and has your calculated value.

View solution in original post

3 Replies
Yeshwanth_KT
Employee
Employee
50 replies posted 25 replies posted 10 likes received

Hi,

Even though the result is just 12 Bit, it is still stored in a 32 Bit location. You can access the result either in uint32 or uint16 by using suitable APIs. Storing the result in uint8 will lead to loss of data.

Yeshwanth

0 Likes

Since the WaveDac is 8 bits, would it be better to use a 8 bit ADC?

0 Likes
ScottA_91
Employee
Employee
10 solutions authored 100 replies posted 50 replies posted

So I'm going to start with some basics and work from there.

In c, we have a lot of data types, but for this case we'll consider 3.

uint8_t

uint16_t

int16_t

Now each of these are integer types (whole numbers).  The "u" on the front stands for unsigned (meaning no negative numbers).  The number indicates the number of bits that can be stored in the data type.  (I said I was starting with basics.)

The SAR ADC (Successive approximation ADC) reads values and gives you an answer in a specified bit range.  The maximum number of bits it can give you is 12.  (Not really, but we're not going to go into special ways to use the ADC to get more bits today.)  But wait, I hear you say, 12 is less than 16 and more than 8.  To which I reply you are correct, because that's how math works.  So what happens if I try to stuff 12 bits into an 8 bit data structure?  The top 4 bits are dropped on the floor, and your PID goes nuts as the most significant data is lost.  Well that's not good.  (Incidentally, you can configure the ADC to give you 8 bits of data instead and nothing would be dropped on the floor, but you might have trouble near max/min values which I'll go into in a minute.)

So if you have the ADC configured for 12 bits, you probably want a 16 bit data structure to hold it.  Furthermore, with PSoC5, the counts are always signed.  In PSoC4 the result can be configured to be either signed or unsigned.  Basically this just moves the midpoint of the resulting data.

P4SAR.png

Because there are so many ways to configure this, I've found it easier to just use a kit, put a pot on the ADC pin and go between min and max in the debugger to find your min and max values.  Note: you minimum may be a little lower and the maximum a little higher than what you expect due to the nature of a SAR ADC.  This is the reason using an 8 bit value may be more difficult, as there is some wrap around at the extremes.

Getting back to the question at hand, let's say we do our calculations based on the range we expect (and special case any values beyond your expected range) how do we move from this 12 bit value, stored in a 16 bit data structure to be an 8 bit value.

Well, basically, you want to chop off the bottom 4 bits, to get an 8 bit value.  Right shift by 4 and cast as an int8_t/uint8_t.  If you're going from int16_t to uint8_t and you can have values in the 0xFxx range, make sure you deal with 2's compliment before doing the cast (add 0x800).

Something like:

int16_t foo = 0x7ff;

uint8_t bar;

bar = uint8_t((foo +0x800)>>4);

Assuming foo was signed and has your calculated value.