Using the Seeed Grove 6 Axis Accel/Gyro over I2C and Pin Interrupts with the Renesas DK-S124

Created by Austin Oltmanns, last modified on Aug 07, 2017

Welcome once again to this series on use of the DK-S124. In this guide, general use of the I2C peripheral will be covered along with specific use of Seeed’s breakout of the LSM6DS3 (an economical, easy to use IMU). Both the DK-S124 and the 6 axis IMU (Inertial Measurement Unit, seed part no. 105020012) are available at digikey.com. Renesas DK-S124: https://www.digikey.com/short/3v0383 and Seeed IMU: https://www.digikey.com/short/3v038f. This guide assumes you have completed the Getting Started guide and have a basic familiarity with e2 studio however, detailed instructions and links to previous guides will be given should something be unclear. As always, pertinent documents are linked below for reference.

This particular sensor will be easy to use because Renesas has provided a Grove connector on the board (there is one caveat to this as you will see below). Also, you may notice that there is already an accelerometer on the dev-board; but, there is no gyroscope. This makes it impossible/very difficult to measure any kind of rotation in an application, so a 6 axis IMU has been chosen instead.

For this example program, a resettable collision detection device will be made. Its function will be to poll the IMU for any acceleration/rotation beyond predefined acceptable limits. If the IMU does report something beyond these limits, an LED will be turned on until it is reset by one of the push buttons. To do this, two threads will be used: one to read the sensor and post a message if a collision is detected and another thread to manage the LED by turning it on when receiving a message and off if the push button is pressed through an interrupt by using the External IRQ Driver on r_icu.

Useful Links:

Dev-Board User’s Manual: https://www.renesas.com/en-us/doc/products/renesas-synergy/doc/r12um0006eu0100-synergy-dk-s124.pdf

S124 Data Sheet: https://www.renesas.com/en-us/doc/products/renesas-synergy/doc/r01ds0264eu0100_synergy_s124.pdf

S124 User’s Manual: https://www.renesas.com/en-us/doc/products/renesas-synergy/doc/r01um0003eu0120-synergy-s124.pdf

Synergy Software Package User’s Manual: https://synergygallery.renesas.com/media/products/1/156/en-US/r01us0171eu0096_synergy_ssp.pdf

Basics of Synergy Software Platform Book: https://www.renesas.com/en-us/media/products/synergy/book/Basics_of_the_Renesas_Synergy_Platform_1703.pdf

LSM6DS3 Data Sheet: http://www.st.com/content/ccc/resource/technical/document/datasheet/a3/f5/4f/ae/8e/44/41/d7/DM00133076.pdf/files/DM00133076.pdf/jcr:content/translations/en.DM00133076.pdf

:warning:Important Note
At the time of writing, Renesas has made a design error in the DK-S124, and the Grove I2C connector has been installed backwards. Because of this, the power and data lines have been flipped. If you plug in the Seeed IMU breakout board with the cable they have provided, it will not work! Fortunately, this should not damage the module, but no guarantees can be made if you do plug it in without first modifying the cable/connector. Instructions for doing this are given below.

Righting the Wrongs

Identify the problem

First thing to do, is to make sure your board actually has this problem. It’s possible that in a future revision, this error will have been corrected. Below is what the incorrect configuration is.

image

Following is what it should look like according to Seeed (the specifier of the Grove connector).
image

Notice that the Renesas connector is backwards.

To correct this error, there are a few options.

  1. Desolder the connector from the Renesas DK-S124, and resolder it with the proper orientation.
  2. Desolder the connector from the Seeed IMU and resolder it with the proper orientation.
  3. Cut the connector cable and swap the wires around, soldering them for a good connection.
  4. Pry the contacts in the cable connector on one end with a small screw-driver and reinsert them to make a crossover cable. (Best option)

Each option has its advantages and disadvantages. Option one would fix the error forever, but comes with the possibility of breaking your dev-board if you do not have a steady hand. Option two is similar to option one, but does not solve the problem and is made more difficult by the fact the connector is surface mount on the Seeed IMU and its contacts are bent one way already, as opposed to the through hole one on the DK-S124. Additionally, this would only solve the problem for this IMU and it could not be used for any other normal Grove connector, possibly making this the worst option. Option 3 is a simple option, but will leave you with an ugly cable. Finally, Option 4 is what will be covered in this guide as it offers the smallest liability to your components and will leave you with a nice Grove crossover cable (something which should not exist).

