基于S32K144实现TPS929120的基本控制功能

news2025/7/17 16:06:54

文章目录

    • 前言
    • 1.TPS92910简介
    • 2.硬件调试平台
      • 2.1 灯板原理图
      • 2.2 参考电流
      • 2.3 器件地址
    • 3.TPS929120通信协议
      • 3.1 物理层
      • 3.2 数据链路层
      • 3.3 传输层
        • 2.3.1 读写时序
        • 2.3.2 帧格式说明
        • 2.3.3 寄存器lock与unlock
        • 2.3.4 输出通道控制
    • 4.使用S32K144驱动TPS92910
      • 4.1 实现命令帧格式
        • 4.1.1 写寄存器的帧格式
        • 4.1.1 读寄存器的帧格式
      • 4.2 实现Uart串口收发
      • 4.3 实现基本的控制功能
      • 4.3.1 操作TPS92910的基本函数
      • 4.3.1 TPS929120控制流程
    • 5.参考资料

前言

最近拜访一些车灯客户时,发现使用最多的多通道LED Driver是TI的TPS929120,恰好我们代理的国产线正在做对标TPS929120的产品。为了方便后面的车灯方案推广,笔者和同事参考TI官网的资料,做了一套TPS929120的demo板,同时主控MCU采用了现在最火的车规通用MCU–S32K144,并配套编写了简单的软件demo。
如下是笔者学习TPS929120时整理的内容,希望对需要快速熟悉TPS929120的读者有所帮助。

1.TPS92910简介

TPS929120是TI公司在2019年4月份发布的具有FlexWire接口的12通道汽车级40V高边LED驱动芯片,其主要特点如下:

  • 12路高边精确电流输出通道
    • 供电电压4.5V到40V
    • 电阻预设电流最高到75mA
    • 2bit全局的,6bit独立的电流设置
    • 输出电流在5mA到75mA时,精度可达±5%
    • 输出电流在1mA时,精度为±10%
    • 输出电流50mA时的压降为0.5V
    • 12bit独立PWM调光
    • 可编程的PWM频率最高可达20kHz
    • 支持线性和指数两种调光方式
  • FlexWire控制接口
    • 最高1MHz的时钟频率
    • FlexWire总线最多可挂16个器件
    • 一帧命令最多可以传输8字节的寄存器数据
    • 内部集成5V LDO可以给CAN收发器供电
  • 诊断和保护功能
    • 可编程的fail-safe状态
    • LED开路检测
    • LED短路检测
    • 单颗LED短路诊断
    • 可编程的欠压检测
    • 开漏模式的ERR引脚,可以通知主机是否发生故障
    • 用于判断FlexWire通信是否正常的看门狗和CRC校验
    • 用于引脚电压测量的8bit的ADC
    • 过温保护

2.硬件调试平台

笔者用来调试TPS929120所制作的DEMO板,整体框图如下:

DEMO板分为驱动板和灯板两部分,接近客户的实际使用情况。其中,

  • 驱动板上面主要是给灯板供电的DCDC,给S32K和TJA1044供电的LDO;
  • 灯板上面主要是灯驱TPS929120和LED灯驱;
  • 驱动板和灯板之间通过差分总线进行通信,抗干扰能力相比传统的I2C,SPI提高很多;
  • 由于给灯板供电只有6.5V,所以TPS929120的整体功耗相比正常的12V供电系统能降低不少。

另外,该Demo板也预留了MCU的UART引脚作为测试点,方便查看S32K144和TPS929120的通信数据,从而在调试时更快的锁定问题。

2.1 灯板原理图

灯板原理图参考如下官方demo板进行设计:

2.2 参考电流

参考电流计算公式如下,其中Vref为1.235V(数据手册典型值),Kref默认值为512(可以通过修改寄存器CONF_MISC1中的CONF_REFRANGE进行调整)。

根据查表,此电路中TPS929120默认的参考电流为50mA(灯板上TPS929120贴的REF电阻为12.4K,计算值为51mA)。

2.3 器件地址

TPS929120可以使用外部地址,也可以使用内部EEPROM预烧写的地址,此次DEMO使用外部地址。两片TPS929120的ADDR0,ADDR1,ADDR2引脚电压分别为000,100;根据下面的器件地址设置表格可以知道(EEP_DEVADDR[3:0]的默认值为0000b),两片TPS929120的地址分别为0和1。

3.TPS929120通信协议

