 |
 |
View previous topic :: View next topic |
Author |
Message |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
Storing PWM Configuration on MLX90614 for MCU-Independent T |
Posted: Thu Feb 20, 2025 5:55 am |
|
|
I am trying to configure the MLX90614 thermal sensor to operate in PWM mode for temperature reading without an MCU. My goal is to write the desired PWM configuration to the EEPROM only once, so the sensor can retain this setting and run in PWM mode after power cycles. Specifically, I want to enable single PWM mode with either open-drain or push-pull output for direct temperature reading.
I think I'm making a mistake somewhere. I can't get it to work properly. Can anyone help me?
Code: |
#include <18F67J60.h>
#fuses NOWDT
#use delay(crystal=25MHz)
#define LCD_ENABLE_PIN PIN_F3
#define LCD_RS_PIN PIN_F1
#define LCD_RW_PIN PIN_F2
#define LCD_DATA4 PIN_F4
#define LCD_DATA5 PIN_F5
#define LCD_DATA6 PIN_F6
#define LCD_DATA7 PIN_F7
#include <lcd.c>
#include <stdint.h>
// I2C Kullanimi icin Tanimlamalar
#use i2c(Master, SDA=PIN_C0, SCL=PIN_A3, FAST=100000)
#define MLX90614_RAWIR1 0x04
#define MLX90614_RAWIR2 0x05
#define MLX90614_TA 0x06
#define MLX90614_TOBJ1 0x07
#define MLX90614_TOBJ2 0x08
// EEPROM ADDR
#define MLX90614_I2C_ADDR 0x0E
#define MLX90614_TOMAX 0x00
#define MLX90614_TOMIN 0x01
#define MLX90614_PWMCTRL 0x02
#define MLX90614_TA_RANGE 0x03
#define MLX90614_EMISSIVITY 0x04
#define MLX90614_CONFIG_REGISTER_1 0x05
// EEPROM Write and Erase Operations
#define ERASE_EEPROM_VALUE 0x0000 // EEPROM silme işlemi için
#define DEFAULT_EMISSIVITY 0xFFFF // Emisivite varsayılan (1.0)
// Emissivity Adjustment Function
#define CALCULATE_EMISSIVITY(epsilon) ((uint16_t)(65535 * (epsilon) + 0.5)) // Emisivite hesaplama
#define PWM_OPEN_DRAIN 0x03 // 0000 0011 -> PWM Etkin, Tekli Mod, Open-Drain
#define PWM_PUSH_PULL 0x07 // 0000 0111 -> PWM Etkin, Tekli Mod, Push-Pull
#define WRITE_ROM PIN_A4
#define ERASE_ROM PIN_D0
/**
* set_pwm_mode(unsigned int8 mode):
* --------------------------------
* Configures the MLX90614 sensor's PWM output mode.
*
* @param mode: The PWM configuration value.
* - 0x03 (0000 0011): PWM Enabled, Single Mode, Open-Drain
* - 0x07 (0000 0111): PWM Enabled, Single Mode, Push-Pull
*
* Bit Explanation:
* - Bit0: PWM Mode Selection (1 = Single Mode, 0 = Extended Mode)
* - Bit1: PWM Enable (1 = Enabled, 0 = Disabled)
* - Bit2: SDA/PWM Pin Configuration (1 = Push-Pull, 0 = Open-Drain)
*/
#define PWM_OPEN_DRAIN 0x03 // 0000 0011 -> PWM Enabled, Single Mode, Open-Drain
#define PWM_PUSH_PULL 0x07 // 0000 0111 -> PWM Enabled, Single Mode, Push-Pull
void set_pwm_mode(unsigned int8 mode)
{
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(MLX90614_PWMCTRL);
i2c_write(mode); // Parametreye bağlı PWM modu
i2c_stop();
}
void clear_pwm_mode(void)
{
// Clear PWM configuration by writing 0x00 to the PWMCTRL register
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(MLX90614_PWMCTRL);
i2c_write(0x00); // Disable PWM mode
i2c_stop();
}
float MLX90614_get_temperature(uint16_t value)
{
// Convert from raw value to Celsius (Kelvin to Celsius)
float temperature = (value * 0.02) - 273.15;
return temperature;
}
unsigned int MLX90614_read(unsigned char device_address, unsigned char location)
{
unsigned char PEC = 0x00;
unsigned char lb = 0x00;
uint16_t hb = 0x0000;
i2c_start();
i2c_write(device_address);
i2c_write(location);
i2c_start();
i2c_write((device_address + 1));
lb = i2c_read(1);
hb = i2c_read(1);
PEC = i2c_read(0);
i2c_stop();
hb <<= 8;
hb |= lb;
return hb;
}
void main(void)
{
float temperature;
unsigned int16 reading;
lcd_init();
while(TRUE)
{
reading = MLX90614_read(MLX90614_I2C_ADDR, MLX90614_TOBJ1);
temperature = MLX90614_get_temperature(reading);
lcd_gotoxy(1,1);
printf(lcd_putc,"Temperature: %0.3fF", temperature);
if(!input(WRITE_ROM)) // pull_up
{
delay_ms(10);//debounce
while(!input(WRITE_ROM));
set_pwm_mode(PWM_OPEN_DRAIN);
}
else if(input(ERASE_ROM)) //pull_down
{
delay_ms(10); // debounce
while(input(ERASE_ROM));
clear_pwm_mode();
}
delay_ms(1000);
}
} |
_________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19700
|
|
Posted: Thu Feb 20, 2025 6:18 am |
|
|
Re read the data sheet.
On this chip you have to erase an EEPROM cell before you can write it.
Section 8.3.3 in the data sheet:
"Erase (write 0) must take place before write of desired data is made."
8.3.3.1
Gives the description of what has to happen. You have to write a zero,
wait 10mSec (5 min, but 10 is recommended), and hen write your new
data.
You have to do the clear operation before you can do the write. After
both, then power cycle the chip. You still have to perform this erase,
Even if the cell is already 0. It is like a lock mechanism. It'll only
accept the write of a value after a 0 is written. |
|
 |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
