help with i2c

I am having a problem getting i2c to work with XMMC. I am trying to read a DS3231 real time clock. The attached code works fine when compiled using LMM, however, it never returns from the i2cOpen call when compiled using XMMC.
The attached example uses pins 0 and 1 for the i2c bus. I get the same result if I move the DS3231 to pins 28 and 29 and use i2cBootOpen; it works fine using LMM, but never returns from the i2cBootOpen call using XMMC.
Any help would be greatly appreciated.
--markM
The attached example uses pins 0 and 1 for the i2c bus. I get the same result if I move the DS3231 to pins 28 and 29 and use i2cBootOpen; it works fine using LMM, but never returns from the i2cBootOpen call using XMMC.
Any help would be greatly appreciated.
--markM
#include <stdio.h>
#include <i2c.h>
/* DS3231 pin assignments */
#define _rtcDataPin 0
#define _rtcClockPin 1
/* i2c addresses */
#define DS3231_I2C_WRITE_ADDR 0xd0
#define DS3231_I2C_READ_ADDR 0xd1
/* DS3231 register offsets */
#define DS3231_SECONDS_REG 0
#define DS3231_MINUTES_REG 1
#define DS3231_HOURS_REG 2
#define DS3231_DATE_TIME_BYTE_COUNT 7 // Includes bytes 0-6
#define MAX_I2C_BUS 16
#define TRUE 1
char bcd2bin(char bcd_value)
{
char temp;
temp = bcd_value;
temp >>= 1;
temp &= 0x78;
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
void read_DS3231(I2C *bus)
{
int hour, minute, second, wday, mday, month, year;
uint8_t buffer[DS3231_DATE_TIME_BYTE_COUNT];
printf("data regesters selected\n");
/* read the data registers */
if (i2cRead(bus, DS3231_I2C_READ_ADDR, buffer, DS3231_DATE_TIME_BYTE_COUNT, TRUE) != 0)
printf("read failed\n");
else
{
printf("good read\n");
second = bcd2bin(buffer[DS3231_SECONDS_REG]);
minute = bcd2bin(buffer[DS3231_MINUTES_REG]);
hour = bcd2bin(buffer[DS3231_HOURS_REG]);
printf("\d:d:d\n", hour, minute,second);
}
return;
}
int main(void)
{
I2C *bus;
I2C_COGDRIVER dev;
/* open i2c bus */
bus = i2cOpen(&dev, _rtcClockPin,_rtcDataPin, 4000);
printf("i2cOpen returned x\n",bus);
/* select the DS3231 data registers */
if (i2cWrite(bus, DS3231_I2C_WRITE_ADDR, 0, 1, TRUE) != 0)
printf("Write failed\n");
else
read_DS3231(bus);
return 0;
}
Comments
If you paste <%02d> into the reply to thread box then switch to advanced mode it is changed to <d> that is why my printf(s) look weird.
--markM
There is some I2C discussion in the Learn forum http://forums.parallax.com/showthread.php/148348-Any-example-code-for-I2C
Should it work in xmm mode? Or, is there a known problem using it that way?
if (i2cWrite(bus, DS3231_I2C_WRITE_ADDR, 0, 1, TRUE) != 0) printf("Write failed\n"); else read_DS3231(bus);
This code passes zero as the third parameter to i2cWrite. That parameter is supposed to be a pointer to a buffer containing the data to write. That would be okay if the fourth parameter, number of bytes to write, was zero but in this case it is 1.Most likely we will end up with libsimplei2c and other drivers ....
There are some things that I would like to code with this instead of the Spin2Cpp version of my own driver...
BTW: Is there a list somewhere of all the different drivers that come with PropGCC.
I didn't know about i2c.h. I'd guess there's an spi.h around somewhere too, right?
No, there is no spi.h at the moment. Someone was working on a generic SPI driver but I don't think they ever checked it in and I don't recall who it was. Do you have a proposed API for SPI? It wouldn't be too hard to create a driver.
Regarding this code
​ if (i2cWrite(bus, DS3231_I2C_WRITE_ADDR, 0, 1, TRUE) != 0)
It is writing a 1 byte of zero. I copied it from someone else's code. It seems to work fine. However, from your comment I assume that it is bad technique. I'll change it.--markM
From C:\propgcc\propeller-elf\include\i2c.h ....
/** * @brief Write to an I2C device * * @details Write to an I2C device at the specified address. * The address should be the device address in bits 7:1 and * a zero in bit 0. If count is zero only the address byte * will be sent. Set the stop parameter to TRUE to cause an * I2C stop sequence to be emitted after the data. Setting it * to FALSE omits the stop sequence. * * @param dev I2C device to write to * @param address I2C address in bits 7:1, zero in bit 0 * @param buffer Address of the buffer containing data to write * @param count Number of bytes of data to write * @param stop TRUE to send a stop sequence after the data * * @returns 0 on success, -1 on failure. * */ static inline int i2cWrite(I2C *dev, int address, uint8_t *buffer, int count, int stop) { return (*dev->ops->write)(dev, address, buffer, count, stop); }
That tells you everything you need to know about how to use the function. To me, it is glorious!
Anyway, you found a real problem with i2cOpen that I am in the process of fixing. Thanks!!!!
Would it be possible to have cognew work in CMM/LMM and XMM?
My guess is that it would be possible to use compile time flags to select the appropriate cognew at compile time. In CMM/LMM the cognew would be the same as it is now. In XMM, it would check out a lock, copy the 2K bytes, use the CMM/LMM cognew, and then release the lock.
Anyway, that's just a suggestion. Otherwise, the onus is each and every developer to provide two methods of starting cog drivers, and that sounds like a hassle.
use_cog_driverx(id) load_cog_driverx(id, param)
The id is the name of the file containing the driver with ".c" for COG C drivers or ".spin" for PASM drivers replaced by "_cog". For example, the i2c driver is in the file "i2c_driver.c" and the id for it is "i2c_driver_cog". This id scheme is used because the linker produces symbols like "_load_start_i2c_driver_cog" and "_load_stop_i2c_driver_cog" to mark the start and end of the driver image in memory.A side effect of the change is that code that uses i2cBootOpen() gets the following error messages when attempting to compile. This code complies cleanly under the old version of propgcc. This is not a problem for me.
It seems like this is an issue David is working on. He's on vacation right now though.