Post Go back to editing

Fail to use the function max31343_reg_read_time_stamp()

Category: Hardware
Product Number: AD-PQMON-SL

Hardware: AD-PQMON-SL

 

Goal:

Display RTC clock time (with battery) in iio_pqm.c

max31343_reg_read_time_stamp(max31343_dev, &ts)

 

case CURRENT_TIME_READABLE:

                return snprintf(buf, len, "%04d-%02d-%02d %02d:%02d:%02d",

                                                ts.year, ts.mon + 1, ts.day,

                                                ts.hr, ts.min, ts.sec);

 

Problem Description:

After adding max31343 initialisation, set the timestamp and cleanup code in basic_example.c, a hex file can be built, but fails to be detected by iio_info

 

Microsoft Windows [Version 10.0.19045.6466]

(c) Microsoft Corporation. All rights reserved.

 

C:\Users\YongYH>cd C:\Users\YongYH\Private\Tools\libiio\Windows-VS-2022-x64 & iio_info -u serial:COM4,115200,8n1

Unable to create IIO context serial:COM4,115200,8n1: No such file or directory (2)

 

Troubleshooting steps that I have taken:

  1. If max31343 related codes are removed from basic_example.c, iio_info can run without abnormal
  2. Using latest version of max31343.c and max31343.h
  3. Tried to refine my code in basic_example.c by using AI, but the error persisted.

/*******************************************************************************
 *   @file   basic_example.c
 *   @brief  PQM firmware, called by main
 *   @author Robert Budai (robert.budai@analog.com)
 ********************************************************************************
 * Copyright (c) 2024 Analog Devices, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of Analog Devices, Inc. nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#ifdef BASIC_EXAMPLE
#include "basic_example.h"
#endif

 /* ============ ADD THESE INCLUDES AT THE TOP ============ */
#include "max31343.h"
#include "common_data.h"
/* ============ END NEW INCLUDES ============ */

int32_t pqm_init(struct pqm_desc **desc, struct pqm_init_para *param)
{
	struct pqm_desc *d;
	d = (struct pqm_desc *)no_os_calloc(1, sizeof(*d));

	if (!d)
		return -ENOMEM;

	d->ext_buff = param->ext_buff;
	d->ext_buff_len = param->ext_buff_len;
	for (int i = 0; i < TOTAL_PQM_CHANNELS; i++) {
		for (int j = 0; j < MAX_CH_ATTRS; j++) {
			d->pqm_ch_attr[i][j] = 0;
		}
	}
	for (int i = 0; i < PQM_DEVICE_ATTR_NUMBER; i++) {
		d->pqm_global_attr[i] = param->dev_global_attr[i];
	}
	*desc = d;

	return 0;
}

int32_t pqm_remove(struct pqm_desc *desc)
{
	if (!desc)
		return -EINVAL;
	no_os_free(desc);

	return 0;
}

int32_t update_pqm_channels(void *dev, uint32_t mask)
{
	struct pqm_desc *desc;

	if (!dev)
		return -ENODEV;

	desc = dev;
	desc->active_ch = mask;

	return 0;
}

int32_t close_pqm_channels(void *dev)
{
	struct pqm_desc *desc;

	if (!dev)
		return -ENODEV;

	desc = dev;
	desc->active_ch = 0;

	return 0;
}

#if defined(PQM_CONN_SERIAL)
int32_t enable_RS482_driver()
{
	// Enable driver and receiver of ADM2587, used only by serial connection
	int status;
	struct no_os_gpio_sec *enable_ADM2587;
	struct nhd_c12832a1z_dev *nhd_c12832a1z_device;

	struct max_gpio_init_param gpio_extra_ip_ADM2587 = {
		.vssel = MXC_GPIO_VSSEL_VDDIOH,
	};

	struct no_os_gpio_init_param gpio_ADM2587_ip = {
		.port = 2,
		.number = 15,
		.pull = NO_OS_PULL_NONE,
		.platform_ops = &max_gpio_ops,
		.extra = &gpio_extra_ip_ADM2587,
	};

	status = no_os_gpio_get(&enable_ADM2587, &gpio_ADM2587_ip);
	if (status)
		return status;
	status = no_os_gpio_set_value(enable_ADM2587, 1);
	return status;
}
#endif

