summaryrefslogtreecommitdiff
path: root/util/flash_jlink.py
blob: 160c25e9dfd566d14184e517f7621bfcbd651097 (plain)
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
#!/usr/bin/env python

# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Flashes firmware using Segger J-Link.

This script requires Segger hardware attached via JTAG/SWD.
"""
import argparse
import logging
import os
import subprocess
import sys
import tempfile

JLINK_COMMANDS = '''
r
loadfile {FIRMWARE}
go
exit
'''


class BoardConfig:
    def __init__(self, interface, device):
        self.interface = interface
        self.device = device


SWD_INTERFACE = 'SWD'
DRAGONCLAW_CONFIG = BoardConfig(interface=SWD_INTERFACE, device='STM32F412CG')
ICETOWER_CONFIG = BoardConfig(interface=SWD_INTERFACE, device='STM32H743ZI')

BOARD_CONFIGS = {
  'dragonclaw': DRAGONCLAW_CONFIG,
  'bloonchipper': DRAGONCLAW_CONFIG,
  'dartmonkey': ICETOWER_CONFIG,
  'icetower': ICETOWER_CONFIG,
}


def create_jlink_command_file(firmware_file):
    tmp = tempfile.NamedTemporaryFile()
    tmp.write(JLINK_COMMANDS.format(FIRMWARE=firmware_file).encode('utf-8'))
    tmp.flush()
    return tmp


def flash(jlink_exe, ip, device, interface, cmd_file):
    cmd = [
      jlink_exe,
      '-ip', ip,
      '-device', device,
      '-if', interface,
      '-speed', 'auto',
      '-autoconnect', '1',
      '-CommandFile', cmd_file
    ]
    logging.debug('Running command: "%s"', ' '.join(cmd))
    subprocess.run(cmd)


def main():
    parser = argparse.ArgumentParser()

    default_jlink = './JLink_Linux_V670e_x86_64/JLinkExe'
    parser.add_argument(
        '--jlink', '-j',
        help='JLinkExe path (default: ' + default_jlink + ')',
        default=default_jlink)

    default_ip = '127.0.0.1:2551'
    parser.add_argument(
        '--ip', '-n',
        help='IP address of J-Link or machine running JLinkRemoteServerCLExe '
             '(default: ' + default_ip + ')',
        default=default_ip)

    default_board = 'bloonchipper'
    parser.add_argument(
        '--board', '-b',
        help='Board (default: ' + default_board + ')',
        default=default_board)

    default_firmware = os.path.join('./build', default_board, 'ec.bin')
    parser.add_argument(
        '--image', '-i',
        help='Firmware binary (default: ' + default_firmware + ')',
        default=default_firmware)

    log_level_choices = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
    parser.add_argument(
        '--log_level', '-l',
        choices=log_level_choices,
        default='DEBUG'
    )

    args = parser.parse_args()
    logging.basicConfig(level=args.log_level)

    if args.board not in BOARD_CONFIGS:
        logging.error('Unable to find a config for board: "%s"', args.board)
        sys.exit(1)

    config = BOARD_CONFIGS[args.board]

    args.image = os.path.realpath(args.image)
    args.jlink = os.path.realpath(args.jlink)

    cmd_file = create_jlink_command_file(args.image)
    flash(args.jlink, args.ip, config.device, config.interface, cmd_file.name)
    cmd_file.close()


if __name__ == '__main__':
  sys.exit(main())