This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/CC2650: Linking problem

Part Number: CC2650
Other Parts Discussed in Thread: SYSBIOS, CSD

Tool/software: TI C/C++ Compiler

Hello,

I am trying to implement SDSPI to CC2650. I took code from several sources and tried to get over the compilation problems 

but now I face a linking problem I do not understand.

undefined first referenced
symbol in file
--------- ----------------
SDSPI_config C:/ti/tirtos_cc13xx_cc26xx_2_18_00_03/products/tidrivers_cc13xx_cc26xx_2_16_01_13/packages/ti/drivers/lib/drivers_cc26xxware.aem3<SDSPI.oem3>

I don't know where did he get the small c because whenever there is a "SDSPI_Config" it's with a capital C.

I will give you the code from the SDSPI.h and SDSPI.c (and the call from the task):

SDSPI.c:

/*
* Copyright (c) 2013, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*-----------------------------------------------------------------------*/
/* MMC/SDC (in SPI mode) control module (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/

#include <xdc/std.h>
#include <xdc/runtime/Assert.h>
#include <xdc/runtime/Diags.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/Types.h>
#include <xdc/runtime/Timestamp.h>

#include <ti/drivers/SDSPI.h>

#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/hal/Hwi.h>

/* driverlib header files */
#include <inc/hw_memmap.h>
#include <inc/hw_types.h>
#include <driverlib/gpio.h>
#include <driverlib/ssi.h>
/*#include <driverlib/sysctl.h>*/
#include "C:\ti\tirtos_cc13xx_cc26xx_2_18_00_03\products\tidrivers_cc13xx_cc26xx_2_16_01_13\packages\ti\mw\fatfs\ffconf.h"

typedef enum SDSPITiva_CardType {
NOCARD = 0,
MMC = 1,
SDSC = 2,
SDHC = 3
} SDSPITiva_CardType;

#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GPIO_DIR_MODE_IN 0x00000000 // Pin is a GPIO input
#define GPIO_DIR_MODE_OUT 0x00000001 // Pin is a GPIO output
#define GPIO_DIR_MODE_HW 0x00000002 // Pin is a peripheral function

typedef enum {
FR_OK = 0,
FR_DISK_ERR,
FR_INT_ERR,
FR_NOT_READY,
FR_NO_FILE,
FR_NO_PATH,
FR_INVALID_NAME,
FR_DENIED,
FR_EXIST,
FR_INVALID_OBJECT,
FR_WRITE_PROTECTED,
FR_INVALID_DRIVE,
FR_NOT_ENABLED,
FR_NO_FILESYSTEM,
FR_MKFS_ABORTED,
FR_TIMEOUT,
FR_LOCKED,
FR_NOT_ENOUGH_CORE,
FR_TOO_MANY_OPEN_FILES,
FR_INVALID_PARAMETER
}FRESULT;

#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */

typedef unsigned short WORD;


typedef unsigned char BYTE;

/* Status of Disk Functions */
typedef BYTE DSTATUS;

/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;

typedef unsigned long SDSPIBaseAddrType;
typedef unsigned long SDSPIDataType;
typedef unsigned long DWORD;

typedef struct FATFS {
BYTE fs_type;
BYTE drv;
BYTE csize;
BYTE n_fats;
BYTE wflag;
BYTE fsi_flag;
WORD id;
WORD n_rootdir;
_SYNC_t sobj;
DWORD last_clust;
DWORD free_clust;
DWORD n_fatent;
DWORD fsize;
DWORD volbase;
DWORD fatbase;
DWORD dirbase;
DWORD database;
DWORD winsect;
BYTE win [_MAX_SS];
} FATFS ;


typedef struct SDSPITiva_Object {
uint32_t driveNumber;
DSTATUS diskState;
SDSPITiva_CardType cardType;
uint32_t bitRate;
FATFS filesystem;
} SDSPITiva_Object, *SDSPITiva_Handle;


/* Used to check status and initialization */
static Int SDSPI_count = -1;

/* Definitions for MMC/SDC command */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */

#define SD_SECTOR_SIZE 512

#define START_BLOCK_TOKEN 0xFE
#define START_MULTIBLOCK_TOKEN 0xFC
#define STOP_MULTIBLOCK_TOKEN 0xFD

#define DRIVE_NOT_MOUNTED ~0

/*
* Array of SDSPI_Handles to determine the association of the FatFs drive number
* with a SDSPI_Handle
* _VOLUMES is defined in <ti/sysbios/fatfs/ffconf.h>
*/
static SDSPI_Handle sdspiHandles[_VOLUMES];

/* ms scaling to function timeouts */
static Bits32 mSScalingFactor = 0;

