ATtiny Assembly
The following sections give some tips on programming the ATtiny10(and series).
LDI R16, 0b0101
OUT DDRB, R16 ; Equivalent to pinMode(1, OUTPUT); pinMode(3, OUTPUT);
Unlike the older AVR chips, such as the ATmega328 and ATtiny85, the ATtiny10 enables pullup resistors using a separate pullup register, PUEB. To set pullups on input pins you set the corresponding bits in this register. For example, to set a pullup resistor on input pin 2:
LDI R16, 0b0010
OUT PUEB, R16 ; Equivalent to pinMode(2, INPUT_PULLUP);
digitalWrite To set the state of an output you set the corresponding bits in the PORTB register. For example, to set bit 1 low and bit 3 high (assuming they have been defined as outputs):
LDI R16, 0b0100
OUT PORTB, R16 ; Equivalent to digitalWrite(1, LOW); digitalWrite(3, HIGH);
digitalRead To read the state of the I/O pins you read the PINB register:
IN R16, PINB
PWM You can use OC0A (PB0) and OC0B (PB1) for PWM output. You first need to configure the Timer/Counter into PWM mode for that pin; for example, using PB0 in C:
TCCR0A = 2<<COM0A0 | 3<<WGM00; // 10-bit PWM on OC0A (PB0), non-inverting mode
TCCR0B = 0<<WGM02 | 1<<CS00; // Divide clock by 1
DDRB = 0b0001; // Make PB0 an output
To output we write the value to the appropriate output compare register, OCR0A:
OCR0A = 1000; // Equivalent to analogWrite(0, 1000)
//With a 5V supply this will set PB0 to 1000/1024 * 5V, or 4.88V.
In assembly
;Too large check separate repo
To use an I/O pin for analogue input you first need to configure the Analogue-to-Digital Converter. For example, to use ADC0 in C:
ADMUX = 0<<MUX0; // ADC0 (PB0)
ADCSRA = 1<<ADEN | 3<<ADPS0; // Enable ADC, 125kHz clock
//To read an analogue value from the pin we then need to start a conversion, and when the conversion is ready read the ADC register:
ADCSRA = ADCSRA | 1<<ADSC; // Start
while (ADCSRA & 1<<ADSC); // Wait while conversion in progress
int temp = ADCL; // Copy result to temp
In assembly :
.CSEG
.ORG 0x0000
Start:
; Set clock divider
LDI R16, 0x0011 ; clock divided by 8 for 1MHz (0x00 divides by 1 - RUNS AT 8MHz)
LDI R17, 0xD8 ; the key for CCP
OUT CCP, R17 ; Configuration Change Protection, allowsprotected changes
OUT CLKPSR, R16 ; sets the clock divider
; Initialize and setup ADC once
INIT_ADC:
; set up the ADC
; ADCSRA contains [ADEN, ADSC, ADATE, ADIF, ADIE, ADPS2, ADPS1, ADPS0]
; which means: enable, start, trigger enable, int flag, int enable, clock prescaler
;
; ADCSRB contains [-,-,-,-,-,ADTS2, ADTS1, ADTS0]
; means: auto trigger soure 0=free running, 1=analog comparator, 2=int0, 3,5=timer comp. A,B,
; 4=tmer overflow, 6=pinchange int, 7=timer capture
;
; ADMUX contains [-,-,-,-,-,-,MUX1,MUX0]
; sets the channel(pin) for conversion
;
; DIDR0 contains [-,-,-,-,ADC3D to ADC0D]
; disables the digital input, not necessary, but uses less power
LDI R17, (1<<ADC1D) ; disable digital on PB1
OUT DIDR0, R17
LDI R18, (1<<MUX0) ; Analog Channel: ADC1 admux=>01 (PB1)
OUT ADMUX, R18
LDI R20, 0b10000110 ; Enable ADC, ADC prescaler CLK/64
OUT ADCSRA, R20
; FOR INTERRUPT
;LDI R19, 0x00 ; Free Running mode
;OUT ADCSRB, R19
;LDI R20, (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE) ; enable, start, trigger, int enable, prescaler=2(min)
;OUT ADCSRA, R20
; To be Looped
REPEAT:
READ_ADC:
LDI R16, 0b01000000 ; Set ADSC in ADCSRA to start conversion
IN R17, ADCSRA ;
OR R17, R16 ;
OUT ADCSRA, R17
WAIT_ADC:
IN R16, ADCSRA ; check ADIF flag in ADCSRA
SBRS R16, 4 ; skip jump when conversion is done (flag set)
RJMP WAIT_ADC ; loop until ADIF flag is set
LDI R17, 0b00010000 ; Set the flag again to signal 'ready-to-be-cleared' by hardware
IN R18, ADCSRA ;
OR R18, R17 ;
OUT ADCSRA, R18 ; so that controller clears ADIF
IN R18, ADCL
; do cool stuff with read value :)
RJMP REPEAT
;-----------------------------------------------------------------------
Run the blink.asm file