Klipper seria.c 文件代码分析

news2024/11/18 2:50:18

一. 前言

        Klipper 底层硬件的串口模块程序写的是否正确是决定下位机与上位机能否正常通信的前提,如果这个文件的驱动没写好,那上位机控制下位机就无从谈起,更无法通过上位机去验证下位机程序的正确性。

        本篇博文将详细解析 Klipper src 文件夹下的 lpc176x 单片机的 serial.c,来分析其中的 API 函数的功能和作用,以此为新的平台的串口驱动的移植提供参考。

二. serial_init 函数

        serial_init 函数主要是:

        1. 对串口的根时钟进行初始化;

        2. 设置通信配置:

  • 波特率:通过设置分频系数(DLL 和 DLM)进行设置,前提是设置 LCR 的 bit7 为 1,即使能开启对除数锁存器的访问 );
  • 字长(设置 LCR 的 [1:0] ,默认 8 个字节)
  • 停止位(设置 LCR 的 bit2,默认 1 个停止位)
  • 奇偶校验(设置 LCR 的 bit3 进行使能,默认不进行奇偶校验;[5:4] 选择发送数据的奇偶校验值,这里不深入研究)

        代码及注释如下: 

void
serial_init(void)
{
    // Setup baud
    enable_pclock(PCLK_UARTx); //使能 UART 时钟
    LPC_UARTx->LCR = (1<<7); // set DLAB bit 开启对除数锁存器的访问
    uint32_t pclk = get_pclock_frequency(PCLK_UARTx); //得到时钟频率
    uint32_t div = pclk / (CONFIG_SERIAL_BAUD * 16); //的分频系数
    LPC_UARTx->DLL = div & 0xff;  //设置分频系数低 8 位
    LPC_UARTx->DLM = (div >> 8) & 0xff;  //设置分频系数高 8 位
    LPC_UARTx->FDR = 0x10;   //取消预分频
    LPC_UARTx->LCR = 3; // 8N1 ; clear DLAB bit,设置停止位、奇偶校验、极性

    // Enable fifo
    LPC_UARTx->FCR = 0x01;  //使能 FIFO

    // Setup pins
    gpio_peripheral(GPIO_Rx, GPIO_FUNCTION_UARTx, 0);
    gpio_peripheral(GPIO_Tx, GPIO_FUNCTION_UARTx, 0);

    // Enable receive irq
    armcm_enable_irq(UARTx_IRQHandler, UARTx_IRQn, 0);
    LPC_UARTx->IER = 0x01;   //使能接收中断
}

三. 使能发送中断

        程序使用 serial_enable_tx_irq API 函数来进行发送中断的使能:

  1. 先要通过判断 LSR 寄存器的 bit5 位为 1 即发送 FIFO 里面没有数据,串口可以发送新的数据;
  2. 之后在此函数中调用 kick_tx 函数来实现发送中断的使能。
void
serial_enable_tx_irq(void)
{
    if (LPC_UARTx->LSR & (1<<5)) {    //上一字节发送完成
        irqstatus_t flag = irq_save();
        kick_tx();  //发送一个字节后使能发送中断
        irq_restore(flag);
    }
}

        对于  kick_tx 函数,其中的逻辑是:

  1. 先向 THR 中写数据,然后判断到 THR 不为空之后,使能发送中断;
  2. 数据由 serial_get_tx_byte 函数得到,此函数将遍历函数内部数组的数据,将其赋值给 data,然后向 THR 赋值,将 data 通过中断的方式发送出去;
  3. 若数组遍历到尽头之后,变量 ret 将被赋值0为 -1,在 if(ret) 条件判断中,函数将通过设置 IER 寄存器,关闭发送中断,只使能接收中断。
// Write tx bytes to the serial port
static void kick_tx(void)
{
    for (;;) {
        if (!(LPC_UARTx->LSR & (1<<5))) {
            // Output fifo full - enable tx irq,有数据需要发送,使能发送中断
            LPC_UARTx->IER = 0x03;
            break;
        }
        uint8_t data;
        int ret = serial_get_tx_byte(&data);
        if (ret) {
            // No more data to send - disable tx irq
            LPC_UARTx->IER = 0x01;
            break;
        }
        LPC_UARTx->THR = data;
    }
}

       从 IER 寄存器可以看到 0x01 对应的是 Enable 接收数据中断,0x03 则同时 Enable 了接收和发送中断。

