正点原子Linux开发板 spi内核驱动 0.96寸ips屏教程

正点原子Linux开发板 spi内核驱动 0.96寸ips屏教程

最近做下底层SPI驱动来驱动IPS屏,本来想实现这种效果:

在这里插入图片描述后面想着暂时不做frambuffer,用用spi巩固一下吧,于是就有了本次记录。

首先选择模块

去tb某店买了两块ips屏幕,一块0.96寸,一块1.3寸(当时 想着两个都用下,大的显示的多些)
显示屏如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200620172251526.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JheW1vbmRfOTdf,size_16,color_FFFFFF,t_70
拿到代码后,找的stm32的1.3寸屏程序作为参考,开始移植1.3寸屏到linux上去。折腾了一上午加半个下午,显示屏就是没亮?what 我把每个发过去的spi数据都打印出来,都是对的,我惊了。脑袋嗡嗡的了,罢了 换0.96寸的屏,重新配置初始化命令,刷新屏幕,亮了!我崩溃了,合着屏幕是坏的? 示例程序有问题? 后面检查发现spi->mode = SPI_MODE_2; /*MODE0,CPOL=0,CPHA=0 //出问题的地方!!!*/spi模式需要改。
驱动1.3寸显示屏请移步如下链接:
1.3寸ips显示屏驱动地址
0.96寸的屏幕,以下是代码部分:

设备树配置

		//功能引脚
        pinctrl_ipsRes: ipsRes {    //屏幕复位u引脚
            fsl,pins = <
            	MX6UL_PAD_GPIO1_IO01__GPIO1_IO01        0x10B0 /* LED0 */
            >;
        };  
        pinctrl_ipsDc: ipsDc {      //屏幕dc(data or command)u引脚
            fsl,pins = <
            	MX6UL_PAD_GPIO1_IO04__GPIO1_IO04        0x10B0 
            >;
        };
       ..............//附加节点
        &ecspi3 {
			fsl,spi-num-chipselects = <1>;
			cs-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>; /* cant't use cs-gpios! */
			pinctrl-names = "default";
			pinctrl-0 = <&pinctrl_ecspi3>;
			status = "okay";

		spidev: ipsTft@0 {
			compatible = "alientek,ipsTft";
			spi-max-frequency = <1000000000>;	//频率无脑给的很大,但是刷新频率快不起来
			reg = <0>;
		};
};

spi驱动程序(用的spi_driver)

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/spi/spi.h>
#define ipsTft_CNT	1
#define ipsTft_NAME	"ipsTft"
#define LCD_W 240
#define LCD_H 240
#define X_MAX_PIXEL	        160
#define Y_MAX_PIXEL	        80
#define RED  	0xf800
#define GREEN	0x07e0
#define BLUE 	0x001f
#define WHITE	0xffff
#define BLACK	0x0000
#define YELLOW  0xFFE0
#define GRAY0   0xEF7D   	//»ÒÉ«0 3165 00110 001011 00101
#define GRAY1   0x8410      	//»ÒÉ«1      00000 000000 00000
#define GRAY2   0x4208      	//»ÒÉ«2  1111111111011111
u8 buf[9] = {
RED, GREEN,	BLUE,WHITE,	BLACK,	YELLOW,GRAY0 ,GRAY1 ,GRAY2 
};
struct ipsTft_dev {
	dev_t devid;				/* 设备号 	 */
	struct cdev cdev;			/* cdev 	*/
	struct class *class;		/* 类 		*/
	struct device *device;		/* 设备 	 */
	struct device_node	*nd; 	/* 设备节点 */
	int major;					/* 主设备号 */
	void *private_data;			/* 私有数据 		*/
	int dc_gpio;				/* 片选所使用的GPIO编号		*/
    int res_gpio;                 /*ips屏幕复位引脚*/
    int cs_gpio;                    /*磁力计的cs*/
};
static struct ipsTft_dev ipsTftdev;
void ipsTft_reginit(struct ipsTft_dev *dev);
// struct spi_lcd_cmd{

