Skip to content

Commit a19602f

Browse files
committed
updating readme, fixing help functions
1 parent 22a869c commit a19602f

File tree

5 files changed

+89
-55
lines changed

5 files changed

+89
-55
lines changed

README.md

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,84 @@
11
# isp-programmer
22
ISP Programmer for NXP Cortex-M Chips
33

4-
Command line programmer for the NXP ISP interface.
4+
Command-line tool for programming NXP microcontrollers via the UART ISP interface.
55

66
## Features
77
### Secure Write
8-
The checksum in flash is written to zero as the first write, so if the upload
9-
fails the chip will boot back into the ISP mode.
10-
The image is then written from the top most page down to the first page.
11-
The first sector contains the valid image checksum so a failed write will
12-
keep the device in ISP mode instead of just being bricked.
138

9+
To prevent bricking the chip during an interrupted write:
10+
11+
- The checksum in flash is first set to zero, forcing the chip to boot into ISP mode if power is lost.
12+
- The image is then written from the topmost page down to the first page.
13+
- The first sector (which contains the valid checksum) is written last.
14+
15+
This ensures that any failure during programming will leave the chip in ISP mode.
1416

1517
## Chip Families Supported:
18+
+ LPC80x
19+
+ LPC802
20+
+ LPC804
21+
+ LPC82x
22+
+ LPC822
23+
+ LPC824
1624
+ LPC84x
17-
+ LPC82x
18-
+ LPC80x
25+
+ LPC844
26+
+ LPC845
27+
28+
### Untested, expected to work
29+
+ LPC81x
30+
+ LPC810
31+
+ LPC811
32+
+ LPC812
33+
+ LPC83x
34+
+ LPC832
35+
+ LPC834
36+
+ LPC86x
37+
+ LPC865
1938