四. 中断服务函数 

        中断服务函数将通过 IIR 寄存器判断是否达到了中断条件,若产生了 THRE 中断,即获取到 status 为 0x02,即数据发送寄存器 THR 为空,程序将产生串口中断,在程序使能发送中断时,在 kick_tx 中发出一个 FIFO 的数据,THR 将为空,程序将发生中断发送下一个 FIFO 的数据,直到 Disable 掉串口发送中断。

void UARTx_IRQHandler(void)
{
    uint32_t iir = LPC_UARTx->IIR, status = iir & 0x0f; //获取中断状态
    if (status == 0x04) //接收中断
        serial_rx_byte(LPC_UARTx->RBR);
    else if (status == 0x02)  //发送中断
        kick_tx();
}

         从 IIR 寄存器可以看到 0x02 对应的是发生了接收数据中断,0x04 是出现了发送中断。 

五. 总结

        程序只有安照正确的逻辑编写 API 函数,Klipper 下位机驱动才可以适配上层的应用层代码,对于 serial.c 程序,核心是理解中断发送和接收的条件,在应用代码的基础上编写发送和接收函数。

        完整代码如下:

// lpc176x serial port
//
// Copyright (C) 2018-2021  Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.

#include "board/armcm_boot.h" // armcm_enable_irq
#include "autoconf.h" // CONFIG_SERIAL_BAUD
#include "board/irq.h" // irq_save
#include "board/serial_irq.h" // serial_rx_data
#include "command.h" // DECL_CONSTANT_STR
#include "internal.h" // gpio_peripheral
#include "sched.h" // DECL_INIT

#if CONFIG_LPC_SERIAL_UART0_P03_P02
  DECL_CONSTANT_STR("RESERVE_PINS_serial", "P0.3,P0.2");
  #define GPIO_Rx GPIO(0, 3)
  #define GPIO_Tx GPIO(0, 2)
  #define GPIO_FUNCTION_UARTx 1
  #define LPC_UARTx LPC_UART0
  #define UARTx_IRQn UART0_IRQn
  #define PCLK_UARTx PCLK_UART0
#elif CONFIG_LPC_SERIAL_UART3_P429_P428
  DECL_CONSTANT_STR("RESERVE_PINS_serial", "P4.29,P4.28");
  #define GPIO_Rx GPIO(4, 29)
  #define GPIO_Tx GPIO(4, 28)
  #define GPIO_FUNCTION_UARTx 3
  #define LPC_UARTx LPC_UART3
  #define UARTx_IRQn UART3_IRQn
  #define PCLK_UARTx PCLK_UART3
#endif

// Write tx bytes to the serial port
static void
kick_tx(void)
{
    for (;;) {
        if (!(LPC_UARTx->LSR & (1<<5))) {
            // Output fifo full - enable tx irq,有数据需要发送,使能发送中断
            LPC_UARTx->IER = 0x03;
            break;
        }
        uint8_t data;
        int ret = serial_get_tx_byte(&data);
        if (ret) {
            // No more data to send - disable tx irq
            LPC_UARTx->IER = 0x01;
            break;
        }
        LPC_UARTx->THR = data;
    }
}

void
UARTx_IRQHandler(void)
{
    uint32_t iir = LPC_UARTx->IIR, status = iir & 0x0f; //获取中断状态
    if (status == 0x04) //接收中断
        serial_rx_byte(LPC_UARTx->RBR);
    else if (status == 0x02)  //发送中断
        kick_tx();
}

void
serial_enable_tx_irq(void)
{
    if (LPC_UARTx->LSR & (1<<5)) {    //上一字节发送完成
        irqstatus_t flag = irq_save();
        kick_tx();  //发送一个字节后使能发送中断
        irq_restore(flag);
    }
}

void
serial_init(void)
{
    // Setup baud
    enable_pclock(PCLK_UARTx); //使能 UART 时钟
    LPC_UARTx->LCR = (1<<7); // set DLAB bit 开启对除数锁存器的访问
    uint32_t pclk = get_pclock_frequency(PCLK_UARTx); //得到时钟频率
    uint32_t div = pclk / (CONFIG_SERIAL_BAUD * 16); //的分频系数
    LPC_UARTx->DLL = div & 0xff;  //设置分频系数低 8 位
    LPC_UARTx->DLM = (div >> 8) & 0xff;  //设置分频系数高 8 位
    LPC_UARTx->FDR = 0x10;   //取消预分频
    LPC_UARTx->LCR = 3; // 8N1 ; clear DLAB bit,设置停止位、奇偶校验、极性

    // Enable fifo
    LPC_UARTx->FCR = 0x01;  //使能 FIFO

    // Setup pins
    gpio_peripheral(GPIO_Rx, GPIO_FUNCTION_UARTx, 0);
    gpio_peripheral(GPIO_Tx, GPIO_FUNCTION_UARTx, 0);

    // Enable receive irq
    armcm_enable_irq(UARTx_IRQHandler, UARTx_IRQn, 0);
    LPC_UARTx->IER = 0x01;   //使能接收中断
}
DECL_INIT(serial_init);

