Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add applet for programming/reading TI/Chipcon 8051 based radios: CC111x, CC251x, CC253x, & CC254x #185

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a471e15
applet.program.chipcon: add support for reading & writing TI/chipcon …
samlittlewood Feb 18, 2020
7145721
Use globs for imports.
samlittlewood Feb 20, 2020
2b2b723
Reduce write block size to fit in smallest parts RAM.
samlittlewood Feb 20, 2020
a045a4e
Remove debug detritus - 'status' command.
samlittlewood Feb 20, 2020
e05858d
Remove speculative comments.
samlittlewood Feb 20, 2020
30a4ff0
Use IntEnum and IntFlag as appropriate.
samlittlewood Feb 20, 2020
038e7de
Get rid of debug LEDs (again).
samlittlewood Feb 20, 2020
4af9c71
Move device descriptions into glasgow.database.ti.chipcon.
samlittlewood Feb 20, 2020
9fb5efc
Combine hex records into one chuunk before writing.
samlittlewood Feb 20, 2020
b23acb4
Whitespace cleanup.
samlittlewood Feb 20, 2020
ee8f355
Tidy up variable names.
samlittlewood Feb 20, 2020
7b715d8
Use constant for write buffer address.
samlittlewood Feb 20, 2020
ee81fa0
Reworked reset and clocks/delays - all through fifo and no sleeps. So…
samlittlewood Feb 22, 2020
d5bbd1d
Cleanup remaining debris from reset and clock rework.
samlittlewood Feb 22, 2020
62a8b84
Handle writing lock bits with arguments, and cope with connecting to …
samlittlewood Feb 23, 2020
66aa35a
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Mar 2, 2020
74c227c
Extended to handle cc253x and cc254x.
samlittlewood Mar 9, 2020
a1ad15d
Heavy application of enums to get rid of inline opcode constants.
samlittlewood Mar 10, 2020
5554ed3
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Mar 10, 2020
1b98e83
Fix up typos.
samlittlewood Mar 10, 2020
7198ef2
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Mar 31, 2020
c7975e8
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Apr 6, 2020
4968b2f
Increase delay after programming page to cope with cc2430.
samlittlewood Apr 6, 2020
95227a7
Tidy up naming and docstrings.
samlittlewood Apr 6, 2020
b3df807
Tidy up whitespace and naming.
samlittlewood Apr 6, 2020
4a77938
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood May 27, 2020
ede5c32
Add dummy arguments to claim_interface in simulation.
samlittlewood May 27, 2020
79275f8
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Jul 16, 2020
175b0b7
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Jul 31, 2020
159e234
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Aug 21, 2020
a9d84c1
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Oct 1, 2020
534cbe7
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Oct 15, 2020
6649433
Merge remote-tracking branch 'upstream/master' into samlittlewood/app…
samlittlewood Nov 7, 2020
5d884ed
Merge remote-tracking branch 'upstream/main' into samlittlewood/apple…
samlittlewood Aug 4, 2021
a091b6f
Merge remote-tracking branch 'upstream/main' into samlittlewood/apple…
samlittlewood Sep 28, 2021
361b860
Merge remote-tracking branch 'upstream/main' into samlittlewood/apple…
samlittlewood Nov 16, 2021
0a20d6d
Merge remote-tracking branch 'upstream/main' into samlittlewood/apple…
samlittlewood Jun 10, 2022
bc4dea8
Update software/glasgow/applet/program/chipcon/ccdpi.py
samlittlewood Jun 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions software/glasgow/applet/all.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

samlittlewood marked this conversation as resolved.
Show resolved Hide resolved
from .internal.selftest import SelfTestApplet
from .internal.benchmark import BenchmarkApplet

Expand All @@ -22,6 +23,7 @@
from .debug.arm.swd import DebugARMSWDApplet

