前言
K230 芯片是一款基于 RISC-V 架构的端侧 AIoT 芯片,包含两个核心:
CPU 1: RISC-V 处理器,1.6GHz,32KB I-cache, 32KB D-cache, 256KB L2 Cache,128bit RVV 1.0扩展
CPU 0: RISC-V 处理器,0.8GHz,32KB I-cache, 32KB D-cache, 128KB L2 Cache
K230 SDK 提供了不同版本,包含了基于Linux&RT-smart 双核异构系统及RT-smart单系统开发需要用到的源代码,工具链和其他相关资源。
为了更加全面掌握嵌入式和AI的知识,我们选择Linux&RT-smart SDK,本系列教程先介绍简要基于C的相关开发,之后介绍使用MicroPython的开放方法,建议以MicroPython开发为主,快速验证算法和方案,后续对性能有要求时候转化成c;
双系统SDK内存可以配置,在k230_sdk下运行make menuconfig->Memory configuration可以配置各个区域使用的内存空间,也可以直接编译configs/k230_canmv_defconfig修改,各区域说明如下
bash
CONFIG_MEM_TOTAL_SIZE="0x20000000" #内存总体容量 不支持配置
CONFIG_MEM_PARAM_BASE="0x00000000" #参数分区起始地址 不支持配置
CONFIG_MEM_PARAM_SIZE="0x00100000" #参数分区大小 不支持配置
CONFIG_MEM_IPCM_BASE="0x00100000" #核间通讯起始地址 不支持配置
CONFIG_MEM_IPCM_SIZE="0x00100000" #核间通讯共享内存大小 不支持配置
CONFIG_MEM_RTT_SYS_BASE="0x00200000" #大核RTT起始地址 支持配置
CONFIG_MEM_RTT_SYS_SIZE="0x07E00000" #大核RTT使用的地址范围 支持配置
CONFIG_MEM_AI_MODEL_BASE="0x1FC00000" #AI模型加载起始地址 支持配置
CONFIG_MEM_AI_MODEL_SIZE="0x00400000" #AI模型加载地址区域 支持配置
CONFIG_MEM_LINUX_SYS_BASE="0x08000000" #小核linux起始地址 支持配置
CONFIG_MEM_LINUX_SYS_SIZE="0x08000000" #小核linux地址区域 支持配置
CONFIG_MEM_MMZ_BASE="0x10000000" #mmz共享内存其实地址 支持配置
CONFIG_MEM_MMZ_SIZE="0x0FC00000" #mmz 共享内存区域 支持配置
CONFIG_MEM_BOUNDARY_RESERVED_SIZE="0x00001000" #隔离区 不支持配置
大家也可以根据实际需要从官网或者自己编译相应的SDK
下面对于各种驱动的介绍大家也可以参与K210系列教程的内容(https://blog.csdn.net/bin_zhang1/article/details/135519402?fromshare=blogdetail\&sharetype=blogdetail\&sharerId=135519402\&sharerefer=PC\&sharesource=bin_zhang1\&sharefrom=from_link)
为了方便大家查找相关资料这里提供原理图连接
CanMV-K230 V1.1 开发板位号图文件连接
一、UART
UART概述:通用异步收发器,该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。
K230共有5路uart,且uart模块支持红外模式,支持RS485模式,支持DMA,部分端口支持流控,数据位支持5/6/7/8比特,停止位1/2比特,波特率可以支持到1.5MHz。
c
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);
二、I2C
I2C:由Philips公司(2006年迁移到NXP)在1980年代初开发的一种简单、双线双向的同步串行总线,它利用一根时钟线和一根数据线在连接总线的两个器件之间进行信息的传递,为设备之间数据交换提供了一种简单高效的方法。每个连接到总线上的器件都有唯一的地址,任何器件既可以作为主机也可以作为从机,但同一时刻只允许有一个主机。
K230共有5路i2c,i2c模块支持主模式,支持DMA,支持7/10比特寻址,支持中断,i2c模块传输速率支持100k/400k/1M/3.4M.
三、GPIO
GPIO:(general porpose intput output)通用输入输出端口的简称。可以通过软件控制其输出和输入,通俗来说就是常用引脚,可以控制引脚的高低电平,对其进行读取或者写入。
k230共有2路gpio,每路gpio包含32个gpio端口,共64个gpio端口,每个gpio端口均支持输入输出功能,支持上升沿中断,下降沿中断,高低电平中断,和双边沿中断。k230的每个gpio端口的中断相互独立互不影响。
方法1:
c
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:
bash
设置好中断模式后通过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)
{
/* 接收中断 */
}
}
ioctl操作gpio
用户程序直接操作 /dev/gpiochipN:
bash
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);
四、Hard-lock
嘉楠自研模块,用于同核不通进程间或异核之间对共享资源的互斥而实现的硬件互斥锁,可用于对共享资源的互斥使用。
k230有128个硬件互斥锁,其作用类似Linux的自旋锁,可以用于对同一资源的互斥。
五、ADC
ADC 即模拟数字转换器(Analog-to-digital converter),是指将连续变化的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。模数转换器可以实现这个功能,在各种不同的产品中都可以找到它的身影。
K230集成一路ADC转换器,共6各通道,分辨率12bit,最高每秒1M次的单通道连续模数转换。
六、WDT
WDT 是watchdog的简称,本质上是一个定时器,软件程序需要每隔一段时间喂一次狗,如果WDT超时则可以产生一个中断信号或复位信号到CPU,由此通过软硬件结合的方式防止程序运行异常而不复位。
wdt,watchdog模块,k230有两路wdt,大小核分别使用一路,wdt支持中断和复位两种模式,默认使用复位模式,即当wdt的超时时间溢出时,直接使soc复位
七、OTP
OTP 主要用于存储安全敏感的机密信息。OTP 集成在安全模块 PUF 中,为整个 SoC 提供安全存储功能,保护根密钥和启动代码等关键数据不被攻击者破坏。大核侧 OTP 驱动主要提供读、写两种功能,可读写区域768bytes 空间。如果产品量产需要用到OTP的读写保护功能等等,请联系我们,我们会提供相关的接口驱动程序。
OTP 集成在安全模块 PUF 中,为整个 SoC 提供安全存储功能,保护根密钥和启动代码等关键数据不被攻击者破坏。小核侧 OTP 驱动主要提供读功能,可读写区域空间为768bytes。Linux 侧 OTP 驱动挂载在 nvmem 框架上,具体的框架结构如下图所示:
八、TS
K230 TS(Temperature Sensor),自研温度传感器,采用 TSMC 12nm 工艺。TS 的应用场景是降频。大核侧 TS 驱动主要提供读功能,在读 TS 之前,首先需要配置 TS 寄存器使能信号、输出模式,然后才能读出芯片的结温。另外,TS 寄存器每 2.6s 读取一次芯片结温。
大核侧 TS 驱动主要提供读功能,在读 TS 之前,首先需要配置 TS 寄存器使能信号、输出模式,然后才能读出芯片的结温。另外,TS 寄存器每 2.6s 读取一次芯片结温。Rt-smart 侧 TS 驱动的结构如下图所示:
九、PWM
PWM是一种对模拟信号电平进行数字编码的方法,通过不同频率的脉冲使用方波的占空比用来对一个具体模拟信号的电平进行编码,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替所需要波形的设备。
K230集成了2路PWM,每一路有3各通道,即通道 0~2 属于PWM0,通道 3~5 属于PWM1(软件上表现为通道 0~5 ),每一路都可输出独立波形。
十、RTC
实时时钟可以提供精确的实时时间,它可以用于产生年、月、日、时、分、秒、星期等信息。
十一、RTCTIMER(HWTIMER)
通过内部计数器模块对内外部脉冲信号进行计数,可以工作在定时器模式和计数器模式。
总结
基于C的开发现在嘉楠提供的API尚不完善,建议以MicroPython开发为主,快速验证算法和方案,后续对性能有要求时候转化成c;