If what you require is secobd DMA to trigger right after first one is finished (but not at the same time), it should be possible. I dont remember exact register names, but following should be configurable:
Set both dmas to trigger from the same timer (i believe it should be possible, but never tried using same source for multiple dmas), chain them together (finishing first enables second and finishing second enables first - or just keep first enabled all the time).
If I remember correctly, you can set the second dma to accept triggers even while in disabled state, so it should trigger instantly after being enabled by first dma.
(Edit: DCHxCON.CHAED)
Alternatively, if triggering from same source would not work, you might get away by triggering second dma from first dma interrupt (as long as you set it to fire only from finished transfer).
Also, doubling timer frequency and using classic "ping-pong" chaining (1 enables 2, 2 enables 1, same trigger) would probably work as well (as long as you manage to latch out data before next trigger).
edit: Ok, got it working, tested on PIC32MZ2064DAS, because thats what I have at hand. It appears that triggering multiple DMAs from same source is totally ok. However using DMA interrupt to trigger DMA is NOT ok, because it requires to manualy clear DCHxINT in order to trigger again. Clearing it using another DMA wont work (at least it didnt for me).
I have put together following sample, it uses 3 DMAs in total. DMA0 feeds buffer (
data_in) to DMA1 and DMA2. DMA1 copies first two bytes from
buffer into
buffer_out, DMA2 does the same for second two bytes.
All DMAs react to _TIMER_2_VECTOR, but DMA0 has lower priority than DMA1 & DMA2, which seems to work fine (geting expected output). More testing is deffinitely required before using in production. :) If you can get any other trigger source for DMA0 (Input Change Notification from PMP WR pin should be fine), than I would advise doing so.
char __attribute__((coherent)) buffer[5] = { 0 };
char __attribute__((coherent)) buffer_out[5] = { 0 };
const char * data_in =
"A01\n" "B02\n" "C03\n" "D04\n" "E05\n" "F06\n" "G07\n" "H08\n" "I09\n";
void dma_init() {
PMD7bits.DMAMD = 0;
// setup timer
T2CON = (7 << _T2CON_TCKPS_POSITION); // 256 prescaler
TMR2 = 0;
PR2 = UINT16_MAX; // just using long timer to make sure I can catch change
T2CONSET = _T2CON_ON_MASK; // turn timer on
DMACON = (1 << _DMACON_ON_POSITION); // Enable DMA module if it hasn't been
DCRCCON = 0; // crc check module is disabled
/* DMA 0 - feeds buffer */
DCH0CON = 0;
DCH0ECON = (_TIMER_2_VECTOR << _DCH3ECON_CHSIRQ_POSITION) | // trigger cell transfer event on _DMA_2_VECTOR (when DMA2 finishes)
(1 << _DCH3ECON_SIRQEN_POSITION); // start on matching interrupt
DCH0CON = (2 << _DCH0CON_CHPRI_POSITION); // channel priority has to be lower than DMA1 & DMA2
DCH0CSIZ = 4; // copy 4 bytes at once
DCH0SSIZ = strlen(data_in);
DCH0SSA = KVA_TO_PA(data_in);
DCH0DSIZ = 4;
DCH0DSA = KVA_TO_PA(buffer); // feed into buffer
/* DMA 1 - sends byte 1 - 2 */
DCH1CON = 0;
DCH1ECON = (_TIMER_2_VECTOR << _DCH1ECON_CHSIRQ_POSITION) | // trigger cell transfer event on _TIMER_1_VECTOR
(1 << _DCH1ECON_SIRQEN_POSITION); // start on matching interrupt
DCH1CON = (1 << _DCH1CON_CHCHNS_POSITION) | // enable when higher dma finishes
(1 << _DCH1CON_CHCHN_POSITION) | // allow chaining
(3 << _DCH2CON_CHPRI_POSITION); // channel priority has to be higher than DMA0
DCH1CSIZ = 2; // cell size 2
DCH1SSIZ = 2; // source size is 2
DCH1SSA = KVA_TO_PA(buffer); // bytes 1-2 from buffer
DCH1DSIZ = 2; // dest size 2
DCH1DSA = KVA_TO_PA(buffer_out); // feed into uart
/* DMA 2 - sends byte 3 */
DCH2CON = 0;
DCH2ECON = (_TIMER_2_VECTOR << _DCH2ECON_CHSIRQ_POSITION) | // trigger cell transfer event on _TIMER_1_VECTOR
(1 << _DCH2ECON_SIRQEN_POSITION); // start on matching interrupt
DCH2CON = (0 << _DCH2CON_CHCHNS_POSITION) | // enable when lower dma finishes
(1 << _DCH2CON_CHCHN_POSITION) | // allow chaining
(1 << _DCH2CON_CHAED_POSITION) | // register start event when disabled
(3 << _DCH2CON_CHPRI_POSITION); // channel priority has to be higher than DMA0
DCH2CSIZ = 2; // cell size 2
DCH2SSIZ = 2; // source size 2
DCH2SSA = KVA_TO_PA(buffer + 2); // byte 3 - 4 from buffer
DCH2DSIZ = 2; // dest size 2
DCH2DSA = KVA_TO_PA(buffer_out + 2); // feed into uart
/* Start DMAs 0 & 1 */
DCH0CONSET = _DCH0CON_CHEN_MASK;
DCH1CONSET = _DCH1CON_CHEN_MASK;
while(1) {
uart_directf("OUT: %s" CRLF, buffer_out);
delay_us(100 * 1000);
}
}
post edited by Morce323 - 2021/01/15 06:07:05