/* Function prototypes */
static UInt rcvr_datablock(SDSPITiva_HWAttrs const *hwAttrs,
UChar *buf, UInt btr);
static inline Void releaseSPIBus(SDSPITiva_HWAttrs const *hwAttrs);
static inline UChar rxSPI(SDSPITiva_HWAttrs const *hwAttrs);
static UChar send_cmd(SDSPITiva_HWAttrs const *hwAttrs, UChar cmd,
ULong arg);
static Void send_initial_clock_train(SDSPITiva_HWAttrs const *hwAttrs);
static inline Void takeSPIBus(SDSPITiva_HWAttrs const *hwAttrs);
static inline Void txSPI(SDSPITiva_HWAttrs const *hwAttrs, UChar dat);
static UChar wait_ready(SDSPITiva_HWAttrs const *hwAttrs);
static UInt xmit_datablock(SDSPITiva_HWAttrs const *hwAttrs,
const UChar *buf, UChar token);

/* FatFs disk I/O functions */
DSTATUS SDSPITiva_diskInitialize(UChar drv);
DRESULT SDSPITiva_diskIOctrl(UChar drv, UChar ctrl, Void *buf);
DRESULT SDSPITiva_diskRead(UChar drv, UChar *buf, ULong sector,
UChar count);
DSTATUS SDSPITiva_diskStatus(UChar drv);
DRESULT SDSPITiva_diskWrite(UChar drv, const UChar *buf,
ULong sector, UChar count);

/* SDSPITiva functions */
Void SDSPITiva_init(SDSPI_Handle handle);
SDSPI_Handle SDSPITiva_open(SDSPI_Handle handle, UInt drv, SDSPI_Params *params);
Void SDSPITiva_close(SDSPI_Handle handle);

/* SDSPI function table for SDSPITiva implementation */
const SDSPI_FxnTable SDSPITiva_fxnTable = {
SDSPITiva_init,
SDSPITiva_open,
SDSPITiva_close,
};

/* Default SDSPI params */
extern const SDSPI_Params SDSPI_defaultParams;

/*
* ======== rcvr_datablock ========
* Function to receive a block of data from the SDCard
*
* btr count must be an even number
*/
static UInt rcvr_datablock(SDSPITiva_HWAttrs const *hwAttrs, UChar *buf,
UInt btr)
{
UChar token;
Bits32 timeoutLimit;

/* Wait for data packet in timeout of 100 ms */
timeoutLimit = Timestamp_get32() + 100 * mSScalingFactor;
do {
token = rxSPI(hwAttrs);
} while ((token == 0xFF) && (Timestamp_get32() <= timeoutLimit));

if (token != START_BLOCK_TOKEN) {
/* If not valid data token, return error */
return (0);
}

/* Receive the data block into buffer */
do {
*(buf++) = rxSPI(hwAttrs);
} while (--btr);

/* Read the CRC, but discard it */
rxSPI(hwAttrs);
rxSPI(hwAttrs);

/* Return with success */
return (1);
}

/*
* ======== releaseSPIBus ========
* Function to release the SPI bus
*
* @param hwAttrs Pointer to hardware attributes
*/
static inline Void releaseSPIBus(SDSPITiva_HWAttrs const *hwAttrs)
{
/* Deselect the SD card. */
GPIOPinWrite(hwAttrs->portCS, hwAttrs->pinCS, hwAttrs->pinCS);
}

/*
* ======== rxSPI ========
* Function to receive one byte onto the SPI bus. Polling (Blocked)
*
* @param hwAttrs Pointer to hardware attributes
*/
static inline UChar rxSPI(SDSPITiva_HWAttrs const *hwAttrs)
{
SDSPIDataType rcvdat;

/* write dummy data */
SSIDataPut(hwAttrs->baseAddr, 0xFF);

/* read data frm rx fifo */
SSIDataGet(hwAttrs->baseAddr, &rcvdat);

return ((UChar)rcvdat);
}

/*
* ======== send_cmd ========
* Function that will transmit an command to the SDCard
*
* @param hwAttrs Pointer to hardware attributes
*
* @param cmd SD command
*
* @param arg SD command argument
*/
static UChar send_cmd(SDSPITiva_HWAttrs const *hwAttrs, UChar cmd, ULong arg)
{
UChar n;
UChar res;

if (wait_ready(hwAttrs) != 0xFF) {
Log_print1(Diags_USER1, "SDSPI:(%p) send_cmd: SD card wait time expired",
hwAttrs->baseAddr);
return (0xFF);
}

/* Send command packet */
txSPI(hwAttrs, cmd); /* Command */
txSPI(hwAttrs, (UChar)(arg >> 24)); /* Argument[31..24] */
txSPI(hwAttrs, (UChar)(arg >> 16)); /* Argument[23..16] */
txSPI(hwAttrs, (UChar)(arg >> 8)); /* Argument[15..8] */
txSPI(hwAttrs, (UChar)arg); /* Argument[7..0] */

if (cmd == CMD0) {
/* CRC for CMD0(0) */
n = 0x95;
}
else if (cmd == CMD8) {
/* CRC for CMD8(0x1AA) */
n = 0x87;
}
else {
/* Default CRC should be at least 0x01 */
n = 0x01;
}

/* Future enhancement to add CRC support */
txSPI(hwAttrs, n);

/* Receive command response */
if (cmd == CMD12) {
/* Skip a stuff byte when stop reading */
rxSPI(hwAttrs);
}

/* Wait for a valid response in timeout; 10 attempts */
n = 10;
do {
res = rxSPI(hwAttrs);
} while ((res & 0x80) && --n);

/* Return with the response value */
return (res);
}

