what changes should be done if I use ICM 40627 instead of ICM 20608 .

Hi Team,

I am working on air mouse development using NRF 52832.

nrf standard package support ICM 20608 with AIR_Motion Library , but its not available now in  https://www.invensense.com/developers/software-downloads/ website.

now latest version ICM 40627 is available.

how to include this package and what all changes i should do with nrf std package to support ICM 40627.

Thank you

  • Hello,

    I wouldn't know. I believe you need to ask Invensense, who writes these libraries. 

    nrf standard package support ICM 20608 with AIR_Motion Library

    What do you mean by this? Do you have any references?

    Best regards,

    Edvin

  • AN-000275 Air Motion Library (AML) Integration Guide v1.0.pdf

    In this document invensense has mentioned migrating details in the beginning pages.

    at the page number '4 of 13' he has mentioned to include the driver file and  other files without any modification. 

    But just before the last point he has mentioned to change ' printer function and USB function adjust according to customer platform'

    what exactly changes i should do wrt to this comment.

    i am attaching code files for your reference.

    /*
     * ________________________________________________________________________________________________________
     * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved.
     *
     * This software, related documentation and any modifications thereto (collectively "Software") is subject
     * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
     * and other intellectual property rights laws.
     *
     * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
     * and any use, reproduction, disclosure or distribution of the Software without an express license agreement
     * from InvenSense is strictly prohibited.
     *
     * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
     * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
     * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
     * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
     * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
     * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     * OF THE SOFTWARE.
     * ________________________________________________________________________________________________________
     */
    
    #include "example-aml.h"
    
    #include "usb.h"
    
    
    extern void msg_printer(const char * str, ...);
    /* --------------------------------------------------------------------------------------
     *  Static and extern variables
     * -------------------------------------------------------------------------------------- */
    
    /* Icm406xx driver object */
    static struct inv_icm406xx icm_driver;
    
    
    /* ICM mounting matrix for AML referential.
     * For AML algorithm, accelerometer data are inverted compared to ICM convention, 
     * It expects gravity minus acceleration and ICM measures acceleration minus gravity */
    static int32_t accel_mounting_matrix[9]= {0,    1,    0,
                                              1,    0,    0,
                                              0,    0,    1 };
    
    static int32_t gyro_mounting_matrix[9]= { 0,   -1,    0,
                                             -1,    0,    0,
                                              0,    0,   -1 };
    
    /* Contains algorithms configuration */
    static InvnAlgoAMLConfig config;
    
    /* Contains algorithms inputs */
    static InvnAlgoAMLInput input;
    
    /* Contains algorithms outputs */
    static InvnAlgoAMLOutput output;
    
    /* Flag set once a UART RX frame is received */
    extern int irq_event_main_uart;
    
    /* Outptut data to print */
    extern uint32_t data_to_print;
    
    /* Keep track of the sensor timestamp */
    static uint64_t s_timestamp_us;
    
    /* --------------------------------------------------------------------------------------
     *  Functions definition
     * -------------------------------------------------------------------------------------- */
    static void print_algo_inputs_outputs(void);
    static void apply_mounting_matrix(const int32_t matrix[9], int16_t raw[3]);
    
    /*
     * This function set up the communication with the ICM chip.
     */
    int SetupInvDevice(struct inv_icm406xx_serif * icm_serif)
    {
    	int rc = 0;
    	uint8_t who_am_i;
    
    	/* Init device */
    	rc = inv_icm406xx_init(&icm_driver, icm_serif, HandleInvDeviceFifoPacket);
    	if (rc != INV_ERROR_SUCCESS) {
    		msg_printer("  !ERROR: Failed to initialize Icm406xx");
    		return rc;
    	}
    	
    	/* Check WHOAMI */
    	msg_printer("Check ICM whoami value");
    
    	rc = inv_icm406xx_get_who_am_i(&icm_driver, &who_am_i);
    	if (rc != INV_ERROR_SUCCESS) {
    		msg_printer("  !ERROR: Failed to read Icm406xx whoami value.");
    		return rc;
    	}	
    	if (who_am_i != ICM_WHOAMI) {
    		msg_printer("  !ERROR: Bad WHOAMI value. Got 0x%02x (expected: 0x%02x)", who_am_i, ICM_WHOAMI);
    		return INV_ERROR;
    	}
    	return rc;
    }
    
    /*
     * This function set up the MEMS (accel, gyro)
     */
    int ConfigureInvDevice(void)
    {
    	int rc = 0;
    	/* Set FSR */
    	rc |= inv_icm406xx_set_accel_fsr(&icm_driver, ACCEL_FSR_G);
    	rc |= inv_icm406xx_set_gyro_fsr(&icm_driver, GYRO_FSR_DPS);
    
    	/* Set frequencies */ 
    	rc |= inv_icm406xx_set_accel_frequency(&icm_driver, ACCEL_FREQ);
    	rc |= inv_icm406xx_set_gyro_frequency(&icm_driver, GYRO_FREQ);
    
    	/* Enable sensors */
    	rc |= inv_icm406xx_enable_accel_low_noise_mode(&icm_driver);
    	rc |= inv_icm406xx_enable_gyro_low_noise_mode(&icm_driver);
    	
    	return rc;
    }
    
    /*
     * This function set up the AML algorithm
     */
    int InitInvAMLAlgo(void)
    {
    	memset(&input, 0, sizeof(input));
    	memset(&output, 0, sizeof(output));
    	memset(&config, 0, sizeof(config));
    
    	/* FSR */
    	config.acc_fsr = 16;
    	config.gyr_fsr = 2000;
    
    	/* Delta Gain */
    	config.delta_gain[0] = INVN_ALGO_AML_DELTA_GAIN_DEFAULT;
    	config.delta_gain[1] = INVN_ALGO_AML_DELTA_GAIN_DEFAULT;
    
    	/* Initialize AML algorithms */
    	return invn_algo_aml_init(&icm_driver, &config);
    }
    
    /*
     * Function called to reset the Swipe recognition
     */
    void ResetInvAMLAlgoSwipeRecognition(void)
    {
    	invn_algo_aml_reset_swipe_recognition();
    	output.swipes_detected = 0;
    }
    
    /*
     * Function called to update the button click status
     */
    void ClickButton(bool on_off)
    {
    	input.click_button = on_off;
    
    	if (input.click_button)
    		ResetInvAMLAlgoSwipeRecognition();
    }
    
    /*
     * Function called if the MCU reveives an IRQ
     */
    int GetDataFromInvDevice(void)
    {
    	/*
    	 * Extract packets from FIFO. Callback defined at init time (i.e. 
    	 * HandleInvDeviceFifoPacket) will be called for each valid packet extracted from 
    	 * FIFO.
    	 */
    	return inv_icm406xx_get_data_from_fifo(&icm_driver);
    }
    
    /*
     * Callback called after fetching the accel and gyro value from the chip FIFO
     */
    void HandleInvDeviceFifoPacket(inv_icm406xx_sensor_event_t * event)
    {
    
    	/* Skipping processing if FIFO doesn't contain all required data */
    	if (   !(event->sensor_mask & (1 << INV_ICM406XX_SENSOR_ACCEL))
    		|| !(event->sensor_mask & (1 << INV_ICM406XX_SENSOR_GYRO)) )
    		return;
    
    	s_timestamp_us = inv_icm406xx_get_time_us();
    
    	input.racc_data[0] = event->accel[0];
    	input.racc_data[1] = event->accel[1];
    	input.racc_data[2] = event->accel[2];
    	
    	input.rgyr_data[0] = event->gyro[0];
    	input.rgyr_data[1] = event->gyro[1];
    	input.rgyr_data[2] = event->gyro[2];
    
    	apply_mounting_matrix(accel_mounting_matrix, input.racc_data);
    	apply_mounting_matrix(gyro_mounting_matrix, input.rgyr_data);
    
    	/* Process the AML algo */
    	invn_algo_aml_process(&input, &output);
    
    	/* Update USB HID interface with the delta output computed */
    	if (output.status & INVN_ALGO_AML_STATUS_DELTA_COMPUTED)
    	/* !!! Should be modified based on your own platform for usb hid function*/
    		inv_usb_hid_mouse_move(output.delta[0], output.delta[1]);
    
    	/* Update USB HID interface with the button click detected */
    	inv_usb_hid_mouse_button_click(input.click_button, false);
    
    	print_algo_inputs_outputs();
    }
    
    
    static void apply_mounting_matrix(const int32_t matrix[9], int16_t raw[3])
    {
    	unsigned i;
    	int16_t out_raw[3];
    	
    	for(i = 0; i < 3; i++) {
    		out_raw[i] =  ((int16_t)matrix[3*i+0] * raw[0]);
    		out_raw[i] += ((int16_t)matrix[3*i+1] * raw[1]);
    		out_raw[i] += ((int16_t)matrix[3*i+2] * raw[2]);
    	}
    
    	raw[0] = out_raw[0];
    	raw[1] = out_raw[1];
    	raw[2] = out_raw[2];
    }
    
    /* --------------------------------------------------------------------------------------
     *  Utility function for the data logging
     * -------------------------------------------------------------------------------------- */
    static void print_algo_inputs_outputs(void)
    {
    	static uint8_t prev_status;
    
    	/* Print intputs */
    	if (data_to_print & MASK_PRINT_INPUT_TEST) {
    		msg_printer("%d %d %d %d %d %d",
    			input.racc_data[0], input.racc_data[1], input.racc_data[2],
    			input.rgyr_data[0], input.rgyr_data[1], input.rgyr_data[2]
    			);
    	}
    	if (data_to_print & MASK_PRINT_INPUT_ACC_DATA) {
    		msg_printer("%lld: INPUT  RAcc=[%d %d %d]",
    			s_timestamp_us,
    			input.racc_data[0], input.racc_data[1], input.racc_data[2]
    			);
    	}
    	if (data_to_print & MASK_PRINT_INPUT_GYR_DATA) {
    		msg_printer("%lld: INPUT  RGyr=[%d %d %d]",
    			s_timestamp_us,
    			input.rgyr_data[0], input.rgyr_data[1], input.rgyr_data[2]
    			);
    	}
    	if ((data_to_print & MASK_PRINT_INPUT_CLICK) && (input.click_button)) {
    		msg_printer("%lld: INPUT  Click", s_timestamp_us);
    	}
    
    	/* Print outputs */
    	if ((data_to_print & MASK_PRINT_OUTPUT_STATUS) && (prev_status != output.status)) {
    		if (output.status & INVN_ALGO_AML_STATUS_STATIC)
    			msg_printer("%lld: OUTPUT Status Static", s_timestamp_us);
    		else
    			msg_printer("%lld: OUTPUT Status Non-static", s_timestamp_us);
    		prev_status = output.status;
    	}
    
    	if ((output.status & INVN_ALGO_AML_STATUS_NEW_GYRO_OFFSET)
    		&& (data_to_print & MASK_PRINT_OUTPUT_GYR_BIASES_DATA)) {
    		msg_printer("%lld: OUTPUT GyrBias(dps)=[%f, %f, %f]",
    			s_timestamp_us,
    			((float)output.gyr_offset[0] / 32768 * config.gyr_fsr) * 0.0625,
    			((float)output.gyr_offset[1] / 32768 * config.gyr_fsr) * 0.0625,
    			((float)output.gyr_offset[2] / 32768 * config.gyr_fsr) * 0.0625);
    	}
    
    	if ((output.status & INVN_ALGO_AML_STATUS_DELTA_COMPUTED)
    		&& (data_to_print & MASK_PRINT_OUTPUT_DELTA)) {
    		msg_printer("%lld: OUTPUT Pointing Delta=[%d, %d]",
    			s_timestamp_us,
    			output.delta[0], output.delta[1]);
    	}
    
    	if (data_to_print & MASK_PRINT_OUTPUT_SWIPES) {
    		if (output.swipes_detected & INVN_ALGO_AML_SWIPE_LEFT)
    			msg_printer("%lld: OUTPUT Swipe Left", s_timestamp_us);
    		if (output.swipes_detected & INVN_ALGO_AML_SWIPE_RIGTH)
    			msg_printer("%lld: OUTPUT Swipe Right", s_timestamp_us);
    		if (output.swipes_detected & INVN_ALGO_AML_SWIPE_UP)
    			msg_printer("%lld: OUTPUT Swipe Up", s_timestamp_us);
    		if (output.swipes_detected & INVN_ALGO_AML_SWIPE_DOWN)
    			msg_printer("%lld: OUTPUT Swipe Down", s_timestamp_us);
    		if (output.swipes_detected & INVN_ALGO_AML_SWIPE_CLOCKWISE)
    			msg_printer("%lld: OUTPUT Swipe Clockwise", s_timestamp_us);
    		if (output.swipes_detected & INVN_ALGO_AML_SWIPE_COUNTERCLOCKWISE)
    			msg_printer("%lld: OUTPUT Swipe Counter Clockwise", s_timestamp_us);
    
    		if (output.swipes_detected != 0) {
    			msg_printer("Click on button to restart the Swipe gesture Recognition");
    			/* Clear swipe detected flag */
    			output.swipes_detected = 0;
    		}
    	}
    
    	if (data_to_print & MASK_PRINT_OUTPUT_QUAT) {
    		msg_printer("%lld: OUTPUT Quat=[%f, %f, %f, %f]",
    		s_timestamp_us,
    		(float)output.quaternion[0] / (1 << 10), (float)output.quaternion[1] / (1 << 10), 
    		(float)output.quaternion[2] / (1 << 10), (float)output.quaternion[3] / (1 << 10));
    	}
    }
    
    /*
     * ________________________________________________________________________________________________________
     * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved.
     *
     * This software, related documentation and any modifications thereto (collectively "Software") is subject
     * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
     * and other intellectual property rights laws.
     *
     * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
     * and any use, reproduction, disclosure or distribution of the Software without an express license agreement
     * from InvenSense is strictly prohibited.
     *
     * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
     * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
     * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
     * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
     * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
     * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     * OF THE SOFTWARE.
     * ________________________________________________________________________________________________________
     */
    
    #include "example-aml.h"
    
    /* InvenSense utils */
    #include "Invn/ErrorHelper.h"
    #include <stdarg.h>
    /* board driver */
    #include "uart.h"
    #include "uart_mngr.h"
    #include "delay.h"
    #include "gpio.h"
    #include "timer.h"
    #include "usb.h"
    #include "common.h"
    #include "spi_master.h"
    #include "i2c_master.h"
    #include "system-interface.h"
    
    /* std */
    #include <stdio.h>
    
    /* --------------------------------------------------------------------------------------
     * Example configuration
     * 
     * *** Please refer to the example-aml.h for more configuration options ***
     *
     * -------------------------------------------------------------------------------------- */
    
    /*
     * Select UART port on which msg_printer() will be logged.
     */
    #define LOG_UART_ID INV_UART_SENSOR_CTRL
    
    /* 
     * Set of timers used throughout standalone applications 
     */
    #define TIMEBASE_TIMER INV_TIMER1
    #define DELAY_TIMER    INV_TIMER2
    
    #define INV_SPI_AP   INV_SPI_REVG
    #define ICM_I2C_ADDR   0x69
    #define TO_MASK(a) (1U << (unsigned)(a))
    
    /* --------------------------------------------------------------------------------------
     *  Global variables
     * -------------------------------------------------------------------------------------- */
    
    
    
    /*
     * Outptut data to print
     * Default behavior: no data to print
     */
    uint32_t data_to_print = 0;
    
    /* --------------------------------------------------------------------------------------
     *  Static variables
     * -------------------------------------------------------------------------------------- */
    
    /* Flag set from icm406xx device irq handler */
    static volatile int irq_from_device;
    
    /* Flag set once a click button is detected */
    static volatile bool irq_event_sw0_button = false;
    
    /* Flag set once the initialization is done */
    static bool ready_to_go = false;
    
    /* --------------------------------------------------------------------------------------
     *  Forward declaration
     * -------------------------------------------------------------------------------------- */
    
    static int SetupMCUHardware(struct inv_icm406xx_serif * icm_serif);
    static void ext_interrupt_inv_cb(void * context, unsigned int int_num);
    static void sw0_interrupt_cb(void * context, unsigned int int_num);
    static void usb_hid_suspend_action_cb(void);
    static void usb_hid_resume_action_cb(void);
    static char get_user_command_from_uart(void);
    static void process_user_command(void);
    static void print_help(void);
    void check_rc(int rc, const char * msg_context);
    void msg_printer(const char * str, ...);
    int inv_icm406xx_io_hal_read_reg(struct inv_icm406xx_serif * serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen);
    int inv_icm406xx_io_hal_write_reg(struct inv_icm406xx_serif * serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen);
    
    /* --------------------------------------------------------------------------------------
     *  Main
     * -------------------------------------------------------------------------------------- */
    
    int main(void)
    {
    	int rc = 0;
    	struct inv_icm406xx_serif icm406xx_serif;
    
    	/* Initialize MCU */
    	rc = SetupMCUHardware(&icm406xx_serif);
    	/* Initialize ICM device */
    	rc |= SetupInvDevice(&icm406xx_serif);
    	/* Initialize algorithm */
    	rc |= InitInvAMLAlgo();
    	/* Configure ICM device */
    	rc |= ConfigureInvDevice();
    	
    	check_rc(rc, "Error while configuring ICM device");
    	msg_printer( "OK");
    	ready_to_go = true;	
    	/* Print reminder on how to use example */
    	print_help();	
    	msg_printer( "Start processing");
    	do {
    		/* Check Icm406xx IRQ */
    		if (irq_from_device & TO_MASK(INV_GPIO_INT1)) {
    			inv_disable_irq();
    			irq_from_device &= ~TO_MASK(INV_GPIO_INT1);
    			inv_enable_irq();
    
    			rc = GetDataFromInvDevice();
    			check_rc(rc, "error while getting data from ICM device");
    
    			/* Clear SW0 button IRQ */
    			if (irq_event_sw0_button) {
    				/* Button is active low */
    				if (!inv_gpio_get_status(INV_GPIO_SW0_BUTTON)) {
    					ClickButton(true);
    				} else {
    					ClickButton(false);
    					
    					inv_disable_irq();
    					irq_event_sw0_button = false;
    					inv_enable_irq();
    				}
    			}
    		}
    		
    		process_user_command();
    		
    	} while(1);
    }
    
    
    /* --------------------------------------------------------------------------------------
     *  Functions definitions
     * -------------------------------------------------------------------------------------- */
    
    void process_user_command(void)
    {
    	uint8_t command_from_uart=0;
    	
    	command_from_uart = get_user_command_from_uart();
    	
    	switch(command_from_uart) {
    		case 'a': data_to_print ^= MASK_PRINT_INPUT_ACC_DATA;          break; /* Print input accel data */
    		case 'g': data_to_print ^= MASK_PRINT_INPUT_GYR_DATA;          break; /* Print input gyro data */
    		case 'c': data_to_print ^= MASK_PRINT_INPUT_CLICK;             break; /* Print input click */
    		case 'O': data_to_print ^= MASK_PRINT_OUTPUT_STATUS;           break; /* Print output status */ 
    		case 'G': data_to_print ^= MASK_PRINT_OUTPUT_GYR_BIASES_DATA;  break; /* Print output gyroscope biases data */
    		case 'D': data_to_print ^= MASK_PRINT_OUTPUT_DELTA;            break; /* Print output pointing delta */ 
    		case 'S': 
    			data_to_print ^= MASK_PRINT_OUTPUT_SWIPES;
    			ResetInvAMLAlgoSwipeRecognition(); /* Print output swipe gesture detected */
    			break;
    		case 'Q': data_to_print ^= MASK_PRINT_OUTPUT_QUAT;             break;
    		case 't': data_to_print ^= MASK_PRINT_INPUT_TEST;              break;
    		case 'h':
    		case 'H':
    			print_help(); /* Print helper command */
    			break;
    		case 0:
    			break; /* No command received */
    		default: 
    			msg_printer( "Unknown command : '%c'", command_from_uart);
    			print_help();
    			break;
    	}
    	if (command_from_uart)
    		msg_printer( "Received : '%c'", command_from_uart);
    }
    
    void print_help(void)
    {
    	msg_printer( "#########################");
    	msg_printer( "#   Help - Example AML   #");
    	msg_printer( "#########################");
    	msg_printer( "\t'a' : print input raw accel");
    	msg_printer( "\t'g' : print input raw gyro");
    	msg_printer( "\t'c' : print input click");
    	msg_printer( "\t'O' : print output status");
    	msg_printer( "\t'G' : print output gyroscope biases data");
    	msg_printer( "\t'D' : print delta data (pointing)");
    	msg_printer( "\t'S' : print swipes gesture detected");
    	msg_printer( "\t'Q' : print AG fusion quaternion");
    	msg_printer( "\t'h' : print this helper");
    }
    
    
    void config_uart(inv_uart_num_t log_uart_id)
    {
    	inv_uart_mngr_init_struct_t uart_mngr_config;
    	
    	uart_mngr_config.uart_num = log_uart_id;
    	uart_mngr_config.baudrate = 921600;
    	uart_mngr_config.flow_ctrl = INV_UART_FLOW_CONTROL_NONE;
    	inv_uart_mngr_init(&uart_mngr_config);
    }
    
    /*
     * This function initializes MCU on which this software is running.
     * It configures:
     *   - a UART link used to send traces to a terminal 
     *   - interrupt priority group and GPIOs so that MCU can receive interrupts from both ICM406xx
     *   - a microsecond timer requested by Icm406xx driver to compute some delay
     *   - a microsecond timer used to get some timestamps
     *   - a serial link to communicate from MCU to Icm406xx
     */
    static int SetupMCUHardware(struct inv_icm406xx_serif * icm_serif)
    {
    	int rc = 0;
    	inv_usb_init_struct_t usb_init;
    
    	inv_io_hal_board_init();
    
    	/* configure UART */
    	config_uart(LOG_UART_ID);
    
    	/* Start USB stack and provided callbacks */
    	usb_init.suspend_action_cb = usb_hid_suspend_action_cb;
    	usb_init.resume_action_cb  = usb_hid_resume_action_cb;
    	inv_usb_init(&usb_init);
    
    	/* Setup message facility to see internal traces from FW */
    	msg_printer( "###########################");
    	msg_printer( "#       Example AML       #");
    	msg_printer( "###########################");
    
    	/*
    	 * Configure input capture mode GPIO (pin PA30).
    	 * This pin is connected to Icm406xx INT1 output and thus will receive interrupts 
    	 * enabled on INT1 from the device.
    	 * A callback function is also passed that will be executed each time an interrupt
    	 * fires.
    	 */
    	inv_gpio_sensor_irq_init(INV_GPIO_INT1, ext_interrupt_inv_cb, 0);
    
    	/*
    	 * Configure input capture mode GPIO (pin PA02).
    	 * This pin is connected to SW0 button.
    	 * A callback function is also passed that will be executed each time an push 
    	 * button occurs.
    	 */
    	inv_gpio_sensor_irq_init(INV_GPIO_SW0_BUTTON, sw0_interrupt_cb, 0);
    
    	/* Init timer peripheral for delay */
    	inv_delay_init(DELAY_TIMER);
    
    	/*
    	 * Configure the timer for the timebase
    	 */
    	inv_timer_configure_timebase(1000000);
    	inv_timer_enable(TIMEBASE_TIMER);
    
    	/* Initialize serial inteface between MCU and Icm406xx */
    	icm_serif->context   = 0;        /* no need */
    	icm_serif->read_reg  = inv_icm406xx_io_hal_read_reg;
    	icm_serif->write_reg = inv_icm406xx_io_hal_write_reg;
    	icm_serif->configure = NULL;
    	icm_serif->max_read  = 1024*32;  /* maximum number of bytes allowed per serial read */
    	icm_serif->max_write = 1024*32;  /* maximum number of bytes allowed per serial write */
    	icm_serif->serif_type = SERIF_TYPE;
    	
    	switch (icm_serif->serif_type) {
    			case ICM406XX_UI_SPI4:
    			{
    				/* Default SPI frequency is 6 Mhz */
    				inv_spi_master_init(INV_SPI_AP, 6*1000*1000);
    				break;
    			}
    
    			case ICM406XX_UI_I2C:
    			    /* Set I2C clock is 400kHz by default */
    			    inv_i2c_master_init();
    			    break;
    			default:
    				return -1;
    		}
    
    		return 0;
    	
    	return rc;
    }
    
    /*
     * Icm406xx interrupt handler.
     * Function is executed when an Icm406xx interrupt rises on MCU.
     * This function get a timestamp and store it in a dedicated timestamp buffer.
     */
    void ext_interrupt_inv_cb(void * context, unsigned int int_num)
    {
    	(void)context;
    
    	irq_from_device |= TO_MASK(int_num);
    }
    
    /*
     * SW0 button interrupt handler.
     * Function is executed when releasing from a push button.
     */
    void sw0_interrupt_cb(void * context, unsigned int int_num)
    {
    	(void)context;
    	if (int_num == INV_GPIO_SW0_BUTTON) {
    		irq_event_sw0_button = true;
    	}
    }
    
    /*
     * USB HID suspend callback.
     * Function is executed when USB bus enter in suspend mode.
     */
    static void usb_hid_suspend_action_cb(void)
    {
    	if (ready_to_go)
    		msg_printer( "USB HID suspend");
    }
    
    /*
     * USB HID resume callback.
     * Function is executed when USB bus is wakeup.
     */
    static void usb_hid_resume_action_cb(void)
    {
    	if (ready_to_go)
    		msg_printer( "USB HID resume");
    }
    
    /* Get char command on the UART */
    static char get_user_command_from_uart(void)
    {
    	char rchar, cmd = 0;
    	
    	if(inv_uart_mngr_available(LOG_UART_ID) != 0) {
    		rchar = inv_uart_mngr_getc(LOG_UART_ID);
    		if (rchar != '\n')
    			cmd = rchar;
    	}
    	return cmd;
    }
    
    /*
     * Helper function to check RC value and block programm execution
     */
    void check_rc(int rc, const char * msg_context)
    {
    	if (rc < 0) {
    		msg_printer("%s: %d (%s)\r\n", msg_context, rc, inv_error_str(rc));
    		while(1);
    	}
    }
    
    /*
     * Printer function for message facility
     */
    void msg_printer(const char * str, ...)
    {
    	va_list ap;
    	va_start(ap, str);
    	static char out_str[256]; /* static to limit stack usage */
    	unsigned idx = 0;
    	idx += vsnprintf(&out_str[idx], sizeof(out_str) - idx, str, ap);
    	if (idx >= (sizeof(out_str)))
    		return;
    	idx += snprintf(&out_str[idx], sizeof(out_str) - idx, "\r\n");
    	if (idx >= (sizeof(out_str)))
    		return;
    
    	inv_uart_mngr_puts(LOG_UART_ID, out_str, idx);
    }
    
    
    /* ---------------------------------------------------
     * Low-level serial interface function implementation 
     * --------------------------------------------------- */
    
    int inv_icm406xx_io_hal_read_reg(struct inv_icm406xx_serif * serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
    {
    	switch (serif->serif_type) {
    		case ICM406XX_UI_SPI4:
    		        return inv_spi_master_read_register(INV_SPI_AP, reg, rlen, rbuffer);
    		case ICM406XX_UI_I2C:
    		       while(inv_i2c_master_read_register(ICM_I2C_ADDR, reg, rlen, rbuffer)) {
    			             inv_delay_us(32000); // Loop in case of I2C timeout
    		            }
    		       return 0;
    		default:
    		return -1;
    	}
    	
    }
    
    int inv_icm406xx_io_hal_write_reg(struct inv_icm406xx_serif * serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen)
    {
    	int rc;
    
    	switch (serif->serif_type) {
    		case ICM406XX_UI_SPI4:
    		for(uint32_t i=0; i<wlen; i++) {
    			rc = inv_spi_master_write_register(INV_SPI_AP, reg+i, 1, &wbuffer[i]);
    			if(rc)
    			return rc;
    		}
    		return 0;
    		case ICM406XX_UI_I2C:
    		while(inv_i2c_master_write_register(ICM_I2C_ADDR, reg, wlen, wbuffer)) {
    			inv_delay_us(32000); // Loop in case of I2C timeout
    		}
    		return 0;
    		default:
    		return -1;
    	}
    }
    
    /*
     * Icm406xx driver needs to get time in us. Let's give its implementation here.
     */
    uint64_t inv_icm406xx_get_time_us(void)
    {
    	return inv_timer_get_counter(TIMEBASE_TIMER);
    }
    
    /*
     * Icm406xx driver needs a sleep feature from external device. Thus inv_icm406xx_sleep_us
     * is defined as extern symbol in driver. Let's give its implementation here.
     */
    void inv_icm406xx_sleep_us(uint32_t us)
    {
    	inv_delay_us(us);
    }
    /*
     * Clock calibration module needs to disable IRQ. Thus inv_helper_disable_irq is
     * defined as extern symbol in clock calibration module. Let's give its implementation
     * here.
     */
    void inv_helper_disable_irq(void)
    {
    	inv_disable_irq();
    }
    
    /*
     * Clock calibration module needs to enable IRQ. Thus inv_helper_enable_irq is
     * defined as extern symbol in clock calibration module. Let's give its implementation
     * here.
     */
    void inv_helper_enable_irq(void)
    {
    	inv_enable_irq();
    }
    
    
    
    example-aml.h

  • Reference for ICM 20608: smart remote 3 package has driver file named "..\..\..\Source\Drivers\drv_gyro_icm20608.c'

  • Are you asking me how to port from Invensense's ICM 20608 library to Invensense's ICM 40627 driver? 

    I see that we used the 20608 in SR3 (smart remote 3), and I also know that we used eMD 6.12 in the Thingy:52 SDK, and we shared how to use these versions, since they are part of a reference design, but this is not something that we can maintain, and update for every release of 3rd party updates.

    If you need help porting to a later version, I suggest you reach out to Invensense. I am sorry, but I am not familiar with these libraries in depth. 

    Best regards,

    Edvin

  • ok Edvin. Thank you for the timely help. You can close the ticket

Related