CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC24 IMU development - BMO085 9-DOF

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
benoitstjean



Joined: 30 Oct 2007
Posts: 595
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PIC24 IMU development - BMO085 9-DOF
PostPosted: Wed Dec 03, 2025 10:08 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Dec 03, 2025 11:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Dec 03, 2025 11:38 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Dec 03, 2025 11:59 am     Reply with quote

I guess the library you are referring to on GitHub is for Arduino, not PIC?

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 19996

View user's profile Send private message

PostPosted: Wed Dec 03, 2025 12:00 pm     Reply with quote

[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

View user's profile Send private message

PostPosted: Wed Dec 03, 2025 1:02 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Dec 11, 2025 10:49 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Dec 11, 2025 11:56 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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