/*
* ======== send_initial_clock_train ========
* Function to get the SDCard into SPI mode
*
* @param hwAttrs Pointer to hardware attributes
*/
static Void send_initial_clock_train(SDSPITiva_HWAttrs const *hwAttrs)
{
UInt i;
SDSPIDataType dat;

/* Deselect the SD card. */
GPIOPinWrite(hwAttrs->portCS, hwAttrs->pinCS, hwAttrs->pinCS);

/* Switch the SPI TX line to a GPIO and drive it high too. */
GPIOPinTypeGPIOOutput(hwAttrs->portTX, hwAttrs->pinTX);
GPIOPinWrite(hwAttrs->portTX, hwAttrs->pinTX, hwAttrs->pinTX);

/*
* Send 10 bytes over the SPI bus. This causes the clock to toggle several
* times to get the SD Card into SPI mode.
*/
for (i = 0; i < 10; i++) {
/*
* Write DUMMY data. SSIDataPut() waits until there is room in the
* FIFO.
*/
SSIDataPut(hwAttrs->baseAddr, 0xFF);

/* Flush data read during data write. */
SSIDataGet(hwAttrs->baseAddr, &dat);
//rxSPI(hwAttrs);
}

/* Revert to hardware control of the SPI TX line. */
GPIODirModeSet(hwAttrs->portSPI, hwAttrs->pinMOSI, GPIO_DIR_MODE_HW);

Log_print1(Diags_USER1, "SDSPI:(%p) initialized SD card to SPI mode",
hwAttrs->baseAddr);
}

/*
* ======== takeSPIBus ========
* Function to take the SPI bus
*
* @param hwAttrs Pointer to hardware attributes
*/
static inline Void takeSPIBus(SDSPITiva_HWAttrs const *hwAttrs)
{
/* Select the SD card. */
GPIOPinWrite(hwAttrs->portCS, hwAttrs->pinCS, 0);
}

/*
* ======== txSPI ========
* Function to transmit one byte onto the SPI bus. Polling (Blocked)
*
* @param hwAttrs Pointer to hardware attributes
*
* @param dat Data to be sent onto the SPI bus
*/
static inline Void txSPI(SDSPITiva_HWAttrs const *hwAttrs, UChar dat)
{
SDSPIDataType rcvdat;

/* Write the data to the tx fifo */
SSIDataPut(hwAttrs->baseAddr, dat);

/* flush data read during the write */
SSIDataGet(hwAttrs->baseAddr, &rcvdat);
}

/*
* ======== wait_ready ========
* Function to check if the SDCard is busy
*
* This function queries the SDCard to see if it is in a busy state or ready
* state
*
* @param hwAttrs Pointer to hardware attributes
*/
static UChar wait_ready(SDSPITiva_HWAttrs const *hwAttrs)
{
UChar res;
Bits32 timeoutLimit;

/* Wait for data packet in timeout of 500 ms */
timeoutLimit = Timestamp_get32() + 500 * mSScalingFactor;

rxSPI(hwAttrs);
do {
res = rxSPI(hwAttrs);
} while ((res != 0xFF) && (Timestamp_get32() <= timeoutLimit));

return (res);
}

/* _READONLY is defined in <ti/sysbios/fatfs/diskio.h> */
#if _READONLY == 0
/*
* ======== xmit_datablock ========
* Function to transmit a block of data to the SDCard
*
* @param hwAttrs Pointer to hardware attributes
*
* @param params SDSPITiva hardware attributes
*
* @param buf pointer to const data buffer
*
* @param token command token to be sent to the SD card prior to
* sending the data block. The available tokens are:
* START_BLOCK_TOKEN
* START_MULTIBLOCK_TOKEN
* STOP_MULTIBLOCK_TOKEN
*/
static UInt xmit_datablock(SDSPITiva_HWAttrs const *hwAttrs,
const UChar *buf,
UChar token)
{
UChar resp;
UChar wc;

if (wait_ready(hwAttrs) != 0xFF) {
/* Return with error */
return (0);
}

/* Xmit data token */
txSPI(hwAttrs, token);

/* Send data only when token != STOP_MULTIBLOCK_TOKEN */
if (token != STOP_MULTIBLOCK_TOKEN) {
/* Is data token */
wc = 0;
/* Transferring 512 byte blocks using a 8 bit counter */
do {
/* Xmit the SD_SECTOR_SIZE byte data block */
txSPI(hwAttrs, *buf++);
txSPI(hwAttrs, *buf++);
} while (--wc);

/* Future enhancement to add CRC support */
txSPI(hwAttrs, 0xFF);
txSPI(hwAttrs, 0xFF);

/* Reveive data response */
resp = rxSPI(hwAttrs);

/* If not accepted, return error */
if ((resp & 0x1F) != 0x05) {
return (0);
}
}

/* Return with success */
return (1);
}
#endif /* _READONLY */

