MC3479 Accelerometer Troubles - Page 1
Forum section: electronics / beginners

author: CMASupra
author_rank: Newbie
timestamp: January 20, 2021, 04:39:29 am
content: Hello. I'm trying to use an accelerometer (the mCube or MEMSIC MC3479) to detect when a user is shaking my device (a dice) in their hand. This accelerometer supports "shake" interrupts, which is the feature I am having trouble getting working.I successfully got "tilt" interrupts working (though the interrupts only came when I had the dice flat, not when tilted, which seems backward). The only difference in my code between using "tilt" and "shake" interrupts is in the initialization code.Getting the "tilt" interrupts working (though backward) makes me confident I'm successfully reading and writing with the accelerometer and that my interrupt line coming from INTN1 on the accelerometer going to the microcontroller is working. It makes me believe that the problem is either in the accelerometer itself or in my accelerometer initialization code.The accelerometer initialization code for "shake" interrupts (not working):Code:// Set up the accelerometer (ACC) by writing data to it through SPI.spiWriteToAcc(0x07, 0x00); // enter STANDBY state and disable I2C WDTwhile ((spiReadFromAcc(0x05) & 0x03) != 0x00); // wait for the ACC to enter STANDBY statespiWriteToAcc(0x33, 0x88); // INTN2 = push-pull & active-low. INTN1 = push-pull & active-low.spiWriteToAcc(0x08, 0x13); // set internal data rate (IDR) to 100HzspiWriteToAcc(0x20, 0x20); // 8g range (4096 steps), no low pass filterspiWriteToAcc(0x2D, 0x08); // FIFO disabled, all interrupts combined onto INTN1spiWriteToAcc(0x31, 0x00); // don't swap INTN1 and INTN2, 4-wire SPI mode, clear all interrupts togetherspiWriteToAcc(0x09, 0x4C); // enable ANYM and SHAKE features, use real-time raw dataspiWriteToAcc(0x46, 0x00); // set SHAKE threshold LSBspiWriteToAcc(0x47, 0x10); // set SHAKE threshold MSBspiWriteToAcc(0x48, 0x80); // set SHAKE duration LSBspiWriteToAcc(0x49, 0x30); // set SHAKE duration MSB and count thresholdspiWriteToAcc(0x06, 0x08); // only enable SHAKE interrupts, don't auto-clear interruptsspiWriteToAcc(0x07, 0x01); // enter WAKE state and disable I2C WDTwhile ((spiReadFromAcc(0x05) & 0x03) != 0x01); // wait for the ACC to enter WAKE statespiWriteToAcc(0x14, 0x00); // clear any pending interruptsThe accelerometer initialization code for "tilt" interrupts (working but backward):Code:// Set up the accelerometer (ACC) by writing data to it through SPI.spiWriteToAcc(0x07, 0x00); // enter STANDBY state and disable I2C WDTwhile ((spiReadFromAcc(0x05) & 0x03) != 0x00); // wait for the ACC to enter STANDBY statespiWriteToAcc(0x33, 0x88); // INTN2 = push-pull & active-low. INTN1 = push-pull & active-low.spiWriteToAcc(0x08, 0x13); // set internal data rate (IDR) to 100HzspiWriteToAcc(0x20, 0x20); // 8g range (4096 steps), no low pass filterspiWriteToAcc(0x2D, 0x08); // FIFO disabled, all interrupts combined onto INTN1spiWriteToAcc(0x31, 0x00); // don't swap INTN1 and INTN2, 4-wire SPI mode, clear all interrupts togetherspiWriteToAcc(0x09, 0x41); // enable TILT/FLIP feature, use real-time raw dataspiWriteToAcc(0x40, 0x20); // set TILT threshold LSB (lower number = device must be flatter to get interrupts)spiWriteToAcc(0x41, 0x00); // set TILT threshold MSBspiWriteToAcc(0x42, 0x04); // set TILT debounce timespiWriteToAcc(0x06, 0x01); // only enable TILT interrupts, don't auto-clear interruptsspiWriteToAcc(0x07, 0x01); // enter WAKE state and disable I2C WDTwhile ((spiReadFromAcc(0x05) & 0x03) != 0x01); // wait for the ACC to enter WAKE statespiWriteToAcc(0x14, 0x00); // clear any pending interruptsMain loop code looking for interrupts from the accelerometer:Code:int main(void){/* Replace with your application code */init();PORTA.OUT = 0x00; // turn all 7 LEDs on_delay_ms(500);PORTA.OUT = 0xFE; // turn all 7 LEDs off// Main loop.while (1){if ((PORTB.IN & 0x04) == 0x00) // if an interrupt has occurred{PORTA.OUT = nextVal(PORTA.OUT);spiWriteToAcc(0x14, 0x00); // clear the interrupt_delay_ms(200);}}}I should note that a "shake" interrupt seems to often trigger when I turn the dice off, back on, and then shake it. I am unable to get a second interrupt to trigger after that without restarting the dice again. This is only true with the "shake" initialization settings in the code above. If I use the following "shake" initialization settings, I very rarely get a single interrupt, and I never get multiple interrupts.Code:spiWriteToAcc(0x46, 0x00); // set SHAKE threshold LSBspiWriteToAcc(0x47, 0x10); // set SHAKE threshold MSBspiWriteToAcc(0x48, 0x02); // set SHAKE duration LSBspiWriteToAcc(0x49, 0x10); // set SHAKE duration MSB and count thresholdI have tried using "if ((spiReadFromAcc(0x13) & 0x08) != 0x00)" in my main loop instead of using "if ((PORTB.IN & 0x04) == 0x00)", and it seems the "shake" bit in register 0x13 of the accelerometer is reacting to me shaking the dice, but there isn't an interrupt at PORTB if I go back to the larger main loop code I pasted above.I have attached the relevant section of the schematic for my dice. VCC=3.0V for my testing.I appreciate any help that can be offered. I have access to a good amount of lab equipment if I should test anything, though my soldering skills are very bad so I'd rather not solder anything unless I have to.Edit:In case it helps, here are the functions I use to read and write to/from the accelerometer. The microcontroller is an ATtiny406 in a VQFN package.Code:uint8_t inline makeAccWriteCommand(uint8_t addr){return (addr & 0x7F); // clear the MSb to tell the ACC this is a write}uint8_t inline makeAccReadCommand(uint8_t addr){return (addr | 0x80); // set the MSb to tell the ACC this is a read}/*** Writes 1 byte of data to the accelerometer (ACC) over SPI.** @param addr Register address to write to on ACC.* @param data The byte to write to the register on the ACC.*/void spiWriteToAcc(uint8_t addr, uint8_t data){addr = makeAccWriteCommand(addr); // modify addr to be a writePORTC.OUTCLR = 0x08; // send SS low/activeSPI0.DATA = addr; // send the register address to the ACCwhile (!(SPI0.INTFLAGS & 0x80)); // wait for the data to be fully sentaddr = SPI0.DATA; // clear the interrupt flag by reading INTFLAGS and then DATASPI0.DATA = data; // send the register data to the ACCwhile (!(SPI0.INTFLAGS & 0x80)); // wait for the data to be fully sentaddr = SPI0.DATA; // clear the interrupt flag by reading INTFLAGS and then DATAPORTC.OUTSET = 0x08; // send SS high/inactive}/*** Reads 1 byte of data from the accelerometer (ACC) over SPI.** @param addr Register address to read on the ACC.* @return The byte of data read from the ACC.*/uint8_t spiReadFromAcc(uint8_t addr){addr = makeAccReadCommand(addr); // modify addr to be a readPORTC.OUTCLR = 0x08; // send SS low/activeSPI0.DATA = addr; // send the register address to the ACCwhile (!(SPI0.INTFLAGS & 0x80)); // wait for the data to be fully sentaddr = SPI0.DATA; // clear the interrupt flag by reading INTFLAGS and then DATASPI0.DATA = 0x00; // send a blank byte while waiting for the ACC to get the datawhile (!(SPI0.INTFLAGS & 0x80)); // wait for the data to be fully sentaddr = SPI0.DATA; // clear the interrupt flag by reading INTFLAGS and then DATASPI0.DATA = 0x00; // send a blank byte while reading from the ACCwhile (!(SPI0.INTFLAGS & 0x80)); // wait for the data to be fully sentaddr = SPI0.DATA; // clear the interrupt flag by reading INTFLAGS and then DATAPORTC.OUTSET = 0x08; // send SS high/inactivereturn addr; // return the data read from the ACC}

