 |
 |
| View previous topic :: View next topic |
| Author |
Message |
benoitstjean
Joined: 30 Oct 2007 Posts: 595 Location: Ottawa, Ontario, Canada
|
| PIC24 IMU development - BMO085 9-DOF |
Posted: Wed Dec 03, 2025 10:08 am |
|
|
Hi guys,
Anyone here has done any kind of implementation of 9-DOF (or 6-DOF) IMU devices with PICs?
I'm trying to find something simple that can provide a heading, I believe I can do that with a magnetometer and other components (hence the 9-DOF) but many of them that I find online are discontinued.
So really, just testing the waters here to see who has had good success with such device - a recent one that is not discontinued - and what is the part number.
Unless you have other ideas... basically, I just want to point the circuit in one direction, set that as my 0 base, then if I rotate it on the Z plane (let's say 55 degrees to the left), then the device will know that it was rotated 55 degrees to the left.
Thanks!
Ben
Last edited by benoitstjean on Thu Dec 11, 2025 10:42 am; edited 1 time in total |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19996
|
|
Posted: Wed Dec 03, 2025 11:29 am |
|
|
First thing to say is make sure you are looking at a 3.3v PIC. Though a lot
of the modules claim 3.3v and 5v operation, the PIC SPI, requires signals
to go to 0.8* the supply to be seen as 'high', and the chips usually cannot
guarantee this for a 5v PIC.
There is a driver for the ICM-20948 on GitHub. I'd suggest you look at
this. |
|
 |
benoitstjean
Joined: 30 Oct 2007 Posts: 595 Location: Ottawa, Ontario, Canada
|
|
Posted: Wed Dec 03, 2025 11:38 am |
|
|
Hmmmm.... not sure why that one didn't pop-up in my searches... The PIC24 on my circuit runs at 3.3V right now. I also have lever translators.
However, I don't like the fact that it says on DK website "Not For New Designs". Maybe there's a new replacement part.
Anyhow, I'll have a look.
Thanks!
Ben |
|
 |
benoitstjean
Joined: 30 Oct 2007 Posts: 595 Location: Ottawa, Ontario, Canada
|
|
Posted: Wed Dec 03, 2025 11:59 am |
|
|
I guess the library you are referring to on GitHub is for Arduino, not PIC?
Ben |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19996
|
|
Posted: Wed Dec 03, 2025 12:00 pm |
|
|
[url]
https://invensense.tdk.com/products/motion-tracking/9-axis/icm-20948/
[/url]
There are supply problems with the magnetometer wafers used in these.
The ICM-42670-P or the ICM-42688-P are the replacements. The former
is similar (9 axis), but the latter is only 6 axis.
The point is you'd need to start from the existing code, and modify it
yourself to suit the replacement sensor. |
|
 |
benoitstjean
Joined: 30 Oct 2007 Posts: 595 Location: Ottawa, Ontario, Canada
|
|
Posted: Wed Dec 03, 2025 1:02 pm |
|
|
Ah ok thanks for the heads-up.
But on Git-Hub, was there on in particular you were looking at?
Ben |
|
 |
benoitstjean
Joined: 30 Oct 2007 Posts: 595 Location: Ottawa, Ontario, Canada
|
|
Posted: Thu Dec 11, 2025 10:49 am |
|
|
I've settled with the BMO085 sensor on a small protoboard tied to a PIC24EP512GP806.
I have the base code below but it doesn't work, it returns "RX Error".
I'm just running this quickly here to see if someone has an idea as to what could be the issue, this is fresh code from today and I will continue to troubleshoot but if anyone sees anything off, that would be appreciated.
In case you ask, the reason I have void BNO085_SetupSPI(void) it's because the SPI port must be changed to reflect the BMO085 because due to using an existing PCB with an EEPROM on SPI3, in the EEPROM code, I do the same but to re-configure the code for the EEPROM since it's different.
When I do a re-factor of the PCB, I may change to another SPI for either IC.
Functional code for the IMU will be posted here for others to enjoy!
Thanks!
Ben
| Code: |
#define BNO085_INT PIN_C13 // Pin 47 -- Sensor interrupt input
#define BNO085_RESET PIN_B8 // Pin 21 -- Sensor reset active LOW output
#define BNO085_CS PIN_B10 // Pin 23 -- Sensor SPI chip select active LOW output
#define BNO085_P0_WAKE PIN_C14 // Pin 48 -- Sensor P0/WAKE output
unsigned int8 shtp_seq[6] = {0,0,0,0,0,0}; // One seq per channel
//-----------------------------------------------------------------------------
// Initialize BNO08x (SPI mode)
//-----------------------------------------------------------------------------
void BNO085_Init(void)
{
// Sensor reset (NRST)
output_high(BNO085_RESET);
delay_ms(10);
output_low(BNO085_RESET);
delay_ms(10);
output_high(BNO085_RESET);
delay_ms(20);
// WAKE high (idle), CS high
output_high(BNO085_P0_WAKE);
output_high(BNO085_CS);
// Startup delay: datasheet t1 + t2 ~94 ms, give margin
delay_ms(120);
// Wait for INT low (ready)
while( input( BNO085_INT ) == TRUE )
{
// waiting for HINTN low
}
// Discard initial advertisement/reset packets
{
unsigned int8 tmp[64] = {0};
while( !input( BNO085_INT ))
{
BNO085_ReceivePacket( tmp, sizeof( tmp ));
delay_ms(1);
}
}
}
//-----------------------------------------------------------------------------
// Get Product ID (basic communication test)
//-----------------------------------------------------------------------------
void BNO085_GetProductID(void)
{
unsigned int8 cmd[2] = { 0xF9, 0x00 }; // Product ID request
unsigned int8 rx[64];
int16 len;
// Send request on channel 2 (sensor hub control)
BNO085_SendPacket(2, cmd, 2);
// Wait for response
if( !BNO085_WaitIntLow( 200 ) == TRUE )
{
fprintf( MONITOR_SERIAL, " No response" );
return;
}
len = BNO085_ReceivePacket( rx, sizeof( rx ));
if( len <= 0 )
{
fprintf( MONITOR_SERIAL, " RX error\r\n" );
return;
}
// Product ID response: report 0xF8
if (rx[4] == 0xF8)
{
unsigned int8 sw_major = rx[6];
unsigned int8 sw_minor = rx[7];
fprintf( MONITOR_SERIAL, " Product ID %u.%u", sw_major, sw_minor );
}
else
{
fprintf( MONITOR_SERIAL, " Unexpected report 0x%X", rx[4] );
}
}
//-----------------------------------------------------------------------------
// Wait for INT low with timeout (ms)
//-----------------------------------------------------------------------------
int1 BNO085_WaitIntLow(unsigned int16 timeout_ms)
{
while (timeout_ms--)
{
if( !input( BNO085_INT ) == TRUE )
{
return 1;
}
delay_ms(1);
}
return 0; // timeout
}
//-----------------------------------------------------------------------------
// SPI setup helper
//-----------------------------------------------------------------------------
void BNO085_SetupSPI(void)
{
// BNO08x requires SPI mode 3 (CPOL=1, CPHA=1), up to 3 MHz
setup_spi3(SPI_MASTER | SPI_SCK_IDLE_HIGH | SPI_XMIT_H_TO_L | SPI_SAMPLE_AT_END | SPI_CLK_DIV_16);
}
//----------------------------------------------------------------------------
// Receive one SHTP packet into buffer; returns total bytes or -1.
//----------------------------------------------------------------------------
int16 BNO085_ReceivePacket(unsigned int8 *buffer, unsigned int16 max_len)
{
unsigned int16 total_len;
unsigned int16 cargo_len;
if( input( BNO085_INT ) == TRUE )
return 0; // no packet ready
BNO085_SetupSPI();
output_low( BNO085_CS );
delay_us(2);
// Read 4-byte SHTP header
buffer[0] = spi_write3(0xFF);
buffer[1] = spi_write3(0xFF);
buffer[2] = spi_write3(0xFF);
buffer[3] = spi_write3(0xFF);
total_len = buffer[0] | (( unsigned int16 ) buffer[1] << 8 );
total_len &= 0x7FFF; // strip continuation bit
if( total_len < 4 || total_len > max_len )
{
output_high( BNO085_CS );
return -1;
}
cargo_len = total_len - 4;
// Read payload
for( unsigned int16 i = 0; i < cargo_len; i++ )
{
buffer[4 + i] = spi_write3( 0xFF );
}
output_high( BNO085_CS );
return 4 + cargo_len;
}
//-----------------------------------------------------------------------------
// BNO08x SPI helpers
//-----------------------------------------------------------------------------
void BNO085_SendPacket(unsigned int8 channel, unsigned int8 *data, unsigned int16 len)
{
unsigned int16 total_len = len + 4; // include SHTP header
BNO085_SetupSPI();
// Wake pulse if asleep
output_low(BNO085_P0_WAKE);
delay_us(200);
output_high(BNO085_P0_WAKE);
// Wait for INT low
if (!BNO085_WaitIntLow(50))
return; // no response
output_low(BNO085_CS);
delay_us(2);
// SHTP header
spi_write3(total_len & 0xFF); // Length LSB
spi_write3((total_len >> 8) & 0x7F); // Length MSB (bit 15 continuation clear)
spi_write3(channel); // Channel
spi_write3(shtp_seq[channel]++); // Sequence
// Payload
for (unsigned int16 i = 0; i < len; i++) {
spi_write3(data[i]);
}
delay_us(2);
output_high(BNO085_CS);
}
|
|
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19996
|
|
Posted: Thu Dec 11, 2025 11:56 pm |
|
|
First, why are you using setup_spi?
#use spi is much more capable. It can do the entire 32bit transfer as a
single operation. Consider using this.
Also with this you can setup two streams for the different SPI modes
and the compiler will switch the configuration to match the stream
being used.
If you want to use setup_spi, use the following defines for mode numbers:
| Code: |
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
|
Your configuration looks wrong.
Then, get rid of your rotations to generate the transfer length and retrieve
the bytes from this. Use the make8 and make16 functions. Smaller, quicker,
less likely to go wrong. |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|