/*
* ======== SDSPITiva_close ========
* Function to unmount the FatFs filesystem and unregister the SDSPITiva
* disk I/O functions from SYS/BIOS' FatFS module.
*
* @param handle SDSPI_Handle returned by SDSPI_open()
*/
Void SDSPITiva_close(SDSPI_Handle handle)
{
UInt key;
DRESULT dresult;
FRESULT fresult;
SDSPITiva_Object *object = handle->object;
SDSPITiva_HWAttrs const *hwAttrs = handle->hwAttrs;

/* Unmount the FatFs drive */
fresult = f_mount(object->driveNumber, NULL);
if (fresult != FR_OK) {
Log_print2(Diags_USER1, "SDSPI:(%p) Could not unmount FatFs volume @ "
"drive number %d",
hwAttrs->baseAddr, object->driveNumber);
}

/* Unregister the disk_*() functions */
dresult = disk_unregister(object->driveNumber);
if (dresult != RES_OK) {
Log_print2(Diags_USER1, "SDSPI:(%p) Error unregistering disk functions "
"@ drive number %d",
hwAttrs->baseAddr, object->driveNumber);
}

SSIDisable(hwAttrs->baseAddr);

Log_print1(Diags_USER1, "SDSPI:(%p) closed", hwAttrs->baseAddr);

key = Hwi_disable();
object->driveNumber = DRIVE_NOT_MOUNTED;
Hwi_restore(key);
}

/*
* ======== SDSPITiva_diskInitialize ========
* Function to initialize the SD Card. This function is called by the FatFs
* module and must not be called by the application!
*
* @param drv Drive Number
*/
DSTATUS SDSPITiva_diskInitialize(UChar drv)
{
UChar n;
UChar ocr[4];
SDSPITiva_CardType cardType;
Types_FreqHz freq;
Bits32 timeoutLimit;
SDSPITiva_Object *object = sdspiHandles[drv]->object;
SDSPITiva_HWAttrs const *hwAttrs = sdspiHandles[drv]->hwAttrs;

/* No card in the socket */
if (object->diskState & STA_NODISK) {
Log_error1("SDSPI:(%p) disk initialization failed: No disk",
hwAttrs->baseAddr);

return (object->diskState);
}

/* Initialize the SD Card for SPI mode */
send_initial_clock_train(hwAttrs);

/* Select the SD Card's chip select */
takeSPIBus(hwAttrs);
cardType = NOCARD;

/* Send the CMD0 to put the SD Card in "Idle" state */
if (send_cmd(hwAttrs, CMD0, 0) == 1) {

/*
* Determine what SD Card version we are dealing with
* Depending on which SD Card version, we need to send different SD
* commands to the SD Card, which will have different response fields.
*/

if (send_cmd(hwAttrs, CMD8, 0x1AA) == 1) {
/* SDC Ver2+ */
for (n = 0; n < 4; n++) {
ocr[n] = rxSPI(hwAttrs);
}

/*
* Ensure that the card's voltage range is valid
* The card can work at vdd range of 2.7-3.6V
*/
if ((ocr[2] == 0x01) && (ocr[3] == 0xAA)) {
/* Wait for data packet in timeout of 1s */
timeoutLimit = Timestamp_get32() + 1000 * mSScalingFactor;
do {
/* ACMD41 with HCS bit */
if (send_cmd(hwAttrs, CMD55, 0) <= 1 &&
send_cmd(hwAttrs, CMD41, 1UL << 30) == 0) {
timeoutLimit = 1;
break;
}
} while (Timestamp_get32() <= timeoutLimit);

/*
* Check CCS bit to determine which type of capacity we are
* dealing with
*/
if ((timeoutLimit) && send_cmd(hwAttrs, CMD58, 0) == 0) {
for (n = 0; n < 4; n++) {
ocr[n] = rxSPI(hwAttrs);
}
cardType = (ocr[0] & 0x40) ? SDHC : SDSC;
}
}
}

/* SDC Ver1 or MMC */
else {
/*
* The card verion is not SDC V2+ so check if we are dealing with a
* SDC or MMC card
*/
if ((send_cmd(hwAttrs, CMD55, 0) <= 1 &&
send_cmd(hwAttrs, CMD41, 0) <= 1)) {
cardType = SDSC;
}
else {
cardType = MMC;
}

/* Wait for data packet in timeout of 1s */
timeoutLimit = Timestamp_get32() + 1000 * mSScalingFactor;
do {
if (cardType == SDSC) {
/* ACMD41 */
if (send_cmd(hwAttrs, CMD55, 0) <= 1 &&
send_cmd(hwAttrs, CMD41, 0) == 0) {
timeoutLimit = 1;
break;
}
} else {
/* CMD1 */
if (send_cmd(hwAttrs, CMD1, 0) == 0) {
timeoutLimit = 1;
break;
}
}
} while (Timestamp_get32() <= timeoutLimit);

/* Select R/W block length */
if (!(timeoutLimit) ||
send_cmd(hwAttrs, CMD16, SD_SECTOR_SIZE) != 0) {
cardType = NOCARD;
}
}
}

object->cardType = cardType;

/* Deselect the SD Card's chip select */
releaseSPIBus(hwAttrs);

/* Idle (Release DO) */
rxSPI(hwAttrs);

/* Check to see if a card type was determined */
if (cardType != NOCARD) {
/* Reconfigure the SPI bust at the new frequency rate */
BIOS_getCpuFreq(&freq);
SSIDisable(hwAttrs->baseAddr);

SSIConfigSetExpClk(hwAttrs->baseAddr,
freq.lo,
SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER,
object->bitRate,
8);

SSIEnable(hwAttrs->baseAddr);

Log_print3(Diags_USER1,
"SDSPI:(%p) CPU freq: %d; Reconfiguring SDSPI freq to %d",
hwAttrs->baseAddr,
freq.lo,
object->bitRate);

/* Initialization succeeded */
object->diskState &= ~STA_NOINIT;
}
else {
Log_print1(Diags_USER1, "SDSPI:(%p) disk initialization failed",
hwAttrs->baseAddr);
}

return (object->diskState);
}

