Hello All,
I'm trying to implement an I2C communication using EVALBOT. Evalbot is the master which has to continuously receive date from slave.
Can someone please give me rough sketch of the algorithm to be used. Do I need to send acknowledge after receiving each byte ? Or will the I2CMasterDataGet() function do it on its own? Is it possible to continuously keep on reading (and store each byte), rather than reading byte by byte?
Any help will be very much appreciated.
Thanks
Past post - blessed both by Stellaris Sue & independent forum user - provides I2C set-up/guidance from both TI responder and this reporter.
http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/p/169023/639164.aspx#639164
The "ACKs" (and dreaded NAKs) are generated automatically by the I2C functions provided by TI's StellarisWare. Suspect that continuous reading of I2C Slave is at least somewhat dependent upon that specific slave. (for instance - I know that many EEproms auto increment their address and may "dump" their entire "guts" without requiring the "full" I2C transaction "initiator" to be re-sent)
I2C is well covered w/in StellarisWare (entire chapter), MCU datasheet, and numerous software examples are provided. (look both in examples and peripheral folders of StellarisWare...
Thanks for your reply.
I tried studying all the example codes in StellarisWare.
// Set the address for slave module. This is a 7-bit address sent in the// following format:// [A6:A5:A4:A3:A2:A1:A0:RS]//// A zero in the R/S position of the first byte means that the master// transmits (sends) data to the selected slave, and a one in this position// means that the master receives data from the slave.//
Suppose my device slave address in 0x39(given in the datasheet), do I need to append RS bit.? My master is always in read mode.
Will answer with an example - our firm uses an I2C based GPIO expander which has the Slave Address 0x20. StellarisWare function is coded as shown, below:
ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x20, false); // Config'd for write @ slave adr 0x20
Your MCU may not have the in-built ROM functions - in that case use I2CMaster...
What you call RS bit is R/W in I2C terminology - and is automatically placed for you by StellarisWare. (via last entry w/in function - false = write, true = read) Signal "RS" suggests that yours is an I2C-based Display - several of these have issues - suggest that you experiment & master I2C with the safer, more robust I2C EEprom. Keep in mind that I2C accommodates 7 bit addressing - thus the Msb should never be set when placed/coded w/in the I2C address field.
Curious if you reviewed earlier referenced I2C post - and if you found that useful? (it was generated to assist those with exact I2C issues you presented...)
Hello,
I went through your first post. It really helped me in setting up the pin configurations. Thanks a lot.
But I'm trying to use I2C0 in read mode. My EVALBOT need to read data. I have used the above said function with true to put my slave address on bus.
I have the following issues.
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); //Dummy 1 byte receive
while(!(I2CSlaveStatus(I2C0_SLAVE_BASE) & I2C_SLAVE_ACT_TREQ)) { }
ulDataRx = I2CMasterDataGet(I2C0_MASTER_BASE);
It is always stuck in the while loop.
I know I'm doing something fundamentally wrong somewhere. Please help me identify my mistake(s).
Please have a look into my code.
void main(void){ ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); //LEDS ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_4 | GPIO_PIN_5);
ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_PIN_4); SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); GPIOPinConfigure(GPIO_PB2_I2C0SCL); GPIOPinConfigure(GPIO_PB3_I2C0SDA); GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_OD); GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_OD); GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_DIR_MODE_HW); GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_DIR_MODE_HW);
I2CMasterEnable(I2C0_MASTER_BASE); I2CMasterInitExpClk(I2C0_MASTER_BASE,SysCtlClockGet(),true); //Initialises I2C Master //I2CSlaveInit(I2C0_SLAVE_BASE, 0x39); //Initialises I2C Slave //I2CSlaveEnable(I2C0_SLAVE_BASE); I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, 0x39,true);
int i; int controlWord; controlWord = I2C_MASTER_CMD_BURST_RECEIVE_START; int numberOfBytes = 16; char* data;
for(i = 0; i < numberOfBytes; i++) { // The second byte has to be receive with CONTINUE control word if(i == 1) controlWord = I2C_MASTER_CMD_BURST_RECEIVE_CONT; // The last byte has to be receive with FINISH control word if(i == numberOfBytes - 1) controlWord = I2C_MASTER_CMD_BURST_RECEIVE_FINISH; // If we have only one byte to receive, it is not BURST send but SINGLE if(numberOfBytes == 1) controlWord = I2C_MASTER_CMD_SINGLE_RECEIVE;
// Read a byte I2CMasterControl(I2C0_MASTER_BASE, controlWord); // Wait to finish reading DCLK_status= I2CMasterLineStateGet(I2C0_MASTER_BASE); //2 bit status of SDA and SCL while(I2CMasterBusy(I2C0_MASTER_BASE));
// Move byte from register data[i] = I2CMasterDataGet(I2C0_MASTER_BASE); }
}
My SDA and SCL is always 0, and Master I2c is always busy.
Pardonnez-moi - haven't time to go thru your code - maybe later upon landing. Instead - here is known good code which reads from a TI - I2C-based ADC - by comparing listings you can likely discover a "fix." Later - will try & review your code - as/if still required. Again - this code runs on Stellaris M4F "'talking" to mini TI I2C-based ADC.
*** Update: Unclear if you have - earlier - succeeded in generating an I2C Write (from Stellaris) to I2C Slave. Thought that the reference posts covered that aspect well - before delving into your failed receive - have you tested your I2C WRITES? As code below shows - any attempt @ I2C Read is doomed without earlier, successful I2C Writes.
*** Update 2: Like this aspect of your I2C code:
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);GPIOPinConfigure(GPIO_PB2_I2C0SCL);GPIOPinConfigure(GPIO_PB3_I2C0SDA);GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
but then - your next few lines (below) "undo" your nice I2C set-up: KILL these 4 lines (below):
GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_OD);GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_OD);GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_DIR_MODE_HW);GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_DIR_MODE_HW);
If interested - you can visit functions GPIOPinConfigure() and GPIOPinTypeI2C() and learn the detail of how they function - you "undo" much of their work with the code listed - urge you to kill.
You really need to first positively establish that you can Write via I2C - using the sample code/set-up from reference post. Please include your "Pass/Fail" I2C Write RESULTS before we continue with I2C Read... Even a basic scope can track/reveal SDA & SCL activity - do not forget pull-up Rs to 3V3. (3-10K usually fine)
Here - known good config: Stellaris M4F (yours may not require PinType listed - review datasheet)
i2c_setup: ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1); GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6); // *** Note special I2CSCL treatment for M4 ROM_GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7); ROM_GPIOPinConfigure(GPIO_PA6_I2C1SCL); ROM_GPIOPinConfigure(GPIO_PA7_I2C1SDA);
while(1) { ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x48, false); // Write 0x48 address Slave ADC ROM_I2CMasterDataPut(I2C1_MASTER_BASE, 0x8); // Rd CH3 Upper byte w/in ADC ROM_I2CMasterControl(I2C1_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND); // Delay until transmission completes while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {}
ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x48, true); // Read slave @ 0x48 ROM_I2CMasterControl(I2C1_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {}
ulADCup = ROM_I2CMasterDataGet(I2C1_MASTER_BASE); // upper byte recovered into var ulADCup ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x48, false); // Write ROM_I2CMasterDataPut(I2C1_MASTER_BASE, 0x09); // Rd CH3 Lower Byte ROM_I2CMasterControl(I2C1_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND); while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {}
ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x48, true); // Read ROM_I2CMasterControl(I2C1_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {}
ulADClo = ROM_I2CMasterDataGet(I2C1_MASTER_BASE); // lower byte recovered into var ulADClo ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x48, false); // Write ROM_I2CMasterDataPut(I2C1_MASTER_BASE, 0x01); // IntCtrl Reg ROM_I2CMasterControl(I2C1_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND); while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {} ROM_I2CMasterSlaveAddrSet(I2C1_MASTER_BASE, 0x48, true); // Read ROM_I2CMasterControl(I2C1_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {} ulINTCTRL = ROM_I2CMasterDataGet(I2C1_MASTER_BASE); ulADC_count ++; ROM_SysCtlDelay(9000000); }
Try this and report. (should this work - kindly report & let's "wrap" this forum thread (expanding beyond listed Subject) Also - like to know if use of color & bold assists your/others understanding and the "flow" of the post.
I have I2C working properly on the evalbot. The software was derived using the display driver as a starting point. The OLED is operating on I2C1. Look at display96x16x1.c in \StellarisWare\boards\ek-evalbot\drivers. It will show you how to initialize the I2C channel and send commands to the OLED. After that, the reading is easy.
Thanks a lot for your elaborate reply. The color scheme and bold does assist very much in understanding the flow.
PULL UP :
Please not that I2C0 in Evalbot is connected to audio module with pull up of 1K. Do you want me to add more resistance?
I tried writing to the slave. Was able to execute all statements in the CCS simulator. The ACK for data and address is 0(reset value), meaning acknowledged. The MCS register doesn't exhibit any changes for second write nor for any reads. Also the bit in MCS corresponding to generate start and stop is always at zero.
If i'm able to get a oscilloscope, I will share the observations.
I tried reading, but the value read is always zero which is wrong. Also, I need to read from a particular register in slave. How do it do that?
I2CMasterDataGet(I2C0_MASTER_BASE) : is this is the only way to read?
Thanks a lot for your time and effort. I really appreciate it.
Hello Greg,
I studied the display96x16x1.c and other I2C example code. I have attached my code, please have a look it it if you get time.
6708.i2c.c
The issue is that the value read is always zero. Any quick thought?
-Thanks
Not Greg but have "quick thought." To read a particular I2C Slave's specific register you must match the Slave's set-up/config (primarily register address) protocol. If I were you I'd temporarily use a very small EEprom (can just clip to your I2C bus - you will have to supply power) which greatly simplifies your read effort.
The I2CMasterDataGet() function usually is required to read from the slave (suggest you stay with this @ this stage)... Until it is confirmed that your I2C "Writes" are proper - your Reads may continue to frustrate. You may be able to find a free I2C data tester "on-line" - to confirm that your understanding & execution of I2C writes are correct.