Перейти к содержанию
    

Нецелая системная частота STM32F4

Вариант с покупкой готового модуля для высокоточной генерации частоты.

Если ТС живёт в крупном городе, то возможно стоит поискать в местном радиомагазине DDS-генератор сигнала AD9833 (скорее всего находятся в отделе для Arduino). Микросхема выдаёт такие сигналы: синус, меандр, треугольник. Диапазон выходной частоты от 0 до 12.5МГц, с шагом 0.1Гц.

Или ещё более крутой вариант AD9834. Выдаёт синус и треугольник. По частоте на выходе: до 37.5МГц при тактовой 75МГц с разрешением 0.28Гц. А при тактировании 1МГц - разрешение 0.004Гц.

 

Фотки модулей (для поиска в радиомагазине), и примерные ссылки на Али (чисто для ориентировки по ценам, и чтоб бегло посмотреть описание): AD9833AD9834

Скрытый текст

AD9833.png.62beeaee482efebeb48df0fe4df89e6a.png   AD9834.png.f6a430f887bedfc1d81836522ff47ac8.png

Сам пользовался AD9833 для точной генерации частоты. Программируется просто.

Второй вариант только рассматривал, но не работал с ним.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Частота тактирования ЦАП и частота сигнала получаемого с него - никак не связаны (ну т.е. - если конечно частота получаемого сигнала много меньше частоты тактирования ЦАП).

При частоте тактирования ЦАП = 46875Гц нет никаких проблем получить на выходе синусоидальный сигнал с частотой = ровно 8 кГц (ФНЧ по выходу ЦАП-а конечно никто не отменял).

Не понял Вас, можете пояснить, как при частоте квантования ЦАП = 46875Гц получить ровно 8 кГц? Там же получается нецелое число точек на период.

 

31 minutes ago, controller_m30 said:

DDS-генератор сигнала AD9833

Спасибо, интересная штука, но мне кроме синуса нужно и другие сигналы воспроизводить, нужен ЦАП

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 минуты назад, Dima1060 сказал:

Не понял Вас, можете пояснить, как при частоте квантования ЦАП = 46875Гц получить ровно 8 кГц? Там же получается нецелое число точек на период.

Примерно так:

#define F_TON     8000   //[Hz]
#define F_SMPL    46875  //[Hz]
#define AMPLITUDE 100    //амплитуда
#define divRound(a, b) (((a) + (b) / 2) / (b)) //деление a/b с округлением до ближайшего целого

static u32 phase;

while (...) {
  phase += (u32)divRound(1ull * F_TON << 32, F_SMPL);
  s32 j = sine(phase);
  //далее: масштабируем по амплитуде и выводим в ЦАП (лучше через DMA)
  j = __SMMULR(j, AMPLITUDE * 2);
  ...
}

Цикл генерит сэмплы синусоиды F_TON с сэмпловой частотой =F_SMPL.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, Dima1060 сказал:

но мне кроме синуса нужно и другие сигналы воспроизводить, нужен ЦАП

Да, да. Это предложение только для генерации точной тактовой частоты в одном из модулей схемы. Например, это может быть основная частота МК (вместо кварца 8МГц используется такой генератор), или для точного регулирования частоты модуля I2S в МК (вход I2S_CKIN, как предлагали выше), или только для частоты работы самого ЦАП, если там есть такой вход.

Т.е. из всех возможностей, в генераторе используется только вывод меандра, и его частота. Генератор относительно недорогой, и точный с большим запасом для данного применения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

45 минут назад, jcxz сказал:

Примерно так:

Цикл генерит сэмплы синусоиды F_TON с сэмпловой частотой =F_SMPL.

Фазу можно точнее накапливать (например, алгоритм Брезенхема), но будет небольшой фазовый шумок.

У jcxz без фазового шума, но с небольшим отклонением по частоте (где-то в 6 знаке после запятой 8000.0000016298145 Гц).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jcxz сказал:

#define divRound(a, b) (((a) + (b) / 2) / (b)) //деление a/b с округлением до ближайшего целого

Ух ты! Первый раз такой фокус вижу. А зачем здесь a и b в скобках?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, Herz сказал:

Ух ты! Первый раз такой фокус вижу. А зачем здесь a и b в скобках?

Это стандартный приём. Зачем: представьте, что в качестве аргумента b в макрос будет подставлено какое-то выражение. Например: divRound(x, 1 + 20). Тогда (если без скобок) выражение будет вычислено неверно.

Поэтому: Правило хорошего тона - заключать все аргументы макроса в скобки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 minutes ago, Herz said:

Ух ты! Первый раз такой фокус вижу. А зачем здесь a и b в скобках?

Фокус и правда зачетный.. ))

Подставляем: a = 10, b = 1, находим: divRound(10,1) = 5.

С другой стороны: a/b = 10/1 = 10..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, blackfin сказал:

находим: divRound(10,1) = 5.

((10) + ((1) / 2) / 1 = (10 + 1 / 2) / 1 = (10 + 0) / 1 = 10

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, blackfin сказал:

Подставляем: a = 10, b = 1, находим: divRound(10,1) = 5.

Может вам стоит повторить школьный курс математики? Этак с 1-го класса.... :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 minutes ago, jcxz said:

Может вам стоит повторить школьный курс математики? Этак с 1-го класса.... :unknw:

Постоянно повторяю.. ))

PS. Очень мелкий текст на мобильнике. Увидел две скобки после b. Был не прав..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

34 минуты назад, Herz сказал:

Ух ты! Первый раз такой фокус вижу. А зачем здесь a и b в скобках?

Есть ещё такой:

#define divCeil(a, b) (((a) + (b) - 1) / (b))  //деление a/b с округлением до ближайшего большего целого

:smile:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Раз уж мы про округления, то

f_ton = 8000
f_smpl = 46875

def divRound(a, b):
	return ((a + b // 2) // b)

p1 = 0
p2 = 0
for i in range(f_smpl):
	p1 += divRound(f_ton << 32, f_smpl)
	p1 &= 0xFFFFFFFF;
	
	p2 += f_ton
	if p2 > f_smpl:
		p2 -= f_smpl
	p3 = (p2 << 32) // f_smpl
	p3 &= 0xFFFFFFFF
	
	print(i, p1, p3, p1 - p3)

p3 дает нулевую фазовую ошибку через f_smpl семплов, а p1 дает ошибку 1.63E-6.

warn{это Python, поэтому // - это не комментарий, а целочисленное деление}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 минут назад, adnega сказал:

Раз уж мы про округления, то

...

Зачем так сложно? Если так уж хочется ещё точнее поддерживать частоту, то достаточно просто увеличить точность phase - сделать его 64-битным. С 64-разрядным приращением. И для sine() брать старшие 32 разряда от phase.

Тогда вместо LDR\ADD\STR будет LDRD\ADD\ADC\STRD - всего на 1 команду больше.

 

PS: Даже с 32-разрядной фазой - Вы же сами посчитали погрешность частоты. Она составит какие-то доли ppm. Ещё поискать нужно генератор, который даст сопоставимую погрешность. А если генератор имеет на порядки меньшую точность, то какой смысл считать фазу точнее?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...