2039
Chips using UU-encoded protocols (e.g., LPC1700 family) are not supported.
21-
Other NXP devices with 1 kB sector sizes may work by adding their configuration to the lpctools_parts.def file.
40+
Other NXP devices with 1 kB sectors *may* work if added to the `lpctools_parts.def` file.
41+
2242
The configuration file is identical to that used by the [lpctools project](http://git.techno-innov.fr/?p=lpctools).
2343

24-
## Usage
25-
### Erase Entire Flash
44+
## Installation
45+
46+
### From PyPI
47+
2648
```bash
27-
isp_programmer --device /dev/ttyUSB0 -b 9600 -crystal_frequency 12000 masserase
49+
pip install isp_programmer
2850
```
2951

30-
### Program Flash
52+
### From Source
3153
```bash
32-
isp_programmer --device /dev/ttyUSB0 -b 9600 -crystal_frequency 12000 writeimage --imagein blinky804.hex
54+
git clone https://github.com/snhobbs/isp-programmer.git
55+
cd isp-programmer
56+
pip install .
3357
```
3458

35-
### Read Chip Info
59+
> Default chip definitions are bundled. For custom chips, use the --config-file flag or copy your lpctools_parts.def to /etc/lpctools_parts.def.
60+
61+
62+
## Usage
63+
### Erase Entire Flash
3664
```bash
37-
isp_programmer --device /dev/ttyUSB0 -b 9600 -crystal_frequency 12000 querychip
65+
isp_programmer --device /dev/ttyUSB0 -b 9600 -crystal_frequency 12000 masserase
3866
```
3967

40-
## Installation
41-
### pypi
68+
### Program Flash Image
4269
```bash
43-
pip install isp_programmer
70+
isp_programmer --device /dev/ttyUSB0 -b 9600 -crystal_frequency 12000 writeimage --imagein blinky804.hex
4471
```
4572

46-
### From Source
73+
### Read Chip Info
4774
```bash
48-
git clone https://github.com/snhobbs/isp-programmer.git
49-
cd isp-programmer
50-
pip install .
75+
isp_programmer --device /dev/ttyUSB0 -b 9600 -crystal_frequency 12000 querychip
5176
```
5277

53-
The default location for the configuration file is at /etc/lpctools_parts.def.
54-
The file can either be copied there or the path passed in when calling the tool
55-
with the --config_file/-f flag. If none is given or found then the default parts are still available.
56-
5778
## Similar Projects
58-
+ https://github.com/JitterCompany/mxli
59-
+ https://github.com/idreamoferp/nxp_isp
60-
+ https://github.com/pzn1977/nxp_isp_loader
61-
+ https://github.com/laneboysrc/LPC81x-ISP-tool
62-
+ https://github.com/Senseg/lpc21isp
63-
+ https://github.com/ulfen/nxpprog
79+
+ [MXLI by JitterCompany](https://github.com/JitterCompany/mxli)
80+
+ [NXP ISP by idreamoferp](https://github.com/idreamoferp/nxp_isp)
81+
+ [NXP ISP Loader by pzn1977](https://github.com/pzn1977/nxp_isp_loader)
82+
+ [LPC81x ISP Tool by laneboysrc](https://github.com/laneboysrc/LPC81x-ISP-tool)
83+
+ [LPC21ISP by Senseg](https://github.com/Senseg/lpc21isp)
84+
+ [Nxpprog by ulfen](https://github.com/ulfen/nxpprog)

src/isp_programmer/cli.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ def gr1(ctx, **kwargs):
5252
_log.setLevel(level)
5353

5454

55-
@gr1.command("sync", help="Read the chip ID and boot code")
55+
@gr1.command("sync", help="Synchronize connection to chip")
5656
@click.pass_context
5757
def cli_sync(ctx):
5858
iodevice = UartDevice(ctx.obj["device"], baudrate=ctx.obj["baud"])
5959
isp = ISPConnection(iodevice)
6060
isp.SyncConnection()
6161

6262

63-
@gr1.command("query-chip", help="Read the chip ID and boot code")
63+
@gr1.command("query-chip", help="Read chip Part ID, UID, and boot code version")
6464
@click.pass_context
6565
def cli_QueryChip(ctx):
6666
iodevice = UartDevice(ctx.obj["device"], baudrate=ctx.obj["baud"])
@@ -87,9 +87,7 @@ def cli_MassErase(ctx):
8787
_log.info("Mass Erase Successful")
8888

8989

90-
@click.option(
91-
"--start_sector", type=int, default=0, required=True, help="Sector to write to"
92-
)
90+
@click.option("--start_sector", type=int, default=0, help="Sector to write to")
9391
@click.option(
9492
"--imagein", type=str, required=True, help="Location of hex file to program"
9593
)

src/isp_programmer/lpctools_parts.def

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
0x00008044, LPC804M101JHI33, 0x00000000, 0x08000, 32, 0x04, 0x10000000, 0x1000, 0x800, 0x400, 0
2222

2323
# LPC84x
24+
0x00008442, LPC844M301JBD48, 0x00000000, 0x10000, 32, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
25+
0x00008441, LPC844M301JBD64, 0x00000000, 0x10000, 32, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
26+
0x00008444, LPC844M301JHI33, 0x00000000, 0x10000, 32, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
27+
0x00008443, LPC844M301JHI48, 0x00000000, 0x10000, 32, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
28+
2429
0x00008452, LPC845M301JBD48, 0x00000000, 0x10000, 64, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
2530
0x00008451, LPC845M301JBD64, 0x00000000, 0x10000, 64, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
2631
0x00008454, LPC845M301JHI33, 0x00000000, 0x10000, 64, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 0
@@ -29,14 +34,14 @@
2934
# LPC81X Family
3035
0x00008100, LPC810M021FN8, 0x00000000, 0x1000, 4, 0x04, 0x10000000, 0x0400, 0x300, 0x100, 0
3136
0x00008122, LPC812M101JDH20, 0x00000000, 0x4000, 16, 0x04, 0x10000000, 0x1000, 0x800, 0x400, 0
32-
#
37+
3338
# LPC11XX Family
3439
0x2540102B, LPC1114FHN33/302, 0x00000000, 0x8000, 8, 0x04, 0x10000000, 0x2000, 0x800, 0x400, 1
3540
0x4d80002b, LPC11A04UK, 0x00000000, 0x8000, 8, 0x04, 0x10000000, 0x2000, 0x800, 0x400, 1
36-
#
41+
3742
# LPC12XX Family
3843
0x3640C02B, LPC1224FBD48/101, 0x00000000, 0x8000, 8, 0x04, 0x10000000, 0x1000, 0x800, 0x400, 1
39-
#
44+
4045
# LPC17XX Family
4146
0x26011922, LPC1764FBD100, 0x00000000, 0x10000, 16, 0x04, 0x10000000, 0x4000, 0x800, 0x800, 1
4247

src/isp_programmer/parts_definitions.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
consistent with other formats
44
"""
55

6+
from typing import Dict, List
7+
68
column_names = [
79
"part id",
810
"name",
@@ -21,7 +23,7 @@
2123
]
2224

2325

24-
def read_lpcparts_string(string: str) -> dict[str, list]:
26+
def read_lpcparts_string(string: str) -> Dict[str, List]:
2527
lpc_tools_column_locations = {
2628
"part id": 0,
2729
"name": 1,
@@ -77,28 +79,27 @@ def ReadChipFile(fname: str) -> dict:
7779
return df
7880

7981

80-
def GetPartDescriptorLine(fname: str, partid: int) -> dict[str, str]:
82+
def GetPartDescriptorLine(fname: str, partid: int) -> Dict[str, str]:
8183
entries = ReadChipFile(fname)
8284
for i, line_part_id in enumerate(entries["part id"]):
8385
if partid == line_part_id:
8486
return {key: entries[key][i] for key in entries}
85-
raise UserWarning(f"PartId {partid} not found in {fname}")
87+
raise ValueError(f"PartId {hex(partid)} not found in {fname}")
8688

8789

8890
def GetPartDescriptor(fname: str, partid: int) -> dict[str, str]:
8991
# FIXME redundant function
9092
descriptor = GetPartDescriptorLine(fname, partid)
91-
if descriptor is None:
92-
raise UserWarning("Warning chip %s not found in file %s" % (hex(partid), fname))
9393
return descriptor
9494

9595

9696
def check_parts_definition_dataframe(df):
9797
"""
98-
Takes the standard layout dataframe, check the field validity
98+
Takes the standard layout dataframe, check the field validity.
99+
Works with dict or DataFrame
99100
"""
100101
valid = True
101-
for _, line in df.iterrows():
102-
if line["RAMRange"][1] - line["RAMRange"][0] + 1 != line["RAMSize"]:
102+
for start, end, size in zip(df["RAMStart"], df["RAMEnd"], df["RAMSize"]):
103+
if end - start + 1 != size:
103104
valid = False
104105
return valid

src/isp_programmer/tools.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@
33
from pycrc.algorithms import Crc
44

55

6-
def collection_to_string(arr):
6+
def collection_to_string(arr) -> str:
7+
"""Convert a list of integer character codes to a string."""
78
return "".join([chr(ch) for ch in arr])
89

910

10-
# 2s compliment of checksum
1111
def CalculateCheckSum(frame) -> int:
12+
"""
13+
Calculate 2's complement checksum of the sum of frame entries.
14+
Assumes 'frame' is an iterable of integers.
15+
"""
1216
csum = 0
1317
for entry in frame:
1418
csum += entry
1519
return (1 << 32) - (csum % (1 << 32))
1620

1721

18-
def Crc32(frame: bytes) -> int:
19-
# CRC32
22+
def nxp_crc32(frame: bytes) -> int:
23+
"""
24+
Calculate CRC32 using pycrc with standard polynomial.
25+
Note: polynomial here is 0x104C11DB6, which is non-standard (33 bits).
26+
"""
2027
polynomial = 0x104C11DB6
2128
crc = Crc(
2229
width=32,
@@ -31,9 +38,11 @@ def Crc32(frame: bytes) -> int:
3138

3239

3340
def calc_crc(frame: bytes):
41+
"""Calculate CRC32 using zlib (fast, standard)."""
42+
# 0x04C11DB7
3443
return zlib.crc32(frame, 0)
35-
# return Crc32(frame)
3644

3745

38-
def calc_sector_count(image, sector_bytes):
46+
def calc_sector_count(image, sector_bytes: int) -> int:
47+
"""Calculate number of sectors needed to store the image."""
3948
return int(math.ceil(len(image) / sector_bytes))

0 commit comments

Comments
 (0)