1. Lab preparation

Reminder to watch the videos linked in day06 - §1. Preparation

Become familiar with the content available at RJHcoding.com - AVR Assembly Tutorials. Notice that we’ve effectively looked at Example Programs #1 and #3 already, though those are intended for the ATmega328P MCU.

Part of the Lab 1 activity has to do with how you create “functions” in assembly, which are called subroutines.

Compare the two different toggle-a-pin implementations:

Some major differences to note are

  • 16-bit versus 8-bit down counter for the inner loop.

  • Exclusive-OR two registers, then store to PORTB with a single delay block versus
    Set and clear register bit with two functionally identical delay blocks.

  • RJH uses assembly for the ATmega328P while we are using the ATtiny85.

Are there any instructions that the 'mega can execute that are not available in the 'tiny? Figure this out by studying the AVR-instruction-set-manual_2021.pdf. Section 7.1 Core Descriptions on page 149 and the following Device Tables provide the information about the specific AVR instruction set variants each of these MCUs use.

3. Another branch

Modify the sbi/cbi “slow-blink” day06 code to use a different branch instruction (BR__) instead of BREQ.

To better understand what branch instructions do and when they jump versus when they fall through, please read

SR bits C, Z, and S, are especially useful for decision making.

Detecting any result other than zero requires some more work with the CPU. Changing from the BREQ to a different branch condition requires first setting the appropriate status register bits, then branching on its value.

Instructions for setting SR bits with the result a comparison operation:

  • CP

  • CPI

An idea to consider:

  • Setting a register to (256 - x) and then incrementing the register via inc will overflow in x steps.

4. Subroutines

Convert the two explicit delay double-loops from “slow-blink” to call a single delay subroutine twice.

From the excellent site RJHcoding.com - AVR Assembly Tutorials, please read:

Instead of using hard-coded constants, use the .equ assembler directive to define symbols for the inner and outer loop iteration counts:

.equ INNER_COUNT = 0xFF  ; 8b unsigned
.equ OUTER_COUNT = 0xFF  ; 8b unsigned

...

Main:
    ; set pin high
    sbi ...
    rcall Delay

    ;set pin low
    cbi ...
    rcall Delay

    rjmp Main


Delay:
    ; <delay code here>
    ret  ;return from subroutine

5. blinkfast

Write a program that toggles an ATtiny85 output pin with exactly 50% duty cycle as fast as possible (no timer or other peripheral).
attiny fastest blink
Figure 1. Output waveform with 4 CLK duration

Before you think that the code that pulls off the blistering speed of Figure 1 is perfect, understand that it has one flaw — a glitch every once in a while. The exact periodic interval remains a trade secret since it would give away the solution.

5.1. Special oscilloscope triggering modes

Because the glitch happens less than 0.1% of the time, it can be difficult to actually see or capture.

Enter the many other triggering modes of the Scope in Waveforms (and other nice oscilloscopes).

Consider Figure 2 and see that the low time of PB3 is indeed low for 4 μs, double of the normal 2 μs for a 50% duty-cycle 250 kHz waveform.

The trigger settings are all of the dropdown boxes from Mode: to HoldOff:. Clicking tiny green up-arrow on the right side of this area will collapse the advanced settings, as per the mouse-over text hint.

This particular trigger condition was set up to look for a low (negative) pulse whose duration was more than 3 μs. Determining what is "low" or "high" is set by the level of 2 V with a hysteresis of ±100 mV.

attiny fastest glitch
Figure 2. Glitch in output waveform