「求助」PWM+DMA驅(qū)動(dòng)ws2812內(nèi)存溢出

QQ截圖20241224111524.jpg

這個(gè)數(shù)組口算都超4K,而V003只有2K的RAM


#define PIXEL_NUM? ? ? ?72? ? ? ? ? // LED的數(shù)量

#define NUM? ? ? ? ? ? ?(24*PIXEL_NUM + 100)? //LED顏色數(shù)組


工程包:

icon_rar.gifWS2812.zip



看到5*社區(qū)有一個(gè)帖子說可以用DMA雙緩沖進(jìn)行搬運(yùn)RGB顏色數(shù)據(jù),從而降低RAM,

求助CH32如何配置。


配合AI自行摸索(剛學(xué)編程多擔(dān)待)

#include "debug.h"

#define PIXEL_NUM? ? ? ?72? ? ? ? ? // 定義LED的數(shù)量

#define BUFFER_SIZE? ? ?(24 * 2)? ? // 每個(gè)緩沖區(qū)大小為2個(gè)WS2812像素的數(shù)據(jù)大?。?6字節(jié))

#define WS1? ? ? ? ? ? ?43? ? ? ? ? ? // PWM高電平的時(shí)間長(zhǎng)度,對(duì)應(yīng)0.9us

#define WS0? ? ? ? ? ? ?14? ? ? ? ? ? // PWM低電平的時(shí)間長(zhǎng)度,對(duì)應(yīng)0.3us

#define TIM2_CH2CVR_ADDRESS? ? 0x40000038? ? // TIM2_UP是DMA的通道2, 比較/捕獲寄存器

int16_t pixel_buffer1[BUFFER_SIZE];

int16_t pixel_buffer2[BUFFER_SIZE];

volatile int current_buffer = 0;

volatile uint16_t pixel_index = 0;

// 初始化TIM2 PWM輸出

void TIM2_PWMOut_Init(u16 arr, u16 psc, u16 ccp) {

//

}


// 初始化DMA傳輸

void TIM2_DMA_Init(DMA_Channel_TypeDef *DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize) {

? ? DMA_InitTypeDef DMA_InitStructure = {0};

? ? RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

? ? DMA_DeInit(DMA_CHx);

? ? DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;? ? ?// 外設(shè)地址

? ? DMA_InitStructure.DMA_MemoryBaseAddr = memadr;? ? ? ?// 內(nèi)存地址

? ? DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;? ?// 數(shù)據(jù)傳輸方向:內(nèi)存到外設(shè)

? ? DMA_InitStructure.DMA_BufferSize = bufsize;? ? ? ? ? // 緩沖區(qū)大小

? ? DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;? // 不遞增外設(shè)地址

? ? DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;? ? ? ? ? ?// 遞增內(nèi)存地址

? ? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 半字?jǐn)?shù)據(jù)大小

? ? DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;? ? ? ? ?// 半字?jǐn)?shù)據(jù)大小

? ? DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;? ? ? ? ? ? ? ? ? ? ? ? ?// 循環(huán)模式

? ? DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;? ? ? ? ? ? ? ? ?// 最高優(yōu)先級(jí)

? ? DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;? ? ? ? ? ? ? ? ? ? ? ? ? ? // 禁止內(nèi)存到內(nèi)存?zhèn)鬏?/p>

? ? DMA_Init(DMA_CHx, &DMA_InitStructure);

? ? DMA_ITConfig(DMA_CHx, DMA_IT_TC | DMA_IT_HT, ENABLE); // 啟用半傳輸和全傳輸中斷

? ? DMA_Cmd(DMA_CHx, ENABLE);? ? // 使能DMA通道

}

// 搬運(yùn)

void DMA1_Channel2_IRQHandler(void) {

? ? if (DMA_GetITStatus(DMA1_IT_HT2)) {? // 半傳輸中斷

? ? ? ? // MCU 準(zhǔn)備好下一組像素的數(shù)據(jù),寫入到未被DMA使用的緩沖區(qū)

? ? ? ? uint32_t color = Wheel(pixel_index++ % 256);

? ? ? ? WS281x_SetPixelColor(current_buffer ? pixel_buffer1 : pixel_buffer2, 0, color);

? ? ? ? color = Wheel(pixel_index++ % 256);

? ? ? ? WS281x_SetPixelColor(current_buffer ? pixel_buffer1 : pixel_buffer2, 1, color);

? ? ? ? DMA_ClearITPendingBit(DMA1_IT_HT2);

? ? }

? ? if (DMA_GetITStatus(DMA1_IT_TC2)) {? // 傳輸完成中斷

? ? ? ? // MCU 準(zhǔn)備好下一組像素的數(shù)據(jù),寫入到未被DMA使用的緩沖區(qū)

? ? ? ? uint32_t color = Wheel(pixel_index++ % 256);

? ? ? ? WS281x_SetPixelColor(current_buffer ? pixel_buffer1 : pixel_buffer2, 0, color);

? ? ? ? color = Wheel(pixel_index++ % 256);

? ? ? ? WS281x_SetPixelColor(current_buffer ? pixel_buffer1 : pixel_buffer2, 1, color);

? ? ? ? DMA_ClearITPendingBit(DMA1_IT_TC2);

? ? }

}


