|
1 | 1 | from abc import abstractproperty |
2 | 2 | from fractions import Fraction |
| 3 | +import math |
3 | 4 | import re |
4 | 5 |
|
5 | 6 | from ..hdl import * |
@@ -160,17 +161,22 @@ def _osc_base_freq(self): |
160 | 161 |
|
161 | 162 | @property |
162 | 163 | def _osc_div(self): |
163 | | - div_min = 2 |
164 | | - div_max = 128 |
165 | | - div_step = 2 |
166 | | - div_frac = Fraction(self._osc_base_freq, self.osc_frequency) |
| 164 | + div_range = range(2, 128, 2) |
| 165 | + div_frac = Fraction(self._osc_base_freq, self.osc_frequency) |
167 | 166 |
|
168 | | - if div_frac.denominator != 1 or div_frac not in range(div_min, div_max, div_step): |
| 167 | + if div_frac.denominator != 1 or div_frac not in div_range: |
| 168 | + achievable = ( |
| 169 | + min((frac for frac in div_range if frac > div_frac), default=None), |
| 170 | + max((frac for frac in div_range if frac < div_frac), default=None) |
| 171 | + ) |
169 | 172 | raise ValueError( |
170 | | - "On-chip oscillator frequency (platform.osc_frequency) must be chosen such that " |
171 | | - "the oscillator divider, calculated as ({}/{}), is an integer between {} and {} in " |
172 | | - "steps of {}" |
173 | | - .format(div_frac.numerator, div_frac.denominator, div_min, div_max, div_step)) |
| 173 | + f"On-chip oscillator frequency (platform.osc_frequency) must be chosen such that " |
| 174 | + f"the base frequency of {self._osc_base_freq} Hz is divided by an integer factor " |
| 175 | + f"between {div_range.start} and {div_range.stop} in steps of {div_range.step}; " |
| 176 | + f"the divider for the requested frequency of {self.osc_frequency} Hz was " |
| 177 | + f"calculated as ({div_frac.numerator}/{div_frac.denominator}), and the closest " |
| 178 | + f"achievable frequencies are " + |
| 179 | + ", ".join(str(self._osc_base_freq // frac) for frac in achievable if frac)) |
174 | 180 |
|
175 | 181 | return div_frac.numerator |
176 | 182 |
|
|
0 commit comments