so I wnat to toggle a pin in a ISR, so I figure I should do it as fast as possible, and it looks like the smartest way of doing that is to set the PINxn register. now I have been trying to make my code easy to modify by using #define for any direct pin/port access as this code is run on both a mega and a mini, so just changing the contents of a #define is much easier to catch all instances, but I dont like using #defines ass they are so damn powerful. is there a way to use the arduino library to translate from a digital pin number to a port number? I know all the info exists in the corel i braries, i just don't know if I can use some magical function call that the compiler will then optomize down to just a SBI or CBI command.
permnoob:
so I wnat to toggle a pin in a ISR, so I figure I should do it as fast as possible, and it looks like the smartest way of doing that is to set the PINxn register. now I have been trying to make my code easy to modify by using #define for any direct pin/port access as this code is run on both a mega and a mini, so just changing the contents of a #define is much easier to catch all instances, but I dont like using #defines ass they are so damn powerful. is there a way to use the arduino library to translate from a digital pin number to a port number? I know all the info exists in the corel i braries, i just don't know if I can use some magical function call that the compiler will then optomize down to just a SBI or CBI command.
Good question. The answer to me would be sure, as the existing functions like digitalRead() digitalWrite analogRead(); have to be able to resolve the abstraction from arduino pin numbers to physical port/pin. Ironically however the extra steps and functions required would work against the reason to use direct port manipulation in the first place, improved I/O speed.
Anyway I'm a hardware guy but would like to see a nice clean example of what you are trying to use. Anything that can help speed up an ISR is a worth effort. I will admit that a lot of #define statements make my eyes glaze over even though I know they are critical to the sketch code.
Why not do your set/clear bit inline? See: Inline Assembler Cookbook
I will admit that a lot of #define statements make my eyes glaze over even though I know they are critical to the sketch code.
I'm a hardware guy also, and have never found #define to be critical to anything.
Their biggest 'attraction' seems to be that variables are not allowed to be changed by the code. I only tried using them once, and then had to undo them because my properly doublenested array reference (basically a pointer in an array which pointed to a font in another array) could not be compiled when #define was used, but const worked.
So now I don't use either and just use byte, int, and unsighed long, and occasionally byte and float. It's not hard to write code that doesn't corrupt itself.
There's the other point that either #define or const will put the definition in flash vs keeping it in RAM. I've never run into the problem of running out of RAM (altho I have gone past the bounds of an array due to accidental coding errors).
If you are prepared to use, for example, the pin that maps to PortB3 on both the Mega and Mini the same code should run on both with no changes. This certainly worked for me with an Uno and an Attiny.
...R
so to clarify my reasoning, here it is,
#define is dangerous because if you have #DEFINE pinA 13, then if you have a variable called pinAstate, at compile time that variable become 13state, and will fail to compile. seemseasy enough to avoid, but one mistake could go unnoticed for a long time and be quite hard to track donw in alarge program, so I am using consts, to give the complier a hint of "hey man, you can probably optomize this somehow" as that is my understanding of what it does, along with throw up an error if Itry to change its value, which is nifty as it basically forces me to adhere to my own design intent and not kludge (too much).
as for why use direct port maniuplation for speed and then slow it down by creating my own tools like this, well theoretically if I can have a compiler level modification (like #define, but preferably safer) that will be translated into a SBI or whatever magically by the complier adn be just as blazing fast on the arduino itself.
now I can't just say "I'll stick to portb3 on all arduinos" because on some that may be digital pin 13,on athoer it could be digital pin 2. if/when I find an elegant solution I will post it here, currently I am using ifdefs which are meh. it works but very quickly 10 lines of code is 40 and it gets less readable, everythign is a trade off you know.
permnoob:
#define is dangerous because if you have #DEFINE pinA 13, then if you have a variable called pinAstate, at compile time that variable become 13state,
To the best of my knowledge the compiler will treat pinA as completely different from pinAstate and won't mix them up.
I'm not a C expert but don't see any difference between
#define pinA 13
and
byte pinA = 13;
except that the #define doesn't use any storage space and, of course, if you use #define you can't later use
pinA = someothervalue;
Using conditional #defines that take account of whichever device the program is intended for is a simple way to generate different code for different devices.
You haven't said why you can't use (for example) pin 13 on one device and pin 2 on another. It can be a very simple solution.
...R
Robin2:
You haven't said why you can't use (for example) pin 13 on one device and pin 2 on another. It can be a very simple solution....R
Becasue I am lazy and dumb. I want to be able to wire up any and all devices the same (physically) and flash identical firmware to it and have it "just work" rather than have to keep good notes and remember which model I am playing with etc. As for your comment on how #define will substitute, I tHINK I am right, but I am looking in a book right now t osee for sure which one of us wins a prize on this one.
Rather than look for a book try some code. This for example ...
#define pinA 13
int testNum;
void setup() {
Serial.begin(9600);
Serial.println("Starting TestDefine.ino");
int pinAxxx = 5;
testNum = pinA;
Serial.println(testNum);
Serial.println(pinA);
Serial.println(pinAxxx);
}
void loop () {
}
...R
~/dev/c $ cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#define pinA 13
int main () {
uint8_t pinAtest = 1;
printf("The value of pinA is %d, and pinAtest is %u.\n", pinA, pinAtest);
return 0;
}
~/dev/c $ gcc -o test test.c
~/dev/c $ ./test
The value of pinA is 13, and pinAtest is 1.
Don't be scared of #define. The C pre-processor is pretty well designed. Using a const is OK, but in my personal opinion, a little sloppy. Why use a variable as a placeholder when it won't vary? Just use the #define. Using int or byte without defining it as read-only is even worse.... you're leaving the door wide open for its value to change by an accidental "if (x = y)" statement somewhere.
But hey, if you have a system that works for you, so be it.
Also, check pins_arduino.h for all the pin abstraction stuff. It has sections like these, which you will find interesting for your purposes:
const uint16_t PROGMEM port_to_mode_PGM[] = {
NOT_A_PORT,
NOT_A_PORT,
(uint16_t) &DDRB,
(uint16_t) &DDRC,
(uint16_t) &DDRD,
};
const uint16_t PROGMEM port_to_output_PGM[] = {
NOT_A_PORT,
NOT_A_PORT,
(uint16_t) &PORTB,
(uint16_t) &PORTC,
(uint16_t) &PORTD,
};
const uint16_t PROGMEM port_to_input_PGM[] = {
NOT_A_PORT,
NOT_A_PORT,
(uint16_t) &PINB,
(uint16_t) &PINC,
(uint16_t) &PIND,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
PD, /* 0 */
PD,
PD,
PD,
PD,
PD,
PD,
PD,
PB, /* 8 */
PB,
PB,
PB,
PB,
PB,
PC, /* 14 */
PC,
PC,
PC,
PC,
PC,
};