Part Number: LAUNCHXL-F28379D
Other Parts Discussed in Thread: LAUNCHXL-F28069M
Hi All,
I'm working with the LaunchXL-F28379D, using the i2c_ex1_loopback example code.
In loopback mode, the code functions as expected.
In modifying it to not use loopback mode:
//############################################################################# // // FILE: i2c_ex1_loopback.c // // TITLE: I2C Digital Loopback with FIFO Interrupts // //! \addtogroup driver_example_list //! <h1>I2C Digital Loopback with FIFO Interrupts</h1> //! //! This program uses the internal loopback test mode of the I2C module. Both //! the TX and RX I2C FIFOs and their interrupts are used. //! //! A stream of data is sent and then compared to the received stream. //! The sent data looks like this: \n //! 0000 0001 \n //! 0001 0002 \n //! 0002 0003 \n //! .... \n //! 00FE 00FF \n //! 00FF 0000 \n //! etc.. \n //! This pattern is repeated forever. //! //! \b External \b Connections \n //! - None //! //! \b Watch \b Variables \n //! - \b sData - Data to send //! - \b rData - Received data //! // //############################################################################# // $TI Release: F2837xD Support Library v3.08.00.00 $ // $Release Date: Mon Dec 23 17:32:30 IST 2019 $ // $Copyright: // Copyright (C) 2013-2019 Texas Instruments Incorporated - http://www.ti.com/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the // distribution. // // Neither the name of Texas Instruments Incorporated nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // $ //############################################################################# // // Included Files // #include "driverlib.h" #include "device.h" // // Defines // #define MASTER_ADDRESS 0x29 #define SLAVE_ADDRESS 0x28 #define MICRO_SECONDS_10 5 #define MICRO_SECONDS_50 25 #define MICRO_SECONDS_100 50 #define MICRO_SECONDS_150 75 #define MICRO_SECONDS_200 100 #define MICRO_SECONDS_250 125 #define MICRO_SECONDS_300 150 #define MICRO_SECONDS_350 175 #define MICRO_SECONDS_400 200 #define MICRO_SECONDS_450 225 #define MICRO_SECONDS_500 250 #define MICRO_SECONDS_1500 750 #define MILLI_SECONDS_10 5000 #define MILLI_SECONDS_3500 1750000 #define MILLI_SECONDS_5000 2500000 #define SECONDS_7 3500000 #define SEND_1_BYTE 1 #define SEND_2_BYTES 2 #define SEND_3_BYTES 3 #define SEND_4_BYTES 4 #define SEND_5_BYTES 5 #define SEND_6_BYTES 6 #define SEND_7_BYTES 7 #define SEND_8_BYTES 8 #define SEND_9_BYTES 9 #define SEND_10_BYTES 10 #define SEND_11_BYTES 11 #define SEND_12_BYTES 12 #define SEND_13_BYTES 13 #define SEND_14_BYTES 14 #define SEND_15_BYTES 15 #define SEND_16_BYTES 16 #define SEND_17_BYTES 17 #define SEND_18_BYTES 18 #define SEND_19_BYTES 19 #define SEND_20_BYTES 20 // // Globals // uint16_t sData[32]; // Send data buffer uint16_t rData[32]; // Receive data buffer uint16_t backLightBrightness = 1; uint16_t returnData; uint32_t loopCounter = 0; // This counter is used in the main loop uint16_t captureBuffer[32]; int captureBufferIndex; // // Function Prototypes // void initI2CFIFO(void); __interrupt void i2cFIFOISR(void); uint16_t I2C_Write(uint32_t base, uint16_t *data, uint16_t data_length, uint32_t delay_us); uint16_t I2C_Write(uint32_t base, uint16_t *data, uint16_t data_length, uint32_t delay_us) { int i; I2C_sendStartCondition(base); for (i = 0; i < data_length; i++) { I2C_putData(I2CA_BASE, data[i]); DEVICE_DELAY_US(5);//delete...poll I2C regs to determine when to move forward } I2C_sendStopCondition(base); Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8); // Issue ACK DEVICE_DELAY_US(delay_us); return 0; } uint16_t I2C_Read(uint32_t base); uint16_t I2C_Read(uint32_t base) { // Disable/enable I2C module to change SEND/RECEIVE mode I2C_disableModule(I2CA_BASE); I2C_setConfig(I2CA_BASE, I2C_MASTER_RECEIVE_MODE | I2C_REPEAT_MODE); I2C_enableModule(I2CA_BASE); I2C_Write(I2CA_BASE, sData, SEND_1_BYTE, MICRO_SECONDS_200); // Disable/enable I2C module to change SEND/RECEIVE mode I2C_disableModule(I2CA_BASE); I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); I2C_enableModule(I2CA_BASE); return rData[0]; } // // Main // void main(void) { uint16_t i; // // Initialize device clock and peripherals // Device_init(); // // Disable pin locks and enable internal pullups. // Device_initGPIO(); // // Initialize GPIOs 104 and 105 for use as SDA A and SCL A respectively // // OR // // Initialize GPIOs 0 and 1 for use as SDA A and SCL A respectively // GPIO_setPinConfig(GPIO_0_SDAA); // Was 104 GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); GPIO_setQualificationMode(0, GPIO_QUAL_ASYNC); GPIO_setPinConfig(GPIO_1_SCLA); GPIO_setPadConfig(1, GPIO_PIN_TYPE_PULLUP); GPIO_setQualificationMode(1, GPIO_QUAL_ASYNC); GPIO_setPadConfig(32, GPIO_PIN_TYPE_STD); GPIO_setDirectionMode(32, GPIO_DIR_MODE_OUT); GPIO_writePin(32, 0); // // Initialize PIE and clear PIE registers. Disables CPU interrupts. // Interrupt_initModule(); // // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // Interrupt_initVectorTable(); // // Interrupts that are used in this example are re-mapped to ISR functions // found within this file. // Interrupt_register(INT_I2CA_FIFO, &i2cFIFOISR); // // Set I2C use, initializing it for FIFO mode // initI2CFIFO(); // // Initialize the data buffers // for(i = 0; i < 32; i++) { sData[i] = 0; rData[i] = 0; } // // Enable interrupts required for this example // Interrupt_enable(INT_I2CA_FIFO); // // Enable Global Interrupt (INTM) and realtime interrupt (DBGM) // EINT; ERTM; /* sData[0] = 0xfe; sData[1] = 0x01; // This bit of code causes the display to reset. It works as expected. GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_2_BYTES, MILLI_SECONDS_3500); GPIO_writePin(32, 0); // This lowers the brightness of the display. It works as expected. sData[0] = 0xfe; sData[1] = 0x99; sData[2] = 0x00; // Disable/enable I2C module to change SEND/RECEIVE mode I2C_disableModule(I2CA_BASE); I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); I2C_enableModule(I2CA_BASE); // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_3_BYTES, MICRO_SECONDS_500); GPIO_writePin(32, 0); // This sets the Customer Data string in the display module sData[0] = 0xfe; sData[1] = 0x34; sData[2] = 0x0f; sData[3] = 82; // ' ' sData[4] = 111; // ' ' sData[5] = 98; // 'b' sData[6] = 105; // ' ' sData[7] = 110; // ' ' sData[8] = 32; // ' ' sData[9] = 68; // ' ' sData[10] = 97; // ' ' sData[11] = 108; // ' ' sData[12] = 101; // ' ' sData[13] = 32; // ' ' sData[14] = 86; // ' ' sData[15] = 105; // ' ' sData[16] = 99; // ' ' sData[17] = 101; // ' ' sData[18] = 0; // ' ' sData[19] = 0; // ' ' sData[20] = 0; // ' ' sData[21] = 0; // ' ' sData[22] = 0; // ' ' sData[23] = 0; // ' ' sData[24] = 0; // ' ' sData[25] = 0; // ' ' sData[26] = 0; // ' ' sData[27] = 0; // ' ' sData[28] = 0; // ' ' sData[29] = 0; // ' ' sData[30] = 0; // ' ' sData[31] = 0; // ' ' // Disable/enable I2C module to change SEND/RECEIVE mode I2C_disableModule(I2CA_BASE); I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); I2C_enableModule(I2CA_BASE); GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_18_BYTES, MICRO_SECONDS_1500); GPIO_writePin(32, 0); */ // // Loop forever. Suspend or place breakpoints to observe the buffers. // while(1) { if(loopCounter++ > 20000000) // { loopCounter = 0; sData[0] += 1; sData[0] &= 0xff; sData[1] = 0x9a; GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_1_BYTE, MICRO_SECONDS_250); GPIO_writePin(32, 0); DEVICE_DELAY_US(1000); DEVICE_DELAY_US(1); } // I2C_Read(I2CA_BASE); // This writes 0x28r 0x00 and results in a receive fifo interrupt returnData = rData[0]; // rData[0] is populated in the ISR // This switch statement provides a way to trigger the logic analyzer when desired switch(returnData) { case 0xee: DEVICE_DELAY_US(10); GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; case 0x35: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; case 0x06: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; case 0x40: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; default : break; } /* // A FIFO interrupt will be generated for each Rx based // on the Interrupt levels configured. // The ISR will handle pulling data from the RX FIFO if(loopCounter == 5000) // Set Backlight Brightness { if(++backLightBrightness > 255) { backLightBrightness = 0; } else { backLightBrightness *= 2; backLightBrightness -= 1; } sData[0] = 0xfe; sData[1] = 0x99; sData[2] = backLightBrightness; I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_3_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 10000) // Get Protocol Revision { sData[0] = 0xfe; sData[1] = 0x00; // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_2_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 15000) // Set Backlight Brightness { if(++backLightBrightness > 255) { backLightBrightness = 0; } else { backLightBrightness *= 2; backLightBrightness -= 1; } sData[0] = 0xfe; sData[1] = 0x99; sData[2] = backLightBrightness; I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_3_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 20000) // Get Module Type { sData[0] = 0xfe; sData[1] = 0x37; // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_2_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 25000) // Set Backlight Brightness { if(++backLightBrightness > 255) { backLightBrightness = 0; } else { backLightBrightness *= 2; backLightBrightness -= 1; } sData[0] = 0xfe; sData[1] = 0x99; sData[2] = backLightBrightness; I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_3_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 30000) // Get Module String { sData[0] = 0xfe; sData[1] = 0x38; // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_2_BYTES, MICRO_SECONDS_500); GPIO_writePin(32, 0); } if(loopCounter == 35000) // Set Backlight Brightness { if(++backLightBrightness > 255) { backLightBrightness = 0; } else { backLightBrightness *= 2; backLightBrightness -= 1; } sData[0] = 0xfe; sData[1] = 0x99; sData[2] = backLightBrightness; I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_3_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 40000) // Get Customer Data { sData[0] = 0xfe; sData[1] = 0x35; // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_2_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter == 55000) // Set Backlight Brightness { if(++backLightBrightness > 255) { backLightBrightness = 0; } else { backLightBrightness *= 2; backLightBrightness -= 1; } sData[0] = 0xfe; sData[1] = 0x99; sData[2] = backLightBrightness; I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE); // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_3_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } if(loopCounter++ > 60000) // Get Backlight Brightness { loopCounter = 0; sData[0] = 0xfe; sData[1] = 0x9a; // GPIO_writePin(32, 1); I2C_Write(I2CA_BASE, sData, SEND_2_BYTES, MICRO_SECONDS_250); GPIO_writePin(32, 0); } I2C_Read(I2CA_BASE); // This writes 0x28r 0x00 and results in a receive fifo interrupt returnData = rData[0]; // rData[0] is populated in the ISR // This switch statement provides a way to trigger the logic analyzer when desired switch(returnData) { case 0xfc: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; case 0x35: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; case 0x06: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; case 0x40: DEVICE_DELAY_US(10); // GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); break; default : break; } */ } } // // Function to configure I2C A in FIFO mode. // void initI2CFIFO() { // // Must put I2C into reset before configuring it // I2C_disableModule(I2CA_BASE); // // I2C configuration. Use a 400kHz I2CCLK with a 50% duty cycle. // // Actual values to produce precisely 115.2kHz SCL @ 35% dutycycle HWREGH(I2CA_BASE + I2C_O_PSC) = I2C_PSC_IPSC_M & 16; HWREGH(I2CA_BASE + I2C_O_CLKH) = 13; HWREGH(I2CA_BASE + I2C_O_CLKL) = 28; I2C_setConfig(I2CA_BASE, (I2C_MASTER_SEND_MODE | I2C_REPEAT_MODE)); I2C_setDataCount(I2CA_BASE, 1); I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8); // // Configure for external mode (no loopback) // I2C_setSlaveAddress(I2CA_BASE, SLAVE_ADDRESS); I2C_setOwnSlaveAddress(I2CA_BASE, MASTER_ADDRESS); I2C_disableLoopback(I2CA_BASE); I2C_setEmulationMode(I2CA_BASE, I2C_EMULATION_STOP_SCL_LOW); // // FIFO and interrupt configuration // I2C_enableFIFO(I2CA_BASE); I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF | I2C_INT_TXFF); I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TX1, I2C_FIFO_RX1); I2C_enableInterrupt(I2CA_BASE, I2C_INT_RXFF | I2C_INT_TXFF); // // Configuration complete. Enable the module. // I2C_enableModule(I2CA_BASE); } // // I2C A Transmit & Receive FIFO ISR. // __interrupt void i2cFIFOISR(void) { uint16_t i; // // If receive FIFO interrupt flag is set, read data // if((I2C_getInterruptStatus(I2CA_BASE) & I2C_INT_RXFF) != 0) { uint16_t bytes_Received; bytes_Received = I2C_getRxFIFOStatus(I2CA_BASE); I2C_setDataCount(I2CA_BASE, bytes_Received); for(i = 0; i < bytes_Received; i++) { rData[i] = I2C_getData(I2CA_BASE); if(rData[i] != 0x00) { captureBufferIndex &= 0x1f; captureBuffer[captureBufferIndex++] = rData[i]; DEVICE_DELAY_US(1); } if(rData[i] == 0xfc) { GPIO_writePin(32, 1); DEVICE_DELAY_US(1); GPIO_writePin(32, 0); } } // // Clear interrupt flag // I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF); Example_PassCount++; } // // Transmit FIFO interrupt is not used // // If transmit FIFO interrupt flag is set, put data in the buffer // else if((I2C_getInterruptStatus(I2CA_BASE) & I2C_INT_TXFF) != 0) { //This interrupt is not enabled } // // Issue ACK // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8); } // // End of File //
but instead to transmit data over I2C to a separate slave processor (LaunchXL-F28069M), the data stream stops after the first transaction. Here's how it looks on the logic analyzer:
You can see that the 1st transaction completes perfectly as expected, including start, stop, data, and ACKs. However, there is never a 2nd transaction. The code has a loop/counter that sends a data byte every few seconds. At the end of the 1st loop cycle, the 1st I2C transaction occurs (sending the data shown above), then the main loop is idle until the next loop/counter cycle begins again. Stepping through the code, I see that the data is being loaded into the I2CDXR, but no data is sent. In fact, no start or stop condition occurs. The following logic analyzer image shows the trigger pulse from a GPIO (bottom trace), with a conspicuous absence of start, stop, data, etc conditions in the SDA and SCL traces.
I'm having trouble understanding the inner workings of the I2C hardware module as well as the example software code.
After the 1st transaction, the STT and STP bits in the I2CMDR register are both set, and they don't seem to be getting reset.
I'm running the I2C module in repeat mode (I2CMDR RM bit = 1). The Technical Reference Manual (SPRUHM8I, page 2332) says that the STP bit "...is automatically cleared after the STOP condition has been generated" In stepping through the code, it appears the stop condition is set as expected at the end of 1st transaction, but the STP bit isn't getting reset.
The second transaction starts about 5 seconds after the first, so I don't think it's writing to the I2C module before it has time to complete housekeeping from the first transaction.
The manual also talks about how "The I2C module delays clearing of [the STP] bit until after the I2CSTR[SCD] bit is set." I can see that this bit is set, so it shouldn't be preventing clearing of the STP bit.
Can you help me understand the inter-workings and relationships of these register bits? I'm also a little hazy on whether using FIFO interrupts negates the use of the other interrupt registers (e.g. I2CIER).
Information in the manual is too terse for me to adequately decipher. Is there a better reference to help me understand? I've labored long and hard over i2c_ex1_loopback, i2c_ex3_external_loopback, and i2c_eeprom examples running in both the LaunchXL-F28069M and LaunchXL-F28379D dev modules, and my head is swimming.
Thanks in advance for the help,
robin