Hi, The code below makes the led on pin 13 (arduino uno) turn on and off via registers.
#define CLR(x,y) (x&=(~(1<<y))) // set HIGH
#define SET(x,y) (x|=(1<<y)) // SEL LOW
void setup() {
DDRB = B00100000; // set as output
}
void loop() {
SET(PORTB,5); // pin 13 HIGH
delay(1000);
CLR(PORTB,5); // pin 13 LOW
delay(1000);
}
DDR is actually the name of an register. When I look that up in the datasheet, I find adress '0x24'
see datasheet p624 ( http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf )
If I then change the registry name to the registry address, the code no longer works. (see code below)
#define CLR(x,y) (x&=(~(1<<y))) // set HIGH
#define SET(x,y) (x|=(1<<y)) // SEL LOW
byte DDRB_test = (*(volatile uint8_t *)(0x24));
void setup() {
DDRB_test = B00100000; // set as output
}
void loop() {
SET(PORTB,5); // pin 13 HIGH
delay(1000);
CLR(PORTB,5); // pin 13 LOW
delay(1000);
}
How is this possible? Or am I forgetting something?
You're forgetting to look at the definition of DDRB for your processor. (Hint: it's in your installation)
Thank you for your response. Where can I find that?
Something like hardware/tools/avr/avr/include/avr
The DDRB address is correct.
Or rather, both codes work at least on my Nano.
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.
Very weird.... It won't work here
Please paste the compiled assembly list here.
It becomes clear what is happening.
Sketch uses 678 bytes (2%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
C:\Users\LocalUser\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude -CC:\Users\LocalUser\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf -v -patmega328p -carduino -PCOM14 -b115200 -D -Uflash:w:C:\Users\LOCALU~1\AppData\Local\Temp\arduino_build_417879/portenta_registers_led.ino.hex:i
avrdude: Version 6.3-20190619
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2014 Joerg Wunsch
System wide configuration file is "C:\Users\LocalUser\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf"
Using Port : COM14
Using Programmer : arduino
Overriding Baud Rate : 115200
AVR Part : ATmega328P
Chip Erase delay : 9000 us
PAGEL : PD7
BS2 : PC2
RESET disposition : dedicated
RETRY pulse : SCK
serial program mode : yes
parallel program mode : yes
Timeout : 200
StabDelay : 100
CmdexeDelay : 25
SyncLoops : 32
ByteDelay : 0
PollIndex : 3
PollValue : 0x53
Memory Detail :
Block Poll Page Polled
Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack
----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff
flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff
lfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
hfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
efuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
lock 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00
signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00
Programmer Type : Arduino
Description : Arduino
Hardware Version: 3
Firmware Version: 4.4
Vtarget : 0.3 V
Varef : 0.3 V
Oscillator : 28.800 kHz
SCK period : 3.3 us
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: reading input file "C:\Users\LOCALU~1\AppData\Local\Temp\arduino_build_417879/portenta_registers_led.ino.hex"
avrdude: writing flash (678 bytes):
Writing | ################################################## | 100% 0.12s
avrdude: 678 bytes of flash written
avrdude: verifying flash memory against C:\Users\LOCALU~1\AppData\Local\Temp\arduino_build_417879/portenta_registers_led.ino.hex:
avrdude: load data flash data from input file C:\Users\LOCALU~1\AppData\Local\Temp\arduino_build_417879/portenta_registers_led.ino.hex:
avrdude: input file C:\Users\LOCALU~1\AppData\Local\Temp\arduino_build_417879/portenta_registers_led.ino.hex contains 678 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 0.09s
avrdude: verifying ...
avrdude: 678 bytes of flash verified
avrdude done. Thank you.
The code uploads without error, but the LED does not blink.
It's an IDE message.
Look at the assembly list of the compiled your program.
laura2000:
Where can I find that?
For the AVR processors:
hardware/tools/avr/avr/include/avr
The files are 'ioXXX.h' where 'XX' is the processor ID. for the UNO and Nano the ID is m328p so look in iom328p.h.
In there you will find:
#define PORTB _SFR_IO8(0x05)
io.h contains:
#include <avr/sfr_defs.h>
which contains definitions for _SFR_IO8
Look like the main difference between a register address and a RAM address is an offset of 0 or 0x20 depending on version... ?
This address offset is the difference between using IN / OUT or LD / ST.
You can use both, not the difference version.
EDIT:
Look at datasheet. Page:624, Note:4
Sorry, But i didn't find that...
@laura2000
I'm so sorry, the above my post was wrong.
I think it couldn't have worked if I deep thought about it.
The address of the register can't be put in a variable.
The compiler try optimize it into a RAM address.
The reason why it worked with my case is that it used the internal LED, so the on-board comparator detected the PULLUPed voltage of the input pin and made the board LED shine brightly.
All PORTB remains input.
I think there is no choice but to use the #defined name or direct write the address as it is.
#define CLR(x,y) (x&=(~(1<<y))) // set HIGH
#define SET(x,y) (x|=(1<<y)) // SEL LOW
#define DDRB_test (*(volatile uint8_t *)(0x24))
void setup() {
DDRB_test = B00100000; // set as output
}
void loop() {
SET(PORTB,5); // pin 13 HIGH
delay(1000);
CLR(PORTB,5); // pin 13 LOW
delay(1000);
}
Well... it's the same as original DDRB...
1 Like
Here ya go:
#define CLR(x,y) (x&=(~(1<<y))) // set HIGH
#define SET(x,y) (x|=(1<<y)) // SEL LOW
volatile uint8_t *DDRB_test = &DDRB;
void setup() {
*DDRB_test = B00100000; // set as output
}
void loop() {
SET(PORTB,5); // pin 13 HIGH
delay(1000);
CLR(PORTB,5); // pin 13 LOW
delay(1000);
}
3 Likes
@gfvalvo
gfvalvo:
Here ya go
Good point! +1
Oh yeah, I forgot to add * when assign when trying various things...
Probably it's the solution to OP @laura2000
1 Like
Thank you for your help. The code below works
#define CLR(x,y) (x&=(~(1<<y))) // set HIGH
#define SET(x,y) (x|=(1<<y)) // SEL LOW
volatile uint8_t *DDRB_test = (0x24);
void setup() {
*DDRB_test = B00100000; // set as output
}
void loop() {
SET(PORTB,5); // pin 13 HIGH
delay(1000);
CLR(PORTB,5); // pin 13 LOW
delay(1000);
}
Koepel
July 16, 2021, 6:19am
18
Why ?
Optimizing for speed in the setup() function is almost never needed. The slower pinMode() can be used in setup().
The Arduino bitSet() and bitClear() can be used. They work on a variable but also on the registers. They turn into the direct and fast assembly instruction.
void loop() {
bitSet(PORTB,5); // pin 13 HIGH
delay(1000);
bitSet(PORTB,5); // pin 13 LOW
delay(1000);
}
The ATmega328P has an extra. When a pin is OUTPUT, then writing to the PINB registers toggles those output pins. Since only one output should be toggled, the rest of the bits must be written with zero. The Arduino bit() can be used for that or just write 0b00100000 to PINB.
void setup()
{
pinMode( 13, OUTPUT);
}
void loop()
{
PINB = bit( 5); // toggle pin 13 (it is a output)
delay(1000);
}
I know that, but I won't stick to just controlling LEDs either.
westfw
July 20, 2021, 9:02pm
20
Presumably with C++. you could also use "references":
volatile uint8_t & DDRB_test = (*(volatile uint8_t *)(0x24));
void setup() {
DDRB_test = 0b00100000; // set as output
}
1 Like