AG32( MCU + FPGA)实现多串口(15个UART)的应用

时间:2024-11-08 22:17:50

AG32 的引脚定义

AG32只有模拟相关的IO是固定的,其它数字IO接口可以任意分配。

QFN-32 Pin name AG32VFxxxK AGRV2KQ32
1 PIN_1 IO/RTC IO_GB
2 PIN_2 IO/OSC_IN IO
3 PIN_3 IO/OSC_OUT IO
4 NRST NRST NRST
5 PIN_5 IO_ADC_IN12 IO
6 VDDA33 VDDA33 VDDA33
7 PIN_7 IO_WKUP_ADC_IN0_CMP_PA0 IO
8 PIN_8 IO_ADC_IN1_CMP_PA1 IO
9 PIN_9 IO_ADC_IN2_CMP_PA2 IO
10 PIN_10 IO_ADC_IN3_CMP_PA3 IO
11 PIN_11 IO_ADC_IN4_CMP_PA4_DAC0 IO
12 PIN_12 IO_ADC_IN5_CMP_PA5_DAC1 IO
13 PIN_13 IO_ADC_IN6 IO
14 PIN_14 IO_ADC_IN7 IO
15 PIN_15 IO_BOOT1 IO
16 VDD33 VDD33 VDD33
17 GND GND GND
18 PIN_18 IO IO
19 PIN_19 IO IO
20 PIN_20 IO_UART0_TX IO
21 PIN_21 IO_UART0_RX IO
22 PIN_22 IO_USBDM IO
23 PIN_23 IO_USBDP IO
24 PIN_24 IO_JTMS JTMS
25 PIN_25 IO_JTCK JTCK
26 PIN_26 IO_JTDI IO
27 PIN_27 IO_JTDO IO
28 PIN_28 IO_JNTRST IO
29 PIN_29 IO IO
30 BOOT0 BOOT0 GND
31 PIN_31 IO IO
32 VDD33 VDD33 VDD33
  website: www.hizyuan.com  

AG32VF407VGT6  LQFP100封装,有5个UART。除了MCU本身带的5个UART,需要更多就用内部FPGA编程实现。

目前我们可以提供新的多串口参考设计,用FPGA逻辑实现了10个,MCU自带5个。总共可以实现15个串口UART通信。

Logic设计相关的参考设计:

multi_uart.v 参考代码:

uart_tx #(DATA_WIDTH, FIFO_DEPTH) u_tx[CNT-1:0](
  .clk        (apb_clock                 ),
  .rstn       (apb_resetn                ),
  .baud16     (baud16                    ),
  .tx_write   (tx_write                  ),
  .tx_data    (apb_pwdata[DATA_WIDTH-1:0]),
  .lcr_sps    (lcr_sps                   ),
  .lcr_stp2   (lcr_stp2                  ),
  .lcr_eps    (lcr_eps                   ),
  .lcr_pen    (lcr_pen                   ),
  .tx_clear   (clear_flags               ),
  .tx_full    (tx_full                   ),
  .tx_empty   (tx_empty                  ),
  .tx_busy    (tx_busy                   ),
  .tx_complete(tx_complete               ),
  .tx_dma_en  (tx_dma_en                 ),
  .tx_dma_clr (tx_dma_clr                ),
  .tx_dma_req (tx_dma_req                ),
  .uart_txd   (uart_txd                  )
);

uart_rx #(DATA_WIDTH, FIFO_DEPTH) u_rx[CNT-1:0](
  .clk          (apb_clock    ),
  .rstn         (apb_resetn   ),
  .baud16       (baud16       ),
  .lcr_sps      (lcr_sps      ),
  .lcr_stp2     (lcr_stp2     ),
  .lcr_eps      (lcr_eps      ),
  .lcr_pen      (lcr_pen      ),
  .rx_read      (rx_read      ),
  .rx_clear     (clear_flags  ),
  .rx_full      (rx_full      ),
  .rx_empty     (rx_empty     ),
  .rx_data      (rx_data      ),
  .rx_idle      (rx_idle      ),
  .framing_error(framing_error),
  .parity_error (parity_error ),
  .break_error  (break_error  ),
  .overrun_error(overrun_error),
  .rx_dma_en    (rx_dma_en    ),
  .rx_dma_clr   (rx_dma_clr   ),
  .rx_dma_req   (rx_dma_req   ),
  .uart_rxd     (uart_rxd     )
);
endmodule

uart_rx.v 参考代码:

module uart_rx #(parameter DATA_WIDTH = 8, FIFO_DEPTH = 4) (
  input                       clk,
  input                       rstn,
  input                       baud16,
  input                       uart_rxd,
  input                       lcr_sps,
  input                       lcr_stp2,
  input                       lcr_eps,
  input                       lcr_pen,
  input                       rx_read,
  input                       rx_clear,
  output                      rx_full,
  output                      rx_empty,
  output     [DATA_WIDTH-1:0] rx_data,
  output reg                  rx_idle,
  input                       rx_dma_en,
  input                       rx_dma_clr,
  output reg                  rx_dma_req,
  output reg                  framing_error,
  output reg                  parity_error,
  output reg                  break_error,
  output reg                  overrun_error
);
parameter UART_IDLE   = 3'h0;
parameter UART_START  = 3'h1;
parameter UART_DATA   = 3'h2;
parameter UART_PARITY = 3'h3;
parameter UART_STOP   = 3'h4;

