Hi all,
I have been trying to implement some code that takes a reading from the ADC10 on the MSP430 (Slave) and then transmits this over I2C to a Stellaris (Master).
The problem I am facing is the MSP430 code I am using is setup to only send 1 byte, but as I understand it the ADC value I want to send is an Integer, so 2 bytes.
The code basically takes 10 readings from the ADC and places them in an array, adds them together and divides by 10, then this is placed in the variable avg_adc. I also use an itoa function to turn the ADC value into a char string (this was purely created to try and send over I2C as not fully understanding the problem, hence this post).
The Stellaris code is copied after the MSP430 code, I appreciate this is not the correct form for this but gives and overview of the whole handshaking process. Also the code on the MSP430 will eventually be ported across to the MSP430G2230.
MSP430G CODE
//******************************************************************************
// MSP430G2xx2 Demo - I2C Slave Transmitter, single byte
//
// Description: I2C Slave communicates with I2C Master using
// the USI. Slave data is sent and increments from 0x00 with each transmitted
// byte which is verified by the Master.
//******************************************************************************
// MSP430G2xx2 Demo - I2C Slave Transmitter, single byte
//
// Description: I2C Slave communicates with I2C Master using
// the USI. Slave data is sent and increments from 0x00 with each transmitted
// byte which is verified by the Master.
// LED off for address or data Ack; LED on for address or data NAck.
// ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
//
// ***THIS IS THE SLAVE CODE***
//
// Slave Master
// (MSP430G2xx2_usi_06.c)
// MSP430G2xx2 MSP430G2xx2
// ----------------- -----------------
// /|\| XIN|- /|\| XIN|-
// | | | | | |
// --|RST XOUT|- --|RST XOUT|-
// | | | |
// LED <-|P1.0 | | |
// | | | P1.0|-> LED
// | SDA/P1.7|------->|P1.7/SDA |
// | SCL/P1.6|<-------|P1.6/SCL |
//
// Note: internal pull-ups are used in this example for SDA & SCL
//
// D. Dang
// Texas Instruments Inc.
// December 2010
// Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
//******************************************************************************
#include <msp430g2432.h>
#include "ExtFunc/itoa.h"
unsigned int SLV_Data = avg_adc;
char SLV_Addr = 0x90; // Address is 0x48<<1 for R/W
int I2C_State = 0; // State variable
//////////////////////
int adc[10] = 0;
unsigned int avg_adc = 0;
void adc_Setup() {
ADC10CTL1 = CONSEQ_2 + INCH_1; // Repeat single channel, A1
ADC10CTL0 = ADC10SHT_1 + MSC + ADC10ON + ADC10IE; // Sample & Hold Time + ADC10 ON + Interrupt Enable;
ADC10DTC1 = 0x0A; // 10 conversions
ADC10AE0 |= 0x01; // P1.0 ADC option select
}
void adc_Sam10() {
ADC10CTL0 &= ~ENC; // Disable Conversion
while (ADC10CTL1 & BUSY); // Wait if ADC10 busy
ADC10SA = (int) adc; // Transfers data to next array (DTC auto increments address)
ADC10CTL0 |= ENC + ADC10SC; // Enable Conversion and conversion start
}
//////////////////////
int main(void) {
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
if (CALBC1_1MHZ == 0xFF) // If calibration constants erased
{
while (1)
; // do not load, trap CPU!!
}
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
P1OUT = 0xC0; // P1.6 & P1.7 Pullups
P1REN |= 0xC0; // P1.6 & P1.7 Pullups
//P1DIR = 0xFF; // Unused pins as outputs
P2OUT = 0;
P2DIR = 0xFF;
USICTL0 = USIPE6 + USIPE7 + USISWRST; // Port & USI mode setup
USICTL1 = USII2C + USIIE + USISTTIE; // Enable I2C mode & USI interrupts
USICKCTL = USICKPL; // Setup clock polarity
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
_EINT();
while (1) {
//LPM0; // CPU off, await USI interrupt
_NOP(); // Used for IAR
////////////////////////
adc_Setup();
adc_Sam10();
// Add all the sampled data and divide by 10 to find average
avg_adc = ((adc[0] + adc[1] + adc[2] + adc[3] + adc[4] + adc[5] + adc[6] + adc[7] + adc[8] + adc[9]) / 10);
////////////////////////
int base = 10; // Sets the base of the conversion to10 i.e. Decimal
unsigned char buffer[4]; // Buffer stores the string
itoa(avg_adc, buffer, base); // Itoa function call with 3 parameter
//ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void) {
__bic_SR_register_on_exit(CPUOFF);
// Clear CPUOFF bit from 0(SR)
/////////////////////////
}
//******************************************************
// USI interrupt service routine
//******************************************************
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX(void) {
if (USICTL1 & USISTTIFG) // Start entry?
{
P1OUT |= 0x01; // LED on: Sequence start
I2C_State = 2; // Enter 1st state on start
}
switch (I2C_State) {
case 0: //Idle, should not get here
break;
case 2: //RX Address
USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, RX Address
USICTL1 &= ~USISTTIFG; // Clear start flag
I2C_State = 4; // Go to next state: check address
break;
case 4: // Process Address and send (N)Ack
if (USISRL & 0x01) // If read...
SLV_Addr++; // Save R/W bit
USICTL0 |= USIOE; // SDA = output
if (USISRL == SLV_Addr) // Address match?
{
USISRL = 0x00; // Send Ack
P1OUT &= ~0x01; // LED off
I2C_State = 8; // Go to next state: TX data
} else {
USISRL = 0xFF; // Send NAck
P1OUT |= 0x01; // LED on: error
I2C_State = 6; // Go to next state: prep for next Start
}
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
break;
case 6: // Prep for Start condition
USICTL0 &= ~USIOE; // SDA = input
SLV_Addr = 0x90; // Reset slave address
I2C_State = 0; // Reset state machine
break;
case 8: // Send Data byte
USICTL0 |= USIOE; // SDA = output
USISRL = SLV_Data; // Send data byte
USICNT |= 0x08; // Bit counter = 8, TX data
I2C_State = 10; // Go to next state: receive (N)Ack
break;
case 10: // Receive Data (N)Ack
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x01; // Bit counter = 1, receive (N)Ack
I2C_State = 12; // Go to next state: check (N)Ack
break;
case 12: // Process Data Ack/NAck
if (USISRL & 0x01) // If Nack received...
{
P1OUT |= 0x01; // LED on: error
} else // Ack received
{
P1OUT &= ~0x01; // LED off
//SLV_Data++; // Increment Slave data
}
// Prep for Start condition
USICTL0 &= ~USIOE; // SDA = input
SLV_Addr = 0x90; // Reset slave address
I2C_State = 0; // Reset state machine
break;
}
USICTL1 &= ~USIIFG; // Clear pending flags
}
STELLARIS LM3S6965 CODE
#include "inc/lm3s6965.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "drivers/rit128x96x4.h"
#include "inc/hw_memmap.h"
#include "driverlib/systick.h"
//#include "utils/ustdlib.h"
#include "driverlib/i2c.h"
#include "inc/hw_i2c.h"
#include "driverlib/gpio.h"
#include "itoa.h"
char buff[6]={0};
const char datos[8]={0};
unsigned long i2cdata = 0;
void Setup_i2c_HW()
{
// Turn on I2C0 and Reset to a known state
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
// Configure the PortB pins for I2C0
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// Enable Port B of GPIO
// SCL 0 Bit 2 Output
// SDA 0 Bit 3 Output
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
}
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{}
#endif
int main(void)
{
// Setup clock for 8Mhz
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ);
Setup_i2c_HW();
// Initialize the OLED display.
RIT128x96x4Init(1000000);
// Print a string on the OLED
RIT128x96x4StringDraw("", 30, 30, 25); // Arguments Hor axis, Vert axs, 0-15 grey scale value
// This function initialises operation of the I2C Master block by configuring
// the bus speed for the master and enabling the I2C Master block.
// Param - ulBase = I2C0_MASTER_BASE - Enable and Initialise Master module
// Param - ulI2CClk = SysCtlClockGet() - Gets and returns the processor clock rate
//SysCtlClockSet() must be used and a supported clock rate for the I2C peripheral.
// Param - bFast = false - I2C Master Clk set to 100kbps.
I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), false);
while(1)
{
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x48, true);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(I2CMasterBusy(I2C0_MASTER_BASE));
i2cdata=I2CMasterDataGet(I2C0_MASTER_BASE);
//
volatile unsigned long ulLoop;
//ic2_read_byte();
//
for(ulLoop = 0; ulLoop < 200000; ulLoop++)
{}
itoa(i2cdata, buff, 10);
RIT128x96x4StringDraw (buff, 30, 34, 15);
//RIT128x96x4StringDraw (i2cdata, 30, 34, 15);
//
for(ulLoop = 0; ulLoop < 200000; ulLoop++)
{}
RIT128x96x4StringDraw ("I2C value is", 30, 24, 15);
}
}
Thanks in advance,
Ant