author: Kappa
author_rank: Newbie
timestamp: March 17, 2022, 01:56:44 pm
content: Did you find a solution to the problem? Considering using it.

author: CMASupra
author_rank: Newbie
timestamp: March 19, 2022, 05:17:09 pm
content: I did not find a solution even after trying the sample code provided by mCube online to use their MC3479A Evaluation Board with an Arduino DUE. What's weird is their sample code writes to registers that don't exist according to the datasheet.Arduino sample code:https://github.com/mcubemems/mCube_mc34x9_arduino_driverInstructions for sample code:https://mcubemems.com/wp-content/uploads/2020/02/EV3419A-QSG-and-Demo-APS-045-0033v1.0.pdfMC3479 datasheet:https://www.mouser.com/datasheet/2/821/20200827164636363-1900743.pdfPart of the problem is that I just don't understand the descriptions related to SHAKE in the datasheet (ANYMOTION threshold, ANYMOTION debounce, SHAKE threshold, SHAKE duration, SHAKE peak-to-peak). The descriptions are on pages 71-74 of the datasheet.I'm still open to advice from anyone.

author: tepalia02
author_rank: Regular Contributor
timestamp: May 11, 2022, 01:44:51 pm
content: Are you applying Kalman filtering? Without that, accelerometers and gyros are more likely to give unrealistic data.

author: CMASupra
author_rank: Newbie
timestamp: May 16, 2022, 03:12:48 pm
content: I’m not using any kind of filtering because I’m not looking at the raw data. I’m only trying to use the shake feature of the accelerometer, which I assume would do any filtering in hardware.However, thanks for telling me about that filtering. I do see that I was writing 0 to bit 6 of register 0x9, which means debounce was not being used. I can try enabling debounce and report back. You also gave me something to research if I have to use the raw data instead of the shake feature or a different accelerometer.