New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switching between master and slave role on ATTiny85 fails. #5

Closed
x821938 opened this Issue Oct 19, 2017 · 10 comments

Comments

Projects
None yet
2 participants
@x821938
Copy link

x821938 commented Oct 19, 2017

I have a sketch on my attiny where I need to change between being an i2c master and a slave. This doesn't work.

If I only work as a master and poll some sensors - it works fine.
If I only work as a slave and get polled from another master it works fine.

If I want the functionality of being both a master and a slave (eg switching role with a button on the attiny), then the slave fails. I tried the Wire.end() when I want to go from being slave to master, but without luck.

Any ideas?

Best regards,
Alex.

@puuu

This comment has been minimized.

Copy link
Owner

puuu commented Oct 20, 2017

Switching between master and slave mode is an interesting question. I never tried it.
Simultaneous operation of master and slave mode is impossible because of the shared buffers. That is why it is important to stop the slave mode before using master mode, otherwise the interrupt routine will overwrite the data in the buffer.

Theoretically, it should work like this:

Wire.onRequest(requestEvent);
Wire.onReceive(receiveEvent);

// master mode
Wire.begin()
Wire.beginTransmission()
Wire.write(slave_addr);
Wire.write(data1);
Wire.endTransmission()

// slave mode
Wire.begin(this_slave_addr) // this enables the slave interrupts
// doing the slave stuff and decide to switch the mode
Wire.end() // this disables the slave interrupts

// master mode
Wire.begin()
Wire.beginTransmission()
Wire.write(slave_addr);
Wire.write(data2);
Wire.endTransmission()

Please report if this is working. If not, please provide a minimal example and describe the problem in detail.

@x821938

This comment has been minimized.

Copy link

x821938 commented Oct 20, 2017

Hi,

Thanks for getting back to me so fast :) I made a small example with an ATTiny85 connected to a VEML6070 light sensor and an Arduino Pro-Mini via I2C bus.

I made an absulute minimal code for both the Pro-Mini and the ATTiny. It can be found here: https://github.com/x821938/test_usi_i2c_master_slave_switch

The Attiny starts as a slave. If it receives the command byte 'L'. It:

  1. Ends slave mode
  2. Becomes a master and gets light data from VEML6070 UV sensor
  3. Enters slave mode again

The Pro-Mini waits a little after sending the 'L' command and then pull the light data from the ATTiny slave.

If I comment out the part of the Pro-Mini code where I send the 'L' command, then the ATTiny slave nicely talks back to me. Just sending zeroes (obviousely, because it never reads from sensor). But as soon as the ATTiny has switched to master mode, I get 255 values from it. (because of missing error handling - but I am trying to keep the code minimal for demonstration purposes)

Likewise I have also tested the ATTiny talking to the lightsensor - without ever enabling slave mode. Via the visual feedback led, I can prove that it also works fine by itself.

I hope the example makes sense.

Best regards,
Alex

@puuu

This comment has been minimized.

Copy link
Owner

puuu commented Oct 20, 2017

Hi,
the example code is clear to me. But I did not yet get, why you get 255.
Could it be, that the ATTiny did not release the SDA line correctly, e.g., does Pro-Mini read also 255 from the light sensor.
Did you can check the voltage of the SDA line? A call of readFromLightSensor(); in setup() of the Pro-Mini can also help to investigate this problem.

@x821938

This comment has been minimized.

Copy link

x821938 commented Oct 20, 2017

Here is output from my datalogger when attiny behaves good and wrong.

alt text
alt text

If that can help.

@x821938

This comment has been minimized.

Copy link

x821938 commented Oct 20, 2017

Here is the output on my Pro-Mini:

Sending master a command: L
Giving him a little time to finish his job
We got light value from I2C slave: 255
We got light value directly from sensor: 0

Sending master a command: L
Giving him a little time to finish his job
We got light value from I2C slave: 255
We got light value directly from sensor: 0

Sending master a command: L
Giving him a little time to finish his job
We got light value from I2C slave: 255
We got light value directly from sensor: 6

When Wire.requestFrom fails to get data, it always return 255. I think the attiny releases the SDA fine. The Pro-mini reads the value fine. See output.

@x821938

This comment has been minimized.

Copy link

x821938 commented Oct 20, 2017

Anoher dump.

Wrong:
alt text

Good:
alt text

@x821938

This comment has been minimized.

Copy link

x821938 commented Oct 21, 2017

Hi again,

I found the mistake in your library :)
You forget to set values in the begin method for the slave.... When I change it to this, it works:

void USIWire::begin(uint8_t address) {
  BufferIndex = 0;
  BufferLength = 0;
  transmitting = 0;
  USI_TWI_Slave_Initialise(address);
}

If you only run slave mode it works because the variables get set in the inital declaration.

Best regards,
Alex

@puuu

This comment has been minimized.

Copy link
Owner

puuu commented Oct 23, 2017

Thank you for the information.

The missing reset of the variables in USIWire::begin are definitely a bug. Please feel free to submit a pull request.

But, I did not understand, why this cause the problem with the 255 value. If the variables are not set to 0 during WIRE.begin(), then BufferIndex and BufferLength differ from 0 after the call of Wire.requestFrom(). This leads to a not correctly working Wire.read() in slave mode. For your code on the ATTiny this means:

  • after a reset and receiving the first 'L', readFromLightSensor() should work as expected and read out the sensor and write is into lightValue.
  • since readFromLightSensor() calls Wire.requestFrom(), Wire.read() will return -1 in slave mode and readFromLightSensor() will never be called again.

The dumps of your logic analyser show that the USIWire work correctly in slave mode, e.g., changes of the SDA signal for ACK.

Does the ATTiny still report 255 with you patch? If yes, can you provide a dump that show the 'L' request and the subsequent master mode of the ATTiny?

puuu added a commit that referenced this issue Oct 25, 2017

src/USIWire.cpp: fix initialisation of slave mode
Solves problems switching from master mode to slave mode.
Fix for issue: #5
@x821938

This comment has been minimized.

Copy link

x821938 commented Oct 26, 2017

When the attiny failed to switch from master to slave, it never answered when the pro mini was polling for data. This means that SDA was high all the time the the master was communicating. Because I didn't have error handling on my pro mini, the received value will be 255 because it's latching in binary ones on each SCL clock pulse.

@puuu

This comment has been minimized.

Copy link
Owner

puuu commented May 22, 2018

Closed with #6 .

@puuu puuu closed this May 22, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment