How to add byte-wide interfaces to UDB Designer components?

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

cross mob
Anonymous
Not applicable

I'm trying to create a 16-bit adder using the UDB Editor. First of all, is this even possible? It seems that if I want a device with 48 "pins" I may not have enough registers to handle two words of input and one word of output.

Background might help, I guess. I am trying to set up DMA to allow write (at least), and ideally also read, from a 4K array in SRAM on PSOC 5 (and maybe also PSOC 4). I have a 16-bit address bus implemented in two sets of 8 GPIO pins. The access from the external bus is random, and one byte at a time. A R/W pin indicates the direction of data flow, and there are another 8 pins for D0-D7. This currently works fine for writing to a single uint8 in SRAM, but not for being able to address multiple locations based on the GPIO address.

What I think I need is this adder, so I can load it with the base address of the array at startup, and have it add to that the offset into the array coming from the lower 12 bits of the address bus.

I've been looking for indexed DMA solutions, but the documentation on that is really sparse and I still can't see how it would do what I need. As far as I can tell, indexed DMA works if you can get the absolute destination address from somewhere else. I can get the relative offset, but not the absolute address... thus the need (I think) for an adder. I do see that the Keil compiler allows some explicit object positioning in SRAM, but I'm using gcc.

So, the goal I'm currently working towards in the UDB Editor is this adder. It's pretty easy to see how to set up some instructions and state machine states to load A0 from D0, then add A0 to D1 and have the result available from the ALUout. What I can't see is how to correctly make byte or word wide interfaces available in the component so I can connect them to my pins. UDB Designer allows me to add single pin/bit inputs, and it also allows me to add design-wide variables (but the design-wide variables seem to be almost undocumented... what is registered vs. combinatorial? what kinds of expressions are allowed for them?) Come to think of it, I really only need 12 "pins" for the offset address from my GPIO pins. Everything else I can read and write in firmware/software.

To recap, here's what I think I need:

--- in the solution ---

1. Connect AD0-A12 from GPIO pins to the adder component... maybe also connect CS or some other enable signal or clock

2. Configure DMA to use address from adder output as destination

--- when running ---

1. Create 4K uint8 array

2. Set the LO16 of the array start address into the adder

3. (when a new address is available, the adder will be providing a computed absolute corresponding address into the 4K array so DMA read or write requests can source or store the correct byte location)

I've been reading through the AN's on the UDB Editor. I'm not yet finding what I need. I get the impression that I need to use the FIFO registers to load D0 and D1 first, but I still don't see how to load F0 and F1 from hardware inputs. I also dropped a Control Register into the design, but I can't see how to hook that up to anything.

Worst case, I might be able to make this work with an interrupt to copy a single DMA-received byte to the correct location in the buffer, or, I guess I could create an interrupt handler to copy each written byte into the correct place in the array after DMA is complete, but that's a lot messier and I already know the entire CPU-driven data read process isn't fast enough on PSOC 4. Hardware/firmware addressable DMA seems so much more elegant here.   

So, thanks in advance for some pointers on what I'm trying to do, or towards documentation that I should be reading.

Thanks,
Paul

0 Likes
1 Solution
Anonymous
Not applicable

I tried to set this up with an interrupt moving the data after DMA was complete, but this seemed to take too long, and there were other odd and undesirable side-effects in my project once I added a second DMA to capture the low 8 bits of the address.

I did manage to get things maybe working by adding an explicit CY_SET_REG16 call in my main spin loop to set the destination of the DMA to the correct location in the buffer. I need to do some more tests to see if this is really fast and reliable enough. It is still not ideal, I think, because it does require dependence on the CPU to update the destination address, and also will require me to disable DMA writes when the PSoC CPU is busy doing other tasks.

In case it's helpful to someone else, and we don't come up with better answers in this thead:

//Towards the top of main

    DMA_1Init();

    DMADestAddress = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[DMATD].TD1[2u];

//In the for(;;) loop

            laddress = Pin_Address_Low_Read();

            haddress = Pin_Address_High_Read();

            page = haddress & 15;

          

            //Pages above 11 are R/W - this sets the target address for the DMA

            if (page > 11)

                CY_SET_REG16(DMADestAddress, LO16((uint32)(&buffer[page][laddress])));

            else

                CY_SET_REG16(DMADestAddress, LO16((uint32)(&DMAData)));

               //DMAData is a dummy uint8 in case someone tries to write to a R/O address

View solution in original post

0 Likes
2 Replies
Anonymous
Not applicable

I tried to set this up with an interrupt moving the data after DMA was complete, but this seemed to take too long, and there were other odd and undesirable side-effects in my project once I added a second DMA to capture the low 8 bits of the address.

I did manage to get things maybe working by adding an explicit CY_SET_REG16 call in my main spin loop to set the destination of the DMA to the correct location in the buffer. I need to do some more tests to see if this is really fast and reliable enough. It is still not ideal, I think, because it does require dependence on the CPU to update the destination address, and also will require me to disable DMA writes when the PSoC CPU is busy doing other tasks.

In case it's helpful to someone else, and we don't come up with better answers in this thead:

//Towards the top of main

    DMA_1Init();

    DMADestAddress = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[DMATD].TD1[2u];

//In the for(;;) loop

            laddress = Pin_Address_Low_Read();

            haddress = Pin_Address_High_Read();

            page = haddress & 15;

          

            //Pages above 11 are R/W - this sets the target address for the DMA

            if (page > 11)

                CY_SET_REG16(DMADestAddress, LO16((uint32)(&buffer[page][laddress])));

            else

                CY_SET_REG16(DMADestAddress, LO16((uint32)(&DMAData)));

               //DMAData is a dummy uint8 in case someone tries to write to a R/O address

0 Likes
Anonymous
Not applicable

...and, just when I think I'm making progress... ugh.

This solution has the same issue as the loop read I was previously using: there's some oddness in the timing of the device with which I'm interfacing (I guess) when values being written have 1000 for their top four data bits. If I set the DMA to single address, it's fine to pick up all values. If I set the DMA destination in the loop, even with just the low address and no page, and even with having pulled out some other things from the loop, and even with the clock cranked to 79Mhz, data writes between 128 and 143 are always dropped.

I really need a solution that doesn't require the CPU's involvement.

0 Likes