Skip to content

Commit

Permalink
Add sam support (modm-io#1)
Browse files Browse the repository at this point in the history
* working device files for D21, D51, L21
  • Loading branch information
Ethan Slattery authored and salkinium committed Oct 21, 2019
1 parent 988d9f9 commit 0adbae3
Show file tree
Hide file tree
Showing 8 changed files with 2,469 additions and 89 deletions.
704 changes: 704 additions & 0 deletions devices/sam/samd21.xml

Large diffs are not rendered by default.

1,100 changes: 1,100 additions & 0 deletions devices/sam/samd51.xml

Large diffs are not rendered by default.

597 changes: 597 additions & 0 deletions devices/sam/saml21.xml

Large diffs are not rendered by default.

114 changes: 50 additions & 64 deletions tools/generator/dfg/sam/sam_device_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,14 @@ class SAMDeviceTree:
@staticmethod
def _properties_from_file(filename):
device_file = XMLReader(filename)

device = device_file.query("//device")[0]
architecture = device.get('architecture')
p = {}

# get more specific product codes?
# for variant in device_file.query("//variant"):
# variant.get('ordercode')
partname = device_file.query("//device")[0].get('name').lower()
LOGGER.info("Parsing Device File For '%s'", device_file.query("//device")[0].get('name'))

partname = device_file.query("//device")[0].get('name')
did = SAMIdentifier.from_string(partname.lower())
p['id'] = did

LOGGER.info("Parsing '%s'", did.string)

# information about the core and architecture
core = device_file.query("//device")[0].get('architecture').lower().replace("cortex-", "")
for param in (device_file.query("//device/parameters")[0]):
Expand All @@ -54,13 +48,11 @@ def _properties_from_file(filename):
elif name in ['LPRAM']:
p['lpram'] = size
# SAMD512 has 'smart' eeprom, SAML21 has a ReadWhileWrite Array
elif name == ['SEEPROM', 'RWW']:
elif name in ['SEEPROM', 'RWW']:
p['eeprom'] = size

raw_modules = device_file.query("//peripherals/module/instance")
modules = []
signals = []
gpios = []
ports = []
for m in raw_modules:
tmp = {'module': m.getparent().get('name').lower(), 'instance': m.get('name').lower()}
Expand All @@ -70,48 +62,56 @@ def _properties_from_file(filename):
modules.append(tmp)
p['modules'] = sorted(list(set([(m['module'], m['instance']) for m in modules])))

signals = []
gpios = []
raw_signals = device_file.query("//peripherals/module/instance/signals/signal")
modules_only = not len(raw_signals)
p['modules_only'] = modules_only

if modules_only:
# Parse GPIOs manually from mask
for port in ports:
port = port['instance'][-1:]
port_mask = device_file.query("//modules/module[@name='PORT']/register-group[@name='PORT{0}']/register[@name='PORT{0}']/@mask".format(port.upper()))
if len(port_mask) == 0:
# The port mask is split up
port_mask = device_file.query("//modules/module[@name='PORT']/register-group[@name='PORT{0}']/register[@name='PORT{0}']/bitfield/@mask".format(port.upper()))
port_mask = sum([int(mask, 16) for mask in port_mask])
else:
port_mask = int(port_mask[0], 16)
for pos in range(8):
if (1 << pos) & port_mask:
gpios.append((port, str(pos)))
gpios = sorted(gpios)
else:
for s in raw_signals:
tmp = {'module': s.getparent().getparent().getparent().get('name').lower(),
'instance': s.getparent().getparent().get('name').lower()}
tmp.update({k:v.lower() for k,v in s.items()})
if tmp['group'] in ['p', 'pin'] or tmp['group'].startswith('port'):
gpios.append(tmp)
else:
signals.append(tmp)
gpios = sorted([(g['pad'][1], g['pad'][2]) for g in gpios])
for s in raw_signals:
tmp = {'module': s.getparent().getparent().getparent().get('name').lower(),
'instance': s.getparent().getparent().get('name').lower()}
tmp.update({k:v.lower() for k,v in s.items()})
if tmp['group'] in ['p', 'pin'] or tmp['group'].startswith('port'):
gpios.append(tmp)
else:
signals.append(tmp)
gpios = sorted([(g['pad'][1], g['pad'][2:]) for g in gpios])

# Signal information is missing
p['signals'] = signals
p['gpios'] = gpios

LOGGER.debug("Found GPIOs: [%s]", ", ".join([p.upper() + i for p,i in p['gpios']]))
LOGGER.debug("Available Modules are:\n" + SAMDeviceTree._modulesToString(p['modules']))

interrupts = []
for i in device_file.query("//interrupts/interrupt"):
interrupts.append({'position': i.get('index'), 'name': i.get('name')})
p['interrupts'] = interrupts

#### Events are similar to interrupts, but instead of triggering an ISR data is passed from source
#### to sink without waking the processor
# event sources
event_sources = []
for i in device_file.query("//events/generators/generator"):
event_sources.append({'index': i.get('index'), 'name': i.get('name'), 'instance': i.get('module-instance')})
p['event_sources'] = event_sources

# event sinks or 'users' as the datasheet calls them
event_users = []
for i in device_file.query("//events/users/user"):
event_users.append({'index': i.get('index'), 'name': i.get('name'), 'instance': i.get('module-instance')})
p['event_users'] = event_users

LOGGER.debug("Found GPIOs: [%s]", ", ".join([p.upper() + i for p,i in p['gpios']]))
LOGGER.debug("Available Modules are:\n" + SAMDeviceTree._modulesToString(p['modules']))
# LOGGER.debug("Found Signals:")
# for sig in p['signals']:
# LOGGER.debug(" %s", sig)
# LOGGER.debug("Found Interrupts:")
# for intr in p['interrupts']:
# LOGGER.debug(" %s", intr)
# LOGGER.debug("Found Event Sources:")
# for eventSrc in p['event_sources']:
# LOGGER.debug(" %s", eventSrc)
# LOGGER.debug("Found Event Users:")
# for eventUsr in p['event_users']:
# LOGGER.debug(" %s", eventUsr)

return p

@staticmethod
Expand All @@ -130,7 +130,6 @@ def _modulesToString(modules):
def _device_tree_from_properties(p):
tree = DeviceTree('device')
tree.ids.append(p['id'])
LOGGER.info(("Generating Device Tree for '%s'" % p['id'].string))

def topLevelOrder(e):
order = ['attribute-flash', 'attribute-ram', 'attribute-eeprom', 'attribute-core', 'attribute-mcu', 'header', 'attribute-define']
Expand Down Expand Up @@ -165,26 +164,19 @@ def driverOrder(e):
core_child.setAttributes('name', 'core', 'type', p['core'])
core_child.addSortKey(lambda e: (int(e['position']), e['name']) if e.name == 'vector' else (-1, ""))
core_child.addSortKey(lambda e: (e['name'], int(e['size'])) if e.name == 'memory' else ("", -1))
for memory in ['flash', 'ram', 'eeprom']:
for memory in ['flash', 'ram', 'lpram', 'eeprom']:
if memory not in p: continue;
memory_section = core_child.addChild('memory')
memory_section.setAttribute('name', memory)
memory_section.setAttribute('size', p[memory])
# for vector in p['interrupts']:
# vector_section = core_child.addChild('vector')
# vector_section.setAttributes(['position', 'name'], vector)

# Clock
clock_child = tree.addChild('driver')
clock_child.setAttributes('name', 'clock', 'type', 'sam')
for vector in p['interrupts']:
vector_section = core_child.addChild('vector')
vector_section.setAttributes(['position', 'name'], vector)

modules = {}
for m, i in p['modules']:
# filter out non-peripherals
if m in ['cpu', 'jtag', 'exint', 'fuse', 'gpio']: continue;
if m in ['lockbit', 'boot_load']: continue;
# ATtiny AVR8X has more peripherals
if m in ['clkctrl', 'cpuint']: continue;
# filter out non-peripherals: fuses, micro-trace buffer
if m in ['fuses', 'mtb', 'systemcontrol', 'systick']: continue;
if m not in modules:
modules[m] = [i]
else:
Expand All @@ -196,10 +188,6 @@ def driverOrder(e):
dtype = name
compatible = 'sam'

if name.startswith('tc'):
dtype = 'tc'
compatible = name

driver.setAttributes('name', dtype, 'type', compatible)
# Add all instances to this driver
if any(i != dtype for i in instances):
Expand All @@ -221,8 +209,6 @@ def driverOrder(e):
# add all signals
for s in [s for s in p['signals'] if s['pad'] == ("p" + port + pin)]:
driver, instance, name = s['module'], s['instance'], s['group']
if driver.startswith('tc'): driver = 'tc';
if driver == 'cpu': driver = 'core'; instance = 'core';
# add the af node
pin_signal = {'driver': driver}
if instance != driver:
Expand Down
13 changes: 7 additions & 6 deletions tools/generator/dfg/sam/sam_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
[
# SAMD devices
{
'family': ['D'],
'name': ['21'],
'size': ['15', '16', '17', '18']
'family': ['d'],
'series': ['21']
},{
'family': ['D'],
'name': ['51'],
'size': ['18', '19', '20']
'family': ['d'],
'series': ['51']
},{
'family': ['l'],
'series': ['21']
},
]
13 changes: 4 additions & 9 deletions tools/generator/dfg/sam/sam_identifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,17 @@ def from_string(string):

# SAM platform with SAMD, SAML, SAMC, SAM4, SAMG, SAMS, SAME, and SAMV
if string.startswith("sam") or string.startswith("atsam"):
matchString = r"a?t?sam(?P<family>[a-z])(?P<series>[0-9]{2})(?P<pin>[a-z])(?P<flash>[0-9]{2})(?P<variant>[a-z])(?P<package>u?)"
matchString = r"a?t?sam(?P<family>[a-z])(?P<series>[0-9]{2})(?P<pin>[a-z])(?P<flash>[0-9]{2})(?P<variant>[a-z])-?(?P<package>[a-z]?)"
match = re.search(matchString, string)
if match:
i = DeviceIdentifier("{platform}{family}{series}{pin}{flash}{variant}{package}")
i = DeviceIdentifier("{platform}{family}{series}{pin}{flash}{variant}")
i.set("platform", "sam")
i.set("family", match.group("family").lower())
i.set("series", match.group("series").lower())
i.set("pin", match.group("pin").lower())
i.set("flash", match.group("flash").lower())
i.set("variant", match.group("variant").lower())
# package in atdf file is either U (wlcsp) or not annotated.
# we will use 'm' (normally QFN) to represent all other options (TQFP, UFBGA)
if match.group("package"):
i.set("package", match.group("package").lower())
else:
i.set("package", 'm')
# package in atdf file is only annotated if it matters. otherwise it is blank, so roll it into a 2 character variant
i.set("variant", match.group("variant").lower() + match.group("package").lower())
return i


Expand Down
2 changes: 1 addition & 1 deletion tools/generator/raw-data-extractor/extract-sam.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import os

families = [
"SAMD21", "SAMD51",
"SAMD21", "SAMD51", "SAML21"
]
packurl = "http://packs.download.atmel.com/"

Expand Down
15 changes: 6 additions & 9 deletions tools/generator/sam_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
# Copyright (c) 2016, Fabian Greif
# All rights reserved.
# TESTING: exec(open("./sam_generator.py").read())
# merge_group = sam_groups
# devices = [d.copy() for d in devices.values()]

import os
import sys
Expand All @@ -24,7 +22,6 @@
LOGGER = logging.getLogger('dfg.sam')

if __name__ == "__main__":
devices = {}
loglevel = 'INFO'
devs = []
device_depth = 1e6
Expand All @@ -42,14 +39,14 @@
continue
devs.append(arg)

# if not len(devs):
# devs.append('samd51')
if not len(devs):
devs.append('saml21')

dfg.logger.configure_logger(loglevel)

devices = {}
for dev in devs:
xml_path = os.path.join(os.path.dirname(__file__), 'raw-device-data', 'sam-devices', '*', ('AT' + dev.upper() + '*'))
# xml_path = os.path.join(os.getcwd(), 'raw-device-data', 'sam-devices', '*', ('AT' + dev.upper() + '*'))
files = glob.glob(xml_path)
for filename in files:
device = SAMDeviceTree.from_file(filename)
Expand All @@ -73,11 +70,10 @@ def filename(ids):
if k in ['type', 'pin']: v.sort()
if len(v) > 0:
p[k] = "_".join(v)
fmt = "sam{platform}{family}{series}{pin}{flash}{variant}{package}"
fmt = "{platform}{family}{series}"
return fmt.format(**p)

folder = os.path.join(os.path.dirname(__file__), '..', '..', 'devices', 'sam')
# folder = os.path.join(os.getcwd(), '..', '..', 'devices', 'sam')
parser = DeviceParser()
parsed_devices = {}
for dev in mergedDevices:
Expand All @@ -89,7 +85,8 @@ def filename(ids):
# and extract all the devices from it
parsed_devices[device.partname] = device

tmp_folder = os.path.join(os.path.dirname(__file__), 'single')
# tmp_folder = os.path.join(os.path.dirname(__file__), 'single')
tmp_folder = os.path.join(os.getcwd(), 'single')
os.makedirs(tmp_folder, exist_ok=True)
for pname, pdevice in parsed_devices.items():
# these are the properties from the merged device
Expand Down

0 comments on commit 0adbae3

Please sign in to comment.