03

はじめに

Githubで公開されている,GitHub - bztsrc/raspi3-tutorial: Bare metal Raspberry Pi 3 tutorialsのコードを読んでいく.今回は03_uart1を理解することを目的とする.

対象ファイル:uart.c, main.c
キーワード:uart, GPIO

uart.c

#include "gpio.h"

/* Auxilary mini UART registers */
#define AUX_ENABLE      ((volatile unsigned int*)(MMIO_BASE+0x00215004))
#define AUX_MU_IO       ((volatile unsigned int*)(MMIO_BASE+0x00215040))
#define AUX_MU_IER      ((volatile unsigned int*)(MMIO_BASE+0x00215044))
#define AUX_MU_IIR      ((volatile unsigned int*)(MMIO_BASE+0x00215048))
#define AUX_MU_LCR      ((volatile unsigned int*)(MMIO_BASE+0x0021504C))
#define AUX_MU_MCR      ((volatile unsigned int*)(MMIO_BASE+0x00215050))
#define AUX_MU_LSR      ((volatile unsigned int*)(MMIO_BASE+0x00215054))
#define AUX_MU_MSR      ((volatile unsigned int*)(MMIO_BASE+0x00215058))
#define AUX_MU_SCRATCH  ((volatile unsigned int*)(MMIO_BASE+0x0021505C))
#define AUX_MU_CNTL     ((volatile unsigned int*)(MMIO_BASE+0x00215060))
#define AUX_MU_STAT     ((volatile unsigned int*)(MMIO_BASE+0x00215064))
#define AUX_MU_BAUD     ((volatile unsigned int*)(MMIO_BASE+0x00215068))

/**
 * Set baud rate and characteristics (115200 8N1) and map to GPIO
 */
void uart_init()
{
    register unsigned int r;
    
    /* UARTの初期化 */
    *AUX_ENABLE |=1;       // enable UART1を有効化
    *AUX_MU_IER = 0;       // 割込みを無効化
    *AUX_MU_CNTL = 0;      // Tx, Rxを無効化 
    *AUX_MU_LCR = 3;       // UART8-bitモードに
    *AUX_MU_MCR = 0;       // uart lineをhighに
    *AUX_MU_IER = 0;      // 割込みを無効化
    *AUX_MU_IIR = 0xc6;    // 受信FIFOと送信FIFOをクリア
    *AUX_MU_BAUD = 270;    // ボードレートを設定
    
    /* GPIO14,15をalt5モードに */
    r=*GPFSEL1;
    r&=~((7<<12)|(7<<15)); // gpio14, gpio15
    r|=(2<<12)|(2<<15);    // alt5に
    *GPFSEL1 = r;
    /* GPIO14,15のプルアップ・ダウンを無効に */
    *GPPUD = 0;
    r=150; while(r--) { asm volatile("nop"); }  //150クロック待つ
    *GPPUDCLK0 = (1<<14)|(1<<15);
    r=150; while(r--) { asm volatile("nop"); }
    *GPPUDCLK0 = 0;        // flush GPIO setup

    /* Tx, Rxを有効化 */
    *AUX_MU_CNTL = 3;      // Tx, Rxを有効化
}

/**
 * Send a character
 */
void uart_send(unsigned int c) {
    /* wait until we can send */
    do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20));
    /* write the character to the buffer */
    *AUX_MU_IO=c;
}

/**
 * Receive a character
 */
char uart_getc() {
    char r;
    /* wait until something is in the buffer */
    do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01));
    /* read it and return */
    r=(char)(*AUX_MU_IO);
    /* convert carrige return to newline */
    return r=='\r'?'\n':r;
}

/**
 * Display a string
 */
void uart_puts(char *s) {
    while(*s) {
        /* convert newline to carrige return + newline */
        if(*s=='\n')
            uart_send('\r');
        uart_send(*s++);
    }
}
  • わからないこと一覧
    • なぜ割込み無効化を2回もするのか?
    • MCRレジスタに関して何をしているのか?
      uart lineをlowにするってどゆこと?信号がないときはHighになるように設定しているっぽい
    • ボードレート設定の270とい数はどこから来たのか
    • UARTで使うGPIOをプルアップ・ダウン無効にする理由は?
      マニュアルには書いていないが,他の人たちもみなこのようにしているので当たり前なのか

cソースファイル(main.c)

#include "uart.h"

void main()
{
    // set up serial console
    uart_init();
    
    // say hello
    uart_puts("Hello World!\n");
    
    // echo everything back
    while(1) {
        uart_send(uart_getc());
    }
}

無限ループし,アセンブリ言語のコードには戻らない