Wow - writing a 1 to set something to 0

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,082
I just carefully re-re-re-re-read the nRF24L01+ datasheet and realized that in order to set the TX_DS flag OFF we must write a value in which that flag is ON!

Totally counterintuitive, but I'm sure there are sound reasons, lesson? RTFM !
 

Ian0

Joined Aug 7, 2020
6,663
NXP's LPC processors do the same thing, often to reset the interrupt flags registers.
So if follows that if you read the flags register then write the number you have read back to the same register, it clears it.
Weird, but convenient!
 

BobaMosfet

Joined Jul 1, 2009
2,053
I just carefully re-re-re-re-read the nRF24L01+ datasheet and realized that in order to set the TX_DS flag OFF we must write a value in which that flag is ON!

Totally counterintuitive, but I'm sure there are sound reasons, lesson? RTFM !
Remember, it is not the spoon that bends, it is you who must bend around the spoon.
 

MrChips

Joined Oct 2, 2009
27,651
I just carefully re-re-re-re-read the nRF24L01+ datasheet and realized that in order to set the TX_DS flag OFF we must write a value in which that flag is ON!

Totally counterintuitive, but I'm sure there are sound reasons, lesson? RTFM !
This is normal. RTFM!
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,082
This is normal. RTFM!
Well its been years since I did much at all with digital electronics. Is there a term for this? writing 1 to set it to 0? Is there a converse, like write a 0 to set it to 1 or any other variants? is there reason for doing things that way?
 

MrChips

Joined Oct 2, 2009
27,651
You might think that this is counter intuitive but it is not so. Computer HW designers have been doing this for years.

Imagine that you have an 8-bit register, with bits B7-B6-B5-B4-B3-B2-B1-B0.
You can read 8 bits simultaneously. You can also write 8 bits simultaneously.

Now imagine that each bit represents a unique piece of data, for example, eight interrupt flags from eight different devices.
Suppose you wanted to clear the interrupt request flags for device #2 and device #5 seen as bits B2 and B5.
How would you do that?

You send a clear flag command with the binary word 00100100 which selects which flags you are addressing.
Conversely, there could be a set flag command which allows one to set a selected bit. Hence the data represents the bit selection, not the data to be written. I call it a bit mask.

Many MCUs (if not most) have native ASM instructions to clear bits in register (CBR) and set bits in register (SBR) (ref: Atmel AVR instruction set).

I am not aware of any operation that requires the user to write a 0 to set a bit to 1.
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,082
You might think that this is counter intuitive but it is not so. Computer HW designers have been doing this for years.

Imagine that you have an 8-bit register, with bits B7-B6-B5-B4-B3-B2-B1-B0.
You can read 8 bits simultaneously. You can also write 8 bits simultaneously.

Now imagine that each bit represents a unique piece of data, for example, eight interrupt flags from eight different devices.
Suppose you wanted to clear the interrupt request flags for device #2 and device #5 seen as bits B2 and B5.
How would you do that?

You send a clear flag command with the binary word 00100100 which selects which flags you are addressing.
Conversely, there could be a set flag command which allows one to set a selected bit. Hence the data represents the bit selection, not the data to be written. I call it a bit mask.

Many MCUs (if not most) have native ASM instructions to clear bits in register (CBR) and set bits in register (SBR) (ref: Atmel AVR instruction set).

I am not aware of any operation that requires the user to write a 0 to set a bit to 1.
OK, I understand the scenario I suppose. The "register" itself is designed to work that way, we can't write a 1 "into" the register, we can only really read the value in there. We can write a 1 and that - effectively - forces the associate bit low.

I've been writing code for the nRF24 recently and added an update register API to complement the Get/Set API.

Of course under the hood that has to read the register to get current state, update the byte and then write that byte back, that's two operations and in a harsher problem space the byte could change between me reading it and writing the update but not in this nRF24 device - thankfully.

To update a byte register you pass two bytes, one with the values and one with the "mask" defining which bits to change, so you'd pass say 05 04 to update two bits: 0000 0101 and 0000 0100 to change only bits 0 and 2 to the values 0 and 1 respectively, all other bits being left as is, this is now all done via small macro (of course we need to first read the current value, but that's done invisibly inside the AP):

Code:
// Convert any register struct into a unisgned int
#define REG_TO_INT(Register) (*(uint8_t*)(&(Register)))

// Compute the result register from a Current value after applying New bit values as indicated by a Mask struct
#define TWIDDLE(Current,New,Mask) (~(REG_TO_INT(Mask)) & REG_TO_INT(Current)) | (REG_TO_INT(Mask) & REG_TO_INT(New))
These nRF24 registers, typically look like this:

