Skip to content

接着_Static_assert看一遍uart.c的代码(未完成)

module

c
typedef struct {
    int index;
    gpio_id_t tx, rx;
    unsigned int fn;
} uart_config_t;

static struct {
    volatile uart_t *uart_base, *uart;
    uart_config_t config;
} module = { .uart_base = UART_BASE,
             .uart = NULL, // will be set in uart_init
};
  • 定义了一个全局变量 module
  • volatile 告诉程序在用这个变量的时候总是从对应地址中读取,而不使用缓存。常用在驱动代码中。

uart_reinit_custom

c
void uart_reinit_custom(int uart_id, gpio_id_t tx, gpio_id_t rx, unsigned int gpio_fn) {

    ...

    // 设置使用哪个UART,指定GPIO端口,
    module.config.index = uart_id;
    module.config.tx = tx;
    module.config.rx = rx;
    module.config.fn = gpio_fn; // ??
    module.uart = module.uart_base + module.config.index;

    // clock up peripheral
    // gating bits [0:5], reset bits [16:21]
    // `CCU_UART_BGR_REG` 地址 `0x090C`
    // `0x90C` 寄存器 0-5位代表控制 UART0-5 的时钟控制,置1为打开时钟
    // `0x90C` 寄存器 16-21 位代表控制 UART0-5 的复位,置1为解除reset状态
    uint32_t bit = 1 << module.config.index;
    uint32_t reset = bit << 16;
    ccu_enable_bus_clk(CCU_UART_BGR_REG, bit, reset);

    // configure GPIOs
    // 使能两个GPIO口,TODO 不理解为什么要pullup,为什么要用 GPIO_FN_ALT6
    gpio_set_function(module.config.tx, module.config.fn);
    gpio_set_pullup(module.config.tx);
    gpio_set_function(module.config.rx, module.config.fn);
    gpio_set_pullup(module.config.rx);

    // configure baud rate
    uint32_t baud = 115200;
    module.uart->regs.fcr = 1;      // enable TX/RX fifo,UART FIFO Control Register
    module.uart->regs.halt = 1;     // temporarily disable TX transfer,UART Halt TX Register

    uint32_t sys_clock_rate = 24 * 1000000;
    uint32_t udiv = sys_clock_rate / (16 * baud);
    module.uart->regs.lcr |= LCR_DLAB;  // set DLAB = 1 to access DLL/DLH, UART Line Control Register
    module.uart->regs.dll = udiv & 0xff;        // low byte of divisor -> DLL, UART Divisor Latch Low Register
    module.uart->regs.dlh = (udiv >> 8) & 0xff; // hi byte of divisor -> DLH, UART Divisor Latch High Register
    module.uart->regs.lcr &= ~LCR_DLAB; // set DLAB = 0 to access RBR/THR
    module.uart->regs.halt = 0;     // re-enable TX transfer

    // configure data-parity-stop (low 4 bits of LCR)
    uint8_t data = 0b11;    // 8 data
    uint8_t parity = 0b0;   // no parity
    uint8_t stop = 0b0;     // 1 stop
    uint8_t settings = (parity << 3) | (stop << 2) | (data << 0);
    while (module.uart->regs.usr & USR_BUSY) ; // wait until uart not busy
    // clear low 4 bits, replace with settings 8-n-1
    module.uart->regs.lcr = (module.uart->regs.lcr & ~0b1111) | settings;

    module.uart->regs.mcr = 0;    // disable modem control
    module.uart->regs.ier = 0;    // disable interrupts by default
}

confirm_uart_initalized

c
static void confirm_uart_initialized(const char *fn_name) { // 函数的参数是`函数名`
    if (module.uart != NULL && fn_name == NULL) {
        // 如果全局变量`module.uart`不为空,且参数函数名为空,则抛出错误
        error("uart_init() must be called only once");
    } else if (module.uart == NULL && fn_name != NULL) {
        // 如果全局变量`module.uart`为空,且参数函数不为空,代表还没有调用`uart_init`
        // if uart_init has not been called, there is no serial connection to read/write
        // All calls to uart operations are dead ends (that means no printf/assert!)
        // Force a call to uart_init here to enable reporting of problem
        // (otherwise lack of output is ultra mysterious)
        uart_reinit_custom(0, GPIO_PB8, GPIO_PB9, GPIO_FN_ALT6);
        error("uart_init() must be called before using %s()", fn_name);
    }
}

uart_reinit_custom

c
void uart_reinit_custom(int uart_id, gpio_id_t tx, gpio_id_t rx, unsigned int gpio_fn) {
    if (module.uart) {  // shut down previous if active
        uart_flush();
        gpio_set_function(module.config.tx, GPIO_FN_DISABLED); // disconnect gpio
        gpio_set_pullnone(module.config.tx);
        gpio_set_function(module.config.rx, GPIO_FN_DISABLED);
        gpio_set_pullnone(module.config.rx);
        module.uart = NULL;
    }
    ...
}
  • 如果激活过uart,做以下操作把它关闭掉
  • uart_flush():