EasyScale单总线数字调光

一、协议介绍

上篇文章【STM32】基于TPS61165芯片的LED驱动电路-CSDN博客介绍了TPS61165芯片的传统操作(PWM调光和高低电平点亮熄灭)。看到网友留言芯片还可以用单总线控制,便有了这篇文章。

芯片有2种调光模式,一种就是之前使用的PWM调光,还有一种叫做EasyScale 单总线数字调光。

芯片默认是PWM调光,要想进入单总线模式,需要在芯片从shutdown起来后执行以下3个步骤

对应的时序图如下

其中关键的时序参数如下表格所示

可以看出,逻辑0是长低+短高,逻辑1是短低+长高。下降沿开始,下降沿结束。

笔者设置逻辑0是300us的低电平+100us的高电平;逻辑1是100us的低电平+300us的高电平。

us延时函数

cpp 复制代码
#define CPU_FREQUENCY_MHZ 72 // STM32时钟主频
void delay_us(__IO uint32_t delay) {
   int last, curr, val;
   int temp;
   while (delay != 0) {
       temp = delay > 900 ? 900 : delay;
       last = SysTick->VAL;
       curr = last - CPU_FREQUENCY_MHZ * temp;
       if (curr >= 0) {
           do {
               val = SysTick->VAL;
           } while ((val < last) && (val >= curr));
       } else {
           curr += CPU_FREQUENCY_MHZ * 1000;
           do {
               val = SysTick->VAL;
           } while ((val <= last) || (val > curr));
       }
       delay -= temp;
   }
}

逻辑生成函数

cpp 复制代码
/* short:100us long:300us */
static void genLogic(uint8_t logic)
{
   if(logic == 0)
   {
      CTRL_LOW();
      delay_us(300);
      CTRL_HIGH();
      delay_us(100);
   }
   else if(logic == 1)
   {
      CTRL_LOW();
      delay_us(100);
      CTRL_HIGH();
      delay_us(300);
   }
   else
   {

   }
}

先拉低CTRL引脚至少2.5ms让芯片进入shutdown

cpp 复制代码
void LED_Shutdown()
{
   CTRL_LOW();
   HAL_Delay(3);
}

拉高CTRL,保持至少100us,再拉低至少260us,拉高CTRL。至此,芯片就成功进入单总线数字调光模式了。从CTRL被拉高开始,至少1ms后(检测延时>100us,检测时间>260us)再发送编程波形。笔者简化处理为CTRL拉高600us,CTRL拉低600us,再拉高

cpp 复制代码
void LED_Enter()
{
   CTRL_HIGH();
   delay_us(600);
   CTRL_LOW();
   delay_us(600);
   CTRL_HIGH();
}

一旦设置好亮度,就不能在线修改,需要将芯片先shutdown,唤醒后再发送数据调节亮度。

这里阐述了这个功能的应用场景:有时其实我们并不需要一直给芯片发PWM,可以让芯片通过单总线配置好亮度就进入空闲状态(低功耗/休眠)以节约能源消耗。

单总线数字调光是在总线上发送不同的数据来改变芯片反馈引脚的电压实现调光,有32个挡位,如下表格所示

二、协议实现

数据链路

有点类似I2C总线。地址固定为0x72。一帧信息为起始+设备地址+结束+起始+数据+结束。

发送字节前需要发送Start

cpp 复制代码
static void writeStart()
{
   CTRL_HIGH();
   delay_us(50);
}

发送数据

cpp 复制代码
static void writeData(uint8_t dat)
{
   for (uint8_t i = 0; i < 8; i++)
   {
      genLogic(((dat << i) & 0x80) == 0x80);
   }
}

发送完一个字节需要发送EOS

cpp 复制代码
static void writeEOS()
{
   CTRL_LOW();
   delay_us(50);
   CTRL_HIGH();
}

如果需要响应,切换IO模式

