I am currently setting up SPI on a nrf52832. I keep getting this error when building "undefined reference to `nrfx_spi_init' ". I do not use the nrfx_spi.c file at all as I am running on the legacy drivers. I have enabled SPI and SPI0 (the instance I want) in the sdk_config.h file. I do not know where this error could be coming from. I have attached the file I use the spi files as well as my config file.4101.sdk_config.h
/*****************************************************************************
* File Name: fram.c
*
* Date Created: 5/12/20
*
* Author: Bob Theumer
*
* Description: Software for interface to nonvolatile fram chip (25040A)
* on EV2 Speedo & Tach gauges. FRAM is connected via SPI bus
* and stores the gauge's meter readings.
*
* Function List:
* Public
* spi_init()
* framInit()
* framReadDataByte()
* framWriteDataByte()
* framWriteDataPage()
* Private
* readFRAMStatusRegister()
* readByteFromMemory()
* sendByteToMemory()
* writeEnableSequence()
* void spi_event_handler()
*
* Notes:
*
* CSRCS Log
* $Log$
* Revision 1.0 2020-05-26 10:08:06-07 bobt
* Initial revision
*
*
* Copyright (c) 2020 ISSPRO Inc.
*****************************************************************************/
/* Include shared modules, which are used for whole project*/
//#include "PE_Types.h"
#include "AppTypes.h"
#include "assert.h"
#include "stdbool.h"
#include "nrf_drv_spi.h"
/* Include application files */
#include "fram.h"
#include "custom_board.h"
// Local Definitions
#define BYTE_MAX_VALUE 0x00FF // 255
#define PAGE_MAX_BYTES 16
#define SPI_INSTANCE 0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0); /**< SPI instance. */
static volatile bool spi_xfer_done; /**< Flag used to indicate that SPI instance completed the transfer. */
// Private Functions
static uint8_t readFRAMStatusRegister(void);
static uint8_t readByteFromMemory(void);
static void sendByteToMemory(uint8_t data);
static void writeEnableSequence(void);
void spi_event_handler(nrf_drv_spi_evt_t const *p_event, void *p_context);
// Private Data
//TODO
/*****************************************************************************
*
* Function: spi_init()
*
* Description: Initializes the spi channel on nrf52832.
*
* Input: None
*
* Output: None
*
* Notes: None
*
*****************************************************************************/
void spi_init()
{
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin = SPI_SS_PIN;
spi_config.miso_pin = SPI_MISO_PIN;
spi_config.mosi_pin = SPI_MOSI_PIN;
spi_config.sck_pin = SPI_SCK_PIN;
APP_ERROR_CHECK(nrf_drv_spi_init(&spi,&spi_config,spi_event_handler,NULL));
}
/*****************************************************************************
*
* Function: framInit()
*
* Description: Initializes the signals used to access the FRAM chip.
*
* Input: None
*
* Output: None
*
* Notes: This assumes SPI port has been configured already.
*
*****************************************************************************/
void framInit(void)
{
nrf_gpio_pin_set(SPI_SS_PIN); // Ensure active high chip select is high
}
/*****************************************************************************
*
* Function: framReadDataByte()
*
* Description: Function reads one byte from a defined FRAM address location.
*
* Input: uint16_t - address of FRAM location to be read from.
* Range: address can be between 0 thru 511 (0x1ff).
*
* Output: uint8_t - data read from FRAM location
* Range: data can be between 0 thru 255 (0xff)
*
* Notes: This function takes only about 65 uSec to complete.
* See Data sheet 8ICFM25040A Pages 7 & 8 for more details.
*
*****************************************************************************/
uint8_t framReadDataByte(uint16_t address)
{
uint8_t cmd = FRAM_READ_MEM_CMD;
uint8_t rxData;
// Check if memory address is more than 8-bits.
if (address > BYTE_MAX_VALUE)
{
// Yes, need to set the A8 bit in command.
cmd |= FRAM_A8_BIT;
}
nrf_gpio_pin_clear(SPI_SS_PIN); // Activate chip select by clearing it
// Read consists of its command first, then address byte (8-bits).
sendByteToMemory(cmd);
sendByteToMemory((uint8_t)(address & BYTE_MAX_VALUE));
rxData = readByteFromMemory();
nrf_gpio_pin_set(SPI_SS_PIN); // Disable chip select by setting high
return rxData;
}
/*****************************************************************************
*
* Function: framWriteDataByte()
*
* Description: Function writes one byte to a defined FRAM address location.
*
* Input: uint16_t - address of FRAM location to be written to.
* Range: address can be between 0 thru 511 (0x1ff).
* uint8_t - data to be written to the FRAM.
* Range: data can be between 0 thru 255 (0xff)
*
* Output: None
*
* Notes: This function takes only about 87 uSec to complete.
* See Data sheet 8ICFM25040A Pages 7 & 8 for more details.
*
*****************************************************************************/
void framWriteDataByte(uint16_t address, uint8_t data)
{
uint8_t cmd = FRAM_WRITE_MEM_CMD;
writeEnableSequence(); // Must set write enable latch first
nrf_gpio_pin_clear(SPI_SS_PIN); // Activate chip select by clearing it
// Check if memory address is more than 8-bits.
if (address > BYTE_MAX_VALUE)
{
// Yes, need to set the A8 bit in command.
cmd |= FRAM_A8_BIT;
}
// Write consists of its command first, then address byte (8-bits)
// to write to, and then the data itself (8-bits).
sendByteToMemory(cmd);
sendByteToMemory((uint8_t)(address & BYTE_MAX_VALUE));
sendByteToMemory(data);
nrf_gpio_pin_set(SPI_SS_PIN); // Disable chip select by setting high
}
/*****************************************************************************
*
* Function: framWriteDataPage()
*
* Description: Function to write up to 16 bytes (= 1 page) to FRAM.
*
* Input: uint16_t - starting address (must be page aligned).
* uint8_t* - pointer to the buffer that contains the bytes.
* uint8_t - number of bytes to be written to a given page.
* Range: 1 thru 16 bytes (can't over flow page).
*
* Output: None
*
* Notes: This function takes about up to 410 uSec to complete (for
* 16 bytes). Since we only currently write 3 bytes at a time
* (though we may combine trip meters into one write, TBD)
* it only takes about 100 uSec which isn't too bad.
*
* See Data sheet 8ICFM25040A Pages 7 & 8 for more details.
*
*****************************************************************************/
void framWriteDataPage(uint16_t address, uint8_t *data, uint8_t numBytes)
{
uint8_t cmd = FRAM_WRITE_MEM_CMD;
uint8_t i;
// Conduct boundry check for the page write.
assert((address/PAGE_MAX_BYTES) == ((address+(numBytes - 1))/PAGE_MAX_BYTES));
writeEnableSequence(); // Must set write enable latch first
nrf_gpio_pin_clear(SPI_SS_PIN); // Activate chip select by clearing it
// Check if memory address is more than 8-bits.
if (address > BYTE_MAX_VALUE)
{
// Yes, need to set the A8 bit in command.
cmd |= FRAM_A8_BIT;
}
// Write consists of its command first, then address byte (8-bits)
// to write to, and then the data itself (we limit it to 16 bytes).
sendByteToMemory(cmd);
sendByteToMemory((uint8_t)(address & BYTE_MAX_VALUE));
for (i = 0; i < numBytes; i++)
{
sendByteToMemory((uint8_t) *data++);
}
nrf_gpio_pin_set(SPI_SS_PIN); // Disable chip select by setting high
}
// Private Functions
/*****************************************************************************
*
* Function: readFRAMStatusRegister()
*
* Description: Return actual status of FRAM chip at this moment in time.
*
* Input: None
*
* Output: uint8_t Bit 0 = Not used in FRAM (only EEPROMs).
* Bit 1 = Write Enable Latch (WEL).
* Bit 2 = BP0 bit Array Protection
* Bit 3 = BP1 bit Array Protection
*
* Notes: See Data sheet 8ICFM25040A Page 6 for more details.
*
*****************************************************************************/
static uint8_t readFRAMStatusRegister(void)
{
uint8_t rxData;
nrf_gpio_pin_clear(SPI_SS_PIN); // Activate chip select by clearing it
sendByteToMemory(FRAM_READ_STATUS_CMD);
rxData = readByteFromMemory();
nrf_gpio_pin_set(SPI_SS_PIN); // Disable chip select by setting high
return rxData;
}
/*****************************************************************************
*
* Function: readByteFromMemory()
*
* Description: Return a byte read from the FRAM memory.
*
* Input: None
*
* Output: uint8_t - Actual byte read from the FRAM chip.
* Range: data can be between 0 thru 255 (0xff)
*
* Notes: Function assumes the caller function has already set
* FRAM Chip Select signal to a Low level logic state.
*
*****************************************************************************/
static uint8_t readByteFromMemory(void)
{
uint8_t rxData, result;
uint8_t dummy = FRAM_WRITE_EN_LATCH_CMD; // Ignored by FRAM
bool empty = false;
// Need 8 more clocks to read data so send out dummy message.
result = nrf_drv_spi_transfer(&spi, &dummy, 1, NULL, 0);
assert (result == true);
// NOTE: do-while seems to work better than just a while?
do
{
empty = &spi_xfer_done;
} while (!empty);
result = nrf_drv_spi_transfer(&spi,NULL,0,&rxData,1);
assert (result == true);
return rxData;
}
/*****************************************************************************
*
* Function: sendByteToMemory()
*
* Description: Writes a byte to the FRAM memory.
*
* Input: uint8_t - Actual byte to be written to the FRAM chip.
* Range: data can be between 0 thru 255 (0xff)
*
* Output: None
*
* Notes: Function assumes the caller function has already set
* FRAM Chip Select signal to a Low level logic state.
*
*****************************************************************************/
static void sendByteToMemory(uint8_t data)
{
uint8_t result;
bool empty = false;
result = nrf_drv_spi_transfer(&spi,&data, 1, NULL, 0);
assert (result == true);
// NOTE: do-while seems to work better than just a while?
do
{
empty = &spi_xfer_done;
} while (!empty);
// Read what the spi read while you transmit byte.
result = nrf_drv_spi_transfer(&spi, NULL, 0, &data, 1);
assert (result == true);
}
/*****************************************************************************
*
* Function: writeEnableSequence()
*
* Description: Sends Write Enable Latch (WREN) command to the FRAM. This
* is required prior to writing any data to it.
*
* Input: None
*
* Output: None
*
* Notes: Command must be sent singularly, ie between activation &
* deactiviation of its chip select.
*
*****************************************************************************/
static void writeEnableSequence(void)
{
nrf_gpio_pin_clear(SPI_SS_PIN); // Activate chip select by clearing it
sendByteToMemory(FRAM_WRITE_EN_LATCH_CMD);
nrf_gpio_pin_set(SPI_SS_PIN); // Disable chip select by setting high
}
/*****************************************************************************
*
* Function: spi_event_handler()
*
* Description: Determines when SPI transfer is done
*
* Input: None
*
* Output: None
*
* Notes: None
*
*****************************************************************************/
void spi_event_handler(nrf_drv_spi_evt_t const *p_event, void *p_context)
{
spi_xfer_done = true;
}