/*
* ======== SDSPITiva_diskIOctrl ========
* Function to perform specifed disk operations. This function is called by the
* FatFs module and must not be called by the application!
*
* @param drv Drive Number
*
* @param ctrl Control code
*
* @param buf Buffer to send/receive control data
*/
DRESULT SDSPITiva_diskIOctrl(UChar drv, UChar ctrl, Void *buf)
{
DRESULT res = RES_ERROR;
UChar n;
UChar csd[16];
WORD csize;
SDSPITiva_Object *object = sdspiHandles[drv]->object;
SDSPITiva_HWAttrs const *hwAttrs = sdspiHandles[drv]->hwAttrs;

if (object->diskState & STA_NOINIT) {
Log_error1("SDSPI:(%p) disk IO control: disk not initialized",
hwAttrs->baseAddr);

return (RES_NOTRDY);
}

/* Select the SD Card's chip select */
takeSPIBus(hwAttrs);

switch (ctrl) {
case GET_SECTOR_COUNT:
/* Get number of sectors on the disk (ULong) */
if ((send_cmd(hwAttrs, CMD9, 0) == 0) &&
rcvr_datablock(hwAttrs, csd, 16)) {

/* SDC ver 2.00 */
if ((csd[0] >> 6) == 1) {
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
*(ULong*)buf = (ULong)csize << 10;
}
/* MMC or SDC ver 1.XX */
else {
n = (csd[5] & 15) +
((csd[10] & 128) >> 7) +
((csd[9] & 3) << 1) + 2;

csize = (csd[8] >> 6) +
((WORD)csd[7] << 2) +
((WORD)(csd[6] & 3) << 10) + 1;

*(ULong*)buf = (ULong)csize << (n - 9);
}
Log_print2(Diags_USER2,
"SDSPI:(%p) disk IO control: sector count: %d",
hwAttrs->baseAddr,
*(ULong*)buf);
res = RES_OK;
}
break;

case GET_SECTOR_SIZE:
/* Get sectors on the disk (WORD) */
*(WORD*)buf = SD_SECTOR_SIZE;
Log_print2(Diags_USER2,
"SDSPI:(%p) disk IO control: sector size: %d",
hwAttrs->baseAddr,
*(WORD*)buf);
res = RES_OK;
break;

case CTRL_SYNC:
/* Make sure that data has been written */
if (wait_ready(hwAttrs) == 0xFF) {
Log_print1(Diags_USER2,
"SDSPI:(%p) disk IO control: control sync: ready",
hwAttrs->baseAddr);
res = RES_OK;
}
else {
Log_print1(Diags_USER2,
"SDSPI:(%p) disk IO control: control sync: not ready",
hwAttrs->baseAddr);
res = RES_NOTRDY;
}
break;

default:
Log_print1(Diags_USER2,
"SDSPI:(%p) disk IO control: parameter error",
hwAttrs->baseAddr);
res = RES_PARERR;
break;
}

/* Deselect the SD Card's chip select */
releaseSPIBus(hwAttrs);

/* Idle (Release DO) */
rxSPI(hwAttrs);

return (res);
}

