osyan wrote:I am using USART,DMA on at91sam7x256 and i need to use chained buffer to receive data like this:
...
Based on 4th byte i should change the Receive Next Counter Register
...
Whats my problem?

(1) You didn't read the datasheet carefully.
(2) Your code doesn't seem to write anything to the Next Pointer Register.
(3) Writing to the Next Counter Register after the ENDRX interrupt is too late! The transfer has probably already been terminated! Proper DMA chaining does not require the transfer to be (re)enabled for each buffer.

blue_z wrote:
(1) You didn't read the datasheet carefully.
(2) Your code doesn't seem to write anything to the Next Pointer Register.
(3) Writing to the Next Counter Register after the ENDRX interrupt is too late! The transfer has probably already been terminated! Proper DMA chaining does not require the transfer to be (re)enabled for each buffer.

Regards

Thanks for your answer.
The code above is just the USART_ISR.
I have initialized the next pointer register Once at the start of main routine as below:

To what?
Seems like you have two problems, and IMO the solutions may be mutually exclusive.

DMA chaining

Granted the Atmel datasheet could describe DMA chaining a lot better, since it's tersely described in one sentence with related details scattered in other paragraphs.
Some of it is ambiguous or misleading:

Programming the Next Counter/Pointer registers chains the buffers. The counters are decremented after each data transfer as stated above ...

Presumably "counters are decremented" refers only to the active PERIPH_RCR or PERIPH_TCR register, and not the PERIPH_RNCR and PERIPH_TNCR registers.

The key point is:

... but when the transfer counter reaches zero, the values of the Next Counter/Pointer are loaded into the Counter/Pointer registers in order to re-enable the triggers.

So when the PERIPH_RCR (the current count) decrements to zero,

(1) the nonzero value in PERIPH_RNCR (the backup count) is copied into PERIPH_RCR (the current count),
(2) the PERIPH_RNPR (the backup pointer) is copied into PERIPH_RPR (the current pointer),
(3) the data transfer continues with these new values in PERIPH_RCR & PERIPH_RPR,
(4) the PERIPH_RNCR (the backup count) is set to zero to inhibit another chaining operation unless PERIPH_RNCR is written again
(5) the ENDRX flag is set because the PERIPH_RCR register reached zero.

But if you haven't written anything to the PERIPH_RNCR (the backup count) before the current operation completes, then none of the above happens, since:

When the counter reaches zero, the transfer is complete and the PDC stops transferring data

To perform dynamic DMA chaining, you need to schedule a transfer to provide the time to calculate the next backup transfer parameters and load them into the DMA controller. That is, the "current" DMA transfer must span a time interval long enough to derive/calculate and then write the count and pointer for the "backup" DMA transfer. The "backup" transfer must be setup before the "current" transfer completes.

If you're extracting a value from data received in transfer #1, then that data is not (safely) available until after transfer #1 is complete. If DMA chaining is utilized, then that data is available while chained-transfer #2 is in progress. You could use that extracted value to setup a chained-transfer #3, but you must have setup an intermediate chained-transfer #2 to buy time to perform the necessary extraction & processing.

message framing

Your code requires the USART "device driver" to be cognizant of the message protocol (in order to extract a length value), and has the "device driver" receive intact message frames (as opposed to a stream of bytes).

Trying to detect and assemble the message frame in the device driver is typically a bad idea, and even worse in the ISR. That overloads the functionality of the device driver, and reduces modularity and abstraction layers.
Your ISR code may work with idealized input in a controlled environment for a homework assignment, but out in the real world, such simple code would not be robust enough to handle message-frame issues such as a loss of message byte alignment. Simplistic message-framing code can lead to occasional mysterious link failures that require manual intervention. Attempts to enhance the robustness of the framing code will add bulk to the ISR, which is not optimal for performance.

For example, in your ISR before bufferA[3] is written to PERIPH_RNCR, is there a check to verify that bufferA[0] is actually an ASCII SOH character indicating the (possible) start of a message? What recovery action does the ISR perform if bufferA[0] is not the expected SOH character (and by implication, bufferA[3] should not be used as a byte count)?

The USART device driver should only receive the data and store it in a buffer without trying to analyze or process it. Perform the scan for the message frame on this buffered data in a tasklet or a higher-level protocol layer.

.. Thanks you for the detailed reply. I am trying to get a double buffer scheme for an I2SC0 implementation on a SAMG55. I think you've answered my main question and that was when to write to the next buffer/counter. If I am reading this correctly there is no message that the next buffer pointer has been transferred. So the only solution is a scheduled write that has to occur when the lead buffer is being written out?

Thanks blue_z. Apologies for my bad terminology. I was referring to the TPR/TCR pointer/counter as 'main', not the NEXT buffer. I understand them a bit more now that I sort of have it working. As far as the Next counter and pointer being transferred to the main buffer pointer and counter.

The problem I am having is that I had intended to use an interrupt somehow to reload the Next params. I have it all working well in a polling loop but I wasn't able to get an interrupt to work as the handler was swamped with interrupts, even though I had only enabled TXEMPTY or only ENDTX. It seems interrupts were not cleared upon writing new values to the Next registers.

jonavarque wrote:I was referring to the TPR/TCR pointer/counter as 'main', not the NEXT buffer. ...
As far as the Next counter and pointer being transferred to the main buffer pointer and counter.

"Main" and "main buffer" might work for you, but the more common descriptor is "current". "Current" is not used in the Atmel HW datasheet, but is used in the Atmel Linux driver and is also what I'm used to using.
"Current" has a temporal attribute that "main" lacks.

jonavarque wrote:It seems interrupts were not cleared upon writing new values to the Next registers.

You should be able to check that by reading the status register before and after updating the next/backup count register.
Note that writing to the pointer registers will not reset the interrupt condition.

Main, Current... pretty much the same thing here... but.. ok, that wasn't my question though. I have had to take over someone else's design and I have very little time to get this wrapped up. All I want to know is how to accomplish interrupt driver buffer management for the I2S block. I find the manual woefully inadequate and I am under a massive deadline. I had it partially working but I was unable to control the interrupts

I'm back at this problem this morning so I will try to hack through it.

The manual says that the I2SC_SSR register is used to reset and interrupt but there are only 4 parameters in that register, RXOR, TXUR, RXORCH, TXURCH. I don't see how to reset from a TXBUFE, TXEN, ENDTX, etc. That's where I am confused.

i2s_callback_t TXReadyCB()
{
*((uint32_t *)0x40000218 ) = GetNextWaveBuf(); // gets the addr of the current ready buf
*((uint32_t *)0x4000021C ) = GetNextWaveBufLen(); // Gets the length
NVIC_ClearPendingIRQ(I2SC0_IRQn);//using this to clear the interrupt
ReadNext();// get the next data into the dirty buffer. (only one of 3 not in use for sure)
}