六. 参考文献

1. 来源:NXP 官网,UM10360

https://cache.nxp.com.cn/secured/assets/documents/en/user-guide/UM10360.pdf?__gda__=1690807854_806c303fe28ea3f108ebbd4977345cb6&fileExt=.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/816550.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

提词器怎么用?这个方法看一看

提词器怎么用&#xff1f;在现代社会中&#xff0c;提词器的应用场景非常广泛。除了学习、工作、听力障碍和翻译&#xff0c;它还可以应用于其他领域&#xff0c;如演讲、广播、新闻报道等。比如说&#xff0c;在演讲中&#xff0c;提词器可以帮助演讲者更好地掌握演讲内容。演…

网络防御之VPN

配置IKE 第一阶段 [r1]ike proposal 1 [r1-ike-proposal-1]encryption-algorithm aes-cbc-128 [r1-ike-proposal-1]authentication-algorithm sha1 [r1-ike-proposal-1]dh group2 [r1-ike-proposal-1]authentication-method pre-share[r1]ike peer aaa v1 [r1-ike-peer-aaa…

提升数据质量的四大有效方式

在数字时代的今天&#xff0c;企业对于高质量、值得信赖的数据的需求越来越高。 目前&#xff0c;已经有很多企业将数据质量视为技术问题而非业务问题&#xff0c;这也是获取高质量数据的最大限制因素。只有查找技术缺陷&#xff0c;例如重复数据、缺失值、乱序序列&#xff0…

api自动化测试

API测试已成为日常的测试任务之一&#xff0c;为了提高测试效率&#xff0c;减少重复的手工操作&#xff0c;API自动化测试也逐渐变得愈加重要&#xff0c;本文是自己在API自动化测试方面的一些经验积累和心得、汇总成文&#xff0c;以飨读者 我相信自动化技能已经成为高级测试…

uniapp跨域解决

uniapp跨域解决 跨域是什么 跨域指的是浏览器不能执行其他网站的脚本&#xff0c;当一个网页去请求另一个域名的资源时&#xff0c;域名、端口、协议任一不同&#xff0c;就会存在跨域。跨域是由浏览器的同源策略造成的&#xff0c;是浏览器对JavaScript施加的安全限制。 报错…

直线导轨的精密等级以及划分依据

直线导轨的作用&#xff0c;是用来支撑和引导运动部件&#xff0c;按给定的方向做往复直线运动的&#xff0c;直线导轨是高精密度的传动元件&#xff0c;广泛使用在各行各业中。 直线导轨的精密等级是判断产品质量的一个重要指标。在众多种类的直线导轨产品中&#xff0c;精密等…

【BASH】回顾与知识点梳理(一)

【BASH】回顾与知识点梳理 一 前言一. 认识与学习 BASH1.1 硬件、核心与 Shell1.2 为何要学文字接口的 shell&#xff1f;1.3 系统的合法 shell 与 /etc/shells 功能1.4 Bash shell 的功能1.5 查询指令是否为 Bash shell 的内建命令&#xff1a; type1.6 指令的下达与快速编辑按…

vue3搭建Arco design UI框架

技术&#xff1a;Vue3.2.40 UI框架&#xff1a;Arco design 2.44.7 需要安装:yarn 1.22.19 和npm 8.19.4 1.第一步安装本地全局arco脚手架 管理员运行CMD npm i -g arco-cli安装成功后如下&#xff1a; 2.第二步在需要存放项目的文件夹拉取项目 我这里把项目存放在 D:\W…

CTF:信息泄露.(CTFHub靶场环境)

CTF&#xff1a;信息泄露.&#xff08;CTFHub靶场环境&#xff09; “ 信息泄露 ” 是指网站无意间向用户泄露敏感信息&#xff0c;泄露了有关于其他用户的数据&#xff0c;例如&#xff1a;另一个用户名的财务信息&#xff0c;敏感的商业 或 商业数据 &#xff0c;还有一些有…

【枚举+结论】icpc2022 济南 A

Problem - A - Codeforces 题意&#xff1a; 思路&#xff1a; 本来的思路是这样的 考虑最后会变成什么数&#xff0c;手摸了几个发现&#xff0c;都是2&#xff0c;不论本来的集合是不是包含2 然后就是猜测是不是直接变成2就好了 然后要去掉m个&#xff0c;直接考虑去掉最…

高速过孔同进同出?到底是什么一种设计体验

高速先生成员--黄刚 每当来一个比较新的概念时&#xff0c;高速先生总是非常的喜欢&#xff0c;随之而来的求知欲也会爆发个小宇宙。其实问题的来源是我们公司的北京分部的资深设计工程师&#xff0c;北京分部本身也是我司全国20多个分部里设计能力最强的分部之一了&#xff0c…

类的封装和包(JAVA)

封装 所有的OOP语言都会有三个特征&#xff1a; 封装&#xff1b;继承&#xff1b;多态。 本篇文章会为大家带来有关封装的知识。 在我们日常生活中可以看到电视就只有那么几个按键&#xff08;开关&#xff0c;菜单……&#xff09;和一些接口&#xff0c;而而我们通过这些东…

Day08-作业(MySQLMybatis入门)

作业1&#xff1a;多表查询 数据准备&#xff1a; 重新创建一个数据库 db03_homework 执行如下脚本&#xff0c;创建表结构&#xff0c;导入测试数据 -- 部门管理 create table tb_dept(id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not n…

想了解好用的翻译pdf的软件吗?

在全球化的时代背景下&#xff0c;跨国贸易越来越普遍&#xff0c;跨语言沟通也越来越频繁。小黄是一家跨国公司的员工&#xff0c;他梦想能在全球各地拓展自己的业务&#xff0c;奈何遇到了一个巨大的挑战&#xff1a;跨语言沟通。在这其中&#xff0c;pdf文件是他经常接收到的…

CNN-NER论文详解

论文&#xff1a;https://arxiv.org/abs/2208.04534 代码&#xff1a;https://github.com/yhcc/CNN_Nested_NER/tree/master 文章目录 有关工作前期介绍CNN-NER模型介绍 代码讲解主类多头biaffineCNNLoss解码数据传入格式 参考资料 有关工作 前期介绍 过去一共主要有四类方式…

基于canvas画布的实用类Fabric.js的使用

目录 前言 一、Fabric.js简介 二、开始 1、引入Fabric.js 2、在main.js中使用 3、初始化画布 三、方法 四、事件 1、常用事件 2、事件绑定 3、事件解绑 五、canvas常用属性 六、对象属性 1、基本属性 2、扩展属性 七、图层层级操作 八、复制和粘贴 1、复制 2…

高并发架构去重难?架构必备技能 - 布隆过滤器

系列文章目录 当Dubbo遇到高并发&#xff1a;探究流量控制解决方案 主从选举机制&#xff0c;架构高可用性的不二选择 高并发架构去重难&#xff1f;架构必备技能 - 布隆过滤器 系列文章目录前言一、布隆过滤器简介二、特性与应用场景三、参数定制四、java版本的Demo五、总结 …

安全学习DAY13_WEB应用源码获取

信息打点-WEB应用-源码获取 文章目录 信息打点-WEB应用-源码获取小节概述-思维导图资产架构-源码获取&#xff08;后端&#xff09;后端-开源后端-闭源-源码泄露源码泄露原因源码泄露方式集合网站备份压缩包git&#xff0c;svn源码泄露DS_Store文件泄露composer.json 泄露资源搜…

网络安全 Day24-select高级用法和多表连接

select高级用法和多表连接 1. select 多子句单表高级实践1.1 select 多子句高级语法1.2 聚合函数1.3 group by 实践1.4 having 筛选1.5 order by 排序1.6 limit 2. 多表连接 1. select 多子句单表高级实践 1.1 select 多子句高级语法 where 和 having 区别是后者是分组后进行…

计算机视觉实验:人脸识别系统设计

实验内容 设计计算机视觉目标识别系统&#xff0c;与实际应用有关&#xff08;建议&#xff1a;最终展示形式为带界面可运行的系统&#xff09;&#xff0c;以下内容选择其中一个做。 1. 人脸识别系统设计 (1) 人脸识别系统设计&#xff08;必做&#xff09;&#xff1a;根据…