Electronic – How to instruct the compiler to use 8 bit bytes instead of 16 bit integers

assemblyattinycembeddedoptimization

I have the following code in my microcontroler program:

int analogValue = ADCH;        // ADC Data Register

//
// Simple analog comparator. 
// If analogValue lower than threshold then toggle output high,
// Otherwise toggle it low.
//
if ( analogValue > 128 ) {
    PORTB = 0;                 // Port B Data Register
} else {
    PORTB = _BS( outputPin );  // Port B Data Register
}

Where:

  • ADCH is the register that contains the value from the ADC
  • PORTB is a dital output port that toggles an LED

Looking at the resulting assembly code, I noticed that it is doing a 16 bit compare (lines 40-44) where strictly speaking only 8 bits would have been sufficient:

40:   90 e0           ldi     r25, 0x00       ; 0
42:   81 38           cpi     r24, 0x81       ; 129
44:   91 05           cpc     r25, r1
46:   14 f0           brlt    .+4             ; 0x4c <__SREG__+0xd>
48:   18 ba           out     0x18, r1        ; PORTB
4a:   f5 cf           rjmp    .-22            ; 0x36 <__CCP__+0x2>
4c:   28 bb           out     0x18, r18       ; PORTB
4e:   f3 cf           rjmp    .-26            ; 0x36 <__CCP__+0x2>

I realize I declared analogValue as int, which indeed is 16 bit on AVR, but …

How can I instruct the compiler to use 8 bit comparison? The Arduino IDE allows me to use byte, but avr-gcc by default doesn't.

Check this page for the complete program and its disassembled resulting code.

EDIT1:

Changing int to char changes the assembly code to:

14:   11 24           eor     r1, r1          ; r1 = 0
3e:   18 ba           out     0x18, r1        ; PORTB

Basically skipping the test entirely.

EDIT2: (Thnx: Wouter van Ooijen)

Changing int to unsigned char changes the assembly code to:

3c:   85 b1           in      r24, 0x05       ; ADCH
3e:   ...
40:   87 fd           sbrc    r24, 7          ; compare < 128 (well optimized)
42:   02 c0           rjmp    .+4             ; 0x48 <__SREG__+0x9>
44:   18 ba           out     0x18, r1        ; 24
46:   f7 cf           rjmp    .-18            ; 0x36 <__CCP__+0x2>
48:   98 bb           out     0x18, r25       ; 24
4a:   f5 cf           rjmp    .-22            ; 0x36 <__CCP__+0x2>

Best Answer

I actually think a better practice that avoids this architectural ambiguity is to include <stdint.h> then use declarative types like:

  • uint8_t for unsigned 8-bit integers
  • int8_t for signed 8-bit integers
  • uint16_t for unsigned 16-bit integers
  • uint32_t for unsigned 32-bit integers

and so on...