Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: SPI & PDC, missing LSByte ?
PostPosted: Sun Jul 12, 2009 8:36 pm 
Offline

Joined: Wed Nov 09, 2005 11:34 am
Posts: 9
Hi All,

Im trying to make contact to a sensor through SPI.
To get a heads start, i modified the example code for my AT91SAM7S64-EK board, that talks to a AT26 type flash.

I changed some of the code ( chip select, clock polarity, etc ) to match the sensors datasheet.
When i request the temperature by issuing the command 0x0500, I can see this code going out to the sensor.
I see the sensor replying with also 16 bits of data with data that even makes sense.
The strange thing is, when i check the code on a scope, it correctly matches a reasonable
temperature (something like 0xC0A2). This value should be received by the PDC of the SPI,
but what i receive in the value i print out is 0xE00C0.
This C0 correctly matches the pattern of the data i need but im missing LSByte ?
When i change the read command to read a status or something, again, the pattern sent by
the controller is ok, the code returned by the sensor is ok, but only the first byte is shown in the log (in AT26_ReadStatus).

I have tried the same in loopback mode, but still the results are the same.
As you can see in AT26_ReadStatus, i print out the value of tmp before doing the transfer, then the transfer, then i check the value of tmp again.
The LSByte of tmp, is the MSByte of the 16 bit answer i need. Since i reset the value of tmp to fixed value 0x12345678, it
looks like more bits are clocked in ?


The main program is :

Code:
#include <board.h>
#include <dbgu/dbgu.h>
#include <pio/pio.h>
#include <aic/aic.h>
#include <utility/assert.h>
#include <utility/trace.h>
#include <utility/math.h>
#include <components/spi-flash/at26.h>
#include <utility/led.h>


#include <string.h>

//------------------------------------------------------------------------------
//         Internal definitions
//------------------------------------------------------------------------------

/// Maximum device page size in bytes.
#define MAXPAGESIZE     256

/// Address of the SPI peripheral connected to the AT26.
#define SPI_BASE        AT91C_BASE_SPI
/// Peripheral identifier of the SPI connected to the AT26.
#define SPI_ID          AT91C_ID_SPI
/// Chip select value used to select the AT26 chip.
#define SPI_CS          0
/// SPI peripheral pins to configure to access the serial flash.
#define SPI_PINS        PINS_SPI, PIN_SPI_NPCS0

//------------------------------------------------------------------------------
//         Internal variables
//------------------------------------------------------------------------------

/// SPI driver instance.
static Spid spid;

/// Serial flash driver instance.
static At26 at26;

/// Pins to configure for the application.
static Pin pins[] = {SPI_PINS, PINS_LEDS };

//------------------------------------------------------------------------------
//         Internal functions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
/// Interrupt service routine for the SPI peripheral. Forwards the interrupt
/// to the SPI driver.
//------------------------------------------------------------------------------
static void ISR_Spi(void)
{
    SPID_Handler(&spid);
}

//------------------------------------------------------------------------------
/// Reads and returns the status register of the serial flash.
/// \param pAt26  Pointer to an AT26 driver instance.
//------------------------------------------------------------------------------
static unsigned char AT26_ReadStatus(At26 *pAt26)
{
    unsigned char error;
    unsigned short tmp = 0x1234;

    trace_LOG(trace_INFO, "\n\r0x%X\n\r", tmp );

    SANITY_CHECK(pAt26);
   
    error = AT26_SendCommand(pAt26, 0x03, 2, (unsigned char*) &tmp, 2, 0, 0, 0); // AT26_ReadStatus
    ASSERT(!error, "-F- AT26_GetStatus: Failed to issue command.\n\r");

    // Wait for transfer to finish
    while (AT26_IsBusy(pAt26));

    trace_LOG(trace_INFO, "0x%X\n\r", tmp );
   
    return 0;
}
//------------------------------------------------------------------------------
///
//------------------------------------------------------------------------------
int main(void)
{
    // Configure the DBGU
    trace_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
    trace_LOG(trace_INFO, "------------------------------------------------\n\r");
    trace_LOG(trace_INFO, "Basic SPI test project\n\r");
   
    // Initialize the SPI and serial flash
    PIO_Configure(pins, PIO_LISTSIZE(pins));
    AIC_ConfigureIT(SPI_ID, 0, ISR_Spi);
    SPID_Configure(&spid, SPI_BASE, SPI_ID);

    unsigned int csr = (0x0F<<16) | (0x60<<8) /* | AT91C_SPI_NCPHA */  | AT91C_SPI_CPOL;
    SPID_ConfigureCS(&spid, 0x00, csr );

    AT26_Configure(&at26, &spid, SPI_CS);
   
    AIC_EnableIT(SPI_ID);
   
    trace_LOG(trace_INFO, "-I- SPI and AT26 drivers initialized\n\r");
    trace_LOG(trace_INFO, "Starting endless loop.\n\r");

    int sample = 0;
    int tmp;
    while( 1 )
    {
     
      for( unsigned d1 = 0; d1 < 3; d1++)
        for( unsigned d2 = 0; d2 < 32768; d2++)
          tmp += 1;

      LED_Toggle(0);

      AT26_ReadStatus(&at26);
    }
    return 0;
}



