Odd code behaviour, just FYA

Please enjoy a war story and have a laugh on me.

The error in the code below kept me busier for longer than I will ever say.

I have solved the problem. Many of you will solve it just by reading it, others will find the compiler warning useful.

TBC I have the compiler warnings cranked up to the max. For some reason, I got no warning from the full code. Only late in the game of boiling this down for your consideration did the compiler start warning me. Of how I had gone wrong all by myself.

This code in the simulator does the same thing on an UNO I have. So once again, the simulator is not a, or the, problem.


Wokwi_badge odd code problem


The code:

/// https://wokwi.com/projects/371826133999362049
// https://forum.arduino.cc/t/odd-code-behaviour-just-fya/1153935

# define anLED  7

void setup() {
  Serial.begin(115200);
  Serial.println(" close to minimum \n");

  pinMode(anLED, OUTPUT);
  digitalWrite(anLED, LOW);

  bool flag;

  int xx = analogRead(A0);

  Serial.print("reading "); Serial.println(xx);
  Serial.print("flag before          "); Serial.println(flag);

  if (xx > 100) {
    Serial.println("       WTF");  // Serial.flush(); for (; ;);
    flag = true;
  }

  Serial.print("flag after           "); Serial.println(flag);
}

void loop() {
}

The output


 close to minimum 

reading 0
flag before          0
flag after           1

shows the flag changing after one if statement whose test is false and therefor does not run the body code.

In the larger sketch, please imagine how baffled I might have been, and how much instrumentation was in there when I discovered what was happening.

I think everything in the sketch is necessary to invoke this behaviour.

I wonder aloud if the optimiser played a roll. I further wonder what the assembly code might reveal. I may try to learn enough to take a look. Above my paygrade by an order of magnitude, binary at least.

a7

2 Likes

No initial value given.

Thanks for posting that!

Even given the warning, I don't understand the result either.

Reading an uninitialised value invokes undefined behaviour, so I guess that initialising flag (to false) solved the issue?

That is the fun part of UB, anything can happen.

This is a nice example for our next discussion on why UB is something to worry about. Also, have a look at this gem.

undefined value = undefined behavior

I believe an unitialized global variable flag would behave differently.

2 Likes

It is my understanding the global variables are always initialized to some default, if not explicitly written into the code.

But yes, in a test on the Arduino Uno using IDE 1.8.19, an "uninitialized" global flag does not exhibit the problem.

flag was not given an initial value. Would of worked ok as long as xx started off > 100 and we wouldn't know of this problem.

Did you also include -pedantic? It can be a real life saver.

The following sketch exhibits the same behaviour in your simulated project.

void setup() {
  Serial.begin(9600);

  bool flag;
  Serial.println(flag);  // Prints "0".
  if (random(1)) {       // Always zero.
    flag = true;
  }
  Serial.println(flag);  // Prints "1".
}

void loop() {}

I remember some time ago now getting involved with a similar user problem.
He was loading a struct, which contained a bool, from an EEPROM. With a new EEPROM, which was "0xFF" filled, he was having extreme difficulties with the behaviour of this bool variable. The conclusion we came to is that if you write to a simple bool, you set only its bit 0. However, if you read a bool you get back the whole containing byte including also bits 1 to 7 which may include any rubbish which got into it previously. Hence you could set such a bool false but on subsequent reading it was true. But also it is impossible to clean out. This was simply another consequence of bad initialisation.

It would be very interesting to see the assembly code generated by the program in the OP, to understand exactly what it is doing. I'm really curious how the value of flag manages to print a different value in the two print statements.

I extracted this from Wokwi as an experiment but have not studied it:


sketch.ino.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 5d 00 	jmp	0xba	; 0xba <__ctors_end>
   4:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
   8:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
   c:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  10:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  14:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  18:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  1c:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  20:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  24:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  28:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  2c:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  30:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  34:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  38:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  3c:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  40:	0c 94 26 02 	jmp	0x44c	; 0x44c <__vector_16>
  44:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  48:	0c 94 96 02 	jmp	0x52c	; 0x52c <__vector_18>
  4c:	0c 94 70 02 	jmp	0x4e0	; 0x4e0 <__vector_19>
  50:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  54:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  58:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  5c:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  60:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>
  64:	0c 94 85 00 	jmp	0x10a	; 0x10a <__bad_interrupt>

00000068 <__trampolines_end>:
  68:	00 00       	nop
  6a:	00 00       	nop
  6c:	24 00       	.word	0x0024	; ????
  6e:	27 00       	.word	0x0027	; ????
  70:	2a 00       	.word	0x002a	; ????

00000072 <port_to_output_PGM>:
  72:	00 00 00 00 25 00 28 00 2b 00                       ....%.(.+.

0000007c <digital_pin_to_port_PGM>:
  7c:	04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03     ................
  8c:	03 03 03 03                                         ....

00000090 <digital_pin_to_bit_mask_PGM>:
  90:	01 02 04 08 10 20 40 80 01 02 04 08 10 20 01 02     ..... @...... ..
  a0:	04 08 10 20                                         ... 

000000a4 <digital_pin_to_timer_PGM>:
  a4:	00 00 00 08 00 02 01 00 00 03 04 07 00 00 00 00     ................
  b4:	00 00 00 00                                         ....

000000b8 <__ctors_start>:
  b8:	e9 03       	fmulsu	r22, r17

000000ba <__ctors_end>:
  ba:	11 24       	eor	r1, r1
  bc:	1f be       	out	0x3f, r1	; 63
  be:	cf ef       	ldi	r28, 0xFF	; 255
  c0:	d8 e0       	ldi	r29, 0x08	; 8
  c2:	de bf       	out	0x3e, r29	; 62
  c4:	cd bf       	out	0x3d, r28	; 61

000000c6 <__do_copy_data>:
  c6:	11 e0       	ldi	r17, 0x01	; 1
  c8:	a0 e0       	ldi	r26, 0x00	; 0
  ca:	b1 e0       	ldi	r27, 0x01	; 1
  cc:	e0 e8       	ldi	r30, 0x80	; 128
  ce:	f8 e0       	ldi	r31, 0x08	; 8
  d0:	02 c0       	rjmp	.+4      	; 0xd6 <__do_copy_data+0x10>
  d2:	05 90       	lpm	r0, Z+
  d4:	0d 92       	st	X+, r0
  d6:	aa 36       	cpi	r26, 0x6A	; 106
  d8:	b1 07       	cpc	r27, r17
  da:	d9 f7       	brne	.-10     	; 0xd2 <__do_copy_data+0xc>

000000dc <__do_clear_bss>:
  dc:	22 e0       	ldi	r18, 0x02	; 2
  de:	aa e6       	ldi	r26, 0x6A	; 106
  e0:	b1 e0       	ldi	r27, 0x01	; 1
  e2:	01 c0       	rjmp	.+2      	; 0xe6 <.do_clear_bss_start>

000000e4 <.do_clear_bss_loop>:
  e4:	1d 92       	st	X+, r1

000000e6 <.do_clear_bss_start>:
  e6:	a0 31       	cpi	r26, 0x10	; 16
  e8:	b2 07       	cpc	r27, r18
  ea:	e1 f7       	brne	.-8      	; 0xe4 <.do_clear_bss_loop>

000000ec <__do_global_ctors>:
  ec:	10 e0       	ldi	r17, 0x00	; 0
  ee:	cd e5       	ldi	r28, 0x5D	; 93
  f0:	d0 e0       	ldi	r29, 0x00	; 0
  f2:	04 c0       	rjmp	.+8      	; 0xfc <__do_global_ctors+0x10>
  f4:	21 97       	sbiw	r28, 0x01	; 1
  f6:	fe 01       	movw	r30, r28
  f8:	0e 94 38 04 	call	0x870	; 0x870 <__tablejump2__>
  fc:	cc 35       	cpi	r28, 0x5C	; 92
  fe:	d1 07       	cpc	r29, r17
 100:	c9 f7       	brne	.-14     	; 0xf4 <__do_global_ctors+0x8>
 102:	0e 94 c8 02 	call	0x590	; 0x590 <main>
 106:	0c 94 3e 04 	jmp	0x87c	; 0x87c <_exit>

0000010a <__bad_interrupt>:
 10a:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>

0000010e <_ZN5Print5writeEPKhj>:

// Public Methods //////////////////////////////////////////////////////////////

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
 10e:	af 92       	push	r10
 110:	bf 92       	push	r11
 112:	cf 92       	push	r12
 114:	df 92       	push	r13
 116:	ef 92       	push	r14
 118:	ff 92       	push	r15
 11a:	0f 93       	push	r16
 11c:	1f 93       	push	r17
 11e:	cf 93       	push	r28
 120:	df 93       	push	r29
 122:	6c 01       	movw	r12, r24
 124:	7b 01       	movw	r14, r22
 126:	8b 01       	movw	r16, r22
 128:	04 0f       	add	r16, r20
 12a:	15 1f       	adc	r17, r21
 12c:	eb 01       	movw	r28, r22
 12e:	5e 01       	movw	r10, r28
 130:	ae 18       	sub	r10, r14
 132:	bf 08       	sbc	r11, r15
  size_t n = 0;
  while (size--) {
 134:	c0 17       	cp	r28, r16
 136:	d1 07       	cpc	r29, r17
 138:	59 f0       	breq	.+22     	; 0x150 <_ZN5Print5writeEPKhj+0x42>
    if (write(*buffer++)) n++;
 13a:	69 91       	ld	r22, Y+
 13c:	d6 01       	movw	r26, r12
 13e:	ed 91       	ld	r30, X+
 140:	fc 91       	ld	r31, X
 142:	01 90       	ld	r0, Z+
 144:	f0 81       	ld	r31, Z
 146:	e0 2d       	mov	r30, r0
 148:	c6 01       	movw	r24, r12
 14a:	09 95       	icall
 14c:	89 2b       	or	r24, r25
 14e:	79 f7       	brne	.-34     	; 0x12e <_ZN5Print5writeEPKhj+0x20>
    else break;
  }
  return n;
}
 150:	c5 01       	movw	r24, r10
 152:	df 91       	pop	r29
 154:	cf 91       	pop	r28
 156:	1f 91       	pop	r17
 158:	0f 91       	pop	r16
 15a:	ff 90       	pop	r15
 15c:	ef 90       	pop	r14
 15e:	df 90       	pop	r13
 160:	cf 90       	pop	r12
 162:	bf 90       	pop	r11
 164:	af 90       	pop	r10
 166:	08 95       	ret

