概述
本文介紹了如何使用瑞薩RA微控制器,結(jié)合E2STUDIO配置工具和SPI通訊接口,來驅(qū)動和控制WS2812 LED燈帶。這是一個集硬件連接、軟件配置和編程開發(fā)于一體的綜合性項目,目標是實現(xiàn)對LED燈帶顏色和亮度的精確控制。
視頻教學(xué)
[https://www.bilibili.com/video/BV14u4y1h7u6/]
樣品申請
[https://www.wjx.top/vm/wBbmSFp.aspx#]
源碼下載
[https://download.csdn.net/download/qq_24312945/88489756]
芯片級聯(lián)方法
芯片在上電復(fù)位以后,接收DIN端打來的數(shù)據(jù),接收夠24bit后,DO端口開始轉(zhuǎn)發(fā)數(shù)據(jù),供下一個芯片提供輸入數(shù)據(jù)。在轉(zhuǎn)發(fā)之前,DO口一直拉低。此時燈珠將不接收新的數(shù)據(jù),內(nèi)置RGB芯片根據(jù)接收到的24bit數(shù)據(jù)后產(chǎn)生的不同占空比信號,展現(xiàn)不同亮度。如果DIN端輸入信號為RESET信號,芯片將接收到的數(shù)據(jù)送顯示,芯片將在該信號結(jié)束后重新接收新的數(shù)據(jù),在接收完開始的24bit數(shù)據(jù)后,通過DO口轉(zhuǎn)發(fā)數(shù)據(jù),燈珠在沒有接收到RESET碼前,RGB亮度保持不變,當接收到80us以上低電平RESET碼后,燈珠內(nèi)部RGB芯片將根據(jù)剛才接收到的24bit數(shù)據(jù)后產(chǎn)生的不同占空比信號,展現(xiàn)不同亮度。
數(shù)據(jù)傳輸
24bit數(shù)據(jù)結(jié)構(gòu):
時序
時序波形圖如下所示。
新建工程
軟件準備
保存工程路徑
芯片配置
本文中使用R7FA4M2AD3CFP來進行演示。
開始SPI配置
點擊Stacks->New Stack->Connectivity->SPI (r_sci_spi)。
SPI屬性配置
將SPI的配置速度設(shè)為7.5M,數(shù)據(jù)寬度設(shè)為8位。
CPHA配置為第二邊沿采樣;在第一個跳變沿時,MOSI在空閑狀態(tài)保持高電平,而在第二個跳變沿,它會保持上一次傳輸?shù)淖罱K電平。由于發(fā)送數(shù)據(jù)的最后一位總是低電平,這樣配置可以避免WS2812誤判。CPOL設(shè)置為高,確保SCK在空閑時保持高電平狀態(tài)。
時鐘配置
SPI (r_sci_spi)的時鐘來自PLCKA。
查詢用戶手冊,配置7.5M頻率需要PLCK主頻為60M。
開發(fā)板上的外部高速晶振為12M,需要修改XTAL為12M,配置PCLKA為60MHz。
SPI配置
系統(tǒng)采用單總線協(xié)議,通過總線上高低電平的時長來區(qū)分邏輯0和1。WS2811工作在800kHz頻率下,將SPI設(shè)置為6.4MHz—即其工作頻率的8倍—可以確保每個字節(jié)(8位)正好對應(yīng)一個邏輯位。在這種設(shè)置下,‘11111000’(0xF8)代表邏輯1,‘11000000’(0xC0)代表邏輯0。
由于瑞薩RA在SPI發(fā)送時候會拉高電平。
所以在發(fā)送的時候需要先發(fā)送8位低電平進行復(fù)位,復(fù)位時間最短位80us。
7.5MHz頻率換算位時間位133.3ns,80us/133.3ns≈600位,為了確保復(fù)位成功,需發(fā)送700位的低電平數(shù)據(jù),即發(fā)送700/8≈88字節(jié)數(shù)據(jù)。
所以定義顯存數(shù)組為88+實際燈珠數(shù)量。
//燈條顯存SPI數(shù)據(jù)緩存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24+88] = {0};
邏輯分析儀顯示如下所示。
邏輯0下發(fā)送的數(shù)據(jù)為11000000’(0xC0)。
邏輯0下高電平位264ns。
邏輯0下低電平位800ns。
邏輯1下發(fā)送的數(shù)據(jù)為‘11111000’(0xF8)。
邏輯1下高電平位666ns。
邏輯1下低電平位400ns。
這種精確的時序配置和電平控制對于確保WS2812燈帶的正確驅(qū)動至關(guān)重要,可以通過上述配置來優(yōu)化SPI接口的性能,確保與WS2812的高效通信。
CPHA配置
CPHA配置為第二邊沿采樣下數(shù)據(jù)傳輸結(jié)束如下所示。
CPHA配置為第二邊沿采樣下數(shù)據(jù)傳輸結(jié)束如下所示。
由于RESET Code為低電平,且要大于80us,所以數(shù)據(jù)傳輸完畢必須為低電平。
代碼
在main.c中添加頭文件。
#include "ws2812.h"
在main.c中添加函數(shù)申明和移位操作以及回調(diào)函數(shù)處理。
fsp_err_t err = FSP_SUCCESS;
volatile bool g_transfer_complete = false;
void sci_spi_callback (spi_callback_args_t * p_args)
{
if (SPI_EVENT_TRANSFER_COMPLETE == p_args- >event)
{
g_transfer_complete = true;
}
}
extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT];
void move_Front()
{
uint8_t i;
uint8_t temp[3];
temp[0] = gWs2812bDat[0].R;
temp[1] = gWs2812bDat[0].G;
temp[2] = gWs2812bDat[0].B;
for (i = 0; i < WS2812B_AMOUNT-1; i++)
{
gWs2812bDat[i].R = gWs2812bDat[i+1].R;
gWs2812bDat[i].G = gWs2812bDat[i+1].G;
gWs2812bDat[i].B = gWs2812bDat[i+1].B;
}
gWs2812bDat[7].R = temp[0];
gWs2812bDat[7].G = temp[1];
gWs2812bDat[7].B = temp[2];
}
添加初始化顯示。
err = R_SCI_SPI_Open(&g_spi0_ctrl, &g_spi0_cfg);
assert(FSP_SUCCESS == err);
sci_spi_extended_cfg_t sci_spi_extended_cfg_t1;
WS2812B_Task();
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
添加流水燈。
while (1)
{
WS2812B_Task();
move_Front();
R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
}
hal_entry.c
#include "hal_data.h"
#include "ws2812.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
fsp_err_t err = FSP_SUCCESS;
volatile bool g_transfer_complete = false;
void sci_spi_callback (spi_callback_args_t * p_args)
{
if (SPI_EVENT_TRANSFER_COMPLETE == p_args- >event)
{
g_transfer_complete = true;
}
}
extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT];
void move_Front()
{
uint8_t i;
uint8_t temp[3];
temp[0] = gWs2812bDat[0].R;
temp[1] = gWs2812bDat[0].G;
temp[2] = gWs2812bDat[0].B;
for (i = 0; i < WS2812B_AMOUNT-1; i++)
{
gWs2812bDat[i].R = gWs2812bDat[i+1].R;
gWs2812bDat[i].G = gWs2812bDat[i+1].G;
gWs2812bDat[i].B = gWs2812bDat[i+1].B;
}
gWs2812bDat[7].R = temp[0];
gWs2812bDat[7].G = temp[1];
gWs2812bDat[7].B = temp[2];
}
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
/* TODO: add your own code here */
err = R_SCI_SPI_Open(&g_spi0_ctrl, &g_spi0_cfg);
assert(FSP_SUCCESS == err);
sci_spi_extended_cfg_t sci_spi_extended_cfg_t1;
WS2812B_Task();
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
while (1)
{
WS2812B_Task();
move_Front();
R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
/*******************************************************************************************************************//**
* This function is called at various points during the startup process. This implementation uses the event that is
* called right before main() to set up the pins.
*
* @param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
/* Enable reading from data flash. */
R_FACI_LP- >DFLCTL = 1U;
/* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
* C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
}
if (BSP_WARM_START_POST_C == event)
{
/* C runtime environment and system clocks are setup. */
/* Configure pins. */
R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
}
}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
}
FSP_CPP_FOOTER
#endif
ws2812.c
/*
* ws2812.c
*
* Created on: 2023年10月31日
* Author: Administrator
*/
#include "ws2812.h"
#include "hal_data.h"
extern fsp_err_t err ;
extern volatile bool g_transfer_complete ;
//燈條顯存SPI數(shù)據(jù)緩存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24+88] = {0};
//燈條顯存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {
//R G B
0XFF, 0X00, 0X00, //0
0X00, 0XFF, 0X00, //1
0X00, 0X00, 0XFF, //2
0X00, 0XFF, 0XFF, //3
0XFF, 0X00, 0XFF, //4
0XFF, 0XFF, 0X00, //5
0XFF, 0XFF, 0XFF, //6
0X00, 0X00, 0X00, //7
};
void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r,uint8_t g,uint8_t b)
{
uint8_t *pR = &gWs2812bDat_SPI[88+(Ws2b812b_NUM) * 24 + 8];
uint8_t *pG = &gWs2812bDat_SPI[88+(Ws2b812b_NUM) * 24];
uint8_t *pB = &gWs2812bDat_SPI[88+(Ws2b812b_NUM) * 24 + 16];
for(uint8_t i = 0; i < 8; i++) {
if(g & 0x80) {
*pG = CODE_1;
}
else {
*pG = CODE_0;
}
if(r & 0x80) {
*pR = CODE_1;
}
else {
*pR = CODE_0;
}
if(b & 0x80) {
*pB = CODE_1;
}
else {
*pB = CODE_0;
}
r < <= 1;
g < <= 1;
b < <= 1;
pR++;
pG++;
pB++;
}
}
void WS2812B_Task(void)
{
uint8_t dat = 0;
for(int i=0;i< 88;i++)
{
gWs2812bDat_SPI[i]=0;
}
//將gWs2812bDat數(shù)據(jù)解析成SPI數(shù)據(jù)
for(uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
{
WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
}
//總線輸出數(shù)據(jù)
/* Send the reset command */
g_transfer_complete = false;
err = R_SCI_SPI_Write(&g_spi0_ctrl, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), SPI_BIT_WIDTH_8_BITS);
assert(FSP_SUCCESS == err);
/* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
while ( g_transfer_complete==false)
{
;
}
// //使總線輸出低電平
// g_transfer_complete = false;
// err = R_SCI_SPI_Write(&g_spi0_ctrl, dat, 1, SPI_BIT_WIDTH_8_BITS);
// assert(FSP_SUCCESS == err);
// /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
// while ( g_transfer_complete==false)
// {
// ;
// }
//幀信號:一個大于50us的低電平
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
}
ws2812.h
/*
* ws2812.h
*
* Created on: 2023年10月31日
* Author: Administrator
*/
#ifndef WS2812_H_
#define WS2812_H_
#include < stdint.h >
// 編碼 0 : 11000000
#define CODE_0 0xc0
// 編碼 1 : 11111000
#define CODE_1 0xF8
/*ws2812b燈珠數(shù)量*/
#define WS2812B_AMOUNT 8
typedef struct
{
uint8_t R;
uint8_t G;
uint8_t B;
} tWs2812bCache_TypeDef;
extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT];
void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r,uint8_t g,uint8_t b);
void WS2812B_Task(void);
#endif /* WS2812_H_ */
審核編輯 黃宇
-
瑞薩
+關(guān)注
關(guān)注
35文章
22309瀏覽量
86304 -
SPI
+關(guān)注
關(guān)注
17文章
1706瀏覽量
91578 -
燈珠
+關(guān)注
關(guān)注
0文章
80瀏覽量
18452 -
WS2812
+關(guān)注
關(guān)注
0文章
32瀏覽量
6179
發(fā)布評論請先 登錄
相關(guān)推薦
評論