//     u8  reg_addr; // command

//     u8  len;  //需要从spi_lcd_datas数组里发出数据字节数

//     int delay_ms; //此命令发送数据完成后,需延时多久

// }cmds[] = {

//     {0x36, 1, 0},

//     {0x3A, 1, 0},

//     {0xB2, 5, 0},

//     {0xB7, 1, 0},

//     {0xBB, 1, 0},

//     {0xC0, 1, 0},

//     {0xC2, 1, 0},

//     {0xC3, 1, 0},

//     {0xC4, 1, 0},

//     {0xC6, 1, 0},

//     {0xD0, 2, 0},

//     {0xE0, 14, 0},

//     {0xE1, 14, 0},

//     {0x21, 0, 0},

//     {0x11, 0, 0},

//     {0x29, 0, 0},

// };
// u8 spi_lcd_datas[] = {

//     0x00, 

//     0x05,

//     0x0c,0x0c,0x00,0x33,0x33,

//     0x35,

//     0x19,

//     0x2c,

//     0x01,

//     0x12, 

//     0x20, 

//     0x0F, 

//     0xA4,0xA1,

//     0xD0,0x04,0x0D,0x11,0x13,0x2B,0x3F,0x54,0x4C,0x18,0x0D,0x0B,0x1F,0x23,

//     0xD0,0x04,0x0C,0x11,0x13,0x2C,0x3F,0x44,0x51,0x2F,0x1F,0x1F,0x20,0x23,

// };
struct spi_lcd_cmd{
    u8  reg_addr; // command
    u8  len;  //需要从spi_lcd_datas数组里发出数据字节数
    int delay_ms; //此命令发送数据完成后,需延时多久
}cmds[] = {
    {0x11, 0, 120},
    {0x21, 0, 0},
    {0x21, 0, 0},
    {0xB1, 3, 0},
    {0xB2, 3, 0},
    {0xB3, 6, 0},
    {0xB4, 1, 0},
    {0xC0, 3, 0},
    {0xC1, 1, 0},
    {0xC2, 2, 0},
    {0xC3, 2, 0},
    {0xC4, 2, 0},
    {0xC5, 1, 0},
    {0xE0, 16, 0},
    {0xE1, 16, 0},
    {0x3A, 1, 0},
    {0x36, 1, 0},
    {0x29, 0, 0},
};
u8 spi_lcd_datas[] = {
   0x05,0x3A,0x3A,
   0x05,0x3A,0x3A,
   0x05,0x3A,0x3A,0x05,0x3A,0x3A,
   0x03,
   0x62,0x02,0x04,
   0xC0,
   0x0D,0x00,
   0x8D,0x6A,
   0x8D,0xEE,
   0x0E,
   0x10,0x0E,0x02,0x03,0x0E,0x07,0x02,0x07,0x0A,0x12,0x27,0x37,0x00,0x0D,0x0E,0x10,
   0x10,0x0E,0x03,0x03,0x0F,0x06,0x02,0x08,0x0A,0x13,0x26,0x36,0x00,0x0D,0x0E,0x10,
   0x05,    
   0xA8,
};
/*
 * @description	: 向ipsTft多个寄存器写入数据
 * @param - dev:  ipsTft设备
 * @param - reg:  要写入的寄存器首地址
 * @param - val:  要写入的数据缓冲区
 * @param - len:  要写入的数据长度
 * @return 	  :   操作结果
 */
static s32 ipsTft_write_regs(struct ipsTft_dev *dev,u8 *buf, u8 len)
{
	int ret;
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;
	t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */
	/* 发送要写入的数据 */
	t->tx_buf = buf;			/* 要写入的数据 */
	t->len = len;				/* 写入的字节数 */
	spi_message_init(&m);		/* 初始化spi_message */
	spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
	ret = spi_sync(spi, &m);	/* 同步发送 */
	kfree(t);					/* 释放内存 */
	return ret;
}
/*
 * @description	: 向ipsTft指定寄存器写入指定的值,写一个寄存器
 * @param - dev:  ipsTft设备
 * @param - reg:  要写的寄存器
 * @param - data: 要写入的值
 * @return   :    无
 */	