Moving the contacts around

To convert your Seeed Grove cable to a Renesas Grove-Evorg crossover cable, you will need a small screwdriver/pick that can pry underneath the plastic tabs holding the contacts in place.

image

Simply lift the small plastic tab and pull on the wire to release the socket. Do this for each wire on one and only one connector. Then reinsert the contacts in reverse order. When you are done, your IMU/Cable/Dev-board setup should look like this:
image
image
Note that the black wire is GND, the red wire is 3.3V, and the yellow and white wires are the I2C lines. The label and color matchups on the DK-S124 should match the label and color matchups on the Seeed IMU.

Configuring the Threads and Modules

Now that the hardware has been configured properly, it is time to setup the software. Create a new project in e2 studio, remembering to select the proper board (if this step seems unfamiliar, please refer to EWFSDAFSAD). Next, open up the project configuration tab and create a new thread. This will be the I2C thread, and it will post a message if the accelerometer is read to have an acceleration above a certain threshold (this could be a collision detection or a passenger safety warning).

After the thread has been created, add the I2C driver from Driver>Connectivity>I2C Master Driver on r_riic. Then, for this accelerometer the device Slave Address is 0x6A. Be sure to change this in the properties section of the I2C thread.

The second thread to create is the LED thread. This thread needs the Messaging Framework from Framework>Services>Messaging Framework on sf_message. Add it, and it will be configured from the Messaging Tab after this next driver is added. The other driver this thread will need is the External IRQ Driver on r_icu from Driver>Input>External IRQ driver on r_icu. Add it and change the Channel to 3 (the channel that SW2 is on), set Trigger to “Falling”, change the Callback to “irq3_callback” and the Interrupt Priority to “Priority 1”. Next, go to the pins tab and expand the Ports section. Make sure P004 is set in Input Mode, None for pullup, and IRQ3 for IRQ. It is not necessary to add the ioport driver to this thread, because that module is global to the entire application and is already present in the HAL/Common thread.

Next, go to the Messaging Tab of the configuration page. Create an event class called “COLLISION”. Add the LED Thread to the subscriber’s list. This will conclude the setup of the Threads and Modules, and you may save the configuration file and press the green Generate Project Content Button.

Adding the Code

If you open the src directory from the project explorer, you should see something like this depending on what you have named your threads. The next step is to add the header file for the custom message type we created in the Messaging Tab in the last set of instructions. Right click the “src” folder and navigate to New>Header File. Name it “collision_api.h”. Fill it with the following code:
collision_api.h

#ifndef COLLISION_API_H_
#define COLLISION_API_H_
#include "sf_message_api.h" //this is a message, so the message api is needed
 
typedef struct collision_payload_s
{
    sf_message_header_t header; //every message must include a header of this type
    uint8_t collision_type;
} collision_payload_t; //This name is specified in "Event Class" properties as "Payload Type"
 
#endif /* COLLISION_API_H_ */

Next, the code for the I2C thread will be added. This thread will setup and poll the IMU over I2C and post a message if a collision has been detected. Please see the IMU’s datasheet for specifics on the data being written and received over the I2C bus.

iic_thread_entry.c

#include "iic_thread.h"
#include "collision_api.h"
 
#define COLLISIONTHRESHOLD 25000
 