cpp 复制代码
static void changePinMode()
{
   GPIO_InitTypeDef GPIO_InitStruct = {0};

  /*Configure GPIO pin : CTRL_Pin */
  GPIO_InitStruct.Pin = CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(CTRL_GPIO_Port, &GPIO_InitStruct);
}

static void resumePinMode()
{
   GPIO_InitTypeDef GPIO_InitStruct = {0};

  /*Configure GPIO pin : CTRL_Pin */
  GPIO_InitStruct.Pin = CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(CTRL_GPIO_Port, &GPIO_InitStruct);
}

设置亮度函数

数据字节的最高位用于配置是否要芯片做出应答。

cpp 复制代码
HAL_StatusTypeDef LED_SetLight(uint8_t step)
{
   writeStart();
   writeData(0x72);
   writeEOS();

   writeStart();
#ifdef LED_ACK
   writeData(step | 0x80);
   writeEOS();
   changePinMode();
   if (HAL_GPIO_ReadPin(CTRL_GPIO_Port, CTRL_Pin) == GPIO_PIN_RESET)
   {
      resumePinMode();
      return HAL_OK;
   }
   else
   {
      resumePinMode();
      return HAL_ERROR;
   }
#else
   writeData(step);
   writeEOS();
   return HAL_OK;
#endif
}

无需响应的情形

发送完地址的最后一个bit,等待一段时间EOS(小于360us),拉高CTRL(Tstart),开始发送数据字节,发送完毕后等待EOS,总线常高。连接CTRL的单片机引脚配置推挽输出。

使用逻辑分析仪采集波形如下

需响应的情形

数据字节最高位是1,发送完数据字节,等待EOS时间,如果芯片应答,CTRL引脚会被芯片拉低一段时间tACK(<512us),需要在总线配置上拉电阻用于检测CTRL电平判断是否正确应答(拉低)。连接CTRL的单片机引脚配置开漏输出,并在CTRL引脚上拉电阻到3.3V。

发送完数据后,改成输入模式,此时如果芯片正确响应,会把CTRL拉低,让MCU检测到就可以。检测完毕,将GPIO再切换回开漏输出。使用逻辑分析仪采集波形如下

设置好亮度后MCU就可以进低功耗模式。主函数如下

cpp 复制代码
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int32_t light = 0;
uint8_t str[20];
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
   KeyDrv_Config();
   ST7789_Init();
   ST7789_Clear(BLACK);
   __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
   uint8_t re = 0;
   LED_Shutdown();
   LED_Enter();
   re = LED_SetLight(light % 32);
   
   sprintf(str, "light:%d %d  ", light % 32, re);
   ST7789_ShowString(0, 140, str, Font_16x26, ST7789_RGB565(0xFFFF), BLACK);
   
   light+=3;
   HAL_Delay(1000);

   if (light == 30)
   {
      sprintf(str, "in stop mode");
      ST7789_ShowString(0, 140, str, Font_16x26, ST7789_RGB565(0xFFFF), BLACK);
      HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFE);
   }
   
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

三、驱动附录

LED.c

cpp 复制代码
#include "LED.h"

#define CPU_FREQUENCY_MHZ 72 // STM32时钟主频
void delay_us(__IO uint32_t delay) {
   int last, curr, val;
   int temp;
   while (delay != 0) {
       temp = delay > 900 ? 900 : delay;
       last = SysTick->VAL;
       curr = last - CPU_FREQUENCY_MHZ * temp;
       if (curr >= 0) {
           do {
               val = SysTick->VAL;
           } while ((val < last) && (val >= curr));
       } else {
           curr += CPU_FREQUENCY_MHZ * 1000;
           do {
               val = SysTick->VAL;
           } while ((val <= last) || (val > curr));
       }
       delay -= temp;
   }
}


/* short:100us long:300us */
static void genLogic(uint8_t logic)
{
   if(logic == 0)
   {
      CTRL_LOW();
      delay_us(300);
      CTRL_HIGH();
      delay_us(100);
   }
   else if(logic == 1)
   {
      CTRL_LOW();
      delay_us(100);
      CTRL_HIGH();
      delay_us(300);
   }
   else
   {

   }
}

