Hello there, I've been working on some bare metal Arduino Uno Rev3 programming. I have a lot of experience with embedded systems programming in general as well with electrical stuff, but for some reason I can't get this one part to work(I've gotten previous bare metal Arduino stuff working). I'm trying to make the LED change when the button is pressed, but I don't think it's detecting the button correctly. Did I make a stupid mistake?
Current code(Leftover Port C stuff from debugging)
//Button: PD4
//LED: PD2
//IO 0x20-0x5F
//datad: offset 0xB
//datac: offset 0x8
//ddrd: offset 0xA
//ddrc: offset 0x7
#define PORTD_DATA (*((volatile unsigned long *)0x2B))
#define PORTD_DDR (*((volatile unsigned long *)0x2A))
//#define PORTC_DATA (*((volatile unsigned long *)0x28))
//#define PORTC_DDR (*((volatile unsigned long *)0x27))
int main() {
/* Initialization */
//Set direction of pins 1=out 0=in
PORTD_DDR |= (1<<2);
PORTD_DDR &= ~(1<<4);
//Set LED to initially be off
PORTD_DATA &= ~(1<<2);
/* Main Program Loop */
while(1<2) {
//Get button value
unsigned long button = (PORTD_DATA&(1<<4))>>2;
//Set LED to button value
PORTD_DATA |= button;
/*if (button>>2==0) {
PORTD_DATA |= (1<<2);
}
else {
PORTD_DATA &= ~(1<<2);
}*/
}
}
My current wiring(too lazy to make a diagram):
Pretty certain it has to do with the code for the input.
When reading a port, you need to read from the PINx register, rather than the PORTx register.
Edit: this is an architecture-dependent thing, BTW. Several microprocessor families do not have a separate "PORTx" register, but just one address that accesses the value on the pins right now. 8bit PICs and 8051s, I think.
#define PORTD_DATA (*((volatile unsigned long *)0x2B))
#define PORTD_DDR (*((volatile unsigned long *)0x2A))
Even when programming "bare metal", it is considered better practice to #include <avr/io.h> to get the "standard" (and hopefully "known correct") port definitions.
I am just used to writing "volatile unsigned long", I should probably change it. Not sure about the addresses though, but that's what was specified in the datasheet and what I got to work on a different project.
You can read the register at PORTD, but all you get is what you put there when you wrote to it, as @westfw pointed out and I have been reminded.
PIND is the input port and this is where the DDRD comes in.
You may be accustomed to simpler ports. I believe I used one that only had one register. Write to it, and strong 0s and weak 1s could be seen at the pins.
The weak 1s were usable as inputs, as they could be pulled high and would read back as 1.
No PINX register, no DDRX register. For an 8 bit input port, write 0xff then listen to see who says different.
The weak output nature of the 1s never seemed to be the problem you might think. It is nice to have a fuller-fledged ports, but then of course you gotta remember the three registers.
The LED, having no resistor, will screw up the value you read from the port that it is on. This is because it will just present to the port the turn on voltage of the LED which is about 1.5V for a red one. And this is below the threshold for a logic one.
It will also damage that port pin because it will be drawing in excess of the 40mA threshold where damage starts to occur. Sure it might still work but it is on the path to an early death.