CVS: python msp430-dco.py,NONE,1.1

Chris Liechti <[email protected]>
Newsgroups gmane.comp.hardware.texas-instruments.msp430.gcc.cvs
Message-ID <[email protected]>
Update of /cvsroot/mspgcc/python
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12471/python

Added Files:
	msp430-dco.py 
Log Message:
new tool for DCO clock measurement and callibration

--- NEW FILE: msp430-dco.py ---
#!/usr/bin/env python
#
# MSP430 clock callibration utility.
#
# This tool can measure the internal oscillator of F1xx, F2xx and F4xx devices
# that are connected to the JTAG. It can  display the supported frequencies,
# or run a software FLL to find the settings for a specified frequency.
#
# (C) 2005 Chris Liechti <[email protected]>
# this is distributed under a free software license, see license.txt
#
# $Id: msp430-dco.py,v 1.1 2005/12/29 04:00:01 cliechti Exp $

from msp430 import memory, jtag
import sys
import cStringIO
import struct

debug = False

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def nice_frequency(frequency):
    """return a string of the frequency with SI unit and a reasonable number
       of digits"""
    if frequency < 1e3:
        return "%dHz" % frequency
    elif frequency < 10e3:
        return "%.3fkHz" % (frequency/1e3)
    elif frequency < 100e3:
        return "%.2fkHz" % (frequency/1e3)
    elif frequency < 1e6:
        return "%.1fkHz" % (frequency/1e3)
    elif frequency < 10e6:
        return "%.3fMHz" % (frequency/1e6)
    elif frequency < 1e9:
        return "%.2fMHz" % (frequency/1e6)
    return "%.2fGHz" % (frequency/1e9)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#see mspgcc cvs/jtag/funclets/counter.S
COUNTER_FUNCLET = """\
@0200
00 02 08 02 22 02 60 07 32 c2 d2 40 fb ff 57 00
d2 40 f4 ff 56 00 0e 43 0f 43 1e 53 0f 63 fd 3f
03 43 ff 3f
q
"""


def getDCOFreq(dcoctl, bcsctl1):
    """measure DCO frequency on a F1xx or F2xx device"""
    funclet = memory.Memory()
    funclet.loadTIText(cStringIO.StringIO(COUNTER_FUNCLET))
    #XXX dcor
    funclet[0].data = funclet[0].data[:6] + chr(dcoctl) + chr(bcsctl1) + funclet[0].data[8:]
    runtime = jtag._parjtag.funclet(funclet[0].data, 100)
    count = jtag._parjtag.regread(14) | (jtag._parjtag.regread(15) << 16)
    return 1000*count*4/runtime

def setDCO(fmin, fmax, maxrsel=7):
    """Software FLL for F1xx and F2xx devices"""
    if debug: sys.stderr.write("setDCO target: %dHz < frequency < %dHz\n" % (fmin, fmax))
    dco = 3<<5
    bcs1 = maxrsel
    fast = True
    upper = False
    lower = False
    
    for tries in range(50):
        if upper and lower and fast:
            if debug: sys.stderr.write("switching to high resolution mode\n")
            fast = False
        frequency = getDCOFreq(dco, bcs1)
        if frequency > fmax:
            if debug: sys.stderr.write("%luHz is too high, decreasing\n" % frequency)
            upper = True
            dco -= fast and 32 or 1
            if dco <= 0:
                dco = 255
                bcs1 -= 1
                if bcs1 <= 0:
                    raise IOError("Couldn't get DCO working with correct frequency.")
        elif frequency < fmin:
            if debug: sys.stderr.write("%luHz is too low, increasing\n" % frequency)
            lower = True
            dco += fast and 32 or 1
            if dco > 255:
                dco = 0
                bcs1 += 1
                if ++bcs1 > 7:
                    raise IOError("Couldn't get DCO working with correct frequency.")
        else:
            if debug: sys.stderr.write("%luHz is OK\n" % frequency)
            return frequency, dco, bcs1
    raise IOError("Couldn't get DCO working with correct frequency.")

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#see mspgcc cvs/jtag/funclets/counterplus.S
COUNTERPLUS_FUNCLET = """\
@0200
00 02 0c 02 3c 02 00 0e 80 80 00 00 32 c2 72 d0
40 00 d2 40 f4 ff 52 00 d2 40 ed ff 51 00 d2 40
e9 ff 53 00 d2 40 e4 ff 54 00 d2 40 da ff 50 00
0e 43 0f 43 1e 53 0f 63 fd 3f 03 43 ff 3f
q
"""

