tag 标签: uart

相关帖子
相关博文
  • 热度 3
    2024-3-8 11:37
    749 次阅读|
    1 个评论
    B y Toradex 胡珊逢 简介 Verdin iMX8M Plus 具有四个串口,其中 UART3 是用于 A53 核心上的系统如 Linux 的默认调试串口,出于设计需要可能需要将调试口换到其他串口,文章将介绍如何使用 UART1 作调试串口。 硬件介绍 Verdin iMX8M Plus 的四个串口 UART1 ~ UART4 中, UART3 为默认的 A53 调试串口, UART4 为 M7 调试串口,其余两个作为通用 UART 使用。 Verdin 系列的模块均使用 1.8V TTL 电平,在连接外部设备时请先检查电压。本次测试使用的是 Dahlia 底板,在 X20 扩展接口 Pin12 和 Pin13 分别将模块的 UART1_RXD 和 UART1_TXD 引出。四个串口的物理地址如下: UART 起始地址 结束地址 UART1 0x3086_0000 0x3086_FFFF UART2 0x3089_0000 0x3089_FFFF UART3 0x3088_0000 0x3088_FFFF UART4 0x30A6_0000 0x30A6_FFFF 软件修改 调试串口更改的软件涉及到三个部分, ATF 、 U-Boot 和 Linux 。 ATF 会和 U-Boot 等其他文件如 DDR 固件一起打包成用于 NXP i.MX 8M Plus 处理器的启动文件。这些文件的下载和编译请参考 该网页 。文章使用到的完整补丁请从 这里下载 。 ATF ATF 代码的 imx8mp_bl31_setup.c 中,把 RDC_PDAP_UART1 划分到 A53 所在的 D0 域。 --------------------------- --- a/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c +++ b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c @@ -53,7 +53,7 @@ static const struct imx_rdc_cfg rdc = { - MX8MP_PAD_UART3_RXD__UART3_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL), - MX8MP_PAD_UART3_TXD__UART3_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL), + MX8MP_PAD_UART1_RXD__UART1_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL), + MX8MP_PAD_UART1_TXD__UART1_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL), }; imx_iomux_v3_setup_multiple_pads(uart_pads, ARRAY_SIZE(uart_pads)); - init_uart_clk(2); + init_uart_clk(0); return 0; } --------------------------- 在 include/configs/verdin-imx8mp.h 将 CONFIG_MXC_UART_BASE 的地址也设置为 UART1 。同时修改 console 。 --------------------------- --- a/include/configs/verdin-imx8mp.h +++ b/include/configs/verdin-imx8mp.h "boot_script_dhcp=" BOOT_SCRIPT "\0" \ - "console=ttymxc2\0" \ + "console=ttymxc0\0" \ "fdt_board=dev\0" \ @@ -111,7 +111,7 @@ #define PHYS_SDRAM_2_SIZE (SZ_4G + SZ_1G) /* UART */ -#define CONFIG_MXC_UART_BASE UART3_BASE_ADDR +#define CONFIG_MXC_UART_BASE UART1_BASE_ADDR /* Monitor Command Prompt */ #define CONFIG_SYS_CBSIZE SZ_2K --------------------------- Linux Linux 的 device tree 同样也需要做修改。在 freescale/imx8mp-verdin-dev.dtsi 中取消 UART1 默认配置下的 RS485 功能。 --------------------------- --- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-dev.dtsi /* Verdin UART_1, connector X50 through RS485 transceiver */ &uart1 { + /* linux,rs485-enabled-at-boot-time; rs485-rts-active-low; rs485-rx-during-tx; + */ status = "okay"; }; --------------------------- imx8mp-verdin.dtsi 中更改 stdout-path 调试串口输出至 UART1 ,并删除 RTS 和 CTS 功能引脚。 --------------------------- --- a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi @@ -8,7 +8,7 @@ / { chosen { - stdout-path = &uart3; + stdout-path = &uart1; }; aliases { @@ -891,7 +891,7 @@ &snvs_pwrkey { &uart1 { pinctrl-names = "default"; pinctrl-0 = ; - uart-has-rtscts; + /* uart-has-rtscts; */ }; /* Verdin UART_2 */ @@ -1331,8 +1331,8 @@ pinctrl_sai3: sai3grp { pinctrl_uart1: uart1grp { fsl,pins = - , /* SODIMM 135 */ - , /* SODIMM 133 */ + /* , SODIMM 135 */ + /* , SODIMM 133 */ --------------------------- 修改完毕上述文件后重新编译 flash.bin ( imx-boot )和 device tree 文件,并将其放入支持 Toradex Easy Installer 烧录的镜像文件中。同时也需要修改镜像文件中的 u-boot-initial-env-sd ,将 console 改为 console=ttymxc0 。该文件会在烧录系统时配置 U-Boot 环境变量。安装完镜像后,在 UART1 即可看到启动日志。 总结 通过上述几个文件的修改,可以切换 A53 调试串口。对于 Linux 系统通常建议保留一个调试串口,这将有利于调试和后期其他问题排查。
  • 热度 9
    2022-11-4 00:11
    1993 次阅读|
    0 个评论
    一:第一感受: 优点:板子小巧,功能强大,做工优良 不足:没有led指示灯,有led灯的话调试会方便很多 二:工程环境搭建 直接参考官网资料,很容易就搭建好了工程环境,测试ok,不得不说资料很详细。 三:IO口测试 直接用官方例程进行测试: 由于没有指示灯,所以直接用万用表进行功能测试 1:执行指令 GPIO_SET_OUTPUT_PIN_INV(gpio_sel,(GPIO_PIN7)); 量PA7脚电压为1.6V 2:执行指令 GPIO_SET_OUTPUT_PIN_TO_1(gpio_sel,(GPIO_PIN7)); 量PA7脚电压为3.2V 3:执行指令 GPIO_SET_OUTPUT_PIN_TO_0(gpio_sel,(GPIO_PIN7)); 量PA7脚电压为0V 三:串口功能测试 同样直接用官方例程进行测试不用做任何修改:接串口4到usb转串口模块上:直接测试收发如下: 四:串口printf功能移植 参考大神的方法:链接如下: 五:HAL库移植测试 参考游乐场大神的程序,链接如下: 最开始测试,串口波特率不对,修改如下图所示分频后解决 然后还遇到的问题是打印中文信息乱码,如下图所示: 经过咨询大神,发现是编码不一致导致,HAL库中使用的是UTF8字符编码,修改后OK如下图所示: 目前移植的程序还存在申请锁超时问题,待进一步解决。 总结:MC3172单片机上手容易,多线程操作给力,串口丰富可以任意分配功能强大。
  • 热度 4
    2022-5-20 07:14
    2075 次阅读|
    2 个评论
    UART介绍 简介 通用异步收发器(Universal Asynchronous Receiver/Transmitter),既UART 时序 根据时序图可以了解到: 1. uart在空闲的时候是高电平 2. 当突变为低电平或者有一个下降沿,则是告知接收方uart要传数据了 3. 这里实现为8bit数据传输,当数据传输完成,在1或1.5或2个时钟周期内将传输线拉高,表示停止传输 UART之RX实现 状态转移图 源代码 状态转移实现 always @(*) begin case (state) IDLE:begin if(rx_pin==1'b0) nextstate <= START; else nextstate <= IDLE; end START:begin if(cycle_cnt == CYCLE_CNT_MAX-1)//当一个BIT周期后,接收数据 nextstate <= REC_BYTE; else nextstate <= START; end REC_BYTE:begin if(cycle_cnt == CYCLE_CNT_MAX-1&&bit_cnt==4'd7)//8位数据接收完成,跳转到检测停止位 nextstate <= STOP; else nextstate <= REC_BYTE; end STOP:begin if(cycle_cnt == CYCLE_CNT_MAX/2-1)//半个bit周期,检测到停止位,将接收的数据发送到其他模块 nextstate <= DATA; else nextstate <= STOP; end DATA:begin //一个时钟周期后模块进入空闲态 nextstate <= IDLE; end endcase end 时序描述 //周期计数,既系统时钟内每个BIT所需要的周期数,通过波特率可计算出最大计数值 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) cycle_cnt <= 16'd0; else if(state == REC_BYTE && (cycle_cnt == CYCLE_CNT_MAX-1||nextstate != state))//只需要在开始接收数据时开始计数,所以前提条件是状态在REC_BYTE,而且如果计数值达到最大值或者在状态跳转的时候都需要将计数值清零 cycle_cnt <= 16'd0; else cycle_cnt <= cycle_cnt + 16'd1; end //位计数,以确认接收的位数 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) bit_cnt <= 4'd0; else if(state == REC_BYTE) //仅在接收数据状态时进行位计数 if(cycle_cnt == CYCLE_CNT_MAX-1) bit_cnt <= bit_cnt + 4'd1; else bit_cnt <= bit_cnt; else bit_cnt <= 4'd0; end //数据接收 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_data_r <= 8'd0; else if(state == REC_BYTE && cycle_cnt == CYCLE_CNT_MAX/2-1) rx_data_r <= tx_pin; else rx_data_r <= rx_data_r; end //将数据传输给其他模块 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_data <= 8'd0; else if(state == STOP || nextstate != state) rx_data <= rx_data_r; end //接收完成标志 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_done <= 1'b0; else if(state == STOP ) rx_done <= 1'b1; else rx_done <= 1'b0; end UART之TX实现 实现TX就不用三段式状态机这么麻烦了,直接用序列机完全就可以了 模块使能或者说发送请求 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) tx_en <= 1'b0; else if(tx_req_pos == 1'b1) tx_en <= 1'b1; else if(bit_cnt == 4'd11) tx_en <= 1'b0; else tx_en <= tx_en; end 周期计数、位计数 //周期计数,既系统时钟内每个BIT所需要的周期数,通过波特率可计算出最大计数值 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) cycle_cnt <= 16'd0; else if(tx_en) if(cycle_cnt == CYCLE_CNT_MAX-1)//当模块使能时,开始计数,计数到最大值再从零开始 cycle_cnt <= 16'd0; else cycle_cnt <= cycle_cnt + 16'd1; else cycle_cnt <= 16'd0; end //位计数 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) bit_cnt <= 4'd0; else if(cycle_cnt == 16'd1) //如果计数到最大值bit_cnt累加的话,那么数据发送需要多等一个bit周期 bit_cnt <= bit_cnt + 4'd1; else if(bit_cnt == 4'd11) bit_cnt <= 4'd0; else bit_cnt <= bit_cnt; end 发送数据 always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) tx_pin_r <= 1'b1; else case(bit_cnt) 0:tx_pin_r <= 1'b1; //这里需要避免bit_cnt=0的时候发送起始位,因为当复位的时候bit_cnt的值是零的,会在复位时就已经发出了起始位,而导致接收端的误判和发送的时序紊乱 1:tx_pin_r <= START_BIT; 2:tx_pin_r <= send_data ; 3:tx_pin_r <= send_data ; 4:tx_pin_r <= send_data ; 5:tx_pin_r <= send_data ; 6:tx_pin_r <= send_data ; 7:tx_pin_r <= send_data ; 8:tx_pin_r <= send_data ; 9:tx_pin_r <= send_data ; 10:tx_pin_r <= STOP_BIT; default: tx_pin_r <= 1'b1; end
  • 2022-5-13 14:00
    2 次阅读|
    0 个评论
    智慧灯杆是集照明、视频监控、交通管理、环境监测、通信等多功能于一体的新型信息基础设施,是构建新型智慧城市的重要载体。 5G 的普及,为智慧灯杆发展创造了新机遇,作为新一代城市信息基础设施的智慧灯杆,与“新基建”中的不少领域相关,比如 5G 基站、新能源汽车充电桩和车联网等。 智慧灯杆作为智慧城市的一个重要组成部分和重要入口,是智慧城市信息化建设天然的搭载平台。可以说在智慧城市建设中, 5G 是不可或缺的主角,而智慧杆将如同末梢神经元般存在。 智慧灯杆物联网领域技术复杂,涉及网络通信、云计算、电力、人工智能等专业种类, 内含通信、视频监控、照明、环境监测、交通、信息发布、能源、运维等多个子系统。 产品设计需考虑各系统的兼容、协同,灯杆的弹性扩展以及产品服务的升级、回退、扩容等等,整体复杂度高,专业要求高。 国内某交通信号系统供应商,计划研发一款集路灯照明控制、 LED 显示、 WiFi 热点、视频监控、广告屏、环境监测、紧急呼叫、汽车充电桩、 4G/5G 微型基站等多种功能于一体的智慧灯杆产品。 智慧灯杆是多种设备设施和技术的综合体,从功能硬件方面看,通信杆、路灯、交通监控、安防监控、环境监测 、路侧广告牌等多种主要功能设施于一身。 如此多的功能设施需要互联互通,其核心是通信控制设备,因此作为主控的核心板要求算力高,性能强,且需支持多路网口和 UART ,支持 5G 和 OpenWrt 系统。 综合评估后,飞凌推荐用户选用 FET1046A-C 核心板进行产品开发。 该核心板有丰富的接口资源,包括原生 8 路网口( 最大支持 2 路 10GbE 接口), 4 路 UART , 3 路 USB3.0 等,基于该款核心板开发的通信控制设备通过光纤接口,可以实现 4G/5G 微基站和无线高速 WiFi 覆盖。 RJ45 网口方便智慧灯杆快速接入 LED 信息发布屏、高清摄像头、 WiFi 等杆载设备。 RS485 可用于环境传感器、环境监测单元、单灯控制器等设备串口通信。 FET1046A-C 核心板搭载 4 核 ARM Cortex-A72 处理器, 1.8GHz 主频, 2GB DDR4 RAM ,数据吞吐量最高可达 2.1GT/s ,高达 45000 CoreMark 分值的性能,满足执行多种通信形式、通信速率和网络协议的需求,支持对不同智慧灯杆通信方式的选用,可实现智慧灯杆系统的一站式搭建。
  • 热度 21
    2021-3-21 21:57
    2691 次阅读|
    0 个评论
    FreeModbus 从站设计( 8 ) - 用 HAL 库函数理清 Modbus 的数据收发流程 关键词: FreeModbus STM32F103 CubeMX HAL 库 1. 基本框图 如图 1 所示, HAL 库的函数中,与 Freemodbus 协议栈相关的,主要是定时器和串口的操作部分。孔丙火(微信公众号:孔丙火)认为,可以这样简单描述:在协议栈完成初始化后,就将串口( RS485 )设置为接收状态,等待主站的数据,当接收到主站的一个字节的数据后,开启定时器,在 3.5 个字符周期内如果接收到了第二个字节的数据,则将定时器清零重新开始计时,若果 3.5 个字符周期内没有接收到新的字节,则认为一帧数据接收完毕,开始处理数据,并相应地发送回复数据,回复数据也是逐个字节进行发送的。 图 1 2. 接口函数 2.1 vMBPortSerialEnable() 这个函数定义在 portserial.c 中,所有的调用均在 mbrtu.c 和 mbascii.c 中,由于这里我们只实现 RTU ,因此,只关注 mbrtu.c 中调用。在 mbrtu.c 中,共有 5 处调用此函数,分别在 eMBRTUStop() 、 eMBRTUStop() 、 eMBRTUSend() 、 xMBRTUTransmitFSM() 中,这个函数的作用,就是使能或禁止串口的接收或发送中断,状态的转换是根据协议栈的状态机来进行的,孔丙火(微信公众号:孔丙火)认为,看一看 Modbus 协议文本中的状态机图,有助于深入理解协议的运行。基于以上理解, vMBPortSerialEnable() 函数的代码如下: 图2 HAL_UART_Receive_IT(&huart2,&ucUsrUart2Rxbuf,1) ,这个函数是 HAL 库函数,孔丙火(微信公众号:孔丙火)认为,可以这样理解,以中断方式通过串口 2 接收一个字节的数据,存在变量 ucUsrUart2Rxbuf 中,这里取得是 ucUsrUart2Rxbuf 的地址指针。 __HAL_UART_DISABLE_IT(&huart2,UART_IT_RXNE) 这个函数是禁止接收中断。在这个函数下面,写了这样一个语句: huart2.RxState = HAL_UART_STATE_READY; 同样的,在发送部分有: huart2.gState = HAL_UART_STATE_READY; 下面简单阐述一下作用。 最初开始弄 FreeModbus 移植的时候,在网上查阅了一些资料,有的是基于 HAL 库的,有的不是,有的是交叉使用,由于学习了一段时间的 HAL 库,感觉其还是比较易用的,孔丙火(微信公众号:孔丙火)就想着能不能完全用 HAL 库的函数来实现的 FreeModbus 移植,于是就有后来的实践。 加这样一个语句,是为了解决在实际调试过程中碰到的问题。刚开始调试的时候发现,单片机作为从站,只能接收一帧数据,第 2 帧以后的数据,不再有反应。由于是调用 HAL_UART_Receive_IT(&huart2,&ucUsrUart2Rxbuf,1); 来使能接收非空中断,调用 __HAL_UART_DISABLE_IT(&huart2,UART_IT_RXNE); 来禁用接收非空中断,那就要从 HAL_UART_Receive_IT() 这个函数开始说起,在以前的文章中,孔丙火(微信公众号:孔丙火)说过,这个函数本质上是一个配置函数,配置好接收缓冲区的指针和一次接收的字节数,把这个函数贴出来看一下: 图 3 可以看出,这个函数的主要功能就是设置接收缓存的指针和字节数,然后使能接收非空中断,但在一开始有一个条件判断, RxState ,这其实是对串口接收状态的一个管理,当串口中断方式接收已经被配置过了、接收过程还没有完成的时候,是不能再次配置的,防止接收数据出错。 在这个函数中,配置完了以后,就将 RxState 的状态置为了 HAL_UART_STATE_BUSY_RX ,这个状态是在串口中断处理函数中完成数据接收后,重新设为 HAL_UART_STATE_READY 。在本文的程序中,当从站接收数据完成后(定时器动作,表示一个完整的帧接收完成),协议栈需要将接收非空中断禁掉,但这之前串口仍处于接收状态(调用过 HAL_UART_Receive_IT(&huart2,&ucUsrUart2Rxbuf,1) ),因此 RxState 的状态是 HAL_UART_STATE_BUSY_RX ,这样在下次转为接收时,无法 HAL_UART_Receive_IT ()来进行配置,就是由于上面提到的图 3 红框中的条件判断。因此,在发现此问题后,加了这个语句,确保后续能正常接收,并且这样可以不用修改 HAL 库本身的函数。发送部分是同样的道理。 下一篇精彩继续。 文章在公众号( 孔丙火 )同步推出,欢迎查看更多系列文章。 单片机、 PLC 、嵌入式软硬件的设计经验分享,秉承“点点滴滴皆智慧”的理念,以实际项目为单元阐述知识点,一起分享,共同交流。
相关资源