static void ipsTft_write_onereg(struct ipsTft_dev *dev, u8 buf)
{
	ipsTft_write_regs(dev,&buf, 1);
    //spi_write(dev,&buf, 1);
}
/*
    funciton: 写一个命令
*/
void write_command(struct ipsTft_dev *dev, u8 cmd)
{
    // dc , command:0
    gpio_set_value(dev->dc_gpio, 0); 
    ipsTft_write_onereg(dev,cmd);
}
/*
    funciton: 写一个数据
*/
void write_data(struct ipsTft_dev *dev, u8 data)
{
    gpio_set_value(dev->dc_gpio, 1);
    ipsTft_write_onereg(dev,data);
}
/*
    funciton: 写一个数据
*/
static void write_datas(struct ipsTft_dev *dev, int data,int len)
{
    gpio_set_value(dev->dc_gpio, 1);
    ipsTft_write_regs(dev,(u8 *)&data,len);
}
/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做pr似有ate_data的成员变量
 * 					  一般在open的时候将private_data似有向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int ipsTft_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &ipsTftdev; /* 设置私有数据 */
    ipsTft_reginit(&ipsTftdev);
	return 0;
}
/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int ipsTft_release(struct inode *inode, struct file *filp)
{
	return 0;
}
/* ipsTft操作函数 */
static const struct file_operations ipsTft_ops = {
	.owner = THIS_MODULE,
	.open = ipsTft_open,
	.release = ipsTft_release,
};
void Address_set(struct ipsTft_dev *dev,unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{ 
    write_command(dev,0x2a);
    write_data(dev,x1>>8);
    write_data(dev,x1);
    write_data(dev,x2>>8);
    write_data(dev,x2);
    write_command(dev,0x2b);
    write_data(dev,y1>>8);
    write_data(dev,y1);
    write_data(dev,y2>>8);
    write_data(dev,y2);
    write_command(dev,0x2C);					 						 
}
/*
    刷屏函数
*/
void LCD_Clear(struct ipsTft_dev *dev)
{
	u16 i,j;  	
	Address_set(dev,0,0,LCD_W-1,LCD_H-1);
    for(i=0;i<LCD_W;i++)
	 {
	  for (j=0;j<LCD_H;j++)
	   	{
        	//write_datas(dev,0xF800,2);	    //全红 		
            write_data(dev,0xF800>>8);
            write_data(dev,0xF800&0xFF);
	    }
	  }
}
/*************************************************

0.96'

*************************************************/
void Lcd_SetRegion(struct ipsTft_dev *dev,u16 x_start,u16 y_start,u16 x_end,u16 y_end)
{		
	write_command(dev,0x2a);
	write_data(dev,0x00);
	write_data(dev,x_start+1);
	write_data(dev,0x00);
	write_data(dev,x_end+1);
	write_command(dev,0x2b);
	write_data(dev,0x00);
	write_data(dev,y_start+0x1A);
	write_data(dev,0x00);
	write_data(dev,y_end+0x1A);	
	write_command(dev,0x2c);
}
/*************************************************
0.96'显示屏填充函数
*************************************************/
void Lcd_Clear_small(struct ipsTft_dev *dev,u16 Color)            
{	
   unsigned int i,m;
   Lcd_SetRegion(dev,0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);
   write_command(dev,0x2C);
   for(i=0;i<X_MAX_PIXEL;i++)
    for(m=0;m<Y_MAX_PIXEL;m++)
    {	
	  	//LCD_WriteData_16Bit(Color);
          write_data(dev,Color>>8);
          write_data(dev,Color&0xFF);
    }   
}
/*
 * ipsTft内部寄存器初始化函数 
 * @param  	: 无
 * @return 	: 无
 */
void ipsTft_reginit(struct ipsTft_dev *dev)
{
     int i, j, n;
    gpio_set_value(ipsTftdev.res_gpio, 0);
    mdelay(500);
    gpio_set_value(ipsTftdev.res_gpio, 1);
    mdelay(500);
    n = 0; // n用于记录数据数组spi_lcd_datas的位置
    //发命令,并发出命令所需的数据
    for (i = 0; i < ARRAY_SIZE(cmds); i++) //命令
    {
        write_command(dev, cmds[i].reg_addr);
        for (j = 0; j < cmds[i].len; j++) //发出命令后,需要发出的数据
            if(cmds[i].len!=0)
                write_data(dev, spi_lcd_datas[n++]);
        printk("the n is %d\n",n);
        if (cmds[i].delay_ms) //如有延时则延时
            mdelay(cmds[i].delay_ms);
    }
    n=0;
    while(n<9){
         Lcd_Clear_small(dev,*(buf+n));
         n++;
         mdelay(1000);
    }
    printk("ips init finish!\n");
}
 /*
  * @description     : spi驱动的probe函数,当驱动与
  *                    设备匹配以后此函数就会执行
  * @param - client  : spi设备
  * @param - id      : spi设备ID
  * 
  */	
static int ipsTft_probe(struct spi_device *spi)
{
	int ret = 0;
	/* 1、构建设备号 */
	if (ipsTftdev.major) {
		ipsTftdev.devid = MKDEV(ipsTftdev.major, 0);
		register_chrdev_region(ipsTftdev.devid, ipsTft_CNT, ipsTft_NAME);
	} else {
		alloc_chrdev_region(&ipsTftdev.devid, 0, ipsTft_CNT, ipsTft_NAME);
		ipsTftdev.major = MAJOR(ipsTftdev.devid);
	}
	/* 2、注册设备 */
	cdev_init(&ipsTftdev.cdev, &ipsTft_ops);
	cdev_add(&ipsTftdev.cdev, ipsTftdev.devid, ipsTft_CNT);
	/* 3、创建类 */
	ipsTftdev.class = class_create(THIS_MODULE, ipsTft_NAME);
	if (IS_ERR(ipsTftdev.class)) {
		return PTR_ERR(ipsTftdev.class);
	}
	/* 4、创建设备 */
	ipsTftdev.device = device_create(ipsTftdev.class, NULL, ipsTftdev.devid, NULL, ipsTft_NAME);
	if (IS_ERR(ipsTftdev.device)) {
		return PTR_ERR(ipsTftdev.device);
	}
	/* 获取设备树中cs片选信号 */
	ipsTftdev.nd = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000");
	if(ipsTftdev.nd == NULL) {
		printk("ecspi3 node not find!\r\n");
		return -EINVAL;
	}
	/* 2、 获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */
	ipsTftdev.cs_gpio = of_get_named_gpio(ipsTftdev.nd, "cs-gpio", 0);
	if(ipsTftdev.cs_gpio < 0) {
		printk("can't get cs-gpio");
		return -EINVAL;
	}
    ipsTftdev.nd = of_find_node_by_path("/ipsRes");
	if(ipsTftdev.nd == NULL) {
		printk("res-gpio node not find!\r\n");
		return -EINVAL;
        }
    ipsTftdev.res_gpio = of_get_named_gpio(ipsTftdev.nd, "res-gpio", 0);
    if(ipsTftdev.res_gpio < 0) {
		printk("can't get res-gpio");
		return -EINVAL;
	}
    ipsTftdev.nd = of_find_node_by_path("/ipsDc");
	if(ipsTftdev.nd == NULL) {
		printk("ipsDcgpio node not find!\r\n");
		return -EINVAL;
        }
    ipsTftdev.dc_gpio = of_get_named_gpio(ipsTftdev.nd, "dc-gpio", 0);
    if(ipsTftdev.dc_gpio < 0) {
		printk("can't get ipsDc-gpio");
		return -EINVAL;
	}
	/* 3、设置GPIO1_IO20为输出,并且输出高电平 */
	ret = gpio_direction_output(ipsTftdev.cs_gpio, 1);
	if(ret < 0) {
		printk("can't set cs gpio!\r\n");
	}
    ret = gpio_direction_output(ipsTftdev.res_gpio, 1);
	if(ret < 0) {
		printk("can't set res gpio!\r\n");
	}
    ret = gpio_direction_output(ipsTftdev.dc_gpio, 1);
	if(ret < 0) {
		printk("can't set dc gpio!\r\n");
	}
	/*初始化spi_device */
	spi->mode = SPI_MODE_0;	/*MODE0,CPOL=0,CPHA=0*/
	spi_setup(spi);
	ipsTftdev.private_data = spi; /* 设置私有数据 */
	/* 初始化ipsTft内部寄存器 */
	ipsTft_reginit(&ipsTftdev);		
	return 0;
}
/*
 * @description     : spi驱动的remove函数,移除spi驱动的时候此函数会执行
 * @param - client 	: spi设备
 * @return          : 0,成功;其他负值,失败
 */
static int ipsTft_remove(struct spi_device *spi)
{
	/* 删除设备 */
	cdev_del(&ipsTftdev.cdev);
	unregister_chrdev_region(ipsTftdev.devid, ipsTft_CNT);
	/* 注销掉类和设备 */
	device_destroy(ipsTftdev.class, ipsTftdev.devid);
	class_destroy(ipsTftdev.class);
	return 0;
}
/* 传统匹配方式ID列表 */
static const struct spi_device_id ipsTft_id[] = {
	{"alientek,ipsTft", 0},  
	{}
};
/* 设备树匹配列表 */
static const struct of_device_id ipsTft_of_match[] = {
	{ .compatible = "alientek,ipsTft" },
	{ /* Sentinel */ }
};
/* SPI驱动结构体 */	
static struct spi_driver ipsTft_driver = {
	.probe = ipsTft_probe,
	.remove = ipsTft_remove,
	.driver = {
			.owner = THIS_MODULE,
		   	.name = "ipsTft",
		   	.of_match_table = ipsTft_of_match, 
		   },
	.id_table = ipsTft_id,
};
/*
 * @description	: 驱动入口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init ipsTft_init(void)
{
	return spi_register_driver(&ipsTft_driver);
}
/*

 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit ipsTft_exit(void)
{
	spi_unregister_driver(&ipsTft_driver);
}
module_init(ipsTft_init);
module_exit(ipsTft_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("raymond");

insmode 一下就行了😜,加载模块后在/dev下会有一个ipsTft节点。
在这里插入图片描述
probe函数调用后会触发屏幕初始化配置函数,配置完后屏幕会刷新几种颜色(纯用于测试,加载自动测试,岂不美哉),APP文件只需要open一下就会重复刷新操作。(没完善,就是测试一下spi驱动,真要自己找字库那真的没意思了)想要好看的话用frambuffer吧!

app

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd;
	char *filename;
	int ret = 0;
	if (argc != 2) {
		printf("Error Usage!\r\n");
		return -1;
	}
	filename = argv[1];
	fd = open(filename, O_RDWR);
	if(fd < 0) {
		printf("can't open file %s\r\n", filename);
		return -1;
	}else{
        printf("open the ips!\n");
    }
	close(fd);	/* 关闭文件 */	
	return 0;
}

