I am a lowly programming intern at a company manufacturing (among other things) small computers for embedded integration. I have been handed a handful of Digilent PMOD devices that looked interesting for the company to write drivers for. So far, it has been a valuable (and quite fun) experience, but I've hit a wall with the Pmod PMON1. My experience is in mechanics and pure programming and my electrical knowledge is limited. An electrical engineer helped me set up a monitored device with controlable load, and I know Digilent's approach to the I²C protocol from the Pmod HYGRO. Now, following the same protocol and what I understand from the documentation, I have written the code below. I would assume to get two different values from the digilent_pmodpmon1_get_resistance() calls to reflect the changed load, but I just get the same data twice: 32, 10.
What am I misunderstanding?
Spoiler
int main ( int argc, char *argv[] ) {
i2c_setup(); // same method I used for the HYGRO, so this should work
set_i2c_register(i2cAddress, noOp); // Awaken the device
digilent_pmodpmon1_zero_wiper(); // I assume that I now am zeroing the internal potentiometer so I have a reference point
digilent_pmodpmon1_get_resistance(); // I assume that I am here getting the value of the internal potentiometer (might be zero or whatever the monitored device has changed it to)
printf("change current now\n" );
sleep(2); // At this point, I manually change the load of the monitored device while the program sleeps
digilent_pmodpmon1_get_resistance(); // Again, I assume that I am getting the value of the potentiometer. This should now be different since the load has changed
i2cClose();
return 1; }
/* --- CONSTANTS --- */ // Addresses taken from the Analog documentation
/** @brief Address of the I2C device. */
const int i2cAddress = 0x2F; // I assume that this is the main address, since it only appeared on my i2cdetect after plugging in the monitored device
const int i2cReadAddress = 0x30; // the address after the assumed main address. Also appeared after plugging in the monitored device, so I assume that one of the two will contain the readback data
/** @brief No operation */
const int noOp = 0x0;
/** @brief register for zeroing the wiper */
const int zeroWiperReg = 0x02;
/** @brief Read contents of RDAC register */
const int readRdac = 0x05;
/** *@brief The board has 2 I2C ports: i2c-0 is PMOD A, i2c-1 is PMOD B. */
const char deviceLocation[11] = "/dev/i2c-0";
/* --- VARIABLES --- */
/** @brief I2C device handle. */
static int i2cFileDescriptor;
/* --- METHODS --- */
/** @brief Opens the Linux device.
* @details Wakes the device by writing a 0 to it.
* @return i2cFileDescriptor on success, exits program on failure. */ int i2c_setup() {
i2cFileDescriptor = open(deviceLocation, O_RDWR);
usleep(20000); // Give the sensors time to wake up
if ( i2cFileDescriptor < 0)
{
exit(1);
}
if (ioctl( i2cFileDescriptor, I2C_SLAVE_FORCE, i2cAddress) < 0)
{
printf("Failed to acquire bus access and/or talk to slave.\n");
//ERROR HANDLING; you can check errno to see what went wrong
}
usleep(20000);
return i2cFileDescriptor; }
/** @brief Sets the value of a register on the Pmod PMON1 device.
* @details Used for the setup methods.
* @return 1 on error, 0 on success.
* @param reg The register thas will be written to.
* @param value The value to write. */ int set_i2c_register(unsigned char reg, unsigned char value) {
unsigned char outbuf[2];
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[1];
// The first byte indicates which register we'll write to.
outbuf[0] = reg;
// The second byte indicates the value to write.
outbuf[1] = value;
// Transfer the i2c packets to the kernel and verify it worked.
packets.msgs = messages;
packets.nmsgs = 1;
if(ioctl( i2cFileDescriptor, I2C_RDWR, &packets) < 0) {
perror("Set: Unable to send data");
return 1;
}
return 0; }
/** @brief Closes the Linux device.
* @return Void. */ void i2cClose() {
close( i2cFileDescriptor); }
/** @brief Write the RDAC Register and Place the Wiper at Zero Scale
* @details
* @return */ void digilent_pmodpmon1_zero_wiper() {
int length;
unsigned char buffer[2];
//----- WRITE BYTES -----
buffer[0] = zeroWiperReg;
length = 1; // Number of bytes to write
if (write(i2cFileDescriptor, buffer, length) != length) //write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
{
/* ERROR HANDLING: i2c transaction failed */
printf("Failed to write to the i2c bus.\n");
exit(1);
}
usleep(20000); //give the device time to answer. }
/** @brief Gets the resistance on the connected device.
* @details Reading from the device requires first writing dummy data to the relevant register, then waiting, and then reading from the same register.
* @return
*/ int digilent_pmodpmon1_get_resistance()
{
int length;
unsigned char buffer[2];
//----- WRITE BYTES -----
buffer[0] = readRdac;
length = 1; // Number of bytes to write
if (write(i2cFileDescriptor, buffer, length) != length) //write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
{
// ERROR HANDLING: i2c transaction failed
printf("Failed to write to the i2c bus.\n");
exit(1);
}
usleep(20000); //give the device time to answer.
//----- READ BYTES -----
length = 2; // Number of bytes to read
if (read(i2cFileDescriptor, buffer, length) != length) //read() returns the number of bytes actually read, if it doesn't match then an error occurred (e.g. no response from the device)
{
//ERROR HANDLING: i2c transaction failed
printf("Failed to read from the i2c bus.\n");
exit(1);
}
printf("%i, %i\n", buffer[0], buffer[1]);
Question
Tore Sæderup
Greetings
I am a lowly programming intern at a company manufacturing (among other things) small computers for embedded integration. I have been handed a handful of Digilent PMOD devices that looked interesting for the company to write drivers for. So far, it has been a valuable (and quite fun) experience, but I've hit a wall with the Pmod PMON1. My experience is in mechanics and pure programming and my electrical knowledge is limited. An electrical engineer helped me set up a monitored device with controlable load, and I know Digilent's approach to the I²C protocol from the Pmod HYGRO. Now, following the same protocol and what I understand from the documentation, I have written the code below. I would assume to get two different values from the digilent_pmodpmon1_get_resistance() calls to reflect the changed load, but I just get the same data twice: 32, 10.
What am I misunderstanding?
int main ( int argc, char *argv[] )
{
i2c_setup(); // same method I used for the HYGRO, so this should work
set_i2c_register(i2cAddress, noOp); // Awaken the device
digilent_pmodpmon1_zero_wiper(); // I assume that I now am zeroing the internal potentiometer so I have a reference point
digilent_pmodpmon1_get_resistance(); // I assume that I am here getting the value of the internal potentiometer (might be zero or whatever the monitored device has changed it to)
printf("change current now\n" );
sleep(2); // At this point, I manually change the load of the monitored device while the program sleeps
digilent_pmodpmon1_get_resistance(); // Again, I assume that I am getting the value of the potentiometer. This should now be different since the load has changed
i2cClose();
return 1;
}
/* --- CONSTANTS --- */ // Addresses taken from the Analog documentation
/** @brief Address of the I2C device. */
const int i2cAddress = 0x2F; // I assume that this is the main address, since it only appeared on my i2cdetect after plugging in the monitored device
const int i2cReadAddress = 0x30; // the address after the assumed main address. Also appeared after plugging in the monitored device, so I assume that one of the two will contain the readback data
/** @brief No operation */
const int noOp = 0x0;
/** @brief register for zeroing the wiper */
const int zeroWiperReg = 0x02;
/** @brief Read contents of RDAC register */
const int readRdac = 0x05;
/** *@brief The board has 2 I2C ports: i2c-0 is PMOD A, i2c-1 is PMOD B. */
const char deviceLocation[11] = "/dev/i2c-0";
/* --- VARIABLES --- */
/** @brief I2C device handle. */
static int i2cFileDescriptor;
/* --- METHODS --- */
/** @brief Opens the Linux device.
* @details Wakes the device by writing a 0 to it.
* @return i2cFileDescriptor on success, exits program on failure. */
int i2c_setup()
{
i2cFileDescriptor = open(deviceLocation, O_RDWR);
usleep(20000); // Give the sensors time to wake up
if ( i2cFileDescriptor < 0)
{
exit(1);
}
if (ioctl( i2cFileDescriptor, I2C_SLAVE_FORCE, i2cAddress) < 0)
{
printf("Failed to acquire bus access and/or talk to slave.\n");
//ERROR HANDLING; you can check errno to see what went wrong
}
usleep(20000);
return i2cFileDescriptor;
}
/** @brief Sets the value of a register on the Pmod PMON1 device.
* @details Used for the setup methods.
* @return 1 on error, 0 on success.
* @param reg The register thas will be written to.
* @param value The value to write. */
int set_i2c_register(unsigned char reg, unsigned char value)
{
unsigned char outbuf[2];
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[1];
messages[0].addr = i2cAddress;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = outbuf;
// The first byte indicates which register we'll write to.
outbuf[0] = reg;
// The second byte indicates the value to write.
outbuf[1] = value;
// Transfer the i2c packets to the kernel and verify it worked.
packets.msgs = messages;
packets.nmsgs = 1;
if(ioctl( i2cFileDescriptor, I2C_RDWR, &packets) < 0) {
perror("Set: Unable to send data");
return 1;
}
return 0;
}
/** @brief Closes the Linux device.
* @return Void. */
void i2cClose()
{
close( i2cFileDescriptor);
}
/** @brief Write the RDAC Register and Place the Wiper at Zero Scale
* @details
* @return */
void digilent_pmodpmon1_zero_wiper()
{
int length;
unsigned char buffer[2];
//----- WRITE BYTES -----
buffer[0] = zeroWiperReg;
length = 1; // Number of bytes to write
if (write(i2cFileDescriptor, buffer, length) != length) //write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
{
/* ERROR HANDLING: i2c transaction failed */
printf("Failed to write to the i2c bus.\n");
exit(1);
}
usleep(20000); //give the device time to answer.
}
/** @brief Gets the resistance on the connected device.
* @details Reading from the device requires first writing dummy data to the relevant register, then waiting, and then reading from the same register.
* @return
*/
int digilent_pmodpmon1_get_resistance()
{
int length;
unsigned char buffer[2];
//----- WRITE BYTES -----
buffer[0] = readRdac;
length = 1; // Number of bytes to write
if (write(i2cFileDescriptor, buffer, length) != length) //write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
{
// ERROR HANDLING: i2c transaction failed
printf("Failed to write to the i2c bus.\n");
exit(1);
}
usleep(20000); //give the device time to answer.
//----- READ BYTES -----
length = 2; // Number of bytes to read
if (read(i2cFileDescriptor, buffer, length) != length) //read() returns the number of bytes actually read, if it doesn't match then an error occurred (e.g. no response from the device)
{
//ERROR HANDLING: i2c transaction failed
printf("Failed to read from the i2c bus.\n");
exit(1);
}
printf("%i, %i\n", buffer[0], buffer[1]);
return buffer[0];
}
Link to comment
Share on other sites
4 answers to this question
Recommended Posts
Archived
This topic is now archived and is closed to further replies.