CPU Course Review - 18. AMBA BUS (APB Protocol - UART)

2025. 2. 28. 15:21·AI SOC COURSE/SYSTEM VERILOG (CPU 설계)

1. Title

AMBA BUS (APB Protocol)


2. Category

"RISC-V", "AMBA BUS", "APB Protocol"

 

3. Key Concepts

 

CPU Course Review - 17. AMBA BUS (APB Protocol - FND CONTROL)

1. TitleAMBA BUS (APB Protocol)2. Category"RISC-V", "AMBA BUS", "APB Protocol" 3. Key ConceptsAPB Protocol을 Verilog로 구현한다. 4. Setup  CPU Course Review - 15. AMBA BUS (APB Protocol - GPIO)1. TitleAMBA BUS (APB Protocol)2. Category"RISC

salmon1113.tistory.com

APB Protocol을 Verilog로 구현한다.

 

4. Setup

이전 게시글에서 FND에 APB Interface를 추가한 것에 이어 APB Interface를 이용해 UART를 구현한다.

5. Code Review

module apb_slave_interface_uart (
    input  logic        PCLK,     // APB CLK
    input  logic        PRESET,   // APB asynchronous RESET
    // APB Interface Signals
    input  logic [31:0] PADDR,
    input  logic        PWRITE,
    input  logic        PSEL,
    input  logic        PENABLE,
    input  logic [31:0] PWDATA,
    output logic [31:0] PRDATA,
    output logic        PREADY,
    // Internal Signals
    output logic control,
    output logic [ 7:0] tx_data,
    input  logic [ 7:0] rx_data
);

    localparam START_ADDR = 4'h0;
    localparam TX_ADDR = 4'h4;
    localparam RX_ADDR = 4'h8;

    logic [31:0] start_reg, rx_reg, tx_reg;

    assign control = start_reg[0];
    assign tx_data = tx_reg[7:0];
    assign rx_reg  = {24'b0, rx_data};

    always_ff @(posedge PCLK, posedge PRESET) begin
        if (PRESET) begin
            start_reg <= 0;
            tx_reg <= 0;
        end else begin
            PREADY <= 1'b0;

            if (PSEL && PENABLE && PWRITE) begin
                PREADY <= 1'b1;
                case (PADDR[3:0])
                    START_ADDR: start_reg <= PWDATA;
                    TX_ADDR: tx_reg <= PWDATA;
                    default: ;
                endcase
            end else if (PSEL && PENABLE && !PWRITE) begin
                PREADY <= 1'b1;
                case (PADDR[3:0])
                    START_ADDR: PRDATA <= start_reg;
                    RX_ADDR: PRDATA <= rx_reg;
                    default: PRDATA = 'x;
                endcase
            end
        end
    end
endmodule


module UART_FIFO_TOP (
    input clk,
    input reset,
    input start,
    input [7:0] tx_data,
    output [7:0] rx_data,
    input rx,
    output tx
);

    wire [7:0] w_tx_data, w_rx_data;
    wire w_empty, w_full;
    wire w_start;


    wire [7:0] w_fifo_data;

    wire w_tx_busy, w_rx_done;

    /*
    FIFO U_TX_FIFO(
    .clk(clk), .reset(reset),
    .wData(tx_data),
    .wr_en(1),
    .full(),
    .rData(w_tx_data),
    .rd_en(1),
    .empty()
    );
*/

    UART_TOP U_UART (
        .clk(clk),
        .reset(reset),
        .start(start),
        .tx_data(tx_data),
        .rx(rx),
        .tx(tx),
        .rx_data(rx_data),
        .tx_busy(),
        .tx_done(),
        .rx_busy(),
        .rx_done()
    );

    /*
    FIFO U_RX_FIFO(
    .clk(clk), .reset(reset),
    .wData(rx_data),
    .wr_en(1),
    .full(),
    .rData(rx_data),
    .rd_en(1),
    .empty()
    ); 
    */
endmodule
CPU를 통해 0x1000_5000번지를 통해 UART를 ENABLE 시킨 후,
0x1000_5004번지에 값을 쓰게 되면, 해당 값을 UART로 송신한다.
0x1000_5008번지에서는 송신되는 값을 항상 받아 레지스터에 저장 후, LED를 동작시키는 신호로 빠져나간다.
module periph_uart ( 
    input  logic        PCLK,          // APB CLK
    input  logic        PRESET,        // APB asynchronous RESET
    // APB Interface Signals
    input  logic [31:0] PADDR,
    input  logic        PWRITE,
    input  logic        PSEL,
    input  logic        PENABLE,
    input  logic [31:0] PWDATA,
    output logic [31:0] PRDATA,
    output logic        PREADY,
    input  logic        start_button,
    // Internal Signals
    input  logic        rx,
    output logic        tx
);

    logic [7:0] tx_data, rx_data;
    logic control, clk_out;

    apb_slave_interface_uart U_APB_SLAVE_INTERFACE (
        .*,
        .control(control),
        .tx_data(tx_data),
        .rx_data(rx_data)
    );
 
    clock_gate U_CLOCK_GATE(
        .clk_in(PCLK),
        .enable(control),
        .clk_out(clk_out)
    );

    UART_FIFO_TOP U_UART (
        .clk(clk_out),
        .reset(PRESET),
        .start(start_button),
        .tx_data(tx_data),
        .rx_data(rx_data),
        .rx(rx),
        .tx(tx)
    );
endmodule

7. Testing and Debugging

* Testing Tools: VIVADO, BASYS-3, Modelsim

  • 헤더 파일(하드웨어 레지스터 정의, 구조체, 함수 선언)
#include <stdint.h>

#define __IO              volatile


typedef struct{
    __IO uint32_t DDR;
    __IO uint32_t ODR;
} GPO_TypeDef;

typedef struct{
    __IO uint32_t DDR;
    __IO uint32_t IDR;
} GPI_TypeDef;

typedef struct{
    __IO uint32_t DDR;
    __IO uint32_t IDR;
    __IO uint32_t ODR;
} GPIO_TypeDef;

typedef struct{
    __IO uint32_t START;
    __IO uint32_t DATA;
} FND_TypeDef;

typedef struct{
    __IO uint32_t START;
    __IO uint32_t PRESCALER;
    __IO uint32_t TX;
    __IO uint32_t RX;
} UART_TypeDef;


#define APB_PERIPH_BASE      0X10000000
#define RAM_BASE             (APB_PERIPH_BASE + 0X0000)
#define GPOA_BASE            (APB_PERIPH_BASE + 0X1000)
#define GPIB_BASE            (APB_PERIPH_BASE + 0X2000)
#define GPIOC_BASE           (APB_PERIPH_BASE + 0X3000)
#define FND_BASE             (APB_PERIPH_BASE + 0X4000)
#define UART_BASE            (APB_PERIPH_BASE + 0X5000)

#define GPOA_DDR *(volatile uint32_t *)(GPOA_BASE + 0x00)
#define GPOA_ODR *(volatile uint32_t *)(GPOA_BASE + 0x04)
#define GPIB_DDR *(volatile uint32_t *)(GPIB_BASE + 0x00)
#define GPIB_IDR *(volatile uint32_t *)(GPIB_BASE + 0x04)

#define GPIOC_DDR *(volatile uint32_t *)(GPIOC_BASE + 0x00)
#define GPIOC_IDR *(volatile uint32_t *)(GPIOC_BASE + 0x04)
#define GPIOC_ODR *(volatile uint32_t *)(GPIOC_BASE + 0x08)

#define FND_START *(volatile uint32_t *)(FND_BASE + 0x00)
#define FND_DATA *(volatile uint32_t *)(FND_BASE + 0x04)

#define UART_START     *(volatile uint32_t *)(UART_BASE + 0x00)
#define UART_PRESCALER *(volatile uint32_t *)(UART_BASE + 0x04)
#define UART_TX        *(volatile uint32_t *)(UART_BASE + 0x08)
#define UART_RX        *(volatile uint32_t *)(UART_BASE + 0x0c)

#define GPOA    ((GPO_TypeDef *)GPOA_BASE)
#define GPIB    ((GPI_TypeDef *)GPIB_BASE)
#define GPIOC   ((GPIO_TypeDef *)GPIOC_BASE)
#define FND     ((FND_TypeDef *)FND_BASE)
#define UART    ((UART_TypeDef*)UART_BASE)

void UART_INIT(UART_TypeDef* UARTx, uint32_t prescale);
void UART_SEND(UART_TypeDef* UARTx, uint32_t number);
uint32_t UART_RECEIVE(UART_TypeDef* UARTx);

void LIGHT_INIT(GPO_TypeDef* GPOx);
void LIGHT_EN(GPO_TypeDef* GPOx, uint32_t number);
  • 소스 파일(함수 구현)

void UART_INIT(UART_TypeDef* UARTx, uint32_t prescale)
{
    UARTx->START = 0x01;
    UARTx->PRESCALER = prescale;

}
void UART_SEND(UART_TypeDef* UARTx, uint32_t number)
{
    UARTx->TX = number;
}

uint32_t UART_RECEIVE(UART_TypeDef* UARTx)
{
    return UARTx->RX;
}

/////////////////////////////////////////////////////////////////////////////

void LIGHT_INIT(GPO_TypeDef* GPOx)
{
    GPOx->DDR = 0xff;
}

void LIGHT_EN(GPO_TypeDef* GPOx, uint32_t number)
{
    GPOx->ODR = number;
}

/////////////////////////////////////////////////////////////////////////////

void delay(int n)
{
    uint32_t temp = 0;

    for(int i = 0; i < n; i++)
    {
            for (int j = 0; j < 1000; j++)
        {
            temp ++;
        }
    }
}
  • 응용 코드 (사용자 코드): 드라이버를 호출해서 하드웨어를 제어하는 부분.
int main()
{
    uint32_t rx_data = 0;
    uint32_t tx_data = 0x41;  //  'A'
    uint32_t prescale = 10416;   // 9600 BAUD RATE;
    

    UART_INIT(UART, prescale);
    
    
    LIGHT_INIT(GPOA);

    UART_SEND(UART, tx_data);
    while(1)
    {    
        rx_data = UART_RECEIVE(UART);
        LIGHT_EN(GPOA, rx_data);
    }
}

 

GPOA에 0x41('A') 값을 저장하고 있다가 User가 Start 신호를 보내면 TX로 'A'를 내보내고, RX는 값을 항상 받아 레지스터에 저장 후, LED를 동작시키는 신호로 동작하는 코드 작성.

 

 

 

'AI SOC COURSE > SYSTEM VERILOG (CPU 설계)' 카테고리의 다른 글

CPU Course Review - 20. AMBA BUS (APB Protocol - SENSORS)  (0) 2025.03.01
CPU Course Review - 19. AMBA BUS (APB Protocol - PWM)  (0) 2025.02.28
CPU Course Review - 17. AMBA BUS (APB Protocol - FND CONTROL)  (0) 2025.02.27
CPU Course Review - 16. Linker Script, Startup Code  (0) 2025.02.27
CPU Course Review - 15. AMBA BUS (APB Protocol - GPIO)  (0) 2025.02.26
'AI SOC COURSE/SYSTEM VERILOG (CPU 설계)' 카테고리의 다른 글
  • CPU Course Review - 20. AMBA BUS (APB Protocol - SENSORS)
  • CPU Course Review - 19. AMBA BUS (APB Protocol - PWM)
  • CPU Course Review - 17. AMBA BUS (APB Protocol - FND CONTROL)
  • CPU Course Review - 16. Linker Script, Startup Code
Dinoj
Dinoj
  • Dinoj
    AlOG
    Dinoj
  • 전체
    오늘
    어제
    • 분류 전체보기 (201)
      • PCB 이론 (13)
        • PI (2)
        • SI (11)
      • 회로 이론 (63)
        • 기타 학습 (20)
        • UVM (Universal Verification.. (12)
        • AI HARDWARE (12)
        • COMPUTER VISION (18)
        • Python (Pytorch) (1)
      • PROJECTS (29)
        • AI 가속기 (10)
        • 영상 처리 (3)
        • UVM (Universal Verification.. (2)
        • CPU 설계 (5)
        • CMOS VLSI (2)
        • Verilog (2)
        • Firmware (2)
        • C 언어 (2)
        • 기타 프로젝트 (1)
      • Linux (20)
        • Embedded Linux (Rpi) (7)
        • Petalinux (7)
        • Linux 기초 (6)
      • AMBA BUS (16)
        • AXI BUS (5)
        • APB BUS (2)
        • Vitis (8)
      • AI SOC COURSE (53)
        • 영상 처리 (5)
        • SYSTEM VERILOG (CPU 설계) (20)
        • VERILOG 기초 (5)
        • CMOS VLSI (7)
        • FIRMWARE (9)
        • C PROGRAMMING (1)
        • Python (Keras) (6)
      • 코딩 지식 (5)
        • SYSTEM VERILOG (3)
        • TCL (2)
      • TISTORY (1)
  • 블로그 메뉴

    • 홈
    • 글쓰기
    • 관리
    • Info
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Dinoj
CPU Course Review - 18. AMBA BUS (APB Protocol - UART)
상단으로

티스토리툴바