当前位置: 首页 > news >正文

[RK3566-Android11] 使用SPI方式点LED灯带-JE2815/WS2812,实现呼吸/渐变/随音量变化等效果

问题描述

之前写了一篇使用GPIO方式点亮LED灯带的文章
https://blog.csdn.net/jay547063443/article/details/134688745?fromshare=blogdetail&sharetype=blogdetail&sharerId=134688745&sharerefer=PC&sharesource=jay547063443&sharefrom=from_link
使用GPIO有一个问题是,在系统开机或者内存占用过大时,在做呼吸灯这种颜色变化较快的效果时,会出现显示乱颜色,或者显示的颜色不准确的问题。这还是由于内存占用高时操作GPIO控制纳秒级的高低电平宽度时会导致延时高,导致乱色。RK在RK3308_Linux_PartyBox_SDK音频方案点亮灯带使用的是SPI的方式。但这部分代码未开放,只知道原理是使用spi data模拟输出,调整好clk频率,用0和1去控制输出高低电平的宽度。使用SPI的好处是,类似PWM可以发送持续稳定的波形,可以更精确的控制纳秒级的高低电平。
下图为成品图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在附上一个呼吸灯效果视频:

led


解决方案:

1…config打开SPI配置:

# CONFIG_SPI_PXA2XX is not set
+CONFIG_SPI_ROCKCHIP=y
+CONFIG_SPI_ROCKCHIP_TEST=y
# CONFIG_SPI_SC18IS602 is not set

2.dts配置spi具体使用哪个可以根据自己的原理图配置

&spi0 {status = "okay";// max-freq = <48000000>; // 默认不用配置,SPI 设备工作时钟值,io 时钟由工作时钟分频获取// assigned-clock-rates = <200000000>; // 使能DMA模式,通讯长度少于32字节不建议用,置空赋值去掉使能,如 "dma-names;";// dma-names = "tx","rx";// 默认不用配置,读采样延时,详细参考 “常见问题”“延时采样时钟配置方案” 章节// rx-sample-delay-ns = <10>; spi_test@00 {compatible ="rockchip,spi_test_bus1_cs0";// 片选0或者1reg = <0>;id = <0>;// 不配置则为 0,配置为1// spi-cpol;// 不配置则为 0,配置为1// spi-cpha;// IO 先传输 lsb// spi-lsb-first;// spi clk输出的时钟频率,不超过50Mspi-max-frequency = <1000000>;};
};