int main(void) {

? ? USART_Printf_Init(115200);

? ? printf("SystemClk:%d\r\n", SystemCoreClock);

? ? Delay_Init();

? ? // 初始化所有像素為關(guān)閉狀態(tài)

? ? WS_Write_RGB_to_Buffer(0x0, 0, 0, pixel_buffer1);

? ? WS_Write_RGB_to_Buffer(0x0, 0, 0, pixel_buffer2);

? ? TIM2_PWMOut_Init(57, 0, 0); // 調(diào)整周期值、高電平、低電平時(shí)間

? ? TIM2_DMA_Init(DMA1_Channel2, (u32)TIM2_CH2CVR_ADDRESS, (u32)pixel_buffer1, BUFFER_SIZE);? ? // 初始化DMA傳輸

? ? NVIC_InitTypeDef NVIC_InitStructure;

? ? NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;

? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

? ? NVIC_Init(&NVIC_InitStructure);

? ? TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);? ? // 使能TIM2的DMA更新功能

? ? TIM_Cmd(TIM2, ENABLE);? ? // 使能TIM2

? ? TIM_CtrlPWMOutputs(TIM2, ENABLE);? ? // 使能TIM2的PWM輸出

? ? while (1) {

? ? }

}




熱門產(chǎn)品 : USB3.0 HUB控制器:CH634

動(dòng)態(tài)算啊,不要一次性算好。


簡(jiǎn)單點(diǎn)的話,一個(gè)把 printf 去掉,另一個(gè)把 int16_t send_Buf[NUM]; 改成 uint8_t send_Buf[NUM]; 并配 DMA 源為 8位


感謝您的回復(fù),

將int16_t send_Buf[NUM];? ? 改成uint8_t

并將DMA也改成8位? ??

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte ;?

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;??


確實(shí)是可以增加一些LED通過編譯(但沒有達(dá)到72顆LED)

還有編譯后時(shí)序不對(duì),LED無法點(diǎn)亮

因沒有示波器、邏輯分析儀無法準(zhǔn)確判斷

debug也用不了,報(bào):Error: OpenOCD only supports Debug Module version 2 (0.13) and 3 (1.0), not 15 (dmstatus=0xffffffff). This error might be caused by a JTAG signal issue. Try reducing the JTAG clock speed.




#include "debug.h"

#define PIXEL_NUM? ? ? ?72? ? ? ? ? // 定義LED的數(shù)量

#define NUM? ? ? ? ? ? ?(24*PIXEL_NUM + 100)? //LED顏色數(shù)組

#define WS1? ? ? ? ? ? ?43? ? ? ? ? ? // PWM高電平的時(shí)間長(zhǎng)度,對(duì)應(yīng)0.9us

#define WS0? ? ? ? ? ? ?14? ? ? ? ? ? // PWM低電平的時(shí)間長(zhǎng)度,對(duì)應(yīng)0.3us

#define TIM2_CH2CVR_ADDRESS? ? 0x40000038? ? // TIM2_UP是DMA的通道2, 比較/捕獲寄存器

int16_t send_Buf[NUM];? ? ? ? ? ? ? // 存儲(chǔ)PWM數(shù)據(jù)的緩沖區(qū)

// 初始化TIM2 PWM輸出

void TIM2_PWMOut_Init(u16 arr, u16 psc, u16 ccp) {

? ? GPIO_InitTypeDef? ? ? ? GPIO_InitStructure = {0};

? ? TIM_OCInitTypeDef? ? ? ?TIM_OCInitStructure = {0};

? ? TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};

? ? RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);

? ? RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

? ? RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

? ? GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);

? ? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

? ? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

? ? GPIO_Init(GPIOC, &GPIO_InitStructure);

? ? TIM_TimeBaseInitStructure.TIM_Period = arr;? ? ? ? ?// 自動(dòng)重裝載周期值

