§ Верхний уровень

serial SERIAL(

    .clk12    (),      // Частота
    .rx       (),      // Входящие данные
    .rx_byte  (),      // Исходящий байт (8 bit)
    .rx_ready ()       // Строб готовности
);

§ Код модуля

  • Модуль приёмопередатчика UART (FTDI Marsohod)
  • Скорость: 460800 бод, эквивалентно 51200 байт в секунду (50 кб в секунду)
  • Длина: 1 старт бит + 8 бит (байт) + 1 (бит чётности)
module serial(
    input   wire            clk12,          // Частота 12,00 MHZ
    input   wire            rx,             // Входящие данные
    output  reg     [7:0]   rx_byte,        // Исходящий байт
    output  wire            rx_ready        // Бит готовности
);

// 460800 baud
parameter R_COUNT = 26;     // Полный период (12'000'000 / 26 ~ 460800 бод)

reg [8:0] rc_data;          // Исходящие данные
reg [1:0] latch;            // Детектор спада фронта
reg [6:0] period   = 1'b0;  // Период между битами
reg [3:0] num_bits = 1'b0;  // Количество считанных битов (0..8)
reg [1:0] flg      = 1'b0;  // Логика, позволяющая установить строб готовности
reg       waiting  = 1'b1;  // По умолчанию, режим приёма включён

// Формируется строб готовности после 1 такта по приёму
assign rx_ready = (flg == 2'b10);

// С помощью двух подряд идущих битов определяем, когда будет спад, чтобы начать приём
always @(posedge clk12) latch <= {latch[0], rx};

// Признак окончания данных
wire eof = (period == R_COUNT-1 && num_bits == 4'd9);

// Распределение входящих битов данных
// num_bits =     9      8 7 6 5 4 3 2 1    0    <--- справа налево
//            Четность [     Данные     ] Старт

// Основной модуль приёма
always @(posedge clk12) begin

    // Обнаружен спад во время ожидания данных - это стартовый бит.
    // Переключаемся в режим приёма данных
    if (waiting && latch[1:0] == 2'b10) begin
        waiting <= 1'b0;

    end

    // Сейчас мы в режиме приема данных
    else if (!waiting) begin

        // Сброс периода, и просмотр результатов
        if (period == R_COUNT-1) begin

            period <= 1'b0;

            // Был принят последний бит, в режим ожидания
            if (num_bits == 4'd9) begin

                waiting  <= 1'b1;           // В режим ожидания спада (старт-бита)
                num_bits <= 1'b0;           // Для следующего раза
                rx_byte  <= rc_data[7:0];   // Берем итоговые данные (без старт бита и бита чётности, 8-я позиция)

            // К следующему биту
            end else num_bits <= num_bits + 1'b1;

        end
        else begin

            // Обнаружен полупериод - пишет данные
            if (period == R_COUNT / 2) rc_data <= {latch[1], rc_data[8:1]};

            // Считаем количество тиков
            period <= period + 1'b1;

        end

    end

    // Пишется бит EOF, на следующем такте будет выставлен 1 (строб), который потом исчезнет на ещё одном такте
    flg <= {flg[0], eof};

end

endmodule