Altifigence Academy

63 / 63 · Теория

Итоговый практикум: передатчик UART и время кадра

Объедините делитель, сдвиговый регистр и управление потоком в кадр 8N1 и проверьте границы битов.

Сначала зафиксируйте формат кадра

Предварительные знания: счётчики, сдвиговые регистрыРегистр хранит многобитное состояние. Синхронные регистры в этом курсе записывают определённый вход на фронте тактового сигнала. Подробнее, valid/ready и синхронный сбросСброс возвращает состояние к заданному начальному значению. Нужно определить, синхронен он или асинхронен и имеет ли приоритет над другими управляющими сигналами. Подробнее.

Кадр UARTUART передаёт последовательные данные со стартовым битом, битами данных и стоповым битом без отдельной линии такта. Передатчик и приёмник должны согласовать скорость передачи и формат кадра. 8N1 содержит один стартовый бит, восемь битов данных и один стоповый бит; бит паритета отсутствует. Idle и stop равны 1, start — 0, данные передаются от LSBLSB — бит с наименьшим позиционным весом. Проверяйте одновременно направление записи и правила индексации. Подробнее. Все биты удерживаются одинаковое время. Практикум рассматривает только передачу от источника в том же тактовом домене.

Bactual=fclkD,ϵ=Bactual−BtargetBtarget×100%B_{\mathrm{actual}}=\frac{f_{\mathrm{clk}}}{D},\qquad \epsilon=\frac{B_{\mathrm{actual}}-B_{\mathrm{target}}}{B_{\mathrm{target}}}\times100\%

Для 48 MHz и целевых 115200 baud можно выбрать целый делитель D=417. Фактическая скорость примерно 115108 baud, ошибка около −0.080%. Допустимую суммарную ошибку с приёмником проверяют по спецификациям устройств.

Разверните 0x53 в порядок передачи

Запись 0x53 — 01010011, но по линии от младшего бита идут 1,1,0,0,1,0,1,0. Одна ячейка рисунка — битовый интервал из D системных тактов, а не один системный период. До и после показано по одной ячейке idle для сравнения.

UART 8N1 · 0x53 · младший бит первым
Показать данные диаграммы
Данные диаграммы: каждый символ — один интервал; точка сохраняет предыдущее состояние; p — один тактовый цикл.
СигналДиаграммаЗначения шины
tx101.0.10101.
фаза234523452345ожидание → старт → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → стоп → ожидание

От start до конца stop проходит ровно 10D тактов. Последовательные одинаковые биты тоже занимают каждый свой период: отсутствие перехода на линии не означает отсутствие бита.

Захватите входной байт только один раз

Контракт реализации требует константу CLKS_PER_BIT≥1. При busy вход не принимается, весь кадр использует data, захваченные при старте. Вместо нового bit-clock используется счётчик момента сдвига внутри исходного тактового домена.

SystemVerilog
module uart_tx #(
    parameter int unsigned CLKS_PER_BIT = 417,
    localparam int CW = (CLKS_PER_BIT <= 1) ? 1 : $clog2(CLKS_PER_BIT)
) (
    input  logic       clk, rst,
    input  logic       in_valid,
    output logic       in_ready,
    input  logic [7:0] in_data,
    output logic       tx, busy, done
);
    logic [9:0] frame;
    logic [3:0] bits_left;
    logic [CW-1:0] ticks_left;
    assign in_ready = !busy;

    always_ff @(posedge clk) begin
        if (rst) begin
            tx         <= 1'b1;
            busy       <= 1'b0;
            done       <= 1'b0;
            bits_left  <= 4'd0;
            ticks_left <= '0;
        end else begin
            done <= 1'b0;
            if (!busy) begin
                if (in_valid) begin
                    frame      <= {1'b1, in_data, 1'b0};
                    tx         <= 1'b0;
                    busy       <= 1'b1;
                    bits_left  <= 4'd10;
                    ticks_left <= CW'(CLKS_PER_BIT-1);
                end
            end else if (ticks_left != 0) begin
                ticks_left <= ticks_left - 1'b1;
            end else if (bits_left == 4'd1) begin
                tx   <= 1'b1;
                busy <= 1'b0;
                done <= 1'b1;
            end else begin
                frame      <= {1'b1, frame[9:1]};
                tx         <= frame[1];
                bits_left  <= bits_left - 1'b1;
                ticks_left <= CW'(CLKS_PER_BIT-1);
            end
        end
    end
endmodule

На фронте приёма E0 tx становится start=0. Далее переход к следующему биту происходит через каждые D тактов. На E0+9D начинается stop, на E0+10D снимается busy и на цикл появляется done. Последний stop тоже должен длиться D периодов.

До фронта завершения in_ready=0, поэтому новый кадр принимается не раньше следующего фронта. Минимальный интервал приёмов равен 10D+110D+1 тактам. Один дополнительный idle-такт — часть нормального поведения.

Предскажите биты вручную

Данные 8'h53 от LSB: 1,1,0,0,1,0,1,0. Полный кадр:

Позицияstartd0d1d2d3d4d5d6d7stop
tx0110010101

Нельзя проверять лишь число изменений tx: одинаковые соседние биты не создают переходов. От начала кадра выбирайте середину каждого битового интервала, сравнивайте с эталоном и проверяйте длительность start и stop. Для быстрой модульной проверки используйте также D=1,2,3.

Расширение: соединение с FIFO

FIFOFIFO — очередь, выдающая данные в порядке их поступления. Правила заполненности, пустоты и допустимости одновременного чтения и записи входят в контракт поведения. Подробнее с регистрацией выхода чтения обновляет dout и dout_valid сразу после фронта принятия pop. Следующая схема общего домена выбирает ответ на следующем положительном фронтеПоложительный фронт — момент перехода такта из 0 в 1. Его следует отличать от уровня, означающего весь интервал CLK=1. Подробнее. Если передать UART значение dout на самом фронте pop, это может быть прежнее значение. Добавьте однопозиционный буфер возвращённого байта и состояние pending, передавая UART ровно один раз при ready.

Итоговая проверка включает 00,FF,01,80,55,53, изменения входа во время busy, последовательные кадры и reset посреди кадра. Политика reset прерывает передачу и возвращает tx в idle=1. Приёмник всё же может увидеть допустимый кадр, поэтому один лишь формат кадра UART не гарантирует обнаружения прерванной передачи. Если затронутые данные обязательно нужно отбросить, задайте системный контракт, который согласует reset приёмника с передатчиком либо передаёт приёмнику отдельный сигнал о прекращении передачи.

Дополнительное чтение: Microchip — EUSART and 8N1 framing

Попробуйте сами

CLKS_PER_BIT=4, данные приняты на E0. Найдите фронты начала d0, stop и появления done. При новом in_valid=1 на E40 принимается ли следующий байт на этом фронте?

Прочитать объяснение

D0 начинается после E4, stop — E36, done — E40. До E40 busy=1 и in_ready=0, поэтому новый байт ещё не принят. Передатчик должен хранить valid и data; следующий байт можно принять на E41. Кадр длится 40 тактов, минимальный интервал приёма — 41.

Выбор действует в этом браузере. Его можно изменить внизу страницы.