TI E2E Community
Hercules™ Safety Microcontrollers
Hercules™ Safety Microcontrollers Forum
MibSPI with DMA
I am trying to setup MibSPI with the DMA and for some reason the DMA is not activated when I set the TXDMAENA bit in DMAxCTRL.
At first I setup a DMA channel 13 to work with MibSPI, but I was using the DMA just to copy the data from RAM into the SPI RAM. That worked fine as soon as I set the software trigger for channel 13.
At this point I set the DMA trigger for channel 13 to hardware, initialized the DMACTRL to 0x8B0d2000 (buffer 11, DMA req 13). The DMA requests are mapped at default (req 0 -> chan 0). The PCP is set the same way as it worked with the software trigger. I used the DMACNTLEN = 1 and DMACOUNT.ICOUNT = 64 (as I’m transferring 64 elements). As soon as I set TXDMAENA the DMACOUNT.COUNT becomes 65, but nothing happens on the DMA registers. I expect the PBACSA, PBACDA and PBACTC to be updated with the information from the PCP of DMA Ch 13, but it doesn’t. The control fields in the TX RAM buffer is set to 0xB80D (the DMA suppose to copy only the data part).
1. Why the MibSPI is not triggering the DMA channel?
2. The BUFIDx is set to the beginning of the RAM for the TG which I want to transfer to with the DMA. Is that the intention on the BUFIdx?
3. I don’t exactly understand the difference between Buffer Mode 1 and 5 (skip, or suspend), which one should I use?
4. If I want to transfer large amount of data without processor intervention, how the MibSPI handshakes with the DMA?
5. Do I need to define DMA frames the size of the SPI buffer of the TG I am using?
Hello Alex and thank you for your post.
I have asked one of our engineers who has created an example project of DMA-enabled SPI transfers to respond to your questions. In the meantime, have you reviewed the example code for suggestions? It can be found in the HalCoGen subfolder: C:\Program Files (x86)\Texas Instruments\Hercules\HALCoGen\vx.xx\examples
Thanks for the response.
I did look at the suggested example and I don’t see anything that I didn’t do per that example. However there are few components in that example that I don’t understand:
1. In my code I transfer bytes, so my element destination offset in the PCP is 4, but in your example you transfer 16 bit data, so to my understanding that offset should be 2, but you have it at 4. Why is that?
2. In your example the ICOUNT that goes to DMACTRL is 0 but the One Shot bit is set to 1. In the TRM it says that if this bit is 1, the length is defined by the ICOUNT in the MibSPI and not by the DMA controller. Why then the ICOUNT is set to 0?
3. The example does not show Buffer Mode settings since the function mibspiInit() is not provided and depends on setting done in Halcogen tool. What should be the Buffer Mode settings?
4. In the example AUTOINIT_ON = 1, in the TRM Auto-initiation mode is enabled when AIM = 0.
Which one is correct? Why example needs Auto-initiation mode enabled?
Clarifying on your questions :
1. Irrespective of if you are transferring bytes or half-words, the destination offset would always be 4.This is since the MibSPI RAM organisation has control bytes in between which we need to skip. If you need bytes you need to choose the element size and mibspi data length accordingly .
2. With one-shot enabled the length of the transfer would be ICOUNT +1 , for 0 it would be one. The user needs to change this based on the requirement.Although this doesn't seem to be documented well.
3. If you open the halcogen using the help, you would see the halcogen settings. I see the that this case uses default mibspi settings with chip_select as CS_NONE and you can vary the length as required and accordingly set the ICOUNT.
4. The AUTOINIT definition in the TRM is incorrect. AUTOINIT is ON with 1.We will correct this in the next revision.
Try with these changes and let me know how it goes.
Sorry for any delay from us. Any more queries are welcome.
In regards to you answers:
1. I understand now that the offset is always in bytes. I originally thought that the offset is in elements. It is called "element offset". It is a bit confusing. Maybe it can be clarified in the next TRM release.
2. In the example the buffer size is 127, so why is the ICOUNT set to 0 for 1 transfer?
3. My question was regarding the buffer mode (skip, suspend, always...).
Can you please provide answers to my fisrt email in this set (before Brian responded)?
I had a look into your first question.If you are using the TMS5703137x , you need to check with the data sheet on the DMA req line mapping.In the DMACTRL- try 0x8B07200 instead of 0x8B0D200 , the line should be 7 for req 13.
Try this out and share your experience on this ..Yes for 2. the ICOUNT should have been 127 (for 128) .
I will attempt to answer your questions in the original post.
1. Why the MibSPI is not triggering the DMA channel?
>> The MibSPI module supports 8 bidirectional DMA channels. These require actual 16 different hardware request connections to the DMA controller. These are labeled MIBSPI1 through MibSPI1 in the datasheet. You are trying to use MibSPI1 as the hardware request that is generated when a TX DMA condition occurs.
This MibSPI1 request line is actually mapped to the DMA request number 27, as shown in the datasheet in the DMA request mapping table.
So if you want the DMA channel 13 to be triggered by this DMA request, you have to program Ch13ASI in the DMA control register DREQASI3 to 27.
>> Yes, this is the first buffer that the DMA will transfer the data to.
>> Setting BUFMODE = 1 instructs the MibSPI to skip this buffer until new data is written to the TX DATA field of this buffer. The sequencer will move on to the next transmit buffer.
Setting BUFMODE = 5 instructs the MibSPI to suspend transfers until new data is written to the TX DATA field of this buffer. The sequencer will wait for the CPU or DMA to copy new data into the TX DATA field in this case.
>> The MibSPI allows you to transfer up to 64kB of data with a single DMA request. This is possible by first setting the "LARGE COUNT" field of the DMACNTLEN register in the MibSPI module. Once this field is set, the initial count of data to be transferred comes from the ICOUNT field of the DMAxCOUNT register (where x is the MibSPI DMA channel being used, channel 0 in your case). You can enable an interrupt from the DMA controller once the transfer is done.
>> This is completely application-specific. There is a great deal of flexibility in controlling the sequencer as it parses through the TX RAM (see BUFMODE field). There are also several choices for triggering any defined transfer group. The simplest usage would certainly be to wait until all buffers in a transfer group have been transmitted and to then generate a DMA request to refill these buffers for the next transfers.
I got to retest this issue and it still doesn’t work for me as I expect. The DMA is triggered now by the SPI, but if I set ICOUNT in the SPI DMACOUNT register, the SPI will only transfer one element and the group will be suspended. If I set the SPI ICOUNT to 0 then the MIBSPI will work properly. The DMA will always transfer per the control packet ITCOUNT, but what is going to happen if the ITCOUNT in the control packet is greater than the MIBSPI buffer size? According to the TRM the DMA should work of the SPI ICOUNT, but if I don’t set the DMA’s control packet ITCOUNT the DMA won’t transfer. Herea are my settings and what I oserved:
Just in case I modified the DMA channel to 3, so I will be under 8. Per the data sheet MibSpi1 is mapped to DMAREG[ 5].
I modified the defaults DMAREQx settings, swapping requests between channel 5 and 3 :
dmaREG->DREQASI0 = 0x00010205;
dmaREG->DREQASI1 = 0x04030507;
Then I set the following in the SPI registers:
spiReg->DMACTRL = 0x89032000;
spiReg->DMACNTLEN = 1;
spiReg->DMACOUNT = 63U << SHIFT16;
The control fields in the MIBSPI buffer is set to 0xB8 (suspend single transfer mode) in all data fields but last, where I raise the CS and release the lock bit.
Then I set the DMA control packet parameters (including ITCOUNT = 0x00010040).
Then I set DMA hardware trigger to channel 3
Then I set TXDMENA bit in spiReg->DMACTRL.
At this point the DMA channel is triggered and it transfers data per its control packet ITCOUNT into the MIBSPI buffer ignoring the SPI ICOUT value.
Then I set TGENA bit in the proper TGxCTRL register. At this point one element is transferred via SPI and the group is suspended.
If I do not set the DMACOUNT and DMACNTLEN then the SPI transfers all 64 bytes.
I will summarize my questions here:
Please excuse me for dropping the ball on this post.
Is it possible for you to upload or paste your routines for setting up the MibSPI and DMA transfers? I will have to try and replicate the behavior on my setup as I am not able to do so with a code example from our verification team.
I will answer some of your questions though:
>> Need to check once you paste/upload the code that sets up the DMA and MibSPI.
Thanks for the response.
I am attaching the driver files2055.MibSPI_DMA.zip.
I thought that I finally I understood how the MibSPI works, but what I tried after that, didn’t work either. I am currently using MibSPI/DMA only for writing data to MRAM. Here is how I understood the MibSPI/DMA should work:
If the process I described is incorrect, please correct me, or explain the process to me if all is wrong.
The problem I am having is this:
After I set the TXDMENA the DMA starts the transfer into the SPI TG buffers. After I enable the TG the ICOUNTx is loaded into COUNTx and the SPI is transmitting the first data batch. However, while the SPI is transmitting 64 bytes (size of my data is one byte), the COUNTx is decremented only one time. The TRM (spnu499 page 1543) claims that COUNTx represents the “actual number of DMA transfer that remain until the DMA channel is disabled”. Why COUNTx is decremented only once and never again?
The DMA is never triggered again and the TXDMENA is never cleared. No more transfers are happening on this TG after this one batch. The TG is waiting for new data to come from DMA and the DMA is waiting for SPI to trigger the DMA. Shouldn’t the DMA be triggered when the last buffer in the TG is transmitted?
Thanks for helping,
The MibSPI updates the COUNTx once each time that the buffer pointed by BUFIDx in the DMAxCTRL register is transferred through the MibSPI. The MibSPI does not keep track of how many buffers got transmitted before or after that particular buffer, so the behavior you are observing is correct. We will update the documentation to reflect this so that it is clearly explained.
In general, say the MibSPI needs to transfer 10 frames, each frame having 64 bytes of data. Then you need to configure MibSPI ICOUNT as 10, and the DMA controller needs to be configured to transfer 10 frames of 64 byte-elements. This way, each time the MibSPI requests a DMA transfer, there will be 64 bytes transferred to the MibSPI RAM. Also, the MibSPI will stop generating DMA requests after transmitting 10 frames.
Please also note that you need to enable the auto-initiation mode for the DMA channel being used for these transfers. Without this, the hardware channel enable in the HWCHENAS register gets cleared after the channel completes one block transfer.
Let me know if this helps.
It finally worked for me. In addition to what you mentioned, I had to disable the Oneshot mode in TGxCTRL, otherwise the SPI won't work after the first transmission. I also had to clear the NOBRK bit, otherwise the other groups could never be transmitted after the MibSPI group is started.
One last question I have regarding this. Is there any way to automatically reset the chip select after the block is transmitted? In my setup I transmit the data to the MRAM after the chip select was enabled with the previous group, but the only way I can see to clear the chip select is to create an interrupt routine that will be called at the end of the transmission and will do it manually. Is there a better way?
Thanks for the confirmation.
Are you driving the chip select as an I/O pin or as a SPI functional pin? If you are using the chip select as a SPI function, then you can drive it low and release it using the CSHOLD control field of the transmit buffer. You can choose to do this in the 64th buffer so that the chip select is released after every 64 transmissions. If you need to send multiple packets before releasing the chip select, you could trigger another DMA channel to write to the control field of the last buffer.
The only way I was able to disable the CS after the transfer, is using the SPI interrupt. Your suggestion to use another DMA channel doesn’t work because the chained DMA channel will be triggered after the first DMA transfer and not the whole block. I don’t understand why it is like that, since I set the transfer mode in the DMA PCP to Block.
I also tried to create another TG that is triggered after the SPI data transfer TG and I set the NOBRK bit in DMAxCTRL. The additional TG is resetting all CS, but the NOBRK bit set does not prevent it from transmitting at the end of the first data set. I was under impression, per the TRM, that this is exactly what it should do (not to let any other TG transmit until the all the data is transmitted and the COUNTx is 0). Do you have any explanation to that?
The other problem I had that in Suspend-Single Transfer mode I was not able to clear the INTFLGRDYx bit, because the group was suspended after the whole data transfer is finished. Is that how it supposed to work? I had to change the buffer to Skip-Single Transfer mode and in that mode after I clear the TGENA bit in the interrupt routine, only then I can clear the associated INTFLGRDY bit.
There is a very specific recipe to make this thing work and I spent a lot of time on it. There is no way you can figure it out from the TRM. To my opinion there should have been an assigned bit in the DMAxCTRL to make the CS release automatic at the end of the transfer.
Unfortunately, at this point I believe that MibSPI/DMA functionality is buggy on the processor I’m working on (TMS570LS3137). I thought that somehow I made it to work, but I did my test on two data sets of 64 bytes each and I believed that all I have to do now is increase the ICOUNT and Frame count to as many data sets as I need, but I was wrong. When I changed to three data sets it didn’t work already. In “skip” buffer mode, when NOBRK bit is not set, the group will generate INTRDY every two data sets, so you cannot use the interrupt for the transfer completion. When NOBRK bit is set, the number of actual SPI transfers is undefined. Although it works with two data sets, anything over that will give you unexpected results. Although, according to COUNTx it seems finishing the whole transfer, but from what you see on the oscilloscope you know that it is not true. It looks like the DMA does work properly. I don’t have any other group running on that SPI during this transfer. If I don’t use an interrupt to detect completion, then with the NOBRK bit off it will complete the whole transfer, but how do I know when? This is not working the way it should.
Are you aware of those issues?
Just to let you know, I was able to make it work eventually. I used DMA BTC interrupt to trigger the additional DMA channel that updates the buffer control field to release the chip select. Another thing that I found out is that the PCP of the DMA channel that does the transfer cannot be configured in Block mode, because then the DMA will transfer the whole block on each trigger. So although my code eventually works, please check with the developers the following issues that I found with the processor:
All content and materials on this site are provided "as is". TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with regard to these materials, including but not limited to all implied warranties and conditions of merchantability, fitness for a particular purpose, title and non-infringement of any third party intellectual property right. TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with respect to these materials. No license, either express or implied, by estoppel or otherwise, is granted by TI. Use of the information on this site may require a license from a third party, or a license from TI.
TI is a global semiconductor design and manufacturing company. Innovate with 100,000+ analog ICs andembedded processors, along with software, tools and the industry’s largest sales/support staff.