00000168 <_ZN14HardwareSerial17availableForWriteEv>:
{
  tx_buffer_index_t head;
  tx_buffer_index_t tail;

  TX_BUFFER_ATOMIC {
    head = _tx_buffer_head;
 168:	fc 01       	movw	r30, r24
 16a:	53 8d       	ldd	r21, Z+27	; 0x1b
    tail = _tx_buffer_tail;
 16c:	44 8d       	ldd	r20, Z+28	; 0x1c
 16e:	25 2f       	mov	r18, r21
 170:	30 e0       	ldi	r19, 0x00	; 0
 172:	84 2f       	mov	r24, r20
 174:	90 e0       	ldi	r25, 0x00	; 0
  }
  if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail;
 176:	82 1b       	sub	r24, r18
 178:	93 0b       	sbc	r25, r19
 17a:	54 17       	cp	r21, r20
 17c:	10 f0       	brcs	.+4      	; 0x182 <_ZN14HardwareSerial17availableForWriteEv+0x1a>
 17e:	cf 96       	adiw	r24, 0x3f	; 63
 180:	08 95       	ret
  return tail - head - 1;
 182:	01 97       	sbiw	r24, 0x01	; 1
}
 184:	08 95       	ret

00000186 <_ZN14HardwareSerial4readEv>:
    return _rx_buffer[_rx_buffer_tail];
  }
}

int HardwareSerial::read(void)
{
 186:	fc 01       	movw	r30, r24
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer_head == _rx_buffer_tail) {
 188:	91 8d       	ldd	r25, Z+25	; 0x19
 18a:	82 8d       	ldd	r24, Z+26	; 0x1a
 18c:	98 17       	cp	r25, r24
 18e:	61 f0       	breq	.+24     	; 0x1a8 <_ZN14HardwareSerial4readEv+0x22>
    return -1;
  } else {
    unsigned char c = _rx_buffer[_rx_buffer_tail];
 190:	a2 8d       	ldd	r26, Z+26	; 0x1a
 192:	ae 0f       	add	r26, r30
 194:	bf 2f       	mov	r27, r31
 196:	b1 1d       	adc	r27, r1
 198:	5d 96       	adiw	r26, 0x1d	; 29
 19a:	8c 91       	ld	r24, X
    _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
 19c:	92 8d       	ldd	r25, Z+26	; 0x1a
 19e:	9f 5f       	subi	r25, 0xFF	; 255
 1a0:	9f 73       	andi	r25, 0x3F	; 63
 1a2:	92 8f       	std	Z+26, r25	; 0x1a
    return c;
 1a4:	90 e0       	ldi	r25, 0x00	; 0
 1a6:	08 95       	ret

int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
 1a8:	8f ef       	ldi	r24, 0xFF	; 255
 1aa:	9f ef       	ldi	r25, 0xFF	; 255
  } else {
    unsigned char c = _rx_buffer[_rx_buffer_tail];
    _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
    return c;
  }
}
 1ac:	08 95       	ret

000001ae <_ZN14HardwareSerial4peekEv>:
{
  return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
 1ae:	fc 01       	movw	r30, r24
  if (_rx_buffer_head == _rx_buffer_tail) {
 1b0:	91 8d       	ldd	r25, Z+25	; 0x19
 1b2:	82 8d       	ldd	r24, Z+26	; 0x1a
 1b4:	98 17       	cp	r25, r24
 1b6:	31 f0       	breq	.+12     	; 0x1c4 <_ZN14HardwareSerial4peekEv+0x16>
    return -1;
  } else {
    return _rx_buffer[_rx_buffer_tail];
 1b8:	82 8d       	ldd	r24, Z+26	; 0x1a
 1ba:	e8 0f       	add	r30, r24
 1bc:	f1 1d       	adc	r31, r1
 1be:	85 8d       	ldd	r24, Z+29	; 0x1d
 1c0:	90 e0       	ldi	r25, 0x00	; 0
 1c2:	08 95       	ret
}

int HardwareSerial::peek(void)
{
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
 1c4:	8f ef       	ldi	r24, 0xFF	; 255
 1c6:	9f ef       	ldi	r25, 0xFF	; 255
  } else {
    return _rx_buffer[_rx_buffer_tail];
  }
}
 1c8:	08 95       	ret

000001ca <_ZN14HardwareSerial9availableEv>:
  // clear any received data
  _rx_buffer_head = _rx_buffer_tail;
}

int HardwareSerial::available(void)
{
 1ca:	fc 01       	movw	r30, r24
  return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
 1cc:	91 8d       	ldd	r25, Z+25	; 0x19
 1ce:	22 8d       	ldd	r18, Z+26	; 0x1a
 1d0:	89 2f       	mov	r24, r25
 1d2:	90 e0       	ldi	r25, 0x00	; 0
 1d4:	80 5c       	subi	r24, 0xC0	; 192
 1d6:	9f 4f       	sbci	r25, 0xFF	; 255
 1d8:	82 1b       	sub	r24, r18
 1da:	91 09       	sbc	r25, r1
}
 1dc:	8f 73       	andi	r24, 0x3F	; 63
 1de:	99 27       	eor	r25, r25
 1e0:	08 95       	ret

000001e2 <_Z17Serial0_availablev>:
#endif

// Function that can be weakly referenced by serialEventRun to prevent
// pulling in this file if it's not otherwise used.
bool Serial0_available() {
  return Serial.available();
 1e2:	83 e7       	ldi	r24, 0x73	; 115
 1e4:	91 e0       	ldi	r25, 0x01	; 1
 1e6:	0e 94 e5 00 	call	0x1ca	; 0x1ca <_ZN14HardwareSerial9availableEv>
 1ea:	21 e0       	ldi	r18, 0x01	; 1
 1ec:	89 2b       	or	r24, r25
 1ee:	09 f4       	brne	.+2      	; 0x1f2 <_Z17Serial0_availablev+0x10>
 1f0:	20 e0       	ldi	r18, 0x00	; 0
}
 1f2:	82 2f       	mov	r24, r18
 1f4:	08 95       	ret

000001f6 <_Z14serialEventRunv>:
#endif

void serialEventRun(void)
{
#if defined(HAVE_HWSERIAL0)
  if (Serial0_available && serialEvent && Serial0_available()) serialEvent();
 1f6:	80 e0       	ldi	r24, 0x00	; 0
 1f8:	90 e0       	ldi	r25, 0x00	; 0
 1fa:	89 2b       	or	r24, r25
 1fc:	29 f0       	breq	.+10     	; 0x208 <_Z14serialEventRunv+0x12>
 1fe:	0e 94 f1 00 	call	0x1e2	; 0x1e2 <_Z17Serial0_availablev>
 202:	81 11       	cpse	r24, r1
 204:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>
  if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2();
#endif
#if defined(HAVE_HWSERIAL3)
  if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3();
#endif
}
 208:	08 95       	ret

0000020a <_ZN14HardwareSerial17_tx_udr_empty_irqEv>:
#endif

// Actual interrupt handlers //////////////////////////////////////////////////////////////

void HardwareSerial::_tx_udr_empty_irq(void)
{
 20a:	fc 01       	movw	r30, r24
  // If interrupts are enabled, there must be more data in the output
  // buffer. Send the next byte
  unsigned char c = _tx_buffer[_tx_buffer_tail];
 20c:	a4 8d       	ldd	r26, Z+28	; 0x1c
 20e:	a8 0f       	add	r26, r24
 210:	b9 2f       	mov	r27, r25
 212:	b1 1d       	adc	r27, r1
 214:	a3 5a       	subi	r26, 0xA3	; 163
 216:	bf 4f       	sbci	r27, 0xFF	; 255
 218:	2c 91       	ld	r18, X
  _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;
 21a:	84 8d       	ldd	r24, Z+28	; 0x1c
 21c:	90 e0       	ldi	r25, 0x00	; 0
 21e:	01 96       	adiw	r24, 0x01	; 1
 220:	8f 73       	andi	r24, 0x3F	; 63
 222:	99 27       	eor	r25, r25
 224:	84 8f       	std	Z+28, r24	; 0x1c

  *_udr = c;
 226:	a6 89       	ldd	r26, Z+22	; 0x16
 228:	b7 89       	ldd	r27, Z+23	; 0x17
 22a:	2c 93       	st	X, r18
  // location". This makes sure flush() won't return until the bytes
  // actually got written. Other r/w bits are preserved, and zeroes
  // written to the rest.

#ifdef MPCM0
  *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0);
 22c:	a0 89       	ldd	r26, Z+16	; 0x10
 22e:	b1 89       	ldd	r27, Z+17	; 0x11
 230:	8c 91       	ld	r24, X
 232:	83 70       	andi	r24, 0x03	; 3
 234:	80 64       	ori	r24, 0x40	; 64
 236:	8c 93       	st	X, r24
#else
  *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0)));
#endif

  if (_tx_buffer_head == _tx_buffer_tail) {
 238:	93 8d       	ldd	r25, Z+27	; 0x1b
 23a:	84 8d       	ldd	r24, Z+28	; 0x1c
 23c:	98 13       	cpse	r25, r24
 23e:	06 c0       	rjmp	.+12     	; 0x24c <_ZN14HardwareSerial17_tx_udr_empty_irqEv+0x42>
    // Buffer empty, so disable interrupts
    cbi(*_ucsrb, UDRIE0);
 240:	02 88       	ldd	r0, Z+18	; 0x12
 242:	f3 89       	ldd	r31, Z+19	; 0x13
 244:	e0 2d       	mov	r30, r0
 246:	80 81       	ld	r24, Z
 248:	8f 7d       	andi	r24, 0xDF	; 223
 24a:	80 83       	st	Z, r24
  }
}
 24c:	08 95       	ret

0000024e <_ZN14HardwareSerial5writeEh>:
  // If we get here, nothing is queued anymore (DRIE is disabled) and
  // the hardware finished transmission (TXC is set).
}

