How to config Due SPI using SAM3X registers

I configured the SPI as follows, but I am constantly reading 0s from SPI_RDR, the RDRF flag was never raised either.

void setup() {
  Serial.begin(9600);
  
  //SPI serial recieve 
  REG_PMC_PCER0 |= PMC_PCER0_PID24;// Power up SPI clock
  REG_SPI0_WPMR = 0<<SPI_WPMR_WPEN;//Unlock user interface for SPI
  
  //Instance SPI0, MISO: PA25, (MISO), MOSI: PA26, (MOSI), SCLK: PA27, (SCLK), NSS: PA28, (NPCS0) 
  REG_PIOA_ABSR |= PIO_ABSR_P25; // Transfer Pin control from PIO to SPI
  REG_PIOA_PDR |= PIO_PDR_P25;   // Set MISO pin to an output

  REG_PIOA_ABSR |= PIO_ABSR_P26; // Transfer Pin control from PIO to SPI
  //REG_PIOA_PDR |= 0<<PIO_PDR_P26;   // Set MOSI pin to an input

  REG_PIOA_ABSR |= PIO_ABSR_P27; // Transfer Pin control from PIO to SPI
  //REG_PIOA_PDR |= 0<<PIO_PDR_P27;   // Set SCLK pin to an input

  REG_PIOA_ABSR |= PIO_ABSR_P28; // Transfer Pin control from PIO to SPI
  //REG_PIOA_PDR |= 0<<PIO_PDR_P28;   // Set NSS pin to an input
  
  REG_SPI0_CR |= SPI_CR_SPIEN; // Enable SPI
  REG_SPI0_MR = 0<<SPI_MR_MSTR; // Slave mode  
}

void loop() {
  // put your main code here, to run repeatedly:
  //if(REG_SPI0_SR&0x0001 == 1)
  //{
    int result = REG_SPI0_RDR;
    Serial.println(result);
    delayMicroseconds(1);
  //}
}

Due_Fast_PWM.ino.ino (2.96 KB)

Never mind I figure that out.
Here’s my code:

//SPI serial recieve 
  REG_PMC_PCER0 |= PMC_PCER0_PID24;// Power up SPI clock
  REG_SPI0_WPMR = 0<<SPI_WPMR_WPEN;//Unlock user interface for SPI
  
  //Instance SPI0, MISO: PA25, (MISO), MOSI: PA26, (MOSI), SCLK: PA27, (SCLK), NSS: PA28, (NPCS0) 
  REG_PIOA_ABSR |= PIO_ABSR_P25; // Transfer Pin control from PIO to SPI
  REG_PIOA_PDR |= PIO_PDR_P25;   // Set MISO pin to an output

  REG_PIOA_ABSR |= PIO_ABSR_P26; // Transfer Pin control from PIO to SPI
  REG_PIOA_PDR |= 0<<PIO_PDR_P26;   // Set MOSI pin to an input

  REG_PIOA_ABSR |= PIO_ABSR_P27; // Transfer Pin control from PIO to SPI
  REG_PIOA_PDR |= 0<<PIO_PDR_P27;   // Set SCLK pin to an input

  REG_PIOA_ABSR |= PIO_ABSR_P28; // Transfer Pin control from PIO to SPI
  REG_PIOA_PDR |= 0<<PIO_PDR_P28;   // Set NSS pin to an input

  //REG_ISER0 = 1<<24; //Enable interrupt controller
  REG_SPI0_CR = 1; // Enable SPI
  REG_SPI0_MR = 0; // Slave mode  
  REG_SPI0_IER = 1<<SPI_IER_RDRF|1<<SPI_IER_OVRES|1<<SPI_IER_NSSR; //Enable interrupts
  SPI0->SPI_CSR[0] = SPI_CSR_NCPHA|SPI_CSR_BITS_12_BIT; // Shift on falling edge and transfer 12 bits.
1 Like

Here is an example sketch to test SPI0 in loopback:

/********************************************************************************/
/**                SPI in local or remote loopback with interruptions          **/
/**                Connect MISO to MOSI pins on a single board                 **/
/********************************************************************************/


volatile uint32_t DataReceived;
volatile boolean Flag_SPI;

void setup() {

  Serial.begin(250000);
  
  PMC->PMC_PCER0 |= PMC_PCER0_PID24;    // SPI0 power ON
                  
  
  // Program the PIO controllers to assign
  // the SPI output pins to their peripheral functions (page 679)
  PIOA->PIO_PDR = PIO_PDR_P25
                  | PIO_PDR_P26
                  | PIO_PDR_P27
                  | PIO_PDR_P28;

  PIOA->PIO_ABSR &= ~(PIO_PA25A_SPI0_MISO
                      | PIO_PA26A_SPI0_MOSI
                      | PIO_PA27A_SPI0_SPCK
                      | PIO_PA28A_SPI0_NPCS0);

  // SPI Disable
  SPI0->SPI_CR = SPI_CR_SPIDIS;// SPI is in slave mode after software reset !!
  // Perform a SPI software reset twice, like SAM does.
  SPI0->SPI_CR = SPI_CR_SWRST;
  SPI0->SPI_CR = SPI_CR_SWRST;
  delay(10);

  // SPI0 operates in Master mode, local loopback
  SPI0->SPI_MR = SPI_MR_MSTR
                 | SPI_MR_MODFDIS             // Disable Mode Fault detection
                 | SPI_MR_WDRBT               // Wait data read before Transfer
                 | SPI_MR_LLB                 // Local loopback (MISO -->MOSI)
                 | SPI_MR_PCS(0b1110)
                 | SPI_MR_DLYBCS(0b01111111); // Maximum delay between Chip Selects

  // Data transfer parameters
  SPI0->SPI_CSR[0] |= SPI_CSR_CPOL          // Inactive state value of SPCK is logic level one
                      | SPI_CSR_NCPHA       // Data is captured on the leading edge of SPCK and changed on the following edge
                      | SPI_CSR_CSNAAT      // Chip select active after transfer
                      | SPI_CSR_BITS_16_BIT // Bits per transfer
                      | SPI_CSR_SCBR(100)   // slowest bit rate
                      | SPI_CSR_DLYBS(100); // Maximum delay from NPCS falling edge (activation)
                                            // to the first valid SPCK transition

  // Receive Data Register Full Interrupt and
  // Transmit Data Register Empty Interrupt Enable
  SPI0->SPI_IER = SPI_IER_RDRF | SPI_IER_TDRE;
  NVIC_EnableIRQ(SPI0_IRQn);

  SPI0->SPI_CR = SPI_CR_SPIEN;            // Enable SPI0

}

void loop() {

  if (Flag_SPI) {
    Serial.print(" Data Received = 0b"); Serial.println( DataReceived & 0xFFFF, BIN);
    Flag_SPI = false;
    delay(1000);
  }

}

void SPI0_Handler() {

  uint16_t DataSend = 0b1100110011001100;
  uint32_t status = SPI0->SPI_SR;

  if ((status & SPI_SR_TDRE) == SPI_SR_TDRE) SPI0->SPI_TDR |= SPI_TDR_TD(DataSend);
  if ((status & SPI_SR_RDRF) == SPI_SR_RDRF) {
    DataReceived = SPI0->SPI_RDR & SPI_RDR_RD_Msk;
    Flag_SPI = true;
  }
}