AVR GCC - typecasting trouble - c

I'm using an AVR microcontroller to write to a programmable frequency divider chip via the I2C bus. At certain intervals I'm trying to have the following function is called to update the frequency output of the chip:
void 1077WriteDiv(int16_t data)
{
uint8_t upperByte = (uint8_t)((uint16_t)data>>2);
i2c_start(DS1077_BASE_ADDRESS);
i2c_write(DIVIDE_REGISTER);
i2c_write(upperByte);
i2c_write(0x0);
i2c_stop();
}
I'm trying to get the top 8 bits of a ten bit value in the "data" variable and write it out. The second "write" command writes the lower 8 bits of the "divide" register on the chip, 0 in this case.
As a test case I'm incrementing the "data" variable (which has to be signed for certain reasons) from zero, shifting it left 2 bits and calling this function each time. I get garbage out. However, when I do this:
void 1077WriteDiv(int16_t data)
{
//uint8_t upperByte = (uint8_t)((uint16_t)data>>2);
static uint8_t thing = 0;
i2c_start(DS1077_BASE_ADDRESS);
i2c_write(DIVIDE_REGISTER);
i2c_write(thing++);
i2c_write(0x0);
i2c_stop();
}
Everything works as expected. There's obviously some kind of problem in how I'm shifting and typecasting the original "data" variable, but I've tried all kinds of permutations with the same results. It would be much appreciated if anyone could point out where I might be going wrong.

Try
uint8_t upperByte = (uint8_t) ((data & 0x3FC) >> 2);
You cannot rely on the cast to a smaller int to delete the high-order bits that you are trying to get rid of.

i2c_write(thing++);
Would mean your divider increments every call. If you increment "data" and shift it right by two then your divider increments every four calls. Your two code sections are not equivalent.
What interval are you calling this function at? What is "garbage out"? How do you know the value passed into the function is correct? How do you know the value sent out to the DS1077 is wrong?
Check all your assumptions.
The cast and shift look fine to me. At least I think they'd work in any C compiler I've ever used. From a C standard perspective you can refer to this draft (ISO/IEC 9899:TC2 6.3 Conversions):
Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or subtracting one more than the maximum value that
can be represented in the new type until the value is in the range of
the new type
Which is the only one I have access to right now. Perhaps someone else can chime in on the standard question. The compiler may not be standard compliant...

Related

AVR uint8_t doesn't get correct value

I have a uint8_t that should contain the result of a bitwise calculation. The debugger says the variable is set correctly, but when i check the memory, the var is always at 0. The code proceeds like the var is 0, no matter what the debugger tells me. Here's the code:
temp = (path_table & (1 << current_bit)) >> current_bit;
//temp is always 0, debugger shows correct value
if (temp > 0) {
DS18B20_send_bit(pin, 0x01);
} else {
DS18B20_send_bit(pin, 0x00);
}
Temp's a uint8_t, path_table's a uint64_t and current_bit's a uint8_t. I've tried to make them all uint64_t but nothing changed. I've also tried using unsigned long long int instead. Nothing again.
The code always enters the else clause.
Chip's Atmega4809, and uses uint64_t in other parts of the code with no issues.
Note - If anyone knows a more efficient/compact way to extract a single bit from a variable i would really appreciate if you could share ^^
1 is an integer constant, of type int. The expression 1 << current_bit also has type int, but for 16-bit int, the result of that expression is undefined when current_bit is larger than 14. The behavior being undefined in your case, then, it is plausible that your debugger presents results for the overall expression that seem inconsistent with the observed behavior. If you used an unsigned int constant instead, i.e. 1u, then the resulting value of temp would be well defined as 0 whenever current_bit was greater than 15, because the result of the left shift would be zero.
Solve this problem by performing the computation in a type wide enough to hold the result. Here's a compact, correct, and pretty clear way to correct your code to do that:
DS18B20_send_bit(pin, (path_table & (((uint64_t) 1) << current_bit)) != 0);
Or if path_table has an unsigned type then I prefer this, though it's more of a departure from your original:
DS18B20_send_bit(pin, (path_table >> current_bit) & 1);
Realization #1 here is that AVR is 1980-1990s technology core. It is not a x64 PC that chews 64 bit numbers for breakfast, but an extremely inefficient 8-bit MCU. As such:
It likes 8 bit arithmetic.
It will struggle with 16 bit arithmetic, by doing tricks with 16 bit index registers, double accumulators or whatever 8 bit core tricks it prefers to do.
It will literally take ages to execute 32 bit arithmetic, by invoking software libraries inline.
It will probably melt through the floor if attempting 64 bit arithmetic.
Before you do anything else, you need to get rid of all 64 bit arithmetic and radically minimize the use of 32 bit arithmetic. Period. There should be no single variable of uint64_t in your code or you are doing it very very wrong.
With this revelation also comes that all 8 bit MCUs always have an int type which is 16 bits.
In the code 1<<current_bit, the integer constant 1 is of type int. Meaning that if current_bit is 15 or larger, you will shift bits into the sign bit of this temporary int. This is always a bug. Strictly speaking this is undefined behavior. In practice, you might end up with random change of sign of your numbers.
To avoid this, never use any form of bitwise operators on signed numbers. When mixing integer constants such as 1 with bitwise operators, change them to 1u to avoid bugs like the one mentioned.
If anyone knows a more efficient/compact way to extract a single bit from a variable i would really appreciate if you could share
The most efficient way in C is: uint8_t variable; ... if(variable & (1u << bits)). This should translate to the relevant "branch if bit set" instruction.
My general advise would be find your tool chain's disassembler and see what machine code that the C code actually generated. You don't have to be an assembler guru to read it, peeking at the instruction set should be enough.

