数码之家

 找回密码
 立即注册
搜索
查看: 6115|回复: 50

[C51] 硬件SPI驱动TM1640

[复制链接]
发表于 2023-5-7 17:38:22 | 显示全部楼层 |阅读模式
TM1640 是一种LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 驱动等电路。本产品性能优良,质量可靠。主要应用于电子产品LED显示屏驱动。采用SOP28的封装形式。

本文仅以驱动TM1640为例,实际上,知道原理后,很容易扩展到其它类似芯片,如TM1668、TM1621等。

TM1640连续写时序如下图:



这个时序既不是I2C,也不是SPI,但是,一部分像I2C,有Start、Stop,一部分像SPI。
要实现这个控制时序,有2个要点:数据在时钟低电平时改变;时钟高电平时间至少维持1μS。控制这种芯片,一般做法是纯软件照时序图控制,但是,那样会消耗很多CPU时间。

对于有硬件SPI接口的芯片来说,只要简单变通一下,就可以用软硬结合的办法控制TM1640,大大减少CPU时间占用。

大部分芯片SPI时序图是这样,只需控制通讯速率就能满足TM1640控制时序。


不过,有的芯片SPI时序是这样,需要硬件上处理一下才能满足TM1640控制时序。


控制要点:
(1)确保数据在时钟低电平时改变数据,对于那些SPI接口在时钟高电平时改变数据的芯片,在时钟线加RC积分电路把时钟上升沿推后,确保数据在时钟低电平时改变。


部分RC参数测试结果如下:


(2)初始化时不使能SPI,只需用一般GPIO方式控制MOSI和SCLK输出高电平。
(3)开始发送数据时,用一般GPIO方式控制MOSI和SCLK输出高电平输出一个启动信号(MOSI输出电平一会后SCLK输出低电平)。
(4)SPI接口初始化配置为:先发送数据低位、CPOL=0、CPHA=1(空闲时时钟=低电平,数据在第二个边沿采样),使能SPI,使能SPI中断(数据量不多,DMA意义不大),发送Command1:设置数据。
(5)在SPI中断服务程序中禁用SPI,用一般GPIO方式控制MOSI和SCLK输出一个停止信号和一个启动信号,然后使能SPI,发送Command2:设置地址。
(6)中断方式继续发送数据直到显示数据发送完成。
(7)最后一个字节显示数据发送完成后的SPI中断禁用SPI,用一般GPIO方式控制MOSI和SCLK输出一个停止信号和一个启动信号,然后使能SPI,发送Command3:控制显示。
(8)发送Command3后的SPI中断禁用SPI,用一般GPIO方式控制MOSI和SCLK输出一个停止信号,一次显示数据输出完成。

上述处理信号时序如下:


实际信号如下:


扩展应用
对像TM1668那样多了STB通讯线的芯片,只需在输出STB信号的地方禁用SPI,输出STB信号,然后使能SPI继续通讯即可。


对需要一个前导位+8数据位的SPI通讯,只需禁用SPI,输出前导位,然后再使能SPI发送8位数据即可。


22楼更新代码:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 6家元 +130 收起 理由
vip2128 + 30 優秀文章
jf201006 + 20 謝謝分享
hongo + 20 原創內容
cushion + 20 優秀文章
aping365 + 20 優秀文章
慕名而来 + 20 優秀文章

查看全部打赏

 楼主| 发表于 2023-5-7 22:20:34 来自手机浏览器 | 显示全部楼层
慕名而来 发表于 2023-5-7 21:04
楼主你好,关于本帖中的最后一个时序图片的实现,我曾经也想利用I/O模拟发送D/CX加硬件SPI的方式实现,但是 ...

如果要控制的设备也是SPI接口只是多一位数据的话,是不需要加RC延时的,只需程序上加一位数据即可。我手上没有需要9位格式的通讯的芯片,有空我写一段你试下能不能用。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-8 01:43:33 来自手机浏览器 | 显示全部楼层
inthsunshine 发表于 2023-5-7 23:27
其实还是io模拟更好,类似i2c, 这种读写数据量很小,也只有键盘扫描或者显示更新才会运行,基本不消耗什么 ...

本文只是一种方法来讲,当SPI接口紧缺而且有更重要的用途,当然要取舍,如果空闲,为什么不用呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-8 01:54:38 来自手机浏览器 | 显示全部楼层
595953427@qq 发表于 2023-5-8 00:15
反复看了这个帖子,一直不明白用硬件SPI驱动TM1640的意义是什么,TM1640的数据量不大,对速度要求不高,任 ...

我个人的习惯是,能用硬件接口通讯就不用软件模拟,就这个TM1640来说,刚开始不加RC电路之前无法点亮,已用软件模拟方式点亮了,但这不是我想要的,于是,想出了这种方法。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-8 10:00:21 来自手机浏览器 | 显示全部楼层
本帖最后由 mmxx2015 于 2023-5-8 10:01 编辑
inthsunshine 发表于 2023-5-8 09:38
不过从你的操作过程看,远比io模拟更复杂, 一会开中断一会关中断;IO模式一会复用,一会通用,硬件上还 ...


