- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I am writing a custom component to drive WS2812 pixels with as less hardware as possible. I am already done with Verilog part, but I can't get DMA working. When I write to FIFO using CPU, it is working as expected. When I try my DMA code, nothing happens.
Does anyone see what I am doing wrong? I need to use DMA. Simultaneously driving 24 strings + generating patterns seems like too much for CPU only approach.
Thanks in advance,
Stanislav
#include "cytypes.h"
#include "cyfitter.h"
#include "`$INSTANCE_NAME`_DMA_dma.h"
#define `$INSTANCE_NAME`_Data_Reg `$INSTANCE_NAME`_WS2812Internal_Shifter_u0__F0_REG
#define `$INSTANCE_NAME`_DMAStatus_Active 0
#define `$INSTANCE_NAME`_DMAStatus_Completed 1
#define `$INSTANCE_NAME`_DMAStatus_Failure -1
void `$INSTANCE_NAME`_InitDMA();
void `$INSTANCE_NAME`_InitIRQ(cyisraddress isr);
void `$INSTANCE_NAME`_SendDMA(uint8_t *data, uint16_t count);
uint8_t `$INSTANCE_NAME`_GetDMAStatus();
void `$INSTANCE_NAME`_WaitDMAComplete();
#include <project.h>
#include "cytypes.h"
#include "stdlib.h"
#include "cyfitter.h"
#include "`$INSTANCE_NAME`_WS2812.h"
uint8_t `$INSTANCE_NAME`_DmaChannel;
uint8_t `$INSTANCE_NAME`_DmaTd;
void `$INSTANCE_NAME`_InitDMA()
{
`$INSTANCE_NAME`_DmaChannel = `$INSTANCE_NAME`_DMA_DmaInitialize(1,1,HI16(CYDEV_SRAM_BASE),HI16(CYDEV_PERIPH_BASE));
`$INSTANCE_NAME`_DmaTd = CyDmaTdAllocate();
}
void `$INSTANCE_NAME`_InitIRQ(cyisraddress isr)
{
`$INSTANCE_NAME`_IsrTxComplete_StartEx(isr);
}
void `$INSTANCE_NAME`_SendDMA(uint8_t *data, uint16_t count)
{
CyDmaTdSetConfiguration(`$INSTANCE_NAME`_DmaTd,count,`$INSTANCE_NAME`_DmaTd,CY_DMA_TD_INC_SRC_ADR | WS2812_1_DMA__TD_TERMOUT_EN );
CyDmaTdSetAddress(`$INSTANCE_NAME`_DmaTd,LO16((uint32)data),LO16(`$INSTANCE_NAME`_Data_Reg));
CyDmaChSetInitialTd(`$INSTANCE_NAME`_DmaChannel,`$INSTANCE_NAME`_DmaTd);
CyDmaChEnable(`$INSTANCE_NAME`_DmaChannel,1);
CyDmaChSetRequest(`$INSTANCE_NAME`_DmaChannel,CPU_REQ);
}
uint8_t `$INSTANCE_NAME`_GetDMAStatus()
{
uint8_t state;
if(CyDmaChStatus(`$INSTANCE_NAME`_DmaChannel,NULL,&state) == CYRET_SUCCESS)
{
if((state && STATUS_CHAIN_ACTIVE) == STATUS_CHAIN_ACTIVE)
return 0;
else
return 1;
}
return -1;
}
void `$INSTANCE_NAME`_WaitDMAComplete()
{
uint8_t state;
while(1)
{
CyDmaChStatus(`$INSTANCE_NAME`_DmaChannel,NULL,&state);
if((state & STATUS_CHAIN_ACTIVE) == 0)
return;
}
}
Solved! Go to Solution.
- Labels:
-
PSoC 5 Device Programming
-
PSoC 5LP
- Tags:
- dma
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Okay, this time I solved the problem myself. As I suspected, incorrent usage of DMA. Here is how I got it working:
uint8_t WS2812_1_DmaChannel;
uint8_t WS2812_1_DmaTd;
void WS2812_1_Init()
{
WS2812_1_DmaChannel = WS2812_1_DMA_DmaInitialize(1,1,HI16(CYDEV_SRAM_BASE),HI16(CYDEV_PERIPH_BASE));
WS2812_1_DmaTd = CyDmaTdAllocate();
CyDmaChSetInitialTd(WS2812_1_DmaChannel,WS2812_1_DmaTd);
}
void WS2812_1_Transfer(uint8_t *data, uint16_t count)
{
CyDmaTdSetConfiguration(WS2812_1_DmaTd,count,CY_DMA_DISABLE_TD,CY_DMA_TD_INC_SRC_ADR);
CyDmaTdSetAddress(WS2812_1_DmaTd,LO16((uint32_t)data),LO16(WS2812_1_Data_Reg));
CyDmaChEnable(WS2812_1_DmaChannel,1);
CyDmaChSetRequest(WS2812_1_DmaChannel,CPU_REQ);
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Okay, this time I solved the problem myself. As I suspected, incorrent usage of DMA. Here is how I got it working:
uint8_t WS2812_1_DmaChannel;
uint8_t WS2812_1_DmaTd;
void WS2812_1_Init()
{
WS2812_1_DmaChannel = WS2812_1_DMA_DmaInitialize(1,1,HI16(CYDEV_SRAM_BASE),HI16(CYDEV_PERIPH_BASE));
WS2812_1_DmaTd = CyDmaTdAllocate();
CyDmaChSetInitialTd(WS2812_1_DmaChannel,WS2812_1_DmaTd);
}
void WS2812_1_Transfer(uint8_t *data, uint16_t count)
{
CyDmaTdSetConfiguration(WS2812_1_DmaTd,count,CY_DMA_DISABLE_TD,CY_DMA_TD_INC_SRC_ADR);
CyDmaTdSetAddress(WS2812_1_DmaTd,LO16((uint32_t)data),LO16(WS2812_1_Data_Reg));
CyDmaChEnable(WS2812_1_DmaChannel,1);
CyDmaChSetRequest(WS2812_1_DmaChannel,CPU_REQ);
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
user_1570836,
Good deal! I'm glad you found the problem.
You're using DMA which has its own difficulties and benefits. In addition, Component authoring is advanced coding. I'd say you were an advanced user.
I'm glad to see you on the forum!
Len
"Engineering is an Art. The Art of Compromise."
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Len,
I would not consider myself as advanced user. I have some experience with PSoC Creator and 5LP’s, but nothing like 10s of projects.
However, I wanted 24 strings simultaneously, so I did my best. And when I make hardware part, I hope it will work together.
Stanislav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Stanislav,
Given that Component Authoring is relatively 'lightly' documented and DMA can be an elegant but complicated subject, it is rarely attempted except by the seasoned programmer. Bravo.
I don't if your WS2812 component is proprietary. If not would you be willing to share it with the PSoC community?
I have contributed a few components I have created to the Code Sharing forum. Community Code Examples
Terminal Support Component Library
A LPF (Low-Pass Filter) Component -- Finally!!!
Len
"Engineering is an Art. The Art of Compromise."
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Len,
Thanks for recognition. You're right, there were parts, where I had to search for related articles and working code.
You may find better components for WS2812, but here you are. It is nothing confidential, in fact it's just for hobby. I wasn't planning to share it, so it is hardcoded to GRBW pixels(Matrix and Strip wrappers). Clock it with 2.815MHz or similar frequency.