执行shell

./ipsApp /dev/ipsTft

好了,简单测试结束,接下来用frambuffer实现上面第一张图的效果。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 正点原子Linux开发板 PCB 是一块专为Linux操作系统开发设计的电路板。它采用了高质量材料制造而成,具有良好的稳定性和性能。该开发板提供了一些核心组件,如处理器,存储器,输入输出接口等,以帮助用户进行快速开发和原型设计。 正点原子Linux开发板 PCB 提供了丰富的连接接口和扩展插槽,以满足开发人员对不同外围设备的需求。用户可以通过这些接口连接各种传感器,执行器,通信模块等,从而实现各种应用场景。此外,该开发板还具有强大的计算和嵌入式能力,可以支持复杂的算法和应用程序。 正点原子Linux开发板 PCB 具有丰富的软件支持。用户可以通过预装的Linux操作系统访问开源软件和工具,以进行应用开发和调试。同时,该开发板还提供了完善的开发文档和示例代码,帮助用户快速上手和开发。 总之,正点原子Linux开发板 PCB 是一块功能强大的电路板,适用于各种Linux应用开发和原型设计。它的高质量材料和稳定性使得它成为开发人员的理想选择,并且丰富的软件支持和接口使得开发过程更加便捷。无论是学习嵌入式系统开发还是进行实际应用的开发,正点原子Linux开发板 PCB 都是一个可靠的工具。 ### 回答2: 正点原子Linux开发板PCB是一种基于Linux操作系统的嵌入式开发板,具有高性能、低功耗和可扩展性等特点。它适用于物联网、智能家居、工业自动化等领域的应用开发。 这款PCB板具有丰富的硬件资源,包括处理器、内存、存储、网络接口、UART、GPIO等,可以满足各种应用的需求。其主要的处理器架构是ARM,支持各种型号的ARM处理器,如ARM Cortex-A7、Cortex-A9等。内存容量通常为1GB或2GB,存储空间可以通过SD卡或者eMMC进行扩展。 正点原子Linux开发板PCB提供了完整的软件开发环境,支持各种主流的开发工具,如GCC、Make、Python等。它的操作系统基于Linux内核,提供了丰富的Linux驱动,方便开发者进行系统调试和应用开发。 这款开发板还支持多种外设接口,如以太网口、USB接口、HDMI等,可以连接各种外部设备和传感器,实现与外界的数据交互。同时,它还支持无线通信,如WiFi、蓝牙等,方便应用开发者实现无线连接和控制。 由于正点原子Linux开发板PCB具有模块化设计,其底板与核心板分离,开发者可以根据需求选择不同规格的底板和核心板组合,实现快速开发和产品迭代。此外,它还提供了丰富的开发文档和示例代码,方便开发者进行学习和参考。 总之,正点原子Linux开发板PCB是一款功能强大、易于开发和定制化的嵌入式开发板,适用于各种应用场景的嵌入式系统开发。 ### 回答3: 正点原子Linux开发板PCB是一款全球领先的开发板,其PCB设计采用了先进的技术和工艺,具有高度的可靠性和稳定性。该开发板搭载了Linux操作系统,为使用者提供了丰富的开发资源和工具,使得开发者可以快速进行应用开发和系统优化。 正点原子Linux开发板PCB设计考虑了多个因素,包括电路布局、分离地平面、电源管理等,确保了每个电路模块之间的电气隔离和优化布局。该开发板还配备了高性能的处理器,能够实现快速的数据处理和计算能力。 正点原子Linux开发板PCB上的电路连接点和接口丰富多样,支持各种外设和传感器的连接,方便用户进行模块化的扩展和定制。同时,该开发板还提供了丰富的软件开发包和驱动程序,使得开发者可以快速进行软件开发和系统调试。 正点原子Linux开发板PCB还具有低功耗和节能特性,能够有效降低系统的能耗。此外,该开发板还具备丰富的通信接口和网络连接功能,可以方便地与其他设备进行数据交互和远程控制。 综上所述,正点原子Linux开发板PCB是一款强大而可靠的开发板,适用于各种嵌入式系统开发和物联网应用场景。无论是初学者还是专业开发者,都可以通过该开发板进行快速、高效的应用开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值