This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Ble application with spi manager library

Hi, 

I'm testing ads1292 sensor with nrf52832.

I got some problem when i use spi manager library.

I'm using ble_app_hrs project.

If i use spi manager without advertising, drdy interrupt and spi_read is working.

But, if i use spi manager after advertising started, drdy interrupt is not working.

my app works as below.

  1. start advertising
  2. start ads1292 continuous mode 
  3. drdyEvent ocurred
  4. read data from ads1292 (Call ads1292ReadData() in drdyEvent())
    drdyEvent() => gpio_in_event
  5. drdyEvent ocurred
  6. read data from ads1292 (Call ads1292ReadData() in drdyEvent())
  7. drdy is not working

I set spi frequency to 250K, 500K, 1M and 2M.

And, i also changed sampling rate of ads1292 to 125sps, 250sps.

But, all state is not working.

I checked spi spec through this question before drawing schematic.
In this question, ovrebekk said "The nRF52832 should not have any problems matching this requirement. ".

Is this a problem with the spi library?

This is my code.

#include "ads1292.h"
#include "nrf_drv_gpiote.h"
#include "nrf_delay.h"

#include "spi_controller.h"
#include "port_define.h"

#define ADS1292_TOTAL_WR_REG_COUNT	13
#define ADS1292_DATA_LEN	9

#define ADS1292_INIT_TRANSFER_COUNT	1

////////////////////////////
nrf_spi_mngr_callback_end_t data_callback;

static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND mADSConfig[ADS1292_TOTAL_WR_REG_COUNT] = {
		0x01 | 0x40, // reg_addr | 0x40
		0x0B, //write length
		0x00,  //CONFIG1 : 250SPS
		0xF0,  //CONFIG2 : enable Lead-off comparator, enable reference buffer, reference 4V
		0x10,  //LOFF
		0x67,  //Channel1
		0x67,  //Channel2
		0x25,  //RLD_SENS
		0x0F,  //LOFF_SENS
		0x40,  //LOFF_STAT
		0x02,  //RESP1
		0x03,  //RESP2
		0x03  //GPIO
};

static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND read_all_reg[ADS1292_TOTAL_WR_REG_COUNT] = {
		0x00 | 0x20, // reg_addr | 0x20
		0x0B, //write length
};


static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND rx_buf[ADS1292_DATA_LEN];


nrf_spi_mngr_transfer_t const ads1292_readReg_transfers[ADS1292_INIT_TRANSFER_COUNT] =
{
	NRF_SPI_MNGR_TRANSFER(read_all_reg, sizeof(read_all_reg), rx_buf, sizeof(read_all_reg))
};	
/////////////////////////




static void ads1292_cmd_cb(void * p_user_data)
{
	__NOP();
}

