Bare-metal Arduino Coding Help

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.


Also, I know what I'm doing with bare-metal and I am aware that using the IDE or such might be more efficient, no need to tell me again.

Is the switch pulled up?

Write a one to the register at the bit where the switch is.

Oh yeah, how is your switch wired?

a7

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.

Yeah, fixed that for ya.

a7

1 Like

Is there a setup function? Is there a current limit resistor for the LED?

Aren't ATmega328P registers generally 8-bits wide?

If 0x2A is the address of four bytes (unsigned long) then how can 0x2B be the address of a different set of four bytes?

Missed that! Another good reason to use the official definitions!

I can send more pictures or try and make a diagram

Not sure where exactly I got the LED, but I was able to use the LED before, just not with a button

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.

Worst case scenario I could just copy a header file or two

Not sure why I write it like that but oh well

I think this is my problem. I saw a input pin port but didn't really consider it for anything as in the past I just read and wrote to the data port.

I got a lot of cleaning up todo

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.

a7

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.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.