Source

ATmega-asm / Examples / Programs / Minimus / blink_timer.py

#!/usr/bin/env python

"""
blink_timer.py - Example of assembler usage.

Copyright (C) 2012 David Boddie <david@boddie.org.uk>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

# Version of the blink program that initialises the vector table to call the
# main function on reset. This verifies that the vector table can be
# initialised and used as expected.

from ATmega.definitions import *
from ATmega.assembler import *
from ATmega.instructions import *

R0 = Register(0)
R16 = Register(16)
R17 = Register(17)
R18 = Register(18)
R19 = Register(19)
R30 = Register(30)
R31 = Register(31)
X = X()
Y = Y()
Z = Z()

# See section 11 of the ATmega32U2 datasheet.

interrupt_table = [             # word address  byte address
    JMP(Reference("main")),     # 0x0000        0x00 (RESET)
    RETI(), RETI(),             # 0x0002        0x04 (INT0)
    RETI(), RETI(),             # 0x0004        0x08 (INT1)
    RETI(), RETI(),             # 0x0006        0x0c (INT2)
    RETI(), RETI(),             # 0x0008        0x10 (INT3)
    RETI(), RETI(),             # 0x000a        0x14 (INT4)
    RETI(), RETI(),             # 0x000c        0x18 (INT5)
    RETI(), RETI(),             # 0x000e        0x1c (INT6)
    RETI(), RETI(),             # 0x0010        0x20 (INT7)
    RETI(), RETI(),             # 0x0012        0x24 (PCINT0)
    RETI(), RETI(),             # 0x0014        0x28 (PCINT1)
    RETI(), RETI(),             # 0x0016        0x2c (USB General)
    RETI(), RETI(),             # 0x0018        0x30 (USB Endpoint)
    RETI(), RETI(),             # 0x001a        0x34 (WDT)
    RETI(), RETI(),             # 0x001c        0x38 (TIMER1 CAPT)
    RETI(), RETI(),             # 0x001e        0x3c (TIMER1 COMPA)
    RETI(), RETI(),             # 0x0020        0x40 (TIMER1 COMPB)
    RETI(), RETI(),             # 0x0022        0x44 (TIMER1 COMPC)
    RETI(), RETI(),             # 0x0024        0x48 (TIMER1 OVF)
    RETI(), RETI(),             # 0x0026        0x4c (TIMER0 COMPA)
    RETI(), RETI(),             # 0x0028        0x50 (TIMER0 COMPB)
    RJMP(Reference("flipPin")), # 0x002a        0x54 (TIMER0 OVF)
    RETI(),
    RETI(), RETI(),             # 0x002c        0x58 (SPI, STC)
    RETI(), RETI(),             # 0x002e        0x5c (USART1 RX)
    RETI(), RETI(),             # 0x0030        0x60 (USART1 UDRE)
    RETI(), RETI(),             # 0x0032        0x64 (USART1 TX)
    RETI(), RETI(),             # 0x0034        0x68 (ANALOG COMP)
    RETI(), RETI(),             # 0x0036        0x6c (EE READY)
    RETI(), RETI(),             # 0x0038        0x70 (SPM READY)
                                #               0x74
    ]

initCounter = [
    LDI(R16, 0),
    STS(0x100, R16)
    ]

DDRD = 0x0a
DDD5 = 0x20 # 00100000
DDD6 = 0x40 # 01000000
LED_enable = DDD5 | DDD6

PORTD = 0x0b
blue_LED = 0x40
red_LED = 0x20

initPins = [
    IN(R0, DDRD),           # R0 = (DDRD)
    LDI(R16, LED_enable),
    OR(R0, R16),            # R0 |= LED_enable
    OUT(DDRD, R0),          # (DDRD) = R0
    
    LDI(R16, blue_LED),     # turn on the blue LED
    OUT(PORTD, R16)
    ]

TCCR0A = 0x24
TCCR0B = 0x25

WGM00 = 0x01
WGM01 = 0x02

TOIE0 = 0x01
TIMSK0 = 0x006e

enableInterrupts = [
    LDI(R16, WGM01 | WGM00),    # set WGM00 and WGM01 to select Fast PWM mode
                                # (section 15.9.1)
    OUT(TCCR0A, R16),           # store TCCR0A
    OUT(TCCR0B, R16),           # store TCCR0B

    LDI(R16, TOIE0),        # set bit 0 (TOIE0 of TIMSK0) to enable overflow
                            # interrupts for timer/counter0 (page 107)
    LDI(R30, TIMSK0 & 0xff),
    LDI(R31, TIMSK0 >> 8),
    STDzi(Z, R16),

    SEI(),
    ]

flipPin = [
    "flipPin",
    LDS(R0, 0x400),
    INC(R0),
    STS(0x400, R0),
    BRNE(Reference("exit flip")),
    
    IN(R17, PORTD),
    LDI(R16, blue_LED | red_LED),
    EOR(R17, R16),
    OUT(PORTD, R17), # (PORTD) = (PORTD) ^ 0x60 (toggle LEDs)
    "exit flip",
    RETI(),
    ]

loop = ["loop",
        RJMP(Reference("loop"))
    ]

main = ["main"] + initCounter + initPins + enableInterrupts + loop

a = Assembler()

program = interrupt_table + main + flipPin

assembly = []

for address, opcode in a.assemble(0, program):
    print hex(address), opcode.text(), Lookup.lookup(opcode.value)
    assembly.append((address, opcode))

f = open("blink.hex", "w")
for line in a.write_hex(assembly):
    f.write(line)

f.close()