|
Posted: Thu Feb 20, 2025 6:35 am |
|
|
Firstly, thank you for your previous detailed explanation regarding the EEPROM write procedure. Based on your guidance, I applied the exact sequence: I performed the erase step by writing 0x0000, waited 10ms, then wrote the new value, and finally performed a power cycle. I understand that this process works like a lock mechanism, ensuring the chip only accepts new data after a proper erase. Could you please confirm if my implementation is correct or if I am missing any important details?
Code: |
void set_pwm_mode(unsigned int8 mode)
{
// Step 1: Erase existing value
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(MLX90614_PWMCTRL);
i2c_write(0x00); // Erase step (write 0x0000)
i2c_stop();
delay_ms(10); // Wait 10ms as recommended
// Step 2: Write new PWM configuration
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(MLX90614_PWMCTRL);
i2c_write(mode); // Write new mode
i2c_stop();
delay_ms(10); // Wait another 10ms
} |
Secondly, I am working on reading temperature data from the MLX90614 sensor via I2C using a 3.3V Ethernet Controller board and displaying the result on an LCD screen. The LCD displays text correctly before entering the while loop, but once the loop starts, nothing appears on the screen. I tested the LCD independently, and it works as expected. Could this issue be related to the SCL and SDA pins on the I2C bus, or are there any timing-related factors I should consider when updating the LCD inside the loop?
Thank you again for your support! _________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19700
|
|
Posted: Thu Feb 20, 2025 7:32 am |
|
|
Your PWM_CTRL address is wrong.
If you look, the address is 000xxxxx to talk to the RAM, or
001xxxxx to take to the EEPROM. You are writing to the RAM, not the
EEPROM......
The write should also be 16bits. Two 8 bit transfers. There should then be
a third transfer for the device to return it's PEC reply. Look at the example
write transfer.
Unlike 'normal' I2C, this device turns the bus round for this reply, so you do
a read without issuing another start. |
|
 |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
