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

Reply
  • 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

Children
  • 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.

  • I will say firstly that there is one issue with that code that I discivered later on. You need to configure and pull high the CS pin for the ADXL372 as it will cause fatal errors with the SPI periheral where you can't communicate with the ADXL362 until a power cycle that allows all caps to discharge. This was due to the other CS pin being floating and pulling itself LOW.

    Yes I consider CS as a GPIO as I just need to control it when I manage the ADXL362. In this manner, it is simply a GPIO with logic High and Low.

    You can treat the ADXL362 INT pin as a button style logic. Set-up your ISR callback as normal, setting the GPIO options for the INT pin with double edge detection (or rising edge detection if you decide to manually service the status register, i.e. not linked mode/self-servicing). From there, the ISR will trigger whenever your INT options are fulfilled by the ADXL362 registers.

    In manual mode you will need to treat it like a button as the INT pin is not held HIGH until sleep mode from ADXL362, it is held HIGH indefinitely until the status register is serviced. In self-servicing, you can treat it like a normal logic interrupt as the HIGH or Low are the awake/sleep modes of the ADXL362.

  • 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

Related