def getDCOPlusFreq(scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1):
    """measure DCO frequency on a F4xx device"""
    funclet = memory.Memory()
    funclet.loadTIText(cStringIO.StringIO(COUNTERPLUS_FUNCLET))
    funclet[0].data = funclet[0].data[:6] + \
                      chr(scfi0) + chr(scfi1) + \
                      chr(scfqctl) + chr(fll_ctl0) + \
                      chr(fll_ctl1) + funclet[0].data[11:]
    #~ funclet..[0x205] = scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1
    runtime = jtag._parjtag.funclet(funclet[0].data, 100)
    count = jtag._parjtag.regread(14) | (jtag._parjtag.regread(15) << 16)
    return 1000*count*4/runtime

def setDCOPlus(fmin, fmax):
    """Software FLL for F4xx devices"""
    first = 0
    last = 27 << 5
    
    if debug: sys.stderr.write("setDCOPlus target: %dHz < frequency < %dHz\n" % (fmin, fmax))

    # Binary search through the available frequencies, selecting the highest
    # frequency whithin the acceptable range
    while first + 1 < last:
        mid = (last + first) / 2
        # Select DCO range from 0.23MHz to 11.2MHz. Specify frequency via Ndco.
        # Disable Modulation. Enable DCO+.
        frequency = getDCOPlusFreq(mid&3, mid>>2, 0x80, 0x80, 0)
        if frequency > fmax:
            if debug: sys.stderr.write("%luHz is too high, decreasing\n" % frequency)
            last = mid
        elif frequency < fmin:
            if debug: sys.stderr.write("%luHz is too low, increasing\n" % frequency)
            first = mid
        else:
            break

    frequency = getDCOPlusFreq(mid&3, mid>>2, 0x80, 0x80, 0)
    if debug: sys.stderr.write("%luHz\n" % frequency)
    if fmin <= frequency <= fmax:
        return frequency, mid&3, mid>>2, 0x80, 0x80, 0
    raise IOError("Couldn't get DCO working with correct frequency.")

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

def get_msp430_type():
    """return the MSP430 type id that is stored in the ROM"""
    (device, ) = struct.unpack(">H", jtag._parjtag.memread(0x0ff0, 2))
    if debug: sys.stderr.write("MSP430 device: 0x%04x\n" % (device, ))
    return device

def adjust_clock(out, frequency, tolerance=0.02):
    """detect MSP430 type and try to set the clock to the given frequency.
    when successful, print the clock control register settings.
    
    this function assumes that the jtag connection to the device has already
    been initialized and that the device is under jtag control and stopped.
    """
    if tolerance < 0.005 or tolerance > 50:
        raise ValueError('tolerance out of range %f' % (tolerance,))
    device = get_msp430_type() >> 8
    if device == 0xf1:
        frequency, dco, bcs1 = setDCO(frequency*(1-tolerance), frequency*(1+tolerance), maxrsel=7)
        out.write('BCSCTL1 = 0x%02x; DCOCTL = 0x%02x; //%dHz\n' % (bcs1, dco, frequency))
    elif device == 0xf2:
        frequency, dco, bcs1 = setDCO(frequency*(1-tolerance), frequency*(1+tolerance), maxrsel=15)
        out.write('BCSCTL1 = 0x%02x; DCOCTL = 0x%02x; //%dHz\n' % (bcs1, dco, frequency))
    elif device == 0xf4:
        frequency, scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1 = setDCOPlus(frequency*(1-tolerance), frequency*(1+tolerance))
        out.write('SCFI0 = 0x%02x; SCFI1 = 0x%02x; SCFQCTL = 0x%02x; FLL_CTL0 = 0x%02x; FLL_CTL1 = 0x%02x; //%dHz\n' % (scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1, frequency))
    else:
        IOError("unknown MSP430 type %2x" % device)