int basic_pqm_firmware()
{

	struct no_os_uart_desc *uart_desc;
	struct pqm_desc *pqm_desc;
	struct iio_app_desc *app;
	struct iio_app_init_param app_init_param = {0};
	struct iio_data_buffer buff = {
		.buff = (void *)iio_data_buffer_loc,
		.size = MAX_SIZE_BASE_ADDR_WITH_SIZE,
	};
	pqlibExample.no_os_cb_desc = NULL;

	memset(iio_data_buffer_loc, 0, MAX_SIZE_BASE_ADDR_WITH_SIZE);

	int status = SYS_STATUS_SUCCESS;

	/* ============ ADD THESE VARIABLE DECLARATIONS ============ */
	struct max31343_dev* max31343_dev = NULL;
	struct max31343_time_stamp ts;
	struct max31343_init_param max31343_init_params;
	/* ============ END NEW VARIABLE DECLARATIONS ============ */

	status = init_lcd();
	if (status)
		goto exit;

	status = no_os_uart_init(&uart_desc, &uart_ip_stdio);
	if (status)
		goto exit;

	no_os_uart_stdio(uart_desc);

#if defined(PQM_CONN_SERIAL)
	status = enable_RS482_driver();
	if (status)
		goto exit;
#endif

	/* ============ INSERT MAX31343 INITIALIZATION HERE ============ */
/* Setup MAX31343 RTC initialization parameters */
	max31343_init_params.i2c_init = &i2c_ip;
	max31343_init_params.battery_en = 1;

	/* Initialize MAX31343 device */
	status = max31343_init(&max31343_dev, max31343_init_params);
	if (status) {
		printf("MAX31343 initialization failed, status: %d\n\r", status);
		goto exit;
	}
	printf("MAX31343 initialized successfully\n\r");

	/* Set the time stamp */
	ts.sec = 0;
	ts.min = 0;
	ts.hr = 12;
	ts.day = 25;
	ts.mon = 2;      /* Month: 0-11 (2 = March) */
	ts.year = 2026;

	status = max31343_set_time_stamp(max31343_dev, ts);
	if (status) {
		printf("Failed to set time stamp, status: %d\n\r", status);
		goto exit;
	}
	printf("Time stamp set successfully: %02d:%02d:%02d %02d-%02d-%04d\n\r",
		ts.hr, ts.min, ts.sec, ts.day, ts.mon + 1, ts.year);

	/* ============ END MAX31343 INITIALIZATION ============ */

#if defined(PQM_CONN_T1L)
	uint8_t adin1110_mac_address[6] = {0x00, 0x18, 0x80, 0x03, 0x25, 0x60};
	struct no_os_gpio_desc *adin1110_swpd_gpio;
	struct no_os_gpio_desc *adin1110_tx2p4_gpio;
	struct no_os_gpio_desc *adin1110_mssel_gpio;
	struct no_os_gpio_desc *adin1110_cfg0_gpio;
	struct no_os_gpio_desc *adin1110_cfg1_gpio;
	struct no_os_gpio_desc *adin1110_int_gpio;
	int ret;

	no_os_gpio_get(&adin1110_cfg0_gpio, &adin1110_cfg0_ip);
	no_os_gpio_get(&adin1110_swpd_gpio, &adin1110_swpd_ip);
	no_os_gpio_get(&adin1110_tx2p4_gpio, &adin1110_tx2p4_ip);
	no_os_gpio_get(&adin1110_mssel_gpio, &adin1110_mssel_ip);
	no_os_gpio_get(&adin1110_cfg1_gpio, &adin1110_cfg1_ip);
	no_os_gpio_get(&adin1110_int_gpio, &adin1110_int_ip);
	no_os_gpio_direction_output(adin1110_swpd_gpio, 1);
	no_os_gpio_direction_output(adin1110_tx2p4_gpio, 0);
	no_os_gpio_direction_output(adin1110_mssel_gpio, 1);
	no_os_gpio_direction_output(adin1110_cfg1_gpio, 1);
	no_os_gpio_direction_output(adin1110_cfg0_gpio, 1);
	no_os_gpio_direction_input(adin1110_int_gpio);

	memcpy(adin1110_ip.mac_address, adin1110_mac_address, NETIF_MAX_HWADDR_LEN);
	memcpy(app_init_param.lwip_param.hwaddr, adin1110_mac_address,
	       NETIF_MAX_HWADDR_LEN);
#endif

	status = afe_init();
	if (status != SYS_STATUS_SUCCESS) {
		printf("AFE Init failed \n\r");
		goto exit;
	}

	status = pqm_measurement_init();
	if (status != SYS_STATUS_SUCCESS) {
		printf("Pqm Measurement Init failed \n\r");
		goto exit;
	}

	status = pqm_init(&pqm_desc, &pqm_ip);
	if (status) {
		printf("PQM initialization failed \n\r");
		goto exit;
	}

	status = pqm_start_measurement(false);
	if (status != SYS_STATUS_SUCCESS) {
		printf("PQM could not start measurements, status: %d \n\r", status);
		goto exit;
	}
	printf("Mesurements started \n\r");

	struct iio_app_device devices[] = {
		IIO_APP_DEVICE("pqm", pqm_desc, &pqm_iio_descriptor, &buff, NULL, NULL)
	};

	app_init_param.devices = devices;
	app_init_param.nb_devices = NO_OS_ARRAY_SIZE(devices);

#if defined(PQM_CONN_USB)
	app_init_param.uart_init_params = iio_demo_usb_ip;
#elif defined(PQM_CONN_SERIAL)
	app_init_param.uart_init_params = iio_demo_serial_ip;
#elif defined(PQM_CONN_T1L)
	app_init_param.uart_init_params = iio_demo_serial_ip;
	app_init_param.lwip_param.platform_ops = &adin1110_lwip_ops;
	app_init_param.lwip_param.mac_param = &adin1110_ip;
	app_init_param.lwip_param.extra = NULL;
#endif

	app_init_param.post_step_callback = &(pqm_one_cycle);
	status = iio_app_init(&app, app_init_param);

	if (status)
		goto exit;

	status = iio_app_run(app);

	iio_app_remove(app);

exit:

	/* ============ ADD MAX31343 CLEANUP IN THE EXIT SECTION ============ */
	if (max31343_dev) {
		int ret_cleanup = max31343_remove(max31343_dev);
		if (ret_cleanup) {
			printf("MAX31343 removal failed, status: %d\n\r", ret_cleanup);
		}
	}
	/* ============ END MAX31343 CLEANUP ============ */

	pqm_remove(pqm_desc);
	no_os_uart_remove(uart_desc);
	return status;
}