static void writeData(uint8_t dat)
{
   for (uint8_t i = 0; i < 8; i++)
   {
      genLogic(((dat << i) & 0x80) == 0x80);
   }
}


static void writeStart()
{
   CTRL_HIGH();
   delay_us(50);
}

static void changePinMode()
{
   GPIO_InitTypeDef GPIO_InitStruct = {0};

  /*Configure GPIO pin : CTRL_Pin */
  GPIO_InitStruct.Pin = CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(CTRL_GPIO_Port, &GPIO_InitStruct);
}

static void resumePinMode()
{
   GPIO_InitTypeDef GPIO_InitStruct = {0};

  /*Configure GPIO pin : CTRL_Pin */
  GPIO_InitStruct.Pin = CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(CTRL_GPIO_Port, &GPIO_InitStruct);
}

static void writeEOS()
{
   CTRL_LOW();
   delay_us(50);
   CTRL_HIGH();
}


HAL_StatusTypeDef LED_SetLight(uint8_t step)
{
   writeStart();
   writeData(0x72);
   writeEOS();

   writeStart();
#ifdef LED_ACK
   writeData(step | 0x80);
   writeEOS();
   changePinMode();
   if (HAL_GPIO_ReadPin(CTRL_GPIO_Port, CTRL_Pin) == GPIO_PIN_RESET)
   {
      resumePinMode();
      return HAL_OK;
   }
   else
   {
      resumePinMode();
      return HAL_ERROR;
   }
#else
   writeData(step);
   writeEOS();
   return HAL_OK;
#endif
}


void LED_Shutdown()
{
   CTRL_LOW();
   HAL_Delay(3);
}

void LED_Enter()
{
   CTRL_HIGH();
   delay_us(600);
   CTRL_LOW();
   delay_us(600);
   CTRL_HIGH();
}

LED.h

cpp 复制代码
#ifndef LED_H
#define LED_H

#include "GPIO.h"
#include "main.h"

// #define LED_ACK

#define CTRL_LOW()   HAL_GPIO_WritePin(CTRL_GPIO_Port, CTRL_Pin, GPIO_PIN_RESET)
#define CTRL_HIGH()   HAL_GPIO_WritePin(CTRL_GPIO_Port, CTRL_Pin, GPIO_PIN_SET)


HAL_StatusTypeDef LED_SetLight(uint8_t step);
void LED_Shutdown();
void LED_Enter();


#endif
相关推荐
电子工程师-C512 小时前
基于51单片机的环境监测及窗帘控制系统
单片机·嵌入式硬件·51单片机
ACP广源盛139246256732 小时前
GSV2231G@ACP#2231G产品规格详解及产品应用分享
嵌入式硬件·计算机外设·音视频
星一工作室2 小时前
STM32项目分享:基于stm32的旋转书架
stm32·单片机·嵌入式硬件
qq_401700413 小时前
单片机如何控制电机
单片机·嵌入式硬件
清风6666663 小时前
基于单片机的篮球比赛计时与比分控制系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
悠哉悠哉愿意4 小时前
【嵌入式学习笔记】从单片机到嵌入式过渡
笔记·单片机·嵌入式硬件·学习
Coder_Boy_4 小时前
【人工智能应用技术】-基础实战-小程序应用(基于springAI+百度语音技术)智能语音控制-单片机环境搭建
stm32·单片机·嵌入式硬件
d111111111d4 小时前
C语言中,malloc和free是什么,在STM32中使用限制是什么,该如何使用?
c语言·开发语言·笔记·stm32·单片机·嵌入式硬件·学习
Mya153592737874 小时前
BX&Mya DSAI130D 3BSE003127R1 模拟量输入模块
嵌入式硬件·plc·输入模块·控制器模块·现货库存·价格优惠·dsai130d