mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
327 lines
11 KiB
Python
327 lines
11 KiB
Python
#!/bin/false
|
|
|
|
# This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
|
#
|
|
# Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
|
#
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
#
|
|
# ----------------------------------------------------------------------------------------
|
|
# Used by boards/BOARDNAME.py to read csv files describing which functions are
|
|
# available on which pins in which packages
|
|
# ----------------------------------------------------------------------------------------
|
|
|
|
import subprocess;
|
|
import re;
|
|
import json;
|
|
import sys;
|
|
import os;
|
|
|
|
ALLOWED_PORTS = "ABCDEFGHIV";
|
|
ALLOWED_FUNCTIONS = {}
|
|
CLASSES = {}
|
|
NAMES = {}
|
|
for i in range(1, 3):
|
|
ALLOWED_FUNCTIONS["DAC"+str(i)+"_OUT"] = "JSH_DAC|JSH_DAC_CH"+str(i);
|
|
ALLOWED_FUNCTIONS["DAC_OUT"+str(i)] = "JSH_DAC|JSH_DAC_CH"+str(i);
|
|
ALLOWED_FUNCTIONS["DAC1_OUT"+str(i)] = "JSH_DAC|JSH_DAC_CH"+str(i);
|
|
ALLOWED_FUNCTIONS["DAC2_OUT"+str(i)] = "JSH_DAC|JSH_DAC_CH"+str(i);
|
|
for i in range(1, 7):
|
|
ALLOWED_FUNCTIONS["USART"+str(i)+"_TX"] = "JSH_USART"+str(i)+"|JSH_USART_TX";
|
|
ALLOWED_FUNCTIONS["USART"+str(i)+"_RX"] = "JSH_USART"+str(i)+"|JSH_USART_RX";
|
|
ALLOWED_FUNCTIONS["USART"+str(i)+"_CK"] = "JSH_USART"+str(i)+"|JSH_USART_CK";
|
|
ALLOWED_FUNCTIONS["UART"+str(i)+"_TX"] = "JSH_USART"+str(i)+"|JSH_USART_TX";
|
|
ALLOWED_FUNCTIONS["UART"+str(i)+"_RX"] = "JSH_USART"+str(i)+"|JSH_USART_RX";
|
|
for i in range(1, 5):
|
|
ALLOWED_FUNCTIONS["SPI"+str(i)+"_SCK"] = "JSH_SPI"+str(i)+"|JSH_SPI_SCK";
|
|
ALLOWED_FUNCTIONS["SPI"+str(i)+"_MISO"] = "JSH_SPI"+str(i)+"|JSH_SPI_MISO";
|
|
ALLOWED_FUNCTIONS["SPI"+str(i)+"_MOSI"] = "JSH_SPI"+str(i)+"|JSH_SPI_MOSI";
|
|
for i in range(1, 5):
|
|
ALLOWED_FUNCTIONS["I2C"+str(i)+"_SCL"] = "JSH_I2C"+str(i)+"|JSH_I2C_SCL";
|
|
ALLOWED_FUNCTIONS["I2C"+str(i)+"_SDA"] = "JSH_I2C"+str(i)+"|JSH_I2C_SDA";
|
|
#I2C_SMBA?
|
|
for i in range(1, 19):
|
|
for ch in range(1, 5):
|
|
ALLOWED_FUNCTIONS["TIM"+str(i)+"_CH"+str(ch)] = "JSH_TIMER"+str(i)+"|JSH_TIMER_CH"+str(ch);
|
|
ALLOWED_FUNCTIONS["TIM"+str(i)+"_CH"+str(ch)+"N"] = "JSH_TIMER"+str(i)+"|JSH_TIMER_CH"+str(ch)+"|JSH_TIMER_NEGATED";
|
|
|
|
CLASSES["CANRX"]="CAN"
|
|
CLASSES["CANTX"]="CAN"
|
|
CLASSES["CAN_RX"]="CAN"
|
|
CLASSES["CAN_TX"]="CAN"
|
|
for i in range(0,17):
|
|
CLASSES["ADC1_IN"+str(i)]="ADC"
|
|
CLASSES["ADC2_IN"+str(i)]="ADC"
|
|
CLASSES["ADC3_IN"+str(i)]="ADC"
|
|
CLASSES["ADC12_IN"+str(i)]="ADC"
|
|
CLASSES["ADC123_IN"+str(i)]="ADC"
|
|
for fn in ALLOWED_FUNCTIONS:
|
|
defn = ALLOWED_FUNCTIONS[fn];
|
|
if defn.startswith("JSH_DAC"): CLASSES[fn]="DAC"
|
|
if defn.startswith("JSH_USART"): CLASSES[fn]="USART"
|
|
if defn.startswith("JSH_SPI"): CLASSES[fn]="SPI"
|
|
if defn.startswith("JSH_I2C"): CLASSES[fn]="I2C"
|
|
if defn.startswith("JSH_TIMER"): CLASSES[fn]="PWM"
|
|
|
|
|
|
DEVICES = {
|
|
"OSC":"OSC",
|
|
"OSC_RTC":"OSC RTC",
|
|
"BOOT0":"BOOT0",
|
|
"BOOT1":"BOOT1",
|
|
"SD":"SD CARD",
|
|
"USB":"USB",
|
|
"BLUETOOTH":"BLUETOOTH",
|
|
"TOUCHSCREEN":"TOUCH",
|
|
"LCD":"LCD",
|
|
"MIC":"MIC",
|
|
"AUDIO":"AUDIO",
|
|
"MEMS":"MEMS",
|
|
"GYRO":"GYRO",
|
|
"JTAG":"JTAG",
|
|
"ESP8266":"ESP8266",
|
|
"MAG":"MAG",
|
|
"IR":"IR",
|
|
"NFC":"NFC",
|
|
"CAPSENSE":"CAPSENSE",
|
|
"PWR":"PWR",
|
|
"ACCEL":"ACCEL",
|
|
"TEMP":"TEMP",
|
|
};
|
|
|
|
for i in range(0,10):
|
|
DEVICES["LED"+str(i)]="LED"+str(i)
|
|
DEVICES["BTN"+str(i)]="BTN"+str(i)
|
|
DEVICES["POT"+str(i)]="POT"+str(i)
|
|
|
|
|
|
for D in DEVICES:
|
|
CLASSES[D]="DEVICE"
|
|
NAMES[D]=DEVICES[D]
|
|
|
|
URLS = {
|
|
"PWM":"/PWM",
|
|
"SPI":"/SPI",
|
|
"I2C":"/I2C",
|
|
"USART":"/USART",
|
|
"DAC":"/DAC",
|
|
"ADC":"/ADC",
|
|
"OSC_RTC":"/Clocks",
|
|
"LED1":"/Flashing+Lights",
|
|
"LED2":"/Flashing+Lights",
|
|
"LED3":"/Flashing+Lights",
|
|
"BLUETOOTH":"/Bluetooth",
|
|
"JTAG":"/AdvancedDebug"
|
|
};
|
|
|
|
# LED/Button devices
|
|
SIMPLE_DEVICES = [
|
|
"LED1","LED2","LED3","LED4","LED5","LED6","LED7","LED8","LED9","LED10",
|
|
"BTN1","BTN2","BTN3","BTN4","BTN5","BTN6","BTN7","BTN8","BTN9","BTN10", ];
|
|
|
|
# Devices with pins that we should leave alone at reset time
|
|
OTHER_DEVICES = [
|
|
"USB","SD","LCD","JTAG","ESP8266","IR","GPS","BAT","HEARTRATE",
|
|
"ACCEL","MAG","TEMP","PRESSURE","SPIFLASH","TOUCH","VIBRATE","MISC"
|
|
];
|
|
|
|
# is a pin name valid
|
|
def isvalidpin(pinname):
|
|
pinport = pinname[1:2]
|
|
if pinname[:1]=="P" and ALLOWED_PORTS.find(pinport)!=-1:
|
|
if pinname.find('-')!=-1: pinname = pinname[:pinname.find('-')]
|
|
pinnum = pinname[2:]
|
|
return pinnum.isdigit()
|
|
return False
|
|
|
|
|
|
# Find/populate a pin
|
|
def haspin(pins, pinname):
|
|
for pin in pins:
|
|
if pin["name"]==pinname:
|
|
return True
|
|
return False
|
|
|
|
# Find/populate a pin
|
|
def findpin(pins, pinname, force):
|
|
if pinname.find('-')!=-1: pinname = pinname[:pinname.find('-')]
|
|
for pin in pins:
|
|
if pin["name"]==pinname:
|
|
return pin
|
|
if force:
|
|
print("ERROR: pin "+pinname+" not found")
|
|
exit(1);
|
|
pin = {}
|
|
pin["name"] = pinname
|
|
pin["port"] = pinname[1:2]
|
|
pin["num"] = pinname[2:]
|
|
pin["sortingname"] = pin["port"]+pin["num"].rjust(2,'0')
|
|
pin["functions"] = {}
|
|
pin["csv"] = {}
|
|
pins.append(pin)
|
|
return pin
|
|
|
|
# Code for scanning AF file
|
|
def scan_pin_af_file(pins, filename, nameoffset, afoffset):
|
|
f = open(os.path.dirname(os.path.realpath(__file__))+'/../boards/pins/'+filename)
|
|
lines = f.readlines()
|
|
f.close()
|
|
for line in lines:
|
|
pindata = line.split(",")
|
|
pinname = pindata[nameoffset].strip()
|
|
if pinname.find('(')>0: pinname = pinname[:pinname.find('(')]
|
|
if not isvalidpin(pinname): continue
|
|
pin = findpin(pins, pinname, False)
|
|
#print(json.dumps(pin, sort_keys=True, indent=2))
|
|
for af in range(0, len(pindata)-afoffset):
|
|
fnames = pindata[af+afoffset].split("/")
|
|
for fname in fnames:
|
|
fname = fname.strip()
|
|
# if fname!="-": print(fname)
|
|
pin["functions"][fname] = af
|
|
#print pinname+" --- "+fname+" : "+str(af)
|
|
return pins
|
|
|
|
# Code for scanning normal file
|
|
def scan_pin_file(pins, filename, nameoffset, functionoffset, altfunctionoffset):
|
|
f = open(os.path.dirname(os.path.realpath(__file__))+'/../boards/pins/'+filename)
|
|
lines = f.readlines()
|
|
f.close()
|
|
headings = lines[0].split(",")
|
|
for line in lines:
|
|
pindata = line.split(",")
|
|
pinname = pindata[nameoffset].strip()
|
|
|
|
extrafunction = ""
|
|
if "BOOT1" in line: extrafunction="BOOT1"
|
|
if pinname.find('(')>0: pinname = pinname[:pinname.find('(')]
|
|
if not isvalidpin(pinname): continue
|
|
pin = findpin(pins, pinname, False)
|
|
for i,head in enumerate(headings):
|
|
pin["csv"][head] = pindata[i].strip()
|
|
if extrafunction!="":
|
|
pin["functions"][extrafunction] = 0
|
|
for fn in pindata[functionoffset].strip().split("/"):
|
|
fname = fn.strip()
|
|
pin["functions"][fname] = 0
|
|
if altfunctionoffset>=0:
|
|
for fn in pindata[altfunctionoffset].strip().split("/"):
|
|
fname = fn.strip()
|
|
pin["functions"][fname] = 1
|
|
# print pin["name"]+" : "+', '.join(pin["functions"])
|
|
return pins
|
|
|
|
# Create a simple list of pins
|
|
def generate_pins(min_pin, max_pin, port_name="D"):
|
|
pins = []
|
|
for n in range(min_pin, max_pin+1):
|
|
findpin(pins, "P"+port_name+str(n), False)
|
|
return pins
|
|
|
|
# fill in gaps - eg. put A2 in A0,A1,A3,A4
|
|
def fill_gaps_in_pin_list(pins):
|
|
# first sort
|
|
pins = sorted(pins, key=lambda pin: pin["sortingname"])
|
|
# then fill in
|
|
prevpin = False
|
|
newpins = []
|
|
for pin in pins:
|
|
if prevpin!=False:
|
|
if prevpin["port"]==pin["port"]:
|
|
for num in range(int(prevpin["num"])+1,int(pin["num"])):
|
|
newpin = {}
|
|
newpin["name"] = "P"+pin["port"]+str(num)
|
|
newpin["port"] = "_NONE"
|
|
newpin["num"] = str(num)
|
|
newpin["sortingname"] = pin["port"]+newpin["num"].rjust(2,'0')
|
|
newpin["functions"] = {}
|
|
newpins.append(newpin)
|
|
print("Added fake pin "+newpin["name"])
|
|
newpins.append(pin)
|
|
prevpin = pin
|
|
return newpins
|
|
|
|
# Only return the pins for the specified package
|
|
def only_from_package(pins, package):
|
|
newpins = []
|
|
for pin in pins:
|
|
# print json.dumps(pin)
|
|
if "csv" in pin:
|
|
pinnumber = pin["csv"][package]
|
|
if pinnumber!="" and pinnumber!="0":
|
|
newpins.append(pin)
|
|
return newpins
|
|
|
|
def get_device_pins(board):
|
|
pins = {}
|
|
for devicename in board.devices:
|
|
for deviceinfo in board.devices[devicename]:
|
|
if deviceinfo[:3]=="pin":
|
|
pinname = board.devices[devicename][deviceinfo]
|
|
pins["P"+pinname] = { "device":devicename, "function": deviceinfo };
|
|
# print(json.dumps(pins))
|
|
return pins
|
|
|
|
# If devices are used by a board, fill in their details for each pin
|
|
def append_devices_to_pin_list(pins, board):
|
|
devicepins = get_device_pins(board)
|
|
|
|
for i,pin in enumerate(pins):
|
|
if pin["name"] in devicepins:
|
|
pins[i]["functions"][devicepins[pin["name"]]["device"]] = devicepins[pin["name"]]["function"]
|
|
# print pins[i]["functions"][devicepins[pin["name"]]["device"]]
|
|
return pins
|
|
|
|
# Get the utility timer for a specific board
|
|
def get_device_util_timer(board):
|
|
if (board.chip["family"]=="STM32L4"):
|
|
if board.chip["part"].startswith("STM32L476") | board.chip["part"].startswith("STM32L496"):
|
|
return { 'timer' : "TIM5", 'defines' : """
|
|
// Used by various pins, but always with other options
|
|
#define UTIL_TIMER TIM5
|
|
#define UTIL_TIMER_IRQn TIM5_IRQn
|
|
#define UTIL_TIMER_IRQHandler TIM5_IRQHandler
|
|
#define UTIL_TIMER_APB1 LL_APB1_GRP1_PERIPH_TIM5
|
|
"""}
|
|
if ((board.chip["family"]=="STM32F1") | (board.chip["family"]=="STM32F2") |
|
|
(board.chip["family"]=="STM32F3") | (board.chip["family"]=="STM32F4")):
|
|
if board.chip["part"].startswith("STM32F401") | board.chip["part"].startswith("STM32F411"):
|
|
return { 'timer' : "TIM5", 'defines' : """
|
|
// Used by various pins, but always with other options
|
|
#define UTIL_TIMER TIM5
|
|
#define UTIL_TIMER_IRQn TIM5_IRQn
|
|
#define UTIL_TIMER_IRQHandler TIM5_IRQHandler
|
|
#define UTIL_TIMER_APB1 RCC_APB1Periph_TIM5
|
|
"""}
|
|
elif "subfamily" in board.chip and board.chip["subfamily"]=="MD":
|
|
return { 'timer' : "TIM4", 'defines' : """
|
|
// frustratingly the 103_MD (non-VL) chips in Olimexino don't have any timers other than 1-4
|
|
#define UTIL_TIMER TIM4
|
|
#define UTIL_TIMER_IRQn TIM4_IRQn
|
|
#define UTIL_TIMER_IRQHandler TIM4_IRQHandler
|
|
#define UTIL_TIMER_APB1 RCC_APB1Periph_TIM4
|
|
"""}
|
|
else:
|
|
return { 'timer' : "TIM7", 'defines' : """
|
|
// nice timer not used by anything else
|
|
#define UTIL_TIMER TIM7
|
|
#define UTIL_TIMER_IRQn TIM7_IRQn
|
|
#define UTIL_TIMER_IRQHandler TIM7_IRQHandler
|
|
#define UTIL_TIMER_APB1 RCC_APB1Periph_TIM7
|
|
"""}
|
|
return False
|
|
|
|
# Remove any pinfunctions from the pins array that are used elsewhere the the board
|
|
def remove_used_pinfunctions(pins, board):
|
|
util_timer = get_device_util_timer(board)
|
|
if util_timer!=False:
|
|
used_function = util_timer['timer']
|
|
for i,pin in enumerate(pins):
|
|
newfunctions = {}
|
|
for fidx,f in enumerate(pin["functions"]):
|
|
if not f.startswith(used_function): newfunctions[f]=pin["functions"][f]
|
|
pins[i]["functions"] = newfunctions
|
|
return pins
|