Hello,
I refer to the last question of the linked topic regarding McBSP DMA.
In our system, a SPI slave is connected to the C2000 McBSP module who acts as a SPI master (through McBSP). In a periodic manner (each 1ms), the slave requests the SPI master to start a SPI transfer using a GPIO (external interrupt). The number of bytes transferred is 12 bytes. The SPI transfer is handled by DMA and started in the EXTI interrupt (coming from the slave). Since the C2000 is also controlling a motor, the time spent in the EXTI ISR must be as short as possible (= McBSP + DMA transfer initialization and start must be optimal).
The problem is: if I initialize the DMA channel only once at startup, the first transfer is correct (12 bytes sent) but the next transfers are incomplete: the first 4 bytes are missing (only 8 bytes sent).
Do you have any idea if there is something more than re-enabling the DMA channels (RUN = 1) in order to re-start the complete transfer?
Here is the DMA configuration:
dma->DMACTRL |= (1 << 0);
asm(" nop");
// Channel 1: McBSPA transmit
// ----------------------------------------------------------
dma->CH1.BURST_SIZE = 1U; // 2 16-bit word per burst
dma->CH1.SRC_BURST_STEP = 1; // increment 1 16-bit addr. between words
dma->CH1.DST_BURST_STEP = 1; // increment 1 16-bit addr. between words
dma->CH1.TRANSFER_SIZE = 2U; // Interrupt every (2 + 1) bursts (= 12 bytes).
dma->CH1.SRC_TRANSFER_STEP = 1; // Move to next word in buffer after each word in a burst.
dma->CH1.DST_TRANSFER_STEP = 0xFFFF; // Decrement back to McBSP DXR2 register.
dma->CH1.SRC_ADDR_SHADOW = (uint32_t)&p_txBuf[0];
dma->CH1.SRC_BEG_ADDR_SHADOW = (uint32_t)&p_txBuf[0]; // TODO (S) : not needed - to be checked.
dma->CH1.DST_ADDR_SHADOW = (uint32_t)&obj->mcbspAHandle->DXR2;
dma->CH1.DST_BEG_ADDR_SHADOW = (uint32_t)&obj->mcbspAHandle->DXR2; // TODO (S) : not needed - to be checked.
// Clear sync error flag
dma->CH1.CONTROL |= (1U << 7);
// Set to maximum to avoid any source/destination wrap.
dma->CH1.SRC_WRAP_SIZE = 0xFFFFU;
dma->CH1.DST_WRAP_SIZE = 0xFFFFU;
// dma->CH1.MODE |= (1U << 15); // Enable channel interrupt.
dma->CH1.MODE |= (1U << 9); // Generate interrupt at end of transfer.
dma->CH1.MODE |= (1U << 8); // Enable peripheral interrupt event.
dma->CH1.MODE |= (14U << 0); // DMA interrupt source: MXEVTA (McBSP transmission).
dma->CH1.CONTROL |= (1U << 4); // Clear any spurious interrupt flags.
// Channel 2: McBSPA receive
// ----------------------------------------------------------
dma->CH2.BURST_SIZE = 1U; // 2 16-bit word per burst
dma->CH2.SRC_BURST_STEP = 1; // increment 1 16-bit addr. between words
dma->CH2.DST_BURST_STEP = 1; // increment 1 16-bit addr. between words
dma->CH2.TRANSFER_SIZE = 2U; // Interrupt every (2 + 1) bursts (= 12 bytes).
dma->CH2.SRC_TRANSFER_STEP = 0xFFFF; // Decrement back to McBSP DRR2 register.
dma->CH2.DST_TRANSFER_STEP = 1; // Move to next word in buffer after each word in a burst.
dma->CH2.SRC_ADDR_SHADOW = (uint32_t)&obj->mcbspAHandle->DRR2;
dma->CH2.SRC_BEG_ADDR_SHADOW = (uint32_t)&obj->mcbspAHandle->DRR2; // TODO (S) : not needed - to be checked.
dma->CH2.DST_ADDR_SHADOW = (uint32_t)&p_rxBuf[0];
dma->CH2.DST_BEG_ADDR_SHADOW = (uint32_t)&p_rxBuf[0]; // TODO (S) : not needed - to be checked.
// Clear sync error flag
dma->CH2.CONTROL |= (1U << 7);
// Set to maximum to avoid any source/destination wrap.
dma->CH2.SRC_WRAP_SIZE = 0xFFFFU;
dma->CH2.DST_WRAP_SIZE = 0xFFFFU;
dma->CH2.MODE |= (1U << 15); // Enable channel interrupt.
dma->CH2.MODE |= (1U << 9); // Generate interrupt at end of transfer.
dma->CH2.MODE |= (1U << 8); // Enable peripheral interrupt event.
dma->CH2.MODE |= (15U << 0); // DMA interrupt source: MREVTA (McBSP reception).
dma->CH2.CONTROL |= (1U << 4); // Clear any spurious interrupt flags.
Here is the code used to re-start the transfer at each slave request:
ENABLE_PROTECTED_REGISTER_WRITE_MODE; dma->CH1.CONTROL |= (1U << 0); dma->CH2.CONTROL |= (1U << 0); DISABLE_PROTECTED_REGISTER_WRITE_MODE;
Here is the first transfer (complete):
Here is the next transfer (missing bytes):
Regards
