I2C Command Bus

The I2C bus is used to communicate between master and slave, in this case the MCU microcontroller and the telemetry and telecommand node (TTC node). The TTC node is pre-programmed to execute two major actions, read and write. This allows us to both read variables from the TTC and instruct it to execture actions. All commands sent to the slave must be preceeded with a 7 bit slave address which is set to be 0x01.

A 7 Bit Node address nW A Command Type A Command Value A
Sr 7 Bit Node Address R A Reply Byte 1 A Reply Bit 0 N P

S- Start Condition
nW- Write Command
A- Acknowledged
R- Read Command
N- Not Acknowledged
Sr- Repeat Start Condition

In order to read values (Current, Voltage, Temperature) from the various solar cells and batteries, the correct I2C bus commands must be known. It is important to regularly check these values to ensure that CubeSat is opperating correctly.

I2C Code

//I2C test code

#include <io.h>

int main() {
  int i;    

  U0CTL=U0CTL | 0x26; //Sets U0CTL to turn on I2C as master
  P3DIR= 0x0A;//Configure I2C pins to output, this will need to be changed to receive data
  P3SEL= 0x0A;//Sets pins to use peripheral module 

  U0CTL=U0CTL & 0xFE; //Disables I2C
  I2CTCTL=I2CTCTL & 0x0F; //Clears I2C config bits
  I2CTCTL=I2CTCTL | 0x90; //Sets word length and ACLK as clock
  U0CTL=U0CTL | 0x01; //Enables I2C

  P1DIR=255;

  while(1) {
    P1OUT=255-P1OUT;
    I2COA=0x01; //Set master address to 1
    I2CSA=0x02; //Set slave address to 2
    I2CDRW=0x5555; //Set data word
    I2CTCTL=I2CTCTL | 0x03; //Initiates a start condition
    for(i=0;i<10000;i++)
      nop();
  }
}

This code has been shown to produce some signals on the logic analyser, however it has not been tested with a simulator so we cannot verify it is using correct I2C

#include <io.h>

int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;

  U0CTL |= SYNC + I2C; //Set USART 0 to I2C

  U0CTL &= ~(I2CEN); //Clear I2C enable
  I2CTCTL |= 0x50; //Set up I2C
  U0CTL |= MST; //Make I2C master
  U0CTL |= I2CEN; //Renable I2C

  I2CTCTL |= 0x02; //Send STOP condition

  while(1) P1OUT=I2CDCTL;
}

This is some alternative code, which generates a stop condition and repots it on P1

04/03/2010

We attempted to send I2C data (0x55) to a slave address 0x41. We successfully generated a start condition like signal. below is the final code.

#include <io.h>

void waitms(int time) {
  BCSCTL1=0x00; //Sets ACLK=LFXT1CLK
  TACCR0=time*4; //assumes one run of clock=0.25ms
  TACTL=0x01D2; //Resets timer, sources from ACLK/8, and sets to count up to TACCR0
  while (!(TACTL & 1));
}

int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;

  BCSCTL2 |= SELS; //Set SMCLK to XT2 oscillator
  BCSCTL2 &= ~0x06; //Set clock divider to 1

  U0CTL |= SYNC + I2C; //Set USART 0 to I2C
  U0CTL |= MST; //Make I2C master

  U0CTL &= ~(I2CEN); //Clear I2C enable
  I2CTCTL |= 0x20; //Set I2C to use SMCLK
  I2CTCTL &= ~(I2CRM); //Set repeat mode to zero
  I2CTCTL &= ~(I2CWORD); //Set to byte mode
  I2CPSC = 0x03; //Set prescalar multiplier to 4x
  I2CSCLH = 0xA; //Set SCL high period to 12x prescalar period
  I2CSCLL = 0xA; //Set SCL low period to 12x prescalar period
  I2COA = 0x01; //Set own address to 1
  I2CSA = 0x41; //Set slave address
  U0CTL |= I2CEN; //Renable I2C

  waitms(100); //Wait for I2C to be ready

  I2CTCTL |= I2CTRX; //Set transmit mode
  I2CNDAT = 0x1; //Set to transmit one byte
  I2CDRB = 0x55; //Gives a data byte
  I2CTCTL |= I2CSTP; //Sets STOP condition bit
  I2CTCTL |= I2CSTT; //Initiates a start condition

  P1DIR=255;
  P2DIR=255;
  P1OUT=0;
  while(1) {
   P1OUT=I2CDCTL;
   P2OUT=255-P2OUT; //Feed this 76KHz square wave signal into H2.21 to simulate a clock
   waitms(13);
  }
}

