矩阵RGB三色LED驱动芯片CH466(SPI模式)

一、简介

CH466 是一款 6*18 矩阵三色LED驱动芯片,3*6路PWM驱动,最多支持18个COM公共端动态扫 描,最多可驱动108组三色LED或324只单色LED。可选7位或8位单色PWM数据,最高3*8位组合 色PWM,支持16777216 种组合颜色。可选6位或7位或8位亮度PWM数据,支持256级灰度。所有 PWM 引脚具有源电流简单恒流功能。

下图为CH466的系统框图。

二、特点

(1)3x6路PWM和18路COM,可驱动最多108组三色LED或324只单色LED

(2)可选7/8位单色PWM数据,最高3*8位组合色PWM,支持16777216种组合颜色

(3)可选6/7/8位亮度PWM数据,支持256级灰度

(4)矩阵大小可调

(5)PWM引脚具有源电流简单恒流功能

(6)接口丰富,支持I2C/UART/USB/SPI接口

  • 1MHz I2C 接口,多个I2C地址可配置

  • 6MHz SPI 接口,支持3线/4线SPI模式

  • 3MHz UART 接口,多种波特率可配置

  • 12MHz 全速USB接口和单线USB接口

(7)支持1路ARGB灯驱动

(8)LED消影时间多级可调

(9)支持自动呼吸功能

(10)免晶体

三、功能概述

1、工作模式配置

在芯片复位后,会根据SPI4_EN、SPI3_EN、USB_EN和UART_EN引脚上的22K下拉电阻选择对应 的工作模式。22K下拉电阻只能同时连接到其中一个引脚上。如果SPI4_EN、SPI3_EN、USB_EN和UART_EN 都未连接22K下拉电阻,芯片将默认工作在I2C模式。在不同的工作模式下,CH466支持的最大RGB 矩阵大小不同。如果芯片使能了RESET#引脚,相应的矩阵COM数量会减少1,详见下表。

2、SPI模式

SPI 接口支持3线模式和4线模式,兼容模式0和模式3。在3线模式下,SCS、SCK、MOSI分别 作为片选、时钟和数据引脚;在4线模式下,SCS、SCK、MOSI、MISO分别充当片选、时钟、主机输出 从机输入数据、主机输入从机输出数据引脚。

4线SPI接口时序如下:

TRI 为传输等待时间 主机发送的第一个字节为命令(Command),其含义见下图。随后,发送需要操作的寄存器地址 和一个Dummy字节。Dummy字节没有实际意义,可以使用0x00或0xFF填充。

(1)写CH466寄存器 主机拉低 SCS,发送命令和需要写入的寄存器地址和数据。连续写入时,支持寄存器地址自增。

(2)读CH466寄存器 主机拉低SCS,发送命令和需要读取的寄存器地址,CH466 会返回对应的寄存器数据。连续读取 时,支持寄存器地址自增。

在三线SPI下,需要注意的是其通讯引脚为MISO,并非MOSI,需要着重注意!!!

三线SPI的读写时序稍微有点区别,写时序和上述4线SPI无明显区别;而读时序就要做出区分,因为其只有1根通讯线,所以在读数据时需要把主机端的MOSI引脚状态改为输入模式,来接收芯片返回的数据。

四、硬件设计

1、芯片外围

此芯片是免晶振设计,所以芯片的外围十分的精简,如下如所示:

需要使用SPI模式,就按章节3.1表格所示,讲对应引脚对地接22K下拉电阻。

2、LED灯设计(部分展示)

芯片目前只支持共阴极的三色LED灯,在选型时需要注意,部分设计如下:

五、程序开发

1、接口初始化

在SPI模式下,根据是3线模式还是4线模式,去使能双线全双工还是单线模式,我们以3线SPI为例:

复制代码
void MySPI3Line_Init()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    SPI_InitTypeDef  SPI_InitStructure = {0};
    DMA_InitTypeDef DMA_InitStructure={0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_SetBits(GPIOA,GPIO_Pin_4);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);
}

2、寄存器读写

具体的寄存器地址和具体每一位的功能可以参考芯片的datasheet,我们使用硬件DMA来进行读写,如果不是频繁的切换灯效,也可以不使用DMA。代码如下:

