npmx drivers

I am using a STM32 with the NPMX drivers.

I am having a few issues and wanted to see if there are recommendations.

Issue 1:

disabling the interrupts does not seem to work

	// Clear all events before enabling interrupts, just in case other interrupt source was configured before.
	for (uint32_t i = 0; i < NPMX_EVENT_GROUP_COUNT; i++) {
	        npmx_err = npmx_core_event_interrupt_disable(&npm1300_instance, (npmx_event_group_t)i, NPMX_EVENT_GROUP_ALL_EVENTS_MASK);
	        if(npmx_err == NPMX_SUCCESS)
	        {
	        		printf("Event Cleared\n");
	        		osDelay(100);
	        }

the above code comes from the PORTING Guide.

when i run that block it looks like it never reaches the NPMX_SUCCESS

I have attached the I2C transactions

it looks like it is writing 0x00 and not 0xFF as I would expect.

Issue 2:

I am trying to set a GPIO as an Interrupt.

	npmx_error_t ret;
	npmx_gpio_t *npmx_gpio_struct;

	// Set GPIO 3 as GPIO Interrupt.
	//
	npmx_gpio_struct = npmx_gpio_get(&npm1300_instance, 3);

	ret = npmx_gpio_mode_set(&npmx_gpio_struct, NPMX_GPIO_MODE_OUTPUT_IRQ);

when i run this it does not look like I get the Index of 3 and I cannot tell about the pointer to the I2C Instance

then the call to npmx_gpio_mode_set throws a hard Fault.

I have tried it with declaring a separate npmx_gpio_t structure and inline declaration like the porting guide.  They both throw faults.

which I guess I should ask if the init function call from the porting guide

static npmx_error_t my_i2c_write_function(void * p_context, uint32_t register_address, uint8_t * p_data, size_t num_of_bytes);
static npmx_error_t my_i2c_read_function(void * p_context, uint32_t register_address, uint8_t * p_data, size_t num_of_bytes);


static void my_npmx_initialization_function(void)
{
    npm1300_backend.p_read = my_i2c_read_function;
    npm1300_backend.p_write = my_i2c_write_function;
    npm1300_backend.p_context = NULL; // Optional context for our use

    npmx_error_t npmx_err = npmx_core_init(&npm1300_instance, &npm1300_backend, NULL, true);
    // TODO: Verify that npmx_err == NPMX_SUCCESS
}

should give me a I2C like this

it appears to write 0x05 and 0x09, then read 0x00.

is this expected from the init Function?

I am looking more into it, but any guidance can help

Parents
  • I would first of all like to see your `my_i2c_write_function` and `my_i2c_write_function` implementations, are you sure they are implemented properly?

    On the first screenshot nothing is happening really. It's neither a write nor a read transaction. Examples of those you can see in the datasheet https://docs.nordicsemi.com/bundle/ps_npm1300/page/chapters/core_components/ctrl_reg/doc/frontpage.html#d89e68

    On the second screenshot it seems to read out the 0x0509 register (ADC_CONFIG) getting value 0. While this can be part of the initialization function, it shouldn't be the only transaction in this case... Did you check the return code of this function call?

  • I am having trouble with the correct STM32 HAL I2C calls for TX and RX.  I believe I have the TX working correctly because I call to clear all interrupts and it appears to work.  the RX might still be an issue.  in the npmx_core_inti() function it looks like it needs to read several registers if you set "Restore Values" to True.  but i only get one read for the ADCCONFIG, but nothing else.  how many reads of registers should there be?
    adc, ntc, charge, discharge, ship.

    Is there any more guidance on the preferred function calls to write to registers? do you

    need to call npmx_xxx_get() for any specific function before calling npmx_xxx_set()?

  • There is no point in using any of the npmx functions as long as the I2C read/write functions are not properly implemented. If you struggle with the implementation, I could give some guidance based on your current code, or at least a reference to STM32 documentation I should use to implement this.

    > but i only get one read for the ADCCONFIG, but nothing else.

    I suspect that the I2C read function returns an error which makes it the first and the last read as the init function will terminate on any communication error. That's why I asked you to check the init return code.

Reply
  • There is no point in using any of the npmx functions as long as the I2C read/write functions are not properly implemented. If you struggle with the implementation, I could give some guidance based on your current code, or at least a reference to STM32 documentation I should use to implement this.

    > but i only get one read for the ADCCONFIG, but nothing else.

    I suspect that the I2C read function returns an error which makes it the first and the last read as the init function will terminate on any communication error. That's why I asked you to check the init return code.

Children
  • i have the I2C working now.  so my only issue is how to use the npmx drivers correctly.

    it turns out I needed to do a conversion from the STM HAL I2C error return status to the npmx_error_t enumeration. so i was returning the correct enum in the I2C read write functions.

    I believe I am starting to understand the nPMX drivers.  

    for example, would this be the correct way to enable vbat to auto measure every second in single measurement mode:

    // Enable VBAT auto measure every 1 second in single measurement mode
        npmx_adc_config_t adc_conf;
        adc_conf.vbat_burst =0;									//Set ADCCONFIG VBAT BURST to SINGLEMODE
        adc_conf.vbat_auto = 1;									//set ADCONFIG VBAT AUTO to Trigger measurement every 1 Second
        npmx_adc_t * adc = npmx_adc_get(&npm1300_instance, 0);
        ret =  npmx_adc_config_set(adc, &adc_conf);
    I have many questions about just the basic order of configuring things and use of correct masks for enabling/disabling charger, creating callbacks correctly, ....

    I guess I will keep trying and open a ticket if I run into issues.

    thanks for your help

  • Good to hear you've solved the I2C issues. Yes, using npmx drivers is not very straight-forward as it allows much finer tuning of different parameters, etc. But that's the appeal of the bare-metal flavour of drivers for many, for simplicity you could use our Zephyr native drivers.

    To help you get through the learning curve on npmx if you continue this way, we have built docs, e.g. here's the page on ADC since you're trying to get some measurements now: https://nordicsemiconductor.github.io/npmx/drivers/adc/index.html

    On the front page of these docs we've also linked https://github.com/NordicSemiconductor/npmx-zephyr where you can find various npmx usage examples. The samples are integrated into the Zephyr environment, but the way the npmx APIs are used does not change based on the environment, so those could be copied (with some adjustments to your use case) if found useful.

  • I have everything "working" but i have a few issues and questions.
    Let me describe my configuration:

    I have a STM32 running FreeRTOS.  I have the PMIC configured for the ADC to automeasure every 1 Second.  all USB, VBAT, ADC, Charger will generate an Interrupt on GPIO3 from the PMIC.
    The STM has a ISR that simply sets a flag the an interrupt occured.

    I have one thread that runs this:

      for(;;)
      {
    	printf("\n myTask01 \n"); //WRC print Task
    
    	if (pmic_interrupt) {
    		  npmx_core_interrupt(&npm1300_instance);
    		  npmx_core_proc(&npm1300_instance);
    		  pmic_interrupt = false;
    		  osDelay(1000);
    	  }
    

    I have a second code that runs the Fuel Gauge

      for(;;)
      {
    	printf("\n myTask02 \n"); //WRC print Task
    	fuel_gauge_update(&npm1300_instance);
    	osDelay(1000);
      }
    

    I have been playing with thread priorities and delay numbers, but i cant get a consistent result.

    The first task sometimes reports the battery voltage or events if I pull the USB.  like this:

    myTask01

    Battery: 4125 mV.

    State: VBUS_CONNECTED_CHARGING_CC.

    State: BATTERY_CONNECTED.

    but most of the time it only prints

    myTask01

    so i know it is entering the task, but not reading the ADC for VBAT.

    either missing the interrupt or the threads are not allotted enough time

    the Fuel Gauge task only prints

    myTask02

    Constant current charging

    Reading ADC measurements failed.

    V: -0.000, I: 0.000, T: -0.00, SoC: 0.00, TTE: nan, TTF: nan

    I guess my questions are

    what is the timing needed for each task to complete the PMIC and Fuel Gauge procedures?

    any thought on why I always get "adc failed" in the Fuel Gauge?

    do i need to configure the ADC different?

  • A new update.  I have the Fuel Gauge responding with actual data.  
    I am still having the issue with Task o1 only responding with the battery voltage once.  but now I have the code getting trapped in task 2.  
    I guess I need to understand the configuration of the PMIC to correctly operate. 
    I have the PMIC generating an interrupt on events from the battery, USB, and charger.  this event toggles a gpio that sets a flag in the STM ISR that is read by a task to run the npmx_core_interrupt() and npmx_Core_proc() functions. 
    is this the correct way to do it?  how should I configure the PMIC to guarantee the works correctly? (ADC settings, Event settings, ..)?

    I am not sure why the Fuel gauge only responds once and holds the device in the second task.  is there a specific config that is needed that is conflicted with how i set up for the other task?
    I have been testing for a while, but not making much progress.  any thought are helpful 
    thanks 

  • Is the interrupt level- or edge-triggered?

    Level-triggered: you should get another interrupt automatically if another event occurred while processing the current events. No additional logic should be needed in this case besides setting the flag in the interrupt handler and disabling the interrupt source until after you have called the processing function. Then it needs to be re-enabled.
    Edge-triggered: the interrupt source doesn't have to be disabled here, but the processing function must be called until the interrupt pin is in the inactive state AND the flag is false. Only ensuring this, the interrupt will be able to fire again.
    I would recommend using the first option. I don't see you re-enabling the interrupt after you call npmx_core_proc. Something to look into.

    As for the potential concurrency issues, I don't have much experience with FreeRTOS to recommend anything specific, but some things to look into are:
    Are threads preemptive or cooperative? If a thread can be preempted, you need to ensure that the I2C access is exclusive to prevent any issues there, e.g. with a mutex.
    Same goes for interrupt handlers. Ideally they should not do any I2C activity at all. But from your description it already seems to be the case.

    The time required to read out the ADC conversion results would depend on your I2C bus frequency. Generally, it is just a few milliseconds. The fuel gauge process function should take even less.

    Overall, guessing the source of the issues here is maybe not the best approach. Are you able to just attach a debugger to your program and do some investigations that way?
    And without seeing any of the actual code you're writing I'm not able to do more specific suggestions here. There is no one correct way to configure everything on the PMIC, this would largely depend on the use case. But there are definitely wrong ways to do that, which would be much easier to identify having code at hand.

Related