DMA SRAM->Periph not working

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
user_1570836
Level 4
Level 4
50 replies posted 25 replies posted 25 sign-ins

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

Snímka.PNG

#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;

    }

}

0 Likes
1 Solution
user_1570836
Level 4
Level 4
50 replies posted 25 replies posted 25 sign-ins

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);

}

View solution in original post

0 Likes
5 Replies
user_1570836
Level 4
Level 4
50 replies posted 25 replies posted 25 sign-ins

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);

}

0 Likes

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

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

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

0 Likes

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

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

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.

0 Likes