Is bit masking comparable to "accessing an array" in bits?

For all the definitions I've seen of bit masking, they all just dive right into how to bit mask, use bitwise, etc. without explaining a use case for any of it. Is the purpose of updating all the bits you want to keep and all the bits you want to clear to "access an array" in bits?
Is the purpose of updating all the bits you want to keep and all the bits you want to clear to "access an array" in bits?
I will say the answer is no.
When you access an array of int you'll do:
int_array[index] = 42; // Write access
int x = int_array[42]; // Read access
If you want to write similar functions to read/write a specific bit in e.g. an unsigned int in a "array like fashion" it could look like:
unsigned a = 0;
set_bit(a, 4); // Set bit number 4
unsigned x = get_bit(a, 4); // Get bit number 4
The implementation of set_bit and get_bit will require (among other things) some bitwise mask operation.
So yes - to access bits in an "array like fashion" you'll need masking but...
There are many other uses of bit level masking.
Example:
int buffer[64];
unsigned index = 0;
void add_to_cyclic_buffer(int n)
{
buffer[index] = n;
++index;
index &= 0x3f; // Masking by 0x3f ensures index is always in the range 0..63
}
Example:
unsigned a = some_func();
a |= 1; // Make sure a is odd
a &= ~1; // Make sure a is even
Example:
unsigned a = some_func();
a &= ~0xf; // Make sure a is a multiple of 16
This is just a few examples of using "masking" that has nothing to do with accessing bits as an array. Many other examples can be made.
So to conclude:
Masking can be used to write functions that access bits in an array like fashion but masking is used for many other things as well.
So there are 3 (or 4) main uses.
One, as you say, is where you use the word as a set of true/false flags, where each flag is just indexed in a symmetric manner. I use 'word' here to be the piece of discrete memory that you are accessing in a single operation. So a byte holds 8 bit values, and a 'long long' holds 64 bits. With a bit more effort an array of words can be used as an array of more packed flags.
A second is where you are doing some manipulation of the value, but still consider the word to hold one value. There are many tricks like setting or clearing bottom bits to ensure alignment, or clearing top bits to get a modulus, shifting to divide or multiply by powers of 2.
A third use is where you want to pack lots of smaller-ranged values into a word. Each of the values is a particular meaning in context. This may either be because you need to communicate with a device that has defined this as the protocol, or because you need to create so many objects that the saving in space in each object outweighs the increase in code size and code speed cost (though that might be contrasted with the increased cache misses causing slowdown if the object were bigger).
As a distinction the fourth case is where these fields are distinct 1-bit flags that have specific meanings in the context of the code. Data objects tend to collect a number of such flags, and it is simply more convenient sometimes to store them as bits in a single location, than to use separate bytes for each flag. Generally testing a particular fixed indexed bit, or a fixed masked bit is no more expensive in code size or speed than testing the whole byte, though writing can be more complex. The storage savings are clear, so often programmers will declare an enumeration of bit masks by default when faced with creating a number of flags in a structure, or when writing a function.

How to copy MSB to rest of the byte?