///////////////////////////////////////////////////////////
static void startConversion(void) {
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[]= {ADS1292_START_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};
		
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

static void stopConversion(void) {
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {ADS1292_STOP_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};
		
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}


static void readContinueMode(void){
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {ADS1292_RDATAC_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};
		
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}
	
	

static void stopContinueMode(void){
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {ADS1292_SDATAC_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};	
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

///////////////////////////////////////////////////////////

void ads1292ReadStart(void){
	startConversion();
	nrf_delay_us(10);
	readContinueMode();
	nrf_drv_gpiote_in_event_enable(ADS_DRDY, true);
}

void ads1292ReadStop(void){
	nrf_drv_gpiote_in_event_enable(ADS_DRDY, false);
	stopContinueMode();
	nrf_delay_us(10);
	stopConversion();
}



void ads1292SetReg(void){	
	static nrf_spi_mngr_transfer_t const ads1292_init_transfers[ADS1292_INIT_TRANSFER_COUNT] =
	{
		NRF_SPI_MNGR_TRANSFER(mADSConfig, sizeof(mADSConfig), NULL, 0)
	};
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = NULL,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &ads1292_init_transfers[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}


static void ads1292_read_cb(ret_code_t result, void * p_user_data)
{
	nrf_delay_us(100);
}

void ads1292ReadAllReg(void){
	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(read_all_reg, ADS1292_TOTAL_WR_REG_COUNT, rx_buf, ADS1292_TOTAL_WR_REG_COUNT)
	};	
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = NULL,
		.end_callback        = ads1292_read_cb,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

void ads1292DataReadCB(ret_code_t result, void * p_user_data)
{	
	data_callback(result, p_user_data);
}

void ads1292ReadData(void){
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {0, };
	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(cmd, ADS1292_DATA_LEN, rx_buf, ADS1292_DATA_LEN)
	};	
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = NULL,
		.end_callback        = ads1292DataReadCB,
		.p_user_data         = rx_buf,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

static void drdyEvent(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action){
	ads1292ReadData();
}



void initAds1292(nrf_spi_mngr_callback_end_t data_cb_fnc) {
	ret_code_t err_code;
	
	// set pwdn
	nrf_drv_gpiote_out_config_t outConfig = GPIOTE_CONFIG_OUT_SIMPLE(false); 
	err_code = nrf_drv_gpiote_out_init(ADS_PWDN, &outConfig);
	APP_ERROR_CHECK(err_code);
	nrf_drv_gpiote_out_clear(ADS_PWDN);

	nrf_drv_gpiote_out_set(ADS_PWDN);
	nrf_delay_ms(1000);
	nrf_drv_gpiote_out_clear(ADS_PWDN);
	nrf_delay_ms(50);
	nrf_drv_gpiote_out_set(ADS_PWDN);
	nrf_delay_ms(50);

	// set drdy
	nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
	in_config.pull = NRF_GPIO_PIN_PULLUP;
	err_code = nrf_drv_gpiote_in_init(ADS_DRDY,  &in_config, drdyEvent);    //interrupt pin
	APP_ERROR_CHECK(err_code);
	nrf_drv_gpiote_in_event_enable(ADS_DRDY, false);
	
	stopContinueMode();
	
	
	ads1292SetReg();
	
	data_callback = data_cb_fnc;
}

SDK version : 15.3.0

sd version : 6.1.1

ads1292_mngr.h

#include "ads1292.h"
#include "nrf_drv_gpiote.h"
#include "nrf_delay.h"

#include "spi_controller.h"
#include "port_define.h"

#define ADS1292_TOTAL_WR_REG_COUNT	13
#define ADS1292_DATA_LEN	9

#define ADS1292_INIT_TRANSFER_COUNT	1

////////////////////////////
nrf_spi_mngr_callback_end_t data_callback;

static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND mADSConfig[ADS1292_TOTAL_WR_REG_COUNT] = {
		0x01 | 0x40, // reg_addr | 0x40
		0x0B, //write length
		0x00,  //CONFIG1 : 250SPS
		0xF0,  //CONFIG2 : enable Lead-off comparator, enable reference buffer, reference 4V
		0x10,  //LOFF
		0x67,  //Channel1
		0x67,  //Channel2
		0x25,  //RLD_SENS
		0x0F,  //LOFF_SENS
		0x40,  //LOFF_STAT
		0x02,  //RESP1
		0x03,  //RESP2
		0x03  //GPIO
};

static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND read_all_reg[ADS1292_TOTAL_WR_REG_COUNT] = {
		0x00 | 0x20, // reg_addr | 0x20
		0x0B, //write length
};


static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND rx_buf[ADS1292_DATA_LEN];


nrf_spi_mngr_transfer_t const ads1292_readReg_transfers[ADS1292_INIT_TRANSFER_COUNT] =
{
	NRF_SPI_MNGR_TRANSFER(read_all_reg, sizeof(read_all_reg), rx_buf, sizeof(read_all_reg))
};	
/////////////////////////




static void ads1292_cmd_cb(void * p_user_data)
{
	__NOP();
}

///////////////////////////////////////////////////////////
static void startConversion(void) {
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[]= {ADS1292_START_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};
		
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

static void stopConversion(void) {
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {ADS1292_STOP_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};
		
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}


static void readContinueMode(void){
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {ADS1292_RDATAC_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};
		
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}
	
	

static void stopContinueMode(void){
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {ADS1292_SDATAC_CMD};

	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(&cmd[0], 1, NULL, 0)
	};	
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = ads1292_cmd_cb,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

///////////////////////////////////////////////////////////

void ads1292ReadStart(void){
	startConversion();
	nrf_delay_us(10);
	readContinueMode();
	nrf_drv_gpiote_in_event_enable(ADS_DRDY, true);
}

void ads1292ReadStop(void){
	nrf_drv_gpiote_in_event_enable(ADS_DRDY, false);
	stopContinueMode();
	nrf_delay_us(10);
	stopConversion();
}



void ads1292SetReg(void){	
	static nrf_spi_mngr_transfer_t const ads1292_init_transfers[ADS1292_INIT_TRANSFER_COUNT] =
	{
		NRF_SPI_MNGR_TRANSFER(mADSConfig, sizeof(mADSConfig), NULL, 0)
	};
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = NULL,
		.end_callback        = NULL,
		.p_user_data         = NULL,
		.p_transfers         = &ads1292_init_transfers[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}


static void ads1292_read_cb(ret_code_t result, void * p_user_data)
{
	nrf_delay_us(100);
}

void ads1292ReadAllReg(void){
	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(read_all_reg, ADS1292_TOTAL_WR_REG_COUNT, rx_buf, ADS1292_TOTAL_WR_REG_COUNT)
	};	
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = NULL,
		.end_callback        = ads1292_read_cb,
		.p_user_data         = NULL,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

void ads1292DataReadCB(ret_code_t result, void * p_user_data)
{	
	data_callback(result, p_user_data);
}

void ads1292ReadData(void){
	static uint8_t NRF_SPI_MNGR_BUFFER_LOC_IND cmd[] = {0, };
	static nrf_spi_mngr_transfer_t const transfer_cmd[] =
	{
		NRF_SPI_MNGR_TRANSFER(cmd, ADS1292_DATA_LEN, rx_buf, ADS1292_DATA_LEN)
	};	
	
	static nrf_spi_mngr_transaction_t const transaction_cmd =
	{
		.begin_callback      = NULL,
		.end_callback        = ads1292DataReadCB,
		.p_user_data         = rx_buf,
		.p_transfers         = &transfer_cmd[0],
		.number_of_transfers = 1,
		.p_required_spi_cfg  = NULL
	};
	scheduleSPI(&transaction_cmd);
}

static void drdyEvent(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action){
	ads1292ReadData();
}



void initAds1292(nrf_spi_mngr_callback_end_t data_cb_fnc) {
	ret_code_t err_code;
	
	// set pwdn
	nrf_drv_gpiote_out_config_t outConfig = GPIOTE_CONFIG_OUT_SIMPLE(false); 
	err_code = nrf_drv_gpiote_out_init(ADS_PWDN, &outConfig);
	APP_ERROR_CHECK(err_code);
	nrf_drv_gpiote_out_clear(ADS_PWDN);

	nrf_drv_gpiote_out_set(ADS_PWDN);
	nrf_delay_ms(1000);
	nrf_drv_gpiote_out_clear(ADS_PWDN);
	nrf_delay_ms(50);
	nrf_drv_gpiote_out_set(ADS_PWDN);
	nrf_delay_ms(50);

	// set drdy
	nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
	in_config.pull = NRF_GPIO_PIN_PULLUP;
	err_code = nrf_drv_gpiote_in_init(ADS_DRDY,  &in_config, drdyEvent);    //interrupt pin
	APP_ERROR_CHECK(err_code);
	nrf_drv_gpiote_in_event_enable(ADS_DRDY, false);
	
	stopContinueMode();
	
	
	ads1292SetReg();
	
	data_callback = data_cb_fnc;
}


#include "spi_controller.h"

#include "port_define.h"


#define SPI_INSTANCE_ID            0

NRF_SPI_MNGR_DEF(m_nrf_spi_mngr, 48, SPI_INSTANCE_ID);


ret_code_t spi_init(void){
	// SPI0 (with transaction manager) initialization.
	nrf_drv_spi_config_t const m_master0_config =
	{
		.sck_pin        = SCLK_BUS,
		.mosi_pin       = SIMO_BUS,
		.miso_pin       = SOMI_BUS,
		.ss_pin         = CS_ADS,
		.irq_priority   = APP_IRQ_PRIORITY_LOWEST,
		.orc            = 0xFF,
		.frequency      = NRF_DRV_SPI_FREQ_2M,
		.mode           = NRF_DRV_SPI_MODE_1,
		.bit_order      = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
	};
	return nrf_spi_mngr_init(&m_nrf_spi_mngr, &m_master0_config);
}


void performSPI(nrf_spi_mngr_transfer_t const * p_transfers, uint8_t number_of_transfers, void (* user_function)(void)){
	ret_code_t err_code;
	err_code = nrf_spi_mngr_perform(&m_nrf_spi_mngr, NULL, p_transfers, number_of_transfers, user_function);
	APP_ERROR_CHECK(err_code);
}


void scheduleSPI(nrf_spi_mngr_transaction_t const * p_transaction){
	uint32_t err_code;
	err_code = nrf_spi_mngr_schedule(&m_nrf_spi_mngr, p_transaction);
	APP_ERROR_CHECK(err_code);
}

spi_controller.h

Parents
  • Two suggestions, first care is required above 500kHz:

    spi_config.frequency = NRF_DRV_SPI_FREQ_500K;  // Ensure less than 4 clk cycles for ADS1292
    
    // Sending Multi-Byte Commands
    // The ADS1291, ADS1292, and ADS1292R serial interface decodes commands in bytes and requires 4 tCLK cycles
    // to decode and execute. Therefore, when sending multi-byte commands, a 4 tCLK period must separate the end of
    // one byte (or opcode) and the next.
    // Assume CLK is 512 kHz, then tSDECODE (4 tCLK) is 7.8125 us. When SCLK is 16 MHz, one byte can be
    // transferred in 500 ns. This byte-transfer time does not meet the tSDECODE specification; therefore, a delay must be
    // inserted so the end of the second byte arrives 7.3125 us later. If SCLK is 1 MHz, one byte is transferred in 8 �s.
    // Because this transfer time exceeds the tSDECODE specification, the processor can send subsequent bytes without
    // delay. In this later scenario, the serial port can be programmed to move from single-byte transfer per cycle to
    // multiple bytes.
    
    // Chip Select (CS)
    // CS selects the ADS1291, ADS1292, and ADS1292R for SPI communication. CS must remain low for the entire
    // duration of the serial communication. After the serial communication is finished, always wait four or more tCLK
    // cycles before taking CS high.

    Second interrupt functions triggering other interrupt functions can be avoided by using flags or signals, so I would suggest only set a flag in both DRDY and SPI interrupts and monitoring those flags on each wakeup (given the interrupt generates a wakeup) and then invoking the functions (eg spi from DRDY). This leads to more robust code and may fix the issues.

  • Thanks for replying.

    I tested using 500K.

    And, it doesn't work.

    I changed code to use flag in main loop.

    But, it also doesn't work.

    When i delete ads1292ReadData(), drdy worked.
    Is there any problem in SDK when using scheduleSPI()?

    	for (;;)
    	{
    		if (NRF_LOG_PROCESS() == false)
    		{
    			idle_state_handle();
    		}
    		
    		if(ads1292_drdy_flag){
    			ads1292_drdy_flag = false;
    			ads1292ReadData();
    		}
    		/*
    		if(ads1292_dat_read_flag){
    			ads1292_dat_read_flag = false;
    			sendData();
    		}
    		*/
    			
    	}

Reply
  • Thanks for replying.

    I tested using 500K.

    And, it doesn't work.

    I changed code to use flag in main loop.

    But, it also doesn't work.

    When i delete ads1292ReadData(), drdy worked.
    Is there any problem in SDK when using scheduleSPI()?

    	for (;;)
    	{
    		if (NRF_LOG_PROCESS() == false)
    		{
    			idle_state_handle();
    		}
    		
    		if(ads1292_drdy_flag){
    			ads1292_drdy_flag = false;
    			ads1292ReadData();
    		}
    		/*
    		if(ads1292_dat_read_flag){
    			ads1292_dat_read_flag = false;
    			sendData();
    		}
    		*/
    			
    	}

Children
No Data
Related