PSoC: how does it work? - Page 1
Forum section: electronics / general

author: djacobow
author_rank: Super Contributor
timestamp: August 29, 2019, 11:35:20 pm
content: Any PSoC experts out there? (And Insane Clown Posse fans?)So, I've got a new gig and the company's product is based on PSoC 6.I'm having trouble wrapping my head around what, exactly, is "fixed" and what is programmable. I mean, I get that you draw stuff in Creator and then click build and it does some hdl synthesis programming blob creation, and it also generates a bunch of hal code, and then you can program using the hal code.But I have questions.- how does that binary programming blob get into the chip? The creator build seems to generate a couple of elf files (the part we're usin has two cores) and then it merges them, and then writes them. Where is the code for the "fpga stuff?" Is it somehow included in the startup code for one of the processors?- Is there any way we can see the HDL code that was generated? A lot of questions I can't answer from the data sheets would be answered if I could just see the implementation of the things.- what is "fixed" and what is changeable? Here's an example. I'm trying to set up DMA for a UART. One of the things you put into the gui for the DMA channel is the length of the DMA transfer. But is that really hard-coding the value into the device? Or can I just change it later in the software. In the case of Tx DMA, of course, what I would like to do is point it at a buffer of whatever length and then let'er rip and notify me when it's done.The generated code for the DMA does have calls like Cy_DMA_Descriptor_SetXloopDataCount() so I think I can set the value to whatever I want. But then if that's the case, why does the silly gui ask me to set that up front?Strange platform.

author: djacobow
author_rank: Super Contributor
timestamp: August 30, 2019, 12:32:01 am
content: Thanks for the helpful info, @blueskull. This makes a lot of sense, and I the whole architecture is making more sense to me now.In the case of the DMA channel, it appears from experimentation that I can indeed change the transfer length at run-time, so values smaller or larger than what I had entered into the gui.I think what the gui does in terms of the dma engine is set up certain things which can't be changed at runtime, but other things which are merely defaults. It's left as an exercise for the programmer to determine which is which.I'm happy to have transmit dma working for my uarts now. Now, I will start on rx dma....

author: FrankBuss
author_rank: Unknown
timestamp: August 30, 2019, 12:44:12 am
content: If you want to know the details, see thetechnical reference manual.I did oncethis RS232 to I2C converterby writing most of the registers for the initialization and routing by hand instead of using the Device Editor. But this was a PSoC 1 device. Would be crazy to try this for a PSoC 6 device, but should be possible

author: djacobow
author_rank: Super Contributor
timestamp: August 30, 2019, 05:26:40 am
content: That reference manual is just the thing for me; a normal register level explanation of the chip. I need the PSoC 63 version, but this is the good stuff. The online docs in Creator are more aimed at consumers of their autogenerated hal, not understanding it.

author: DEV001
author_rank: Contributor
timestamp: August 31, 2019, 06:49:55 pm
content: PSOC 6 is currently in a weird state development tool wise. Cypress is pushing their new ModusToolbox suite for PSOC 6 development but it doesn't currently support actually using any of the UDB features. A user on the Cypress forum found a workaround which I will copy below in case it is removed since it gives some insight into what is generated from the output of PSOC Creator. The user also created a tool to automatically do the process below for you in an app onGithub.https://community.cypress.com/thread/44812First step is enabling the UART Component for PSoC6 in PSoC Creator (import and edit component.cystate, set to prototype or production)Second, design your schematic in PSoC Creator and buildCopy cydevice.trm, cyfitter.h, project.h, cyfitter_cfg.c and .h to a folder inside your Modus project and includeChange the function name Cy_SystemInit inside cyfitter_cfg.c to Cy_UDBInit();and take everything out before: ClockInit();The function ClockInit(): take everything out before: /* Configure peripheral clock dividers */The remaining will be configuration of the UDBs, the IO's and the Peripheral clocks to the UDB.Copy the component API from Creator to a new source subfolder in Modus (something like ComponentAPI/).In the main source file call the new function UDBInit() and it works!

author: PartialDischarge
author_rank: Super Contributor
timestamp: August 31, 2019, 07:29:25 pm
content: Quote from: djacobow on August 29, 2019, 11:35:20 pmThe values asked for in the GUI (ok, most of them) are there to ease your life so you dont have to look up registers, or even know if it is a required value or not upon device startup. I can advise you to keep and eye on the Resource meter at the right side, it tells you what is implemented in UDBs or not. It depends since a timer for example can be implemented in UDBs but is also available as a hardware module. Also, right click on a module, open the datasheet and go to the API Interface section, you will see what can be changed via functions.

author: PartialDischarge
author_rank: Super Contributor
timestamp: August 31, 2019, 07:44:54 pm
content: Quote from: djacobow on August 29, 2019, 11:35:20 pmThat's common to most modules, required values are entered in the GUI, and then that value along the others are automatically loaded once the XXX_StartUp() function is called, no need to call more functions and thats the beauty of it, clean code, modules up and running fast.Of course all the available functions are generated as well in case you need them

