Raspberry Pi 3에서 BareMetal 해봤다 ~ Mini UART ~

소개



지난번 L치카를 했으므로 이번에는 UART를 해보겠습니다.

UART 정보



BCM2837에는 다음 두 가지 UART가 있습니다.
  • UART1: Mini UART
  • UART0: PL011

  • 예제와 같이 다음 데이터 시트 문서 참조.
    BCM2837 ARM Peripherals

    이번에는 간단한 "Mini UART"를 사용합니다.

    사용할 레지스터



    이번에는 MU_IOMU_LSR 를 사용합니다.

    MU_IO


    MU_IO는 송신 FIFO에 데이터를 추가하거나 수신 FIFO에서 데이터를 검색하는 데 사용됩니다.

    자세한 내용은 문서 11페이지에 나와 있습니다.
    BCM2835의 데이터 그대로이므로 0x7E2150400x3F215040로 읽어보십시오.

    MU_LSR


    MU_LSR (Line Status Register)는 UART의 송수신 FIFO 상태 확인에 사용됩니다.

    자세한 내용은 문서 15페이지에 나와 있습니다.
    BCM2835의 데이터 그대로이므로 0x7E2150540x3F215054로 읽어보십시오.

    이번은 송신만으로, 송신 FIFO의 상태를 확인하는 것만으로 좋으므로, 5 비트째의 Transmitter empty 와 6 비트째의 Transmitter idle 를 확인합니다.
  • 5 비트째의 Transmitter empty 는 송신 FIFO 가 적어도 1 바이트를 받아들일 수 있는 경우에 세트된다.
  • 6 비트째의 Transmitter idle는 송신 FIFO가 비어 있고 Transmitter가 유휴 상태일 때 설정된다.

  • 설정 파일



    UART를 사용하기 위해 "config.txt"에 UART 활성화 설정을 추가합니다.

    config.txt
    # ARMコアをAArch64で起動させる
    arm_control=0x200
    
    # UART有効化
    enable_uart=1
    

    UART 프로그램


    // RaspberryPi3 Memory Mapped I/O Base Address
    #define MMIO_BASE 0x3F000000
    
    // Memory Mapped I/O
    #define IOREG(X)  (*(volatile unsigned int *) (X))
    
    // UART
    #define MU_IO           IOREG(MMIO_BASE + 0x00215040)
    #define MU_LSR          IOREG(MMIO_BASE + 0x00215054)
    #define MU_LSR_TX_IDLE  (1U << 6)
    #define MU_LSR_TX_EMPTY (1U << 5)
    
    ///
    // UART Function
    
    // 文字
    void put_char(unsigned char ch){
        // UARTの送信FIFOの状態を確認
        while (!(MU_LSR & MU_LSR_TX_IDLE) && !(MU_LSR & MU_LSR_TX_EMPTY)){
            asm volatile("nop");
        }
        // UARTの送信FIFOへ1バイト追加
        MU_IO = ch;
    }
    
    // 文字列
    void put_str(char *str){
        while(*str != '\0'){
            put_char(*str++);
        }
    }
    
    // 16進数
    void put_hex(unsigned long long num){
        int      n    = 0;
        unsigned long long base = 16;
        unsigned long long d    = 1;
        char buf[32], *bf;
    
        bf = buf;
    
        // 先頭に"0x"を付ける
        *bf++ = '0';
        *bf++ = 'x';
    
        while(num / d >= base){
            d *= base;
        }
    
        while(d != 0){
            int dgt = num / d;
            num %= d;
            d /= base;
            if(n || dgt > 0 || d == 0){
                *bf++ = dgt + (dgt < 10 ? '0' : ('A') - 10);
                ++n;
            }
        }
    
        *bf = 0;
    
        put_str(buf);
    }
    
    ///
    // Main Function
    
    void main(void){
        put_char('A');
        put_str("\r\nHello, world!\r\n");
        put_hex(2882400018);
        put_str("\r\n");
    
        while (1) {
            asm volatile("nop");
        }
    }
    

    회로도



    Raspberry Pi와의 직렬 통신에는 FTDI USB / 시리얼 변환 케이블 (5V)을 사용합니다.



    실행



    직렬 모니터로 GtkTerm을 사용했습니다.

    설정은 "Configuration -> Port"를 열고 다음과 같이 설정.



    이하 실행중인 모습



    문자, 문자열, 16 진수가 제대로 보내지고 있습니다.

    마지막으로



    UART에서 RaspberryPi에서 보낸 메시지를 얻을 수있었습니다.
    BareMetal에서 UART는 디버깅 할 때 등에 도움이되므로 사용할 수 있도록 해두면 손해가 없습니다.

    이 기사의 소스 코드는 Github에 넣어 있기 때문에, 좋으면 부디 ~
    RaspberryPiBareMetal

    좋은 웹페이지 즐겨찾기