不用关中断啊,只需在中断中禁用SPI,发完stop、start再使能SPI。
RC的值是可以大概计算的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-9 01:00:34 | 显示全部楼层
本帖最后由 mmxx2015 于 2023-5-9 01:03 编辑
慕名而来 发表于 2023-5-8 11:11
多谢,期待看到你的代码,其实我的这个三线spi屏也已经驱动成功很久了,现在使用中的是通过可寻址位变量 ...

显示驱动芯片如果是ILI9481,时序要求如下:

时钟电平、高电平最窄分别为40nS,最多时钟周期=100nS。
以STC8H8K64U来说,主频=22.1184MHz时,你这段程序输出信号大致如下图:

时钟低电平宽度不够40nS,需插入延时。
查看反汇编指令,时钟低电平只维持一个系统时钟,对照指令表,以主频=22.1184MHz计算,时间=(1/22.1184MHz)≈45nS,比较临界。

插入延时后的程序(需包含intrins.h):

  1. #define        SCL_LOW_DELAY()                NOP1()
  2. #define        SCL_HIGH_DELAY()        //NOP2()

  3. void write_data(unsigned char dat)
  4. {
  5.         bitdata=dat;
  6.         
  7.         sda=1;
  8.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();        //D/C=1写数据
  9.         sda=bit7;
  10.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  11.         sda=bit6;
  12.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  13.         sda=bit5;
  14.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  15.         sda=bit4;
  16.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  17.         sda=bit3;
  18.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  19.         sda=bit2;
  20.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  21.         sda=bit1;
  22.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  23.         sda=bit0;
  24.         scl=0;SCL_LOW_DELAY();scl=1;SCL_HIGH_DELAY();
  25. }
复制代码
插入延时后的信号


由于带宽的原因,我这个逻辑分析仪无法采集主频=48MHz时的I/O翻转信号,测试主频=40MHz时,I/O翻转速度可以测到但可能不是很准。


主频=48MHz时,指令周期=(1/48MHz)=20.8nS,时钟低电平之后需插入约2个NOP。
  1. #define        SCL_LOW_DELAY()                NOP2()
  2. #define        SCL_HIGH_DELAY()        //NOP2()
复制代码
插入2个NOP后的信号,这样的信号应该能正常通讯了,如果不行,改为3~4个NOP。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-9 09:24:37 来自手机浏览器 | 显示全部楼层
慕名而来 发表于 2023-5-9 09:20
我玩的正是这个9481的TFT屏,第一次学到时序模拟如此清晰明了,其实我也有一个简易的逻辑分析仪,带宽只 ...


测量开关信号,至少需要10倍待测信号频率的带宽,采样频率也要尽量高,不然,要么采不到或者信号宽度误差大。
协议分析是厂家配的软件提供的功能,当然了,也可以自己解析。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-9 10:48:13 来自手机浏览器 | 显示全部楼层
o535913 发表于 2023-5-9 10:21
你们不停的用同一句话回复楼主有意思吗, 别人说的话再复制重复一遍为了M币?

我比较好奇的是为什么不直接做 ...


据说做成I2C接口需要交版权费,I2C接口的版权在NXP手里,不知道SPI是不是要交钱。这种显示芯片通讯协议确实不伦不类。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-17 02:39:06 | 显示全部楼层
慕名而来 发表于 2023-5-8 11:11
多谢,期待看到你的代码,其实我的这个三线spi屏也已经驱动成功很久了,现在使用中的是通过可寻址位变量 ...

基于STC8H8K64U的ILI9481 9bit SPI驱动测试程序,试试看能不能用。


随便发送一些数据、随便指定D/CX信号的时序:




查看开头几个字节的信号,应该是符合ILI9481 9bit SPI时序。


这是完整工程,如果移植到其它程序,只需把spi.c、spi.h复制到目标工程中,按需配置引脚即可。

程序把命令和数据混合的表格逐个发送,使用的是一般指针,表格可以是常数表格,也可以是一段RAM。如果不习惯使用指针,可以按数组方式使用:去掉函数
  1. void SPI_Send_Bytes(INT8U *Source_Pointer,INT16U Send_Bytes)
复制代码
的指针,变成
  1. void SPI_Send_Bytes(INT16U Send_Bytes)
复制代码
调用是只需传递发送字节数即可。
SPI_Send_Bytes()和SPI中断中的装载数据变成:
  1. SPDAT=Display_Test_Table[s_spi_send_count];        //发送一个字节
复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-23 09:05:37 来自手机浏览器 | 显示全部楼层
tomyluo 发表于 2023-5-23 08:42
有没有办法可以不用RC延迟,用其他的芯片实现延迟?RC延迟波形会变差

如果SPI硬件设计成时钟下降沿一会再改变MOSI、时钟高电平保持MOSI状态就可以,但SPI时序上只要求采样沿MOSI输出目标数据,不一定能满足。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-23 11:12:51 来自手机浏览器 | 显示全部楼层
sunnyquan 发表于 2023-5-23 10:54
试试这个芯片IS31FL3743B

其实,用TM1640只是因为之前别人说用这种芯片驱动数码管对收音机模块有干扰,我告诉别人通讯线加RC、SEG串电阻可改善,想实际验证一下是不是真可以改善。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-6-9 06:28 , Processed in 0.156000 second(s), 14 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表