I2C/TWI not initiating start condition

I'm completely new to the nRF and have been trying to set up the nRF as a master for I2C communication with a dsPIC(slave device), the nRF is supposed to always read data from the dsPIC but since the nRF doesn't support being operated as a slave device the nRF is the bus master and the dsPIC is the slave.

I have gone through the reference manual and written the code provided below. The code is free from errors in terms of c language (but correct me if I'm wrong), however, nRF51882 never initiates a start condition. As I mentioned I have never worked with nRF devices before so there might be a very small mistake I'm missing so any help or hints are appreciated.

If any more information is required let me know.

#include <stdio.h>
#include <stdlib.h>

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <nrf.h>

#define GPIO ((GPIO_REGS *)0x50000000)
#define I2C ((I2C_REGS *)0x40003000) //TWI instance 0

typedef struct {
volatile unsigned int aDummy0[321];
volatile unsigned int OUT; // 0x504 Write GPIO port
volatile unsigned int OUTSET; // Set individual bits in GPIO port
volatile unsigned int OUTCLR; // Clear individual bits in GPIO port
volatile unsigned int IN; // 0x510 Read GPIO port
volatile unsigned int DIR; // Direction of GPIO pins
volatile unsigned int DIRSET; // Setting DIR register
volatile unsigned int DIRCLR; // Clearing DIR register
volatile unsigned int aDummy1[120]; // 0x600 Reserved
volatile unsigned int PIN_CNF[31]; // 0x700 Configuration of pin 0-31
} GPIO_REGS;


typedef struct {
//Tasks
volatile unsigned int STARTRX; // 0x000 Start TWI receive sequence
volatile unsigned int aDummy0[1]; //all dummy vars are for alligning structure elements with actual register address
volatile unsigned int STARTTX; // 0x008 Start TWI transmit sequence
volatile unsigned int aDummy1[2];
volatile unsigned int STOP; // 0x014 Stop TWI transaction
volatile unsigned int aDummy2[1];
volatile unsigned int SUSPEND; // 0x01C Suspend TWI transaction
volatile unsigned int RESUME; // 0x020 Resume TWI transaction
//Events
volatile unsigned int aDummy4[56];
volatile unsigned int STOPPED; // 0x104 TWI stopped
volatile unsigned int RXDREADY; // 0x108 TWI RXD byte received
volatile unsigned int aDummy5[4];
volatile unsigned int TXDSENT; // 0x11C TWI TXD byte sent
volatile unsigned int aDummy6[1];
volatile unsigned int ERROR; // 0x124 TWI error
volatile unsigned int aDummy7[4];
volatile unsigned int BB; // 0x138 TWI byte boundary, generated before each byte that is sent or received
//Registers
volatile unsigned int aDummy8[49];
volatile unsigned int SHORTS; // 0x200 Shortcut register
volatile unsigned int aDummy9[63];
volatile unsigned int INTEN; // 0x300 Enable or disable interrupt
volatile unsigned int INTENSET; // 0x304 Enable interrupt
volatile unsigned int INTENCLR; // 0x308 Disable interrupt
volatile unsigned int aDummy10[110];
volatile unsigned int ERRORSRC; // 0x4C4 Error source
volatile unsigned int aDummy11[14];
volatile unsigned int ENABLE; // 0x500 Enable TWI
volatile unsigned int aDummy12[1];
volatile unsigned int PSELSCL; // 0x508 Pin select for SCL
volatile unsigned int PSELSDA; // 0x50C Pin select for SDA
volatile unsigned int aDummy13[2];
volatile unsigned int RXD; // 0x518 RXD register
volatile unsigned int TXD; // 0x51C TXD register
volatile unsigned int aDummy14[1];
volatile unsigned int FREQUENCY; // 0x524 TWI frequency
volatile unsigned int aDummy15[24];
volatile unsigned int ADDRESS; // 0x588 Address used in the TWI transfer

} I2C_REGS;

#define SDA_PIN 30
#define SCL_PIN 0

static void _InitI2C(void) {

    //Set the I2C SDA and SCL pins to inputs
    GPIO->DIRCLR = (1uL << SCL_PIN);
    GPIO->DIRCLR = (1uL << SDA_PIN);
    
    //Configure the SDA and SCL pins
    I2C->PSELSCL = SCL_PIN;
    I2C->PSELSDA = SDA_PIN;
    
    I2C->FREQUENCY = 0x06680000; //400 kbps baud rate
    I2C->ADDRESS = 0x70; //I2C address of bootloader
    
    I2C->ENABLE = 5; //Enable the module
}

int main(void)
{

    _InitI2C();
    int digitisedAN = 0;
    
    while(1)
    {
    
        //I2C->SUSPEND = 1; //Suspend the I2C Bus
        
        //I2C->TXD=0X70;
        
        
        I2C->RXDREADY = 0; //Clear RXDREADY
        I2C->STARTRX = 1; //Start the I2C Read sequence
        
        
        while (I2C->RXDREADY == 0);//While there is no message to read
        //I2C->SUSPEND=1;
        
        digitisedAN = I2C->RXD; //Retrieve first BYTE
        I2C->RXDREADY = 0; //Clear RXDREADY FOR NEXT BYTE
        
        I2C->RESUME = 1; //Resume I2C Bus
        
        I2C->STOP = 1; //Stop before reading the last byte
        
        while (I2C->RXDREADY == 0); //While there is no message to read
        I2C->RXDREADY = 0; //Clear RXDREADY flag for next time
        
        digitisedAN=digitisedAN + I2C->RXD; //Retrieve the 2nd byte
        
        while (I2C->STOPPED == 0); //While the bus has not stopped
        I2C->STOPPED = 0; //Clear STOPPED flag for next time
    
    }

}

  • Hello,

    Thank you for contacting DevZone at NordicSemi.

    Good to know that you have started working with Nordic products. As of 2018, we have shifted to Nordic Connect SDK (NCS) that is a Zephyr based SDK, and we recommend new customers and those initiating new designs to use NCS exclusively rather than nrf5 sdk.

    Also, I have noticed that the product which you are using is very old. In fact, using an NRF52 SoC/board is cheaper than our older chips and is more convenient to use as well.

    As you are starting a new design, and have started with the nRF, may I suggest you to get a newer SoC (e.g NRF52, NRF53, NRF91, or other latest depending upon what kind of technology you want to use that) series and use Nordic Connect SDK using a VSCode IDE.

    It is fairly easy to getting started with the NCS, and probably after setup, you should be running examples within minutes.

    Nonetheless, as you have posted the code, I see a possible issue here:

    In the INIT I2C, you have:

        //Set the I2C SDA and SCL pins to inputs
        GPIO->DIRCLR = (1uL << SCL_PIN);
        GPIO->DIRCLR = (1uL << SDA_PIN);
    

    As from the intention, you want to set both bits (for SDA and SCL) to 1, but actually it is getting overwritten. You may change it to something like this:

     

    //Set the I2C SDA and SCL pins to inputs
    GPIO->DIRCLR = (1uL << SCL_PIN) | (1uL << SDA_PIN);
    

    /BR, Naeem

  • Hi Naeem,

    your response was greatly appreciated I was able to fix the issue I was having with I2C comms. I had a follow-up question about your advice about using the connect SDK.

    As I had previously mentioned I am using an nRF51822 standalone chip with an MKL26Z128VFM4 chip as the programmer.

    I am currently trying to use the nRF's 2.4GHz radio for implementing a BLE application I tried following this application note provided by Nordic (infocenter.nordicsemi.com/.../nan_36.pdf) which says to follow this user guide (https://file.elecfans.com/web1/M00/7F/7D/o4YBAFwnYQuAP5pVAI54fNV38UQ387.pdf) to program the S110 softdevice onto my nRF chip however the guide is only for nRF51822 evaluation kit and hence nrFgo studio doesn't recognize when I have my chip plugged in the PC through the MKL26Z128VFM4. 

    What is my best option for programming the nRF51822 with the MKL26Z128VFM4 chip to use the nRF's 2.4GHz radio for BLE applications?

    Thank you.

  • Hi

    For the nRF51822, what we can provide is a bit limited, as none of our recent IDEs/programming interfaces supports it inherently. Unfortunately, we don't have any experience with the MKL26Z128VFM4, and are generally using J-Link devices for programming and debugging our MCUs, so if you want to use the MKL26Z128VFM4, you'll be on your own here.

    I would recommend getting a Development kit or a J-Link device to program your nRF51822. You can either use Keil µVision as an IDE for development and flashing/debugging, or you can use the nRF Programmer app in the nRF Connect for Desktop application to only flash your nRF51822. The nRFGo Studio is very old and outdated at this point, so I wouldn't suggest using it, nor is it supported by the MKL26Z128VFM4.

    Best regards,

    Simon

Related