osyan wrote:but what can be the solution?
Seems like you have two problems, and IMO the solutions may be mutually exclusive.
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.
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
is written to PERIPH_RNCR, is there a check to verify that bufferA
is actually an ASCII SOH character indicating the (possible) start of a message? What recovery action does the ISR perform if bufferA
is not the expected SOH character (and by implication, bufferA
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.