Hi TI,
I am planning to use I2C in CC2530. I understand TI CC2530 dont have the I2c module hardware support.It only support TI CC2533.
So to use I2C in CC2530 ,
GPIO p1.3 and P1.4 pin for I2c master. P1.3 use as a clock (use timer 3 to generate pwm clock for 400khz) and P1.4 for SDA.
Kindly advice .whether i can use the above way to communicate with I2C Slave.if there is anyother way please advice.
Thanks and Regards
Lakshman.
Hi Lakshman,
You can implement the communication it the FW level, without using timers.
Syncronising timer output with data write (read) on P1.4 is a hard work and
involves constant polling of Timer3 overflow, or interrupt.
If you need a short access (write/read 10 bytes) to your slave, where this access period
can be done in a time of ~few dozens of uSeconds you can, and you should, implement
the I2C inside the code without using timers or interrupts.
Br,
Igor
Hi Igor,
Thanks for the immediate reply.
I didnt understand the solution. Can you please throw some light ?
How can i get the clock for I2C SCL ???
I need 400Khz clock whenever i need to send the data . kindly advice.
Hi,
Lets say that you toggling P1.3 (which is the SCL) in the following way (transaction of a single byte through I2C):
P1.3 = HIGH;tmpByte = dataFor_I2C_Slave[SomeIndex]; // Just for the example
for( int i=0; i<sizeof(byte)-1; i++ ) { P1.3 = P1.3 ^ 0x01; // Toggle P1.3 output blockingDelay(WRITE_DELAY); // Delay needed for Slave to detect rising/falling of SCL p1.4 = !(!(tmpByte & 0x80)); // Set P1.4 with current MSB in tmpByte tmpByte <<= 1; blockingDelay(CLOCK_DELAY); // Delay needed for generating a ~400KHz SCL}
Please note that it is not an accurate example of how to implement the IC2, the important
thing here is the blockingDelay() function, where in first call for this function used to provide
a delay for the slave to capture the falling or rising of the SCL. The second call for this function
intended for delaying the next setting of P1.3 output to create SCL timing of ~400KHz.
The blockingDelay() can be implemented in the following way:
void blockingDelay( uint16 delay ){ while( delay ) { delay--; asm("NOP"); // Here "NOP" is a single system clock instruction (in case // of cc2530 1 system clock = ~31.5nSeconds }}
Thanks for your reply. I got it. So i simulate 400khz by means of delay.
This is what i need. thank you so much.
Just keep in mind that long blocking delays can harm Z-stack normal behavior.
There are i2c hal drivers (hal_i2c.c, hal_i2c.h) available in RemoTi Stack for cc2530.
I use them with Z-Stack to read data from different sensors without problems.
Hi Felix,
It is a nice thing to know, thank you very much for the information.
Hi Felix:
How could I get the REmoTi Stack for cc2530. I found it on TI's website but it need to request.could you send me one .linux_makefile@qq.com
thanks and best regards.
huabai
huabai shen Hi Felix: How could I get the REmoTi Stack for cc2530. I found it on TI's website but it need to request.could you send me one .linux_makefile@qq.com thanks and best regards. huabai
I attach the original files to this post.
Felix
I made modifications to the hal_i2c.c in order to read and write to the TI PCA9555 I2C 16 bit Port expander using theCC2540.
This allows me to read and write to just about any I2C device. This is for the CC25xx that do not have i2c in hardware.
To read I use this function:
if ( I2C_ReadMultByte(PCA9555_ADDR_WR, InPort0, data1, 2 ) )...
To write:
I2C_WriteMultByte(PCA9555_ADDR_WR, PolInvP0, data1, 2);
The function I wrote for reading is:
/********************************************************************* * @fn I2C_ReadMultByte * @brief reads data into a buffer * @param address: linear address on part from which to read * @param reg: internal register address on part read from * @param buffer: target array for read characters * @param len: max number of bytes to read * @return void */uint8 I2C_ReadMultByte( uint8 address, uint8 reg, uint8 *buffer, uint16 len ){ uint16 i = 0; uint8 I2C_ERROR = 0; uint8 I2C_SUCCESS = 1; if (!len) { return(0); } /* Send START condition */ if( hali2cStart()) return I2C_ERROR; /* Set direction of transmission */ // Reset the address bit0 for write address &= OCM_WRITE; /* Send Address and get acknowledgement from slave*/ if ( !hali2cSendByte(address)) return I2C_ERROR; /* Send internal register to read from to */ if ( !hali2cSendByte(reg)) return I2C_ERROR; /* Send RESTART condition */ if( hali2cStart()) return I2C_ERROR; /* Set direction of transmission */ // Reset the address bit0 for read address |= OCM_READ; /* Send Address and get acknowledgement from slave*/ if ( !hali2cSendByte(address)) return I2C_ERROR; /* Read data into buffer */ // read bytes of data into buffer while ( len ) { // SCL may be high. set SCL low. If SDA goes high when input // mode is set the slave won't see a STOP hali2cClock(0); OCM_DATA_HIGH(); buffer[i] = hali2cReceiveByte(); // Acknowledgement if not sending last byte if (len > 1) hali2cWrite(SMB_ACK); // write leaves SCL high // increment buffer register i++; // Decrement the read bytes counter len--; } // condition SDA one more time... hali2cClock(0); OCM_DATA_HIGH(); hali2cWrite(SMB_NAK); hali2cStop(); return I2C_SUCCESS;}
For writing:
/********************************************************************* * @fn I2C_WriteMultByte * @brief reads data into a buffer * @param address: linear address on part from which to read * @param reg: internal register address on part read from * @param buffer: target array for read characters * @param len: max number of bytes to read * @return void */uint8 I2C_WriteMultByte( uint8 address, uint8 reg, uint8 *buffer, uint16 len ){ uint16 i = 0; uint8 I2C_ERROR = 0; uint8 I2C_SUCCESS = 1; if (!len) { return(0); } /* Send START condition */ if( hali2cStart()) return I2C_ERROR; /* Set direction of transmission */ // Reset the address bit0 for write address &= OCM_WRITE; /* Send Address and get acknowledgement from slave*/ if ( !hali2cSendByte(address)) return I2C_ERROR; /* Send internal register to read from to */ if ( !hali2cSendByte(reg)) return I2C_ERROR; /* Write data into register */ // read bytes of data into buffer while ( len ) { // SCL may be high. set SCL low. If SDA goes high when input // mode is set the slave won't see a STOP hali2cClock(0); OCM_DATA_HIGH(); /* Send Address and get acknowledgement from slave*/ if ( !hali2cSendByte(buffer[i])) return I2C_ERROR; // increment buffer register i++; // Decrement the read bytes counter len--; } hali2cStop(); return I2C_SUCCESS;}
Hi greenja,
Thank you for sharing your code.
I am trying to interface a magnetometer to the CC2540 via I2C but I am not able to get the ACK from the magnetometer.
I am using the hal_i2c.c from RemoTI and NOPs to generate some delays to get a frequency below 100 kHz from the 32MHz system clock but still not working... =(
I am able to see in the oscilloscope that the master is sending the slave address correctly and the frequency of the clock is around 10kHz. The problem is that I am never getting the ACK back from the slave.
I use the hal_i2c.c implementation with the HAL_I2C_RETRY_CNT to retry 3 times to send the address . I can see all the retries on the oscilloscope and the sequence is like this:
slave address - start condition -slave address -start condition -slave address ...
Is there any additional delay or clock cycle that has to be added after the slave address is sent to give some time for the ACK?
Any help would be greatly appreciated!!!
Hello Flor,
What mangnetometer are you using? I did have some code for the LSM303DL somewhere but I can't remember the specifics on how I got it to work.
Here are the files that I am currently using to interface the CC2540 to the PCA9555 I/O expander for running a LCD and 7Seg displays.
There are slight variations to the Hal_i2c.zip that was originally posted, can't remember exactly what I changed, so I just included the whole file. I don't think the clock rate section really works. I think I scoped all the values and there was no change in clock speed.
4265.Hal_i2c-1.zip
Thank you very much!! I will give it a try. The magnetometer I am using is the LSM303DLH.
I just llooked over the code. You obviously have to change the OCM_CLK_PORT, data port and pins to match what you are using. I think the main problem was with theses three lines:
hali2cReceive