I/O Ports (Part 5)

Part 12345

I recently received a mail related to some possible modifications of PlainDDS and MicroDDS. The idea from the author is to use pins from various ports.

In its actual version, PlainDDS uses 6 pins from the same PORT (B, C or D). The reason is that this allows fast iterations because of the simple pin level setting. However, it is possible to think about a more flexible solution, to the detriment of performances.

The proposed code looked like this

void dacOutput(long v)
{
 int tmpVal = v;
 bitWrite(PORTD, 5, tmpVal & 1);
 bitWrite(PORTD, 6, (tmpVal & 2) > 0);
 bitWrite(PORTD, 7, (tmpVal & 4) > 0);
 bitWrite(PORTB, 0, (tmpVal & 8) > 0);
 bitWrite(PORTB, 1, (tmpVal & 16) > 0);
 bitWrite(PORTB, 2, (tmpVal & 32) > 0);
 bitWrite(PORTB, 3, (tmpVal & 64) > 0);
 bitWrite(PORTB, 4, (tmpVal & 128) > 0);
}

At first glance, we can see that the execution of the code may take a looooong time because of the sequential approach of bits setting. On the other hand, the signal may be distored, because the least significant bits are set prior to the most significant bits! A first proposal would consist in swapping the lines order.
Secondly, the bit selection (tmpVal & xxx) is a little bit rough and may be written in a more elegant manner: (tmpVal & (1 << n)) where n is an incremented variable. Which leads to the proposal of a loop. But then comes the question of bits and ports that we could be defines in vectors. Oooch, that’s complex.

A probably better idea would consist in setting pins from both ports in a limited number of instructions. See the first proposal written in a very fragmented/self-explicit manner. Bit masks are expressed in binary format (e.g. B00011111 == 0x1F == 31 in decimal) in order to ease the understanding.

void dacOutput(long v)
{
	byte u;
	/* Most significant bits */
	/* Clear register bits */
	PORTB &= B00011111;
	/* Keep 5 MSB */
	u = (v & B11111000);
	/* Shift bits 3 positions to the right */
	u >>= 3;
	/* Set bits */
	PORTB |= u;
	/* Least significant bits */
	/* Clear register bits */
	PORTD &= B11100000;
	/* Keep 3 LSB */
	u = (v & B00000111);
	/* Shift bits 5 positions to the left */
	u <

Same as before written in a compact manner:

void dacOutput(long v)
{
	/* Most significant bits */
	PORTB &= B00011111;
	PORTB |= ((v & B11111000) >> 3);
	/* Least significant bits */
	PORTD &= B11100000;
	PORTD |= ((v & B00000111) << 5);
};

Ultimately, you may (have an aspirin and then) use this very compact method

void dacOutput(long v)
{
	/* Most significant bits */
	PORTB ^= ~(~(PORTB & B00011111) ^ ((v & B11111000) >> 3));
	/* Least significant bits */
	PORTD ^= ~(~(PORTD & B11100000) ^ ((v & B00000111) << 5));
};

HTH

Leave a Reply

You must be logged in to post a comment.