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).

Note: In Null Write mode, the DBUFWF bit is clear only upon the completion of the write to the location specified in DMAxSRC.

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.

Figure 13-5. Null Write Mode
Note:
  1. Read from the address location specified in the DMAxSRC register and set the DBUFWF bit.
  2. Write to the address location specified in the DMAxDST register.
  3. Write to the address location specified in the DMAxSRC register and clear the DBUFWF bit.
  4. 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);    
}