AIO-3399JD4 开发板上的 AD 接口有两种,分别为:温度传感器 (Temperature Sensor)、逐次逼近ADC (Successive Approximation Register)。其中:
-
TS-ADC(Temperature Sensor):支持两通道,时钟频率必须低于800KHZ
-
SAR-ADC(Successive Approximation Register):支持六通道单端10位的SAR-ADC,时钟频率必须小于13MHZ。
内核采用工业 I/O 子系统来控制 ADC,该子系统主要为 AD 转换或者 DA 转换的传感器设计。
下面以SAR-ADC使用ADC风扇为例子,介绍 ADC 的基本配置方法。
配置DTS节点
AIO-3399JD4 SAR-ADC 的 DTS 节点在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 文件中定义,如下所示:
用户首先需在DTS文件中添加ADC的资源描述:
这里申请的是SARADC通道3,在 AIO-3399JD4 中是不提供给客户外部使用的,而且也没有风扇接口,这里只是提供一个参考, 客户可自行参考这个例子 运用SARADC通道0 去做自己的一些开发。
在驱动文件中匹配 DTS 节点
用户驱动可参考Firefly adc demo :kernel/drivers/adc/adc-firefly-demo.c,这是一个侦测Firefly-rk3399风扇状态的驱动。 首先在驱动文件中定义 of_device_id 结构体数组:
然后将该结构体数组填充到要使用 ADC 的 platform_driver 中:
接着在firefly_adc_probe中对DTS所添加的资源进行解析:
获取 AD 通道
注:iio_channel_get 通过 probe 函数传进来的参数 pdev 获取 IIO 通道结构体,probe 函数如下:
读取 AD 采集到的原始数据
调用 iio_read_channel_raw 函数读取 AD 采集的原始数据并存入 val 中。
使用标准电压将 AD 转换的值转换为用户所需要的电压值。其计算公式如下:
注:
-
Vref 为标准电压
-
n 为 AD 转换的位数
-
Vresult 为用户所需要的采集电压
-
raw 为 AD 采集的原始数据
例如,标准电压为 1.8V,AD 采集位数为 10 位,AD 采集到的原始数据为 568,则:
-
功能:获取 iio 通道描述
-
参数:
-
dev: 使用该通道的设备描述指针
-
consumer_channel: 该设备所使用的 IIO 通道描述指针
-
-
功能:释放 iio_channel_get 函数获取到的通道
-
参数:
-
chan:要被释放的通道描述指针
-
-
功能:读取 chan 通道 AD 采集的原始数据。
-
参数:
-
chan:要读取的采集通道指针
-
val:存放读取结果的指针
-
Demo程序使用
在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中使能adc_demo,将”disabled” 改为 “okay”:
编译内核,烧录内核到Firefly-RK3399 开发板上,然后插拔风扇时,会打印内核log信息如下:
获取所有ADC值
有个便捷的方法可以查询到每个SARADC的值:
为何按上面的步骤申请SARADC,会出现申请报错的情况?
驱动需要获取ADC通道来使用时,需要对驱动的加载时间进行控制,必须要在saradc初始化之后。saradc是使用module_platform_driver()进行平台设备驱动注册,最终调用的是module_init()。所以用户的驱动加载函数只需使用比module_init()优先级低的,例如:late_initcall(),就能保证驱动的加载的时间比saradc初始化时间晚,可避免出错。
GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。 RK3399有5组GPIO bank:GPIO0~GPIO4,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分(不是所有 bank 都有全部编号,例如 GPIO4 就只有 C0~C7, D0~D2)。 所有的GPIO在上电后的初始状态都是输入模式,可以通过软件设为上拉或下拉,也可以设置为中断脚,驱动强度都是可编程的。 每个 GPIO 口除了通用输入输出功能外,还可能有其它复用功能,例如 GPIO2_A2,可以利用成以下功能:
-
GPIO2_A2
-
CIF_D2
每个 GPIO 口的驱动电流、上下拉和重置后的初始状态都不尽相同,详细情况请参考《RK3399 规格书》中的 “Chapter 10 GPIO” 一章。 RK3399 的 GPIO 驱动是在以下 pinctrl 文件中实现的:
其核心是填充 GPIO bank 的方法和参数,并调用 gpiochip_add 注册到内核中。
本文以TP_RST(GPIO0_B4)和LCD_RST(GPIO4_D5)这两个通用GPIO口为例写了一份简单操作GPIO口的驱动,在SDK的路径为:
以下就以该驱动为例介绍GPIO的操作。
首先在DTS文件中增加驱动的资源描述:
这里定义了一个脚作为一般的输出输入口:
AIO-3399JD4 的dts对引脚的描述与Firefly-RK3288有所区别,GPIO0_B4被描述为:<&gpio0 12 GPIO_ACTIVE_HIGH>,这里的12来源于:8+4=12,其中8是因为GPIO0_B4是属于GPIO0的B组,如果是A组的话则为0,如果是C组则为16,如果是D组则为24,以此递推,而4是因为B4后面的4。 GPIO_ACTIVE_HIGH表示高电平有效,如果想要低电平有效,可以改为:GPIO_ACTIVE_LOW,这个属性将被驱动所读取。
然后在probe函数中对DTS所添加的资源进行解析,代码如下:
of_get_named_gpio_flags 从设备树中读取 firefly-gpio 和 firefly-irq-gpio 的 GPIO 配置编号和标志,gpio_is_valid 判断该 GPIO 编号是否有效,gpio_request 则申请占用该 GPIO。如果初始化过程出错,需要调用 gpio_free 来释放之前申请过且成功的 GPIO 。 在驱动中调用 gpio_direction_output 就可以设置输出高还是低电平,这里默认输出从DTS获取得到的有效电平GPIO_ACTIVE_HIGH,即为高电平,如果驱动正常工作,可以用万用表测得对应的引脚应该为高电平。 实际中如果要读出 GPIO,需要先设置成输入模式,然后再读取值:
下面是常用的 GPIO API 定义:
在Firefly的例子程序中还包含了一个中断引脚,GPIO口的中断使用与GPIO的输入输出类似,首先在DTS文件中增加驱动的资源描述:
IRQ_TYPE_EDGE_RISING表示中断由上升沿触发,当该引脚接收到上升沿信号时可以触发中断函数。 这里还可以配置成如下:
然后在probe函数中对DTS所添加的资源进行解析,再做中断的注册申请,代码如下:
调用gpio_to_irq把GPIO的PIN值转换为相应的IRQ值,调用gpio_request申请占用该IO口,调用request_irq申请中断,如果失败要调用free_irq释放,该函数中gpio_info-firefly_irq是要申请的硬件中断号,firefly_gpio_irq是中断函数,gpio_info->firefly_irq_mode是中断处理的属性,”firefly-gpio”是设备驱动程序名称,gpio_info是该设备的device结构,在注册共享中断时会用到。
如何定义 GPIO 有哪些功能可以复用,在运行时又如何切换功能呢?以 I2C4 为例作简单的介绍。
查规格表可知,I2C4_SDA 与 I2C4_SCL 的功能定义如下:
在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 里有:
此处,跟复用控制相关的是 pinctrl- 开头的属性:
-
pinctrl-names 定义了状态名称列表: default (i2c 功能) 和 gpio 两种状态。
-
pinctrl-0 定义了状态 0 (即 default)时需要设置的 pinctrl: &i2c4_xfer
-
pinctrl-1 定义了状态 1 (即 gpio)时需要设置的 pinctrl: &i2c4_gpio
这些 pinctrl 在kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi中这样定义:
RK_FUNC_1,RK_FUNC_GPIO 的定义在 kernel/include/dt-bindings/pinctrl/rk.h 中:
另外,像”1 11”,”1 12”这样的值是有编码规则的,编码方式与上一小节”输入输出”描述的一样,”1 11”代表GPIO1_B3,”1 12”代表GPIO1_B4。
在复用时,如果选择了 “default” (即 i2c 功能),系统会应用 i2c4_xfer 这个 pinctrl,最终将 GPIO1_B3 和 GPIO1_B4 两个针脚切换成对应的 i2c 功能;而如果选择了 “gpio” ,系统会应用 i2c4_gpio 这个 pinctrl,将 GPIO1_B3 和 GPIO1_B4 两个针脚还原为 GPIO 功能。
我们看看 i2c 的驱动程序 kernel/drivers/i2c/busses/i2c-rockchip.c 是如何切换复用功能的:
首先是调用 of_get_gpio 取出设备树中 i2c4 结点的 gpios 属于所定义的两个 gpio:
然后是调用 devm_gpio_request 来申请 gpio,接着是调用 pinctrl_lookup_state 来查找 “gpio” 状态,而默认状态 “default” 已经由框架保存到 i2c->dev-pins->default_state 中了。
最后调用 pinctrl_select_state 来选择是 “default” 还是 “gpio” 功能。
下面是常用的复用 API 定义:
在复杂的片上系统(SOC)中,设计者一般会将系统的供电分为多个独立的block,这称作电源域(Power Domain),这样做有很多好处,例如:
-
在IO-Domain的DTS节点统一配置电压域,不需要每个驱动都去配置一次,便于管理;
-
依照的是Upstream的做法,以后如果需要Upstream比较方便;
-
IO-Domain的驱动支持运行过程中动态调整电压域,例如PMIC的某个Regulator可以1.8v和3.3v的动态切换,一旦Regulator电压发生改变,会通知IO-Domain驱动去重新设置电压域。
AIO-3399C原理图上的 Power Domain Map 表以及配置如下表所示:
通过RK3399 SDK的原理图可以看到bt656-supply 的电压域连接的是vcc18_dvp, vcc_io是从PMIC RK808的VLDO1出来的; 在DTS里面可以找到vcc1v8_dvp, 将bt656-supply = <&vcc18_dvp>。 其他路的配置也类似,需要注意的是如果这里是其他PMIC,所用的Regulator也不一样,具体以实际电路情况为标准。
IO指令
GPIO调试有一个很好用的工具,那就是IO指令,AIO-3399C的Android系统默认已经内置了IO指令,使用IO指令可以实时读取或写入每个IO口的状态,这里简单介绍IO指令的使用。 首先查看 io 指令的帮助:
从帮助上可以看出,如果要读或者写一个寄存器,可以用:
使用示例:
-
查看GPIO1_B3引脚的复用情况
-
从主控的datasheet查到GPIO1对应寄存器基地址为:0xff320000
-
从主控的datasheet查到GPIO1B_IOMUX的偏移量为:0x00014
-
GPIO1_B3的iomux寄存器地址为:基址(Operational Base) + 偏移量(offset)=0xff320000+0x00014=0xff320014
-
用以下指令查看GPIO1_B3的复用情况:
-
从datasheet查到[7:6]:
因此可以确定该GPIO被复用为 i2c4sensor_sda。
-
如果想复用为GPIO,可以使用以下指令设置:
GPIO调试接口
Debugfs文件系统目的是为开发人员提供更多内核数据,方便调试。 这里GPIO的调试也可以用Debugfs文件系统,获得更多的内核信息。 GPIO在Debugfs文件系统中的接口为 /sys/kernel/debug/gpio,可以这样读取该接口的信息:
从读取到的信息中可以知道,内核把GPIO当前的状态都列出来了,以GPIO0组为例,gpio-2(GPIO0_A2)作为3G模块的电源控制脚(vcc3v3_3g),输出高电平(out hi)。
Q1: 如何将PIN的MUX值切换为一般的GPIO?
A1: 当使用GPIO request时候,会将该PIN的MUX值强制切换为GPIO,所以使用该pin脚为GPIO功能的时候确保该pin脚没有被其他模块所使用。
Q2: 为什么我用IO指令读出来的值都是0x00000000?
A2: 如果用IO命令读某个GPIO的寄存器,读出来的值异常,如 0x00000000或0xffffffff等,请确认该GPIO的CLK是不是被关了,GPIO的CLK是由CRU控制,可以通过读取datasheet下面CRU_CLKGATE_CON* 寄存器来查到CLK是否开启,如果没有开启可以用io命令设置对应的寄存器,从而打开对应的CLK,打开CLK之后应该就可以读到正确的寄存器值了。
Q3: 测量到PIN脚的电压不对应该怎么查?
A3: 测量该PIN脚的电压不对时,如果排除了外部因素,可以确认下该pin所在的io电压源是否正确,以及IO-Domain配置是否正确。
Q4: gpio_set_value()与gpio_direction_output()有什么区别?
A4: 如果使用该GPIO时,不会动态的切换输入输出,建议在开始时就设置好GPIO 输出方向,后面拉高拉低时使用gpio_set_value()接口,而不建议使用gpio_direction_output(), 因为gpio_direction_output接口里面有mutex锁,对中断上下文调用会有错误异常,且相比 gpio_set_value,gpio_direction_output 所做事情更多,浪费。
AIO-3399JD4 开发板上有 9 个片上 I2C 控制器,各个 I2C 的使用情况如下表:
本文主要描述如何在该开发板上配置 I2C。
配置 I2C 可分为两大步骤:
-
定义和注册 I2C 设备
-
定义和注册 I2C 驱动
下面以配置 GSL3680 为例。
在注册I2C设备时,需要结构体 i2c_client 来描述 I2C 设备。然而在标准Linux中,用户只需要提供相应的 I2C 设备信息,Linux就会根据所提供的信息构造 i2c_client 结构体。
用户所提供的 I2C 设备信息以节点的形式写到 dts 文件中,如下所示:
定义 I2C 驱动
在定义 I2C 驱动之前,用户首先要定义变量 of_device_id 和 i2c_device_id 。
of_device_id 用于在驱动中调用dts文件中定义的设备信息,其定义如下所示:
定义变量 i2c_device_id:
i2c_driver 如下所示:
注:变量id_table指示该驱动所支持的设备。
注册 I2C 驱动
使用i2c_add_driver函数注册 I2C 驱动。
在调用 i2c_add_driver 注册 I2C 驱动时,会遍历 I2C 设备,如果该驱动支持所遍历到的设备,则会调用该驱动的 probe 函数。
通过 I2C 收发数据
在注册好 I2C 驱动后,即可进行 I2C 通讯。
-
向从机发送信息:
-
向从机读取信息:
Q1: 通信失败,出现这种log:”timeout, ipd: 0x00, state: 1”该如何调试?
A1: 请检查硬件上拉是否给电。
Q2: 调用i2c_transfer返回值为-6?
A2: 返回值为-6表示为NACK错误,即对方设备无应答响应,这种情况一般为外设的问题,常见的有以下几种情况:
-
I2C地址错误,解决方法是测量I2C波形,确认是否I2C 设备地址错误;
-
I2C slave 设备不处于正常工作状态,比如未给电,错误的上电时序等;
-
时序不符合 I2C slave设备所要求也会产生Nack信号。
Q3: 当外设对于读时序要求中间是stop信号不是repeat start信号的时候,该如何处理?
A3: 这时需要调用两次i2c_transfer, I2C read 拆分成两次,修改如下:
AIO-3399JD4 开发板上使用红外收发传感器 IR (耳机接口和recovery之间)实现遥控功能,在IR接口处接上红外接收器。本文主要描述在开发板上如何配置红外遥控器。
其配置步骤可分为两个部分:
-
修改内核驱动:内核空间修改,Linux 和 Android 都要修改这部分的内容。
-
修改键值映射:用户空间修改(仅限 Android 系统)。
在 Linux 内核中,IR 驱动仅支持 NEC 编码格式。以下是在内核中配置红外遥控的方法。 所涉及到的文件
定义相关数据结构
以下是定义数据结构的步骤:
注:第一列为键值,第二列为要响应的按键码。
如何获取用户码和IR 键值
在 remotectl_do_something 函数中获取用户码和键值:
注:用户可以使用 DBG_CODE() 函数打印用户码。
使用下面命令可以使能DBG_CODE打印:
将 IR 驱动编译进内核
将 IR 驱动编译进内核的步骤如下所示:
(1)、向配置文件 drivers/input/remotectl/Kconfig 中添加如下配置:
(2)、修改 drivers/input/remotectl 路径下的 Makefile,添加如下编译选项:
(3)、在 kernel 路径下使用 make menuconfig ,按照如下方法将IR驱动选中。
保存后,执行 make 命令即可将该驱动编进内核。
Android 键值映射
文件 /system/usr/keylayout/ff420030_pwm.kl 用于将 Linux 层获取的键值映射到 Android 上对应的键值。用户可以添加或者修改该文件的内容以实现不同的键值映射。
该文件内容如下所示:
注:通过 adb 修改该文件重启后即可生效。
如下图是通过按红外遥控器按钮,所产生的波形,主要由head,Control,information,signed free这四部分组成,具体可以参考RC6 Protocol。
AIO-3399JD4开发板默认外置支持了两个LCD屏接口,一个是LVDS,一个是EDP,接口对应板子上的位置如下图:
另外板子也支持MIPI屏幕,但需要注意的是MIPI和LVDS是复用的,使用MIPI之后不能使用LVDS。MIPI接口如下图:
如Android7.1,由于使用的是mipi转lvds,AIO-3399JD4默认的配置文件kernel/arch/arm64/configs/firefly_defconfig已经把LCD相关的配置设置好了,如果自己做了修改,请注意把以下配置加上:
引脚配置
LVDS屏
AIO-3399JD4的SDK有LVDS DSI的DTS文件:kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-aiojd4-lvds-HSX101H40C.dts,从该文件中我们可以看到以下语句:
保存配置并编译内核,把kernel.img 烧到AIO-3399JD4板子上 我们可以使用串口输入命令,就可以看到蓝灯不停的间隔闪烁
用户还可以使用 cat 命令获取 trigger 的可用值:
与摄像头相关的代码目录如下:
设置摄像头相关的引脚和时钟,即可完成配置过程。
从以下摄像头接口原理图可知,需要配置的引脚有:MIPI_PDN0_CAM和MIPI_RST。
mipi接口
MIPI_PDN0_CAM 对应 RK3399 的 GPIO2_A0;
MIPI_RST 对应GPIO0_B0;
在开发板中,这两个引脚都是在 cam_board.xml 中设置。
配置 Android
修改device/rockchip/rk3399/XXX_PRODUCT/cam_board.xml 来注册摄像头:
最后执行:
即可完成内核的编译。
终端下可以直接修改/system/etc/cam_board.xml调试各参数并重启生效
1.无法打开摄像头,首先确定sensor I2C是否通信。若不通则可检查mclk以及供电是否正常(Power/PowerDown/Reset/Mclk/I2cBus)分别排查 2.支持列表ː 13Mː OV13850/IMX214-0AQH5 8Mː OV8825/OV8820/OV8858-Z(R1A)/OV8858-R2A 5Mː OV5648/OV5640 2Mː OV2680 详细资料可查询SDK/RKDocs
AIO-3399JD4开发板上引出有 3 路 PWM 输出,分别为:
PWM0 屏背光
PWM2 VDDLOG供电
PWM3 红外IR
本章主要描述如何配置 PWM。
RK3399的 PWM 驱动为: kernel/drivers/pwm/pwm-rockchip.c
配置 PWM 主要有以下三大步骤:配置 PWM DTS 节点、配置 PWM 内核驱动、控制 PWM 设备。
配置 PWM DTS节点
在 DTS 源文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi 添加 PWM DTS 配置,如下所示:
pwm_id:需要申请的pwm通道数。
min_period:周期时长最小值。
max_period:周期时长最大值。
duty_ns:pwm 的占空比激活的时长,单位 ns。
用户可在其它驱动文件中使用以上步骤生成的 PWM 节点。具体方法如下:
(1)、在要使用 PWM 控制的设备驱动文件中包含以下头文件:
该头文件主要包含 PWM 的函数接口。
(2)、申请 PWM使用
函数申请 PWM。 例如:
(3)、配置 PWM使用
配置 PWM 的占空比, 例如:
(4)、使能PWM 函数
用于使能 PWM,例如:
(5)控制 PWM 输出主要使用以下接口函数:
功能:用于申请 pwm
功能:用于释放所申请的 pwm
功能:用于配置 pwm 的占空比
功能:使能 pwm
功能:禁止 pwm
参考Demo:kernel/drivers/pwm/pwm-firefly.c
通过内核丰富的debug接口查看pwm注册状态,adb shell或者串口进入android终端 cat /sys/kernel/debug/pwm —注册是否成功,成功则返回接口名和寄存器地址
Pwm无法注册成功:
dts配置文件是否打开对应的pwm。
pwm所在的io口是否被其他资源占用,可以根据报错的返回值去查看原因。
SPI是一种高速的,全双工,同步串行通信接口,用于连接微控制器、传感器、存储设备等。 AIO-3399JD4 SPI引出来了一路SPI2(可复用GPIO)给外部使用。 AIO-3399JD4 开发板提供了 SPI2(单片选)接口,具体位置如下图:
SPI以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,分别是:
Linux内核用CPOL和CPHA的组合来表示当前SPI的四种工作模式:
CPOL:表示时钟信号的初始电平的状态,0为低电平,1为高电平。CPHA:表示在哪个时钟沿采样,0为第一个时钟沿采样,1为第二个时钟沿采样。SPI的四种工作模式波形图如下:
下面以 W25Q128FV Flash模块为例简单介绍SPI驱动的编写。
硬件连接
AIO-3399JD4 与 W25Q128FV 硬件连接如下表:
在kernel/drivers/spi/Kconfig中添加对应的驱动文件配置:
在kernel/drivers/spi/Makefile中添加对应的驱动文件名:
config中选中所添加的驱动文件,如:
配置DTS节点
在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中添加SPI驱动结点描述,如下所示:
status:如果要启用SPI,则设为okay,如不启用,设为disable。
spi-demo@00:由于本例子使用CS0,故此处设为00,如果使用CS1,则设为01。
compatible:这里的属性必须与驱动中的结构体:of_device_id 中的成员compatible 保持一致。
reg:此处与spi-demo@00保持一致,本例设为:0x00。
spi-max-frequency:此处设置spi使用的最高频率。Firefly-RK3399最高支持48000000。
spi-cpha,spi-cpol:SPI的工作模式在此设置,本例所用的模块SPI工作模式为SPI_MODE_0或者SPI_MODE_3,这里我们选用SPI_MODE_0,如果使用SPI_MODE_3,spi_demo中打开spi-cpha和spi-cpol即可。
spidev0: 由于spi_demo与spidev0使用一样的硬件资源,需要把spidev0关掉才能打开spi_demo
定义SPI驱动
在内核源码目录kernel/drivers/spi/中创建新的驱动文件,如:spi-firefly-demo.c 在定义 SPI 驱动之前,用户首先要定义变量 of_device_id 。 of_device_id 用于在驱动中调用dts文件中定义的设备信息,其定义如下所示:
此处的compatible与DTS文件中的保持一致。
spi_driver定义如下所示:
注册SPI设备
在初始化函数static int __init spidev_init(void)中向内核注册SPI驱动: spi_register_driver(&firefly_spi_driver);
如果内核启动时匹配成功,则SPI核心会配置SPI的参数(mode、speed等),并调用firefly_spi_probe。
读写 SPI 数据
firefly_spi_probe中使用了两种接口操作读取W25Q128FV的ID: firefly_spi_read_w25x_id_0接口直接使用了spi_transfer和spi_message来传送数据。 firefly_spi_read_w25x_id_1接口则使用SPI接口spi_write_then_read来读写数据。
成功后会打印:
打开SPI demo
spi-firefly-demo默认没有打开,如果需要的话可以使用以下补丁打开demo驱动:
常用SPI接口
下面是常用的 SPI API 定义:
Linux提供了一个功能有限的SPI用户接口,如果不需要用到IRQ或者其他内核驱动接口,可以考虑使用接口spidev编写用户层程序控制SPI设备。 在 Firefly-RK3399 开发板中对应的路径为: /dev/spidev0.0
spidev对应的驱动代码: kernel/drivers/spi/spidev.c
内核config需要选上SPI_SPIDEV:
DTS配置如下:
详细使用说明请参考文档 spidev 。
Q1: SPI数据传送异常
A1: 确保 SPI 4个引脚的 IOMUX 配置正确, 确认 TX 送数据时,TX 引脚有正常的波形,CLK 频率正确,CS 信号有拉低,mode 与设备匹配。
RK3399有12 个Timers (timer0-timer11),有12 个Secure Timers(stimer0~stimer11) 和 2 个Timers(pmutimer0~pmutimer1), 我们主要用到的是Timers(timer0-timer11)时钟频率为24MHZ ,工作模式有 free-running 和 user-defined count 模式
user-defined count:Timer 先载入初始值到 TIMERn_LOAD_COUNT3 和 TIMER_LOADn_COUNT2寄存器, 当时间累加的值在寄存器TIMERn_LOAD_COUNT1和TIMERn_LOAD_COUNT0时,将不会自动载入到计数寄存器。 用户需要重新关闭计数器和然后重新设置计数器相关才能继续工作。
free-running:Timer先载入初始值到TIMER_LOAD_COUNT3 和 TIMER_LOAD_COUNT2寄存器, 当时间累加的值在寄存器TIMERn_LOAD_COUNT1和TIMERn_LOAD_COUNT0时,Timer将一直自动加载计数寄存器。
1.在 dts 文件中定义 Timer 的相关配置 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi
其中定义的Timer0 的寄存器和中断号和时钟等
其他Timer 对应的中断号可看如下图片
2.对应的驱动文件Kernel/drivers/clocksource/rockchip_timer.c
1.寄存器如下图片
文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-port.dtsi 有spi转uart相关节点的定义:
可以看到,在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-aiojd4.dts文件中使能该节点即可使用。另外,由于我们板子使用的spi转uart串口模块挂到spi1上,所以还要使能spi1节点。如下:
注意:由于spi1_rxd和spi1_txd两个脚可复用为uart4_rx和uart4_tx,所以要留意关闭掉uart4的使用,如下:
配置好串口后,硬件接口对应软件上的节点分别为:
用户可以根据不同的接口使用不同的主机的 USB 转串口适配器向开发板的串口收发数据,例如RS485的调试步骤如下:
(1) 连接硬件
将开发板RS485 的A、B、GND 引脚分别和主机串口适配器(USB转485转串口模块)的 A、B、GND 引脚相连。
(2) 打开主机的串口终端
在终端打开kermit,并设置波特率:
/dev/ttyUSB0 为 USB 转串口适配器的设备文件
(3) 发送数据
RS485 的设备文件为 /dev/ttysWK0。在设备上运行下列命令:
主机中的串口终端即可接收到字符串“firefly RS485 test…”
(4) 接收数据
首先在设备上运行下列命令:
然后在主机的串口终端输入字符串 “Firefly RS485 test…”,设备端即可见到相同的字符串。
-->
-
嵌入式主板
+关注
关注
7文章
6085浏览量
35294 -
安卓
+关注
关注
5文章
2126浏览量
57144 -
Firefly
+关注
关注
2文章
538浏览量
7026
发布评论请先 登录
相关推荐
评论