复制代码
uint8_t spi3_tx_rx_data(uint8_t *p_tx,uint8_t tx_len,uint8_t *p_rx,uint8_t rx_len)
{
    uint8_t *ptr;
    SPI_CS_LOW();
    GPIOA->CFGLR = GPIOA->CFGLR & ~0xF0000000 | 0x90000000;
    SPI1->CTLR1 |= SPI_CTLR1_BIDIOE;        // MOSI Tx Enable
    DMA1_Channel3->CFGR &= ~ DMA_CFGR2_EN;
    DMA1_Channel2->CFGR &= ~ DMA_CFGR2_EN;

    DMA1_Channel3->MADDR = (uint32_t)p_tx;
    DMA1_Channel2->MADDR = (uint32_t)p_rx;

    DMA1_Channel3->CNTR = tx_len;
    DMA1_Channel2->CNTR = tx_len;

    DMA1_Channel3->CFGR |= DMA_CFGR2_EN;    // Tx
    // DMA1_Channel2->CFGR |= DMA_CFGR2_EN;    // Rx
    SPI1->CTLR1 |= SPI_CTLR1_SPE;
    
    while( (!DMA_GetFlagStatus(DMA1_FLAG_TC2)) && (!DMA_GetFlagStatus(DMA1_FLAG_TC3)) );
    while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY));

    if (rx_len)
    {
        GPIOA->CFGLR = GPIOA->CFGLR & ~0xF0000000 | 0x40000000;                                     // 切换为浮空输入
        ptr = p_rx + tx_len;
        SPI1->CTLR1 &= ~SPI_CTLR1_SPE;
        Delay_Us(3);
        if (rx_len == 1)
        {
            SPI1->CTLR1 &= ~SPI_CTLR1_BIDIOE;        // MOSI Rx Enable
            SPI1->CTLR1 |= SPI_CTLR1_SPE;
            SPI1->CTLR1 &= ~SPI_CTLR1_SPE;
            while (!(SPI1->STATR & SPI_STATR_RXNE));
            *ptr++ = SPI1->DATAR; 
        }
        else
        {
            SPI1->CTLR1 &= ~SPI_CTLR1_BIDIOE;        // MOSI Rx Enable
            SPI1->CTLR1 |= SPI_CTLR1_SPE;
            // 接收前N-1的字节
            for (size_t i = 0; i < rx_len - 1; i++)
            {
                while (!(SPI1->STATR & SPI_STATR_RXNE));
                *ptr++ = SPI1->DATAR;
            }
            Delay_Us(3);
            SPI1->CTLR1 &= ~SPI_CTLR1_SPE;
            while (!(SPI1->STATR & SPI_STATR_RXNE));
            *ptr++ = SPI1->DATAR; 
        }
    }
    SPI_CS_HIGH();
    Delay_Ms(1);
    return 0;
}

3、LED驱动

驱动LED只需要按照手册要求初始化各个寄存器的参数,然后给相应的值即可完成LED的驱动,这里以点亮全部灯为例,参考代码如下:

复制代码
void set_all_led(uint8_t i,uint8_t r,uint8_t g,uint8_t b)
{
    for (uint8_t com = 0; com < 18; com++)
    {
        for (uint8_t seg = 0; seg < 6; seg++)
        {
            rgb_buf[6*com + seg][0] = i;
            rgb_buf[6*com + seg][1] = r;
            rgb_buf[6*com + seg][2] = g;
            rgb_buf[6*com + seg][3] = b;
        }
    }
}

以上仅为部分程序,如需完整工程可以私信联系获取。

相关推荐
染予1 小时前
实现功能:给stm32F427zgt6开发板配置网络,电脑可以ping通开发板
stm32·单片机·嵌入式硬件
Hotchip_MEMS1 小时前
单节锂电池充电管理:如何平衡充电速度与电池寿命
人工智能·单片机·嵌入式硬件·物联网
ι:1 小时前
Codex 接管嘉立创EDA 并复现 STM32 Blue Pill 学习底板的完整教学
stm32·嵌入式硬件·学习
西城微科方案开发1 小时前
蓝牙血压计 PCBA 方案
单片机·嵌入式硬件
金戈鐡馬1 小时前
深入解析PGND在FOC中的作用和存在的必要性
单片机·嵌入式硬件·foc·磁场定向控制·电调
笨笨没好名字12 小时前
怎么看懂51单片机电路图与功能实现的C语言编写(2-7入门篇)
c语言·嵌入式硬件·51单片机
项目題供诗16 小时前
STM32-TIM输入捕获(十四)
stm32·单片机·嵌入式硬件
cpsss068117 小时前
Freertos的Systick_Handler重定义
单片机·嵌入式硬件
国产电子元器件18 小时前
电流传感器的输出可以直接接示波器吗?
stm32·单片机·嵌入式硬件