AT91SAM7X512's SPI peripheral gets disabled on write to SPI_TDR

Discussion in 'Embedded Systems and Microcontrollers' started by dor, Mar 18, 2010.

  1. dor

    Thread Starter Active Member

    Feb 20, 2009
    62
    0
    My AT91SAM7X512's SPI peripheral gets disabled on the X time (X varies) that I write to SPI_TDR.
    As a result, the processor hangs on the while loop that checks the TDRE flag in SPI_SR. This while loop is located in the function SPI_Write() that belongs to the software package/library provided by ATMEL.
    The problem occurs arbitrarily - sometimes everything works OK and sometimes it fails on repeated attempts (attemp = downloading the same binary to the MCU and running the program).

    Configurations are (defined in the order of writing):

    1. SPI_MR:
      • MSTR = 1
      • PS = 0
      • PCSDEC = 0
      • PCS = 0111
      • DLYBCS = 0
    2. SPI_CSR[3]:
      • CPOL = 0
      • NCPHA = 1
      • CSAAT = 0
      • BITS = 0000
      • SCBR = 20
      • DLYBS = 0
      • DLYBCT = 0
    3. SPI_CR:
      • SPIEN = 1

    After setting the configurations, the code verifies that the SPI is enabled, by checking the SPIENS flag.

    I perform a transmission of bytes as follows:
    Code ( (Unknown Language)):
    1. const short int dataSize = 5;
    2. // Filling array with random data
    3. unsigned char data[dataSize] = {0xA5, 0x34, 0x12, 0x00, 0xFF};
    4. short int i = 0;
    5. volatile unsigned short dummyRead;
    6.  
    7. SetCS3();    // NPCS3 == PIOA15
    8. while(i-- < dataSize) {
    9.     mySPI_Write(data[i]);
    10.     while((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
    11.     dummyRead = SPI_Read();    // SPI_Read() from Atmel's library
    12. }
    13. ClearCS3();
    14. /**********************************/
    15. void mySPI_Write(unsigned char data) {
    16.     while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
    17.     AT91C_BASE_SPI0->SPI_TDR = data;
    18.     while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE) == 0); // <-- This is
    19.     // where the processor hangs, because that the SPI peripheral is disabled
    20.     // (SPIENS equals 0), which makes TDRE equal to 0 forever.
    21. }[/i]
    Questions:

    1. What's causing the SPI peripheral to become disabled on the write to SPI_TDR?
    2. Should I un-comment the line in SPI_Write() that reads the SPI_RDR register?
      Means, the 4th line in the following code: (The 4th line is originally marked as a comment)
      Code ( (Unknown Language)):
      1. void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data)
      2. {
      3.     // Discard contents of RDR register
      4.     //volatile unsigned int discard = spi->SPI_RDR;
      5.    
      6.     // Send data
      7.     while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
      8.     spi->SPI_TDR = data | SPI_PCS(npcs);
      9.     while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0);
      10. }
    3. Is there something wrong with the code above that transmits 5 bytes of data?

    Please note:

    • The NPCS line num. 3 is a GPIO line (means, in PIO mode), and is not controlled by the SPI controller.
      I'm controlling this line by myself in the code, by de/asserting the ChipSelect#3 (NPCS3) pin when needed.
      The reason that I'm doing so is because that problems occurred while trying to let the SPI controller to control this pin.
    • I didn't use the PDC/DMA controller and prefer not using it.
    • I didn't reset the SPI peripheral twice, because that the errata tells to reset it twice only if I perform a reset - which I don't do. Quoting the errata:
    • I noticed that sometimes, if I put a delay before the write to the SPI_TDR register (in SPI_Write()), then the code works perfectly and the communications succeeds.

    Useful links:


    An example of initializing the SPI and performing a transfer of 5 bytes is highly appreciated and helpful.

    Thank you.

    Best regards,
    Dor.
     
Loading...