I2C On Interrupt

03 Sep 2011

Hello, I recently purchased a few mbeds with the LPC1768 MCU for my hobby. I am experienced with micro-controllers but new to ARM. I am trying to send I2C commands to a slave mbed module. The slave code works fine as I have tried it with other devices. This code does not work. Where am I goofing up?

#include "mbed.h"

InterruptIn PWM_Up_Btn(p20);
InterruptIn PWM_Dn_Btn(p19);
I2C I2C_master(p9, p10);
char command_up[1] = { 'U' }; // U = PWM increase brightness.
char command_dn[1] = { 'D' }; // D = PWM decrease brightness.
const int PWM_CAN_address = 0x08; 

void up_button()
{   
    I2C_master.write(PWM_CAN_address, command_up, 0x01, false);  
}

void dn_button()
{    
    I2C_master.write(PWM_CAN_address, command_dn, 0x01, false);
}

int main() 
{
    // Objects and variables:
    
    
    PWM_Up_Btn.rise(&up_button);
    PWM_Dn_Btn.rise(&dn_button);
    
    PWM_Dn_Btn.mode(PullDown); 
    PWM_Up_Btn.mode(PullDown);
    
    I2C_master.frequency(10000);    
    
    while(1)
    {
    }
}

03 Sep 2011

Is the slave address correct. Mbed uses 8 bit addresses. So you address 0x08 should include bit 0 for R/W. Also note that you use a 10 kbit datarate instead of the default 100k.

03 Sep 2011

I changed the address for both the slave and master as I found out 0x08 is reserved. Still no activity. Here is the slave code in case you find anything there. I also changed the frequency back to 100kHz for both of them.

#include "mbed.h"

int main() 
{
    // Set up I2C:
    I2CSlave receiver(p28, p27);
    receiver.address(0x88);
    
    // Set up PWM:
    char command[1];
    float brightness = 0.08333f;
    PwmOut PWM_Ch_1(p21);
    PWM_Ch_1.period_us(10); // 100kHz PWM.
    PWM_Ch_1.write(0.08333f);
    
    //Adjust PWM brightness based upon I2C value:
    while(1)
    {
        receiver.read(command, 0x01);
        pc.printf("character %c", command[0]);
        if (command[0] == 'U')
        {
            if (brightness < 1.0f)
            {
                brightness += 0.08333f;
                PWM_Ch_1.write(brightness);
            }
        }
        else
        {
            if (brightness > 0.0f)
            {
                brightness -= 0.08333f;
                PWM_Ch_1.write(brightness);
            }
        }
    }
}
03 Sep 2011

OK, you sure that the I2C connection is ok between the mbeds:

  • SDA to SDA
  • SCL to SCL
  • Gnd to Gnd
  • pull-up Resistors on both SDA and SCL (3k3 to 3V3)

Check that mbeds are executing the program and respond to your buttons:

  • add short flash of LED or do printf in the up_btn, dn_btn interrupts.
  • check return value of write(): 0 on success (ack), or non-0 on failure (nack)
  • check to see if slave has been addressed, call receiver.receive() and printf results see: http://mbed.org/projects/libraries/api/mbed/trunk/I2CSlave
  • check return value of read(): 0 on success, non-0 otherwise
  • add short flash of another LED in your main while(1) loop
03 Sep 2011

OK, i spent some time digging and I found out that you have to transmit the data at least twice for it to make it to the slave. When it does make it, the data shows up as if it has been twice transmitted. I want it to work on the first try. There are no problems with the bus. What is up? Here is the code I wrote to troubleshoot the issue. I have a feeling it is the slave because on the first transmission, my terminal displays a null character (or something blank), as if the data did not make it but the address did.

Master Code:

#include "mbed.h"

int main() 
{
    // Objects and variables:
    DigitalIn PWM_Up_Btn(p20);
    DigitalIn PWM_Dn_Btn(p19);
    I2C I2C_master(p9, p10);
    const int PWM_CAN_address = 0x88;
    char command_up[1] = { 'U' }; // U = PWM increase brightness.
    char command_dn[1] = { 'D' }; // D = PWM decrease brightness.
      
    while(1)
    {
        if (PWM_Up_Btn)
        {
            for (int i = 0; i < 2; i++)
            {
                I2C_master.start();
                I2C_master.write(0x88);
                I2C_master.write('U');
                I2C_master.stop();
            }
            wait(0.25f);
            while (PWM_Up_Btn){} // Only allow brighness to advance once per button push.
        }
        if (PWM_Dn_Btn)
        {
            for (int i = 0; i < 2; i++)
            { 
                I2C_master.start();
                I2C_master.write(0x88);
                I2C_master.write('D');
                I2C_master.stop();
            }
            wait(0.25f);
            while (PWM_Dn_Btn){} // Only allow brighness to decrease once per button push.
        }
    }    
}

Slave Code:

#include "mbed.h"

Serial pc(USBTX, USBRX);

int main() 
{
    // Set up I2C:
    I2CSlave receiver(p28, p27);
    receiver.address(0x88);
    
    // Set up PWM:
    char command[1];
    float brightness = 0.08333f;
    PwmOut PWM_Ch_1(p21);
    PWM_Ch_1.period_us(10); // 100kHz PWM.
    PWM_Ch_1.write(0.08333f);
    
    //Adjust PWM brightness based upon I2C value:
    while(1)
    {
        receiver.read(command, 0x01);
        pc.printf("character %c \n", command[0]);
        if (command[0] == 'U')
        {
            if (brightness < 1.0f)
            {
                brightness += 0.08333f;
                PWM_Ch_1.write(brightness);
            }
        }
        else
        {
            if (brightness > 0.0f)
            {
                brightness -= 0.08333f;
                PWM_Ch_1.write(brightness);
            }
        }   
    }
}
03 Sep 2011

I think you may have to wait in the receiver until the master sends you something before doing the actual read(). Follow the example given for the I2CSlave:

while (1) {
  int i = receiver.receive();
  switch (i) {
    case I2CSlave::ReadAddressed:
      //receiver.write(msg, strlen(msg) + 1); // Includes null char
      break;
    case I2CSlave::WriteGeneral:
      receiver.read(command, 1);
      printf("Read G: %c\n", command);
      break;
    case I2CSlave::WriteAddressed:
      receiver.read(command, 1);
      printf("Read A: %c\n", command);
      break;
  }
}
03 Sep 2011

You were right, it all works now.

Thanks