Deepseek 解析16650串口初始化代码

16650串口初始化代码

static unsigned int uart16550_clock = 1843200; //串口时钟
#define UART_DEFAULT_BAUD 115200

void uart_init(void)
{
    unsigned int divisor = uart16550_clock / (UART_DEFAULT_BAUD * 16);
    
    /*关闭中断*/
    writeb(0, UART_IER);

    /*打开DLB字段,设置波特率分频*/
    writeb(0x80, UART_LCR);
    writeb((unsigned char)divisor, UART_DLL);
    writeb((unsigned char)(divisor >> 8), UART_DLM);

    /*设置串口数据格式*/
    writeb(0x3, UART_LCR);

    /*使能FIFO缓冲区,清空FIFO缓冲区,设置14字节阈值*/
    writeb(0xc7, UART_FCR);
}

以上代码摘自《RISC-V 体系结构编程与实践》第一版,P39。

Deepseek思考内容

嗯,我现在需要理解这段UART初始化的代码。首先,用户定义了一个函数uart_init,里面做了一些UART的配置。让我仔细看一下每一部分的作用。

首先,divisor被计算为uart16550_clock除以(UART_DEFAULT_BAUD乘以16)。这里应该是在设置波特率的除数。因为UART通常使用除数来生成正确的波特率,而公式通常是除数=时钟频率/(波特率*16)。所以这一步应该是正确的。

接下来是关闭中断,用writeb(0, UART_IER)。UART_IER是中断使能寄存器,写入0的话就是禁止所有中断,这应该在初始化的时候避免中断干扰,对吧?所以这一步没问题。

然后,打开DLB字段,设置波特率分频。这里写入0x80到UART_LCR。LCR是线路控制寄存器,最高位(DLAB,即Divisor Latch Access Bit)是用来允许访问除数锁存器的。所以这时候设置DLAB为1,允许设置DLL和DLM的值。这一步是对的,因为需要先开启DLAB才能设置波特率的除数。

接着,写入divisor的低8位到UART_DLL,高8位到UART_DLM。这里要注意的是,divisor是一个unsigned int,可能超过8位,所以分两次写入。这里是否正确呢?假设uart16550_clock和UART_DEFAULT_BAUD的值是合适的,divisor的值不会太大,比如如果时钟是1.8432MHz,波特率是9600,那除数就是1.8432e6/(9600*16)=12,所以DLL是12,DLM是0。这时候没问题。但如果divisor的高8位超过的话,可能需要强制转换为unsigned char,防止高位被截断。不过代码里已经做了强制转换,所以应该没问题。

然后设置串口的数据格式,写入0x03到UART_LCR。这时候LCR的低两位是设置数据位长度为8位(因为0x3对应的是8位,因为每个位的意义是:位0和位1决定数据位数,00是5,01是6,10是7,11是8),其他位比如停止位,奇偶校验位等。0x03的话,应该是8位数据,1位停止位,无校验。所以这一步正确。

接下来是使能FIFO,清空FIFO,设置14字节阈值。写入0xc7到UART_FCR。FCR的各位含义是:位0是FIFO使能,位1和2是清空接收和发送FIFO,位6和7设置触发阈值。0xc7二进制是11000111。那这里可能有问题,因为FCR的位6和7是用于设置触发级别的,例如,对于16750,可能的触发值如14字节需要特定的位组合。比如,14字节对应的位可能是两位的组合。例如,00是1字节,01是4字节,10是8字节,11是14字节。所以位7和6设为11的话,就是14字节触发。所以这里写入0xC7的话,低两位是11,也就是使能FIFO(位0),并且位1和2是1,表示清除接收和发送FIFO。然后位7和6是11,设置触发级别为14字节。对吗?但FCR的各个位的布局需要确认。比如,FCR的结构是:Bit 0: Enable FIFOs;Bit 1: Clear接收FIFO;Bit 2: Clear发送FIFO;Bit 3: DMA模式选择;Bit 5-4: Reserved;Bit 7-6: 触发级别。所以,当写入0xC7的话,二进制是11000111。其中,Bit7-6是11,即3,对应触发级别14字节。Bit1和Bit2是1,即清除接收和发送FIFO。Bit0是1,使能FIFO。所以这样设置是正确的。

那有没有可能的问题呢?比如,在设置波特率分频的时候,是否应该先关闭FIFO?或者是否在设置FCR的时候有其他需要注意的地方?

另外,在设置LCR的时候,当写入0x80时,是否会影响其他位的设置?比如,在之后设置LCR为0x03的时候,是否会把DLAB位重新置0?是的,因为在设置完DLL和DLM之后,将LCR设置为0x03,此时DLAB位(最高位)是0,这样后续访问的寄存器就不是DLL和DLM了,而是其他寄存器,比如RBR/THR等。这个是正确的步骤。