|
Posted: Thu Feb 20, 2025 8:04 am |
|
|
Firstly, thank you again for your detailed feedback on the PWM configuration process for the MLX90614. I’ve implemented the corrections you suggested, specifically:
EEPROM Access Correction:
I used 0x20 | MLX90614_PWMCTRL to ensure the EEPROM prefix (001xxxxx) is correctly applied, avoiding accidental RAM access.
16-bit Write Implementation:
The write sequence now transfers LSB and MSB separately as two 8-bit writes, complying with the 16-bit requirement.
PEC Handling:
I added the PEC values (0x6F for erase and 0xE1 for write) based on examples found in application notes.
However, I could not locate the exact reference for PEC value 0x6F in the datasheet.
If this PEC value must be dynamically calculated instead of hardcoded, I would greatly appreciate your guidance.
Does this updated code now fully meet the EEPROM write requirements?
Is the 0x6F PEC value acceptable, or should I calculate it dynamically?
After the write operation, is there any additional PEC verification step you would recommend for robustness?
Code: |
#define MLX90614_I2C_ADDR 0x0E // Updated I2C address based on EEPROM configuration
define MLX90614_PWMCTRL 0x02
void set_pwm_mode(unsigned int16 mode) {
// Step 1: Erase existing value (write 0x0000 to EEPROM)
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1); // Write mode
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix (001xxxxx)
i2c_write(0x00); // LSB (0x0000)
i2c_write(0x00); // MSB (0x0000)
i2c_write(0x6F); // I could not find the PEC value for deletion (from the datasheet example) in the data shette.
i2c_stop();
delay_ms(10); // Wait as per datasheet recommendation
// Step 2: Write new PWM configuration (16-bit transfer)
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1); // Write mode
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
i2c_write(mode & 0xFF); // LSB
i2c_write((mode >> 8) & 0xFF); // MSB
i2c_write(0xE1); // PEC value for write (from datasheet example)
i2c_stop();
delay_ms(10); // Final delay for EEPROM write completion
}
|
_________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19700
|
|
Posted: Thu Feb 20, 2025 9:59 am |
|
|
It doesn't use the PEC value on a write.
It actually sends it to you. It contains bits reflecting the status of the
chip itself.
Given that I2C is a wire or'ed bus (so doesn't mind two devices writing
at once), it is fine to just send the fixed value.
Touch wood it works.
Obviously SCL has to be held high for the PWM to work. Basically if
you send a clock on this, it disables the PWM, waiting for an I2C transaction. |
|
 |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
|
Posted: Thu Feb 20, 2025 10:45 am |
|
|
Thank you very much for your responses. 🙏
Based on your explanations, I have created the following structure. I did not include the PEC value and ensured that the SCL line remains high for the PWM to work.
If I load this code onto the board, I expect the PWM mode to function properly.
Did I understand you correctly? Is there any mistake or detail I might have missed in this setup?
Thanks in advance! 🌟 _________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19700
|
|
Posted: Thu Feb 20, 2025 10:50 am |
|
|
It looks right.
Crossing things!.....  |
|
 |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
|
Posted: Thu Feb 20, 2025 11:14 am |
|
|
Hi Ttelmah,
I’ve updated both the set_pwm_mode and clear_pwm_mode functions based on our previous discussions. My intention is to set the MLX90614 sensor to PWM mode and later clear it properly when switching back to I2C.
For set_pwm_mode, I’m first erasing the existing PWMCTRL value by writing 0x0000 and then writing the new 16-bit mode value, following the EEPROM write sequence in the datasheet.
For clear_pwm_mode, I’m simply clearing the PWMCTRL register by writing 0x0000 again, assuming this is enough to disable PWM mode and return to I2C communication.
My questions:
Does simply writing 0x0000 to the PWMCTRL register properly disable PWM mode and restore I2C functionality?
Am I using the correct EEPROM access prefix (0x20 | MLX90614_PWMCTRL) and addressing for the PWMCTRL register?
Are there any timing or sequence issues in my approach that I should be aware of?
Thanks again for your guidance!
Here’s the complete code:
Code: |
void set_pwm_mode(unsigned int16 mode)
{
// Step 1: Erase existing value (write 0x0000 to EEPROM)
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
i2c_write(0x00); // LSB
i2c_write(0x00); // MSB
i2c_stop();
delay_ms(10); // Wait as per datasheet recommendation
// Step 2: Write new PWM configuration (16-bit transfer)
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL);
i2c_write(mode & 0xFF); // LSB
i2c_write((mode >> 8) & 0xFF); // MSB
i2c_stop();
delay_ms(10); // Wait another 10ms for EEPROM write completion
}
void clear_pwm_mode(void)
{
// Step 1: Enter sleep mode before modifying EEPROM
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0xFF); // Sleep mode command
i2c_write(0xE8); // PEC for sleep mode
i2c_stop();
delay_ms(10);
// Step 2: Clear PWM mode by writing 0x0000 to PWMCTRL register
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
i2c_write(0x00); // LSB (0x0000)
i2c_write(0x00); // MSB (0x0000)
i2c_stop();
delay_ms(10); // Wait for EEPROM write completion
}
|
_________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 19700
|
|
Posted: Thu Feb 20, 2025 12:34 pm |
|
|
You won't be entering sleep mode.
To be in sleep mode, you have to hold the clock line low after sending
the command.
Sleep mode is only available on the 3v version. I never used this. |
|
 |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