parameter BAUD_CNT = 16;
parameter SAMPLE_CNT = 3;

reg [2:0] rx_state;

reg [SAMPLE_CNT+1:0] rx_in; // 2 extra bits for synchronization
reg [1:0] rx_val;
reg [3:0] rx_baud_cnt;
reg rx_bit;
reg rx_parity;
reg [$clog2(DATA_WIDTH):0] rx_data_cnt;
reg [DATA_WIDTH-1:0] rx_shift_reg;
reg rx_idle_en;

wire rx_lo = rx_val <= 1;
wire rx_hi = !rx_lo;
wire rx_sample = baud16 && rx_baud_cnt == BAUD_CNT / 2 + 1; // Where to sample rx input

wire fifo_wren = rx_state == UART_STOP && rx_sample;

sync_fifo #(.WIDTH(DATA_WIDTH), .DEPTH(FIFO_DEPTH), .SHOWAEAD(1)) rx_fifo(
  .clk  (clk         ),
  .rstn (rstn        ),
  .wren (fifo_wren   ),
  .rden (rx_read     ),
  .din  (rx_shift_reg),
  .dout (rx_data     ),
  .full (rx_full     ),
  .empty(rx_empty    )
);

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_in <= {SAMPLE_CNT+1{1'b1}};
  end else if (baud16) begin
    rx_in <= { rx_in[SAMPLE_CNT:0], uart_rxd };
  end
end

integer i;
always @(*) begin
  rx_val = 0;
  for (i = 2; i < SAMPLE_CNT + 2; i = i + 1)
    rx_val = rx_val + rx_in[i];
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_bit <= 1'b0;
  end else if (baud16 && rx_baud_cnt == 15) begin
    rx_bit <= 1'b1;
  end else begin
    rx_bit <= 1'b0;
  end
end

always @(posedge clk) begin
  if (rx_state == UART_START) begin
    rx_data_cnt <= DATA_WIDTH - 1;
  end else if (rx_bit) begin
    if (rx_state == UART_DATA && rx_data_cnt == 0) begin
      rx_data_cnt <= DATA_WIDTH + 1 + lcr_pen + lcr_stp2;
    end else begin
      rx_data_cnt <= rx_data_cnt - 1;
    end
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_shift_reg <= 0;
  end else if (rx_state == UART_DATA && rx_sample) begin
    rx_shift_reg <= { rx_hi, rx_shift_reg[DATA_WIDTH-1:1] };
  end
end

always @(posedge clk) begin
  if (rx_state == UART_START) begin
    rx_parity <= !lcr_eps;
  end else if (rx_state == UART_DATA && rx_bit && !lcr_sps) begin
    rx_parity <= rx_parity ^ rx_shift_reg[7];
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_baud_cnt <= 0;
  end else if (rx_state == UART_IDLE && rx_lo) begin
    rx_baud_cnt <= SAMPLE_CNT - 1;
  end else if (baud16) begin
    rx_baud_cnt <= rx_baud_cnt + 1;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_idle_en <= 1'b0;
  end else if (!rx_empty) begin
    rx_idle_en <= 1'b1;
  end else if (rx_clear) begin
    rx_idle_en <= 1'b0;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_idle <= 1'b0;
  end else if (rx_state == UART_IDLE && rx_data_cnt == 0 && rx_bit && rx_idle_en) begin
    rx_idle <= 1'b1;
  end else if (rx_clear) begin
    rx_idle <= 1'b0;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    framing_error <= 1'b0;
  end else if (rx_state == UART_STOP && rx_sample && rx_lo) begin
    framing_error <= 1'b1;
  end else if (rx_clear) begin
    framing_error <= 1'b0;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    parity_error <= 1'b0;
  end else if (rx_state == UART_PARITY && rx_sample && rx_parity != rx_hi) begin
    parity_error <= 1'b1;
  end else if (rx_clear) begin
    parity_error <= 1'b0;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    break_error <= 1'b0;
  end else if (rx_state == UART_STOP && rx_sample && rx_lo && rx_shift_reg == 0) begin
    break_error <= 1'b1;
  end else if (rx_clear) begin
    break_error <= 1'b0;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    overrun_error <= 1'b0;
  end else if (fifo_wren && rx_full) begin
    overrun_error <= 1'b1;
  end else if (rx_clear) begin
    overrun_error <= 1'b0;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_dma_req <= 1'b0;
  end else if (!rx_dma_en || rx_dma_clr) begin
    rx_dma_req <= 1'b0;
  end else if (!rx_empty) begin
    rx_dma_req <= 1'b1;
  end
end

always @(posedge clk or negedge rstn) begin
  if (!rstn) begin
    rx_state <= UART_IDLE;
  end else begin
    case (rx_state)
      UART_IDLE:   if (rx_lo)  rx_state <= UART_START;
      UART_START:  if (rx_bit && rx_baud_cnt == 0) rx_state <= UART_DATA;
      UART_DATA:   if (rx_bit && rx_data_cnt == 0) rx_state <= lcr_pen ? UART_PARITY : UART_STOP;
      UART_PARITY: if (rx_bit) rx_state <= UART_STOP;
      UART_STOP:   if (rx_sample && rx_hi) rx_state <= UART_IDLE;
    endcase
  end
end

endmodule
 

更多参考设计,欢迎私信交流沟通。