size_t HardwareSerial::write(uint8_t c)
{
 24e:	ef 92       	push	r14
 250:	ff 92       	push	r15
 252:	0f 93       	push	r16
 254:	1f 93       	push	r17
 256:	cf 93       	push	r28
 258:	df 93       	push	r29
 25a:	ec 01       	movw	r28, r24
  _written = true;
 25c:	81 e0       	ldi	r24, 0x01	; 1
 25e:	88 8f       	std	Y+24, r24	; 0x18
  // If the buffer and the data register is empty, just write the byte
  // to the data register and be done. This shortcut helps
  // significantly improve the effective datarate at high (>
  // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
  if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
 260:	9b 8d       	ldd	r25, Y+27	; 0x1b
 262:	8c 8d       	ldd	r24, Y+28	; 0x1c
 264:	98 13       	cpse	r25, r24
 266:	1a c0       	rjmp	.+52     	; 0x29c <_ZN14HardwareSerial5writeEh+0x4e>
 268:	e8 89       	ldd	r30, Y+16	; 0x10
 26a:	f9 89       	ldd	r31, Y+17	; 0x11
 26c:	80 81       	ld	r24, Z
 26e:	85 ff       	sbrs	r24, 5
 270:	15 c0       	rjmp	.+42     	; 0x29c <_ZN14HardwareSerial5writeEh+0x4e>
    // So writing UDR must happen first.
    // Writing UDR and clearing TC must be done atomically, otherwise
    // interrupts might delay the TXC clear so the byte written to UDR
    // is transmitted (setting TXC) before clearing TXC. Then TXC will
    // be cleared when no bytes are left, causing flush() to hang
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
 272:	9f b7       	in	r25, 0x3f	; 63
    return 1;
}

static __inline__ uint8_t __iCliRetVal(void)
{
    cli();
 274:	f8 94       	cli
      *_udr = c;
 276:	ee 89       	ldd	r30, Y+22	; 0x16
 278:	ff 89       	ldd	r31, Y+23	; 0x17
 27a:	60 83       	st	Z, r22
#ifdef MPCM0
      *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0);
 27c:	e8 89       	ldd	r30, Y+16	; 0x10
 27e:	f9 89       	ldd	r31, Y+17	; 0x11
 280:	80 81       	ld	r24, Z
 282:	83 70       	andi	r24, 0x03	; 3
 284:	80 64       	ori	r24, 0x40	; 64
  // make atomic to prevent execution of ISR between setting the
  // head pointer and setting the interrupt flag resulting in buffer
  // retransmission
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    _tx_buffer_head = i;
    sbi(*_ucsrb, UDRIE0);
 286:	80 83       	st	Z, r24
    (void)__s;
}

static __inline__ void __iRestore(const  uint8_t *__s)
{
    SREG = *__s;
 288:	9f bf       	out	0x3f, r25	; 63
  }
  
  return 1;
}
 28a:	81 e0       	ldi	r24, 0x01	; 1
 28c:	90 e0       	ldi	r25, 0x00	; 0
 28e:	df 91       	pop	r29
 290:	cf 91       	pop	r28
 292:	1f 91       	pop	r17
 294:	0f 91       	pop	r16
 296:	ff 90       	pop	r15
 298:	ef 90       	pop	r14
 29a:	08 95       	ret
 29c:	f6 2e       	mov	r15, r22
      *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0)));
#endif
    }
    return 1;
  }
  tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
 29e:	0b 8d       	ldd	r16, Y+27	; 0x1b
 2a0:	10 e0       	ldi	r17, 0x00	; 0
 2a2:	0f 5f       	subi	r16, 0xFF	; 255
 2a4:	1f 4f       	sbci	r17, 0xFF	; 255
 2a6:	0f 73       	andi	r16, 0x3F	; 63
 2a8:	11 27       	eor	r17, r17
 2aa:	e0 2e       	mov	r14, r16
	
  // If the output buffer is full, there's nothing for it other than to 
  // wait for the interrupt handler to empty it a bit
  while (i == _tx_buffer_tail) {
 2ac:	8c 8d       	ldd	r24, Y+28	; 0x1c
 2ae:	8e 11       	cpse	r24, r14
 2b0:	0c c0       	rjmp	.+24     	; 0x2ca <_ZN14HardwareSerial5writeEh+0x7c>
    if (bit_is_clear(SREG, SREG_I)) {
 2b2:	0f b6       	in	r0, 0x3f	; 63
 2b4:	07 fc       	sbrc	r0, 7
 2b6:	fa cf       	rjmp	.-12     	; 0x2ac <_ZN14HardwareSerial5writeEh+0x5e>
      // Interrupts are disabled, so we'll have to poll the data
      // register empty flag ourselves. If it is set, pretend an
      // interrupt has happened and call the handler to free up
      // space for us.
      if(bit_is_set(*_ucsra, UDRE0))
 2b8:	e8 89       	ldd	r30, Y+16	; 0x10
 2ba:	f9 89       	ldd	r31, Y+17	; 0x11
 2bc:	80 81       	ld	r24, Z
 2be:	85 ff       	sbrs	r24, 5
 2c0:	f5 cf       	rjmp	.-22     	; 0x2ac <_ZN14HardwareSerial5writeEh+0x5e>
	_tx_udr_empty_irq();
 2c2:	ce 01       	movw	r24, r28
 2c4:	0e 94 05 01 	call	0x20a	; 0x20a <_ZN14HardwareSerial17_tx_udr_empty_irqEv>
 2c8:	f1 cf       	rjmp	.-30     	; 0x2ac <_ZN14HardwareSerial5writeEh+0x5e>
    } else {
      // nop, the interrupt handler will free up space for us
    }
  }

  _tx_buffer[_tx_buffer_head] = c;
 2ca:	eb 8d       	ldd	r30, Y+27	; 0x1b
 2cc:	ec 0f       	add	r30, r28
 2ce:	fd 2f       	mov	r31, r29
 2d0:	f1 1d       	adc	r31, r1
 2d2:	e3 5a       	subi	r30, 0xA3	; 163
 2d4:	ff 4f       	sbci	r31, 0xFF	; 255
 2d6:	f0 82       	st	Z, r15

  // make atomic to prevent execution of ISR between setting the
  // head pointer and setting the interrupt flag resulting in buffer
  // retransmission
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
 2d8:	9f b7       	in	r25, 0x3f	; 63
    return 1;
}

static __inline__ uint8_t __iCliRetVal(void)
{
    cli();
 2da:	f8 94       	cli
    _tx_buffer_head = i;
 2dc:	0b 8f       	std	Y+27, r16	; 0x1b
    sbi(*_ucsrb, UDRIE0);
 2de:	ea 89       	ldd	r30, Y+18	; 0x12
 2e0:	fb 89       	ldd	r31, Y+19	; 0x13
 2e2:	80 81       	ld	r24, Z
 2e4:	80 62       	ori	r24, 0x20	; 32
 2e6:	cf cf       	rjmp	.-98     	; 0x286 <_ZN14HardwareSerial5writeEh+0x38>

000002e8 <_ZN14HardwareSerial5flushEv>:
  if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail;
  return tail - head - 1;
}

void HardwareSerial::flush()
{
 2e8:	cf 93       	push	r28
 2ea:	df 93       	push	r29
 2ec:	ec 01       	movw	r28, r24
  // If we have never written a byte, no need to flush. This special
  // case is needed since there is no way to force the TXC (transmit
  // complete) bit to 1 during initialization
  if (!_written)
 2ee:	88 8d       	ldd	r24, Y+24	; 0x18
 2f0:	88 23       	and	r24, r24
 2f2:	b9 f0       	breq	.+46     	; 0x322 <_ZN14HardwareSerial5flushEv+0x3a>
    return;

  while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
 2f4:	aa 89       	ldd	r26, Y+18	; 0x12
 2f6:	bb 89       	ldd	r27, Y+19	; 0x13
 2f8:	e8 89       	ldd	r30, Y+16	; 0x10
 2fa:	f9 89       	ldd	r31, Y+17	; 0x11
 2fc:	8c 91       	ld	r24, X
 2fe:	85 fd       	sbrc	r24, 5
 300:	03 c0       	rjmp	.+6      	; 0x308 <_ZN14HardwareSerial5flushEv+0x20>
 302:	80 81       	ld	r24, Z
 304:	86 fd       	sbrc	r24, 6
 306:	0d c0       	rjmp	.+26     	; 0x322 <_ZN14HardwareSerial5flushEv+0x3a>
    if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
 308:	0f b6       	in	r0, 0x3f	; 63
 30a:	07 fc       	sbrc	r0, 7
 30c:	f7 cf       	rjmp	.-18     	; 0x2fc <_ZN14HardwareSerial5flushEv+0x14>
 30e:	8c 91       	ld	r24, X
 310:	85 ff       	sbrs	r24, 5
 312:	f2 cf       	rjmp	.-28     	; 0x2f8 <_ZN14HardwareSerial5flushEv+0x10>
	// Interrupts are globally disabled, but the DR empty
	// interrupt should be enabled, so poll the DR empty flag to
	// prevent deadlock
	if (bit_is_set(*_ucsra, UDRE0))
 314:	80 81       	ld	r24, Z
 316:	85 ff       	sbrs	r24, 5
 318:	ed cf       	rjmp	.-38     	; 0x2f4 <_ZN14HardwareSerial5flushEv+0xc>
	  _tx_udr_empty_irq();
 31a:	ce 01       	movw	r24, r28
 31c:	0e 94 05 01 	call	0x20a	; 0x20a <_ZN14HardwareSerial17_tx_udr_empty_irqEv>
 320:	e9 cf       	rjmp	.-46     	; 0x2f4 <_ZN14HardwareSerial5flushEv+0xc>
  }
  // If we get here, nothing is queued anymore (DRIE is disabled) and
  // the hardware finished transmission (TXC is set).
}
 322:	df 91       	pop	r29
 324:	cf 91       	pop	r28
 326:	08 95       	ret

00000328 <_ZN5Print5writeEPKc.part.2.constprop.16>:
    void clearWriteError() { setWriteError(0); }
  
    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) {
      if (str == NULL) return 0;
      return write((const uint8_t *)str, strlen(str));
 328:	fc 01       	movw	r30, r24
 32a:	01 90       	ld	r0, Z+
 32c:	00 20       	and	r0, r0
 32e:	e9 f7       	brne	.-6      	; 0x32a <_ZN5Print5writeEPKc.part.2.constprop.16+0x2>
 330:	31 97       	sbiw	r30, 0x01	; 1
 332:	af 01       	movw	r20, r30
 334:	48 1b       	sub	r20, r24
 336:	59 0b       	sbc	r21, r25
 338:	bc 01       	movw	r22, r24
 33a:	83 e7       	ldi	r24, 0x73	; 115
 33c:	91 e0       	ldi	r25, 0x01	; 1
 33e:	0c 94 87 00 	jmp	0x10e	; 0x10e <_ZN5Print5writeEPKhj>

00000342 <_ZN5Print7printlnEii.constprop.8>:
  size_t n = print(b, base);
  n += println();
  return n;
}