AT26_SendCommand:

Code:
unsigned char AT26_SendCommand( At26 *pAt26, unsigned char cmd, unsigned char cmdSize, unsigned char *pData, unsigned int dataSize, unsigned int address, SpidCallback callback, void *pArgument)
{
  SpidCmd *pCommand;
 
  SANITY_CHECK(pAt26);
 
  // Check if the SPI driver is available
  if (AT26_IsBusy(pAt26))
  {
    return AT26_ERROR_BUSY;
  }
 
  // Store command and address in command buffer
  pAt26->pCmdBuffer[0] = cmd;
  pAt26->pCmdBuffer[1] = 0x00;
 
  /*
  pAt26->pCmdBuffer[2] = 0x00;
  pAt26->pCmdBuffer[3] = 0x00;
  */ 
 
  // Update the SPI transfer descriptor
  pCommand = &(pAt26->command);
  pCommand->spiCs = 0x00;
  pCommand->cmdSize = cmdSize;
  pCommand->pData = pData;
  pCommand->dataSize = dataSize;
  pCommand->callback = callback;
  pCommand->pArgument = pArgument;
 
  // Start the SPI transfer
  if (SPID_SendCommand(pAt26->pSpid, pCommand))
  {
    return AT26_ERROR_SPI;
  }
  return 0;
}


and finally the SPID_SendCommand

Code:

unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
{
  AT91S_SPI *pSpiHw = pSpid->pSpiHw;
  unsigned int spiMr;
         
  // Try to get the dataflash semaphore
  if (pSpid->semaphore == 0)
  {
    return SPID_ERROR_LOCK;
  }
  pSpid->semaphore--;

  // Enable the SPI clock
  WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
 
  // Enable transmitter and receiver
  WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);

  // Write to the MR register
  spiMr = READ_SPI(pSpiHw, SPI_MR);
  spiMr |= AT91C_SPI_PCS;
  spiMr &= ~((1 << pCommand->spiCs) << 16);
  WRITE_SPI(pSpiHw, SPI_MR, spiMr);

  // Initialize the SPI PDC buffer

  // Transmit pointer register
  WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd);
 
  // Transmit counter register
  WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize);
 
  // Receive pointer register
  WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pData);

  // receive counter register
  WRITE_SPI(pSpiHw, SPI_RCR, pCommand->dataSize);

  // Initialize the callback
  pSpid->pCurrentCommand = pCommand;
 
  // Enable transmitter and receiver
  WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN);

  // Enable buffer complete interrupt
  WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF);
 
  return 0;   
}


with SPI-handler:

Code:
void SPID_Handler(Spid *pSpid)
{
  SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
  AT91S_SPI *pSpiHw = pSpid->pSpiHw;
  volatile unsigned int spiSr;

  // Read the status register
  spiSr = READ_SPI(pSpiHw, SPI_SR);   
  trace_LOG( trace_INFO, "Spi status after transfer : 0x%X\n\r", spiSr );
  if (spiSr & AT91C_SPI_RXBUFF)
  {
    // Disable transmitter and receiver
    WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
   
    // Disable the SPI clock
    WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
   
    // Disable buffer complete interrupt
    WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF);
   
    // Release the dataflash semaphore
    pSpid->semaphore++;
           
    // Invoke the callback associated with the current command
    if (pSpidCmd && pSpidCmd->callback)
    {
       pSpidCmd->callback(0, pSpidCmd->pArgument);
    }
                 
    // Nothing must be done after. A new DF operation may have been started
    // in the callback function.
  }
}


this results in:

0x1234 <== from AT26_ReadStatus
Spi status after transfer : 0x103F2 <== from SPID_Handler
0x00CA <== from AT26_ReadStatus

Where the CA is correct pattern.

Any help is greatly appreciated...


Top
 Profile  
 
 Post subject: Re: SPI & PDC, missing LSByte ?
PostPosted: Tue Jul 14, 2009 8:15 am 
Offline

Joined: Wed Nov 09, 2005 11:34 am
Posts: 9
I have made a workaround by using SPI without DMA.
Seems to be working perfectly.
So all the transfers are ok, but the DMA controller seems to not clock in all the data ?
Still would like to know what im doing wrong here!

Anyone ?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: Bing [Bot] and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: