Tool/software: TI-RTOS
Hi TI experts,
I am trying to implement SPI slave under TI-RTOS driver environment with the below code.
Without semaphore methods using SW CSN pin triggering, instead, with HW CSN pin handling(that is, #define CC26X2R1_SATELLITE_SPI0_CSN IOID_12), I was able to see the data frame on MISO line with updated values from 'SPI_TRANSFER_COMPLETED'.
By the way, after adding the semaphore and SW CSN pin triggering((that is, #define CC26X2R1_SATELLITE_SPI0_CSN PIN_UNASSIGNED, instead,with #define Board_CSN_0 IOID_12), only the data frame on MISO line is always 0x00. And it shows always 'SPI_TRANSFER_FAILED' or no 'SPI_TRANSFER_COMPLETED'.
I didn't understand on how to avoid the 'Writes to Transmit FiFO can Lose data' on your errata sheet.
should I pad two bytes with 0x00 as dummy message ?
Thanks in advance,
Ji-won Lee
/*********************************************************************
* CONSTANTS
*/
#define TASKSTACKSIZE 1024
#define SPI_PACKET_COUNT 4
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
// Task data
Task_Struct SpiSlaveTask;
Char SpiSlaveTaskStack[TASKSTACKSIZE];
static Semaphore_Struct semSpiSlaveTaskAlert;
/*********************************************************************
* LOCAL VARIABLES
*/
SPI_Handle spiHandle;
SPI_Params spiParams;
SPI_Transaction spiTransaction;
uint16_t txBuf[SPI_PACKET_COUNT];
uint16_t rxBuf[SPI_PACKET_COUNT]; // Receive buffer
const uint8_t transferSize = SPI_PACKET_COUNT;
PIN_Handle pinHandle;
PIN_Config pinConfig[] = {
PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE | Board_CSN_0,
PIN_TERMINATE // Terminate list
};
static circularQueue_t RxQueueForSpiSlave;
void SPI_send(void * _txData, void * _rxData, size_t _size)
{
bool transferOK;
spiTransaction.count = _size;
spiTransaction.txBuf = _txData;
spiTransaction.rxBuf = _rxData;
transferOK = SPI_transfer(spiHandle, &spiTransaction);
if(!transferOK)
{
Display_print0(dispHandle, 0, 0, "[SPI Slave]generating failed!!!!!!\r\n");
//SPI_transferCancel(spiHandle);
}
}
// Chip select callback
static void chipSelectCallback(PIN_Handle handle, PIN_Id pinId)
{
bool transferOK = FALSE;
#if 0
// Release the chip select pin
PIN_remove(handle, pinId);
// Open SPI driver
spiHandle = SPI_open(Board_SPI0, &spiParams);
#endif
// Wake up the OS task
Semaphore_post(Semaphore_handle(&semSpiSlaveTaskAlert));
}
// SPI transfer callback
static void SpiTransferCbFxn(SPI_Handle handle, SPI_Transaction *transaction)
{
#if 0
// Close the SPI driver
SPI_close(handle);
// Add chip select back to the PIN driver
PIN_add(pinHandle, pinConfig[0]);
// Register chip select callback
PIN_registerIntCb(pinHandle, chipSelectCallback);
#endif
// Wake up the OS task
//Semaphore_post(Semaphore_handle(&semSpiSlaveTaskAlert));
if(transaction->status == SPI_TRANSFER_COMPLETED)
{
{
#if 1
static uint8 k = 0, j;
k++;
for (j = 0; j < SPI_PACKET_COUNT; j++ )
txBuf[j] = k;
SPI_send(txBuf, NULL, sizeof(txBuf));
#endif
}
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_COMPLETED] Count : %d\r\n", transaction->count);
}
else if(transaction->status == SPI_TRANSFER_STARTED)
{
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_STARTED] Count : %d\r\n", transaction->count);
}
else if(transaction->status == SPI_TRANSFER_CANCELED)
{
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_CANCELED] Count : %d\r\n", transaction->count);
}
else if(transaction->status == SPI_TRANSFER_FAILED)
{
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_FAILED] Count : %d\r\n", transaction->count);
/*
* # Timeout #
* Timeout can occur in ::SPI_MODE_BLOCKING, there's no timeout in ::SPI_MODE_CALLBACK.
* When in ::SPI_MODE_CALLBACK, the transfer must be cancelled by calling SPI_transferCancel().\n
* If a timeout happens in either ::SPI_SLAVE or ::SPI_MASTER mode,
* the receive buffer will contain the bytes received up until the timeout occurred.
* The SPI transaction status will be set to ::SPI_TRANSFER_FAILED.
*/
SPI_transferCancel(spiHandle);
}
else if(transaction->status == SPI_TRANSFER_CSN_DEASSERT)
{
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_CSN_DEASSERT] Count : %d\r\n", transaction->count);
/*
* if PARTIAL_RETURN is enabled, the transfer will end when chip select is deasserted.
* the SPI_Transaction.status and the SPI_transcation.count will be updated to indicate
* whether the transfer ended due to chip select deassertion and how many bytes were transferred.
*/
}
else if(transaction->status == SPI_TRANSFER_PEND_CSN_ASSERT)
{
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_PEND_CSN_ASSERT] Count : %d\r\n", transaction->count);
}
else if(transaction->status == SPI_TRANSFER_QUEUED)
{
Display_printf(dispHandle, 0, 0, "[SPI_TRANSFER_QUEUED] Count : %d\r\n", transaction->count);
}
else
{
Display_printf(dispHandle, 0, 0, "[TRANSFERRING] Count : %d\r\n", transaction->count);
}
}
uint16 spiSlaveRxDataCallback(void *p_rx_buffer,
uint16 length,
uint16 *p_additional_req_data_length)
{
uint8 rx_data;
//Display_printf(dispHandle, 6, 0, "\r\nlength(2): %x\r\n", length);
for (int8 i = 0; i < length; i++ )
{
getDataFromQueue(p_rx_buffer, &rx_data);
processRxSpiData(&rx_data, length);
}
*p_additional_req_data_length -= length;
/* Return the number of bytes that have been processed */
return length;
}
static void BLECentral_processSpiSlaveforMainNode(uint8_t length)
{
static uint16 length_to_be_handled = 0;
uint8 i = 0;
//Display_printf(dispHandle, 6, 0, "\r\nSPI data length: %d", length);
//while (length--)
for ( i = 0; i < length; i++ )
{
uint16 return_value = rxBuf[i];
uint8 rx_data = return_value & 0x00ff;
putDataToQueue(&RxQueueForSpiSlave, rx_data);
//Display_print1(dispHandle, 6, 0, "\r\nSPI data: %x", rx_data);
length_to_be_handled++;
//Display_printf(dispHandle, 6, 0, "\r\nSPI data(1): 0x%02x, length_to_be_handled: %x", rx_data, length_to_be_handled);
}
spiSlaveRxDataCallback((void*)&RxQueueForSpiSlave, length_to_be_handled, &length_to_be_handled);
}
/*********************************************************************
* @fn SpiSlaveFxn
*
* @brief Application task entry point for Huf SPI Slave
*
* @param a0, a1 - not used.
*
* @return None.
*/
Void SpiSlaveFxn(UArg arg0, UArg arg1)
{
bool transferOK = FALSE;
static int8 rxFifoCount = 0;
uint8_t i;
PIN_State pinState;
SPI_init();
SPI_Params_init(&spiParams);
spiParams.dataSize = 16; // 16-bit data size(4-bit ~ 16-bit)
spiParams.bitRate = 1000000; // 1MHz
spiParams.frameFormat = SPI_POL0_PHA0;
spiParams.mode = SPI_SLAVE;
spiParams.transferMode = SPI_MODE_CALLBACK;
spiParams.transferCallbackFxn = SpiTransferCbFxn;
// Configure the transaction
spiTransaction.arg = NULL;
spiTransaction.count = SPI_PACKET_COUNT; // maximum length is 1024 if stack size is enough.
spiTransaction.txBuf = txBuf;
spiTransaction.rxBuf = rxBuf;
// Open the SPI and initiate the first transfer
spiHandle = SPI_open(Board_SPI0, &spiParams);
if (spiHandle == NULL)
{
while(1); // SPI_open() failed
}
// Enable RETURN_PARTIAL
//SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);
// First echo message
for (i = 0; i < transferSize; i++) {
txBuf[i] = i + 1;
rxBuf[i] = i + 1;
}
#if 1
// Open PIN driver and configure chip select pin callback
pinHandle = PIN_open(&pinState, pinConfig);
PIN_registerIntCb(pinHandle, chipSelectCallback);
#endif
#if 1
SPI_send(txBuf, rxBuf, sizeof(txBuf));
#endif
// Wait forever
while (1) {
// Wait for an ALERT callback
// Allow application to sleep until receiving the desired number of characters.
Semaphore_pend(Semaphore_handle(&semSpiSlaveTaskAlert), BIOS_WAIT_FOREVER);
// all characters currently in the RX FIFO
rxFifoCount = SPI_PACKET_COUNT;
BLECentral_processSpiSlaveforMainNode(rxFifoCount);
}
}
void SpiSlaveCreateTask(void)
{
Task_Params taskParams;
// Configure the OS task
Task_Params_init(&taskParams);
taskParams.stack = SpiSlaveTaskStack;
taskParams.stackSize = sizeof(SpiSlaveTaskStack);
taskParams.priority = 1;
Task_construct(&SpiSlaveTask, SpiSlaveFxn, &taskParams, NULL);
// Create the semaphore used to wait for Sensor Controller ALERT events
Semaphore_Params semParams;
Semaphore_Params_init(&semParams);
semParams.mode = Semaphore_Mode_BINARY;
/* Construct APIs are given a data structure with which to store hte instance's variables.
* As the memory has been pre-allocated for the instance, error checking may not be required after constructing
*/
Semaphore_construct(&semSpiSlaveTaskAlert, 0, &semParams);
}