size_t Print::println(int num, int base)
 342:	8f 92       	push	r8
 344:	9f 92       	push	r9
 346:	af 92       	push	r10
 348:	bf 92       	push	r11
 34a:	cf 92       	push	r12
 34c:	df 92       	push	r13
 34e:	ef 92       	push	r14
 350:	ff 92       	push	r15
 352:	0f 93       	push	r16
 354:	1f 93       	push	r17
 356:	cf 93       	push	r28
 358:	df 93       	push	r29
 35a:	cd b7       	in	r28, 0x3d	; 61
 35c:	de b7       	in	r29, 0x3e	; 62
 35e:	a1 97       	sbiw	r28, 0x21	; 33
 360:	0f b6       	in	r0, 0x3f	; 63
 362:	f8 94       	cli
 364:	de bf       	out	0x3e, r29	; 62
 366:	0f be       	out	0x3f, r0	; 63
 368:	cd bf       	out	0x3d, r28	; 61
  return print((unsigned long) b, base);
}

size_t Print::print(int n, int base)
{
  return print((long) n, base);
 36a:	6c 01       	movw	r12, r24
 36c:	99 0f       	add	r25, r25
 36e:	ee 08       	sbc	r14, r14
 370:	ff 08       	sbc	r15, r15
size_t Print::print(long n, int base)
{
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
 372:	f7 fe       	sbrs	r15, 7
 374:	47 c0       	rjmp	.+142    	; 0x404 <__LOCK_REGION_LENGTH__+0x4>
  return write(str);
}

size_t Print::print(char c)
{
  return write(c);
 376:	6d e2       	ldi	r22, 0x2D	; 45
 378:	83 e7       	ldi	r24, 0x73	; 115
 37a:	91 e0       	ldi	r25, 0x01	; 1
 37c:	0e 94 27 01 	call	0x24e	; 0x24e <_ZN14HardwareSerial5writeEh>
 380:	8c 01       	movw	r16, r24
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
 382:	22 27       	eor	r18, r18
 384:	33 27       	eor	r19, r19
 386:	a9 01       	movw	r20, r18
 388:	2c 19       	sub	r18, r12
 38a:	3d 09       	sbc	r19, r13
 38c:	4e 09       	sbc	r20, r14
 38e:	5f 09       	sbc	r21, r15
size_t Print::printNumber(unsigned long n, uint8_t base)
{
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';
 390:	19 a2       	std	Y+33, r1	; 0x21
 392:	ce 01       	movw	r24, r28
 394:	81 96       	adiw	r24, 0x21	; 33
 396:	7c 01       	movw	r14, r24

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    char c = n % base;
 398:	9a e0       	ldi	r25, 0x0A	; 10
 39a:	89 2e       	mov	r8, r25
 39c:	91 2c       	mov	r9, r1
 39e:	a1 2c       	mov	r10, r1
 3a0:	b1 2c       	mov	r11, r1
    n /= base;
 3a2:	ca 01       	movw	r24, r20
 3a4:	b9 01       	movw	r22, r18
 3a6:	a5 01       	movw	r20, r10
 3a8:	94 01       	movw	r18, r8
 3aa:	0e 94 16 04 	call	0x82c	; 0x82c <__udivmodsi4>

    *--str = c < 10 ? c + '0' : c + 'A' - 10;
 3ae:	60 5d       	subi	r22, 0xD0	; 208
 3b0:	f7 01       	movw	r30, r14
 3b2:	62 93       	st	-Z, r22
 3b4:	7f 01       	movw	r14, r30
  } while(n);
 3b6:	21 15       	cp	r18, r1
 3b8:	31 05       	cpc	r19, r1
 3ba:	41 05       	cpc	r20, r1
 3bc:	51 05       	cpc	r21, r1
 3be:	89 f7       	brne	.-30     	; 0x3a2 <_ZN5Print7printlnEii.constprop.8+0x60>
    int getWriteError() { return write_error; }
    void clearWriteError() { setWriteError(0); }
  
    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) {
      if (str == NULL) return 0;
 3c0:	90 e0       	ldi	r25, 0x00	; 0
 3c2:	80 e0       	ldi	r24, 0x00	; 0
 3c4:	30 97       	sbiw	r30, 0x00	; 0
 3c6:	19 f0       	breq	.+6      	; 0x3ce <_ZN5Print7printlnEii.constprop.8+0x8c>
 3c8:	cf 01       	movw	r24, r30
 3ca:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
 3ce:	08 0f       	add	r16, r24
 3d0:	19 1f       	adc	r17, r25
 3d2:	82 e1       	ldi	r24, 0x12	; 18
 3d4:	91 e0       	ldi	r25, 0x01	; 1
 3d6:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
size_t Print::println(int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}
 3da:	80 0f       	add	r24, r16
 3dc:	91 1f       	adc	r25, r17
 3de:	a1 96       	adiw	r28, 0x21	; 33
 3e0:	0f b6       	in	r0, 0x3f	; 63
 3e2:	f8 94       	cli
 3e4:	de bf       	out	0x3e, r29	; 62
 3e6:	0f be       	out	0x3f, r0	; 63
 3e8:	cd bf       	out	0x3d, r28	; 61
 3ea:	df 91       	pop	r29
 3ec:	cf 91       	pop	r28
 3ee:	1f 91       	pop	r17
 3f0:	0f 91       	pop	r16
 3f2:	ff 90       	pop	r15
 3f4:	ef 90       	pop	r14
 3f6:	df 90       	pop	r13
 3f8:	cf 90       	pop	r12
 3fa:	bf 90       	pop	r11
 3fc:	af 90       	pop	r10
 3fe:	9f 90       	pop	r9
 400:	8f 90       	pop	r8
 402:	08 95       	ret
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
    }
    return printNumber(n, 10);
 404:	a7 01       	movw	r20, r14
 406:	96 01       	movw	r18, r12
size_t Print::printNumber(unsigned long n, uint8_t base)
{
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';
 408:	19 a2       	std	Y+33, r1	; 0x21
 40a:	8e 01       	movw	r16, r28
 40c:	0f 5d       	subi	r16, 0xDF	; 223
 40e:	1f 4f       	sbci	r17, 0xFF	; 255

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    char c = n % base;
 410:	8a e0       	ldi	r24, 0x0A	; 10
 412:	c8 2e       	mov	r12, r24
 414:	d1 2c       	mov	r13, r1
 416:	e1 2c       	mov	r14, r1
 418:	f1 2c       	mov	r15, r1
    n /= base;
 41a:	ca 01       	movw	r24, r20
 41c:	b9 01       	movw	r22, r18
 41e:	a7 01       	movw	r20, r14
 420:	96 01       	movw	r18, r12
 422:	0e 94 16 04 	call	0x82c	; 0x82c <__udivmodsi4>

    *--str = c < 10 ? c + '0' : c + 'A' - 10;
 426:	60 5d       	subi	r22, 0xD0	; 208
 428:	f8 01       	movw	r30, r16
 42a:	62 93       	st	-Z, r22
 42c:	8f 01       	movw	r16, r30
  } while(n);
 42e:	21 15       	cp	r18, r1
 430:	31 05       	cpc	r19, r1
 432:	41 05       	cpc	r20, r1
 434:	51 05       	cpc	r21, r1
 436:	89 f7       	brne	.-30     	; 0x41a <__LOCK_REGION_LENGTH__+0x1a>
 438:	30 97       	sbiw	r30, 0x00	; 0
 43a:	29 f0       	breq	.+10     	; 0x446 <__LOCK_REGION_LENGTH__+0x46>
 43c:	cf 01       	movw	r24, r30
 43e:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
 442:	8c 01       	movw	r16, r24
 444:	c6 cf       	rjmp	.-116    	; 0x3d2 <_ZN5Print7printlnEii.constprop.8+0x90>
 446:	10 e0       	ldi	r17, 0x00	; 0
 448:	00 e0       	ldi	r16, 0x00	; 0
 44a:	c3 cf       	rjmp	.-122    	; 0x3d2 <_ZN5Print7printlnEii.constprop.8+0x90>

0000044c <__vector_16>:
#if defined(TIM0_OVF_vect)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
 44c:	1f 92       	push	r1
 44e:	0f 92       	push	r0
 450:	0f b6       	in	r0, 0x3f	; 63
 452:	0f 92       	push	r0
 454:	11 24       	eor	r1, r1
 456:	2f 93       	push	r18
 458:	3f 93       	push	r19
 45a:	8f 93       	push	r24
 45c:	9f 93       	push	r25
 45e:	af 93       	push	r26
 460:	bf 93       	push	r27
	// copy these to local variables so they can be stored in registers
	// (volatile variables must be read from memory on every access)
	unsigned long m = timer0_millis;
 462:	80 91 6f 01 	lds	r24, 0x016F	; 0x80016f <timer0_millis>
 466:	90 91 70 01 	lds	r25, 0x0170	; 0x800170 <timer0_millis+0x1>
 46a:	a0 91 71 01 	lds	r26, 0x0171	; 0x800171 <timer0_millis+0x2>
 46e:	b0 91 72 01 	lds	r27, 0x0172	; 0x800172 <timer0_millis+0x3>
	unsigned char f = timer0_fract;
 472:	30 91 6e 01 	lds	r19, 0x016E	; 0x80016e <timer0_fract>

	m += MILLIS_INC;
	f += FRACT_INC;
 476:	23 e0       	ldi	r18, 0x03	; 3
 478:	23 0f       	add	r18, r19
	if (f >= FRACT_MAX) {
 47a:	2d 37       	cpi	r18, 0x7D	; 125
 47c:	58 f5       	brcc	.+86     	; 0x4d4 <__vector_16+0x88>
	// copy these to local variables so they can be stored in registers
	// (volatile variables must be read from memory on every access)
	unsigned long m = timer0_millis;
	unsigned char f = timer0_fract;

	m += MILLIS_INC;
 47e:	01 96       	adiw	r24, 0x01	; 1
 480:	a1 1d       	adc	r26, r1
 482:	b1 1d       	adc	r27, r1
	if (f >= FRACT_MAX) {
		f -= FRACT_MAX;
		m += 1;
	}

	timer0_fract = f;
 484:	20 93 6e 01 	sts	0x016E, r18	; 0x80016e <timer0_fract>
	timer0_millis = m;
 488:	80 93 6f 01 	sts	0x016F, r24	; 0x80016f <timer0_millis>
 48c:	90 93 70 01 	sts	0x0170, r25	; 0x800170 <timer0_millis+0x1>
 490:	a0 93 71 01 	sts	0x0171, r26	; 0x800171 <timer0_millis+0x2>
 494:	b0 93 72 01 	sts	0x0172, r27	; 0x800172 <timer0_millis+0x3>
	timer0_overflow_count++;
 498:	80 91 6a 01 	lds	r24, 0x016A	; 0x80016a <__data_end>
 49c:	90 91 6b 01 	lds	r25, 0x016B	; 0x80016b <__data_end+0x1>
 4a0:	a0 91 6c 01 	lds	r26, 0x016C	; 0x80016c <__data_end+0x2>
 4a4:	b0 91 6d 01 	lds	r27, 0x016D	; 0x80016d <__data_end+0x3>
 4a8:	01 96       	adiw	r24, 0x01	; 1
 4aa:	a1 1d       	adc	r26, r1
 4ac:	b1 1d       	adc	r27, r1
 4ae:	80 93 6a 01 	sts	0x016A, r24	; 0x80016a <__data_end>
 4b2:	90 93 6b 01 	sts	0x016B, r25	; 0x80016b <__data_end+0x1>
 4b6:	a0 93 6c 01 	sts	0x016C, r26	; 0x80016c <__data_end+0x2>
 4ba:	b0 93 6d 01 	sts	0x016D, r27	; 0x80016d <__data_end+0x3>
}
 4be:	bf 91       	pop	r27
 4c0:	af 91       	pop	r26
 4c2:	9f 91       	pop	r25
 4c4:	8f 91       	pop	r24
 4c6:	3f 91       	pop	r19
 4c8:	2f 91       	pop	r18
 4ca:	0f 90       	pop	r0
 4cc:	0f be       	out	0x3f, r0	; 63
 4ce:	0f 90       	pop	r0
 4d0:	1f 90       	pop	r1
 4d2:	18 95       	reti
	unsigned char f = timer0_fract;

	m += MILLIS_INC;
	f += FRACT_INC;
	if (f >= FRACT_MAX) {
		f -= FRACT_MAX;
 4d4:	26 e8       	ldi	r18, 0x86	; 134
 4d6:	23 0f       	add	r18, r19
		m += 1;
 4d8:	02 96       	adiw	r24, 0x02	; 2
 4da:	a1 1d       	adc	r26, r1
 4dc:	b1 1d       	adc	r27, r1
 4de:	d2 cf       	rjmp	.-92     	; 0x484 <__vector_16+0x38>

000004e0 <__vector_19>:
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#else
  #error "Don't know what the Data Register Empty vector is called for Serial"
#endif
{
 4e0:	1f 92       	push	r1
 4e2:	0f 92       	push	r0
 4e4:	0f b6       	in	r0, 0x3f	; 63
 4e6:	0f 92       	push	r0
 4e8:	11 24       	eor	r1, r1
 4ea:	2f 93       	push	r18
 4ec:	3f 93       	push	r19
 4ee:	4f 93       	push	r20
 4f0:	5f 93       	push	r21
 4f2:	6f 93       	push	r22
 4f4:	7f 93       	push	r23
 4f6:	8f 93       	push	r24
 4f8:	9f 93       	push	r25
 4fa:	af 93       	push	r26
 4fc:	bf 93       	push	r27
 4fe:	ef 93       	push	r30
 500:	ff 93       	push	r31
  Serial._tx_udr_empty_irq();
 502:	83 e7       	ldi	r24, 0x73	; 115
 504:	91 e0       	ldi	r25, 0x01	; 1
 506:	0e 94 05 01 	call	0x20a	; 0x20a <_ZN14HardwareSerial17_tx_udr_empty_irqEv>
}
 50a:	ff 91       	pop	r31
 50c:	ef 91       	pop	r30
 50e:	bf 91       	pop	r27
 510:	af 91       	pop	r26
 512:	9f 91       	pop	r25
 514:	8f 91       	pop	r24
 516:	7f 91       	pop	r23
 518:	6f 91       	pop	r22
 51a:	5f 91       	pop	r21
 51c:	4f 91       	pop	r20
 51e:	3f 91       	pop	r19
 520:	2f 91       	pop	r18
 522:	0f 90       	pop	r0
 524:	0f be       	out	0x3f, r0	; 63
 526:	0f 90       	pop	r0
 528:	1f 90       	pop	r1
 52a:	18 95       	reti

0000052c <__vector_18>:
#elif defined(USART_RXC_vect)
  ISR(USART_RXC_vect) // ATmega8
#else
  #error "Don't know what the Data Received vector is called for Serial"
#endif
  {
 52c:	1f 92       	push	r1
 52e:	0f 92       	push	r0
 530:	0f b6       	in	r0, 0x3f	; 63
 532:	0f 92       	push	r0
 534:	11 24       	eor	r1, r1
 536:	2f 93       	push	r18
 538:	8f 93       	push	r24
 53a:	9f 93       	push	r25
 53c:	ef 93       	push	r30
 53e:	ff 93       	push	r31

// Actual interrupt handlers //////////////////////////////////////////////////////////////

void HardwareSerial::_rx_complete_irq(void)
{
  if (bit_is_clear(*_ucsra, UPE0)) {
 540:	e0 91 83 01 	lds	r30, 0x0183	; 0x800183 <Serial+0x10>
 544:	f0 91 84 01 	lds	r31, 0x0184	; 0x800184 <Serial+0x11>
 548:	80 81       	ld	r24, Z
 54a:	e0 91 89 01 	lds	r30, 0x0189	; 0x800189 <Serial+0x16>
 54e:	f0 91 8a 01 	lds	r31, 0x018A	; 0x80018a <Serial+0x17>
 552:	82 fd       	sbrc	r24, 2
 554:	1b c0       	rjmp	.+54     	; 0x58c <__vector_18+0x60>
    // No Parity error, read byte and store it in the buffer if there is
    // room
    unsigned char c = *_udr;
 556:	90 81       	ld	r25, Z
    rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
 558:	80 91 8c 01 	lds	r24, 0x018C	; 0x80018c <Serial+0x19>
 55c:	8f 5f       	subi	r24, 0xFF	; 255
 55e:	8f 73       	andi	r24, 0x3F	; 63

    // if we should be storing the received character into the location
    // just before the tail (meaning that the head would advance to the
    // current location of the tail), we're about to overflow the buffer
    // and so we don't write the character or advance the head.
    if (i != _rx_buffer_tail) {
 560:	20 91 8d 01 	lds	r18, 0x018D	; 0x80018d <Serial+0x1a>
 564:	82 17       	cp	r24, r18
 566:	41 f0       	breq	.+16     	; 0x578 <__vector_18+0x4c>
      _rx_buffer[_rx_buffer_head] = c;
 568:	e0 91 8c 01 	lds	r30, 0x018C	; 0x80018c <Serial+0x19>
 56c:	f0 e0       	ldi	r31, 0x00	; 0
 56e:	ed 58       	subi	r30, 0x8D	; 141
 570:	fe 4f       	sbci	r31, 0xFE	; 254
 572:	95 8f       	std	Z+29, r25	; 0x1d
      _rx_buffer_head = i;
 574:	80 93 8c 01 	sts	0x018C, r24	; 0x80018c <Serial+0x19>
    Serial._rx_complete_irq();
  }
 578:	ff 91       	pop	r31
 57a:	ef 91       	pop	r30
 57c:	9f 91       	pop	r25
 57e:	8f 91       	pop	r24
 580:	2f 91       	pop	r18
 582:	0f 90       	pop	r0
 584:	0f be       	out	0x3f, r0	; 63
 586:	0f 90       	pop	r0
 588:	1f 90       	pop	r1
 58a:	18 95       	reti
    }
  } else {
    // Parity error, read byte but discard it
    *_udr;
 58c:	80 81       	ld	r24, Z
 58e:	f4 cf       	rjmp	.-24     	; 0x578 <__vector_18+0x4c>

00000590 <main>:

void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();
 590:	78 94       	sei
	
	// on the ATmega168, timer 0 is also used for fast hardware pwm
	// (using phase-correct PWM would mean that timer 0 overflowed half as often
	// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
	sbi(TCCR0A, WGM01);
 592:	84 b5       	in	r24, 0x24	; 36
 594:	82 60       	ori	r24, 0x02	; 2
 596:	84 bd       	out	0x24, r24	; 36
	sbi(TCCR0A, WGM00);
 598:	84 b5       	in	r24, 0x24	; 36
 59a:	81 60       	ori	r24, 0x01	; 1
 59c:	84 bd       	out	0x24, r24	; 36
	// this combination is for the standard atmega8
	sbi(TCCR0, CS01);
	sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
	// this combination is for the standard 168/328/1280/2560
	sbi(TCCR0B, CS01);
 59e:	85 b5       	in	r24, 0x25	; 37
 5a0:	82 60       	ori	r24, 0x02	; 2
 5a2:	85 bd       	out	0x25, r24	; 37
	sbi(TCCR0B, CS00);
 5a4:	85 b5       	in	r24, 0x25	; 37
 5a6:	81 60       	ori	r24, 0x01	; 1
 5a8:	85 bd       	out	0x25, r24	; 37

	// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
	sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
	sbi(TIMSK0, TOIE0);
 5aa:	80 91 6e 00 	lds	r24, 0x006E	; 0x80006e <__DATA_REGION_ORIGIN__+0xe>
 5ae:	81 60       	ori	r24, 0x01	; 1
 5b0:	80 93 6e 00 	sts	0x006E, r24	; 0x80006e <__DATA_REGION_ORIGIN__+0xe>
	// this is better for motors as it ensures an even waveform
	// note, however, that fast pwm mode can achieve a frequency of up
	// 8 MHz (with a 16 MHz clock) at 50% duty cycle

#if defined(TCCR1B) && defined(CS11) && defined(CS10)
	TCCR1B = 0;
 5b4:	10 92 81 00 	sts	0x0081, r1	; 0x800081 <__DATA_REGION_ORIGIN__+0x21>

	// set timer 1 prescale factor to 64
	sbi(TCCR1B, CS11);
 5b8:	80 91 81 00 	lds	r24, 0x0081	; 0x800081 <__DATA_REGION_ORIGIN__+0x21>
 5bc:	82 60       	ori	r24, 0x02	; 2
 5be:	80 93 81 00 	sts	0x0081, r24	; 0x800081 <__DATA_REGION_ORIGIN__+0x21>
#if F_CPU >= 8000000L
	sbi(TCCR1B, CS10);
 5c2:	80 91 81 00 	lds	r24, 0x0081	; 0x800081 <__DATA_REGION_ORIGIN__+0x21>
 5c6:	81 60       	ori	r24, 0x01	; 1
 5c8:	80 93 81 00 	sts	0x0081, r24	; 0x800081 <__DATA_REGION_ORIGIN__+0x21>
	sbi(TCCR1, CS10);
#endif
#endif
	// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
	sbi(TCCR1A, WGM10);
 5cc:	80 91 80 00 	lds	r24, 0x0080	; 0x800080 <__DATA_REGION_ORIGIN__+0x20>
 5d0:	81 60       	ori	r24, 0x01	; 1
 5d2:	80 93 80 00 	sts	0x0080, r24	; 0x800080 <__DATA_REGION_ORIGIN__+0x20>

	// set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
	sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
	sbi(TCCR2B, CS22);
 5d6:	80 91 b1 00 	lds	r24, 0x00B1	; 0x8000b1 <__DATA_REGION_ORIGIN__+0x51>
 5da:	84 60       	ori	r24, 0x04	; 4
 5dc:	80 93 b1 00 	sts	0x00B1, r24	; 0x8000b1 <__DATA_REGION_ORIGIN__+0x51>

	// configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
	sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
	sbi(TCCR2A, WGM20);
 5e0:	80 91 b0 00 	lds	r24, 0x00B0	; 0x8000b0 <__DATA_REGION_ORIGIN__+0x50>
 5e4:	81 60       	ori	r24, 0x01	; 1
 5e6:	80 93 b0 00 	sts	0x00B0, r24	; 0x8000b0 <__DATA_REGION_ORIGIN__+0x50>
#endif

#if defined(ADCSRA)
	// set a2d prescaler so we are inside the desired 50-200 KHz range.
	#if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
		sbi(ADCSRA, ADPS2);
 5ea:	80 91 7a 00 	lds	r24, 0x007A	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
 5ee:	84 60       	ori	r24, 0x04	; 4
 5f0:	80 93 7a 00 	sts	0x007A, r24	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
		sbi(ADCSRA, ADPS1);
 5f4:	80 91 7a 00 	lds	r24, 0x007A	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
 5f8:	82 60       	ori	r24, 0x02	; 2
 5fa:	80 93 7a 00 	sts	0x007A, r24	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
		sbi(ADCSRA, ADPS0);
 5fe:	80 91 7a 00 	lds	r24, 0x007A	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
 602:	81 60       	ori	r24, 0x01	; 1
 604:	80 93 7a 00 	sts	0x007A, r24	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
		cbi(ADCSRA, ADPS2);
		cbi(ADCSRA, ADPS1);
		sbi(ADCSRA, ADPS0);
	#endif
	// enable a2d conversions
	sbi(ADCSRA, ADEN);
 608:	80 91 7a 00 	lds	r24, 0x007A	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
 60c:	80 68       	ori	r24, 0x80	; 128
 60e:	80 93 7a 00 	sts	0x007A, r24	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
	// here so they can be used as normal digital i/o; they will be
	// reconnected in Serial.begin()
#if defined(UCSRB)
	UCSRB = 0;
#elif defined(UCSR0B)
	UCSR0B = 0;
 612:	10 92 c1 00 	sts	0x00C1, r1	; 0x8000c1 <__DATA_REGION_ORIGIN__+0x61>

void HardwareSerial::begin(unsigned long baud, byte config)
{
  // Try u2x mode first
  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
  *_ucsra = 1 << U2X0;
 616:	e0 91 83 01 	lds	r30, 0x0183	; 0x800183 <Serial+0x10>
 61a:	f0 91 84 01 	lds	r31, 0x0184	; 0x800184 <Serial+0x11>
 61e:	82 e0       	ldi	r24, 0x02	; 2
 620:	80 83       	st	Z, r24
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
 622:	e0 91 7f 01 	lds	r30, 0x017F	; 0x80017f <Serial+0xc>
 626:	f0 91 80 01 	lds	r31, 0x0180	; 0x800180 <Serial+0xd>
 62a:	10 82       	st	Z, r1
  *_ubrrl = baud_setting;
 62c:	e0 91 81 01 	lds	r30, 0x0181	; 0x800181 <Serial+0xe>
 630:	f0 91 82 01 	lds	r31, 0x0182	; 0x800182 <Serial+0xf>
 634:	80 e1       	ldi	r24, 0x10	; 16
 636:	80 83       	st	Z, r24

  _written = false;
 638:	10 92 8b 01 	sts	0x018B, r1	; 0x80018b <Serial+0x18>

  //set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
  config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
  *_ucsrc = config;
 63c:	e0 91 87 01 	lds	r30, 0x0187	; 0x800187 <Serial+0x14>
 640:	f0 91 88 01 	lds	r31, 0x0188	; 0x800188 <Serial+0x15>
 644:	86 e0       	ldi	r24, 0x06	; 6
 646:	80 83       	st	Z, r24
  
  sbi(*_ucsrb, RXEN0);
 648:	e0 91 85 01 	lds	r30, 0x0185	; 0x800185 <Serial+0x12>
 64c:	f0 91 86 01 	lds	r31, 0x0186	; 0x800186 <Serial+0x13>
 650:	80 81       	ld	r24, Z
 652:	80 61       	ori	r24, 0x10	; 16
 654:	80 83       	st	Z, r24
  sbi(*_ucsrb, TXEN0);
 656:	e0 91 85 01 	lds	r30, 0x0185	; 0x800185 <Serial+0x12>
 65a:	f0 91 86 01 	lds	r31, 0x0186	; 0x800186 <Serial+0x13>
 65e:	80 81       	ld	r24, Z
 660:	88 60       	ori	r24, 0x08	; 8
 662:	80 83       	st	Z, r24
  sbi(*_ucsrb, RXCIE0);
 664:	e0 91 85 01 	lds	r30, 0x0185	; 0x800185 <Serial+0x12>
 668:	f0 91 86 01 	lds	r31, 0x0186	; 0x800186 <Serial+0x13>
 66c:	80 81       	ld	r24, Z
 66e:	80 68       	ori	r24, 0x80	; 128
 670:	80 83       	st	Z, r24
  cbi(*_ucsrb, UDRIE0);
 672:	e0 91 85 01 	lds	r30, 0x0185	; 0x800185 <Serial+0x12>
 676:	f0 91 86 01 	lds	r31, 0x0186	; 0x800186 <Serial+0x13>
 67a:	80 81       	ld	r24, Z
 67c:	8f 7d       	andi	r24, 0xDF	; 223
 67e:	80 83       	st	Z, r24
 680:	85 e1       	ldi	r24, 0x15	; 21
 682:	91 e0       	ldi	r25, 0x01	; 1
 684:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
 688:	82 e1       	ldi	r24, 0x12	; 18
 68a:	91 e0       	ldi	r25, 0x01	; 1
 68c:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
#include "wiring_private.h"
#include "pins_arduino.h"

void pinMode(uint8_t pin, uint8_t mode)
{
	uint8_t bit = digitalPinToBitMask(pin);
 690:	47 e9       	ldi	r20, 0x97	; 151
 692:	50 e0       	ldi	r21, 0x00	; 0
 694:	fa 01       	movw	r30, r20
 696:	64 91       	lpm	r22, Z
	uint8_t port = digitalPinToPort(pin);
 698:	83 e8       	ldi	r24, 0x83	; 131
 69a:	90 e0       	ldi	r25, 0x00	; 0
 69c:	fc 01       	movw	r30, r24
 69e:	24 91       	lpm	r18, Z
	volatile uint8_t *reg, *out;

	if (port == NOT_A_PIN) return;
 6a0:	22 23       	and	r18, r18
 6a2:	99 f0       	breq	.+38     	; 0x6ca <main+0x13a>

	// JWS: can I let the optimizer do this?
	reg = portModeRegister(port);
 6a4:	30 e0       	ldi	r19, 0x00	; 0
 6a6:	22 0f       	add	r18, r18
 6a8:	33 1f       	adc	r19, r19
 6aa:	f9 01       	movw	r30, r18
 6ac:	e8 59       	subi	r30, 0x98	; 152
 6ae:	ff 4f       	sbci	r31, 0xFF	; 255
 6b0:	a5 91       	lpm	r26, Z+
 6b2:	b4 91       	lpm	r27, Z
	out = portOutputRegister(port);
 6b4:	f9 01       	movw	r30, r18
 6b6:	ee 58       	subi	r30, 0x8E	; 142
 6b8:	ff 4f       	sbci	r31, 0xFF	; 255
 6ba:	25 91       	lpm	r18, Z+
 6bc:	34 91       	lpm	r19, Z
                cli();
		*reg &= ~bit;
		*out |= bit;
		SREG = oldSREG;
	} else {
		uint8_t oldSREG = SREG;
 6be:	2f b7       	in	r18, 0x3f	; 63
                cli();
 6c0:	f8 94       	cli
		*reg |= bit;
 6c2:	3c 91       	ld	r19, X
 6c4:	63 2b       	or	r22, r19
 6c6:	6c 93       	st	X, r22
		SREG = oldSREG;
 6c8:	2f bf       	out	0x3f, r18	; 63
	}
}

void digitalWrite(uint8_t pin, uint8_t val)
{
	uint8_t timer = digitalPinToTimer(pin);
 6ca:	eb ea       	ldi	r30, 0xAB	; 171
 6cc:	f0 e0       	ldi	r31, 0x00	; 0
 6ce:	24 91       	lpm	r18, Z
	uint8_t bit = digitalPinToBitMask(pin);
 6d0:	fa 01       	movw	r30, r20
 6d2:	44 91       	lpm	r20, Z
	uint8_t port = digitalPinToPort(pin);
 6d4:	fc 01       	movw	r30, r24
 6d6:	94 91       	lpm	r25, Z
	volatile uint8_t *out;

	if (port == NOT_A_PIN) return;
 6d8:	99 23       	and	r25, r25
 6da:	e1 f0       	breq	.+56     	; 0x714 <main+0x184>

	// If the pin that support PWM output, we need to turn it off
	// before doing a digital write.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
 6dc:	22 23       	and	r18, r18
 6de:	59 f0       	breq	.+22     	; 0x6f6 <main+0x166>
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
	switch (timer)
 6e0:	23 30       	cpi	r18, 0x03	; 3
 6e2:	09 f4       	brne	.+2      	; 0x6e6 <main+0x156>
 6e4:	5f c0       	rjmp	.+190    	; 0x7a4 <main+0x214>
 6e6:	08 f0       	brcs	.+2      	; 0x6ea <main+0x15a>
 6e8:	52 c0       	rjmp	.+164    	; 0x78e <main+0x1fe>
 6ea:	21 30       	cpi	r18, 0x01	; 1
 6ec:	09 f4       	brne	.+2      	; 0x6f0 <main+0x160>
 6ee:	60 c0       	rjmp	.+192    	; 0x7b0 <main+0x220>
 6f0:	22 30       	cpi	r18, 0x02	; 2
 6f2:	09 f4       	brne	.+2      	; 0x6f6 <main+0x166>
 6f4:	61 c0       	rjmp	.+194    	; 0x7b8 <main+0x228>

	// If the pin that support PWM output, we need to turn it off
	// before doing a digital write.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	out = portOutputRegister(port);
 6f6:	e9 2f       	mov	r30, r25
 6f8:	f0 e0       	ldi	r31, 0x00	; 0
 6fa:	ee 0f       	add	r30, r30
 6fc:	ff 1f       	adc	r31, r31
 6fe:	ee 58       	subi	r30, 0x8E	; 142
 700:	ff 4f       	sbci	r31, 0xFF	; 255
 702:	a5 91       	lpm	r26, Z+
 704:	b4 91       	lpm	r27, Z

	uint8_t oldSREG = SREG;
 706:	8f b7       	in	r24, 0x3f	; 63
	cli();
 708:	f8 94       	cli

	if (val == LOW) {
		*out &= ~bit;
 70a:	9c 91       	ld	r25, X
 70c:	40 95       	com	r20
 70e:	49 23       	and	r20, r25
 710:	4c 93       	st	X, r20
	} else {
		*out |= bit;
	}

	SREG = oldSREG;
 712:	8f bf       	out	0x3f, r24	; 63
	// to 0 (the default).
#if defined(ADMUX)
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
	ADMUX = (analog_reference << 4) | (pin & 0x07);
#else
	ADMUX = (analog_reference << 6) | (pin & 0x07);
 714:	80 e4       	ldi	r24, 0x40	; 64
 716:	80 93 7c 00 	sts	0x007C, r24	; 0x80007c <__DATA_REGION_ORIGIN__+0x1c>
	// without a delay, we seem to read from the wrong channel
	//delay(1);

#if defined(ADCSRA) && defined(ADC)
	// start the conversion
	sbi(ADCSRA, ADSC);
 71a:	80 91 7a 00 	lds	r24, 0x007A	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
 71e:	80 64       	ori	r24, 0x40	; 64
 720:	80 93 7a 00 	sts	0x007A, r24	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>

	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));
 724:	80 91 7a 00 	lds	r24, 0x007A	; 0x80007a <__DATA_REGION_ORIGIN__+0x1a>
 728:	86 fd       	sbrc	r24, 6
 72a:	fc cf       	rjmp	.-8      	; 0x724 <main+0x194>

	// ADC macro takes care of reading ADC register.
	// avr-gcc implements the proper reading order: ADCL is read first.
	return ADC;
 72c:	c0 91 78 00 	lds	r28, 0x0078	; 0x800078 <__DATA_REGION_ORIGIN__+0x18>
 730:	d0 91 79 00 	lds	r29, 0x0079	; 0x800079 <__DATA_REGION_ORIGIN__+0x19>
 734:	89 e2       	ldi	r24, 0x29	; 41
 736:	91 e0       	ldi	r25, 0x01	; 1
 738:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>

  bool flag;

  int xx = analogRead(A0);

  Serial.print("reading "); Serial.println(xx);
 73c:	ce 01       	movw	r24, r28
 73e:	0e 94 a1 01 	call	0x342	; 0x342 <_ZN5Print7printlnEii.constprop.8>
 742:	82 e3       	ldi	r24, 0x32	; 50
 744:	91 e0       	ldi	r25, 0x01	; 1
 746:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
  Serial.print("flag before          "); Serial.println(flag);
 74a:	90 e0       	ldi	r25, 0x00	; 0
 74c:	80 e0       	ldi	r24, 0x00	; 0
 74e:	0e 94 a1 01 	call	0x342	; 0x342 <_ZN5Print7printlnEii.constprop.8>

  if (xx > 100) {
 752:	c5 36       	cpi	r28, 0x65	; 101
 754:	d1 05       	cpc	r29, r1
 756:	44 f0       	brlt	.+16     	; 0x768 <main+0x1d8>
 758:	88 e4       	ldi	r24, 0x48	; 72
 75a:	91 e0       	ldi	r25, 0x01	; 1
 75c:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
 760:	82 e1       	ldi	r24, 0x12	; 18
 762:	91 e0       	ldi	r25, 0x01	; 1
 764:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
 768:	83 e5       	ldi	r24, 0x53	; 83
 76a:	91 e0       	ldi	r25, 0x01	; 1
 76c:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
    Serial.println("       WTF");  // Serial.flush(); for (; ;);
    flag = true;
  }

  Serial.print("flag after           "); Serial.println(flag);
 770:	81 e0       	ldi	r24, 0x01	; 1
 772:	90 e0       	ldi	r25, 0x00	; 0
 774:	0e 94 a1 01 	call	0x342	; 0x342 <_ZN5Print7printlnEii.constprop.8>
#endif

void serialEventRun(void)
{
#if defined(HAVE_HWSERIAL0)
  if (Serial0_available && serialEvent && Serial0_available()) serialEvent();
 778:	c0 e0       	ldi	r28, 0x00	; 0
 77a:	d0 e0       	ldi	r29, 0x00	; 0
 77c:	20 97       	sbiw	r28, 0x00	; 0
 77e:	f1 f3       	breq	.-4      	; 0x77c <main+0x1ec>
 780:	0e 94 f1 00 	call	0x1e2	; 0x1e2 <_Z17Serial0_availablev>
 784:	88 23       	and	r24, r24
 786:	d1 f3       	breq	.-12     	; 0x77c <main+0x1ec>
 788:	0e 94 00 00 	call	0	; 0x0 <__vectors>
 78c:	f7 cf       	rjmp	.-18     	; 0x77c <main+0x1ec>
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
	switch (timer)
 78e:	27 30       	cpi	r18, 0x07	; 7
 790:	b1 f0       	breq	.+44     	; 0x7be <main+0x22e>
 792:	28 30       	cpi	r18, 0x08	; 8
 794:	d1 f0       	breq	.+52     	; 0x7ca <main+0x23a>
 796:	24 30       	cpi	r18, 0x04	; 4
 798:	09 f0       	breq	.+2      	; 0x79c <main+0x20c>
 79a:	ad cf       	rjmp	.-166    	; 0x6f6 <main+0x166>
	{
		#if defined(TCCR1A) && defined(COM1A1)
		case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
		#endif
		#if defined(TCCR1A) && defined(COM1B1)
		case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
 79c:	80 91 80 00 	lds	r24, 0x0080	; 0x800080 <__DATA_REGION_ORIGIN__+0x20>
 7a0:	8f 7d       	andi	r24, 0xDF	; 223
 7a2:	03 c0       	rjmp	.+6      	; 0x7aa <main+0x21a>
static void turnOffPWM(uint8_t timer)
{
	switch (timer)
	{
		#if defined(TCCR1A) && defined(COM1A1)
		case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
 7a4:	80 91 80 00 	lds	r24, 0x0080	; 0x800080 <__DATA_REGION_ORIGIN__+0x20>
 7a8:	8f 77       	andi	r24, 0x7F	; 127
		#endif
		#if defined(TCCR1A) && defined(COM1B1)
		case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
 7aa:	80 93 80 00 	sts	0x0080, r24	; 0x800080 <__DATA_REGION_ORIGIN__+0x20>
 7ae:	a3 cf       	rjmp	.-186    	; 0x6f6 <main+0x166>
		#if defined(TCCR2) && defined(COM21)
		case  TIMER2:   cbi(TCCR2, COM21);      break;
		#endif
		
		#if defined(TCCR0A) && defined(COM0A1)
		case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
 7b0:	84 b5       	in	r24, 0x24	; 36
 7b2:	8f 77       	andi	r24, 0x7F	; 127
		#endif
		
		#if defined(TCCR0A) && defined(COM0B1)
		case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
 7b4:	84 bd       	out	0x24, r24	; 36
 7b6:	9f cf       	rjmp	.-194    	; 0x6f6 <main+0x166>
 7b8:	84 b5       	in	r24, 0x24	; 36
 7ba:	8f 7d       	andi	r24, 0xDF	; 223
 7bc:	fb cf       	rjmp	.-10     	; 0x7b4 <main+0x224>
		#endif
		#if defined(TCCR2A) && defined(COM2A1)
		case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
 7be:	80 91 b0 00 	lds	r24, 0x00B0	; 0x8000b0 <__DATA_REGION_ORIGIN__+0x50>
 7c2:	8f 77       	andi	r24, 0x7F	; 127
		#endif
		#if defined(TCCR2A) && defined(COM2B1)
		case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
 7c4:	80 93 b0 00 	sts	0x00B0, r24	; 0x8000b0 <__DATA_REGION_ORIGIN__+0x50>
 7c8:	96 cf       	rjmp	.-212    	; 0x6f6 <main+0x166>
 7ca:	80 91 b0 00 	lds	r24, 0x00B0	; 0x8000b0 <__DATA_REGION_ORIGIN__+0x50>
 7ce:	8f 7d       	andi	r24, 0xDF	; 223
 7d0:	f9 cf       	rjmp	.-14     	; 0x7c4 <main+0x234>

000007d2 <_GLOBAL__sub_I___vector_18>:
    size_t printNumber(unsigned long, uint8_t);
    size_t printFloat(double, uint8_t);
  protected:
    void setWriteError(int err = 1) { write_error = err; }
  public:
    Print() : write_error(0) {}
 7d2:	e3 e7       	ldi	r30, 0x73	; 115
 7d4:	f1 e0       	ldi	r31, 0x01	; 1
 7d6:	13 82       	std	Z+3, r1	; 0x03
 7d8:	12 82       	std	Z+2, r1	; 0x02
  public:
    virtual int available() = 0;
    virtual int read() = 0;
    virtual int peek() = 0;

    Stream() {_timeout=1000;}
 7da:	88 ee       	ldi	r24, 0xE8	; 232
 7dc:	93 e0       	ldi	r25, 0x03	; 3
 7de:	a0 e0       	ldi	r26, 0x00	; 0
 7e0:	b0 e0       	ldi	r27, 0x00	; 0
 7e2:	84 83       	std	Z+4, r24	; 0x04
 7e4:	95 83       	std	Z+5, r25	; 0x05
 7e6:	a6 83       	std	Z+6, r26	; 0x06
 7e8:	b7 83       	std	Z+7, r27	; 0x07
  volatile uint8_t *ucsrc, volatile uint8_t *udr) :
    _ubrrh(ubrrh), _ubrrl(ubrrl),
    _ucsra(ucsra), _ucsrb(ucsrb), _ucsrc(ucsrc),
    _udr(udr),
    _rx_buffer_head(0), _rx_buffer_tail(0),
    _tx_buffer_head(0), _tx_buffer_tail(0)
 7ea:	84 e0       	ldi	r24, 0x04	; 4
 7ec:	91 e0       	ldi	r25, 0x01	; 1
 7ee:	91 83       	std	Z+1, r25	; 0x01
 7f0:	80 83       	st	Z, r24
 7f2:	85 ec       	ldi	r24, 0xC5	; 197
 7f4:	90 e0       	ldi	r25, 0x00	; 0
 7f6:	95 87       	std	Z+13, r25	; 0x0d
 7f8:	84 87       	std	Z+12, r24	; 0x0c
 7fa:	84 ec       	ldi	r24, 0xC4	; 196
 7fc:	90 e0       	ldi	r25, 0x00	; 0
 7fe:	97 87       	std	Z+15, r25	; 0x0f
 800:	86 87       	std	Z+14, r24	; 0x0e
 802:	80 ec       	ldi	r24, 0xC0	; 192
 804:	90 e0       	ldi	r25, 0x00	; 0
 806:	91 8b       	std	Z+17, r25	; 0x11
 808:	80 8b       	std	Z+16, r24	; 0x10
 80a:	81 ec       	ldi	r24, 0xC1	; 193
 80c:	90 e0       	ldi	r25, 0x00	; 0
 80e:	93 8b       	std	Z+19, r25	; 0x13
 810:	82 8b       	std	Z+18, r24	; 0x12
 812:	82 ec       	ldi	r24, 0xC2	; 194
 814:	90 e0       	ldi	r25, 0x00	; 0
 816:	95 8b       	std	Z+21, r25	; 0x15
 818:	84 8b       	std	Z+20, r24	; 0x14
 81a:	86 ec       	ldi	r24, 0xC6	; 198
 81c:	90 e0       	ldi	r25, 0x00	; 0
 81e:	97 8b       	std	Z+23, r25	; 0x17
 820:	86 8b       	std	Z+22, r24	; 0x16
 822:	11 8e       	std	Z+25, r1	; 0x19
 824:	12 8e       	std	Z+26, r1	; 0x1a
 826:	13 8e       	std	Z+27, r1	; 0x1b
 828:	14 8e       	std	Z+28, r1	; 0x1c

// Function that can be weakly referenced by serialEventRun to prevent
// pulling in this file if it's not otherwise used.
bool Serial0_available() {
  return Serial.available();
}
 82a:	08 95       	ret

0000082c <__udivmodsi4>:
 82c:	a1 e2       	ldi	r26, 0x21	; 33
 82e:	1a 2e       	mov	r1, r26
 830:	aa 1b       	sub	r26, r26
 832:	bb 1b       	sub	r27, r27
 834:	fd 01       	movw	r30, r26
 836:	0d c0       	rjmp	.+26     	; 0x852 <__udivmodsi4_ep>

00000838 <__udivmodsi4_loop>:
 838:	aa 1f       	adc	r26, r26
 83a:	bb 1f       	adc	r27, r27
 83c:	ee 1f       	adc	r30, r30
 83e:	ff 1f       	adc	r31, r31
 840:	a2 17       	cp	r26, r18
 842:	b3 07       	cpc	r27, r19
 844:	e4 07       	cpc	r30, r20
 846:	f5 07       	cpc	r31, r21
 848:	20 f0       	brcs	.+8      	; 0x852 <__udivmodsi4_ep>
 84a:	a2 1b       	sub	r26, r18
 84c:	b3 0b       	sbc	r27, r19
 84e:	e4 0b       	sbc	r30, r20
 850:	f5 0b       	sbc	r31, r21

00000852 <__udivmodsi4_ep>:
 852:	66 1f       	adc	r22, r22
 854:	77 1f       	adc	r23, r23
 856:	88 1f       	adc	r24, r24
 858:	99 1f       	adc	r25, r25
 85a:	1a 94       	dec	r1
 85c:	69 f7       	brne	.-38     	; 0x838 <__udivmodsi4_loop>
 85e:	60 95       	com	r22
 860:	70 95       	com	r23
 862:	80 95       	com	r24
 864:	90 95       	com	r25
 866:	9b 01       	movw	r18, r22
 868:	ac 01       	movw	r20, r24
 86a:	bd 01       	movw	r22, r26
 86c:	cf 01       	movw	r24, r30
 86e:	08 95       	ret

00000870 <__tablejump2__>:
 870:	ee 0f       	add	r30, r30
 872:	ff 1f       	adc	r31, r31
 874:	05 90       	lpm	r0, Z+
 876:	f4 91       	lpm	r31, Z
 878:	e0 2d       	mov	r30, r0
 87a:	09 94       	ijmp

0000087c <_exit>:
 87c:	f8 94       	cli

0000087e <__stop_program>:
 87e:	ff cf       	rjmp	.-2      	; 0x87e <__stop_program>

OK.

So when you say 'FYA' what do you actually mean by that, you did not say ?

Many different meanings of the abreviation FYA;

https://www.abbreviations.com/FYA

I presume you are referring to this thread?

I am afraid there is very little to understand, from the same thread:

Let's just hope it's irritable vowel syndrome, and the A should be an I

Very interesting. If I'm reading it right, in both cases, it is passing a hard-coded value, first time a zero, second time a one. It never reads flag at all!

My guess: since flag is never initialized, the compiler forces its initial read value to zero, using the ldi, r24, 1; This behavior would be expected were flag a global, so makes sense to mimic the global behavior when it is local. How/why it then forces the second read to a value of 1 is a mystery to me.

Serial.print("flag before          "); Serial.println(flag);   //<<<<<<<<<===========
 74a:	90 e0       	ldi	r25, 0x00	; 0
 74c:	80 e0       	ldi	r24, 0x00	; 0
 74e:	0e 94 a1 01 	call	0x342	; 0x342 <_ZN5Print7printlnEii.constprop.8>

  if (xx > 100) {
 752:	c5 36       	cpi	r28, 0x65	; 101
 754:	d1 05       	cpc	r29, r1
 756:	44 f0       	brlt	.+16     	; 0x768 <main+0x1d8>
 758:	88 e4       	ldi	r24, 0x48	; 72
 75a:	91 e0       	ldi	r25, 0x01	; 1
 75c:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
 760:	82 e1       	ldi	r24, 0x12	; 18
 762:	91 e0       	ldi	r25, 0x01	; 1
 764:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
 768:	83 e5       	ldi	r24, 0x53	; 83
 76a:	91 e0       	ldi	r25, 0x01	; 1
 76c:	0e 94 94 01 	call	0x328	; 0x328 <_ZN5Print5writeEPKc.part.2.constprop.16>
    Serial.println("       WTF");  // Serial.flush(); for (; ;);
    flag = true;
  }

  Serial.print("flag after           "); Serial.println(flag);   //<<<<<<<<<===========
 770:	81 e0       	ldi	r24, 0x01	; 1
 772:	90 e0       	ldi	r25, 0x00	; 0
 774:	0e 94 a1 01 	call	0x342	; 0x342 <_ZN5Print7printlnEii.constprop.8>

You cannot reason about Undefined Behavior like that. Modern optimizers are much more sophisticated. The compiler isn't trying to "mimic" the behavior of a global flag, it's applying its many optimizer rules in different passes. If the one of the preconditions of any of the rules is violated, it generates incorrect code that is further mangled by subsequent passes.

I was thinking it means For Your Amusement

1 Like

Yes, for your amusement. Which according to the link, is the most likely interpretation in the "computing abbreviations" context.


So, yes, an uninitialised local variable. Many fixes.

Give it an explicit value. I like this, sometimes I will use an initial value even if I know the language would supply one by default, for clarity. Here setting flag to false would make sense in the original code.

Make it static, then it gets the default value.

Make it global, again then automatically begins life as false. In this case, for clarity, I would set to flase at the top of the loop, even though the original code used the set flag to do something, and cleared it to indicate it had done.

And I always marvel at the "undefined behaviour" thing. I kinda like it, even when it has caused grief.

I was surprised to see not just a wrong value, but a capricious one. And I wonder why I got no warnings until the Universe decided it was time to start. Warning me.

I should have said I have made the sketch small enough, and just about anything I do breaks its brokeness. I had some real life stuff that was looking more and more like what I should be doing. Thanks for boiling it down even further.

And thanks for making me learn how to add more compiler flags. In other places it is easier. I use

-Wall -Wextra -Wshadow

typically. II'll try pedantic but I'm pretty sure the IDE would run out of red ink on my code. :expressionless:

I'm just glad I figured it out, I knew there had to be something I was missing and it would not have been fun to see the heavies land on it in 47 seconds. Bad enough I did the mistake at all, some redemption from finding it myself.

It was close, though. The straw-clutch test of making the variable global occurred to me first. My inability to let that explain the change in behaviour wrankled, so I kept at it until I noticed the failure to assign any initial value no matter automatically or explcitly. By this time I was playing in the simulator, where I don't get warnings. I wanted to see it do it on a real board. That's when I saw the red ink, and that's when I confirmed I had not missed the red ink working with the real sketch.

Imma just mark #2 as a solution but I have learned (or been reminded of) many things from all of you sofa in this thread.

a7

Indeed. That was it from 1 year ago. I see now that it was a slightly different case because the rubbish got squeezed into the bool at runtime and the compiler would not have "known" that this was going to happen, but the effects were similarly perplexing.

Interesting, Before that, I had thought that automatic variables, if unset, simply inherited the contents of the storage location that was assigned to them.