I'm configuring a ICM20948 breakout from primo roni via i2c on a Beagle Bone black, using a minimal linux build using buildroot, via a C program. To do so, i've used this driver for the i2c connection and also this ICM20948 driver as base for the speciffic device, so the target is to merge both.
I've been able to configure some registers (like the sleepmode o lowpowermode) but when setting the fullscale, the values seems not to be changing.
This is more or less the function that pressents the problem
uint16_t set_values(uint16_t register, uint16_t value)
{
unsigned char rxBuffer[1]; // receive buffer
unsigned char txBuffer[2]; // transmit buffer
retval |= ICM_20948_set_bank(2); // Must be in the right bank
txBuffer[0] = register;
retval |= write(device.i2cHandle,txBuffer,1); // device.i2cHandle is the handler obtained when
retval |= read(device.i2cHandle,rxBuffer,1); // opening the /dev/i2c-X
printf("Readed value %x: %x\n",txBuffer[0],rxBuffer[0]);
txBuffer[1] = value;
printf("Intending to write: %x\n", txBuffer[1]);
retval |= write(device.i2cHandle, txBuffer, sizeof(txBuffer));
write(device.i2cHandle,txBuffer,1);
read(device.i2cHandle,rxBuffer,1);
printf("Written value on register %x: %x\n",txBuffer[0],rxBuffer[0]);
}
But the output when doing trying to modify the 0x14 register with the value 0x03 returns what follows:
Readed value 14: 1
Intending to write: 3
Written value on register 14: 1
Any suggestion? Thanks in advance!
Related
I am trying to Interface Poly Phase Energy Mertering IC ADE7758 Using STM32F411VET6. My SPI is working on a prescale of 16, Baud of 6.25 MB/s and MODE 2 i.e CPOL = 1 and CPHA = 0. Here is the snapshot of settings.
My connections are like this.
STM32 - ADE7758
PE11(NSS) - Pin 21(CS)
PE12(SCK) - Pin 23(SCLK)
PE13(MISO) - Pin 24(DOUT)
PE14(MOSI) - Pin 23(DIN)
Here is the global variables and defines
uint8_t aTxBuff[1] = {0};
uint8_t aRxBuff[1] = {0};
#define enableChip HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port,SPI1_NSS_Pin,GPIO_PIN_RESET)
#define disableChip HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port,SPI1_NSS_Pin,GPIO_PIN_SET)
I am trying to read OPMODE(0x13) register.
First i am writing the OPMODE register with a default value of 0x04.
Here is a snapshot of waveform.
My register address is 0x13 and i am writing so i have to logically 'OR' 0x13 with 0x80 i.e My waveform should be 0x93
The Default value on OPMODE register is 0x04
Here is the code i used for writing to ADE7758.
void ADE7758_write8(char reg, unsigned char data)
{
enableChip;
reg|=0x80;
aTxBuff[0] = (unsigned char)reg;
while(HAL_SPI_GetState(&hspi4) == HAL_SPI_STATE_BUSY_TX);
HAL_SPI_Transmit(&hspi4, (uint8_t*)aTxBuff, 1, 1000);
while(HAL_SPI_GetState(&hspi4) == HAL_SPI_STATE_BUSY_TX);
aTxBuff[0] = (unsigned char)data;
HAL_SPI_Transmit(&hspi4, (uint8_t*)aTxBuff, 1, 1000);
disableChip;
}
While writing using SPI to ADE7758 everything shows correct. But the problem occurs when i read back the register.
Here is the code for reading the SPI.
unsigned char ADE7758_read8(char reg)
{
enableChip;
aTxBuff[0] = (unsigned char)reg;
HAL_SPI_TransmitReceive(&hspi4, (uint8_t*)aTxBuff, (uint8_t*)aRxBuff, 1, 1000);
DWT_Delay_us(5);
aTxBuff[0] = 0x00;
HAL_SPI_TransmitReceive(&hspi4, (uint8_t*)aTxBuff, (uint8_t*)aRxBuff, 1, 1000);
disableChip;
return (unsigned char)aRxBuff[0];
}
I have tried to debug the code and constantly monitored value aRxBuff[0] and the value is arbitary( like 0xFF,0xFC,0xDF etc ).
I don't know weather its the fault of reading times but here is the snapshot of Timing Characteristics of ADE7758
Please suggest where am i going wrong while reading SPI from ADE7758? Is it the fault of the way i am reading SPI using HAL or its the fault of timing?
Any suggestions will be appreciated.
I'm a beginner in this field. My goal is to change the output of 8 LEDs (which are connected to PORTA) according to the potentiometer. I have connected the middle line of the potentiometer to PF0, which is ADC0. I also connected the other two lines to the 5V and ground.
I know there's no problem with the chip or connection because the LEDs are working just fine.
But no matter how I change the code below (what I mean by changing is by slightly changing the ADMUX and ADCSRA registers) no output is shown!
I am using atmega128 with 16MHZ clock. Below is the code that I'm trying to solve.
#include <asf.h>
#include <avr/io.h>
#define F_CPU 16000000L
int init_board(void)
{
DDRA=0xff;
PORTA=0x01;
}
int ADC_init(void)
{
//ADCSRA
ADCSRA = 0b10000111;
//ADMUX
ADMUX = 0b01100000; // middle line connected to ADC0
}
int main (void)
{
init_board();
ADC_init();
ADCSRA |= (ADSC >> 1);
while(1)
{
if(ADSC == 0)
{
uint8_t disp_value = ADCL;
PORTA = disp_value;
delay_ms(200);
ADCSRA |= (ADSC >> 1);
}
}
}
I have no idea why the code doesn't work.
I suppose it's because it didn't set my register correctly, but I've followed all the instructions on the atmega128 datasheet.
First issue is your bit shifting, it should be ADCSRA |= (1 << ADSC).
Next issue is results reading. You set fifth bit of ADMUX to 1, so ADLAR=1 and in that mode result is left adjusted so you should read ADCH.
Moreover when you switch to 10-bit resolution, i.e. you start working with multi-byte results, be aware that reading only ADCL is not enough, see datasheet 23.3 for explanation: "Once ADCL is read, ADC access to data registers is blocked. This means that if ADCL has been read, and a conversion completes before ADCH is read, neither register is updated and the result from the conversion is lost. When ADCH is read, ADC access to the ADCH and ADCL Registers is re-enabled."
Lastly, using hardcoded delays for reading is not good practice especially when you change code later to read ADC as fast as possible. In such case after conversion start you should check if ADIF flag is set or react with interrup when ADEN is set. Refer to datasheet for details.
I am trying to test the i2c communication of the MAX77651 chip before programming it.
So here is my setup to do so:
I have an UMFT4222ev connected to my Linux laptop by USB. This chip has his SCL and SDA linked to the SDA and SCL of my MAX77651 thanks to the Evaluation Kit for the MAX77651. My MAX77651evkit is powered with 3,7V on the Vbatt pin.
I also installed the mraa librarie from git hub and the libft4222. I know mraa is well installed because i tried it with and example.
I was told that the mraa library takes in charge the setup of the FT4222 so i only used mraa functions to make my program.
I searched on the website of Maxim integrated the i2c slave address and one register where i could read data and check if everyting is working. I then read the i2c protocol of communication to read a single register which is available here : https://datasheets.maximintegrated.com/en/ds/MAX77650-MAX77651.pdf at the page 78.
With all those informations I tried to make my "test program". I solved the compiling errors but when I execute the program I can't get what is in the register which should be 0xFF.
Here is my program:
#include "stdio.h"
#include "syslog.h"
#include "string.h"
#include "unistd.h"
#include "mraa/i2c.h"
#include "mraa.h"
#define I2C_ADDR 0x48
int
main(int argc, char *argv[])
{
uint8_t *message;
*message=0XAC;
int i,j,k;
char reg_a_lire = 0x06;
mraa_init();
mraa_i2c_context i2c;
i2c = mraa_i2c_init(0);
mraa_i2c_frequency(i2c,MRAA_I2C_FAST);
mraa_i2c_address(i2c, I2C_ADDR);
mraa_i2c_write_byte(i2c,0x90);
mraa_i2c_read(i2c, message,1);
mraa_i2c_write_byte(i2c,reg_a_lire);
mraa_init();
mraa_i2c_write_byte(i2c,0x91);
mraa_i2c_read(i2c, message,1);
mraa_i2c_read(i2c, message,1);
printf("%02X \n", *message);
mraa_i2c_stop(i2c);
return 0;
}
Here is the actual output :
alex#cyclonit-laptop ~/Test_alex/tests $ ./a.out
AC
And i would like to get FF instead of AC.
I think my error could come from something i missed to initialize the FT4222 or from the MAX77651 which I maybe did nt power up correctly and its not sufficient to put 3,7V on Vbatt. But maybe this is a problem with my program because i don't know much about uint8_t and I made something wrong.
I am hoping someone has experience with FT4222 and/or MAX77651 and can help me.
I think you are confused by pg. 75 of the MAX77651 datasheet.
ADDRESS | 7-BIT SLAVE ADDRESS | 8-BIT WRITE ADDRESS | 8-BIT READ ADDRESS
Main Address | 0x48, 0b 100 1000 | 0x90, 0b 1001 0000 | 0x91, 0b 1001 0001
(ADDR = 1)* | | |
-------------+---------------------+---------------------+-------------------
Main Address | 0x40, 0b 100 0000 | 0x80, 0b 1000 0000 | 0x81, 0b 1000 0001
(ADDR = 0)* | | |
Depending on your view of the I²C specification, you either use the 7-bit address or use both 8-bit addresses. The reason is that the first I²C transaction sends the following 8 bit:
76543210
\_____/\-- R/#W
\------ 7-bit Slave Address
In your case that's 0x48 shifted one bit to the left followed by either a 1 for read mode or a 0 for write mode. Notice that
(0x40 << 1) | 0x00 == 0x80 == 8-bit Write Address (ADDR = 0)
(0x40 << 1) | 0x01 == 0x81 == 8-bit Read Address (ADDR = 0)
(0x48 << 1) | 0x00 == 0x90 == 8-bit Write Address (ADDR = 1)
(0x48 << 1) | 0x01 == 0x91 == 8-bit Read Address (ADDR = 1)
Some people like to use the slave address while other people prefer to give separate addresses so it's clear what the first byte of communication will look like.
So you should remove the extraneous mraa_i2c_write_byte(i2c, ...); lines from your code, as their intention seems to be to send the read or write address to the slave.
Check out the MRAA library API reference. There are functions that abstract reading and writing registers, either byte-wide [8-bit] registers or word-wide [16-bit] registers:
mraa_i2c_read_byte_data
mraa_i2c_read_bytes_data
mraa_i2c_write_byte_data
In both cases you should check the return codes to know if the action succeeded. In your case, your message is likely not altered, because there was a stop/error condition beforehand, because the slave did either not ACK its slave address or it did not ACK the 0x90/0x91 data bytes you mistakenly sent, as they don't show up in the Programmer's Guide as valid addresses.
Another issue is that you try to read register INTM_GLBL (0x06; Global Interrupt Mask Register) using two consecutive read operations. I'm not sure if your intention is to read register 0x06 twice or if you intended to read INT_M_CHG (0x07; Global Interrupt Mask for Charger), because that's not what it will do. Notice the description on pg. 78 of the datasheet:
Note that when the MAX77650/MAX77651 receive a stop
they do not modify their register pointer.
This is typical behavior for I²C slaves that support multi-byte/sequential reads. You will have to issue a sequential read operation for multiple bytes of data if you want to read multiple registers, e.g. using mraa_i2c_read_bytes_data.
Something like the following might get you on the right track. It is supposed to read the CID and CLKS settings and wait forever if a read error occurred. If successful, it will disable charging, all outputs, setup the red LED to blink once every other second and -- as soon as you uncomment it -- transition the On/Off Controller into On Via Software state to enable bias and the LED.
#define MAX77651_SLA 0x48u
#define CNFG_GLBL_REG 0x10u
#define CID_REG 0x11u
#define CNFG_CHG_B_REG 0x19u
#define CNFG_SBB0_B_REG 0x2Au
#define CNFG_SBB1_B_REG 0x2Cu
#define CNFG_SBB2_B_REG 0x2Eu
#define CNFG_LDO_B_REG 0x39u
#define CNFG_LED1_A_REG 0x41u
#define CNFG_LED1_B_REG 0x44u
#define CNFG_LED_TOP_REG 0x46u
int main(int argc, char *argv[]) {
uint8_t data;
int res;
mraa_init();
mraa_i2c_context i2c0;
i2c0 = mraa_i2c_init(0);
mraa_i2c_frequency(i2c0, MRAA_I2C_STD);
mraa_i2c_address(i2c0, MAX77651_SLA);
res = mraa_i2c_read_byte_data(i2c0, CID_REG);
if (res < 0) {
printf("Reading CID_REG failed.\n");
mraa_i2c_stop(i2c0);
while(1);
}
data = res;
printf("CID_REG: CLKS = %02X CID = %02X\n", ((data & 0x70u) >> 4), (data & 0x0Fu));
/* you should check return values here */
mraa_i2c_write_byte_data(i2c0, 0x00u /* CHG_EN = off */, CNFG_CHG_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_LDO = off */, CNFG_LDO_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_SBB0 = off */, CNFG_SBB0_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_SBB1 = off */, CNFG_SBB1_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x04u /* EN_SBB2 = off */, CNFG_SBB2_B_REG);
/* set up red led to toggle every second */
mraa_i2c_write_byte_data(i2c0, 0x17u /* P = 1s, D = 50% */, CNFG_LED1_B_REG);
mraa_i2c_write_byte_data(i2c0, 0x98u /* FS = 6.4mA, BRT = 5.0mA */, CNFG_LED1_A_REG);
mraa_i2c_write_byte_data(i2c0, 0x01u /* EN_LED_MSTR = on */, CNFG_LED_TOP_REG);
// DANGER ZONE: enable only when you know what this is supposed to do
//mraa_i2c_write_byte_data(i2c0, 0x10u /* SBIA_EN = on, SBIA_LPM = normal */, CNFG_GLBL_REG);
mraa_i2c_stop(i2c0);
while(1);
}
I managed to read I2C registers of MAX77651.
First looking at the hardware part I had to make sure that VIO had the right voltage like #FRob said in hid comment.
Then for the software, I stopped using the mraa library because i could'nt control everything. I used the FT4222 library which allowed me to open and initiate the FT4222 device. I took some part of the I2C example in this library for the initialization of the device. Then I noticed that I had to first use the FT4222's write function to send the register i wanted to read , then simply use the read function to get my result. Those are the two steps required.
I won't post the whole program i made as it is mainly taken from the I2C example for initialization but here is the part I added to read my register 0X06 which is supposed to contain 0xFF:
uint8 resultat=0x11;
uint8 *p_resultat=&resultat;
int chiffre;
slaveAddr
uint16 bytesToWrite2 = 1;
uint16 bytesWritten2=1;
uint8 valeur= 0x06; // REGISTER TO READ
uint8 *p_valeur=&valeur;
FT4222_I2CMaster_Write(ftHandle,slaveAddr,
p_valeur,bytesToWrite2,&bytesWritten); //INDICATES WHICH REGISTER TO
// READ
chiffre = FT4222_I2CMaster_Read(ftHandle,
slaveAddr,p_resultat,1, &bytesRead); // READ REGISTER
printf("The content of the register %02X is : %02X \n " ,
valeur,resultat); // DISPLAY RESULT
printf("reading success if : %d = 0 \n " , chiffre);
// READING SUCCESS ?
With this code and the initialization i get the following result :
alex#cyclonit-laptop ~/Downloads/libft4222-1.2.1.4/examples $ ./a.out
Device 0 is interface A of mode-0 FT4222H:
0x0403601c FT4222 A
Chip version: 42220200, LibFT4222 version: 01020104
The content of the register 06 is : FF
reading success if : 0 = 0
Skipping interface B of mode-0 FT4222H.
If someone has the same problem you are free to ask me your question by answering this post.I am very thankful to the people here who helped me!
How do I change slave address of mlx90614 with bcm2835 library? I've tried following code...
int main()
{
// Buffer, where I store data which I'll send
unsigned char buf[6];
// bcm2835 i2c module intialisation code
bcm2835_init();
bcm2835_i2c_begin();
bcm2835_i2c_set_baudrate(25000);
bcm2835_i2c_setSlaveAddress(0x00);
// For debug purposes, I read what reason codes operations give.
bcm2835I2CReasonCodes why;
bcm2835_i2c_begin();
// function which reads and prints what value eeprom address 0x0e has.
// See below the main.
printf("Initial check\n");
check(); // this time it prints a factory default value 0x5a.
// To access eeprom, the command must start with 0x2X, where x determines the
// address, resulting 0x2e.
buf[0] = 0x2e;
// According to datasheet, I first have to clear the address before
// real write operation.
buf[1] = 0x00;
buf[2] = 0x00;
why = bcm2835_i2c_write(buf,3);
reason(why); // resolves and prints the reason code. This time it prints OK
// according to datasheet, eeprom needs 5ms to make a write operation,
// but I give it 2 seconds.
sleep(2);
// Then I check did the value in eeprom 0x0e change. IT DOESN'T!
printf("Check after clear\n");
check();
// Then I try to write a new address to the eeprom but since the clearing
// the register didn't work, this is very unlikely to work either.
buf[0] = 0x2e;
buf[1] = 0x4b;
buf[2] = 0x00;
why = bcm2835_i2c_write(buf,3);
reason(why);
sleep(2);
// The datasheet says that I have to reset the power supply and after that
// the device should respond to the new slave address.
// I do that by pluging off the jumper wires and reconnecting them
// after the program has finnished.
bcm2835_i2c_end();
return 0;
}
// The function I use to determine what the reason code was.
void reason(bcm2835I2CReasonCodes why)
{
printf("Reason is: ");
if(why == BCM2835_I2C_REASON_OK)
{
printf("OK");
}else if(why == BCM2835_I2C_REASON_ERROR_NACK){
printf("NACK");
}else if(why == BCM2835_I2C_REASON_ERROR_CLKT){
printf("Clock stretch");
}else if(why == BCM2835_I2C_REASON_ERROR_DATA ){
printf("Data error");
}else{
printf("Dunno lol");
}
printf("\n");
return;
}
// Here I read eeprom 0x2e.
void check()
{
unsigned char buf[6];
unsigned char reg = 0x2e;
bcm2835I2CReasonCodes why;
// better safe than sorry with the buffer :)
buf[0] = 0;
buf[1] = 0;
buf[2] = 0;
why = bcm2835_i2c_write (®, 1);
reason(why);
why = bcm2835_i2c_read_register_rs(®,&buf[0],3);
reason(why);
printf("Buffer values are: %x ; %x ; %x \n", buf[0], buf[1], buf[2]);
}
The output of the program is following:
Initial check
Reason is: OK
Reason is: OK
Buffer values are: 5a ; be ; dc
Reason is: OK
Check after clear
Reason is: OK
Reason is: OK
Buffer values are: 5a ; be ; dc
Reason is: OK
If I run i2cdetect -y 1 after that, the device doesn't appear in the table, but it responds to programs calling it from either 0x00 or 0x5a. After I've used such a program, the i2cdetect detects the device normally from address 0x5a.
So I guess the real question is, why I can't clear and rewrite the eeprom 0x0e?
The description of Mlx90614 SMBus communication can be found below. The most relevat page is IMO the page 19 which actually gives the pseudocode example of what I'm trying to do.
http://www.melexis.com/Assets/SMBus-communication-with-MLX90614-5207.aspx
Here's the datasheet for mlx90614
http://www.melexis.com/Assets/IR-sensor-thermometer-MLX90614-Datasheet-5152.aspx
And here's the documentation for bcm2835
www.airspayce.com/mikem/bcm2835/group__i2c.html
You have to add an Error-Byte. Take a look at this website for an explanation: https://sf264.wordpress.com/2011/03/10/howto-mlx90614-und-pwm/
Calculating CRC-8 for 00002e4b00 gives 0xa3.
I used for calculating CRC-8 this website: http://smbus.org/faq/crc8Applet.htm
I haven't tested this, but I think this should work:
buf[0] = 0x2e;
buf[1] = 0x4b;
buf[2] = 0x00;
buf[3] = 0xa3;
why = bcm2835_i2c_write(buf,4);
Struggled with the exact same problem with my mlx90614s. Here is the write routine I used to solve it (Please note that the bcm2835-library was properly initalized before the call to the routine).
First I called the write routine with "correct" Slaveaddress, command=0x2E (EEPROMAccess | SMBusAddressReg) and data=0x0000 (for erase). The "correct" slave address can be 0x00 or the factory default 0x5a (or whatever is the chip's true address).
After erasing I used the same write routine but now with data=0x005b, to change from the factory default 0x5a to 0x5b, did a Power Off Reset (POR) and the device showed up with its new address (0x5b) using i2cdetect.
uint8_t memWriteI2C16(uint8_t SlaveAddress, uint8_t command, uint16_t data)
{
unsigned char arr[5];
uint8_t status;
//Prepare for CRC8 calc
arr[0] = SlaveAddress<<1; //NB! 7 bit address + a 0 write bit.
arr[1] = command; //Command byte in packet
arr[2] = *((uint8_t *)(&data)); //Extract data low byte
arr[3] = *((uint8_t *)(&data)+1);//Extract data high byte
arr[4] = crc8(&arr[0],4)&0xFF; //Calculate PEC by CRC8
bcm2835_i2c_setSlaveAddress(SlaveAddress);//Transmit address byte to I2C/SMBus
status = bcm2835_i2c_write (&arr[1], 4); //Transmit Command,DataL, DataH and PEC
bcm2835_delay(5); //Delay at least 5ms
return (status);
}
The CRC8 routine I used was:
// Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.
// A table-based algorithm would be faster, but for only a few bytes
// it isn't worth the code size.
// Ref: https://chromium.googlesource.com/chromiumos/platform/vboot_reference/+/master/firmware/lib/crc8.c
uint8_t crc8(const void *vptr, int len)
{
const uint8_t *data = vptr;
unsigned crc = 0;
int i, j;
for (j = len; j; j--, data++) {
crc ^= (*data << 8);
for(i = 8; i; i--) {
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
return (uint8_t)(crc >> 8);
}
In addition: according to the data sheet for the the mlx90614, its default factory state after power up is PWM output. When hooking an mlx90614 in the factory PWM state to the I2C bus on the RPi2, the i2cdetect reports hundreds of I2C devices on the bus. Trying to access the mlx90614 by using the bcm2835-library fails. What is required is to force the mlx90614 out of its PWM-state by holding the SCL low for at least 2ms. Here is what I did:
uint8_t mlx90614SMBusInit()
{
//Hold SCL low for at leat 2ms in order to force the mlx90614 into SMBus-mode
//Ref Melix app note regarding SMBus comm chapter 6.1 and table 5.
uint8_t SCL1 = 3; //BCM2835 pin no 3 -RPi2 and RevB+. Use if i2cdetect -y 1
uint8_t SCL0 = 1; //BCM2835 pin no 1 -RPi2 and RevB+. Use if i2cdetect -y 0
uint8_t SCL;
SCL = SCL1;
bcm2835_gpio_fsel(SCL, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(SCL ,LOW);
bcm2835_delay( 3); //Delay >2 ms
bcm2835_gpio_write(SCL ,HIGH);
return (1);
}
However, this only hold until next power up. Hence it is required to write to the pwmctrl-register in mlx90614's eeprom (disable pwm output and force SDA to OpenDrain). I used the write routine as previously described with command=0x22 (i.e. EEPROMAccess | PWMCTRLAddressRegister) and after erasing the pwmctrl-register content, I wrote 0x0200 to it (the frst 3 nibbles was 020 in my devices...). Power Off Reset (POR) and the device started in SMBus-mode (no jamming of the I2C-bus). The mlx90614 is a tricky little component...
Also if you are using I2C-tools package from any linux distribution (in my case I'm using debian distro) you could change the address with the i2cset command (https://manpages.debian.org/buster/i2c-tools/i2cset.8.en.html), here is an example:
#Find your I2C bus in your linux with the command i2cdetect -l
#(in my case is the i2c-1)
i2cdetect -l
i2c-1 i2c bcm2835 I2C adapter I2C adapter
#Write the word 0x0000 to the address 0x2E and append the PEC check byte.
i2cset -y 1 0x5a 0x2E 0x0000 wp
#Write the new address as a word, to the address 0x2E and append the PEC
#check byte. In my case the new address is 0x005c
i2cset -y 1 0x5a 0x2E 0x005c wp
#Perform a power cycle of the Mlx90614 device
#Check the new address with the command i2cdetect -y 1
i2cdetect -y 1
I am trying to read analogic signal for a sort of mouse with a pic18f14k50 controller. Here the simple circuit: http://dl.dropbox.com/u/14663091/schematiconew.pdf . I have to read analogic signal from AN9 circuit port. Main function reads from the port, and blinks 30 time if threshold is reached:
void main(void) {
InitializeSystem();
#if defined(USB_INTERRUPT)
USBDeviceAttach();
#endif
while(1) {
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) continue;
if(!HIDTxHandleBusy(lastTransmission))
{
int readed = myReadADC2(); //Here i tried both myReadADC2() or myReadADC1()
if(readed>40) { //If read threshold > 40, blink led 30 times
int i;
for(i=0; i<30; i++) {
Delay1KTCYx(0);
mLED_1_On();
Delay1KTCYx(0);
mLED_1_Off();
}
}
lastTransmission = HIDTxPacket(HID_EP, (BYTE*)hid_report_in, 0x03);
}//end while
}//end main
I used two method to read from the AN9 port, myReadADC() that uses OpenADC() API method:
int myReadADC(void) {
#define ADC_REF_VDD_VDD_X 0b11110011
OpenADC(ADC_FOSC_RC & ADC_RIGHT_JUST & ADC_12_TAD, ADC_CH9 & ADC_INT_OFF, ADC_REF_VDD_VDD_X & ADC_REF_VDD_VSS, 0b00000010); // channel 9
SetChanADC(ADC_CH9);
ConvertADC(); // Start conversion
while(BusyADC()); // Wait for completion
return ReadADC(); // Read result
}
and myReadADC2(), that implements manual read from the port.
int myReadADC2() {
int iRet;
OSCCON=0x70; // Select 16 MHz internal clock
ANSEL = 0b00000010; // Set PORT AN9 to analog input
ANSELH = 0; // Set other PORTS as Digital I/O
/* Init ADC */
ADCON0=0b00100101; // ADC port channel 9 (AN9), Enable ADC
ADCON1=0b00000000; // Use Internal Voltage Reference (Vdd and Vss)
ADCON2=0b10101011; // Right justify result, 12 TAD, Select the FRC for 16 MHz
iRet=100;
ADCON0bits.GO=1;
while (ADCON0bits.GO); // Wait conversion done
iRet=ADRESL; // Get the 8 bit LSB result
iRet += (ADRESH << 8); // Get the 2 bit MSB result
return iDelay;
}
Both cases doesn't works, i touch (sending analogic signal) port AN9 but when I set high threshold (~50) led don't blinks, with low threshold (~0) it blinks immidiatly when i provide power to the PIC. Maybe i'm using wrong port? I'm actually passing AN9 as reading port? Or maybe threshold is wrong? How can i found the right value? Thank you
Here the MPLAB C18 Apis http://dl.dropbox.com/u/14663091/API%20microchip%20C18.pdf .
Regarding function myReadADC2(): you need to switch ANSEL and ANSELH configs as RC7/AN9 is configured in bit 1 of ANSELH. Also call me paranoid but for the line
iRet += (ADRESH << 8);
I always like to either save it a temporary variable first or cast explicitly the value ADRESH before shifting it up:
iRet += (((UINT) ADRESH) << 8);
That way I know for sure the bits won't get lost when shifting up which has bitten me before.
Regarding function myReadADC():
OpenADC() only takes two parameters. I presume that bitfield in the third parameter field is for the analog enable (ADRESH/ADRES). I'm assuming that's handled by SetChanADC() but you may have to set ADRESH/ADRES manually. It may help to set a breakpoint in the debugger and stop after configuration is complete to make sure your registers are set appropriatley.