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...