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

Use low power accelerator ADX362 on Thingy:91 board to wake up nRF9160

Hello there!

We would like to use INT1 pin of ADX362 low power accelerometer on Thingy:91 board to interrupt nRF9160 (e.g. wake it up) when some motion is detected.

To the best of my understanding, in asset tracker application you are polling the accelerometer in order to find out the orientation of the board (UPSIDE_DOWN, UP, SIDE...).

Can you give me some hints on how should I configure P0.09 pin of nRF9160 SiP in order to be able to catch the interrupts as well as how should I configure ADX362 module to give me motion interrupts?

Thanks in advance for your time and efforts!

Sincerely,

Bojan.

Parents
  • For my prototyping, I set up the ADXL362 directly to get the kind of sensitivity and options I was looking for. Such as samples required to detect motion, time the device must be idle before triggering an inactive interrupt, etc.

    It might be a better idea to grab the ADXL362 datasheet and use the SPI peripheral directly to set-up the accelerometer. There is a SPI driver for the ADXL362 in the Zephyr repo under sensors or you can use the SPI example in the Zephyr samples to build your own driver functions which is what I did.

    The forum discussion may be of interest to your question

  • Hey, , thanks for sharing your experience with me! It is really appreciated!

    Indeed, it is better to use SPI peripheral and configure ADXL362 register by register than to use high-level functions in sensors library.

    I was able to read ADXL362 ID by using example you shared here. I noticed you consider CS pin like GPIO.

    Do I need to threat INT1 of ADXL362 as a button from nRF9160 point of view in order to be able to activate interrupt on nRF9160 when INT1 goes high?

    Sincerely,

    Bojan.

  • Hey, !

    I think you don't need to manually take care of the SPI's CS pin. Here is how you can specify CS pin during the initialization process:

    #define ADXL362_CS 8;
    struct device * spi_dev;
    struct device *gpio_dev;
    struct spi_cs_control cs_control;
    struct spi_config spi_cfg;
    
    static void spi_init(void)
    {
        const char* const spiName = "SPI_3";
        spi_dev = device_get_binding(spiName);
    
        if (spi_dev == NULL) {
                printk("Could not get %s device\n", spiName);
                return;
        }
    
        gpio_dev = device_get_binding("GPIO_0");
        if(!gpio_dev) {
            printk("could not find GPIO device\n");
            return;
        }
    
        cs_control.delay = 0;
        cs_control.gpio_dev = gpio_dev;
        cs_control.gpio_pin = ADXL362_CS;
        spi_cfg.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB;
        spi_cfg.frequency = 8000000;
        spi_cfg.slave = 0;
        spi_cfg.cs = &cs_control;
    
    }

    Cheers!

    Bojan.

  • Hey ,

    Well spotted, I was unaware that spi_cs_control was a thing. I have implemented it into the init routine and removed the CS pin controls from the read and write functions; it seems to be working as expected.

    Many thanks for that.

  • Hi, !

    What I am experiencing here is inconsistent behaviour of the system and I am getting crazy...

    Sometimes I successfully read ADXL362 ID, sometimes every SECOND read ID is successful, sometimes I can't read it at all!?

    Here is the piece of code I am using to read/write ADXL362 over SPI:

    int read_adxl362(struct device *spi, struct spi_config *spi_cfg,
                     u8_t addr, u8_t *data, u32_t num_bytes){
        
        int err = 0;
    
        /* read cmd */
        err = adxl362_access(spi, spi_cfg,
                               ADXL362_READ_CMD, addr, data, num_bytes);
        if (err) {
                printk("Error during SPI read\n");
                return -EIO;
        }
    
        return 0;       
    }
    
    int write_adxl362(struct device *spi, struct spi_config *spi_cfg,
                      u8_t addr, u8_t *data, u32_t num_bytes){
    
        int err = 0;
        /* write cmd */
        err = adxl362_access(spi, spi_cfg,
                               ADXL362_WRITE_CMD, addr, data, num_bytes);
        if (err) {
                printk("Error during SPI write\n");
                return -ENXIO;
        }
    
        return 0;
    }
    
    int adxl362_access(struct device *spi, struct spi_config *spi_cfg,
    			    u8_t cmd, u8_t addr, void *data, size_t len)
    {
    	u8_t access[2];
    	struct spi_buf bufs[] = {
    		{
    			.buf = access,
    		},
    		{
    			.buf = data,
    			.len = len
    		}
    	};
    	struct spi_buf_set tx = {
    		.buffers = bufs
    	};
    
    	access[0] = cmd;
          
            if (cmd == ADXL362_WRITE_CMD || cmd == ADXL362_READ_CMD) {
    		access[1] = addr;
    
    		bufs[0].len = 2;
    		tx.count = 2;
    
    		if (cmd == ADXL362_READ_CMD) {
    			struct spi_buf_set rx = {
    				.buffers = bufs,
    				.count = 2
    			};
    
    			return spi_transceive(spi, spi_cfg, &tx, &rx);
    		}
    	} else {
    		tx.count = 1;
                    return -EFAULT;
    	}
    }

    Gentlemen from Nordic, is this good way to read/write over SPI or I am missing something? Can you reference me to the point where I can read about proper SPI communication over nRF9160?

    , did you experience in the past some strange and inconsistent reading/writing ADXL362 registers? Can you share with me your code for accessing (reading/writing) ADXL362 registers?

    Thanks in advance!

    Sincerely,

    Bojan

  • I see you are trying to use the ADXL362 driver. I'm not surprised that you are having issues as I remember having issues with those as well.

    I decided to make my own seperate read and write functions for the SPI peripheral using only spi_tranceive() when reading and using spi_write when writing. See spi.h.

    The code is similar to what is in that function, just remove RX code from your write function and replace spi_tranceive() with spi_write().

    tx.count should be 1 when reading and 2 when writing.

  • Hey, .

    I don't try to use ADXL362 driver. Those are my functions for accessing ADXL362 based on SPIM example. Here is how I finally managed to access (read/write) ADXL362 internal registers:

    int read_adxl362(struct device *spi, const struct spi_config *spi_cfg,
                     u8_t addr, u8_t *data, u32_t num_bytes){
        
        int err = 0;
    
        /* read cmd */
        err = adxl362_access(spi, spi_cfg,
                               ADXL362_READ_CMD, addr, data, num_bytes);
        if (err) {
                printk("Error during SPI read\n");
                return -EIO;
        }
    
        return 0;       
    }
    
    int write_adxl362(struct device *spi, const struct spi_config *spi_cfg,
                      u8_t addr, u8_t *data, u32_t num_bytes){
    
        int err = 0;
        /* write cmd */
        err = adxl362_access(spi, spi_cfg,
                               ADXL362_WRITE_CMD, addr, data, num_bytes);
        if (err) {
                printk("Error during SPI write\n");
                return -ENXIO;
        }
    
        return 0;
    }
    
    int adxl362_access(struct device *spi, const struct spi_config *spi_cfg,
    			    u8_t cmd, u8_t addr, void *data, size_t len)
    {
    
    	int err;
    	static u8_t tx_buffer[2];
    	//static u8_t rx_buffer[1];
            tx_buffer[0] = cmd;
            tx_buffer[1] = addr;
    
    	const struct spi_buf tx_buf = {
    		.buf = tx_buffer,
    		.len = sizeof(tx_buffer)
    	};
    	const struct spi_buf_set tx = {
    		.buffers = &tx_buf,
    		.count = 1
    	};
    
    	struct spi_buf rx_buf = {
    		.buf = data,
    		.len = len + 2,
    	};
    	const struct spi_buf_set rx = {
    		.buffers = &rx_buf,
    		.count = 1
    	};
    
    	err = spi_transceive(spi_dev, spi_cfg, &tx, &rx);
    	if (err) {
    		printk("SPI error: %d\n", err);
    	}
    
            return err;
    }

    As you can see, I have a single rx and single tx buffer which seems to be logical. spi_write() function is actually spi_transcieve() with NULL argument on &rx place.

    Cheers,

    Bojan.