TPS929120使用的通信方式,TI称之为FlexWire,其实就是UART(数据链路层)+CAN物理层,然后在传输层增加一些自定义的帧格式,目前其他厂家新出的多通道LED Driver基本都是采用这种通信方式。

3.1 物理层

FlexWire的物理层使用CAN收发器,主要的作用就是将普通的串行信号转换成差分信号(时序图如下),比较常用的有TJA1044,TCAN1042等。

3.2 数据链路层

FlexWire的数据链路层使用的是UART通信,因为TPS929120内部的时钟最高为1MHz,为了通信稳定,所以MCU内部的UART配置的波特率为500K;其它配置为8bit数据位,无奇偶校验,1bit停止位。

3.3 传输层

2.3.1 读写时序

  • 主机向TPS929120写数据:

  • 主机从TPS929120读数据:

需要注意的是,如果加了CAN收发器,由于CAN收发器自带的回环功能,实际上主机也会收到他自身发的数据,所以实际主机收到的数据应该是自身发的数据+TPS929120响应的数据

当一次性写8个寄存器数据时,MCU的UART_RX收到的数据最多,为MCU发出的12字节+2字节

2.3.2 帧格式说明

  • 总体格式如下:

  • 其中DEV_ADDR的组成元素较多,如下所示,其他都是单一元素组成。

2.3.3 寄存器lock与unlock

配置其他寄存器之前需要先配置CONF_LOCK Register(61h)进行解锁,主要是如下四个4bit,这4个bit上电之后默认为1,处于lock状态,需要清0进行unlock。

这4个bit分别能够lock与unlock的寄存器如下图:

2.3.4 输出通道控制

  • CONF_EN0(50h),CONF_EN1(51h)分别控制通道0-7,8-11的使能;默认值为0h。

  • IOUT0(00h)到IOUT11(0Bh)分别通道0到11的电流,一共64-step,实际的通道输出电流的计算公式如下,其中此电路板的I(FULL_RANGE)为50mA;这些寄存器在reset之后加载对应的EEPROM中EEPIx寄存器的值,EEPIx默认为3Fh。

  • PWM0(20h)到PWM11(2Bh),PMWL0(40h)到PWML11(4Bh)都是控制通道0到11的PWM占空比,前者用于粗调,后者用于微调,计算公式如下;前者在reset之后加载对应的EEPROM中EEPPx寄存器的值,为FFh,后者的默认值为Fh。

根据上面的分析,如果只配置通道使能,其他寄存器不设置,使能的通道会输出50mA的电流。

TPS929120在配置通道使能的情况下,即使配置PWM占空比为0,也会有微亮的情况。

4.使用S32K144驱动TPS92910

接下来,将基于S32K144介绍如何使用MCU驱动TPS929120,实现一些基本的灯光控制功能。

4.1 实现命令帧格式

4.1.1 写寄存器的帧格式

写寄存器的帧格式如2.3.2章节所述,先发SYNC(0x55),然后是DEV_ADDR(由4种元素组成),然后是REG_ADDR(数据手册种寄存器的地址),然后是DATA(要写入寄存器的数据),最后是CRC

整体实现代码如下:

void FlexWrite(uint8_t DEV_ADDR_x, uint8_t registerAddr, uint8_t DATA_BYTES[], uint8_t DATA_LENGTH_x, uint16_t checkResponse)
{
    uint8_t DEV_ADDR=0x00, REG_ADDR;
    uint8_t commandFrame[12] = {0};// one longest command frame length is 12
    uint8_t dataLength=0, frameLength=0, responseLength = 0;
    uint16_t i;

    DEV_ADDR = (FLEX_Write | DATA_LENGTH_x | DEV_ADDR_x);
    REG_ADDR = registerAddr;

    commandFrame[0] = 0x55; //SYNC byte
    commandFrame[1] = DEV_ADDR;
    commandFrame[2] = REG_ADDR;

    switch (DATA_LENGTH_x)
    {
    case 0:
        {
            dataLength = 1;
            break;
        }
    case 16:
        {
            dataLength = 2;
            break;
        }
    case 32:
        {
            dataLength = 4;
            break;
        }
    case 48:
        {
            dataLength = 8;
            break;
        }
    default : break;
    }

    for(i=0;i<dataLength;i++)
    {
        commandFrame[i+3] = DATA_BYTES[i];
    }

    commandFrame[i+3] = CRC_LUT(commandFrame+1,i+2); //calculate CRC of all the command frame bytes
    frameLength = i+4; //store the entire command frame byte length
    responseLength=frameLength+2;
    
    uartWrite(commandFrame, frameLength, checkResponse, responseLength); //data will be stored in responseData[]
}