from .program.avr.spi import ProgramAVRSPIApplet
from .program.chipcon import ProgramChipconApplet
from .program.ice40_flash import ProgramICE40FlashApplet
from .program.ice40_sram import ProgramICE40SRAMApplet
from .program.m16c import ProgramM16CApplet
Expand Down
220 changes: 220 additions & 0 deletions software/glasgow/applet/program/chipcon/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# Chipcon, (now Texas Instruments) CC111x CC251x
#
import logging
import argparse
import asyncio
import math

from fx2.format import autodetect, input_data, output_data, flatten_data
from ... import GlasgowApplet
from .ccdpi import CCDPISubtarget, CCDPIInterface, CCDPIError, DEVICES, CONFIG_SEL_FLASH_INFO_PAGE
samlittlewood marked this conversation as resolved.
Show resolved Hide resolved

STATUS_BITS = [
samlittlewood marked this conversation as resolved.
Show resolved Hide resolved
"CHIP_ERASE_DONE",
"PCON_IDLE",
"CPU_HALTED",
"POWER_MODE_0",
"HALT_STATUS",
"DEBUG_LOCKED",
"OSCILLATOR_STABLE",
"STACK_OVERFLOW"
]

class ProgramChipconApplet(GlasgowApplet, name="program-chipcon"):
logger = logging.getLogger(__name__)
help = "program TI/Chipcon CC111x CC251x "
description = """
Program and read back TI/Chipcon CC111x, CC251x and CC243x parts.
"""

__pins = ( "dclk", "ddat", "resetn")

@classmethod
def add_build_arguments(cls, parser, access):
super().add_build_arguments(parser, access)

for pin in cls.__pins:
access.add_pin_argument(parser, pin, default=True)

parser.add_argument(
"-f", "--frequency", metavar="FREQ", type=int, default=1000,
help="set bit rate to FREQ kHz (default: %(default)s)")

def build(self, target, args):
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)

iface.add_subtarget(CCDPISubtarget(
pads=iface.get_pads(args, pins=self.__pins),
out_fifo=iface.get_out_fifo(),
in_fifo=iface.get_in_fifo(auto_flush=False),
period=math.ceil(target.sys_clk_freq / (args.frequency * 1000))
))

# Connect up RESETN
reset, self._addr_reset = target.registers.add_rw(1)
target.comb += [
iface.pads.resetn_t.oe.eq(1),
iface.pads.resetn_t.o.eq(~reset)
]

async def run(self, device, args):
iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args)
chipcon_iface = CCDPIInterface(iface, self.logger, self._addr_reset)
return chipcon_iface

@classmethod
def add_interact_arguments(cls, parser):

def address(arg):
return int(arg, 0)

def length(arg):
return int(arg, 0)

p_operation = parser.add_subparsers(dest="operation", metavar="OPERATION")

p_identify = p_operation.add_parser(
"identify", help="read identity and revision from connected device")

p_status = p_operation.add_parser(
"status", help="read status of device")

p_erase = p_operation.add_parser(
"erase", help="erase whole device.")

p_erase_page = p_operation.add_parser(
"erase-page", help="erase whole device.")

p_erase_page.add_argument(
"address", metavar="ADDRESS", type=address,
help="erase memory from address ADDRESS")

p_read = p_operation.add_parser(
"read", help="read memory")
p_read.add_argument(
"address", metavar="ADDRESS", type=address,
help="read memory from address ADDRESS")
p_read.add_argument(
"length", metavar="LENGTH", type=length,
help="read LENGTH bytes from memory")
p_read.add_argument(
"--code", metavar="CODE", type=argparse.FileType("wb"),
help="read memory contents into CODE")
p_read.add_argument(
"--lock-bits", metavar="LOCK-BITS", type=argparse.FileType("wb"),
help="read flash information page into LOCK-BITS")
samlittlewood marked this conversation as resolved.
Show resolved Hide resolved

