13.4.10.2 Null Write Mode
Some communication protocols require symmetrical buffer accesses; that is, for every read operation performed on a buffer, there must be an accompanying write operation. An example of this requirement occurs with the SPIx module operating in Host mode. When the SPIx module is configured for Host mode, and only received data is of interest, some data must be written to the SPIx transmit buffer in order to start the SPIx clock and receive the external data. In this situation, use Null Data Write mode of the DMA.
The Null Write mode is used to satisfy this requirement. This mode works by transferring
data from the address in DMAxSRC to the address in DMAxDST, like any other DMA
operation. Once this is done, however, the transferred data that are still stored in
DMABUF are written back to the address specified by DMAxSRC. The write-back occurs
before the DMA proceeds to its next transfer. A typical example of this is shown in
Figure 13-5. Null Write mode is enabled by
setting the flow control bits to ‘01
’ (FLWCON[1:0] =
01
).
Figure 13-5 illustrates the basic DMA data flow in Null Write mode. In Null Write mode, both load and store transactions are initiated to the address location specified in DMAxSRC.
- Read from the address location specified in the DMAxSRC register and set the DBUFWF bit.
- Write to the address location specified in the DMAxDST register.
- Write to the address location specified in the DMAxSRC register and clear the DBUFWF bit.
- Repeat until completion.
Null Write Mode shows sample code for Null Write Mode working with SPI. In this configuration, no DMA request is issued until the first block of SPIx data is received. However, in Host mode, no data is received until the SPIx transmits first. To initiate the DMA transfers, the user application must use DMA Null Data Write mode and start DMA Manual Transfer mode.
Null Write Mode
#include <xc.h> #include<stdint.h> uint32_t RXREG[4]; uint32_t temp = 0xABCD; #define BRG (uint32_t) (1000) void DMA_Init(void); void SPI1_Host_Init(void); void SPI1_Host_Init(void) { //Both RX and TX pins are mapped to same pin for LoopBack _RP27R = 14; //re-mapping RP27 as SCK2 _RP42R = 13; //re-mapping RP42 as SDO2 _SDI1R = 42; //re-mapping RP42 as SDI2 SPI1CON1bits.MSTEN = 1; //Host mode SPI1BRG = BRG; // use FPB/4 clock frequency SPI1CON1bits.MODE16 = 0; SPI1IMSKbits.SPIRBFEN = 1; //Transmit buffer empty generates an interrupt event SPI1CON1bits.SPIEN = 1; //Enables module } void DMA_Init(void) { DMACONbits.ON=1; //DMA module is enabled DMAHIGH=0x5000; //set lower and upper address limit DMALOW=0x0000; DMA0CNT = 3; // Number of bytes received DMA0CHbits.SIZE = 0; //8bit DMA0SRC=(uint32_t)&SPI1BUF; // Source address DMA0DST=(uint32_t)&RXREG; // Destination address DMA0CHbits.SAMODE = 0; // DMAxSRC remains unchanged after a transfer completion DMA0CHbits.DAMODE = 1; // DMAxDST is incremented based on the SIZE bit after a transfer completion DMA0CHbits.TRMODE = 0; // Transfer mode,One-Shot mode DMA0CHbits.FLWCON = 0b01; //Null-Write mode DMA0SELbits.CHSEL = 0x6; //Trigger on SPI1 Receive Interrupt DMA0CHbits.CHEN = 1; //DMA Channel is enabled } int main(void) { DMA_Init(); SPI1_Host_Init(); SPI1BUF = 0xAB; //The first write needs to be initiated by SPI (Master) for receive to happen while(!DMA0STATbits.DONE); // Indicates DMA Channel 0 has completed all the transactions while(1); }