Code:
struct NrfReg_RF_SETUP_struct
{
    uint8_t  OBSOLETE : 1;
    uint8_t  RF_PWR : 2;
    uint8_t  RF_DR_HIGH : 1;
    uint8_t  PLL_LOCK : 1;
    uint8_t  RF_DR_LOW : 1;
    uint8_t  RESERVED : 1;
    uint8_t  CONT_WAVE : 1;
};

This is what lay behind all my questions in this other thread.

I also read recently about ARM's bit banding, where you can setup a section of memory as a bit band and associate an addressable word with a single bit in some other word. So that takes up 32 addresses in memory but allows you to set any bit on or off at the hardware level, a single write to the address causes the underlying ARM hardware to write just to the one target bit. They must have done that because it can be very fast indeed to adjust arbitrary bits at the expense of some memory and I guess some designs want that.

ARM seems to have quite a lot of genuine innovations the more I study it, like avoiding needless stack operations when we return from an interrupt and there's a lower priority interrupt already pending and so on.
 
Last edited:

MrChips

Joined Oct 2, 2009
27,651
STM32 MCUs are simply amazing. I write my own graphics libraries. I use bit banding without which pixel graphics would have been very difficult and inefficient.
 

John P

Joined Oct 14, 2008
1,990
On a PIC processor, you clear an interrupt flag by writing a 0 to that bit. On an AVR, you clear them by writing a 1. Evidently both methods work.
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,082
STM32 MCUs are simply amazing. I write my own graphics libraries. I use bit banding without which pixel graphics would have been very difficult and inefficient.
That must be petty interesting, I (many years ago, like mid 80s) developed a library that implemented 3D graphics on a Sinclair QL. This was all written in their "Super basic" language which was slow as you can imagine. Because it was slow I devised numerous optimizations to get it to render reasonably, like eliminating all calls to trig functions and so on. It was fun to see, I very much wanted to buy myself an IBM PC or Mac back then and convert the library into C or something to see how fast I could get it, alas that was not to be, job, life just started to take up my time, I did make a few bucks with it though which was nice.

Some of the optimizations were (especially noticeable speed up for wire frame mode)

  1. Undraw lines rather than clear screen for next image.
  2. Use a precomputed lookup table (90 slots) for very approximated trig functions - had no observable impact on perceived image
  3. Undraw/Draw lines at same time, reduced observable flicker.
 
Last edited:

MrChips

Joined Oct 2, 2009
27,651
How powerful is an STM32F407 MCU?

I have an application using an STM32F407 that digitizes analog waveforms at 42Msps, performs DSP operations, including FFT, and generates VGA graphics output without any additional hardware except for the fast ADC.

This is a photo of initial stages in the development.

1669045556589.png
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,082
How powerful is an STM32F407 MCU?

I have an application using an STM32F407 that digitizes analog waveforms at 42Msps, performs DSP operations, including FFT, and generates VGA graphics output without any additional hardware except for the fast ADC.

This is a photo of initial stages in the development.

View attachment 281154
Pretty cool stuff, that's a decent resolution too. I played around with the DAC on the F446RE Nucleo last year, never programmed such devices before, generated a sine signal from a lookup table, it was fascinating, can't recall the frequency I reached but it looked great on the scope, probably a waste of a DAC in real world applications but its impressive what these devices can do. I recall looking into using DMA for this too, I can't recall if I ever got that far.

Does the display "look like" a contiguous block of memory or do you interact with the display using commands and stuff?
 

MrChips

Joined Oct 2, 2009
27,651
Pretty cool stuff, that's a decent resolution too. I played around with the DAC on the F446RE Nucleo last year, never programmed such devices before, generated a sine signal from a lookup table, it was fascinating, can't recall the frequency I reached but it looked great on the scope, probably a waste of a DAC in real world applications but its impressive what these devices can do. I recall looking into using DMA for this too, I can't recall if I ever got that far.

Does the display "look like" a contiguous block of memory or do you interact with the display using commands and stuff?
The image is stored in a contiguous block of memory as H x V pixels. The STM32F407 itself has enough SRAM for this. No external memory is required. I can access a single pixel or linear vector straight line. The alpha numeric character display uses my own bit-map font stored in flash memory. Bit banding became essential for accessing individual pixels.

If you look closely at the VGA display you will notice some missing dots on the grid pattern. That was because the previously drawn sine wave was erased. I had yet to implement selective erase which is essentially an XOR logic operation.

Note that this is VGA output to a video monitor. There is no way to do this efficiently straight from the MCU without using DMA., i.e. DMA is essential for both the ADC signal capture and the VGA signal generation. Remember that the MCU has to send out HOR SYNC and VERT SYNC signals besides the VIDEO signal. Color output would be another challenge.
 
Top