def measure_clock(out):
    """measure fmin and fmax"""
    device = get_msp430_type() >> 8
    if device == 0xf1:
        for rsel in range(8):
            fmin = getDCOFreq(0x00, rsel)
            fmax = getDCOFreq(0xff, rsel)
            out.write('%s < f(rsel_%d) < %s\n' % (nice_frequency(fmin), rsel, nice_frequency(fmax)))
        fmin = getDCOFreq(0, 0)
        fmax = getDCOFreq(0xff, 0x07)
    elif device == 0xf2:
        for rsel in range(16):
            fmin = getDCOFreq(0x00, rsel)
            fmax = getDCOFreq(0xff, rsel)
            out.write('%s < f(rsel_%d) < %s\n' % (nice_frequency(fmin), rsel, nice_frequency(fmax)))
        fmin = getDCOFreq(0, 0)
        fmax = getDCOFreq(0xff, 0x0f)
    elif device == 0xf4:
        fmin = getDCOPlusFreq(0, 0, 0x80, 0x80, 0)
        #XXX the F4xx has clock settings that go higher, but not all are valid
        #for the CPU
        #~ fmax = getDCOPlusFreq(0x03, 0xff, 0x80, 0x80, 0) # should be around 6MHz
        fmax = getDCOPlusFreq(0x13, 0xbf, 0x80, 0x80, 0) # should be around 16MHz
    else:
        IOError("unknown MSP430 type %2x" % device)
    out.write('fmin = %8dHz (%s)\n' % (fmin, nice_frequency(fmin)))
    out.write('fmax = %8dHz (%s)\n' % (fmax, nice_frequency(fmax)))

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

def main():
    from optparse import OptionParser

    parser = OptionParser(usage="""\
    usage: %prog [options] frequency

MSP430 clock callibration utility.

This tool can measure the internal oscillator of F1xx, F2xx and F4xx devices,
display the supported frequencies, or run a software FLL to find the settings
for a specified frequency.

The target device has to be connected to the JTAG interface.

Examples:
    See min and max clock speeds:
        %prog --measure

    Get clock settings for 2.0MHz +/-2%:
        %prog --tolerance=0.02 2.0e6""")
    parser.add_option("-o", "--output", dest="output",
                      help="write result to given file", metavar="FILE")
    #~ parser.add_option("", "--dcor", dest="dcor",
                      #~ help="use external resistor",
                      #~ default=False, action='store_true')
    parser.add_option("-d", "--debug", dest="debug",
                      help="print debug messages",
                      default=False, action='store_true')
    parser.add_option("-l", "--lpt", dest="lpt",
                      help="set the parallel port",
                      default=None)

    parser.add_option("", "--measure", dest="measure",
                      help="measure min and max clock settings and exit",
                      default=False, action="store_true")

    parser.add_option("-t", "--tolerance", dest="tolerance",
                      help="set the clock tolerance as factor. e.g. 0.1 means 10%",
                      default=0.01, type="float")

    (options, args) = parser.parse_args()

    global debug
    debug = options.debug

    if not options.measure:
        if len(args) != 1:
            parser.error('exacly one argument expected: the target frequency')
        frequency = float(args[0])
    
    #prepare output
    if options.output is None or options.output == '-':
        out = sys.stdout
    else:
        out = file(options.output, 'w')
    
    #
    jtagobj = jtag.JTAG()
    jtagobj.open(options.lpt)               #try to open port
    jtagobj.connect()                       #try to connect to target
    try:
        if options.measure:
            measure_clock(out)
        else:
            adjust_clock(out, frequency, options.tolerance)
        #~ print "%.2f kHz" % (getDCOFreq(0, 0)/1e3)
    finally:
        if sys.exc_info()[:1]:              #if there is an exception pending
            jtagobj.verbose = 0             #do not write any more messages
        jtagobj.reset(1, 1)                 #reset and release target
        jtagobj.close()                     #Release communication port

if __name__ == '__main__':
    try:
        main()
    except SystemExit:
        raise                                           #let pass exit() calls
    except KeyboardInterrupt:
        if debug: raise                                 #show full trace in debug mode
        sys.stderr.write("User abort.\n")               #short messy in user mode
        sys.exit(1)                                     #set errorlevel for script usage
    except Exception, msg:                              #every Exception is caught and displayed
        if debug: raise                                 #show full trace in debug mode
        sys.stderr.write("\nAn error occoured:\n%s\n" % msg) #short messy in user mode
        sys.exit(1)                                     #set errorlevel for script usage    



-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.