3.配置spi-gpio口,以spi0为例子:
这些都是RK默认的配置

	spi0: spi@fe610000 {compatible = "rockchip,rk3066-spi";reg = <0x0 0xfe610000 0x0 0x1000>;interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;#address-cells = <1>;#size-cells = <0>;clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>;clock-names = "spiclk", "apb_pclk";dmas = <&dmac0 20>, <&dmac0 21>;dma-names = "tx", "rx";pinctrl-names = "default", "high_speed";pinctrl-0 = <&spi0m0_cs0 &spi0m0_cs1 &spi0m0_pins>;pinctrl-1 = <&spi0m0_cs0 &spi0m0_cs1 &spi0m0_pins_hs>;status = "disabled";};

4.修改rkxxxx-pinctrl.dtsi里的spi0m0_pins和spi0m0_pins_hs改为我们需要控制的口

		/omit-if-no-ref/spi0m0_pins: spi0m0-pins {rockchip,pins =/* spi0_clkm0 */<0 RK_PB5 2 &pcfg_pull_none>,/* spi0_misom0 */<0 RK_PC5 2 &pcfg_pull_none>,/* spi0_mosim0 */<0 RK_PB6 2 &pcfg_pull_none>;};spi0m0_pins_hs: spi0m0-pins {rockchip,pins =/* spi0_clkm0 */<0 RK_PB5 2 &pcfg_pull_up_drv_level_1>,/* spi0_misom0 */<0 RK_PC5 2 &pcfg_pull_up_drv_level_1>,/* spi0_mosim0 */<0 RK_PB6 2 &pcfg_pull_up_drv_level_1>;};

将spi0_mosim0 改为自己需要控制的GPIO口,可以配置上spi0_clkm0便于使用逻辑分析仪抓取发送的数据结果,spi0_misom0/cs0/csi都不用管他。检查GPIO不要出现复用的情况。

5.spi-test驱动kernel\drivers\spi\spi-rockchip-test.c
查看spi_test_write函数,可以看到RK开放了操作节点便于操作

		printk("echo id number size > /dev/spi_misc_test\n");printk("echo write 0 10 255 > /dev/spi_misc_test\n");printk("echo write 0 10 255 init.rc > /dev/spi_misc_test\n");printk("echo read 0 10 255 > /dev/spi_misc_test\n");printk("echo loop 0 10 255 > /dev/spi_misc_test\n");printk("echo setspeed 0 1000000 > /dev/spi_misc_test\n");printk("echo config 8 > /dev/spi_misc_test\n");

这里我们主要看write部分的逻辑:

	} else if (!strcmp(cmd, "write")) {char name[64];int fd;mm_segment_t old_fs = get_fs();sscanf(argv[0], "%d", &id);sscanf(argv[1], "%d", &times);sscanf(argv[2], "%d", &size);if (argc > 3) {sscanf(argv[3], "%s", name);set_fs(KERNEL_DS);}txbuf = kzalloc(size, GFP_KERNEL);if (!txbuf) {printk("spi write alloc buf size %d fail\n", size);return n;}if (argc > 3) {fd = ksys_open(name, O_RDONLY, 0);if (fd < 0) {printk("open %s fail\n", name);} else {ksys_read(fd, (char __user *)txbuf, size);ksys_close(fd);}set_fs(old_fs);} else {for (i = 0; i < size; i++){txbuf[i] = i % 256;}printk(" txbuf %d \n", i);}start_time = ktime_get();for (i = 0; i < times; i++)spi_write_slt(id, txbuf, size);end_time = ktime_get();cost_time = ktime_sub(end_time, start_time);us = ktime_to_us(cost_time);bytes = size * times * 1;bytes = bytes * 1000 / us;printk("spi write %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes);kfree(txbuf);

按照文档说明 echo 类型 id 循环次数 传输长度>/dev/spi_misc_test
从函数逻辑可以看到,经由echo write 0 10 255 > /dev/spi_misc_test的第三个参数传输长度,在不带文件名的情况时,走

			for (i = 0; i < size; i++){txbuf[i] = i % 256;}

根据输入的第三个参数传输长度,会取低八位连续发送。一个字节是8位。

5.我们来看一下RGB色的转换逻辑,以255,0,0为例子如下图:
在这里插入图片描述
原理类似于我们拼接波形,255 0 0转化为二进制为
1111 1111 0000 0000 0000 0000,也就是
cc cc cc cc 88 88 88 88 88 88 88 88。
204 204 204 204 136 136 136 136 136 136 136 136
也就是说用

			for (i = 0; i < size; i++){txbuf[i] = i % 256;}

取低八位的逻辑需要发出。
205 205 205 205 137 137 137 137 137 137 137 137。

6.由于不可知原因,附上简单版关键代码逻辑:

	} else if (!strcmp(cmd, "rgb")) {......offset = 0;for (repeat = 0; repeat < 15; repeat++) { // 外层循环,重复15次for (i = 0; i < 12; i++) {txbuf[i] = kzalloc(size[i], GFP_KERNEL);if (!txbuf[i]) {printk("Wi:spi write alloc buf size %d fail\n", size[i]);kfree(full_txbuf);return -1;}// 填充当前缓冲区for (j = 0; j < size[i]; j++) {txbuf[i][j] = j % 256; // 根据需求填充}printk("Wi:txbuf[%d] filled, size %d\n", i, size[i]);// 获取当前缓冲区的最后一个字节,并填充到合并缓冲区full_txbuf[offset] = txbuf[i][size[i] - 1];offset++;}}// 记录开始时间start_time = ktime_get();// 发送合并后的缓冲区for (j = 0; j < times; j++) {spi_write_slt(id, full_txbuf, total_size); // 发送所有数据}......

额外填入12组参数,取低八位的最后一个,循环15次填入buf。最后由spi_write_slt发出。
这里的repeat < 15,就是指灯珠数,一条灯带是15颗灯。
spi-max-frequency = <3300000>;
如下命令:
echo rgb 0 1 205 205 205 205 137 137 137 137 137 137 137 137 > /dev/spi_misc_test关闭灯光
echo rgb 0 1 137 205 137 205 137 205 137 205 137 205 137 205 > /dev/spi_misc_test调整红光亮度
echo rgb 0 1 205 205 205 205 137 137 137 137 137 137 137 137 > /dev/spi_misc_test为红光
echo rgb 0 1 137 137 137 137 205 205 205 205 137 137 137 137 > /dev/spi_misc_test为绿光
echo rgb 0 1 137 137 137 137 137 137 137 137 205 205 205 205 > /dev/spi_misc_test为蓝光

7.知道原理其实代码很好写,比如取低八位可以改成取低4位。又或者直接写入
echo rgb 0 1 15 255 0 0 > /dev/spi_misc_test。RGB色,将255 0 0自己在代码里面做逻辑转换。
可玩性很高,你可以控制某一颗灯的颜色,又或者做呼吸灯效果/渐变效果/网上的随音量大小或者音乐律动变化的效果等等。

相关文章:

[RK3566-Android11] 使用SPI方式点LED灯带-JE2815/WS2812,实现呼吸/渐变/随音量变化等效果

问题描述 之前写了一篇使用GPIO方式点亮LED灯带的文章 https://blog.csdn.net/jay547063443/article/details/134688745?fromshareblogdetail&sharetypeblogdetail&sharerId134688745&sharereferPC&sharesourcejay547063443&sharefromfrom_link 使用GPIO…...

PostgreSQL用load语句加载插件

文章目录 1. LOAD 语法2. 用途3. 示例4. 注意事项5. 其他相关命令6. 总结 在 PostgreSQL 中&#xff0c;LOAD 主要用于加载共享库&#xff0c;通常用于扩展功能或性能优化。以下是一些有关 LOAD 语句和 PostgreSQL 中的加载操作的关键信息&#xff1a; 1. LOAD 语法 LOAD 语句…...

一文了解:增强图像搜索之图像嵌入

图像嵌入在现代计算机视觉领域扮演着明星角色&#xff0c;它使得计算机能够像人类一样识别出各种各样的图像。由于计算机只能处理数字信息&#xff0c;我们需要将图像转换成数字向量&#xff0c;并存储在向量数据库中&#xff0c;这样就能迅速地检索到它们。 谈到嵌入技术&…...

yolov9目标检测/分割预测报错AttributeError: ‘list‘ object has no attribute ‘device‘常见汇总

这篇文章主要是对yolov9目标检测和目标分割预测测试时的报错&#xff0c;进行解决方案。 在说明解决方案前&#xff0c;严重投诉、吐槽一些博主发的一些文章&#xff0c;压根没用的解决方法&#xff0c;也不知道他们从哪里抄的&#xff0c;误人子弟、浪费时间。 我在解决前&…...

格姗知识圈博客网站开源了!

格姗知识圈博客 一个基于 Spring Boot、Spring Security、Vue3、Element Plus 的前后端分离的博客网站&#xff01;本项目基本上是小格子一个人开发&#xff0c;由于工作和个人能力原因&#xff0c;部分技术都是边学习边开发&#xff0c;特别是前端&#xff08;工作中是后端开…...

【C++】深入理解C++中的类型推导:从auto到decltype的应用与实践

C11引入了类型推导特性&#xff0c;旨在简化代码并提升开发效率。类型推导使开发者无需显式指定变量的类型&#xff0c;从而让代码更具可读性和灵活性。本文深入探讨了C11引入的auto、decltype和decltype(auto)等关键特性&#xff0c;通过分析其背后的设计理念、实际应用场景&a…...

使用Prometheus对微服务性能自定义指标监控

背景 随着云计算和容器化技术的不断发展&#xff0c;微服务架构逐渐成为现代软件开发的主流趋势。微服务架构将大型应用程序拆分成多个小型、独立的服务&#xff0c;每个服务都可以独立开发、部署和扩展。这种架构模式提高了系统的可伸缩性、灵活性和可靠性&#xff0c;但同时…...

深入解析 Lombok 的实现原理:以 @Builder 为例的实战演示(三)

文章目录 Lombok 的实现原理概述以 Builder 为例&#xff1a;解析 Lombok 如何生成 Builder 模式示例代码&#xff1a;没有 Lombok 的 Builder 模式使用 Lombok 的 Builder 简化代码 Lombok 如何实现 Builder&#xff1a;源码解析案例演示&#xff1a;自定义构造逻辑Lombok 的代…...

SEO基础:什么是SERP?【百度SEO专家】

SEO基础&#xff1a;什么是SERP&#xff1f; 大家好&#xff0c;我是林汉文&#xff08;百度SEO专家&#xff09;&#xff0c;在进行SEO&#xff08;搜索引擎优化&#xff09;时&#xff0c;理解SERP是一个非常重要的基础概念。那么&#xff0c;究竟什么是SERP呢&#xff1f;本…...

HTML5教程(一)- 网页与开发工具

1. 什么是网页 网页 基于浏览器阅读的应用程序&#xff0c;是数据&#xff08;文本、图像、视频、声音、链接等&#xff09;展示的载体常见的是以 .html 或 .htm 结尾的文件 网站 使用 HTML 等制作的用于展示特定内容相关的网页集合。 2. 网页的组成 浏览器 代替用户向服务…...

Java进阶篇设计模式之二 ----- 工厂模式

前言 在上一篇中我们学习了单例模式&#xff0c;介绍了单例模式创建的几种方法以及最优的方法。本篇则介绍设计模式中的工厂模式&#xff0c;主要分为简单工厂模式、工厂方法和抽象工厂模式。 简单工厂模式 简单工厂模式是属于创建型模式&#xff0c;又叫做静态工厂方法模式。…...

考研篇——数据结构王道3.2.2_队列的顺序实现

目录 1.实现方式说明2.代码实现2.12.1.1 代码12.1.2 代码22.1.3 代码3 2.22.2.1 代码42.2.5 代码52.2.6 代码6 总结 1.实现方式说明 多在选择题中考察 队尾指针&#xff08;rear&#xff09;有两种指向方式&#xff1a; 队尾指针指向队尾元素的位置&#xff0c;队尾指针指向…...

从零开始理解 Trie 树:高效字符串存储与查找的利器【自动补全、拼写检查】

题目分析 这道题让我们实现一个 Trie 类&#xff08;也称为前缀树&#xff09;&#xff0c;以便高效地插入和查询字符串。前缀树是一种特殊的树形数据结构&#xff0c;适用于快速存储和检索字符串数据集中的键&#xff0c;比如实现 自动补全 和 拼写检查。 题目要求 Trie 类…...

关于sse、websocket与流式渲染

一、SSE是什么&#xff1f; 网络中的 SSE (Server-Sent Events) 是一种服务器向浏览器单向推送数据的机制&#xff0c;常用于需要实时更新的数据传输&#xff0c;如新闻推送、股票行情、聊天应用等。 SSE 的特点&#xff1a; 单向通信&#xff1a;服务器向客户端推送数据&…...

Python 语法与数据类型详解

Python 语法与数据类型详解 Python 以其简洁易读的语法和丰富多样的数据类型在编程领域占据重要地位。深入理解 Python 的语法和数据类型是掌握这门语言的关键。 一、Python 语法概述 &#xff08;一&#xff09;缩进规则 Python 独特的缩进规则是其语法的重要特征之一。与…...

LeetCode题练习与总结:扁平化嵌套列表迭代器--341

一、题目描述 给你一个嵌套的整数列表 nestedList 。每个元素要么是一个整数&#xff0c;要么是一个列表&#xff1b;该列表的元素也可能是整数或者是其他列表。请你实现一个迭代器将其扁平化&#xff0c;使之能够遍历这个列表中的所有整数。 实现扁平迭代器类 NestedIterato…...

51单片机快速入门之 AD(模数) DA(数模) 转换 2024/10/25

51单片机快速入门之 AD(模数) DA(数模) 转换 2024/10/25 声明:本文图片来源于网络 A模拟信号特点: 电压或者电流 缓慢上升 随着时间连续缓慢上升或下降 D数字信号特点:电压或者电流 保持一段时间的高/低电平 状态 / 突变 (高电压瞬间低电压) 数字电路中 通常将0-1v电压称…...

Typora 、 Minio and PicGo 图床搭建

流程介绍 本地安装Typora笔记工具拥有一台装有docker的服务器配置minio云图床管理控制页面下载PicGo上传工具服务器Docker环境搭建—Ubuntu系统 删除旧docker的所有依赖(非root用户) # 删除docker及安装时自动安装的所有包 sudo apt-get autoremove docker docker-ce docker…...

【计网】UDP Echo Server与Client实战:从零开始构建简单通信回显程序

目录 前言&#xff1a; 1.实现udpserver类 1.1.创建udp socket 套接字 --- 必须要做的 socket&#xff08;&#xff09;讲解 代码实现&#xff1a;​编辑 代码讲解&#xff1a; 1.2.填充sockaddr_in结构 代码实现&#xff1a; 代码解析&#xff1a; 1.3.bind sockfd和…...

微服务网关Zuul

一、Zuul简介 Zuul是Netflix开源的微服务网关&#xff0c;包含对请求的路由和过滤两个主要功能。 1&#xff09;路由功能&#xff1a;负责将外部请求转发到具体的微服务实例上&#xff0c;是实现外部访问统一入口的基础。 2&#xff09;过滤功能&#xff1a;负责对请求的过程…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...