energia / msp430-lg-core

15 stars 12 forks source link

I2C 400KHz not Working On MSP430FR2433 #105

Closed mhmayyan closed 5 years ago

mhmayyan commented 5 years ago

I am trying to Examples -> Wire -> slave_receive with a small modifications.

I tried the following code. It receives but does not send on MSP430FR2433. The same code, however, works on Arduino Nano and other Arduino MCU's.



void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.setClock(400000);
  Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(requestEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

void requestEvent()
{
  Wire.write("C"); // respond with message of 1 byte for confirmation
                       // as expected by master
}```

Any help is appreciated. Thanks in advance.
StefanSch commented 5 years ago

fixed with this pull request https://github.com/energia/msp430-lg-core/pull/106

mhmayyan commented 5 years ago

fixed with this pull request

106

Thanks for the reply.

It works now with 100KHz clock speed, however, it responds to the master request 100 times then it stops responding. It still doesn't send for me with 400KHz.

StefanSch commented 5 years ago

When running with 400kHz please ensure that the pull ups are small enough to support this speed.

You say it stops after 101 - is this stable and always at that time. What do you use as master?

StefanSch commented 5 years ago

Note:
For the Slave this line of code has not functionality: Wire.setClock(400000);

mhmayyan commented 5 years ago

Well, I am using Catena4612 as the master but also tried Arduino Nano and ESP32.

I think, now, I have a better understanding of the problem.

Both examples "slave_receiver" and "slave_sender" work properly on MSP430FR2433. I am, however, unable to get the two registered event fuctions working at the same time. Please, have a look at the two codes below.

The code slave_receiver_sender.ino works well on Arduino Nano but not on the MSP430FR2433. Instead it receives only one i2c message (i.e. "x is 0").

The code simple_master.ino works well on both platforms.

slave_receiver_sender.ino

//*************************************
#include <Wire.h>
void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onRequest(requestEvent); // register event
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}
//*************************************
void loop()
{
  delay(100);
}
//*************************************
void receiveEvent(int howMany)
{
  while(1 < Wire.available())
    Serial.print((char)Wire.read()); // loop through all but the last
  Serial.println((int)Wire.read());   // print the integer
}
//*************************************
void requestEvent()
{
  Wire.write('C'); // respond with message of 1 byte
}

simple_master.ino

#include <Wire.h>
#define SlaveADD  4
// testing i2c MSP430FR2433
byte x = 0;
uint32_t tStamp = 0;
//************************************************
void setup(void)
{
  Wire.begin();
  //   Wire.setClock(400000); // Set I2C frequency
  Serial.begin(9600);
} // end setup
//************************************************
void loop(void)
{
  // testing i2c MSP430FR2433
  if ( millis() - tStamp > 100 ) {

    Wire.beginTransmission(SlaveADD); // transmit to device #4
    Wire.write("x is ");        // sends five bytes
    Wire.write(x);              // sends one byte
    Wire.endTransmission();    // stop transmitting
    x++;

    Wire.requestFrom(SlaveADD, 1);    // request 1 byte from MSP430FR2433
    tStamp = millis();
    while(millis() - tStamp < 5){// wait with timout
      if(Wire.available()){
        while(Wire.available())
          Serial.print((char)Wire.read());
        Serial.println();
        break;
      }
    }

    tStamp = millis();
  }
} // end loop(void)
mhmayyan commented 5 years ago

I used an oscilloscope to monitor the SDA and SCL lines. I have the code simple_master.ino running on Arduino Due and the code slave_receiver_sender.ino on MSP430FR2433. I keep pressing the reset button on the MSP430FR2433 and keep looking at the oscilloscope I see pictures

MSP430FR2433 Reset Button Pressed.png (attached).

When I release the reset button on the MSP430FR2433, I see the other pictures

MSP430FR2433 Reset Button Released_1.png (attached) MSP430FR2433 Reset Button Released_2.png (attached) // zoomed out

So, why do the lines stay low forever? MSP430FR2433 Reset Button Pressed MSP430FR2433 Reset Button Released_1 MSP430FR2433 Reset Button Released_2

StefanSch commented 5 years ago

Hi, could not find the perfect solution but due to the printf in the receiver part of the Slave the ISR is looked for a very long time and the hardware sees the START and STOP bit at the same time which generates lock and enables the clock stretching. You can fix this by replacing in you master code x++; with x++; delay(100);

This ensures that the next Wire frame is only sent after the first on has been handled. You can also modify your code so that the Slave Receive callback function only collects the data but the sending is done in the loop() function.

mhmayyan commented 5 years ago

Thank you very much.

This helped a lot. I added a delay and it worked. My loop function is as follows

void loop(void)
{
  // testing i2c MSP430FR2433
  if ( millis() - tStamp > 100 ) {

    Wire.beginTransmission(SlaveADD); // transmit to device #4
    // Wire.write("x is ");        // sends five bytes
    delayMicroseconds(500);
    Wire.write(x);              // sends one byte
    delayMicroseconds(500);
    Wire.endTransmission();    // stop transmitting
    x++;
    delayMicroseconds(500);

    Wire.requestFrom(SlaveADD, 1);    // request 1 byte from MSP430FR2433
    tStamp = millis();
    while(millis() - tStamp < 5){// wait with timout
      if(Wire.available()){
        while(Wire.available())
          Serial.print((char)Wire.read());
        Serial.println();
        break;
      }
    }

    tStamp = millis();
  }
} // end loop(void)
mhmayyan commented 5 years ago

I noticed that when I modify the board.txt file such that I use 1MHz instead of 16MHz frequency, the slave receives the transmitted number of bytes - 1. So, the last one becomes missing. This problem, though, does not show up when I use the 16MHz or 8MHz frequencies. I am trying to minimize the power consumption using suspend() and wakeup.

Any idea, please?

StefanSch commented 5 years ago

I assume that the overhead of the Energia approach have a unique driver structure for all devices and the method of the callback functions can not be handled when running with 1MHz. So i guess it would require a optimization of this structure and doing a dedicated driver for your application. On the other hand when properly using the low power modes of the MSP430 you will not use more power (or better energy) then when running on a slower clock. The device will just be fast in back int the low power mode. Best case you can even be lower on the power as you reduce the active time which add a static bias current. You of course will have a higher peak current but energy wise you will get identical numbers.

Regards, Stefan