Friday, March 16, 2012

AT91SAM7S and 24 bit SPI transfer.

Most 16-bit DACs take a 24-bit word. After fighting with the PDC to get DMA working, I settled on a simpler solution. The following is an example of writing 24-bits to the SPI bus with an AT91SAM7S256.

unsigned int spi_24bit(unsigned int dacval)
{
 AT91PS_SPI     pSPI = AT91C_BASE_SPI;
 
 //set SPI pins 
 static unsigned int perphA=
  ((unsigned int) AT91C_PA11_NPCS0   ) |
  ((unsigned int) AT91C_PA13_MOSI    ) |
  ((unsigned int) AT91C_PA31_NPCS1   ) |
  ((unsigned int) AT91C_PA12_MISO    ) |
  ((unsigned int) AT91C_PA14_SPCK    ); // Peripheral A
 static unsigned int perphB= (unsigned int) AT91C_PA30_NPCS2 ;

 AT91C_BASE_PIOA->PIO_ASR = perphA;  //set the SPI pins to the peripheral functions
 AT91C_BASE_PIOA->PIO_BSR = perphB;  //set SPI port B pins.
 AT91C_BASE_PIOA->PIO_PDR = (perphA|perphB);  //disable GPIO from changing SPI pins.
 AT91C_BASE_PMC->PMC_PCER = ((unsigned int) 1 << AT91C_ID_SPI);  //enable SPI clock
 AT91C_BASE_SPI -> SPI_CR  = AT91C_SPI_SWRST;//Reset the SPI
 
 /*THIS IS A BIGGIE
 The SWRST bit clears the MR register to defaults!  
 This means that you need to re-enable master mode after you use the CR reset.
 */
 AT91C_BASE_SPI -> SPI_MR  = 0x00000003; //master and variable select
 AT91C_BASE_SPI -> SPI_CR  = AT91C_SPI_LASTXFER|AT91C_SPI_SPIEN;//enable SPI
 AT91C_BASE_SPI -> SPI_CSR[1]=0x00000808;  //keep CS low until new xfer.

 unsigned int databyte1=0;
 unsigned int databyte2=0;
 unsigned int databyte3=0;

 databyte1 = databyte1 | 0x000D0000;  // 0D selects CS1
 databyte2 = (dacval & 0x0000ff00);
 databyte2 = databyte2 >>8;
 databyte2 = databyte2 | 0x000D0000;
 databyte3 = dacval & 0x000000ff;
 databyte3 = databyte3 | 0x010D0000;  //toggle last transfer line.
 
 pSPI -> SPI_TDR = databyte1;
 while(!((pSPI -> SPI_SR)&0x00000002))
 { ;;  //wait for the data to be sent out}
 pSPI -> SPI_TDR = databyte2;
 while(!((pSPI -> SPI_SR)&0x00000002))
 { ;;  //wait for the data to be sent out}
 pSPI -> SPI_TDR = databyte3;
 while(!((pSPI -> SPI_SR)&0x00000002))
 {;;  //wait for the data to be sent out}
 return(dacval);
}