In an interrupt subroutine (called every 5 µs), I need to check the MSB of a byte and copy it to the rest of the byte.
I need to do something like:
if(MSB == 1){byte = 0b11111111}
else{byte = 0b00000000}
I need it to make it fast as it is on an interrupt subroutine, and there is some more code on it, so efficiency is calling.
Therefore, I don't want to use any if, switch, select, nor >> operands as I have the felling that it would slow down the process. If i'm wrong, then I'll go the "easy" way.
What I've tried:
byte = byte & 0b100000000
This gives me 0b10000000 or 0b00000000.
But I need the first to be 0b11111111.
I think I'm missing an OR somewhere (plus other gates). I don't know, my guts is telling me that this should be easy, but it isn't for me at this moment.
The trick is to use a signed type, such as int8_t, for your byte variable, and take advantage of sign extension feature of the shift-right operation:
byte = byte >> 7;
Demo.
Shifting right is very fast - a single instruction on most modern (and even not so modern) CPUs.
The reason this works is that >> on signed operands inserts the sign bit on the left to preserve the sign of its operand. This is called sign extension.
Note: Technically, this behavior is implementation-defined, and therefore is not universally portable. Thanks, Eugene Sh., for a comment and a reference.
EDIT: My answer has confused people because I did not specify unsigned bytes. Here my assumption is that B is of type unsigned char. As one comment notes below, I can omit the &1. This is not as fast as the signed byte solution that the other poster put up, but this code should be portable (once it is understood that B is unsigned type).
B = -((B >> 7)&1)
Negative numbers our are friends. Shifting bits should be fast by the way.
The MSB is actually the sign bit of the number. It is 1 for a negative number and 0 for a positive number.
so the simplest way to do that is
if(byte < 0)
{
byte = -1;
}
else
{
byte = 0;
}
because -1 = 11111111 in binary.
If it is the case for an unsigned integer, then just simply type cast it into a signed value and then compare it again as mentioned above.

C Operator Precedence with pointer increments

I am trying to understand a line of C-code which includes using a pointer to struct value (which is a pointer to something as well).
Example C-code:
// Given
typedef struct {
uint8 *output
uint32 bottom
} myType;
myType *e;
// Then at some point:
*e->output++ = (uint8) (e->bottom >> 24);
Source: https://www.rfc-editor.org/rfc/rfc6386#page-22
My question is:
What exactly does that line of C-code do?
"What exactly does that line of C-code do?"
Waste a lot of time having to carefully read it instead just knowing at a glance. If I was doing code review of that, I'd throw it back to the author and say break it up into two lines.
The two things it does is save something at e->output, then advance e->output to the next byte. I think if you need to describe code with two pieces though, it should be on two lines with two separate statements.
As pointed out by Deduplicator in the comments above, looking at an operator precedence table might help.
*e->output++ = ... means "assign value ... to the location e->output is pointing to, and let e->output point to a new location 8 bits further afterwards (because output is of type uint8).
(uint8) (e->bottom >> 24) is then evaluated to get a value for ...
The line
*e->output++ = (uint8) (e->bottom >> 24);
does the following:
Find the field bottom of the structure pointed to by the pointer e.
Fetch the 32-bit value from that field.
Shift that value right 24 bits.
Re-interpret that value as a uint8_t, which now contains the high order byte.
Find the field output of the structure. It's a pointer to uint8_t.
Store the uint8_t we computed earlier into the address pointed to by output.
And finally, add 1 to output, causing it to point to the next uint8_t.
The order of some of those things might be rearranged a bit as long as the result
behaves as if they had been done in that order. Operator precedence is a completely
separate question from order in which operations are performed, and not really
relevant here.

Reading & comparing 10-bit register in 32-bit architecture

I am currently C programming 10-bit ADC inside 32-bit ARM9 based microcontroller. This 10-bit ADC is saving digitalised analog value in 10 bit register named "ADC_DATA_REG" that uses bits 9-0 (LSB). I have to read this register's value and compare it to a 32 bit constant named "CONST". My attempt looked like this, but it isn't working. What am i missing here? Should i use shift operations? This is my frst time dealing with this so any example will be welcomed.
The below code has been edited regarding coments and anwsers and is still not working. I allso added a while statement which checks if ADC_INT_STATUS flag is raized before reading ADC_DATA_REG. The flag mentioned indicates an interrupt which is pending as soon as ADC finishes conversion and data is ready to read from ADC_DATA_REG. It turns out data remains 0 even after assigning value of register ADC_DATA_REG to it, so that is why my LED is always on. And it allso means i got an interrupt and there should be data in ADC_DATA_REG, instead it seems there isnt...
#define CONST 0x1FF
unsigned int data = 0;
while (!(ADC_INT_STATUS_REG & ADC_INT_STATUS))
data = ADC_DATA_REG;
if ((data & 0x3FF)> CONST){
//code to turn off the LED
}
else{
//code to turn on the LED
}
You dont write how ADC_DATA_REG fetches the 10-bit value. But I assume that it is only a read to some IO-address. In this case the read from the address return 32 bits. In your case only the lower 10 are valid (or interresting). The other 22 bit can be anything (e.g. status bits, rubbish, ...), so before you proceed with the data, you should zero the first 22 bits.
In case the 10-bit value is signed, you should also perform a sign extension and correct your datatype (I know the port IO is unsigned, but maybe the 10-bit value the adc returns isnt). Then your comparison should work.

Resources