CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Storing PWM Configuration on MLX90614 for MCU-Independent T

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
MCUprogrammer



Joined: 08 Sep 2020
Posts: 228

View user's profile Send private message

Storing PWM Configuration on MLX90614 for MCU-Independent T
PostPosted: Thu Feb 20, 2025 5:55 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 6:18 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 6:35 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 7:32 am     Reply with quote

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...... Sad

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 8:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 9:59 am     Reply with quote

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. Smile
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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 10:45 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 10:50 am     Reply with quote

It looks right.
Crossing things!..... Smile
MCUprogrammer



Joined: 08 Sep 2020
Posts: 228

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 11:14 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 12:34 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Feb 20, 2025 12:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Feb 21, 2025 4:52 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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