author: djacobow
author_rank: Super Contributor
timestamp: August 31, 2019, 09:13:57 pm
content: Thanks, Mastertech! This is starting to make more sense now.I was able to set up my DMA to work and it works with buffers of different sizes, so I am happy.You seem to know a lot about PSOC. I have another question:My team wants me to implement some kind of abort() function for the receive DMA, where, ideally, after a call to abort() the isr would be called and then there would be some way to determine how many bytes were actually transferred, if any. I can disable the channel and/or the dma, but:1) I can't figure out how to determine how many bytes had been transferred. I thought maybe Cy_DMA_Descriptor_GetXloopDataCount() would return how many bytes were left to go, but it just contains what I had set it to at the start. Clearly, there is a register somewhere that keeps track of this, but maybe there is no hal function for it?2) I don't get an interrupt if I turn if I disable the DMA or DMA channel. This isn't that big of a deal, since I can just call back to the subscriber directly, but it would be nice to just have a way to force the DMA to stop and to issue the interrupt.As for Modus vs. Creator, well, I have not looked at Modus yet, but heard that it was not really complete so far. My opinion of Creator is not that high. It isincrediblyslow. Right now I am using it, but once I am no longer making design changes, I'm going to just copy out everything auto generated, and treat it as another input to a simple build environment with my own makefile. Also, I'd rather use gdb than their debugger.

author: DEV001
author_rank: Contributor
timestamp: August 31, 2019, 09:35:12 pm
content: Quote from: djacobow on August 31, 2019, 09:13:57 pmI just checked the DMA guide and I saw a mention of what you may be looking for but I haven't used the DMA functionality to know if it is correct.uint32 CyDmaGetDescriptorStatus(int32 channel, int32 descriptor)Parameter Value (Mask)DescriptionBitsCYDMA_TRANSFER_ INDEXNumber of data elements transferred by the descriptor. Counts up from 0 to Number of data elements. When a descriptor is done (Response is DONE), the field is set to ‘0’ when the descriptor is valid and the field is set to Number of data elements when Invalidate descriptor is selected for this descriptor. When a descriptor is not done (Response is NO_ERROR), the field reflects the progress of a data transfer. In case of erroneous behavior (RESPONSE is neither DONE or NO_ERROR), the field is not updated, but keeps its value to ease debugging.At descriptor initialization, this field should be set to zero. This is done by CyDmaSetConfiguration(), CyDmaValidateDescriptor(), and DMA_Start() API functions.This field allows software to read the progress of the data transfer. Note that descriptor source and destination addresses represent base addresses and are not modified during data transfer. However, this field is modified during data transfer and provides an offset wrt. the base addresses.[15:0]

author: djacobow
author_rank: Super Contributor
timestamp: August 31, 2019, 11:56:10 pm
content: Quote from: DEV001 on August 31, 2019, 09:35:12 pmThat all looks pretty good, but it appears to be from an older version of the PDL library. The 3.1.0 version has slightly different names and does not appear to offer such information.After grepping through all the cypress generated source in my computer there is nothing called CYDMA_TRANSFER_INDEX or anything like it. :-(

author: PartialDischarge
author_rank: Super Contributor
timestamp: September 01, 2019, 07:18:02 am
content: Quote from: djacobow on August 31, 2019, 09:13:57 pmThere has to be some internal variable that holds the transfer count, but no idea, skim the .h files and see if you find something. A dirty way of getting this count would be the following: set up another DMA channel transfer that runs in parallel with the other one, this one transfers the contents of a vector that contains 1,2,3,4,5... to a register. If you stop the transfer you will get the count in the register.There is a hardware termination pin in the DMA module, use that to stop the transfer.

author: djacobow
author_rank: Super Contributor
timestamp: September 01, 2019, 03:00:00 pm
content: I've gone through the headers very carefully. No register name that looks like the count or index it's present. Perhaps it's named something unintuitive.Parallel dma is an interesting idea. There is a way to trigger another engine on each transfer. Bit if a waste, but possible. Another thing i will try is successively lowering the requested count until it completes. A bit sloppy, and night not work at all, depending on the implementation. Third option is to configure dma engine to convert bytes from the uart to zero padded 16b, then pre color the buffer before starting the transfer. I can see how far it got by looking where the zeros stop. Also wasteful, though, and requires me to recopy the buffer back to bytes before giving back to app.

author: djacobow
author_rank: Super Contributor
timestamp: September 03, 2019, 02:32:42 pm
content: So, I got a response from an FAE on the Cypress forum. Surprisingly, there is no user accessible register with this information. I can connect a pwm counter to the trigger output of the receive dma engine and read that count. Seems wasteful, but there you go.Definitely an interesting architecture.

author: Gandalf_Sr
author_rank: Super Contributor
timestamp: October 26, 2019, 07:22:42 pm
content: I've done quite a bit professionally with PSoCs for the past 3 years, it's my go-to family now. I haven't used Modus yet, PSoC Creator does all I need and I know my way around it. I have not done much with DMA though. One thing I have figured out is how to set up shared RAM between the m4 and m0+ cores in the PSoC6, that is a topic that you would think they'd put more effort into given that the PSoC6 is dual core.I have also done a couple of projects that talk to a 64 MByte flash using quad SPI (as is used on 2 of the eval PCBs I use).I love the PSoC6, it's so powerful and I just keep on adding code to my big project and it never seems to run out of space.If there's something I can help with, just ask.