综上,这段代码的流程是对的:关闭中断,设置DLAB为1,写入波特率除数,然后设置数据格式(同时关闭DLAB),然后配置FIFO。可能需要注意的地方是,在设置FIFO的时候,是否应该在其他步骤之后?比如,是否在设置波特率前需要禁用FIFO?不过根据UART的初始化流程,通常的步骤是先设置波特率,然后设置数据格式,然后配置FIFO。这里可能没问题。

另外,检查是否在设置FCR的时候,清空FIFO是否正确。因为当FCR的Bit1和Bit2被置1时,会清除FIFO。但这两个位是自动清零的,所以写入0xC7时,Bit1和Bit2会被置1,导致清除FIFO,并且其他位设置。硬件会自动将这些位清零吗?是的,这些位是自动清零的,所以写入后,FCR的值实际上是0xC7 & 0x0F,或者实际上的值可能由硬件处理,但代码中的操作是正确的。

有没有其他潜在的问题?比如,是否在初始化之后重新打开中断?但在这个函数里并没有开启中断,所以如果用户需要中断驱动的UART通信,可能需要在别处设置IER寄存器。但根据函数名uart_init,可能这个初始化函数仅完成基本的配置,中断的开启可能在别处处理。所以这应该不是问题。

所以,这段代码应该能正确初始化UART的波特率、数据格式、FIFO设置,并关闭中断。可能的改进点是否有没有?例如,是否应该等待FIFO清空完成?或者是否有其他的配置步骤?

可能的问题点:在某些情况下,设置波特率的时候可能需要先关闭FIFO。比如,在设置波特率时,是否应该确保FIFO被禁用?不过在这个代码中,FIFO是在设置波特率之后才被启用的,所以应该没有问题。因为设置波特率的时候,FCR可能还没配置,所以此时FIFO可能处于禁用状态。所以步骤是对的。

综上,这段代码是正确的,但需要确认UART的型号是否兼容这些设置。比如,假设使用的是16550兼容的UART,这些寄存器地址和位的定义是正确的。所以如果硬件符合16550的标准,这段代码应该是有效的。

Deepseek总结

这段代码用于初始化16550兼容的UART控制器,以下是逐部分的分析和总结:

  1. 波特率除数计算
unsigned int divisor = uart16550_clock / (UART_DEFAULT_BAUD * 16);
  • 作用:计算波特率分频值。公式为 divisor = 时钟频率 / (波特率 × 16),符合UART标准波特率生成方法。

  • 注意:需确保 uart16550_clock 和 UART_DEFAULT_BAUD 的值正确,避免除法截断错误。

  1. 关闭中断
writeb(0, UART_IER); // 关闭所有中断
  • 作用:禁止UART所有中断(IER寄存器的所有位清零),防止初始化过程中意外中断触发。
  1. 设置波特率
writeb(0x80, UART_LCR); // 启用DLAB(Divisor Latch Access Bit)
writeb((unsigned char)divisor, UART_DLL);  // 除数低字节
writeb((unsigned char)(divisor >> 8), UART_DLM); // 除数高字节
  • 关键点:

    • 设置LCR的最高位(DLAB)为1,允许访问波特率除数寄存器DLL/DLM。

    • 将计算好的divisor写入DLL(低字节)和DLM(高字节),配置正确的波特率。

  1. 配置数据格式
writeb(0x3, UART_LCR); // 8位数据,1位停止位,无校验(DLAB已关闭)
  • 解析:LCR设置为 0x03,对应:

    • 数据位:8位(0b11)。

    • 停止位:1位(LCR的位2为0)。

    • 无校验(LCR的位3-5为0)。

    • DLAB位被清零,后续寄存器访问恢复正常模式。

  1. 配置FIFO
writeb(0xc7, UART_FCR); // 使能FIFO,清空缓冲区,设置14字节触发阈值
  • 位解析(FCR寄存器):

    • Bit 0 (FIFO Enable):1(启用FIFO)。

    • Bit 1-2 (Clear FIFOs):1(清空接收和发送FIFO,操作后自动清零)。

    • Bit 7-6 (Trigger Level):0b11(14字节触发阈值,适用于16750等UART)。

潜在问题与改进建议

  • 中断配置:初始化后中断仍被关闭,若需中断驱动通信,需额外设置IER寄存器。

  • FIFO触发阈值兼容性:14字节阈值可能仅适用于较新型号(如16750),确保硬件支持。

  • 除数计算精度:确保divisor计算无整数截断,必要时添加四舍五入逻辑。

总结

代码正确实现了16550 UART的初始化流程,包括波特率设置、数据格式配置和FIFO使能。需确保硬件兼容性,并根据实际需求补充中断配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值