Go Down

Topic: read multiple pins at once? (Read 3332 times)previous topic - next topic

gschoppe

May 22, 2007, 07:03 am
I need to know whether any of pins 7-2 (set as inputs) are LOW as fast as possible... I read the bit math page  on the playground, and it left me wondering...

is there a method of getting the values of pins 7-0 as a byte, read from each simultaneously, to be evaluated more quickly?

i thought my evaluation might look something like this:
Code: [Select]
`if(GETBYTE > B00000011) {  evaluate (GETBYTE);}`
where GETBYTE was replaced with the name of a register containing the values of pins 1-7.  A piece of code like this would make a false almost immediate, so the if statement could be used as the exit clause of a loop.

does this make any sense?  Is there a way to do this?

jims

#1
May 22, 2007, 08:01 am
A quick look at the pin mapping diagram http://www.arduino.cc/en/Hacking/PinMapping shows pins 0-7 are all on port d. You can access the bits as a byte using PIND. I would use the bitwise AND operator (&) to mask off the two pins you don't care about and then check the result...
Code: [Select]
`if ( (PIND & 0xfc) != 0xfc) {    // then one of them is low}`
0xfc is a hexadecimal B11111100. I have parenthesis around the '&' operation because the bitwise operators have surprisingly low operator precedence and you can easily trick yourself with them, and they are required in this case but I always put them in for bitwise operators.

I didn't compile it to check, but that expression in the 'if' probably takes around 10 cycles to execute (it is a bit long because bitwise operations have to be done at 'int' size by the C spec). This compares to a digitalRead() that takes something like 100 cycles in arduino-0007.

wandrson

#2
May 22, 2007, 03:02 pm
jims has given you the specific answer you requested but you might want to check out the bit math tutorial in the playground (http://www.arduino.cc/playground/Code/BitMath)  it provides a little more background if you need it.

gschoppe

#3
May 22, 2007, 06:01 pmLast Edit: May 22, 2007, 06:01 pm by gschoppe Reason: 1
Thanks a Million Jims, I would never have figured that out on my own.

I did read the bit math tutorial, and it seemed to only skim the surface.  Case in point, it didn't touch on input or other registers at all.

BTW, is there a more complete reference to the relationship between pins, functions, and register names... I figured out that they were all pd#, which I assume means "pin-digital", but how do I derive register names from the abbreviated pinmapping?  Or, better yet it there a list of important registers, and their functions?

thanks,

greg

gschoppe

#4
May 22, 2007, 06:22 pm
secondary question, write related...

would the following two commands be faster than digitalWrite(pin11, HIGH) and digitalWrite(pin11, LOW) ?
also, would it work at all?

Code: [Select]
`PORTD = (B00001000 | PORTD);   // turns on  Pin 11; Leaves all others as-is;PORTD = (B11110111 & PORTD);   // turns off Pin 11; Leaves all others as-is;`

wandrson

#5
May 22, 2007, 06:25 pm
The best reference is the datasheets for either the mega8 or mega168 whichever flavor your using.  Those can be a bear to read through but they are the best source for how the chips work and what things are called.

Another helpful source is the header files used by gcc.  If you are using a mega8 I suggest keeping a printout of iom8.h, if using mega168 than it would be iomx8.h  These files define the ports, pins, and most other names that are useful.

They can be located in arduino-0007\tools\avr\avr\include

Hope this helps.

Walt

wandrson

#6
May 22, 2007, 08:15 pm
The direct reading and writing of pins/ports is much faster than using the digitalRead/Write functions.  I was testing some ISR code yesterday and was using a digitalWrite function within it and tested it to be taking a 9uS for the digital write.  This is roughly equivalent to 144 avr instructions.  The direct read may only be one instruction (1/16,000,000) but could be as many as five or six depending upon what the compiler outputs.

wandrson

#7
May 22, 2007, 08:25 pmLast Edit: May 22, 2007, 08:26 pm by wandrson Reason: 1
In your code below above with the change for digital pin 11  there are a couple of problems.  First d11 is on PORTB not PORTD.  If you look at the pin reference diagram it will show which arduino pins map to which ports.

Also there is a more generic way to write c/c++ code for setting/resetting individual pins.  Here is an example for arduino d11 which is the same as pin PB3

PORTB &= ~(1<<3);  // Turns on (high) arduino pin d11
PORTB |= (1<<3);     // Turns of (low) arduino pin d11

The advantage to the above syntax is that it doesn't alter any of the other pins on the port and the 3 can easily be replaced with another pin number or even a variable.

jims

#8
May 22, 2007, 08:49 pm
wandrson is correct about the speed of the digitalRead and digitalWrite functions.
In 0008 they will be much faster, though still around.. 4uS I think.

Also in 0008 is an API to get the IO registers and bitmask for a given pin number so you can easily do the fast access if you need to without worrying about ports and bit shifting.

It is all a tradeoff. I could have written the digitalRead and write functions to take about 1uS, but then the code size would go up. I figured if you needed better than 4uS you were probably going to be counting instruction cycles anyway and you could take care of yourself.

gschoppe

#9
May 22, 2007, 08:59 pm
wanderson, i'm confused...

the bit math tutorial says,

Quote

// Write simultaneously to pins 8..13...
PORTD = B00111000;   // turns on 13,12,11; turns off 10,9,8

which is correct, PORTB or PORTD?

#10

Go Up