/* IIC Thread entry function */
void iic_thread_entry(void)
{
    //sending conversions init
        sf_message_header_t * pPostBuffer; //pointer for the buffer that must be acquired
        sf_message_acquire_cfg_t acquireCfg = {.buffer_keep =false};
        ssp_err_t errorBuff; //place for error codes from buffer acquisition to go
        sf_message_post_err_t errPost; //place for posting error codes to go
        sf_message_post_cfg_t post_cfg =
        {
           .priority = SF_MESSAGE_PRIORITY_NORMAL, //normal priority
           .p_callback = NULL //no callback needed
        };
        collision_payload_t * pDataPayload; //pointer to the receiving message payload
 
        g_i2c0.p_api->open(g_i2c0.p_ctrl, g_i2c0.p_cfg); //open the i2c peripheral
        int8_t readbuffer[12]; // a place for the received data to go
        uint8_t readaddress = 0x22; //the area in memory of the IMU to read
 
        uint8_t accelconfigwrite[2] = {0x10, 0b01010000}; //the register and flags to set to configure the IMU
        uint8_t gyroconfigwrite[2] = {0x11, 0b01010000}; //same
        //see the IMU data sheet for details
 
        uint8_t collisionstatus=0;
        int16_t collisionmagnitude2 =0;
 
        g_i2c0.p_api->write(g_i2c0.p_ctrl, &accelconfigwrite, 2,false); //write the configuration for the accelerometer
        g_i2c0.p_api->write(g_i2c0.p_ctrl, &gyroconfigwrite, 2,false); //now for the gyroscope
 
        while (1)
        {
            g_i2c0.p_api->write(g_i2c0.p_ctrl, &readaddress, 1, true); //write the address of memory we would like to read
            g_i2c0.p_api->read(g_i2c0.p_ctrl, readbuffer, 12, false); //put the returned data in this buffer
 
            //check squared magnitude of acceleration, square root is unnecessary as square is non-decreasing with magnitude
            collisionmagnitude2 = readbuffer[7]*readbuffer[7] + readbuffer[9]*readbuffer[9] + readbuffer[11]*readbuffer[11];
 
            if (collisionmagnitude2 > COLLISIONTHRESHOLD) collisionstatus =1;
 
            if (collisionstatus !=0) //post a message if there was a collision
            {
                errorBuff = g_sf_message0.p_api->bufferAcquire(g_sf_message0.p_ctrl, &pPostBuffer, &acquireCfg, 300);
                if (errorBuff==SSP_SUCCESS)
                {
                    pDataPayload = (collision_payload_t *) pPostBuffer; //cast buffer to our payload
                    pDataPayload->header.event_b.class_code = SF_MESSAGE_EVENT_CLASS_COLLISION; //set the event class
                    pDataPayload->header.event_b.class_instance = 0; //set the class instance
                    pDataPayload->header.event_b.code = SF_MESSAGE_EVENT_NEW_DATA; //set the message type
                    pDataPayload->collision_type = collisionstatus;
                    g_sf_message0.p_api->post(g_sf_message0.p_ctrl, (sf_message_header_t *) pDataPayload,
                                              &post_cfg, &errPost, TX_WAIT_FOREVER); //post the message
                    collisionstatus=0;
                }
            }
            tx_thread_sleep (5);
        }
}

Finally, the LED thread is relatively simple, and should look like this:

led_thread_entry.c

#include "led_thread.h"
#include "collision_api.h"
 
/* LED Thread entry function */
void irq3_callback(external_irq_callback_args_t * p_args)
{
    g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07, IOPORT_LEVEL_LOW);
}
 
void led_thread_entry(void)
{
    sf_message_header_t * pHeader; //pointer to the message header
    collision_payload_t * thepayload; //pointer to the message payload
 
    g_external_irq0.p_api->open(g_external_irq0.p_ctrl, g_external_irq0.p_cfg); //initialize the IRQ
 
    while (1)
    {
        g_sf_message0.p_api->pend(g_sf_message0.p_ctrl, &led_thread_message_queue,
                                  &pHeader, TX_WAIT_FOREVER); //wait for a message forever
        if (pHeader->event_b.class_code == SF_MESSAGE_EVENT_CLASS_COLLISION) //if the message if the right kind
        {
            thepayload = (collision_payload_t *) pHeader; //cast the received message to the custom type
            if (thepayload->header.event_b.code == SF_MESSAGE_EVENT_NEW_DATA) //if the message event is the right kind
            {
                g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07, IOPORT_LEVEL_HIGH);
                g_sf_message0.p_api->bufferRelease(g_sf_message0.p_ctrl, pHeader, SF_MESSAGE_RELEASE_OPTION_NONE);
            }
        }
        tx_thread_sleep (1);
    }
}

Conclusion

This example showed how to use and configure the Grove Seeed I2C interface on the Renesas DK-S124 for use with of Seeed’s breakout of the LSM6DS3. This example only covered using the Accelerometer but of the 6 axis sensor, the gyroscope is left as an exercise to the reader (it shoud be trivial at this point, the registers are already being read into memory; also note that angular velocities can simply be added as they are independent of each other). Also, use of external interrupts were covered briefly.

To test the function of this program, try shaking the IMU around and getting the green light to turn on. The threshold constant may be changed to adjust sensitivity. To test the code for this guide, the Renesas DK-S124 and the IMU were placed on an RC car and crashed into a few obstacles.

Questions/Comments

Any questions or comments please go to Digi-Key’s TechForu