Hi there,
I am sending two bytes of data (0x10 and 0x00) from the Master in burst mode over I2C0.
The following code works fine as long as I insert two calls to SysCtlDelay prior to placing data onto the I2C master bus and sending it (burst mode). I am able to observe the data being written using an Agilent DSO that has an I2C decoding option.
Why do I need these delays ? Without it (or without placing a BP at the line after it) the first byte (0x10 in this case) is NOT transmitted only the second and subsequent bytes are.
Jump down to the function named I2C_start_measuring to see where the calls to ROM_SysCtlDelay are.
void configure_I2C(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); // I2C0 is used with PortB[3:2]. // GPIO port B needs to be enabled so these pins can be used. // SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // // Configure the pin muxing for I2C0 functions on port B2 and B3. // This is labelled PB2 and PB3 on the eval board. (PB=PortB) GPIOPinConfigure(GPIO_PB2_I2C0SCL); GPIOPinConfigure(GPIO_PB3_I2C0SDA); // set PB3 as I2C SDA pin. the function name omits the word SDA and one needs to read the documentation to discover this. // note an earlier version of my code had both pins being set to SDA (when only one should have) then one of the both being set to SCL //This call sets the pin/pad to open-drain operation with weak pull up as per p. 1277 of the datasheet GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3); //Configure PB2 pin for use as SCL by the I2C peripheral. this sets the pad for push-pull operation (not open drain (OD) as per as per p. 1277 of the datasheet). //OD is is usually how I2C works //see here for the confusion surrounding this being set to push pull rather than open drain http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/254099.aspx GPIOPinTypeI2CSCL(GPIO_PORTB_BASE,GPIO_PIN_2); // // (En/dis)able loopback mode as required. Loopback mode is a built in feature that is useful for debugging I2C operations. It internally connects the I2C // master and slave terminals, which effectively let's you send data as a master and receive data as a slave. //Refer to p. 1057 of E:\Documentation\Device\Datasheet-LM4F232H5QD.pdf NOTE: For external I2C operation you will need to use external pullups // that are stronger than the internal pullups. Refer to the datasheet for more information. //temporarily disable loopback by explicitly setting bit 0 of I2C_O_MCR to 0 (does this code actually work ?!) and commenting out the next line //which sets it to 1 HWREG(I2C0_BASE + I2C_O_MCR) |= 0x00; //HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01; //Sensor might use a clock rate of 400kbps , this isn't documented anywhere I could find, even in their example code. // so set the last parameter to true for now as If the parameter bFast is true, then the master block is set up to transfer data at 400 Kbps; // otherwise, it is set up to transfer data at 100 Kbps I2CMasterInitExpClk(I2C0_BASE, ui32SysClock /*SysCtlClockGet()*/, true); I2CMasterSlaveAddrSet(I2C0_BASE, SENS1_AIRPATH_FLOW_SLAVE_ADDRESS, false /*true*/); //false=>Master reads from slave however the first command will be a write !! (it doesn't work for this parameter to be true) //wait until the Master is not busy sending while(I2CMasterBusy(I2C0_BASE)) { } I2CMasterErrorValue=I2CMasterErr(I2C0_BASE); if (I2CMasterErrorValue!=I2C_MASTER_ERR_NONE) { UARTprintf("\nI2C Master Error: %d\n", I2CMasterErrorValue); } } void I2C_start_measuring(void) { ROM_SysCtlDelay(150);//without a delay of at least 80 (at 100MHz) the first byte is not decoded by the CRO. I2CMasterDataPut(I2C0_BASE, 0x10);//Tx first 8 bits of 0x1000. sometimes this isn't properly written or decoded by the CRO. Why ? I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);// Initiate send of character from Master to Slave while(I2CMasterBusy(I2C0_BASE)) { //wait until bus is not busy } //Check for and report on any error I2CMasterErrorValue=I2CMasterErr(I2C0_BASE); if (I2CMasterErrorValue!=I2C_MASTER_ERR_NONE) { UARTprintf("\nI2C Master Error: %d\n", I2CMasterErrorValue); } ROM_SysCtlDelay(150);//without a delay of at least 80 (at 100MHz) the first byte is not decoded by the CRO. I2CMasterDataPut(I2C0_BASE, 0x00);//Tx second 8 bits of 0x1000 I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);// Initiate send of character from Master to Slave while(I2CMasterBusy(I2C0_BASE)) { //wait until bus is not busy } //Check for and report on any error I2CMasterErrorValue=I2CMasterErr(I2C0_BASE); if (I2CMasterErrorValue!=I2C_MASTER_ERR_NONE) { UARTprintf("\nI2C Master Error: %d\n", I2CMasterErrorValue); } } int main(void) { uint32_t TxData[NUMBER_OF_SAMPLES_PER_CHANNEL]; //32 bits of data in each array element however SPI only uses 16 bits uint32_t RxData[NUMBER_OF_SAMPLES_PER_CHANNEL]; //32 bits of data in each array element however SPI only uses 16 bits uint32_t index,mainLoopIndex,SysTickPeriod;//SysTickPeriod is the period to set the SysTick timer. uint32_t CPU_Load,SysTickAfterAllTasksRun=0;//CPU_Load is the CPU load as an integer value (units=%). //SysTickAfterAllTasksRun it the value the Systick timer has counted down //to after all tasks in the main loop have run. // uint32_t ui32SysClock; // system clock setting schieved by SysCtlClockFreqSet now extern unsigned short TxDataRaw;//SPI bus is only 16 bits wide long ReadDataCount=0;// number of Data bytes read from the Rx read FIFO buffer long WriteDataCount=0;// number of Data bytes able to be written to the Tx write FIFO buffer uint32_t ulDataRx[NUM_SSI_DATA]; //DataRx is an array to receive the data from the AD7606. Each element contains 32 bits of data. // // Set the clocking to run directly from the external crystal/oscillator. // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the // crystal on your board. // use the following line to run the system clock at 16MHz directly from the external crystal // SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // set the Master clock to be say 50MHz (max is 80MHz) by // running from the external crystal via the PLL. The PLL runs at 200MHz // Divide the 200MHz signal by 4.0 (SYSCTL_SYSDIV_4). // The main crystal on the TI LM4F eval board is 16MHz // set the Master clock to be 50MHz which is a period of 20ns // SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); //deprecated // On TM4C129 the function pair of SysCtlClockSet and SysCtlClockGet are now replaced by // SysCtlClockFreqSet which returns the System Clock // set the Master clock to be 100MHz which is a period of 10ns (Max speed is 120MHz and is avoided for now to leave a buffer for future use if needed) ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 100000000); // to run at 80MHz use SYSCTL_SYSDIV_2_5 //SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); //setup the SysTick timer used to delay until the next time multiple //this method is only being used until a real ADC value is being returned and we can sync off that //If the master clock is set to run at 16MHz (max 80MHz) //then loading 16,000,000 into the systick period will cause it to wrap around once per second //it is a 24 bit counter capable of counting down from 2^24=16,777,216 //SysTickPeriod=(SysCtlClockGet()*INTER_PROCESSOR_SAMPLE_PERIOD_IN_MILLISECONDS)/1000;//be careful of the order of evaluation interim fractional results cause truncation.incorrect values SysTickPeriod=(ui32SysClock*INTER_PROCESSOR_SAMPLE_PERIOD_IN_MILLISECONDS)/1000;//be careful of the order of evaluation interim fractional results cause truncation.incorrect values //i.e. SysTickPeriod=50,000,000 x 50 / 1000 = 2,500,000 for 20Hz bulk sample frequency // or SysTickPeriod=50,000,000 x 20 / 1000 = 1,000,000 for 50Hz bulk sample frequency SysTickPeriodSet(SysTickPeriod); //this sets the SysTickPeriod to be the number of system clock periods during the BULK_SAMPLE_PERIOD //setting the SysTickPeriod to this means the counter will wrap around that often. //If not using the ADC for timing then this could be used as the interrupt period. //when faster than 16MHz the SysTick counter will wrap around in less than 1 second as it only has 16,777,216 values //at 50MHz the Systick counter will reach // Enable SysTick to generate interrupts. SysTickIntEnable(); //the systick counter will wrap around in 1 second at 16MHz, and proportionately shorter at the faster clock speeds. //for this reason when timing, ensure you don't exceed the period of the systick timer //reset the timer to a known value by writing to the NVIC_ST__CURRENT register. //refer to the Stellaris Peripheral Driver Library UG and search for NVIC_ST_CURRENT //this might not be necessary as I think the act of loading a value in sets it to zero. HWREG(NVIC_ST_CURRENT)=0x000000; //the SysTick timer is enabled later on. // // Set up the serial console to use for displaying messages. This is // just for debugging and is not needed for SPI operation. // InitConsole(); //init the I2C configure_I2C(); //send start measurement command I2C_start_measuring(); //read flow measurement data read_I2C_data(); }