It was found that the I2C is held busy when there is no connection, however by applying a square wave of constant 3.3V this bit is cleared and remains as such.

PLM-OBDH-I2CStartConditionDiagram-220.jpg

Above is a sketch of the Logic Analyser trace that produced by the above code. The red line is the response from the H1.23, the I2C data pin and the blue a square wave at 76kHz produced from P2. Clock was sourced from pin H1.25

The peak in the red line is believed to be the start condition. I2C requires a ACK (Acknowledgement) bit in return for the start condition and as such, waits for a defined period before repeating. As there is no slave to reply the signal repeated indefinitely.

To progress it is suggested that an I2C slave device is connected.

16/03/10

Today we attempted to link the camera with the main board. Initial tests gave a random but repeating pattern
(photo to be added)
It was deemed that the code was not correct and as such the contents of the registers U0CTL and I2CTCTL were investigated using the code below. The code outputs the contents of a selected register to P1

#include <io.h>

void waitms(int time) {
  BCSCTL1=0x00; //Sets ACLK=LFXT1CLK
  TACCR0=time*4; //assumes one run of clock=0.25ms
  TACTL=0x01D2; //Resets timer, sources from ACLK/8, and sets to count up to TACCR0
  while (!(TACTL & 1));
}

int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;

  waitms(100);

  BCSCTL2 |= SELS; //Set SMCLK to XT2 oscillator
  BCSCTL2 &= ~0x06; //Set clock divider to 1

  U0CTL |= SYNC + I2C; //Set USART 0 to I2C
  U0CTL |= MST; //Make I2C master

  U0CTL &= ~(I2CEN); //Clear I2C enable
  I2CTCTL |= 0x10; //Set I2C to use ACLK
  I2CTCTL &= ~(I2CRM); //Set repeat mode to zero
  I2CTCTL &= ~(I2CWORD); //Set to byte mode
  I2CPSC = 0x03; //Set prescalar multiplier to 4x
  I2CSCLH = 0x12; //Set SCL high period to 12x prescalar period
  I2CSCLL = 0x12; //Set SCL low period to 12x prescalar period
  I2COA = 0x01; //Set own address to 1
  I2CSA = 0x42; //Set slave address
  U0CTL |= I2CEN; //Renable I2C

  waitms(100); //Wait for I2C to be ready

  I2CTCTL |= I2CTRX; //Set transmit mode
  I2CNDAT = 0x1; //Set to transmit one byte
  I2CDRB = 0x55; //Gives a data byte
  I2CTCTL |= I2CSTP; //Sets STOP condition bit
  I2CTCTL |= I2CSTT; //Initiates a start condition

  waitms(30);

  P1DIR=255;

  while(1) {
    P1OUT = U0CTL; //This can be replaced for a different register
    waitms(13);
  }
}

All pins were set as expected apart from bit 0 of UOCTL, the I2C enabled bit.

Upon further investigation, and use of the logic analyser to measure the signal from the respective pin it was found that the pin does turn on but only for ~20ns. It then drops low for 20ns and then returns to high for another 20ns before returning permanently to low. 20ns is far below the time of one clock cycle and as such this is unexplained. However it was attained repeatedly. There was no signal on either the I2C clock or data wire at the time.

This may be a case of a lack of slave and possibly should be tested with the camera attached, however lack of time did not allow for this.

Pull-up resistors

The next step was to try various pull-up resistors to solve the problem. Beginning with 100kOhm resistors on each line, we lowered them until a signal was seen. We found that 4.7kOhm resistors connecting both wires to Vcc allowed a partial I2C signal to be sent.

PLM-OBDH-I2Chalfsignal-221.jpg

There are two things to note: firstly that the I2C signal was incomplete as the master expects an ACK from the slave after the address is sent. Secondly, The data in the address appears to be 1000010, which is not the address we intended to send.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.