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

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.

Related

Assigning a 2 byte variable to a 3 byte register?

My Watch dog timer has a default value of 0x0fffff and i want to write a 2 byte variable (u2 compare) in it. What happens when i assign the value simply like this
wdt_register = compare;
What happens to most significant byte of register?
Register definition. It's 3 bytes register containing H, M, L 8bit registers. 4 most significat bits of H are not used and then it's actually a 20 bit register. Datasheet named all of them as WDTCR_20.
My question is what happens when i assign a value to the register using this line (just an example of 2 byte value written to 3 byte register) :
WDTCR_20 = 0x1234;
Your WDT is a so-called special function register. In hardware, it may end up being three bytes, or it could be four bytes, some of which are fixed/read-only/unused. Your compiler's implementation of the write is itself implementation-dependent if the SFR is declared in a particular way that makes the compiler emit SFR-specific write instructions.
This effectively makes the result of the assignment implementation-dependent; the high eight bits might end up being discarded, might set some other microarchitectural flags, or might cause a trap/crash if they aren't set to a specific (likely all-zeros value). It depends on the processor's datasheet (since you didn't mention a processor/toolchain, we don't know exactly).
For example, the AVR-based atmega328p datasheet shows an example of such a register:
In this case, the one-byte register is actually only three bits, effectively (bits 7..3 are fixed to zero on read and ignored on write, and could very well have no physical flip-flop or SRAM cell associated with them).

What is meant by the following operation?

I cannot understand what is meant by following operation in embedded C?
NVIC_ICPR |= 1 << (vector_number%32);
From the reference manual, I found that
Vector number — the value stored on the stack when an interrupt is serviced.
IRQ number — non-core interrupt source count, which is the vector number minus
16.
But why is it modular division by 32?
It is basically a register with 32 bits in it.
This removes pending state of one or more interrupts within a group of 32. Each bit represents an interrupt number from IRQ0 - IRQ31 (Vector number from 16 - 47).
Writing 1 will remove the pending state. Writing 0 has no effect.
An important point is you should use it like this
NVIC_ICPR |= 1U << (vector_number%32);
This ensures that this will be unsigned int arithmetic - it saves you from UB which arises when vector_number=31. (chux pointed this).

Getting the negative integer from a two's complement value Embedded C

I know that many had similar questions over here about converting from/to two's complement format and I tried many of them but nothing seems to help in my case.
Well, I'm working on an embedded project that involves writing/reading registers of a slave device over SPI. The register concerned here is a 22-bit position register that stores the uStep value in two's complement format and it ranges from -2^21 to +2^21 -1. The problem is when I read the register, I get a big integer that has nothing to do with the actual value.
Example:
After sending a command to the slave to move 4000 steps (forward/positive), I read the position register and I get exactly 4000. However, if I send a reverse move command, say -1, and then read the register, the value I get is something like 4292928. I believe it's the negative offset of the register as the two's complement has no zero. I have no problem sending a negative integer to the device to move x number of steps, however, getting the actual negative integer from the value retrieved is something else.
I know that this involves two's complement but the question is, how to get the actual negative integer out of that strange value? I mean, if I moved the device -4000 steps, what I have to do to get the exact value for the negative steps moved so far from my register?
You need to sign-extend bit 21 through the bits to the left.
For negative values when bit 21 is set, you can do this by ORring the value with 0xFFC00000.
For positive values when bit 21 is clear, you can ensure by ANDing the value with 0x003FFFFF.
The solutions by Clifford and Weather Vane assume the target machine is two's-complement. This is very likely true, but a solution that removes this dependency is:
static const int32_t sign_bit = 0x00200000;
int32_t pos_count = (getPosRegisterValue() ^ sign_bit) - sign_bit;
It has the additional advantage of being branch-free.
The simplest method perhaps is simply to shift the position value left by 10 bits and assign to an int32_t. You will then have a 32 bit value and the position will be scaled up by 210 (1024), and have 32 bit resolution, but 10 bit granularity, which normally shouldn't matter since the position units are entirely arbitrary in any case, and can be converted to real-world units if necessary taking into account the scaling:
int32_t pos_count = (int32_t)(getPosRegisterValue() << 10) ;
Where getPosRegisterValue() returns a uint32_t.
If you do however want to retain 22 bit resolution then it is simply a case of dividing the value by 1024:
int32_t pos_count = (int32_t)(getPosRegisterValue() << 10)) / 1024 ;
Both solutions rely in the implementation-defined behaviour of casting a uint32_t of value not representable in an int32_t; but one a two's complement machine any plausible implementation will not modify the bit-pattern and the result will be as required.
Another perhaps less elegant solution also retaining 22 bit resolution and single bit granularity is:
int32_t pos_count = getPosRegisterValue() ;
// If 22 bit sign bit set...
if( (pos_count & 0x00200000) != 0)
{
// Sign-extend to 32bit
pos_count |= 0xFFC00000 ;
}
It would be wise perhaps to wrap the solution is a function to isolate any implementation defined behaviour:
int32_t posCount()
{
return (int32_t)(getPosRegisterValue() << 10)) / 1024 ;
}

bit and byte interpretation in AVR C

I know this may be wrong section for this but my problem is Microcontroller programming specific (AVR mostly)!
I am sending bytes between two AVR atmega8 using Uart where each bit in the byte stands for something and only one bit is 1 in each byte sent
So if I want to check, say for example, 5th bit in the received byte then if write it as follows:
short byte=UDR;
if(byte&(1<<5))
{
// do stuff for bit 5
}
Then it works fine always
BUT, if I write it as this:
short byte=UDR;
if(byte==0b00100000)
OR
short byte=UDR;
if(byte==0x20)
Then it won't work , also it fails if I use Switch-case instead of if-else
I can't understand the problem, does the compiler interprets it as signed no and 7th Bit as sign?
or something else?
The compiler is AVR-gnu from AVR studio 5
If someone asks I also have LEDs on the receiver that shows received byte
and so I know the byte received is correct but for some reason I cannot compare it for conditions! still can there some noise that causes bits to be misunderstood by the Uart and thus changing the actual byte received?
Help !
LOOK OUT EVERY ONE
Something here is like PARANORMAL
Finally I have cornered the area of problem
I added 8 LEDs to represent the bits of received bytes and here's what I found:
The LEDs represent (1<<5) as 0b00100000 that's ok as its what I sent
BUT
The other LEDs (excluding the 8) assigned to glow on receiving 0b00100000 does not glow!
FTW MAN!
I'm damn sure the received byte is correct ..but something's wrong with if-else and switch-case comparision
It doesn't work because the second formulation changes the meaning of the code, not just the spelling of the mask constant. To test a bit, you must apply the bitwise and (&) to the constant, not just compare the value with the constant:
if (byte & 0b00100000) /* note: 0b00100000 is a gcc extension */
or:
if (byte & 0x20) /* or byte & 32, or byte & (1 << 5), etc. */
C doesn't have a syntax for binary literals, you can't type 0b00100000 and have it compile.
It's a bit hard to understand why it wouldn't work for the == 0x20 case, since we don't know the value of UDR that is specific to your platform.
If UDR has more than 1 bit set, then the exact equality check will of course fail, while the single bit test will succeed.
You can only use switch() with exact values for each case, but you can of course mask before inspecting:
switch( byte & 0x20 )
{
case 0:
break;
case 0x20:
break;
}

AVR GCC - typecasting trouble

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...

Resources