This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DMA parameter reload options

Other Parts Discussed in Thread: ADS8568

Hi,

I have been developing driver for ADS8568 with SPI interface. The DSP is C6748 and OS is DSPBIOS.

The ADC is 16-bit, 8-channel simultaneous. It requires CONVST signal to start conversion and it sends EOC signal to indicate conversion is done. Then 128-bit data (conversion results for 8 channels) is ready to read by host. Host needs to send 128 serial clock to read the result over SPI bus.

All the operations of driver are performed by peripherals without utilizing DSP core. The operation sequence of my driver is;

1 - Set timer output to provide CONVST signal.

2 - Capture EOC signal-comes from ADC when it done conversion-by GPIO interrupt.

3 - EOC signal-GPIO interrupt-triggers an EDMA channel to send dummy bytes. (At this step I need to write 128 serial clock to be able to read 128 data bits from the ADC)

4 - SPI RX interrupt triggers an EDMA channel to get the conversion result from SPI RX buffer to RAM.

5 - Go to interrupt handler after acquiring n data from SPI RX buffer to RAM and post semaphore.

At the step 3, I need 128 serial clocks. To write more dummy bytes to SPI TX register, DSP has to wait until SPI transmit is completed. I used SPI TX EDMA channel to solve that. SPI transmit interrupt triggers the EDMA channel and I have 128 serial clocks.

The problem is I couldn't reload SPI TX EDMA parameters automatically. If I link and reload parameters, I create a deadlock. The EDMA triggered by SPI transmit interrupt and then transmits one more. I don't want to use interrupt service routine to reload the EDMA parameters. I couldn't figure out how to reload.

I hope I could explain my problem. I need your support. Please ask me If you find the explanation is unclear.

Thanks in advance

Serdar

  • I believe I understand your issue.  Although fundamentally you're trying to do something fairly simple, the solution is fairly involved.  The complication comes from the fact that the SPI peripheral will constantly be trying to ask for more data.  However, you need to "throttle" the sending of data based off a GPIO interrupt happening elsewhere.

    So here's how I think about solving this issue:

    1. You need a means of enabling the EDMA channel when the GPIO interrupt occurs and a way of disabling the EDMA channel once you've serviced the data converter (i.e. sent your 128 bit clocks).
    2. The enabling/disabling of a channel happens through the EER/EESR/EECR registers.  You didn't mention which specific SPI port you're using.  Let's assume SPI0 for the moment.  SPI0 Transmit is Event #15 for the EDMA.  Therefore you would enable this event by writing EESR = 1<<15.  You would disable the event by writing EECR = 1<<15.
    3. Instead of using CPU to enable/disable the event you can use the EDMA itself.  In particular, you just put the 32-bit value you're writing (1<<15) into a memory location and use that memory location as the source address of a transfer.  You can then use EESR or EECR as the destination (depending on whether you're setting or clearing).
    4. To start the transfers, you wait for your GPIO event.  In fact, if you're not using any other GPIO that same bank then potentially you could directly initiate the DMA transfer from the GPIO, i.e. no interrupt needed!  If you need the ISR for some reason then I wouldn't bother setting up EDMA for this part of it.  I would simply write EESR = 1<<15 to enable the SPI0 transmit channel.  You should have an event pending in the ER from the last round (or from having taken the SPI transmitter out of reset during startup), and so the moment you enable this channel it should begin transferring data.
    5. To stop the transfer, you can have your SPI parameter set chain to a separate parameter set, i.e. OPT.TCCHEN=1 and TCC equals the channel number you're chaining to.  That will cause that channel to run IMMEDIATELY.  This transfer should be setup to write EECR = 1<<15.  That way it will shut off the transfers.
    6. So once step #5 has completed the EDMA will no longer be servicing SPI0 because you will have disabled that channel.  You will also have a SPI0 Tx Event pending in ER[15] because it never was serviced once you disabled the channel.  This will allow you to continue in this manner indefinitely.

    The receive channel should be very straight forward.  All the hard work is already done on the transmit side.

  • Hi Brad,

    Your answer is great. This is exactly what I was looking for. I implemented that and it works flawless.

    Thanks

    Serdar

  • Wow, great job!  I was expecting 2 or 3 rounds of questions to get it all working properly.  Very impressive work!  Thanks for reporting back the results.  Was there any subtlety that I missed in my initial reply that might be helpful to other people with this same issue?  Anything that tripped you up?

  • After 5 days of testing, I have no issue. Your answer is pretty clear and complete.

    I set ESR register for first triggering SPI Tx DMA channel and then event pending bit sustains, as you sad.

    Sometimes ADC channel order gets shifted on my buffers at reset or reprogram while emulating. SPI Rx DMA makes one more shot before or during initialization. I guess I couldn't clear all the necessary registers. I set EECR register to clear pending events before enable DMA channels but the problem persists. 'System Reset' button on CCS solves the issue.

  • serdar said:
    I set ESR register for first triggering SPI Tx DMA channel and then event pending bit sustains, as you sad.

    Did you mean EESR?  Writing to ESR (Event Set Register) actually initiates the transfer immediately.  Writing to EESR (Event Enable Set Register) just enables the event.  The intent however, is that the event should already be pending in the ER (Event Register) and so it should then be serviced immediately.

    serdar said:
    I set EECR register to clear pending events before enable DMA channels but the problem persists. 'System Reset' button on CCS solves the issue.

    Note that writes to EECR (Event Enable Clear Register) will simply result in disabling the event, i.e. it will not clear a pending event from the ER.  To clear an event from ER you would need to write the ECR (Event Clear Register).  You need to make sure you do this at the proper time though.  In particular, we actually want to have an event pending such that when you enable the SPI Tx Event through EECR that it immediately performs the transfer.  The event gets latched at the moment when you take the SPI out of reset, so if you're going to clear an event then it should be done prior to taking the SPI out of reset.

    Along those lines, if you're doing a lot of reloading/restarting of your program, I suspect it's actually the SPI that's the issue, i.e. make sure your startup code resets the SPI.  Personally, I find it a good practice to reset all the peripherals you're using through the PSC in your initialization code.  That way everything always gets set back to a known state.

  • It's so great I found this right thread. I'm working on the similar project as serdar: using the LCDK c6748 to read data from SPI1, and I want to use EDMA.

    I just began to study the TI's chip. Until now, with normal interrupt from StarterWare SPI example, I can read the SPI correctly, and the speed is acceptable; but you know, with interrupt I can't do other things anymore.

    However, the StarterWare SPI EDMA example can't work correctly on my LCDK c6748. Sometime it can read, but the data are no meaning at all; sometime it is locked and waiting flagRX; sometime it go to the EDMA3 Error Interrupt Service Routine(ISR).

    Brad, do you have any idea about what the wrong is?

  • Also, if I put a breakpoint in the  Edma3ComplHandlerIsr() function, it will not looked at the flagRX checking, and some data can make sense to me; still the program will run into Edma3CCErrHandlerIsr() at each cycle.

    If I remove the breakpoint in the Edma3ComplHandlerIsr() function, it will looked at the flagRX checking again.

    The flagRX checking is at SPI reading:  -- GetStatusCommand() and ResetCommand() functions.

        /* Wait until both the flags are set to 1 in the callback function. */
        while((0 == flagTx) || (0 == flagRx));

  • I think I found the problems of the example codes. Forget my questions.