Доброго времени суток!
Делаю свой первый конфигурируемый приёмник асинхронного последовательного протокола. Конфигурация подразумевает возможность
программного задания скорости приёма.
Соответсвенно, что есть -
есть некоторая частота осциллятора и есть значения частот семплирования линии, рассчитанные
как скорость приёма (baud) умноженная на 64. Множитель 64 взял для более точного распознавания стартового перепада.
Скажем, baud = 115200 Гц => baud*64 = 7 372 800 Гц
Пусть частота осциллятора равна 40 МГц, тогда для получения baud*64 получаем коэффициент деления 5,42.
Тут и начинаются проблемы - если взять, например, 5-ку, то возникает погрешность...
Такая ситуация складывается с любыми значениями baud => нужно корректировать частоту, чтобы избежать рассогласования приёмника и передатчика и сделать это максимально прозрачно для всех остальных компонентов блока приёмника.
Единственный вариант, который пришёл мне в голову - вынести это в блок семплирования линии.
В чём суть, более подробно: рассчитанный коэффициент деления даёт нам в аккурат частоту в 1/64 baud,
но поскольку приходится его округлять, то новый коэффициент уже не будет отмерять ровно по 1/64 baud, т.е.
нужно рассчитать какова новая частота семплирования и подогнать под значение нашего множителя.
Проще говоря: при значении 5 - значение множителя будет 69, а не 64. Для baud 57600 - 63, а не 64 и т.д.
Только для 9600 получилось в аккурат 64
Но хочется, чтобы управляющий автомат так и работал с одним коэффициентом (64), чтобы его ещё больше не усложнять.
Следовательно - как вариант, в блоке семплирования завести внутренний служебный счётчик, который бы отсчитывал реальное кол-во импульсов,
а на выход выдавал уже скорректированное.
Вот пример verilog-кода, демонстрирующий сказанное:
Код
case (baud_num)
1: begin
value <= value + 1; // baud = 9600
inner_cnt <= 0;
end
default: begin //baud = 115200
inner_cnt <= inner_cnt + 1;
value <= (inner_cnt == 12 ||
inner_cnt == 24 || //Такое условие сделал, чтобы более равномерно
inner_cnt == 36 || // провести коррекцию в статистическом смысле
inner_cnt == 48 ||
inner_cnt == 60) ? value : value + 1;
end
endcase
И всё бы ничего - если бы данное решение занимало малое количество логических элементов, так нет...
Может быть, есть какие-то другие способы решить данную проблему, при этом более экономно расходуя ресурсы?
Заранее благодарю за советы.