/*
* ======== SDSPITiva_diskRead ========
* Function to perform a disk read from the SDCard. This function is called by
* the FatFs module and must not be called by the application!
*
* @param drv Drive Number
*
* @param buf Pointer to a buffer on which to store data
*
* @param sector Starting sector number (LBA)
*
* @param count Sector count (1...255)
*/
DRESULT SDSPITiva_diskRead(UChar drv, UChar *buf, ULong sector, UChar count)
{
SDSPITiva_Object *object = sdspiHandles[drv]->object;
SDSPITiva_HWAttrs const *hwAttrs = sdspiHandles[drv]->hwAttrs;

if (!count) {
Log_print1(Diags_USER1, "SDSPI:(%p) disk read: 0 sectors to read",
hwAttrs->baseAddr);

return (RES_PARERR);
}

if (object->diskState & STA_NOINIT) {
Log_error1("SDSPI:(%p) disk read: disk not initialized",
hwAttrs->baseAddr);

return (RES_NOTRDY);
}

/*
* On a SDSC card, the sector address is a byte address on the SD Card
* On a SDHC card, the sector address is address by sector blocks
*/
if (object->cardType != SDHC) {
/* Convert to byte address */
sector *= SD_SECTOR_SIZE;
}

/* Select the SD Card's chip select */
takeSPIBus(hwAttrs);

/* Single block read */
if (count == 1) {
if ((send_cmd(hwAttrs, CMD17, sector) == 0) &&
rcvr_datablock(hwAttrs, buf, SD_SECTOR_SIZE)) {
count = 0;
}
}
/* Multiple block read */
else {
if (send_cmd(hwAttrs, CMD18, sector) == 0) {
do {
if (!rcvr_datablock(hwAttrs, buf, SD_SECTOR_SIZE)) {
break;
}
buf += SD_SECTOR_SIZE;
} while (--count);

/* STOP_TRANSMISSION */
send_cmd(hwAttrs, CMD12, 0);
}
}

/* Deselect the SD Card's chip select */
releaseSPIBus(hwAttrs);

/* Idle (Release DO) */
rxSPI(hwAttrs);

return (count ? RES_ERROR : RES_OK);
}

/*
* ======== SDSPITiva_diskStatus ========
* Function to return the current disk status. This function is called by
* the FatFs module and must not be called by the application!
*
* @param(drv) Drive Number
*/
DSTATUS SDSPITiva_diskStatus(UChar drv)
{
/* Get the pointer to the object */
SDSPITiva_Object *object = sdspiHandles[drv]->object;

/* Use Diags_USER1 to reduce noise in the logs */
Log_print2(Diags_USER2,
"SDSPI:(%p) disk status: diskState: %d",
((SDSPITiva_HWAttrs const *)(sdspiHandles[drv]->hwAttrs))->baseAddr,
object->diskState);

return (object->diskState);
}

#if _READONLY == 0
/*
* ======== SDSPITiva_diskWrite ========
* Function to perform a disk write from the SDCard. This function is called by
* the FatFs module and must not be called by the application!
*
* @param drv Drive Number
*
* @param buf Pointer to a buffer from which to read data
*
* @param sector Starting sector number (LBA)
*
* @param count Sector count (1...255)
*/
DRESULT SDSPITiva_diskWrite(UChar drv, const UChar *buf, ULong sector,
UChar count)
{
SDSPITiva_Object *object = sdspiHandles[drv]->object;
SDSPITiva_HWAttrs const *hwAttrs = sdspiHandles[drv]->hwAttrs;

if (!count) {
Log_print1(Diags_USER1, "SDSPI:(%p) disk write: 0 sectors to write",
hwAttrs->baseAddr);

return (RES_PARERR);
}
if (object->diskState & STA_NOINIT) {
Log_error1("SDSPI:(%p) disk write: disk not initialized",
hwAttrs->baseAddr);

return (RES_NOTRDY);
}
if (object->diskState & STA_PROTECT) {
Log_error1("SDSPI:(%p) disk write: disk protected",
hwAttrs->baseAddr);

return (RES_WRPRT);
}

/*
* On a SDSC card, the sector address is a byte address on the SD Card
* On a SDHC card, the sector address is address by sector blocks
*/
if (object->cardType != SDHC) {
/* Convert to byte address if needed */
sector *= SD_SECTOR_SIZE;
}

/* Select the SD Card's chip select */
takeSPIBus(hwAttrs);

/* Single block write */
if (count == 1) {
if ((send_cmd(hwAttrs, CMD24, sector) == 0) &&
xmit_datablock(hwAttrs, buf, START_BLOCK_TOKEN)) {
count = 0;
}
}
/* Multiple block write */
else {
if ((object->cardType == SDSC) || (object->cardType == SDHC)) {
send_cmd(hwAttrs, CMD55, 0);
send_cmd(hwAttrs, CMD23, count); /* ACMD23 */
}
/* WRITE_MULTIPLE_BLOCK */
if (send_cmd(hwAttrs, CMD25, sector) == 0) {
do {
if (!xmit_datablock(hwAttrs, buf, START_MULTIBLOCK_TOKEN)) {
break;
}
buf += SD_SECTOR_SIZE;
} while (--count);

/* STOP_TRAN token */
if (!xmit_datablock(hwAttrs, 0, STOP_MULTIBLOCK_TOKEN)) {
count = 1;
}
}
}

/* Deselect the SD Card's chip select */
releaseSPIBus(hwAttrs);

/* Idle (Release DO) */
rxSPI(hwAttrs);

return (count ? RES_ERROR : RES_OK);
}
#endif /* _READONLY */