Parents
  • Thank  , it's work!.

    By the way, I found that need to add 100 µs delay after every max31343_reg_read.

    If not, max31343_reg_read_time_stamp() will cause iio_info can't run, will return timeout error.

    int max31343_reg_read_time_stamp(struct max31343_dev *dev,
    				 struct max31343_time_stamp *ts)
    {
    	uint8_t data;
    	int ret;
    	uint8_t century = 0;
    
    	ret = max31343_reg_read(dev, MAX31343_R_SECONDS, &data);
    	if (ret)
    		return ret;
    	ts->sec = no_os_bcd2bin(data);
    
    	no_os_udelay(100);
    
    	ret = max31343_reg_read(dev, MAX31343_R_MINUTES, &data);
    	if (ret)
    		return ret;
    	ts->min = no_os_bcd2bin(data);
    
    	no_os_udelay(100); 
    
    	ret = max31343_reg_read(dev, MAX31343_R_HOURS, &data);
    	if (ret)
    		return ret;
    	ts->hr = no_os_bcd2bin(data);
    
    	no_os_udelay(100); 
    
    	ret = max31343_reg_read(dev, MAX31343_R_DATE, &data);
    	if (ret)
    		return (ret);
    	ts->day = no_os_bcd2bin(data);
    
    	no_os_udelay(100); 
    
    	ret = max31343_reg_read(dev, MAX31343_R_MONTH, &data);
    	if (ret)
    		return ret;
    	
    	no_os_udelay(100); 
    
    	/* 7th bit stores if current year is century */
    	century = data & NO_OS_BIT(7);
    	data &= ~NO_OS_BIT(7);
    	ts->mon = no_os_bcd2bin(data);
    
    	ret = max31343_reg_read(dev, MAX31343_R_YEAR, &data);
    	if (ret)
    		return ret;
    	if (century)
    		ts->year = no_os_bcd2bin(data) + 2100;
    	else
    		ts->year = no_os_bcd2bin(data) + 2000;
    
    	no_os_udelay(100); 
    
    	return 0;
    }

  • Hi  the delay is needed only if you use the latest release of Maxim SDK. If this is the case, I would recommend using a 50 us delay inside the max31343_reg_read() function after the no_os_i2c_read(). You need to modify the code a bit to follow the same logic as is in the no_os_i2c_write() case regarding ret. If you upgrade the SDK to the latest build not latest release, I think this problem is already addressed, so no delay needed.
    p.s. If you use the latest build you need to update some paths since they were changed:

    diff --git a/tools/scripts/maxim.mk b/tools/scripts/maxim.mk


    --- a/tools/scripts/maxim.mk
    +++ b/tools/scripts/maxim.mk
    @@ -15,7 +15,7 @@ OC=arm-none-eabi-objcopy
    SIZE=arm-none-eabi-size

    PYTHON = python
    -ARM_COMPILER_PATH = $(realpath $(dir $(shell find $(MAXIM_LIBRARIES)/../Tools/GNUTools -wholename "*bin/$(CC)" -o -name "$(CC).exe")))
    +ARM_COMPILER_PATH = $(realpath $(dir $(shell find $(MAXIM_LIBRARIES)/../../../Tools/gcc/arm-none-eabi -wholename "*bin/$(CC)" -o -name "$(CC).exe")))

    # Use the user provided compiler if the SDK doesn't contain it.
    ifeq ($(ARM_COMPILER_PATH),)
    @@ -51,6 +51,11 @@ include $(MAXIM_LIBRARIES)/CMSIS/Device/Maxim/$(TARGET_UCASE)/Source/GCC/$(TARGE
    endif
    include $(MAXIM_LIBRARIES)/PeriphDrivers/$(TARGET_LCASE)_files.mk

    +PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SYS/mxc_assert.c
    +PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SYS/mxc_delay.c
    +PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SYS/nvic_table.c
    +PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SYS/mxc_lock.c
    +
    HEX=$(basename $(BINARY)).hex
    TARGET_REV=0x4131

  • Hi  , I have some issue on download latest version of Maxim SDK. Could you help see the new thread? Where to download latest release (not build) Maxim SDK? - Q&A - Energy - EngineerZone

  • Hi  You have the answer in the new thread.

Reply Children
No Data