? ? TIM_TimeBaseInitStructure.TIM_Prescaler = psc;? ? ? // 分頻值

? ? TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

? ? TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

? ? TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

? ? TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

? ? TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

? ? TIM_OCInitStructure.TIM_Pulse = ccp;? ? ? ? ? ? ? ? // 初始脈沖值

? ? TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

? ? TIM_OC2Init(TIM2, &TIM_OCInitStructure);

? ? TIM_Cmd(TIM2, ENABLE);

}


// 初始化DMA傳輸

void TIM2_DMA_Init(DMA_Channel_TypeDef *DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize) {

? ? DMA_InitTypeDef DMA_InitStructure = {0};? ? // 使能DMA1時(shí)鐘

? ? RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);? ? // 復(fù)位DMA通道

? ? DMA_DeInit(DMA_CHx);

? ? DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;? ? ?// 外設(shè)地址

? ? DMA_InitStructure.DMA_MemoryBaseAddr = memadr;? ? ? ?// 內(nèi)存地址

? ? DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;? ?// 數(shù)據(jù)傳輸方向:內(nèi)存到外設(shè)

? ? DMA_InitStructure.DMA_BufferSize = bufsize;? ? ? ? ? // 緩沖區(qū)大小

? ? DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;? // 不遞增外設(shè)地址

? ? DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;? ? ? ? ? ?// 遞增內(nèi)存地址

? ? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 半字?jǐn)?shù)據(jù)大小

? ? DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;? ? ? ? ?// 半字?jǐn)?shù)據(jù)大小

? ? DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;? ? ? ? ? ? ? ? ? ? ? ? ?// 單次模式

? ? DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;? ? ? ? ? ? ? ? ?// 最高優(yōu)先級(jí)

? ? DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;? ? ? ? ? ? ? ? ? ? ? ? ? ? // 禁止內(nèi)存到內(nèi)存?zhèn)鬏?/span>

? ? DMA_Init(DMA_CHx, &DMA_InitStructure);

? ? DMA_Cmd(DMA_CHx, ENABLE);? ? // 使能DMA通道

}


// 將RGB數(shù)據(jù)轉(zhuǎn)換成PWM數(shù)據(jù)并填充到send_Buf中

void WS_WriteAll_RGB(uint8_t n_R, uint8_t n_G, uint8_t n_B) {

? ? uint16_t i, j;

? ? uint8_t dat[24];

? ? for (i = 0; i < 8; i++) {

? ? ? ? dat[i] = ((n_G & 0x80) ? WS1 : WS0);

? ? ? ? n_G <<= 1;

? ? }

? ? for (i = 0; i < 8; i++) {

? ? ? ? dat[i + 8] = ((n_R & 0x80) ? WS1 : WS0);

? ? ? ? n_R <<= 1;

? ? }

? ? for (i = 0; i < 8; i++) {

? ? ? ? dat[i + 16] = ((n_B & 0x80) ? WS1 : WS0);

? ? ? ? n_B <<= 1;

? ? }

? ? for (i = 0; i < PIXEL_NUM; i++) {? ? ?// 填充每個(gè)像素的數(shù)據(jù)到send_Buf

? ? ? ? for (j = 0; j < 24; j++) {

? ? ? ? ? ? send_Buf[i * 24 + j] = dat[j];

? ? ? ? }

? ? }

? ? for (i = PIXEL_NUM * 24; i < NUM; i++)

? ? ? ? send_Buf[i] = 0;? ? ?// 填充剩余的緩沖區(qū)為0,用于產(chǎn)生復(fù)位信號(hào)

}

// 創(chuàng)建一個(gè)GRB顏色值

uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue) {

? ? return green << 16 | red << 8 | blue;

}

// 根據(jù)位置生成彩虹色

uint32_t Wheel(uint8_t WheelPos) {

? ? WheelPos = 255 - WheelPos;

? ? if (WheelPos < 85) {

? ? ? ? return WS281x_Color(255 - WheelPos * 3, WheelPos * 3, 0);? // 綠 -> 黃

? ? }

? ? if (WheelPos < 170) {

? ? ? ? WheelPos -= 85;

? ? ? ? return WS281x_Color(0, 255 - WheelPos * 3, WheelPos * 3);? // 黃 -> 紅

? ? }

? ? WheelPos -= 170;

? ? return WS281x_Color(WheelPos * 3, 0, 255 - WheelPos * 3);? ? ? // 紅 -> 綠

}


// 設(shè)置特定像素的顏色