/*
* ======== SDSPITiva_init ========
* Function to initialize a SDSPITiva_object.
*
* @param handle SDSPI handle
*/
Void SDSPITiva_init(SDSPI_Handle handle)
{
SDSPITiva_Object *object = handle->object;

/* Mark the object as available */
object->driveNumber = DRIVE_NOT_MOUNTED;
object->diskState = STA_NOINIT;
object->cardType = NOCARD;
}

/*
* ======== SDSPITiva_open ========
* Function to mount the FatFs filesystem and register the SDSPITiva disk
* I/O functions with SYS/BIOS' FatFS module.
*
* This function also configures some basic GPIO settings needed for the
* software chip select with the SDCard.
*
* @param handle SDSPI handle
* @param drv Drive Number
* @param params SDSPI parameters
*/
SDSPI_Handle SDSPITiva_open(SDSPI_Handle handle, UInt drv,
SDSPI_Params *params)
{
DRESULT dresult;
FRESULT fresult;
UInt key;
Types_FreqHz freq;
SDSPITiva_Object *object = handle->object;
SDSPITiva_HWAttrs const *hwAttrs = handle->hwAttrs;;

/* Determine if the device was already opened */
key = Hwi_disable();
if (object->driveNumber != DRIVE_NOT_MOUNTED) {
Hwi_restore(key);
return (NULL);
}
/* Mark as being used */
object->driveNumber = drv;
Hwi_restore(key);

/* Store the SDSPI parameters */
if (params == NULL) {
/* No params passed in, so use the defaults */
params = (SDSPI_Params *) &SDSPI_defaultParams;
}

/* Determine time scaling for ms timeouts */
Timestamp_getFreq(&freq);
mSScalingFactor = freq.lo / 1000;

/* Store desired bitRate */
object->bitRate = params->bitRate;

/* Pins used for SPI ( CLK | RX | TX ) */
GPIODirModeSet(hwAttrs->portSPI,
hwAttrs->pinSCK | hwAttrs->pinMISO | hwAttrs->pinMOSI,
GPIO_DIR_MODE_HW);

/* Pin used for Chip Select */
GPIOPinTypeGPIOOutput(hwAttrs->portCS, hwAttrs->pinCS);

/* Raise the chip select pin */
GPIOPinWrite(hwAttrs->portCS, hwAttrs->pinCS, hwAttrs->pinCS);

/*
* Configure the SPI bus to 400 kHz as required per SD specs. This frequency
* will be adjusted later once the SD card has been successfully initialized
*/
BIOS_getCpuFreq(&freq);
SSIConfigSetExpClk(hwAttrs->baseAddr, freq.lo, SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 400000, 8);

Log_print2(Diags_USER1, "SDSPI:(%p) CPU freq: %d; SDSPI freq to 400000 kHz",
hwAttrs->baseAddr, freq.lo);

SSIEnable(hwAttrs->baseAddr);

/* Register the new disk_*() functions */
dresult = disk_register(object->driveNumber,
SDSPITiva_diskInitialize,
SDSPITiva_diskStatus,
SDSPITiva_diskRead,
SDSPITiva_diskWrite,
SDSPITiva_diskIOctrl);

/* Check for drive errors */
if (dresult != RES_OK) {
Log_error1("SDSPI:(%p) disk functions not registered",
hwAttrs->baseAddr);

SDSPITiva_close(handle);
return (NULL);
}

/*
* Register the filesystem with FatFs. This operation does not access the
* SDCard yet.
*/
fresult = f_mount(object->driveNumber, &(object->filesystem));
if (fresult != FR_OK) {
Log_error2("SDSPI:(%p) drive %d not mounted",
hwAttrs->baseAddr, object->driveNumber);

SDSPITiva_close(handle);
return (NULL);
}

/* Store the new SDSPI handle for this FatFs drive number */
sdspiHandles[drv] = handle;

Log_print1(Diags_USER1, "SDSPI:(%p) opened", hwAttrs->baseAddr);

return (handle);
}

