Msp430 i²c модуль и библиотеки
У меня есть проект, который имеет ведущее устройство MSP430G2553 и трехосевой цифровой выход Gyro ITG-3200. ITG3200 использует протокол i²c для связи, поэтому я проверял использование модуля i²c на Msp. Для начала я скачал примеры TI I²c, которые можно найти по http://www.ti.com/lsds/ti/microcontroller/16-bit_msp430/msp430_software_landing.page После отладки первого кода, который находится между мастером MSP и датчик температуры TMP100 в качестве ведомого. Вот пример кода.
//******************************************************************************
// MSP430G2xx3 Demo - USCI_B0 I2C Master to TMP100, Set P1.0 if Temp > 28C
//
// Description: I2C interface to TMP100 temperature sensor in 9-bit mode.
// Timer_A CCR0 interrupt is used to wake up and read the two bytes of
// the TMP100 temperature register every 62ms. If the temperature is greater
// than 28C, P1.0 is set, else reset. CPU is operated in LPM0. I2C speed
// is ~100kHz.
// ACLK = n/a, MCLK = SMCLK = TACLK = BRCLK = default DCO = ~1.2MHz
//
// /|\ /|\ /|\
// | TMP100 10k 10k MSP430G2xx3
// | ------- | | -------------------
// +--|Vcc SDA|<-|---+->|P1.7/UCB0SDA XIN|-
// | | | | | |
// +--|A1,A0 | | | XOUT|-
// | | | | |
// +--|Vss SCL|<-+------|P1.6/UCB0SCL P1.0|---> LED
// \|/ ------- | |
//
// D. Dang
// Texas Instruments Inc.
// February 2011
// Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
//******************************************************************************
#include <msp430.h>
unsigned int RxByteCtr;
unsigned int RxWord;
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P1DIR |= BIT0; // P1.0 output
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x4e; // Set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0RXIE; // Enable RX interrupt
TACTL = TASSEL_2 + MC_2; // SMCLK, contmode
while (1)
{
RxByteCtr = 2; // Load RX byte counter
UCB0CTL1 |= UCTXSTT; // I2C start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable interrupts
// Remain in LPM0 until all data
// is RX'd
if (RxWord < 0x1d00) // >28C?
P1OUT &= ~0x01; // No, P1.0 = 0
else
P1OUT |= 0x01; // Yes, P1.0 = 1
__disable_interrupt();
TACCTL0 |= CCIE; // TACCR0 interrupt enabled
__bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable interrupts
// Remain in LPM0 until TACCR0
// interrupt occurs
TACCTL0 &= ~CCIE; // TACCR0 interrupt disabled
}
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TA0_ISR(void)
{
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
// The USCIAB0TX_ISR is structured such that it can be used to receive any
// 2+ number of bytes by pre-loading RxByteCtr with the byte count.
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
RxByteCtr--; // Decrement RX byte counter
if (RxByteCtr)
{
RxWord = (unsigned int)UCB0RXBUF << 8; // Get received byte
if (RxByteCtr == 1) // Only one byte left?
UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition
}
else
{
RxWord |= UCB0RXBUF; // Get final received byte,
// Combine MSB and LSB
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
Я построил ту же схему, где 2 10K подтягиваний на SDA и SCL, изменил адрес ведомого устройства на 0x69 или 0x68, который является гироскопическим адресом, указанным в руководстве пользователя устройства. Поскольку я еще не построил никакого мониторинга, я использовал осциллограф для проверки импульсов на SCL и SDA. Я еще не ожидал увидеть что-нибудь на SDA, но меня удивляет, почему я не вижу даже тактовый цикл на шине SCL. Он либо всегда на 3,3 В (MSP внутренняя VCC), а иногда и около 1 В (0,80~). Даже когда я удаляю гироскоп, шину SDA и SCL, я не вижу импульсов на порте P1.6. Есть идеи?
Кроме того, если кто-то знает библиотеку для этого устройства, как в Arduino, я действительно хотел бы использовать ее больше, чем пытаться проверить все регистры и прерывания.
2 ответа
Я знаю, что эта тема была на низком уровне в течение некоторого времени. После того, как я много копался и работал в течение месяца, я придумал этот последний чистый код. Я столкнулся с другой проблемой, которую я вставлю сюда.
У меня есть код, над которым я работаю, который соединяет подчиненное устройство гироскопа ITG-3200 и мастер MSP430G2553 через шину I2C. Вчера все работало нормально, но сегодня как-то не работает. Я пытался отлаживать как можно больше без гироскопа ACK, но кажется, что после входа в LPM TX прерывание не происходит, поэтому оно застряло в LPM. Можете ли вы проверить, чтобы увидеть то, что мне не хватает? Я пытался очистить код как можно больше, и он может показаться немного сложным, но не стесняйтесь спрашивать о любой функции.
/* --COPYRIGHT--,
* Copyright (c) 2013, Barışcan Kayaoğlu
* All rights reserved.
*
* --COPYRIGHT--*/
//******************************************************************************
// MSP430G2xx3 I2C Demo - USCI_B0 I2C Master TX/RX single byte from ITG-3200
// gyroscope.
//
// Description: This demo connects a MSP430Gxx3 launchpad to ITG-3200 via
// USCI_B0 I2C module. The launchpad act as a master and itg-300 act as a
// slave. Master reads 6 byte consecutively and send it to the vitual COM
// Port on Usb with USCI_A0 Uart module. DCO = 1MHz
//
// /|\ /|\
// ITG-3200 10k 10k MSP430G2xx3
// slave | | master
// ----------------- | | -----------------
// | SDA|<-|----+---->|P1.7/UCB0SDA |
// | CLK|<-|-.GND | |
// | GND|<-|-' | |
// | SCL|<-+--------->|P1.6/UCB0SCL |
// | VCC|<--. | P1.1/UCA0TX|-------> COM Port (9600 baud)
// | VIO|<--'3.3V | |
// | INT| | |
// Barışcan Kayaoğlu
// May 2013
// Built with CCS Version 5.3.0.00090
//******************************************************************************
#include <msp430g2553.h>
int TXByteCtr; // This counter used for counting bytes before the stop condition
char xRate_L; // Variable to hold X_Low register value
char xRate_H; // Variable to hold X_High register value
char yRate_L; // Variable to hold Y_Low register value
char yRate_H; // Variable to hold Y_High register value
char zRate_L; // Variable to hold Z_Low register value
char zRate_H; // Variable to hold Z_High register value
int i2c_State; // This counter held the state machine condition of I2C
int Rx = 0; // Flag for the interrupt vector. 1 for Receive 0 for Transmit
int init = 0; // Flag for the interrupt vector. 1 for Writing to gyro for config 0 for reading
//Gyro configuration addresses
char WHO_AM_I = 0x00; // Gyro register where it helds the slave address 0x69 | 0x68
char SMPLRT_DIV= 0x15; // Gyro register where it helds the divider value for sample rate
char DLPF_FS = 0x16; // Gyro register where it helds the low pass filter config
//Gyro Memory addresses;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;
char TEMP_OUT_H = 0x1B;
char TEMP_OUT_L = 0x1C;
char itgAddress = 0x69;
//Gyro configuration constants
char DLPF_CFG_0 = 1<<0; // 1
char DLPF_CFG_1 = 1<<1; // 10
char DLPF_CFG_2 = 1<<2; // 100
char DLPF_FS_SEL_0 = 1<<3; // 1000
char DLPF_FS_SEL_1 = 1<<4; //10000
void init_I2C(void);
void Transmit(void);
void Receive(void);
void initUart(void);
void initGyro(void);
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1Mhz
DCOCTL = CALDCO_1MHZ;
//__delay_cycles(15000); // Wait gyro to wake up
P1SEL |= BIT1 + BIT2 + BIT6 + BIT7; // Assign I2C pins to USCI_B0 // Assign Uart pins to USCI_A0
P2SEL |= BIT1 + BIT2 + BIT6 + BIT7; // Assign I2C pins to USCI_B0 // Assign Uart pins to USCI_A0
init_I2C();
initUart();
initGyro();
init = 0; // Flag to reading from configuration writing
while(1) {
switch(i2c_State) {
case 0: // Wait state
__delay_cycles(8000); // 10 ms
i2c_State++;
break;
case 1: // Read X_High state
Rx = 0; // Receive flag = transmit
TXByteCtr = 1; // TXByteCtr 1 for sending register address and stop
Transmit(); // I2C start condition with Write operation
Rx = 1; // Receive flag = receive
Receive(); // I2C start condition with Read operation
i2c_State++;
break;
case 2: // Read X_Low state
Rx = 0; // Receive flag = transmit
TXByteCtr = 1; // TXByteCtr 1 for sending register address and stop
Transmit(); // I2C start condition with Write operation
Rx = 1; // Receive flag = receive
Receive(); // I2C start condition with Read operation
i2c_State++;
break;
case 3: // Read Y_High state
Rx = 0; // Receive flag = transmit
TXByteCtr = 1; // TXByteCtr 1 for sending register address and stop
Transmit(); // I2C start condition with Write operation
Rx = 1; // Receive flag = receive
Receive(); // I2C start condition with Read operation
i2c_State++;
break;
case 4: // Read Y_Low state
Rx = 0; // Receive flag = transmit
TXByteCtr = 1; // TXByteCtr 1 for sending register address and stop
Transmit(); // I2C start condition with Write operation
Rx = 1; // Receive flag = receive
Receive(); // I2C start condition with Read operation
i2c_State++;
break;
case 5: // Read Z_High state
Rx = 0; // Receive flag = transmit
TXByteCtr = 1; // TXByteCtr 1 for sending register address and stop
Transmit(); // I2C start condition with Write operation
Rx = 1; // Receive flag = receive
Receive(); // I2C start condition with Read operation
i2c_State++;
break;
case 6: // Read Z_Low state
Rx = 0; // Receive flag = transmit
TXByteCtr = 1; // TXByteCtr 1 for sending register address and stop
Transmit(); // I2C start condition with Write operation
Rx = 1; // Receive flag = receive
Receive(); // I2C start condition with Read operation
i2c_State++;
break;
case 7:
UCA0TXBUF = 0x58; // X
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x3A; // :
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = xRate_H;
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = xRate_L;
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x09; // tab
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
i2c_State++;
break;
case 8:
UCA0TXBUF = 0x59; // Y
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x3A; // :
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = yRate_H;
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = yRate_L;
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x09; // tab
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
i2c_State++;
break;
case 9:
UCA0TXBUF = 0x5A; // Z
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x3A; // :
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = zRate_H;
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = zRate_L;
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x5C; // \
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x6E; // n
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
i2c_State = 0;
break;
} // End of state machine
}
} // End of Main
void readX_H() {
if(Rx == 1){ // Master Recieve
xRate_H = UCB0RXBUF; // Get RXBuffer value to xRate_H
}
else { // Master Transmit
if (TXByteCtr) { // TX byte counter = 1 : send gyro address
UCB0TXBUF = GYRO_XOUT_H; // Load TX buffer // request from X_High register
TXByteCtr--; // Decrement TX byte counter
}
else { // Tx byte counter = 0 : register address sent
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX interrupt flag
}
}
}
void readX_L() {
if(Rx == 1){ // Master Recieve
xRate_L = UCB0RXBUF; // Get RXBuffer value to xRate_L
}
else { // Master Transmit
if (TXByteCtr) { // TX byte counter = 1 : send gyro address
UCB0TXBUF = GYRO_XOUT_L; // Load TX buffer // request from X_Low register
TXByteCtr--; // Decrement TX byte counter
}
else { // Tx byte counter = 0 : register address sent
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX interrupt flag
}
}
}
void readY_H() {
if(Rx == 1) { // Master Recieve
yRate_H = UCB0RXBUF; // Get RXBuffer value to yRate_H
}
else { // Master Transmit
if (TXByteCtr) { // TX byte counter = 1 : send gyro address
UCB0TXBUF = GYRO_YOUT_H; // Load TX buffer // request from Y_High register
TXByteCtr--; // Decrement TX byte counter
}
else { // Tx byte counter = 0 : register address sent
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX interrupt flag
}
}
}
void readY_L() {
if(Rx == 1){ // Master Recieve
yRate_L = UCB0RXBUF; // Get RXBuffer value to yRate_L
}
else { // Master Transmit
if (TXByteCtr) { // TX byte counter = 1 : send gyro address
UCB0TXBUF = GYRO_YOUT_L; // Load TX buffer // request from Y_Low register
TXByteCtr--; // Decrement TX byte counter
}
else { // Tx byte counter = 0 : register address sent
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX interrupt flag
}
}
}
void readZ_H() {
if(Rx == 1){ // Master Recieve
zRate_H = UCB0RXBUF; // Get RXBuffer value to zRate_H
}
else { // Master Transmit
if (TXByteCtr) { // TX byte counter = 1 : send gyro address
UCB0TXBUF = GYRO_ZOUT_H; // Load TX buffer // request from Z_High register
TXByteCtr--; // Decrement TX byte counter
}
else { // Tx byte counter = 0 : register address sent
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX interrupt flag
}
}
}
void readZ_L() {
if(Rx == 1){ // Master Recieve
zRate_L = UCB0RXBUF; // Get RXBuffer value to zRate_L
}
else { // Master Transmit
if (TXByteCtr) { // TX byte counter = 1 : send gyro address
UCB0TXBUF = GYRO_ZOUT_L; // Load TX buffer // request from Z_Low register
TXByteCtr--; // Decrement TX byte counter
}
else { // Tx byte counter = 0 : register address sent
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX interrupt flag
}
}
}
void initGyro(void) {
TXByteCtr = 2; // 2 bytes will occur. First register address send, Second Data send
init = 1; // config flag to 1 : Sending Divider value
Transmit(); // Start condition with Writing mode
init = 2; // config flag to 2 : Sending Low pass filter value
TXByteCtr = 2; // Restart byte counter
Transmit(); // Start condition with Writing mode
}
void init_I2C(void) {
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 10; // fSCL = 1Mhz/10 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = itgAddress; // Slave Address is 069h
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCB0RXIE + UCB0TXIE; // Enable RX and TX interrupt
}
void initUart(void) {
UCA0CTL1 |= UCSSEL_2; // Use SMCLK
UCA0BR0 = 104; // 1MHz 9600
UCA0BR1 = 0; // 1MHz 9600
UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
}
void Transmit(void){
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX with start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
void Receive(void){
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 &= ~UCTR ; // Clear I2C TX flag
UCB0CTL1 |= UCTXSTT; // I2C start condition
while (UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
void twosCompToDecimal() {
}
#pragma vector = USCIAB0TX_VECTOR // USCI TX interrupt vector. I2C module share RX and TX interrupts.
__interrupt void USCIAB0TX_ISR(void) // This will occur either when RXBuffer is full or TXBuffer is sent.
{
if(init == 1) { // Gyro writing for configuration. Sending LPF register address
if (TXByteCtr == 2) { // byte counter = 2 : sending register address
UCB0TXBUF = DLPF_FS; // Low pass filter value register address to TXBuffer
TXByteCtr--; // Decrement TX byte counter
}
else if(TXByteCtr == 1) { // byte counter = 1 : sending config value
UCB0TXBUF = (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0); // config value to TXBuffer
TXByteCtr--; // Decrement TX byte counter
}
else { // byte counter = 0 : stop condition
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
else if(init == 2) { // Gyro writing for configuration. Sending Sample Rate Divider register address
if (TXByteCtr == 2) { // byte counter = 1 : sending config value
UCB0TXBUF = SMPLRT_DIV; // Sample Rate Divider value to TXBuffer
TXByteCtr--; // Decrement TX byte counter
}
else if(TXByteCtr == 1) { // byte counter = 1 : sending config value
UCB0TXBUF = 9; // config value to TXBuffer
TXByteCtr--; // Decrement TX byte counter
}
else { // byte counter = 0 : stop condition
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
else { // Gyro Reading operation.
switch(i2c_State) {
case 1: // Read X High
readX_H();
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
break;
case 2: // Read X Low
readX_L();
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
break;
case 3: // Read Y High
readY_H();
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
break;
case 4: // Read Y Low
readY_L();
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
break;
case 5: // Read Z High
readZ_H();
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
break;
case 6: // Read Z Low
readZ_L();
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
break;
}
}
}
Это не верно. Либо код, либо комментарии.
//Gyro configuration constants
char DLPF_CFG_0 = 1<<0; // 1
char DLPF_CFG_1 = 1<<1; // 10
char DLPF_CFG_2 = 1<<2; // 100
char DLPF_FS_SEL_0 = 1<<3; // 1000
char DLPF_FS_SEL_1 = 1<<4; //10000
1<< 1 - это 2, а не 10. 1<<2 - это 4, а не 100 и так далее...
Другое дело, что "char" может представлять только до +127 (255 без знака).
Возможно, это не является причиной того, что он не работает, но вы должны посмотреть на него, хотя бы посмотреть, действительно ли это то, что вы хотите отправить.