Skip to content

Commit b19a833

Browse files
authored
Merge pull request #5 from sparkfun/arduino_interface_fwd_declarations
Arduino interface fwd declarations
2 parents 628a63b + 30ff11f commit b19a833

File tree

7 files changed

+742
-49
lines changed

7 files changed

+742
-49
lines changed

examples/Arduino/Example2_Advanced/Example2_Advanced.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define SERIAL_PORT Serial
1818

1919
#define SPI_PORT SPI // Your desired SPI port. Used only when "USE_SPI" is defined
20+
#define SPI_FREQ 10000000// You can override the default SPI frequency
2021
#define CS_PIN 2 // Which pin you connect CS to. Used only when "USE_SPI" is defined
2122

2223
#define WIRE_PORT Wire // Your desired Wire port. Used when "USE_SPI" is not defined
@@ -47,7 +48,7 @@ void setup() {
4748
while( !initialized ){
4849

4950
#ifdef USE_SPI
50-
myICM.begin( CS_PIN, SPI_PORT );
51+
myICM.begin( CS_PIN, SPI_PORT, SPI_FREQ ); // Here we are using the user-defined SPI_FREQ as the clock speed of the SPI bus
5152
#else
5253
myICM.begin( WIRE_PORT, AD0_VAL );
5354
#endif
@@ -61,7 +62,6 @@ void setup() {
6162
initialized = true;
6263
}
6364
}
64-
}
6565

