Friday, October 21, 2011

AT91SAM7S SPI

There seems to be a huge bug in the AT91SAM7S documentation regarding SPI. When you do a software reset via the control register, it resets the mode register.
So, after a AT91C_BASE_SPI -> SPI_CR = AT91C_SPI_SWRST;, you need to do a AT91C_BASE_SPI -> SPI_MR = 0x00000001;

Here's code to get the SPI transfer working:
inline void spi_configure()
{
 AT91PS_SPI     pSPI = AT91C_BASE_SPI;
 static unsigned int perphA=
  ((unsigned int) AT91C_PA11_NPCS0   ) |
  ((unsigned int) AT91C_PA13_MOSI    ) |
  ((unsigned int) AT91C_PA12_MISO    ) |
  ((unsigned int) AT91C_PA14_SPCK    ); // Peripheral A

 AT91C_BASE_PIOA->PIO_ASR = perphA;  //set the SPI pins to the periphial functions
 AT91C_BASE_PIOA->PIO_PDR = (perphA);  //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;
 AT91C_BASE_SPI -> SPI_CR  = AT91C_SPI_SPIEN;
        AT91C_BASE_SPI -> SPI_MR  = 0x00000001; //Enable the MASTER mode
You can then see the transfers on the MOSI pin with:
unsigned int spi_test()
{
 AT91PS_SPI     pSPI = AT91C_BASE_SPI;
 unsigned int data=0x55555555;
 data = data & 0x010FFFFF; // mask non-used bits
 pSPI -> SPI_TDR = data;
 return(data);
}

The fact that a software reset changes the mode register is a pretty important thing to include in the documentation. It took me a week to figure out what was going on. I looked at the ATMEL SPI example, and it has the bug as well. Perhaps there was change between the Rev B and Rev C processors, such as the FLASH issue.

No comments:

Post a Comment