Assembly language question

Hello dude,
I came across the assembly language to toggle "led (D13)".

//First assembly code to toggle led
void setup(){}

void loop()
{ 
  //Toggle PORTB.5 (D13 LED)
  __asm__("sbi  0x4, 0x5");  //DDRB
  __asm__("cbi  0x5, 0x5");  //PORTB
  delay(1000);
  __asm__("sbi  0x5, 0x5"); 
  delay(1000);      
}
//Second assembly code to toggle led
void setup(){}

void loop()
{
  //Toggle PORTB.5 (D13 LED)
  __asm__("cbi  0x4, 0x5");   //DDRB
  delay(500);
  __asm__("sbi  0x4, 0x5");  //DDRB
  delay(500);      
  
}

The first one is easy to understand, but the second one is no idea how is work, because it does not use PORTB to toggle? Can anyone explain about it?

Regards,
pak

The second switches the direction of the pin betwen output and input. This also works, though it is probably not the way it should be done.
For example, if you write log. 1 to the PORTB, pin 5 and then set the pin to output mode, the LED will go on. If you set the pin to input mode, the LED will go off.
Only I don't see in the code that there would be log. 1 in the PORTB. I guess there will be log. 0 (default after reset), so it would turn the LED on/off only if it was connected between 5V and the pin, not the pin and GND as it is in Arduino. But maybe I'm missing something.

Thank for reply,
There is no PORTB statement (assume PORTB=0x00 after reset) in the second assembly code that's why I confused .
This is asm code of the second one which is generated by Arduino IDE v1.0.4 as follow, but it does toggle led at D13 indeed.

000000a6 <setup>:
  a6:	08 95       	ret

000000a8 <loop>:
  a8:	25 98       	cbi	0x04, 5	; 4
  aa:	64 ef       	ldi	r22, 0xF4	; 244
  ac:	71 e0       	ldi	r23, 0x01	; 1
  ae:	80 e0       	ldi	r24, 0x00	; 0
  b0:	90 e0       	ldi	r25, 0x00	; 0
  b2:	0e 94 ab 00 	call	0x156	; 0x156 <delay>
  b6:	25 9a       	sbi	0x04, 5	; 4
  b8:	64 ef       	ldi	r22, 0xF4	; 244
  ba:	71 e0       	ldi	r23, 0x01	; 1
  bc:	80 e0       	ldi	r24, 0x00	; 0
  be:	90 e0       	ldi	r25, 0x00	; 0
  c0:	0e 94 ab 00 	call	0x156	; 0x156 <delay>
  c4:	08 95       	ret

And there is some info about true Read-Modify-Write functionality (ref page 77 of datasheet) and this is what I think about happening in second asm code.

Table 13-1. Port Pin Configurations
DDxn PORTxn PUD(in MCUCR) I/O Pull-up Comment
0 0 X Input No Tri-state (Hi-Z)
0 1 0 Input Yes Pxn will source current if ext. pulled low.
0 1 1 Input No Tri-state (Hi-Z)
1 0 X Output No Output Low (Sink)
1 1 X Output No Output High (Source)

I use official Arduino UNO R3 board and IDE v1.0.4. There is an op-amp rail-to-rail output which triggers to D13 during RMW operation.

Problem solved!, thanks
Regards,
pak

Assember code and delay() seem to be strange bedfellows.

And I suspect PINx would generate code that is as good as the Assembler code.

...R

Robin2:
Assembler code and delay() seem to be strange bedfellows.

It stops you needing to write several million NOPs. :smiley:

With the arduino IDE assembler and C can be mixed. However, this does not give the optimization that someone is usually looking for by using assembler. For example: the "blink sketch" below, written in C will normally compile to a program that is 492 bytes long.
But, if the .o file created during this process by the IDE is converted to Assembler, tweeked a little bit, and loaded into the Arduino with avrdude. The resulting program will only be 30 bytes long, 1/16 the size ! The Arduino IDE adds a lot of overhead when compiling a sketch. With this method, the C compiler is writing the assembly language. All programs are converted to assembler ( machine code) before they are uploaded into the Arduino.

Here is an example of the sketch:
First the C sketch optimized for assembler. It is not calling any C library functions, and is programming registers directly, as someone writing in assembler would do, but it is all in Arduino C, no assembler is used.

// A blink sketch for Arduino Uno , running @ 16MHZ
// 1 second blink on Arduino pin 9 using timer1 for delay
// LED is connected to pin 9 (not pin 13). Square wave output.

void setup()
{
DDRB |= 0x02; // (0x04) Set pin PB1 (1 << DDB1) as output (pinMode(9, OUTPUT)
TCCR1A = 0x40; // (0x80) (1 << COM1A0) set Timer1 output on pin 9 to toggle mode
TCCR1B = 0x0d; // (0x81) (1 << WGM12) set TCT mode; (1 << CS10) | (1 << CS12) set prescaller to 1024
OCR1A = 7812; // (0x89) Compare value 7812 gives 1 hz - (toggle mode divides output by 2)
}

void loop()
{
}

Second: An avr-objdump of the .o object file created by the the Arduino IDE when it compiled the above sketch:

Timer1_blink.cpp.o: file format elf32-avr

Disassembly of section .text.setup:

00000000 :
0: 81 e0 ldi r24, 0x01 ; 1
2: 83 bf out 0x33, r24 ; 51
4: 21 9a sbi 0x04, 1 ; 4
6: 80 e4 ldi r24, 0x40 ; 64
8: 80 93 80 00 sts 0x0080, r24
c: 8d e0 ldi r24, 0x0D ; 13
e: 80 93 81 00 sts 0x0081, r24
12: 84 e8 ldi r24, 0x84 ; 132
14: 9e e1 ldi r25, 0x1E ; 30
16: 90 93 89 00 sts 0x0089, r25
1a: 80 93 88 00 sts 0x0088, r24
1e: 08 95 ret

Disassembly of section .text.loop:

00000000 :
0: 08 95 ret

This file has all the assembly language needed for the sketch, but needs to be tweaked before it can be assembled into a .hex file.
Here is the edited file. The ret instruction at the end of setup is removed. The ret instruction for loop has been changed to a "relative jump to the label "loop:" . Everything that is not an assembler instruction is edited or commented out.

;Timer1_blink.cpp.o: file format elf32-avr
;Disassembly of section .text.setup:
;00000000 :

ldi r24, 0x01
out 0x33, r24
sbi 0x04, 1
ldi r24, 0x40
sts 0x0080, r24
ldi r24, 0x0D
sts 0x0081, r24
ldi r24, 0x84
ldi r25, 0x1E
sts 0x0089, r25

;Disassembly of section .text.loop:

;00000000 :
loop:
rjmp loop

This file is assembled to a .hex file and uploaded with avrdude into the Arduino. (the Arduino IDE also uses avrdude to upload sketches)

pak:
Hello dude,
The first one is easy to understand, but the second one is no idea how is work, because it does not use PORTB to toggle? Can anyone explain about it?

We are more than one dude!

The second sketch does not work, since by default the pins are all
set LOW, and the built-in LED is wired from pin 13 to GND.

If you set the pin high in setup(), or had an LED wired from it to Vcc,
then it would work. Its called "open collector" or "open drain" drive

(deleted)