Richard-Gemmell / teensy4_i2c

An I2C library for the Teensy 4. Provides slave and master mode.
MIT License
92 stars 19 forks source link

I2C between Two Teensy 4.1 Boards #23

Closed Issac-Archer closed 2 years ago

Issac-Archer commented 2 years ago

I'm trying to get I2C communication working between two Teensy 4.1 boards. I have tried various combinations of master writer and master reader but I can't seem to get the slave board to respond to anything. For now I have it set up so that a pushbutton will trigger the master to send the character X and turn on its LED until I release the button. Meanwhile the slave is supposed to blink its own LED when it receives data and print the character to a serial terminal but I'm getting nothing on both the LED and the terminal. I'm using pins 18 and 19 on both boards and have tried it both with and without 2.7K pull-up resistors to 3.3V. Is there a mistake in my code somewhere?

Master Code:

#include <Arduino.h>
#include <i2c_driver.h>
#include <i2c_driver_wire.h>

int pushbutton = 12;
int led = 13;
int i = 0;
char c = 'X';

void setup() 
{
  pinMode(led,OUTPUT);
  pinMode(pushbutton,INPUT_PULLUP);
  Wire.begin();
}

void loop() 
{
  if(digitalRead(pushbutton) == LOW && i == 0)
  {
    Wire.beginTransmission(0x22);
    Wire.write(c);
    Wire.endTransmission();
    digitalWrite(led,HIGH);
    i = 1;
  }

  if(digitalRead(pushbutton) == HIGH && i == 1)
  {
    digitalWrite(led,LOW);
    i = 0;
  }  
}

Slave Code:

#include <Arduino.h>
#include <i2c_driver.h>
#include <i2c_driver_wire.h>

int led = 13;
char c;

void setup() 
{
  Wire.begin(0x22);
  Wire.onReceive(receiveEvent);
  pinMode(led,OUTPUT);
  Serial.begin(9600);
}

void loop() 
{
  delay(100);
}

void receiveEvent(int howMany)
{
  c = Wire.read();
  digitalWrite(led,HIGH);
  Serial.println(c);
  delay(500);
  digitalWrite(led,LOW);
  delay(500);
}
Richard-Gemmell commented 2 years ago

Hi Isaac, The code looks Ok at a glance. I'll check it out more carefully over the weekend.

In the mean time:

I'm not sure whether your button is default high or low. Make sure it doesn't write until you press the button. Reset the Slave device, wait a moment then reset the master device.

cheers, Richard

Issac-Archer commented 2 years ago

Hi Richard,

Thanks for the advice. From the tips I think I have it wired correctly, 18 to 18, 19 to 19. I have the Vin pins tied together and the grounds tied together between the two boards so that when I connect either one to USB both will power up. The button is normally open and grounds the circuit when held down. This commands the master to both light the LED and attempt to transmit once (and at least the LED is working) and to turn off the LED when the button is released.

Is it necessary to ensure the slave boots up before the master boots or is it sufficient to only wait on transmitting? As it is now both boards should boot simultaneously when I connect one to USB and I give both several seconds to boot before pushing the button.

Richard-Gemmell commented 2 years ago

Hi, It's only necessary for the slave to be stable before the master tries to send data to it.

It sounds like you're doing everything right with the hardware. I'll check out the code and let you know what I find. cheers, Richard

Richard-Gemmell commented 2 years ago

I had a look at the code. It works for me.

I had to change the button pin to 11 but I think that's because I fried my pin 12. :(

Event handlers need to be as fast as possible because they're called within a hardware interrupt on the Teensy. Your slave code contains both print() and delay() which are definitely too slow for safety. Here's a version of the slave which moves the bulk of the behaviour into loop() where it's safe. Note also the use of 'volatile'. I wouldn't swear to volatile being necessary in practice but it is in theory. :)

I added the counter for fun. My switch is very bouncy and generates a surprisingly large number of transmissions.

#include <Arduino.h>
#include <i2c_driver.h>
#include <i2c_driver_wire.h>

int led = 13;
volatile char c = 0;
volatile int count = 0;

void receiveEvent(int howMany);

void setup()
{
    Wire.begin(0x22);
    Wire.onReceive(receiveEvent);
    pinMode(led,OUTPUT);
    Serial.begin(9600);
}

void loop()
{
    if(c != 0)
    {
        digitalWrite(led,HIGH);
        Serial.print("Got ");Serial.println(c);
        Serial.print("Count = ");Serial.println(count);
        delay(500);
        digitalWrite(led,LOW);
        delay(500);
        c = 0;
    }
}

void receiveEvent(int howMany)
{
    c = Wire.read();
    count++;
}

good luck, Richard

Issac-Archer commented 2 years ago

Hi Richard,

Thanks for the help! It looks like I have a bad board on the slave side. I was able to get a terminal output from it and blink the LED with some earlier testing so it does execute code but it appears that it is not responding to anything on the I/O pins. I tried reversing their master/slave roles and reassigned the button pin on the new master/old slave board to several different pins, none of which got it to print to terminal or turn on the LED. Is there any single point of failure that could cause several I/O pins plus I2C to fail without completely killing the controller? If it's something I could potentially fix that would be awesome, if not then I'll try again once I get a replacement board.

Also I wasn't aware of the volatile modifier for variables so I looked that up, I'll start using that for interrupts from now on. Thanks!

Richard-Gemmell commented 2 years ago

Hi, I don't know anything about trying to fix a broken board. Try asking on https://forum.pjrc.com/.

Interrupts are quite interesting from a computer science point of view. Effectively the code in the interrupt is executed by a different thread. If you treat it as such you'll have fewer nasty surprises. For example, if an interrupt and the main loop both share a block of memory then the main loop may be half way through reading the block when the interrupt updates it. The main loop sees half of one version of the block and half of the new version. :)

Good luck. I'll close this issue now. Feel free to re-open it if required.

cheers, Richard

efshel commented 2 years ago

Hi Richard, I think I have a similar problem.

I try the same code but it's not working. My slave doesnt receive anything And I try a scan code for my Master and I didn't find any slave

18 is connect to 18, same for 19 I try to add externel pull up resistors but it don't change anything The gnd of both cart are connect The built in led is changing when I push the button so the code seem to be working Both cart are connect with my computer with usb

Do you have any advice for me please ?