2021-11-19 07:59 PM
Hi. I'm having trouble with integer interpretation for DFSDM. From the RM:
> The offset correction allows to calibrate the external sigma-delta modulator offset error. The user configures the offset register with a signed 24-bit correction, and this register is automatically added to the output result. The offset correction value is usually the result of a calibration routine embedded within the microcontroller software that performs the offset calibration calculation and stores the correction into the offset register. All operations in the DFSDM peripheral are in signed format (filtering, integration, offset correction, right bit shift).
This would be fine if it used 16 or 32 bit registers, but I'm not sure how to make my language (Rust) do signed 24 bit integers.
1: Does it expect bit 24 to be the sign bit, or bit 32?
2: How do you handle this properly?
If you ask Rust, and presumably C or C++ as well, to interpret the register as an i32, it will probably use the left most bit as a sign bit, when perhaps DFSDM expects it to use the 24th bit?
Observations: Bit 0 from the output is always 1. Bits 1 - 8 are always 0. The eight most bits on the left are always 0. The "right bit shift" field makes more of these 0.
My intuition here says to use unsigned u32, and do manual bit manipluation to convert to i32s, by explicitly looking for bit 24 for the sin? Also, not sure what to make of the left 8 bits being all 1s all the time. Using DMA.
Solved! Go to Solution.
2021-11-19 08:22 PM
The reference manual will describe the interface implementation.
A signed 24 bit value is just like a signed 32 bit value, but less bits. The MSB has a bit value of -2^23, the other bits have their normal values (2^0 to 2^22). So a value of 0xFFFFFF is -1, just like a value of 0xFFFFFFFF is -1 for int32_t.
Edit:
int32_t offset = DFDSM->CHyCFGR2 >> 8;
if (offset & (1 << 23)) {
offset -= 2 * (1 << 23);
}
2021-11-19 08:22 PM
The reference manual will describe the interface implementation.
A signed 24 bit value is just like a signed 32 bit value, but less bits. The MSB has a bit value of -2^23, the other bits have their normal values (2^0 to 2^22). So a value of 0xFFFFFF is -1, just like a value of 0xFFFFFFFF is -1 for int32_t.
Edit:
int32_t offset = DFDSM->CHyCFGR2 >> 8;
if (offset & (1 << 23)) {
offset -= 2 * (1 << 23);
}
2021-11-20 01:15 AM
It uses 2's complement, where bit 23 reflects the sign.
To go from 32 to 24 bit simply truncate with an AND.
To go from 24 to 32 bit simply sign extend with an 0x00 or 0xFF in the high order byte.
2021-11-20 06:45 AM
Thank you. That clears it up.
Here's another element I discovered: The DMA is reading the whole `rdatar` register, not just the`rdata` field. The `rdata` field is left aligned in the register, so this simplifies things: You can use your language directly to convert to a signed integer (eg `i32`), since the sign field of the 24 bit data is coincidentally aligned to bit 31 of the integer you read from the reg. You can then right shift 8 bits to get rid of the rest of the register (`RDATACH`, RPEND, and some reserved bits) .
This bit on the right that was always 1 was actually the `RDATACH` field, and the other 7 empty bits were the remaining unused bits. The bits on the left being `1` were due to a DC offset that needed to be compensated for.
To set the `offset` value requires some arithmetic if doing a negative value to get bit 23 to be the sign bit.
2021-11-20 12:44 PM
/* Hopefully the next C standard, C23, will make this easier with _BitInt(N) types...
N2709 - Adding a Fundamental Type for N-bit Integers
*/
2021-11-20 05:30 PM
That would be great! Rust too hopefully