6666
// In this advanced example we'll cover how to do a more fine-grained setup of your sensor
6767
SERIAL_PORT.println("Device connected!");
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
/****************************************************************
2+
* Example3_Interrupts.ino
3+
* ICM 20948 Arduino Library Demo
4+
* Builds on Example2_Advanced.ino to set up interrupts when data is ready
5+
* Owen Lyke @ SparkFun Electronics
6+
* Original Creation Date: June 5 2019
7+
*
8+
* For this example you must connect the interrupt pin "INT" on the breakout
9+
* board to the pin specified by "INT_PIN" on your microcontroller.
10+
*
11+
* This code is beerware; if you see me (or any other SparkFun employee) at the
12+
* local, and you've found our code helpful, please buy us a round!
13+
*
14+
* Distributed as-is; no warranty is given.
15+
***************************************************************/
16+
#include "ICM_20948.h" // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU
17+
18+
//#define USE_SPI // Uncomment this to use SPI
19+
20+
#define SERIAL_PORT Serial
21+
22+
#define INT_PIN 2 // Make sure to connect this pin on your uC to the "INT" pin on the ICM-20948 breakout
23+
#define LED_PIN 13
24+
//#define LED_PIN LED_BUILTIN
25+
#define BUFFER_SAMPLE_NUM 32
26+
27+
#define SPI_PORT SPI // Your desired SPI port. Used only when "USE_SPI" is defined
28+
#define SPI_FREQ 5000000// You can override the default SPI frequency
29+
#define CS_PIN 2 // Which pin you connect CS to. Used only when "USE_SPI" is defined
30+
31+
#define WIRE_PORT Wire // Your desired Wire port. Used when "USE_SPI" is not defined
32+
#define AD0_VAL 1 // The value of the last bit of the I2C address.
33+
// On the SparkFun 9DoF IMU breakout the default is 1, and when
34+
// the ADR jumper is closed the value becomes 0
35+
36+
#ifdef USE_SPI
37+
ICM_20948_SPI myICM; // If using SPI create an ICM_20948_SPI object
38+
#else
39+
ICM_20948_I2C myICM; // Otherwise create an ICM_20948_I2C object
40+
#endif
41+
42+
// Some vars to control or respond to interrupts
43+
volatile bool isrFired = false;
44+
volatile bool sensorSleep = false;
45+
volatile bool canToggle = false;
46+
47+
void setup() {
48+
49+
pinMode(INT_PIN, INPUT_PULLUP); // Using a pullup b/c ICM-20948 Breakout board has an onboard pullup as well and we don't want them to compete
50+
attachInterrupt(digitalPinToInterrupt(INT_PIN), icmISR, FALLING); // Set up a falling interrupt
51+
52+
pinMode(LED_PIN, OUTPUT);
53+
digitalWrite(LED_PIN, !sensorSleep);
54+
55+
SERIAL_PORT.begin(115200);
56+
while(!SERIAL_PORT){};
57+
58+
#ifdef USE_SPI
59+
SPI_PORT.begin();
60+
#else
61+
WIRE_PORT.begin();
62+
WIRE_PORT.setClock(400000);
63+
#endif
64+
65+
bool initialized = false;
66+
while( !initialized ){
67+
68+
#ifdef USE_SPI
69+
myICM.begin( CS_PIN, SPI_PORT, SPI_FREQ ); // Here we are using the user-defined SPI_FREQ as the clock speed of the SPI bus
70+
#else
71+
myICM.begin( WIRE_PORT, AD0_VAL );
72+
#endif
73+
74+
SERIAL_PORT.print( F("Initialization of the sensor returned: ") );
75+
SERIAL_PORT.println( myICM.statusString() );
76+
if( myICM.status != ICM_20948_Stat_Ok ){
77+
SERIAL_PORT.println( "Trying again..." );
78+
delay(500);
79+
}else{
80+
initialized = true;
81+
}
82+
}
83+
84+
// In this advanced example we'll cover how to do a more fine-grained setup of your sensor
85+
SERIAL_PORT.println("Device connected!");
86+
87+
// Here we are doing a SW reset to make sure the device starts in a known state
88+
myICM.swReset( );
89+
if( myICM.status != ICM_20948_Stat_Ok){
90+
SERIAL_PORT.print(F("Software Reset returned: "));
91+
SERIAL_PORT.println(myICM.statusString());
92+
}
93+
delay(250);
94+
95+
// Now wake the sensor up
96+
myICM.sleep( sensorSleep );
97+
myICM.lowPower( false );
98+
99+
// The next few configuration functions accept a bit-mask of sensors for which the settings should be applied.
100+
101+
// Set Gyro and Accelerometer to a particular sample mode
102+
// options: ICM_20948_Sample_Mode_Continuous
103+
// ICM_20948_Sample_Mode_Cycled
104+
myICM.setSampleMode( (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), ICM_20948_Sample_Mode_Cycled );
105+
SERIAL_PORT.print(F("setSampleMode returned: "));
106+
SERIAL_PORT.println(myICM.statusString());
107+
108+
109+
ICM_20948_smplrt_t mySmplrt;
110+
mySmplrt.g = 54;
111+
myICM.setSampleRate( ICM_20948_Internal_Gyr, mySmplrt );
112+
SERIAL_PORT.print(F("setSampleRate returned: "));
113+
SERIAL_PORT.println(myICM.statusString());
114+
115+
// Set full scale ranges for both acc and gyr
116+
ICM_20948_fss_t myFSS; // This uses a "Full Scale Settings" structure that can contain values for all configurable sensors
117+
118+
myFSS.a = gpm2; // (ICM_20948_ACCEL_CONFIG_FS_SEL_e)
119+
// gpm2
120+
// gpm4
121+
// gpm8
122+
// gpm16
123+
124+
myFSS.g = dps250; // (ICM_20948_GYRO_CONFIG_1_FS_SEL_e)
125+
// dps250
126+
// dps500
127+
// dps1000
128+
// dps2000
129+
130+
myICM.setFullScale( (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), myFSS );
131+
if( myICM.status != ICM_20948_Stat_Ok){
132+
SERIAL_PORT.print(F("setFullScale returned: "));
133+
SERIAL_PORT.println(myICM.statusString());
134+
}
135+
136+
137+
// Set up Digital Low-Pass Filter configuration
138+
ICM_20948_dlpcfg_t myDLPcfg; // Similar to FSS, this uses a configuration structure for the desired sensors
139+
myDLPcfg.a = acc_d473bw_n499bw; // (ICM_20948_ACCEL_CONFIG_DLPCFG_e)
140+
// acc_d246bw_n265bw - means 3db bandwidth is 246 hz and nyquist bandwidth is 265 hz
141+
// acc_d111bw4_n136bw
142+
// acc_d50bw4_n68bw8
143+
// acc_d23bw9_n34bw4
144+
// acc_d11bw5_n17bw
145+
// acc_d5bw7_n8bw3 - means 3 db bandwidth is 5.7 hz and nyquist bandwidth is 8.3 hz
146+
// acc_d473bw_n499bw
147+
148+
myDLPcfg.g = gyr_d361bw4_n376bw5; // (ICM_20948_GYRO_CONFIG_1_DLPCFG_e)
149+
// gyr_d196bw6_n229bw8
150+
// gyr_d151bw8_n187bw6
151+
// gyr_d119bw5_n154bw3
152+
// gyr_d51bw2_n73bw3
153+
// gyr_d23bw9_n35bw9
154+
// gyr_d11bw6_n17bw8
155+
// gyr_d5bw7_n8bw9
156+
// gyr_d361bw4_n376bw5
157+
158+
myICM.setDLPFcfg( (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), myDLPcfg );
159+
if( myICM.status != ICM_20948_Stat_Ok){
160+
SERIAL_PORT.print(F("setDLPcfg returned: "));
161+
SERIAL_PORT.println(myICM.statusString());
162+
}
163+
164+
// Choose whether or not to use DLPF
165+
// Here we're also showing another way to access the status values, and that it is OK to supply individual sensor masks to these functions
166+
ICM_20948_Status_e accDLPEnableStat = myICM.enableDLPF( ICM_20948_Internal_Acc, true );
167+
ICM_20948_Status_e gyrDLPEnableStat = myICM.enableDLPF( ICM_20948_Internal_Gyr, true );
168+
SERIAL_PORT.print(F("Enable DLPF for Accelerometer returned: ")); SERIAL_PORT.println(myICM.statusString(accDLPEnableStat));
169+
SERIAL_PORT.print(F("Enable DLPF for Gyroscope returned: ")); SERIAL_PORT.println(myICM.statusString(gyrDLPEnableStat));
170+
171+
// Now we're going to set up interrupts. There are a lot of options, but for this test we're just configuring the interrupt pin and enabling interrupts to tell us when new data is ready
172+
/*
173+
ICM_20948_Status_e cfgIntActiveLow ( bool active_low );
174+
ICM_20948_Status_e cfgIntOpenDrain ( bool open_drain );
175+
ICM_20948_Status_e cfgIntLatch ( bool latching ); // If not latching then the interrupt is a 50 us pulse
176+
177+
ICM_20948_Status_e cfgIntAnyReadToClear ( bool enabled ); // If enabled, *ANY* read will clear the INT_STATUS register. So if you have multiple interrupt sources enabled be sure to read INT_STATUS first
178+
179+
ICM_20948_Status_e cfgFsyncActiveLow ( bool active_low );
180+
ICM_20948_Status_e cfgFsyncIntMode ( bool interrupt_mode ); // Can ue FSYNC as an interrupt input that sets the I2C Master Status register's PASS_THROUGH bit
181+
182+
ICM_20948_Status_e intEnableI2C ( bool enable );
183+
ICM_20948_Status_e intEnableDMP ( bool enable );
184+
ICM_20948_Status_e intEnablePLL ( bool enable );
185+
ICM_20948_Status_e intEnableWOM ( bool enable );
186+
ICM_20948_Status_e intEnableWOF ( bool enable );
187+
ICM_20948_Status_e intEnableRawDataReady ( bool enable );
188+
ICM_20948_Status_e intEnableOverflowFIFO ( uint8_t bm_enable );
189+
ICM_20948_Status_e intEnableWatermarkFIFO ( uint8_t bm_enable );
190+
*/
191+
myICM.cfgIntActiveLow(true); // Active low to be compatible with the breakout board's pullup resistor
192+
myICM.cfgIntOpenDrain(false); // Push-pull, though open-drain would also work thanks to the pull-up resistors on the breakout
193+
myICM.cfgIntLatch(true); // Latch the interrupt until cleared
194+
SERIAL_PORT.print(F("cfgIntLatch returned: "));
195+
SERIAL_PORT.println(myICM.statusString());
196+
197+
myICM.intEnableRawDataReady(true); // enable interrupts on raw data ready
198+
SERIAL_PORT.print(F("intEnableRawDataReady returned: "));
199+
SERIAL_PORT.println(myICM.statusString());
200+
201+
202+
// // Note: weirdness with the Wake on Motion interrupt being always enabled.....
203+
// uint8_t zero_0 = 0xFF;
204+
// ICM_20948_execute_r( &myICM._device, AGB0_REG_INT_ENABLE, (uint8_t*)&zero_0, sizeof(uint8_t) );
205+
// Serial.print("INT_EN was: 0x"); Serial.println(zero_0, HEX);
206+
// zero_0 = 0x00;
207+
// ICM_20948_execute_w( &myICM._device, AGB0_REG_INT_ENABLE, (uint8_t*)&zero_0, sizeof(uint8_t) );
208+
209+
SERIAL_PORT.println();
210+
SERIAL_PORT.println(F("Configuration complete!"));
211+
}
212+
213+
void loop() {
214+
if( isrFired ){ // If our isr flag is set then clear the interrupts on the ICM
215+
isrFired = false;
216+
myICM.getAGMT(); // get the A, G, M, and T readings
217+
// myICM.clearInterrupts(); // This would be efficient... but not compatible with Uno
218+
}
219+
220+
myICM.clearInterrupts(); // clear interrupts for next time -
221+
// usually you'd do this only if an interrupt has occurred, however
222+
// on the 328p I2C usage can block interrupts. This means that sometimes
223+
// an interrupt is missed. When missed, if using an edge-based interrupt
224+
// and only clearing interrupts when one was detected there will be no more
225+
// edges to respond to, so no more interrupts will be detected. Here are
226+
// some possible solutions:
227+
// 1. use a level based interrupt
228+
// 2. use the pulse-based interrupt in ICM settings (set cfgIntLatch to false)
229+
// 3. use a microcontroller with nestable interrupts
230+
// 4. clear the interrupts often
231+
232+
233+
if( (millis()%1000) < 5){ // This is a method to turn the sensor on and off once per second without using delays
234+
if( canToggle ){
235+
sensorSleep = !sensorSleep;
236+
myICM.sleep( sensorSleep );
237+
digitalWrite(LED_PIN, !sensorSleep);
238+
canToggle = false;
239+
}
240+
}
241+
if( (millis()%1000) > 500 ){
242+
canToggle = true;
243+
}
244+
}
245+
246+
void icmISR( void ){
247+
isrFired = true; // Can't use I2C within ISR on 328p, so just set a flag to know that data is available
248+
}
249+
250+
251+
// Below here are some helper functions to print the data nicely!
252+
void printPaddedInt16b( int16_t val ){
253+
if(val > 0){
254+
SERIAL_PORT.print(" ");
255+
if(val < 10000){ SERIAL_PORT.print("0"); }
256+
if(val < 1000 ){ SERIAL_PORT.print("0"); }
257+
if(val < 100 ){ SERIAL_PORT.print("0"); }
258+
if(val < 10 ){ SERIAL_PORT.print("0"); }
259+
}else{
260+
SERIAL_PORT.print("-");
261+
if(abs(val) < 10000){ SERIAL_PORT.print("0"); }
262+
if(abs(val) < 1000 ){ SERIAL_PORT.print("0"); }
263+
if(abs(val) < 100 ){ SERIAL_PORT.print("0"); }
264+
if(abs(val) < 10 ){ SERIAL_PORT.print("0"); }
265+
}
266+
SERIAL_PORT.print(abs(val));
267+
}
268+
269+
void printRawAGMT( ICM_20948_AGMT_t agmt){
270+
SERIAL_PORT.print("RAW. Acc [ ");
271+
printPaddedInt16b( agmt.acc.axes.x );
272+
SERIAL_PORT.print(", ");
273+
printPaddedInt16b( agmt.acc.axes.y );
274+
SERIAL_PORT.print(", ");
275+
printPaddedInt16b( agmt.acc.axes.z );
276+
SERIAL_PORT.print(" ], Gyr [ ");
277+
printPaddedInt16b( agmt.gyr.axes.x );
278+
SERIAL_PORT.print(", ");
279+
printPaddedInt16b( agmt.gyr.axes.y );
280+
SERIAL_PORT.print(", ");
281+
printPaddedInt16b( agmt.gyr.axes.z );
282+
SERIAL_PORT.print(" ], Mag [ ");
283+
printPaddedInt16b( agmt.mag.axes.x );
284+
SERIAL_PORT.print(", ");
285+
printPaddedInt16b( agmt.mag.axes.y );
286+
SERIAL_PORT.print(", ");
287+
printPaddedInt16b( agmt.mag.axes.z );
288+
SERIAL_PORT.print(" ], Tmp [ ");
289+
printPaddedInt16b( agmt.tmp.val );
290+
SERIAL_PORT.print(" ]");
291+
SERIAL_PORT.println();
292+
}
293+
294+
295+
void printFormattedFloat(float val, uint8_t leading, uint8_t decimals){
296+
float aval = abs(val);
297+
if(val < 0){
298+
SERIAL_PORT.print("-");
299+
}else{
300+
SERIAL_PORT.print(" ");
301+
}
302+
for( uint8_t indi = 0; indi < leading; indi++ ){
303+
uint32_t tenpow = 0;
304+
if( indi < (leading-1) ){
305+
tenpow = 1;
306+
}
307+
for(uint8_t c = 0; c < (leading-1-indi); c++){
308+
tenpow *= 10;
309+
}
310+
if( aval < tenpow){
311+
SERIAL_PORT.print("0");
312+
}else{
313+
break;
314+
}
315+
}
316+
if(val < 0){
317+
SERIAL_PORT.print(-val, decimals);
318+
}else{
319+
SERIAL_PORT.print(val, decimals);
320+
}
321+
}
322+
323+
void printScaledAGMT( ICM_20948_AGMT_t agmt){
324+
SERIAL_PORT.print("Scaled. Acc (mg) [ ");
325+
printFormattedFloat( myICM.accX(), 5, 2 );
326+
SERIAL_PORT.print(", ");
327+
printFormattedFloat( myICM.accY(), 5, 2 );
328+
SERIAL_PORT.print(", ");
329+
printFormattedFloat( myICM.accZ(), 5, 2 );
330+
SERIAL_PORT.print(" ], Gyr (DPS) [ ");
331+
printFormattedFloat( myICM.gyrX(), 5, 2 );
332+
SERIAL_PORT.print(", ");
333+
printFormattedFloat( myICM.gyrY(), 5, 2 );
334+
SERIAL_PORT.print(", ");
335+
printFormattedFloat( myICM.gyrZ(), 5, 2 );
336+
SERIAL_PORT.print(" ], Mag (uT) [ ");
337+
printFormattedFloat( myICM.magX(), 5, 2 );
338+
SERIAL_PORT.print(", ");
339+
printFormattedFloat( myICM.magY(), 5, 2 );
340+
SERIAL_PORT.print(", ");
341+
printFormattedFloat( myICM.magZ(), 5, 2 );
342+
SERIAL_PORT.print(" ], Tmp (C) [ ");
343+
printFormattedFloat( myICM.temp(), 5, 2 );
344+
SERIAL_PORT.print(" ]");
345+
SERIAL_PORT.println();
346+
}

0 commit comments

Comments
 (0)