p_write = p_operation.add_parser(
"write", help="write and verify memory")
p_write.add_argument(
"--code", metavar="CODE", type=argparse.FileType("rb"),
help="program code memory contents from CODE")
p_write.add_argument(
"--lock-bits", metavar="LOCK-BITS", type=argparse.FileType("rb"),
help="program flash information page from LOCK-BITS")
p_write.add_argument(
"--no-erase", action="store_true",
help="do not erase chip before writing")
p_write.add_argument(
"--offset", metavar="OFFSET", type=address, default=0,
help="adjust memory addresses by OFFSET")

@staticmethod
def _check_format(file, kind):
try:
autodetect(file)
except ValueError:
raise CCDPIError("cannot determine %s file format" % kind)

async def interact(self, device, args, chipcon_iface):

await chipcon_iface.connect()
await chipcon_iface.clock_init()

self.logger.info("connected to {} Rev:{}".format(
chipcon_iface.device.name,
chipcon_iface.chip_rev))
self.logger.info(args.operation)

if args.operation == "identify":
# XXX test SRAM to figure out F8/F16/F32 parts
self.logger.info("Id:{:X} [{}] Rev:{:d}".format(
chipcon_iface.chip_id,
chipcon_iface.device.name,
chipcon_iface.chip_rev))

elif args.operation == "status":
s = await chipcon_iface.get_status()
ss = list(x for i,x in enumerate(STATUS_BITS) if ((0x80 >> i) & s) != 0)
self.logger.info("Status: 0x{:02x} [{}]".format(s, ", ".join(ss)))

elif args.operation == "erase":
await chipcon_iface.chip_erase()

elif args.operation == "erase-page":
await chipcon_iface.erase_flash_page(args,address)

elif args.operation == "read":
if args.code:
self._check_format(args.code, "code")
self.logger.info("reading code (%d bytes)", args.length)
await chipcon_iface.set_config(0)
output_data(args.code,
await chipcon_iface.read_code(args.address, args.length))

if args.lock_bits:
self._check_format(args.lock_bits, "lock-bits")
self.logger.info("reading flash information (%d bytes)", args.length)
await chipcon_iface.set_config(CONFIG_SEL_FLASH_INFO_PAGE)
output_data(args.lock_bits,
await chipcon_iface.read_code(args.address, args.length))
await chipcon_iface.set_config(0)

elif args.operation == "write":
if not args.no_erase:
self.logger.info("erasing chip")
await chipcon_iface.chip_erase()

if args.code:
self._check_format(args.code, "code")
data = input_data(args.code)
self.logger.info("writing code (%d bytes)",
sum([len(chunk) for address, chunk in data]))
await chipcon_iface.set_config(0)
await self._write_flash_blocks(chipcon_iface, data,
chipcon_iface.device.write_block_size)

if args.lock_bits:
self._check_format(args.lock_bits, "lock-bits")
data = input_data(args.lock_bits)
self.logger.info("writing flash information (%d bytes)",
sum([len(chunk) for address, chunk in data]))

await chipcon_iface.set_config(CONFIG_SEL_FLASH_INFO_PAGE)
await self._write_flash_blocks(chipcon_iface, data,
chipcon_iface.device.write_block_size)
await chipcon_iface.set_config(0)

await chipcon_iface.disconnect()

async def _write_flash_blocks(self, chipcon_iface, data, block_size):
"""Write data to flash, breaking into blocks of given size."""

for address, chunk in data:
for o in range(0, len(chunk), block_size):
block = bytes(chunk[o:o+block_size])
await chipcon_iface.write_flash(address+o, block)
readback = await chipcon_iface.read_code(address+o, len(block))

if block != readback:
raise CCDPIError("verification failed at address %#06x: %s != %s" %
(address, readback.hex(), chunk.hex()))


# -------------------------------------------------------------------------------------------------
from ... import GlasgowAppletTestCase, synthesis_test

class ProgramChipconAppletTestCase(GlasgowAppletTestCase, applet=ProgramChipconApplet):
@synthesis_test
def test_build(self):
self.assertBuilds()