有关TPS929120的CRC算法,可以参考之前的文章:

TPS929120的CRC校验的三种实现方法 (qq.com)

4.1.1 读寄存器的帧格式

读寄存器的帧格式和写寄存器的帧格式相近,这里就不赘述了。

4.2 实现Uart串口收发

硬件上使用LPUART1模块,引脚选择PTC8和PTC9,软件配置为波特率500K,8N1。同时,因为使用了CAN收发器,所以串口实际接收到的数据是发送的数据加上TPS929120响应的数据。

整体实现代码如下:

/*********************************************************************************************************
** Function name:       uartWrite
** Descriptions:        N/A
** input parameters:    N/A
** output parameters:   N/A
** Returned value:      N/A
*********************************************************************************************************/
void uartWrite(uint8_t commandFrame[], uint16_t frameLength, uint16_t checkResponse, uint16_t responseLength)
{
    uint8_t i =0;

    /* Enable  the receiver and receive data full interrupt of LPUART1*/
    LPUART_DRV_ReceiveData(INST_LPUART1, responseData, 1u);
    /* The function does not return until the transmit is complete or timeout(2ms) occured*/
    LPUART_DRV_SendDataBlocking(INST_LPUART1, commandFrame, frameLength, 2);
    if(checkResponse == TRUE)
    {
        /* launch timer and set wait time = 2000us
	       * This time should be larger than the time to receive all the response bytes,
	       * And the response receiving time depends on the buard rate and the number of response byte,
	       * For example, baurd rate = 500000, 2 response byte, so the wait time should be larger than 2*10*1/500000 = 40us
	       * Why 2*10 because for each byte there are additional 1 start bit and 1 stop bit
	       */
        timeOut(2000);
	
        /* received all response byte or the wait time exceeds the specified time */
        while(!((timeOutFlag == 1) || (receiveByteNum == responseLength)));

        /*Take some action when successfully received response*/
        if(receiveByteNum == responseLength)
        {
            /* Turn off Red LED and turn on Green LED*/
            PINS_DRV_WritePin(LED_PORT, RED_LED, 1);
            PINS_DRV_TogglePins(LED_PORT, 1<<GREEN_LED);
        }
        /* You can take some action once the response has not been received */
        else
        {
            /* Toggle Red LED and turn off Green LED */
            PINS_DRV_TogglePins(LED_PORT, 1<<RED_LED);
            PINS_DRV_WritePin(LED_PORT, GREEN_LED, 1);
        }

        /* Clear data sent */
        for(i=0; i<frameLength; i++)
        {
            commandFrame[i] = 0x00;
        }
        /* Clear response data*/
        for(i=0; i<responseLength; i++)
        {
            responseData[i] = 0x00;
        }
        /* reset number of response data*/
        receiveByteNum = 0;

        /* Disable the receiver and receive data full interrupt of LPUART1 */
        LPUART_DRV_AbortReceivingData(INST_LPUART1);
    }
}

/*********************************************************************************************************
** Function name:       Lpuart1RxCallback
** Descriptions:        N/A
** input parameters:    N/A
** output parameters:   N/A
** Returned value:      N/A
*********************************************************************************************************/
void Lpuart1RxCallback(void *driverState, uart_event_t event, void *userData)
{
    /* Unused parameters */
    (void)driverState;
    (void)userData;

    /* Check the event type */
    if (event == UART_EVENT_RX_FULL)
    {
        /* Update the buffer index and the rx buffer */
    	receiveByteNum++;
    	LPUART_DRV_SetRxBuffer(INST_LPUART1, &responseData[receiveByteNum], 1U);

    }
}

4.3 实现基本的控制功能

4.3.1 操作TPS92910的基本函数

实现写寄存器的函数之后,就可以基于该函数实现一些基本的操作TPS929120函数了,主要是如下几个:

如下代码中包含了很多寄存器的宏定义,没有进行展开,读者可以借助数据手册进行对比。

  1. unlock与lock寄存器的函数实现如下:

  2. 清除错误状态和标志的函数实现如下:

  3. 配置通道电流的函数实现如下:

  4. 打开通道的函数实现如下:

  5. 关闭通道的函数实现如下:

  6. 配置通道的PWM占空比的函数实现如下:

4.3.1 TPS929120控制流程

实现了上述基本控制函数之后,接下来就是控制TPS929120实现基本的灯效了。

