I'm trying to figure out how I can effectively and efficiently swap the bits of a port and write it to another port.
char BTN_INPUT;
char BTN_OUT;
void loop()
{
BTN_INPUT = PINA; // Read PORT A
BTN_OUTPUT = // do bit swapping magic here
PORTC = BTN_OUTPUT
}
For example:
PORTA == B10100110
I want to shift:
bit 0 to 7
bit 1 to 4
bit 2 to 6
bit 3 to 0
bit 4 to 3
bit 5 to 1
bit 6 to 2
bit 7 to 5
The result would be:
B01110001
and then set write them to PORTC.
Basically its a button swapper but I need it to be very fast so there is as little delay as possible between the input port (A) and when the arduino outputs the result (C).
What's the fastest way to shuffles these bits around? I tried but couldn't come up with any bit shifting logic and just ended up confusing myself. I would appreciate any help provided. Thank you.
At the simplest level you could use bitRead() and bitWrite() to create a variable with the result in it. How fast that would be I have no idea, but an array holding the target bits would mean that you could use a for loop to do the 8 reads and writes.
I suspect you made an error: In your specification bit 3 is shifted to bit 0, in B10100110 bit 3 is cleared but in B01110001 bit 0 is set. This is not consitent.
Anyhow i wrote a short function to do the suffleling. Quite straitforward, there might be faster ways to do that by using xor and shift (google for bit reversal) but this does the job in a very clear way and is easy to modify.
const byte pattern[8] = {1<<7, 1<<4, 1<<6, 1<<0, 1<<3, 1<<1, 1<<2, 1<<5};
byte shuffle(byte in){
byte result = 0;
for(int i = 0; i<8; i++){
result |= (pattern[i]*(in&1));
in >>=1;
}//for(i)
return result;
}//shuffle()
Probably fastest when running (but a bit of time to set up) - you could define an array of 256 bytes, where each element is the transformed bit pattern corresponding to one of the input values.
And yes, that was an error on my part, I apologize nilton61.
I'm trying to avoid this if possible and keep the time taken to do all the button swapping under 1-2ms. I tested last night with my oscilloscope and just a simple:
It took roughly 1.49ms for the arduino to ground the pin on PORTC after the pin on PORTA was grounded. (Yellow is the input button, blue is the output)
I do plan to move this to a CPLD at some point for faster response but in the mean time I need to do it with an Arduino. So any optimizations or help in optimizing this would be appreciate. Thank you all for the replies.
Hackscribble:
Probably fastest when running (but a bit of time to set up) - you could define an array of 256 bytes, where each element is the transformed bit pattern corresponding to one of the input values.
You could write a separate (slower) program to calculate the values for you, which you could cut and paste into the main program code.
Would you please elaborate on this please? Since setup is not an issue and the actual main program speed is, this sounds like an attractive option. I just don't quite understand how this works. Thank you.
Then do the following
new_value = (portA && 0x1) then do bit shift so that bit0 goes to bit7
new_value = new_value + (portA && 0x2) then do bit shift so that bit1 goes to bit4.
and so forth.
There are 256 possible values you can read in on an 8-bit port. Each of those values has one possible output value based on your mapping table. So you can set up a 256 byte array where, for example, element 42 has the output value you need if the input from the port was 42.
Hackscribble:
There are 256 possible values you can read in on an 8-bit port. Each of those values has one possible output value based on your mapping table. So you can set up a 256 byte array where, for example, element 42 has the output value you need if the input from the port was 42.
He is still going to have to do a loop to compare the portA values against the 256.
Granted he can break out when the match is found.
Im a little skeptical to your values.
When i ran this code on a UNO (it has no port A so i hade to chnge it a little) i got delays from input to output varying between 0,5 and 3 us.
Then do the following
new_value = (portA && 0x1) then do bit shift so that bit0 goes to bit7
new_value = new_value + (portA && 0x2) then do bit shift so that bit1 goes to bit4.
and so forth.
I tried something similar to this and it just failed. However, I will give this another go when I am able to test later this evening.
ieee488:
He is still going to have to do a loop to compare the portA values against the 256.
Granted he can break out when the match is found.
No, that's the beauty of this memory-consuming solution: the port value itself serves as the array index, so there's no search time (or O(1) if you insist )
void setup(){
// code to make PORTA inputs with pullups enabled
DDRA= 0x00; // all inputs
PORTA = 0xFF; // write to input pins to enable pullups
// code to make PORTC outputs
DDRC = 0xFF; // all outputs
//
}
void loop()
{
PORTC =PINA; // port c outputs will follow port a inputs
}
From 1280 Spec:
13.2.1 Configuring the Pin
Each port pin consists of three register bits: DDxn, PORTxn, and PINxn. As shown in “Table 13-34 and Table 13-
35 relates the alternate functions of Port L to the overriding signals shown in Figure 13-5 on page 73.” on page 95,
the DDxn bits are accessed at the DDRx I/O address, the PORTxn bits at the PORTx I/O address, and the PINxn
bits at the PINx I/O address.
The DDxn bit in the DDRx Register selects the direction of this pin. If DDxn is written logic one, Pxn is configured
as an output pin. If DDxn is written logic zero, Pxn is configured as an input pin.
If PORTxn is written logic one when the pin is configured as an input pin, the pull-up resistor is activated. To switch
the pull-up resistor off, PORTxn has to be written logic zero or the pin has to be configured as an output pin. The
port pins are tri-stated when reset condition becomes active, even if no clocks are running.
If PORTxn is written logic one when the pin is configured as an output pin, the port pin is driven high (one). If
PORTxn is written logic zero when the pin is configured as an output pin, the port pin is driven low (zero).
Port A was set as INPUT_PULLUP using pinMode() in setup() iirc.
I did have a Serial.print() as well in the loop, but after the button mapping was completed. I don't think that would have effected the time it took the Arduino to ground the pin on PORTC.
I'll check it out. To be fair, the buttons being pressed were going to a seperate pcb that also outputs. So there could be some delay between the button, the pcb, and then the arduino.
When I get home tonight, I will try just the button straight to the arduino and give all the suggestions a shot. Thank you all so much for your contributions!
igendel:
No, that's the beauty of this memory-consuming solution: the port value itself serves as the array index, so there's no search time (or O(1) if you insist )