void WS281x_SetPixelColor(uint16_t n, uint32_t GRBColor) {

? ? uint8_t i;

? ? if (n < PIXEL_NUM) {

? ? ? ? for (i = 0; i < 24; ++i) {

? ? ? ? ? ? send_Buf[24 * n + i] = (((GRBColor << i) & 0X800000) ? WS1 : WS0);

? ? ? ? }

? ? }

}


// 顯示當(dāng)前緩沖區(qū)中的顏色數(shù)據(jù)

void ws281x_show(void) {

? ? // 設(shè)置DMA傳輸?shù)臄?shù)據(jù)計(jì)數(shù)器

? ? DMA_SetCurrDataCounter(DMA1_Channel2, NUM);

? ? // 使能DMA通道

? ? DMA_Cmd(DMA1_Channel2, ENABLE);

? ? // 使能TIM2

? ? TIM_Cmd(TIM2, ENABLE);

? ? // 等待DMA傳輸完成標(biāo)志

? ? while (DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);

? ? // 禁能TIM2

? ? TIM_Cmd(TIM2, DISABLE);

? ? // 禁能DMA通道

? ? DMA_Cmd(DMA1_Channel2, DISABLE);

? ? // 清除DMA傳輸完成標(biāo)志

? ? DMA_ClearFlag(DMA1_FLAG_TC2);

}


// 彩虹循環(huán)效果

void ws281x_rainbowCycle(uint8_t wait) {

? ? uint16_t i, j;

? ? for (j = 0; j < 256 * 5; j++) {? // 循環(huán)多次以形成連續(xù)的效果

? ? ? ? for (i = 0; i < PIXEL_NUM; i++) {

? ? ? ? ? ? // 設(shè)置每個(gè)像素的顏色

? ? ? ? ? ? WS281x_SetPixelColor(i, Wheel(((i * 256 / PIXEL_NUM) + j) & 255));

? ? ? ? }

? ? ? ? // 顯示當(dāng)前設(shè)置的顏色

? ? ? ? ws281x_show();

? ? ? ? // 延時(shí)一段時(shí)間

? ? ? ? Delay_Ms(wait);

? ? }

}


// 彩虹效果

void ws281x_rainbow(uint8_t wait) {

? ? uint16_t i, j;

? ? for (j = 0; j < 256; j++) {

? ? ? ? for (i = 0; i < PIXEL_NUM; i++) {

? ? ? ? ? ? // 設(shè)置每個(gè)像素的顏色

? ? ? ? ? ? WS281x_SetPixelColor(i, Wheel((i + j) & 255));

? ? ? ? }

? ? ? ? // 顯示當(dāng)前設(shè)置的顏色

? ? ? ? ws281x_show();

? ? ? ? // 延時(shí)一段時(shí)間

? ? ? ? Delay_Ms(wait);

? ? }

}


int main(void) {

? ? USART_Printf_Init(115200);

? ? printf("SystemClk:%d\r\n", SystemCoreClock);

? ? Delay_Init();

? ? WS_WriteAll_RGB(0x0, 0, 0);? ? // 初始化所有像素為關(guān)閉狀態(tài)

? ? TIM2_PWMOut_Init(57, 0, 0); // 調(diào)整周期值、高電平、低電平時(shí)間

? ? TIM2_DMA_Init(DMA1_Channel2, (u32)TIM2_CH2CVR_ADDRESS, (u32)send_Buf, NUM);? ? // 初始化DMA傳輸

? ? TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);? ? // 使能TIM2的DMA更新功能

? ? TIM_Cmd(TIM2, ENABLE);? ? // 使能TIM2

? ? TIM_CtrlPWMOutputs(TIM2, ENABLE);? ? // 使能TIM2的PWM輸出

? ? while (1) {

? ? ? ? ws281x_rainbowCycle(10);

? ? }

}



源是8位,因?yàn)槟愕臄?shù)據(jù)沒超過255。但目標(biāo)(也就是外設(shè))依然是16位的,而不該是8位。高位會(huì)用00補(bǔ)齊的。


可以增加TIM的分頻,讓W(xué)S2812的ARR控制再0-255范圍內(nèi),然后就可以把buffer的數(shù)據(jù)類型改成unsigned char了,占用的RAM就減少到原來的1/2了,72個(gè)燈的話,應(yīng)該是只要216字節(jié)就行了。DMA源地址寬度選byte,目標(biāo)地址寬度選halfword。另外,也可以選分段計(jì)算,先刷完一部分,接著計(jì)算剩下的再刷,應(yīng)該也能減少RAM占用


只有登錄才能回復(fù),可以選擇微信賬號(hào)登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频