首先需要对TPS92910进行初始化,主要流程参考如下代码:

然后就是在主循环中实现灯效,这里以呼吸效果为例,代码如下:

下面代码在测试TPS92910竞品更改过,PWM占空比为0时仍有漏电流的问题被修复了。如果驱动TPS929120,建议在PWM占空比到0时,增加关闭通道的操作。

5.参考资料

  • [FAQ] Design an Automotive Animation Lighting with TPS929120-Q1 within 5min - Power management forum - Power management - TI E2E support forums
  • 具有 FlexWire 接口的 TPS929120-Q1 12 通道汽车 40V 高侧 LED 驱动器 数据表 (Rev. B) (ti.com.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/17639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生】玩转Kubernetes实战(一):Pod、ConfigMap的使用

本文主要是利用Kubernetes 集群搭建出一个 WordPress 网站&#xff0c;用了三个镜像&#xff1a;WordPress、MariaDB、Nginx。 下面是其简单的架构图&#xff0c;用于直观的展示这个系统的内部逻辑关系&#xff1a; 简单来说&#xff0c;就是要通过本地地址http://127.0.0.1…

Spring AOP[详解]

一.需求引入 在开发过程中,总会有一些功能与业务逻辑代码耦合度不强(例如保存日志,提交事务,权限验证,异常处理),我们可以将这些代码提取到一个工具类中,需要使用时在调用工具类来实现. ​ 但是这样也会有弊端,那就是我们的代码已经开发完毕,后期如果需要增加公共功能就需要更…

Pinpoint--基础--03--安装部署

Pinpoint–基础–03–安装部署 前提 使用hd用户登陆 完成基础环境搭建https://blog.csdn.net/zhou920786312/article/details/118212302代码位置 https://gitee.com/DanShenGuiZu/learnDemo/tree/master/pinpoint-learn/demo11、安装环境准备 1.1、jdk1.8 基础环境搭建 包含…

一文搞懂MySQL表字段类型长度的含义

不知道大家第一眼看标题的时候有没有理解&#xff0c;什么是“字段类型长度”&#xff0c;这里我来解释下&#xff0c;就比如我们在MySQL建表的时候&#xff0c;比如下面这个建表语句&#xff1a; CREATE TABLE user (id int(10) DEFAULT NULL,name varchar(50) DEFAULT NULL,…

linux系统离线安装docker(分步法一键法)

1 前言 在有的项目场景中&#xff0c;服务器是不允许连接外网的。此时若想在服务器上安装部署docker容器&#xff0c;就不能采用在线方式了&#xff0c;不过可以采取离线方式进行安装。下面我们就一起看看离线安装的两种办法。 一种是分步安装法&#xff0c;一种是一键安装法…

Python冷知识:如何找出新版本增加或删除了哪些标准库?

“内置电池”是 Python 最为显著的特性之一&#xff0c;它提供了 200 多个开箱即用的标准库。但是&#xff0c;历经了 30 多年的发展&#xff0c;很多标准库已经成为了不得不舍弃的历史包袱&#xff0c;因为它们正在“漏电”&#xff01; 好消息是&#xff0c;Python 正在进行…

Pinpoint--基础--02--架构设计

Pinpoint–基础–02–架构设计 1、整体架构 1.1、Pinpoint Collector 数据收集模块&#xff0c;接收Agent发送过来的监控数据&#xff0c;并存储到HBase部署在 Web 容器上 1.2、Pinpoint Web 监控展示模块&#xff0c;展示系统调用关系、调用详情、应用状态等&#xff0c;并…

CleanMyMac磁盘空间内存瘦身清理软件使用教程

许多用着Mac系统电脑的朋友们总是卸载不干净电脑垃圾软件&#xff0c;想要把垃圾软件卸载干净&#xff0c;可以尝试使用苹果电脑清理软件CleanMyMac。 经典的电脑深度清理软件——CleanMyMac。由于苹果电脑硬盘售价高昂&#xff0c;且不可以自行安装内存&#xff0c;很多苹果用…

代码随想录day60|结束亦是开始|84.柱状图中最大的矩形|总结

代码随想录day60 来了老弟 84.柱状图中最大的矩形 思路 本题和42. 接雨水是遥相呼应的两道题目&#xff0c;建议都要仔细做一做&#xff0c;原理上有很多相同的地方&#xff0c;但细节上又有差异&#xff0c;更可以加深对单调栈的理解&#xff01;42. 接雨水 其实这两道题目先…

java 分布式游戏服务器框架,集群游戏服务器框架,游戏服务器网关框架 ioGame 网络游戏服务器框架

网络游戏框架简介 ioGame 是一个由 java 语言编写的网络游戏服务器框架。支持 websocket、tcp &#xff0c;适用于全球同服、回合制游戏、策略游戏、即时战斗等游戏服务器的开发。具有高性能、稳定、易用易扩展、超好编程体验等特点。可做为 H5、手游、端游的 java 游戏服务器…

Intel关NUMA的内存编址

最近在做某国产化平台相关的适配, 不管NUMA的性能和实现方式都和Intel有较大不同, 作为比较对象, 理解Intel的NUMA实现是很有必要的. 虽然从软件角度, 打开NUMA会带来额外的复杂度, 但是从硬件角度, 关闭NUMA其实更复杂, 本文尝试分析关闭NUMA时Intel平台的内存编址. Memory I…

java+springboot基于性别网上学习特征问卷调查及可视化系统

基于JSP技术、SSM框架、B/S机构、Mysql数据库设计并实现了性别网上学习特征及可视化。系统主要包括个人中心、用户管理、调查问卷管理、用户答卷管理、专家建议管理、学习攻略管理、我的收藏管理、爬虫管理、系统管理等功能模块。 (1)绪论 网站的开发背景&#xff0c;意义和系…

栈和队列(带图,有手就废)

文章目录1.栈1.1栈的概念与结构1.2栈的声明1.3动态栈的实现1.3.1初始化栈1.3.2入栈1.3.3出栈1.3.4获取栈顶元素1.3.5获取栈中元素个数1.3.6判断栈是否为空1.3.7销毁栈1.4栈的总结2.队列2.1队列的概念与结构2.2队列的声明2.3队列的实现2.3.1初始化队列2.3.2入队2.3.3出队2.3.4获…

BUUCTF web之WarmUp 源代码详解

目录 前言 PHP代码分析 关于../ 前言 访问除了一张滑稽图&#xff0c;就没其他的了 查看源码&#xff0c;有一个注释了的 source.php&#xff0c;可以尝试直接访问一下。同时进行目录扫描 访问source.php&#xff0c;里面包含php代码&#xff0c;题目说了是php代码审计&…

知识经验分享——YOLOv5-6.0训练出错及解决方法(RuntimeError)

>>>深度学习Tricks&#xff0c;第一时间送达<<< 目录 一、问题bug 二、解决方法 步骤1&#xff1a;打开utils/loss.py文件 步骤2&#xff1a;找到 for i in range(self.nl) 函数&#xff08;CtrlF&#xff09;&#xff0c;作以下替换&#xff1a; 步骤3…

VMware创建Win10操作系统虚拟机

VMware创建Win10操作系统虚拟机1. 安装VMware162. 下载Win10镜像3. 创建虚拟机4. 安装Win105. 安装VMware Tools工具1. 安装VMware16 迅雷云链接&#xff1a;https://pan.xunlei.com/s/VNH9mkbxLqnyB_F_g0h73C_TA1?pwdsdi4# 2. 下载Win10镜像 百度云链接&#xff1a;https:…

优雅的实现符合开闭原则的流水日志抽取demo

如何做出一个标准化记录流水日志(Demo) 昨天晚上 在b站刷到了 极海Channel 海哥的视频 也想去跟着实现一个,作为学习的demo,主要学习思路 可能存在的问题: 可能每一个需要收集的类里取参数的字段可能是不一样的如何去处理如何可以让他更好的作用于新的业务代码上 项目代码日志…

c++STL库

什么是STLSTL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。STL的版本原始版本Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本&#xff0c…

阿里首次公开企业级 SpringBoot 实战进阶笔记

Spring Boot 的重要性不需要我多说了吧&#xff0c;Java程序员们应该都懂&#xff0c;不仅面试会被提问&#xff0c;工作中也非常需要spring boot 不知道大家是如何学习Spring Boot的&#xff0c;据我所知&#xff0c;很多开发者会试着在网上找一些开源项目&#xff0c;通过阅…

马上2023了,云原生架构还不懂?阿里云原生架构笔记带你完全拿下

前言 软件架构发展至今&#xff0c;经历了从单体架构、垂直架构、SOA 架构到现在的以微服务、服务网格等云原生技术为主的演变过程&#xff0c;云原生技术发展势不可挡&#xff0c;老生常谈的“云原生”将依然会是未来的热门话题。而且随着数字化转型加速&#xff0c;企业对于…