|
Posted: Thu Feb 20, 2025 12:46 pm |
|
|
This is the final version of the code then.
Code: |
void set_pwm_mode(unsigned int16 mode)
{
// Step 1: Erase existing value (write 0x0000 to EEPROM)
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
i2c_write(0x00); // LSB
i2c_write(0x00); // MSB
i2c_stop();
delay_ms(10); // Wait as per datasheet recommendation
// Step 2: Write new PWM configuration (16-bit transfer)
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL);
i2c_write(mode & 0xFF); // LSB
i2c_write((mode >> 8) & 0xFF); // MSB
i2c_stop();
delay_ms(10); // Wait another 10ms for EEPROM write completion
}
void clear_pwm_mode(void)
{
// Step 1: Enter sleep mode before modifying EEPROM
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0xE8); // PEC for sleep mode
i2c_stop();
delay_ms(10);
// Step 2: Clear PWM mode by writing 0x0000 to PWMCTRL register
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
i2c_write(0x00); // LSB (0x0000)
i2c_write(0x00); // MSB (0x0000)
i2c_stop();
delay_ms(10); // Wait for EEPROM write completion
}
|
_________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 228
|
|
Posted: Fri Feb 21, 2025 4:52 am |
|
|
After I put the MLX90614 sensor into PWM mode using this configuration, I plan to switch it back to I2C mode using the code above.
Do you see any potential problems with this approach?
Is there an additional step needed to ensure a smooth transition to I2C mode?
Code: |
/**
* configure_pwm_mode(unsigned int8 mode):
* ---------------------------------------
* Configures the PWM output mode on the MLX90614 sensor without using sleep mode or PEC.
*
* @param mode: The PWM configuration value.
* - 0x03 (0000 0011): PWM Enabled, Single Mode, Open-Drain
* - 0x07 (0000 0111): PWM Enabled, Single Mode, Push-Pull
* - 0x00 (0000 0000): PWM Disabled (Clears PWM configuration)
*
* Bit Explanation:
* ----------------
* - Bit0: PWM Mode Selection (1 = Single Mode, 0 = Extended Mode)
* - Bit1: PWM Enable (1 = Enabled, 0 = Disabled)
* - Bit2: SDA/PWM Pin Configuration (1 = Push-Pull, 0 = Open-Drain)
*
* Notes:
* ------
* - Sleep mode and PEC (Packet Error Code) are not used in this function for simplicity.
* - This function directly writes to the PWMCTRL register in EEPROM.
* - After configuring the PWM mode, to revert back to I2C mode, the following code (provided by Ttelmah) will be used:
*
* i2c_start();
* i2c_write(MLX90614_I2C_ADDR << 1);
* i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
* i2c_write(0x00); // LSB (0x0000 to disable PWM)
* i2c_write(0x00); // MSB (0x0000)
* i2c_stop();
*
*/
void configure_pwm_mode(unsigned int8 mode)
{
i2c_start();
i2c_write(MLX90614_I2C_ADDR << 1);
i2c_write(0x20 | MLX90614_PWMCTRL); // EEPROM access prefix
i2c_write(mode); // LSB (PWM configuration value)
i2c_write(0x00); // MSB (0x0000 if disabling PWM)
i2c_stop();
delay_ms(10); // Wait for EEPROM write completion
} |
_________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|