-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathprogram.py
More file actions
executable file
·183 lines (175 loc) · 7.69 KB
/
Copy pathprogram.py
File metadata and controls
executable file
·183 lines (175 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/usr/bin/env python3
from pylibftdi import BitBangDevice
from pylibftdi.driver import BITMODE_SYNCBB
from time import sleep
import argparse
parser = argparse.ArgumentParser(description=
'Program ATMEGA162 through JTAG interface connected to an FT232R')
parser.add_argument('--noverify', action='store_true',
help='Do not verify after programming')
parser.add_argument('elffile', help='.elf file to program in FLASH')
args = parser.parse_args()
dev = BitBangDevice(bitbang_mode=BITMODE_SYNCBB)
TMS = 1 << 4
TDI = 1 << 2
TDO = 1 << 3
TCK = 1 << 5
dev.direction = TMS | TDI | TCK
from math import ceil
from enum import Enum
def jtag_command(instruction, data):
"""Set the instruction register, shift in bits from data, return the output bits
data[0] holds the least significant bits"""
if not isinstance(instruction, AVR_JTAG):
raise ValueError("instruction must be member of AVR_JTAG")
irvalue = instruction.value[0]
nbits = instruction.value[1]
if isinstance(data, int):
data = data.to_bytes(ceil(nbits/8), 'little')
stream = [0]
IR_LENGTH = 4
def clock_in(bits):
"""Output bits then raise TCK.
Returns index of (input state after the rising TCK edge) in the response array."""
stream.append(bits)
stream.append(bits+TCK)
return len(stream)
# Take TAP controller from Test-Logic-Reset to Run-Test/Idle
for ii in range(2):
clock_in(0)
# Take TAP to Shift-IR
for tms in [1,1,0,0]:
clock_in(tms * TMS)
# Shift IDCODE (0x1) into IR
for bit in range(IR_LENGTH):
clock_in((irvalue & 1) * TDI)
irvalue >>= 1
# MSB of IR is shifted with TMS high
stream[-2] |= TMS
stream[-1] |= TMS
# Take TAP to Run-Test/Idle, then Shift-DR
for tms in [1,0,1,0,0]:
clock_in(tms * TMS)
# Shift out nbits of data register
# data[0] is LSB
retindex = None
for bit in range(nbits):
byte = int(bit / 8)
if byte < len(data):
ret = clock_in(TDI*bool(
(data[byte] >> (bit%8)) & 1))
else:
# Pad with zeros
ret = clock_in(0)
if bit == 0:
retindex = ret
#data[int(bit / 8)] >>= 1
# MSB of DR is shifted with TMS high
stream[-2] |= TMS
stream[-1] |= TMS
# Take TAP to Run-Test/Idle
for tms in [1,0]:
clock_in(tms * TMS)
clock_in(0)
dev.flush()
# Return buffer
bytes = bytearray(ceil(nbits / 8))
CHUNK_SIZE = 256
read = []
for offset in range(0, len(stream), CHUNK_SIZE):
written = dev.write(bytearray(stream[offset:offset+CHUNK_SIZE]))
read.append(dev.read(written))
ret = b''.join(read)
for bit in range(nbits):
bytes[int(bit / 8)] |= bool(ret[retindex + 2 * bit] & TDO) << (bit % 8)
return bytes
class AVR_JTAG(Enum):
# (instruction register value, number of bits in selected data register)
IDCODE = (0x1, 32)
PROG_ENABLE = (0x4, 16)
PROG_COMMANDS = (0x5, 15)
PROG_PAGELOAD = (0x6, 1024)
PROG_PAGEREAD = (0x7, 1032)
AVR_RESET = (0xC, 1)
BYPASS = (0xF, 1)
from elftools.elf.elffile import ELFFile
def program_elf(file, verify=True):
"""Write executable into atmega162 program memory. Example:
>>> program('elffile')
"""
elf = ELFFile(open(file, 'rb'))
program = elf.get_section_by_name(b'.text').data()
jtag_command(AVR_JTAG.AVR_RESET, 1)
jtag_command(AVR_JTAG.PROG_ENABLE, 0xA370)
# Chip Erase
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x2380)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3180)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3380)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3380)
sleep(10e-3) # Wait for chip erase
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x2310) # Enter Flash Write
PAGE_BYTES = int(1024 / 8)
for offset in range(0, len(program), PAGE_BYTES):
address = offset >> 1 # Flash words are 2 bytes
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x0700 | (address>>8) & 0xff) # Load Address High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x0300 | address & 0xff) # Load Address Low Byte
jtag_command(AVR_JTAG.PROG_PAGELOAD, program[offset:offset+PAGE_BYTES])
# Write Flash Page
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3500)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700)
sleep(10e-3) # Wait for Flash write
if verify:
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x2302) # Enter Flash Read
for offset in range(0, len(program), PAGE_BYTES):
address = offset >> 1 # Flash words are 2 bytes
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x0700 | (address>>8) & 0xff) # Load Address High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x0300 | address & 0xff) # Load Address Low Byte
read = jtag_command(AVR_JTAG.PROG_PAGEREAD, 0)[1:]
if read[:len(program)-offset] != program[offset:offset+PAGE_BYTES]:
raise RuntimeError('Verification failed at offset {}: wrote {}, read {}'.format(
offset, program[offset:offset+PAGE_BYTES], read))
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x2300) # Exit Programming Mode
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3300) # Exit Programming Mode
jtag_command(AVR_JTAG.PROG_ENABLE, 0)
jtag_command(AVR_JTAG.AVR_RESET, 0)
def poll_fuse_write_complete():
while True:
if jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700)[1] & 2:
break
def program_fuses(fuses, extended_fuses):
if not isinstance(fuses, int):
raise TypeError('Expected int for fuses')
jtag_command(AVR_JTAG.AVR_RESET, 1)
jtag_command(AVR_JTAG.PROG_ENABLE, 0xA370)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x2340) # Enter Fuse Write
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x1300 | (extended_fuses & 0xff)) # Load Data Low Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3b00) # Write Fuse Extended Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3900) # Write Fuse Extended Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3b00) # Write Fuse Extended Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3b00) # Write Fuse Extended Byte
poll_fuse_write_complete()
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x1300 | ((fuses >> 8) & 0xff)) # Load Data Low Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700) # Write Fuse High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3500) # Write Fuse High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700) # Write Fuse High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700) # Write Fuse High Byte
poll_fuse_write_complete()
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x1300 | (fuses & 0xff)) # Load Data Low Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3300) # Write Fuse High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3100) # Write Fuse High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3300) # Write Fuse High Byte
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3300) # Write Fuse High Byte
poll_fuse_write_complete()
def read_fuses_locks():
jtag_command(AVR_JTAG.AVR_RESET, 1)
jtag_command(AVR_JTAG.PROG_ENABLE, 0xA370)
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x2304) # Enter Fuse/Lock Bit Read
jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3a00) # Read fuses and lock bits
extended = jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3e00)[0] # Read fuses and lock bits
high = jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3200)[0] # Read fuses and lock bits
low = jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3600)[0] # Read fuses and lock bits
lock = jtag_command(AVR_JTAG.PROG_COMMANDS, 0x3700)[0] # Read fuses and lock bits
return extended, high << 8 | low, lock
program_elf(args.elffile, verify=not args.noverify)