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.
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.
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.