Reply
  • Hey, .

    I don't try to use ADXL362 driver. Those are my functions for accessing ADXL362 based on SPIM example. Here is how I finally managed to access (read/write) ADXL362 internal registers:

    int read_adxl362(struct device *spi, const struct spi_config *spi_cfg,
                     u8_t addr, u8_t *data, u32_t num_bytes){
        
        int err = 0;
    
        /* read cmd */
        err = adxl362_access(spi, spi_cfg,
                               ADXL362_READ_CMD, addr, data, num_bytes);
        if (err) {
                printk("Error during SPI read\n");
                return -EIO;
        }
    
        return 0;       
    }
    
    int write_adxl362(struct device *spi, const struct spi_config *spi_cfg,
                      u8_t addr, u8_t *data, u32_t num_bytes){
    
        int err = 0;
        /* write cmd */
        err = adxl362_access(spi, spi_cfg,
                               ADXL362_WRITE_CMD, addr, data, num_bytes);
        if (err) {
                printk("Error during SPI write\n");
                return -ENXIO;
        }
    
        return 0;
    }
    
    int adxl362_access(struct device *spi, const struct spi_config *spi_cfg,
    			    u8_t cmd, u8_t addr, void *data, size_t len)
    {
    
    	int err;
    	static u8_t tx_buffer[2];
    	//static u8_t rx_buffer[1];
            tx_buffer[0] = cmd;
            tx_buffer[1] = addr;
    
    	const struct spi_buf tx_buf = {
    		.buf = tx_buffer,
    		.len = sizeof(tx_buffer)
    	};
    	const struct spi_buf_set tx = {
    		.buffers = &tx_buf,
    		.count = 1
    	};
    
    	struct spi_buf rx_buf = {
    		.buf = data,
    		.len = len + 2,
    	};
    	const struct spi_buf_set rx = {
    		.buffers = &rx_buf,
    		.count = 1
    	};
    
    	err = spi_transceive(spi_dev, spi_cfg, &tx, &rx);
    	if (err) {
    		printk("SPI error: %d\n", err);
    	}
    
            return err;
    }

    As you can see, I have a single rx and single tx buffer which seems to be logical. spi_write() function is actually spi_transcieve() with NULL argument on &rx place.

    Cheers,

    Bojan.

Children
No Data
Related