K230小核Linux驱动API参考
1 概述
1.1 概述
UART: 通用异步收发器,该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。
I2C: 由Philips公司(2006年迁移到NXP)在1980年代初开发的一种简单、双线双向的同步串行总线,它利用一根时钟线和一根数据线在连接总线的两个器件之间进行信息的传递,为设备之间数据交换提供了一种简单高效的方法。每个连接到总线上的器件都有唯一的地址,任何器件既可以作为主机也可以作为从机,但同一时刻只允许有一个主机。
GPIO: (general porpose intput output)通用输入输出端口的简称。可以通过软件控制其输出和输入,通俗来说就是常用引脚,可以控制引脚的高低电平,对其进行读取或者写入。
Hard-lock: 嘉楠自研模块,用于同核不通进程间或异核之间对共享资源的互斥而实现的硬件互斥锁,可用于对共享资源的互斥使用。
WDT: WDT是watchdog的简称,本质上是一个硬件定时器,软件程序需要每隔一段时间喂一次狗,如果WDT超时则可以产生一个中断信号或复位信号到CPU,由此通过软硬件结合的方式防止程序运行异常而不能恢复。
OTP: OTP 主要用于存储安全敏感的机密信息,例如 bootrom 的固件信息、加解密密钥、签名信息以及用户自己定义的安全信息等。
TS: K230 TS(Temperature Sensor ),自研温度传感器,采用 TSMC 12nm 工艺,TS 的应用场景是降频。
TRNG: TRNG 主要用于产生真随机数,从而为加解密运算提供一个随机熵源。
ADC: ADC 指模数转换器,是指将连续变化的模拟信号转换为离散的数字信号的器件。
PWM: PWM 脉冲宽度调制,是一种对模拟信号电平进行数字编码的方法,通过调制正脉冲周期所占的比例来对一个具体模拟信号的电平进行编码。
1.2 功能描述
1.2.1 uart模块
K230共有5路uart,且uart模块支持红外模式,支持RS485模式,支持DMA,部分端口支持流控,数据位支持5/6/7/8比特,停止位1/2比特,波特率可以支持到1.5MHz。
1.2.2 i2c模块
K230共有5路i2c,i2c模块支持主模式,支持DMA,支持7/10比特寻址,支持中断,i2c模块传输速率支持100k/400k/1M/3.4M.
1.2.3 gpio模块
k230共有2路gpio,每路gpio包含32个gpio端口,共64个gpio端口,每个gpio端口均支持输入输出功能,支持上升沿中断,下降沿中断,高低电平中断,和双边沿中断。k230的每个gpio端口的中断相互独立互不影响。
1.2.4 hard-lock模块
k230有128个硬件互斥锁,其作用类似Linux的自旋锁,可以用于对同一资源的互斥。
1.2.5 wdt模块
wdt,watchdog模块,k230有两路wdt,大小核分别使用一路,wdt支持中断和复位两种模式,默认使用复位模式,即当wdt的超时时间溢出时,直接使soc复位。
1.2.6 OTP模块
OTP 集成在安全模块 PUF 中,为整个 SoC 提供安全存储功能,保护根密钥和启动代码等关键数据不被攻击者破坏。小核侧 OTP 驱动主要提供读功能,可读区域为包括生产信息在内的 24Kbits 空间。Linux 侧 OTP 驱动挂载在 nvmem 框架上,具体的框架结构如下图所示:
1.2.7 TS模块
大核侧 TS 驱动主要提供读功能,在读 TS 之前,首先需要配置 TS 寄存器使能信号、输出模式,然后才能读出芯片的结温。另外,TS 寄存器每 2.6s 读取一次芯片结温。Rt-smart 侧 TS 驱动的结构如下图所示:
1.2.8 TRNG模块
TRNG 集成在安全模块 PUF 中,为整个 SoC 提供真随机数功能,保护根密钥和启动代码等关键数据不被攻击者破坏。小核侧 TRNG 驱动主要提供读功能,TRNG 驱动挂载在 HW random 框架上,具体的框架结构如下图所示:
1.2.9 ADC模块
K230集成一路ADC转换器,共6各通道,分辨率12bit,最高每秒1M次的单通道连续模数转换。
1.2.10 PWM模块
K230集成了2路PWM,每一路有3各通道,即通道 02 属于PWM0,通道 35 属于PWM1(软件上表现为通道 0~5 ),每一路都可输出独立波形。
2 API参考
2.1 UART API参考
Linux封装了termios API用来给用户使用,termios API描述了一个通用的终端接口,提供了控制异步通讯端口的配置和读写。
termios API举例:
int tcgetattr(int fd,struct termios *termios_p);
int tcsetattr(int fd,int potional_actions,struct termios *termios_p);
int tcsendbreak(int fd,int duration);
int tcdrain(int fd);
int tcflush(int fd, int queue_selector);
int tcflow(int fd, int action);
void cfmakeraw(struct termios *termios_p);
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int cfsetspeed(struct termios *termios_p, speed_t speed);
详细请参考Documentation/driver-api/serial/tty.rst
。
2.2 I2C API参考
linux为用户称封装了系统调用来使用i2c。
2.3 GPIO API参考
2.3.1 sysfs控制gpio
GPIO驱动加载后会在 /sys/class/gpio/
下创建gpio端口的设备节点,每个节点代表一个gpio端口,通过sysfs操作这个gpio端口即可达到操作gpio输入输出和中断的作用。
方法1:
echo N > /sys/class/gpio/export //将编号为 N 的gpio端口导出到sysfs
echo in > /sys/class/gpio/gpioN/direction //将该gpio端口设置成输入模式
cat /sys/class/gpio/gpioN/value //读取该gpio端口电平状态
echo out > /sys/class/gpio/gpioN/direction //将该gpio端口设置成输出模式
echo 1 > /sys/class/gpio/gpioN/value //将该端口输出高电平,注意active_low极性
echo 0 > /sys/class/gpio/gpioN/value //将该端口输出低电平,注意active_low极性
设置中断属性:
echo rising > /sys/class/gpio/gpioN/edge 上升沿中断,中断只能在direction为in时才可以设置
echo falling > /sys/class/gpio/gpioN/edge 下降沿中断
echo both > /sys/class/gpio/gpioN/edge 双边沿中断
方法2:
设置好中断模式后通过poll函数监听中断:
struct pollfd fds[1];
fd = open("/sys/class/gpio/gpioN/value", O_RDONLY)
fds[0].fd = gpio_fd;
fds[0].events = POLLPRI;
while(1)
{
poll(fds, 1, -1);
if (fds[0].revents & POLLPRI)
{
/* 接收中断 */
}
}
2.3.2 ioctl控制gpio
用户程序直接操作 /dev/gpiochipN
:
struct gpiohandle_request req;
struct gpiohandle_data data;
struct gpioevent_request event_req;
struct gpioevent_data event_data;
struct pollfd poll_fd;
fd = open("/dev/gpiochipN", O_RDONLY);
.....
req.lineoffsets[0] = 0;
req.flags = GPIOHANDLE_REQUEST_OUTPUT;
req.lines = 1;
event_req.lineoffset = 0;
event_req.handleflags = GPIOHANDLE_REQUEST_INPUT;
event_req.eventflags = GPIOEVENT_REQUEST_RISING_EDGE;
ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &event_req);
close(fd);
poll_fd.fd = event_req.fd;
poll_fd.events = POLLIN;
while(1)
{
data.values[0] = !data.values[0];
.....
ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
.....
ret = poll(&poll_fd, 1, 3000);
if(ret == 0)
....
else {
read(event_req.fd, &event_data, sizeof(event_data));
}
}
close(req.fd);