Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблемы при проектировании приёмника последовательного интерфейса
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
MIX@
Доброго времени суток!

Делаю свой первый конфигурируемый приёмник асинхронного последовательного протокола. Конфигурация подразумевает возможность
программного задания скорости приёма.

Соответсвенно, что есть -
есть некоторая частота осциллятора и есть значения частот семплирования линии, рассчитанные
как скорость приёма (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 wink.gif
Но хочется, чтобы управляющий автомат так и работал с одним коэффициентом (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


И всё бы ничего - если бы данное решение занимало малое количество логических элементов, так нет...
Может быть, есть какие-то другие способы решить данную проблему, при этом более экономно расходуя ресурсы?

Заранее благодарю за советы.
SSerge
Вот делили бы на 8 или на 16 вместо 64 и никаких проблем бы не было. Во многих контроллерах UART так и работает, с 16 или 8 клоками на бит. И не жужжит.
Если же очень хочется, есть куча вариантов.
1. Почитать как устроен UART у MSP430 и попробовать догадаться как это реализовано.
2. Сразу после кварца поставить хитрый делитель наподобие 155ИЕ8, далее - как обычно. В прежние времена это было весьма распространённым решением, удавалось достаточно точно подогнать битовую скорость при любой (из разумных) частоте кварца.
DmitryR
Выбор раздела подсказывает, что вы используете FPGA. Так вот, там есть PLL, которые умеют умножать входную частоту на дробь (M/N), и эту дробь можно перепрограммировать во время работы.
Builder
Цитата(MIX@ @ Jan 22 2009, 02:58) *
И всё бы ничего - если бы данное решение занимало малое количество логических элементов, так нет...
Может быть, есть какие-то другие способы решить данную проблему, при этом более экономно расходуя ресурсы?

Если не передумаете использовать деление на 64, как Вам советовали, ещё вариант - использовать для деления
метод оценочной функции, получится типа того, как в алгоритме брезенхема делается, при отрисовке линии.

Получится делитель, с автоматическим учётом округлений. Вот только сколько ресурсов будет - надо пробовать, но
скорее всего меньше, чем Ваш вариант.
EvgenyNik
PLL бы Вас выручил, это да. Но цифра 64, действительно, вызывает некоторое недоумение.
Если нет PLL, то я бы взял кварц на 18.432 МГц, поделил на 10 и получил бы частоту, которая в 16 раз больше 115200 и так далее с нормальными кратностями.
Если цифра 64 не даёт покоя wink.gif , то можно сделать деление 18.432 МГц в 2.5 раза на несложной логике, но смысла в этом нет.
Mig&L
Взляните на оригинальный пример Interface RS-232 на http://www.fpga4fun.com/SerialInterface2.html
sazh
Цитата(MIX@ @ Jan 22 2009, 01:58) *
Скажем, baud = 115200 Гц => baud*64 = 7 372 800 Гц
Пусть частота осциллятора равна 40 МГц, тогда для получения baud*64 получаем коэффициент деления 5,42.
Тут и начинаются проблемы - если взять, например, 5-ку, то возникает погрешность...


А на что влияет эта погрешность? 25 нс туда сюда от середины стартового бита. А до стопового бита 250 нс набежит. За пределы бита на всей посылке никуда не денется.
Не нужен вам промежуточный коэффициент деления 64. Достаточно два параметра. Частота осцилятора (любая системная) и частота несущей baud.

http://electronix.ru/forum/index.php?showt...mp;#entry425957
MIX@
Благодарю за советы!
Забыл сказать, что работаю я с учебным стендом на базе FPGA серии Cyclone, в принципе, возможность для ввода внешнего синхросигнала там есть, но не хочется заморачиваться. А PLL использовать не хочется из-за накладываемых ограничений по портируемости - проект прежде всего учебный.

Думаю, оптимальным будет предложенный Mig&L вариант:
Цитата
FPGA baud generator

It is desirable that the 2000000 be a power of two. Obviously 2000000 is not a power of two. So we change the ratio. Instead of the ratio "2000000/115200", let's use "1024/59" = 17.356. That's very close to our ideal ratio, and makes an efficient FPGA implementation.// 10 bits for the accumulator ([9:0]), and one extra bit for the accumulator carry-out ([10])
Код
reg [10:0] acc;   // 11 bits total!

always @(posedge clk)
  acc <= acc[9:0] + 59; // use only 10 bits from the previous result, but save the full 11 bits

wire BaudTick = acc[10]; // so that the 11th bit is the carry-out



Using our 2MHz clock, "BaudTick" is asserted 115234 times a second, a 0.03% error from the ideal 115200.


А с множителем 64 я, наверное, действительно загнул - возьму 16. Слышал, что меньше 16 брать не рекомендуется, в принципе - большой % ошибок будет, сам не проверял. Вот и решил взять с запасом, благо частоты осциллятора позволяют smile.gif

Ещё возникает вопрос: непосредственно перед сдвигающим регистром приёмника всегда ставят некий "синхронизатор" из двух d-триггеров.
Заявляются следующие два аргумента:
1) позволяет избежать "срабатывания" приёмника от случайной помехи на линии
2) служит для синхронизации частоты передатчика и приёмника.
Первый аргумент мне понятен, а вот второй нет - за счёт чего? Не уж-то это что-то вроде укороченного варианта преамбулы в Ethernet'е?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.