/*
* ======== SDSPI_open ========
*/
SDSPI_Handle SDSPI_open(UInt index, UInt drv,
SDSPI_Params *params)
{
SDSPI_Handle handle;

/* _VOLUMES is defined in <ti/sysbios/fatfs/ffconf.h> */
Assert_isTrue((index < SDSPI_count) && (drv <= _VOLUMES), NULL);

/* Get handle for this driver instance */
handle = (SDSPI_Handle)&(SDSPI_Config[index]);

return (handle->fxnTablePtr->openFxn(handle, drv, params));
}
/*
* ======== SDSPI_Params_init ========
*
* Defaults values are:
* @code
* bitRate = 12500000 (Hz)
* @endcode
*
* @param params Parameter structure to initialize
*/
Void SDSPI_Params_init(SDSPI_Params *params)
{
Assert_isTrue(params != NULL, NULL);

*params = SDSPI_defaultParams;
}

SDSPI.h:

/*
* Copyright (c) 2015, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ti_drivers_SDSPI__include
#define ti_drivers_SDSPI__include

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

#define SDSPI_CMD_RESERVED 32

#define SDSPI_STATUS_RESERVED -32

#define SDSPI_STATUS_SUCCESS 0

#define SDSPI_STATUS_ERROR -1

#define SDSPI_STATUS_UNDEFINEDCMD -2

typedef struct SDSPI_Config *SDSPI_Handle;


typedef struct SDSPI_Params {
uint32_t bitRate;
void *custom;
} SDSPI_Params;

typedef void (*SDSPI_InitFxn) (SDSPI_Handle handle);

typedef SDSPI_Handle (*SDSPI_OpenFxn) (SDSPI_Handle handle,
unsigned char drv,
SDSPI_Params *params);

typedef void (*SDSPI_CloseFxn) (SDSPI_Handle handle);

typedef int (*SDSPI_ControlFxn) (SDSPI_Handle handle,
unsigned int cmd,
void *arg);

typedef struct SDSPI_FxnTable {
SDSPI_InitFxn initFxn;

SDSPI_OpenFxn openFxn;

SDSPI_CloseFxn closeFxn;

SDSPI_ControlFxn controlFxn;
} SDSPI_FxnTable;

typedef struct SDSPI_Config {
SDSPI_FxnTable const *fxnTablePtr;

void *object;

void const *hwAttrs;
} SDSPI_Config;

extern void SDSPI_close(SDSPI_Handle handle);

extern int SDSPI_control(SDSPI_Handle handle, unsigned int cmd, void *arg);

extern void SDSPI_init(void);

extern SDSPI_Handle SDSPI_open(UInt index, UInt drv,
SDSPI_Params *params);

extern void SDSPI_Params_init(SDSPI_Params *params);

#ifdef __cplusplus
}
#endif

#endif /* ti_drivers_SDSPI__include */

and the code in the task:

SDSPI_Handle handle2;
SDSPI_FxnTable bla7;
SDSPI_Params params2;
UInt bla = 5;
UInt bla1 = 5;
SDSPI_Params_init(&params2);
//handle2 = SDSPI_open(bla, bla1, &params2);

when I remove the "//" from the last line it happens, but with the ."//" it has the weird linking issue.

regards,

Tomer.

  • Tomer Ben Moshe said:
    I don't know where did he get the small c because whenever there is a "SDSPI_Config" it's with a capital C.

    SDSPI_Config (with a capital C) is a type. SDSPI_config (with a lower case c) is the name of array of type SDSPI_Config.

    The application is supposed to define the SDSPI_config[] array to give the board-specific configuration for the SDSPI driver to use.

    Looking at tirtos_cc13xx_cc26xx_2_21_00_06 none of the examples define the SDSPI_config[] array.

    The MSP_EXP432P401R.c source file from the SimpleLink MSP432 SDK gives an example of how to define the SDSPI_config[] array for a different device, which you should be able to use as a guideline for how to define a SDSPI_config[] array for use in a CC2650 device.

  • Tomer,

    Here is an example of how to create a SDSPI_Config struct. I did not see in your code above where you define the SDSPITiva_HWAttrs, but you will populate it according to your implementation.

    SDSPITiva_Object sdspiCC2650Objects[1];
    
    /* SDSPI configuration structure, describing which pins are to be used */
    const SDSPITiva_HWAttrs sdspiCC2650HWattrs[1] = {
    {
        //field = xyz,
        //field = abc,
    }
    };
    
    const SDSPI_Config SDSPI_config[1] = {
    {
        .fxnTablePtr = &SDSPITiva_fxnTable ,
        .object = &sdspiCC2650Objects[0],
        .hwAttrs = &sdspiCC2650HWattrs[0]
    },
    };
    
    const uint_least8_t SDSPI_count = 1;

    Derrick