Compute prescaler/counter values for a MCU based oscillator, with Python 

'''
this program helps to compute note frequencies for a MCU based oscillator
where the selection of the optimal prescaller and counter value is
needed.

program output is a C array with counter register values.

each next note is larger than the one before it by the same ratio (the
twelfth root of 2, which is 1.05946309435929526456182529494634170077
9204317494... )

please check http://www.math.niu.edu/~rusin/uses-mat ... requencies
for list of frequencies.

to achieve excellent precission you may convert program to use numpy.

with numpy:

>>> def root(n, r):
... from numpy import roots
... return roots([1]+[0]*(r-1)+[-n])
...
root(2, r=12)[0]
(-1.0594630943592918+0j)
'''
DEBUG = False

notes = [
'C ', 'C#', 'D ', 'D#', 'E ', 'F ', 'F#', 'G ', 'G#', 'A ', 'A#', 'B ' ]

default_clock = 84000000.0 # chip clock
start_tone_frequency = 32.703195662574829 # C0
start_tone_midi = 21
stop_tone_frequency = 4186.01 # max desired frequency C8

twelfth_root_of_two = 1.059463094359295264561825294946341700779204317494

clock_frequencies = []
round_list = []
note_list = []

for clock_prescaler in range( 1, int( default_clock ) ):

if default_clock % clock_prescaler == 0:
if default_clock / clock_prescaler > stop_tone_frequency:
clock_frequencies.append( \
( default_clock / clock_prescaler, clock_prescaler ) )

elif DEBUG:
print "frequecy is less than the max desired frequency"

elif DEBUG:
print "divider does not produce round result"

print "---------------------------------------------------------------"
print "suitable frequencies: ", clock_frequencies


for clock_base_hz, clock_prescaler in clock_frequencies:

f = start_tone_frequency
f_midi_note = start_tone_midi

divider_is_less_than_oxffff = True
most_significant_frequency_gap = 0

print "---------------------------------------------------------------"
print "values for osc_base: ", clock_base_hz
print "clock_base_hz octave note f real_frequency tick_counter"

for octave in xrange( 1, 8 ):
for note in notes:

current_note_divider_is_less_than_oxffff = True

if clock_base_hz / f > 0xffff:
current_note_divider_is_less_than_oxffff = False
divider_is_less_than_oxffff = False

counter_value = round( clock_base_hz / f )
real_frequency = clock_base_hz / counter_value
real_frequency_gap = abs( real_frequency - f )

if most_significant_frequency_gap < real_frequency_gap:
most_significant_frequency_gap = real_frequency_gap

print clock_base_hz, octave, note, f, real_frequency_gap, \
counter_value

note_list.append( ( ( clock_base_hz, clock_prescaler ), \
( octave, note, f_midi_note, counter_value, f,
real_frequency, real_frequency - f, \
current_note_divider_is_less_than_oxffff ) ) )

f = f * twelfth_root_of_two
f_midi_note += 1

round_list.append( ( clock_base_hz , clock_prescaler, \
most_significant_frequency_gap, divider_is_less_than_oxffff ) )

suitable_frequencies_sorted = sorted( round_list, key=lambda l: l[2] )

print "---------------------------------------------------------------"
print "suitable frequencies (sorted by total inaccuracy): "
print "True/False shows if 16-bit long counter can be used"
for frequency in suitable_frequencies_sorted:
print frequency

print "---------------------------------------------------------------"
freq_to_list = input("Enter base freq to list notes: ")

print "octave note midi_note divider f real_f frequency_gap"
for record, values in note_list:
if record[0] == freq_to_list:
print values


print "---------------------------------------------------------------"
c_array_legend = ""
c_array_clock_prescalers = ""
c_array_clock_dividers = ""
c_count = 0


''' based on selected frequency create list of counter values '''
for record, values in note_list:
if record[0] == freq_to_list:
c_array_clock_prescalers += "%d, " % record[1]
c_count += 1

print "// osc: prescalers"
print "uint16_t clock_prescaler[%d] = { %s };" \
% ( c_count, c_array_clock_prescalers[:-2] )

''' example of values in note list:

oct note midi countr real_f computed_f f_error 0xffff
(7, 'B ', 104, 506.0, 7902.132820098011, 7905.138339920949, 3.0055198229383677, True)
'''

''' based on selected frequency create list of counter values '''
for record, values in note_list:
if record[0] == freq_to_list:
c_array_clock_dividers += "%d, " % values[3]

print "// osc: counters"
print "uint16_t clock_counter[%d] = { %s };" \
% ( c_count, c_array_clock_dividers[:-2] )

''' based on selected frequency create list of note detailed legends '''
for record, values in note_list:
if record[0] == freq_to_list:
c_array_legend += '"%s%s(%s) c: %s\\nfreq: %s", ' \
% ( values[0], values[1], \
values[2], values[3], \
values[4] )

print "// osc: legends"
print "char * clock_legend[%d] = { %s };" % ( c_count, c_array_legend[:-2] )

print


[ add comment ] ( 2 views )   |  [ 0 trackbacks ]   |  permalink

<<First <Back | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Next> Last>>