ADC using DPPI along with eeprom

Hi, am using the nrf52dk with nrf52832, nrf coonect sdk 2.5.1/ toolchain 2.5.2 and am building a prototype to aquire the signal from the ckp and cmp sensor in the car when its cranking to start and in order to do that am using the adc sample in the DPPI mode in order to aquire the 8000 samples for 1 channel then stop and save the data in the eeprom using the i2c.

the problem its that i cant figure it out how to save it in the eeprom using the i2c because its sends me an error and it cant write to the eeprom. 

Any suggestions how can i do that? 

I am posting my code 

case NRFX_SAADC_EVT_DONE:

            /* STEP 5.3 - Buffer has been filled. Do something with the data and proceed */
            int64_t average = 0;
            int16_t max = INT16_MIN;
            int16_t min = INT16_MAX;
            int16_t counter = 0x0000;//doy de alta el contador
            int16_t current_value; 
            int8_t high_byte = 0x00; //doy de alta los contadores que van a ir en la direeccion de la eeprom
            int8_t low_byte = 0x00;
            int ret;
            int8_t highbyte_current_value;
            int8_t lowbyte_current_value;
            for(int i=0; i < p_event->data.done.size; i++){
            
            high_byte=((counter>>8)&0xff);  //divido las direcciones de 8000 posiciones en el array en 2
            low_byte=(counter&0xff);
                current_value = ((int16_t *)(p_event->data.done.p_buffer))[i];
                highbyte_current_value=((current_value>>8)&0xff);
                lowbyte_current_value= (current_value&0xff);
               //LOG_INF("SAADC buffer %d filled with sample %d ",current_value,i);
                
    /* STEP 7 - Retrieve the API-specific device structure and make sure that the device is ready to use  */





                average += current_value;
                if(current_value > max){
                    max = current_value;
                }
                if(current_value < min){
                    min = current_value;
                }
            }
            average = average/p_event->data.done.size;
            LOG_INF("SAADC buffer at 0x%x filled with %d samples", (uint32_t)p_event->data.done.p_buffer, p_event->data.done.size);
            LOG_INF("AVG=%d, MIN=%d, MAX=%d", (int16_t)average, min, max);
            counter=counter+0x0001;
            //you only need the write address and the eeprom address you want to read from 
     
        uint8_t sensor_regs[3] ={Eeprom_addr_write,0x00,0x00};
        //uint8_t temp_reading[2]= {0xFF,0x00};
        uint8_t temp_reading[4];
        ret = i2c_write_read_dt(&dev_i2c,&sensor_regs,3,&temp_reading,4);
        k_busy_wait(SLEEP_TIME_MS);
          for(int z=0; z < 5; z++){
        printk("waiting... %x\n\r");
       
          }

		if(ret != 0){
			printk("Failed to write/Read I2C device address %x at Reg. %x \n\r", dev_i2c.addr,sensor_regs[0]);
		}
		else{
		printk("memory content write&read %x\n\r",temp_reading[0]);
		printk("memory content write&read %x\n\r",temp_reading[1]);
		printk("memory content write&read %x\n\r",temp_reading[2]);
		printk("memory content write&read %x\n\r",temp_reading[3]);
		}

        
         nrfx_timer_disable(&timer_instance);
            break;

Parents
  • Hi there,

    Exactly which function is returning the error and what error is returned?

    Have you been able to successfully write to the external memory before? 

    regards

    Jared 

  • Yes, i manage to succesfully write and read to the external eeprom program that only does that, but now i want to write the buffer from the ADC example using the DPPI to the eeprom but am having errors and its not working

    first let me show u the little program i made to make it work to write and read from the eeprom:

    uint8_t config[7] = {Eeprom_addr_write,0x00,0x00,0x00,0x01,0x02,0x03};
    
    	ret = i2c_write_dt(&dev_i2c, config, sizeof(config));
    		k_msleep(SLEEP_TIME_MS);
    	if(ret != 0){
    		printk("Failed to Write to I2C device address %x at Reg. %x \n", dev_i2c.addr,config[0]);
    		return -1;
    	}
    
    
    uint8_t data;
    ret = i2c_read_dt(&dev_i2c, &data, sizeof(data));
    k_msleep(SLEEP_TIME_MS);
    		if(ret != 0){
    			printk("Failed to read from I2C device address %x at Reg. %x \n\r", dev_i2c.addr,config[0]);
    		}
    		else{
    		printk("memory content first read %x\n\r",data);
    		}
    //you only need the write address and the eeprom address you want to read from 
    uint8_t sensor_regs[3] ={Eeprom_addr_write,0x00,0x00};
    //uint8_t temp_reading[2]= {0xFF,0x00};
    uint8_t temp_reading[4];
    ret = i2c_write_read_dt(&dev_i2c,&sensor_regs,3,&temp_reading,4);
    k_msleep(SLEEP_TIME_MS);
    		if(ret != 0){
    			printk("Failed to write/Read I2C device address %x at Reg. %x \n\r", dev_i2c.addr,sensor_regs[0]);
    		}
    		else{
    		printk("memory content write&read %x\n\r",temp_reading[0]);
    		printk("memory content write&read %x\n\r",temp_reading[1]);
    		printk("memory content write&read %x\n\r",temp_reading[2]);
    		printk("memory content write&read %x\n\r",temp_reading[3]);
    		}
    	while (1) {
    /* STEP 10 - Read the temperature from the sensor */
    
    /*conversion to MV may nto be supported*/
    
    /* STEP 11 - Convert the two bytes to a 12-bits */
    
    		//k_msleep(SLEEP_TIME_MS);
    	
    }
    }
    

    and i get succesfully the readings on the terminal as follow:

  • But when  i integrate writing to the Eeprom in the Adc using dppi example i get the following error:

  • but as you can see am using the zephyr i2c library for this. do i need to use the nrfx library in this case? is there any sample for this?

  • I will continue to help with this ticket.

    I think that you should be able to use zephyr i2c for this.

    A classic error is to try to use the i2c send function directly from the ADC callback.
    Do you do this?

    Looks like you get an error here. Can you verify that?

    Try to increase CONFIG_I2C_NRFX_TRANSFER_TIMEOUT?

    Regards,
    Sigurd Hellesvik

Reply Children
  • Thx Sigurd,

    Ok now am confused. which library should i work on to talk to the eeprom thry i2c. right now am using 

    #include <zephyr/drivers/i2c.h> but i couldnt make it work. 
    as you can notice the complier its asking for the i2c_nrfx_twi library which i dont have.
    but what i found was an example using the library 

    #include <nrfx_example.h>
    #include <nrfx_twim.h>
    #include <nrfx_twis.h>
    with the example using twi txrx in the visual code
     * @defgroup nrfx_twim_twis_txrx_example TX-RX TWIM with TWIS example
     * @{
     * @ingroup nrfx_twim_twis_examples
     *
     * @brief Example showing the functionality of nrfx_twim and nrfx_twis drivers, when TWI transfer is
     *        performed in TX-RX mode.
    already flashed my nrf52dk with it and it worked but am not sure if its going to work with my adc as its asking for a different library.
    what do u suggest ?
  • Aztec_Coder said:
    what do u suggest ?

    Generally, we suggest using the Zephyr drivers for a device instead of using nrfx directly.

    That being said, it is up to you, so if you find that nrfx drivers work for you, you are free to use those.

    Does this answer your question?

  • Ok can u guide me.how to.implement the reading of the eeprom using the zephyr driver in this case. 

    A classic error is to try to use the i2c send function directly from the ADC callback.

    Do you do this? No, am writing to the eeprom once the dppi driver have completed the adquisition of the 8000 samples and did the average of them. 

    Looks like you get an error here. Can you verify that?

      Am using the #include <zephyr/drivers/i2c.h>  library in my program and i don know how its connected to that library that you are showing me. 

  • Aztec_Coder said:
    Ok can u guide me.how to.implement the reading of the eeprom using the zephyr driver in this case. 

    We have this guide on I2C in general: https://academy.nordicsemi.com/courses/nrf-connect-sdk-fundamentals/lessons/lesson-6-serial-com-i2c/

    I would suggest that you try to first read out the address of the eeprom. Does that work for you?
    It would be nice to know that some communication works first, then go to the write step.

  • yep i already did that excercise regarding the lesson6 in the intermidate course, the problem am having it says that zephyr doesnt actually work with nfrx thats its my question. looks this its my code if u can take a look to point out any mistake am doing:

    /*
     * Copyright (c) 2023 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/logging/log.h>
    #include <nrfx_saadc.h>
    #include <nrfx_timer.h>
    #include <helpers/nrfx_gppi.h>
    #if defined (DPPI_PRESENT)
    #include <nrfx_dppi.h>
    #else
    #include <nrfx_ppi.h>
    #endif
    /* STEP 3 - Include the header file of the I2C API */
    #include <zephyr/drivers/i2c.h>
    /* STEP 4.1 - Include the header file of printk() */
    #include<zephyr/sys/printk.h>
    
    
    LOG_MODULE_REGISTER(Lesson6_Exercise3, LOG_LEVEL_DBG);
    
    /* STEP 2 - Include header for nrfx drivers */
    
    
    /* STEP 3.1 - Define the SAADC sample interval in microseconds */
    #define SAADC_SAMPLE_INTERVAL_US 50
    
    /* STEP 4.1 - Define the buffer size for the SAADC */
    //#define SAADC_BUFFER_SIZE   4000
    #define SAADC_BUFFER_SIZE   8000
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   50
    
    
    /* STEP 8 - Define the I2C slave device address and the addresses of relevant registers */
    #define I2C0_NODE DT_NODELABEL(mysensor)
    #define Eeprom_addr 0b1010000
    #define Eeprom_addr_write 0b10100000
    #define Eeprom_addr_read 0b10100001
    
    
    
    /* STEP 3.2 - Declaring an instance of nrfx_timer for TIMER2. */
    const nrfx_timer_t timer_instance = NRFX_TIMER_INSTANCE(2);
    
    /* STEP 4.2 - Declare the buffers for the SAADC */
    static int16_t saadc_sample_buffer[2][SAADC_BUFFER_SIZE];
    //static int16_t saadc_sample_buffer_2[2][SAADC_BUFFER_SIZE];
    
    /* STEP 4.3 - Declare variable used to keep track of which buffer was last assigned to the SAADC driver */
    static uint32_t saadc_current_buffer = 0;
    //static uint32_t saadc_current_buffer_2 = 0;
    
    
    
    /* STEP 6 - Get the node identifier of the sensor */
    static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C0_NODE);
    
    
    
    static void configure_timer(void)
    {
        nrfx_err_t err;
    
        /* STEP 3.3 - Declaring timer config and intialize nrfx_timer instance. */
        nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG(1000000);
        err = nrfx_timer_init(&timer_instance, &timer_config, NULL);
        if (err != NRFX_SUCCESS) {
    	LOG_ERR("nrfx_timer_init error: %08x", err);
    	return;
    }
    
        /* STEP 3.4 - Set compare channel 0 to generate event every SAADC_SAMPLE_INTERVAL_US. */
        uint32_t timer_ticks = nrfx_timer_us_to_ticks(&timer_instance,
         SAADC_SAMPLE_INTERVAL_US);
        nrfx_timer_extended_compare(&timer_instance,
         NRF_TIMER_CC_CHANNEL0,
          timer_ticks, 
          NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, 
          false);
    
    }
    
    static void saadc_event_handler(nrfx_saadc_evt_t const * p_event)
    {
        nrfx_err_t err;
        switch (p_event->type)
        {
            case NRFX_SAADC_EVT_READY:
            
               /* STEP 5.1 - Buffer is ready, timer (and sampling) can be started. */
                nrfx_timer_enable(&timer_instance);
    
                break;                        
                
            case NRFX_SAADC_EVT_BUF_REQ:
            
                /* STEP 5.2 - Set up the next available buffer. Alternate between buffer 0 and 1 */
                err = nrfx_saadc_buffer_set(saadc_sample_buffer[(saadc_current_buffer++)%2], SAADC_BUFFER_SIZE);
                if (err != NRFX_SUCCESS) {
                LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
                 return;
                }
    
              /* err = nrfx_saadc_buffer_set(saadc_sample_buffer_2[(saadc_current_buffer_2++)%2], SAADC_BUFFER_SIZE);
                if (err != NRFX_SUCCESS) {
                LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
                 return;
                }
    */ 
                break;
    
            case NRFX_SAADC_EVT_DONE:
    
                /* STEP 5.3 - Buffer has been filled. Do something with the data and proceed */
                int64_t average = 0;
                int16_t max = INT16_MIN;
                int16_t min = INT16_MAX;
                int16_t counter = 0x0000;//doy de alta el contador
                int16_t current_value; 
                int8_t high_byte = 0x00; //doy de alta los contadores que van a ir en la direeccion de la eeprom
                int8_t low_byte = 0x00;
                int ret;
                int8_t highbyte_current_value;
                int8_t lowbyte_current_value;
                for(int i=0; i < p_event->data.done.size; i++){
                
                high_byte=((counter>>8)&0xff);  //divido las direcciones de 8000 posiciones en el array en 2
                low_byte=(counter&0xff);
                    current_value = ((int16_t *)(p_event->data.done.p_buffer))[i];
                    highbyte_current_value=((current_value>>8)&0xff);
                    lowbyte_current_value= (current_value&0xff);
                   //LOG_INF("SAADC buffer %d filled with sample %d ",current_value,i);
                    
        /* STEP 7 - Retrieve the API-specific device structure and make sure that the device is ready to use  */
    
    
    
    
    
                    average += current_value;
                    if(current_value > max){
                        max = current_value;
                    }
                    if(current_value < min){
                        min = current_value;
                    }
                }
                average = average/p_event->data.done.size;
                LOG_INF("SAADC buffer at 0x%x filled with %d samples", (uint32_t)p_event->data.done.p_buffer, p_event->data.done.size);
                LOG_INF("AVG=%d, MIN=%d, MAX=%d", (int16_t)average, min, max);
               // counter=counter+0x0001;
                //you only need the write address and the eeprom address you want to read from 
          
    
    
    uint8_t config[7] = {Eeprom_addr_write,0x00,0x00,0x00,0x01,0x02,0x03};
    uint8_t data;
    ret = i2c_read_dt(&dev_i2c, &data, sizeof(data));
    k_msleep(SLEEP_TIME_MS);
    		if(ret != 0){
    			printk("Failed to read from I2C device address %x at Reg. %x \n\r", dev_i2c.addr,config[0]);
    		}
    		else{
    		printk("memory content first read %d\n\r",data);
    		}
    
    /*
            uint8_t sensor_regs[3] ={Eeprom_addr_write,0x00,0x00};
            //uint8_t temp_reading[2]= {0xFF,0x00};
            uint8_t temp_reading[4];
            ret = i2c_write_read_dt(&dev_i2c,&sensor_regs,3,&temp_reading,4);
            k_busy_wait(SLEEP_TIME_MS);
              for(int z=0; z < 5; z++){
            printk("waiting... %x\n\r");
           
              }
    
    		if(ret != 0){
    			printk("Failed to write/Read I2C device address %x at Reg. %x \n\r", dev_i2c.addr,sensor_regs[0]);
    		}
    		else{
    		printk("memory content write&read %x\n\r",temp_reading[0]);
    		printk("memory content write&read %x\n\r",temp_reading[1]);
    		printk("memory content write&read %x\n\r",temp_reading[2]);
    		printk("memory content write&read %x\n\r",temp_reading[3]);
    		}
    
           */ 
             nrfx_timer_disable(&timer_instance);
                break;
    
            default:
                LOG_INF("Unhandled SAADC evt %d", p_event->type);
    
                break;
              
        }
    }
    
    static void configure_saadc(void)
    {
        nrfx_err_t err;
    
        /* STEP 4.4 - Connect ADC interrupt to nrfx interrupt handler */
        IRQ_CONNECT(DT_IRQN(DT_NODELABEL(adc)),
                DT_IRQ(DT_NODELABEL(adc), priority),
                nrfx_isr, nrfx_saadc_irq_handler, 0);
    
        
        /* STEP 4.5 - Initialize the nrfx_SAADC driver */
        err = nrfx_saadc_init(DT_IRQ(DT_NODELABEL(adc), priority));
        if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_saadc_init error: %08x", err);
        return;
    }
    
        
        /* STEP 4.6 - Declare the struct to hold the configuration for the SAADC channel used to sample the battery voltage */
       nrfx_saadc_channel_t channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, 0);
       // nrfx_saadc_channel_t channel_2 = NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN1, 1);
        //nrfx_saadc_channel_t channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(SAADC_CH_PSELP_PSELP_VDD, 0);
    
        /* STEP 4.7 - Change gain config in default config and apply channel configuration */
        channel.channel_config.gain = NRF_SAADC_GAIN1_6;
        err = nrfx_saadc_channels_config(&channel, 1);
        if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_saadc_channels_config error: %08x", err);
        return;
    }
    
        /* STEP 4.8 - Configure channel 0 in advanced mode with event handler (non-blocking mode) */
        nrfx_saadc_adv_config_t saadc_adv_config = NRFX_SAADC_DEFAULT_ADV_CONFIG;
        err = nrfx_saadc_advanced_mode_set(BIT(0),
        NRF_SAADC_RESOLUTION_12BIT,
        &saadc_adv_config,
        saadc_event_handler);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_saadc_advanced_mode_set error: %08x", err);
        return;
    }
                                                
        /* STEP 4.9 - Configure two buffers to make use of double-buffering feature of SAADC */
       err = nrfx_saadc_buffer_set(saadc_sample_buffer[0], SAADC_BUFFER_SIZE);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
        return;
    }
    err = nrfx_saadc_buffer_set(saadc_sample_buffer[1], SAADC_BUFFER_SIZE);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_saadc_buffer_set error: %08x", err);
        return;
    }
        /* STEP 4.10 - Trigger the SAADC. This will not start sampling, but will prepare buffer for sampling triggered through PPI */
    err = nrfx_saadc_mode_trigger();
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_saadc_mode_trigger error: %08x", err);
        return;
    }
    
    }
    
    static void configure_ppi(void)
    {
        nrfx_err_t err;
        /* STEP 6.1 - Declare variables used to hold the (D)PPI channel number */
        uint8_t m_saadc_sample_ppi_channel;
        uint8_t m_saadc_start_ppi_channel;
       // uint8_t m_saadc_stop_ppi_channel;
    
        /* STEP 6.2 - Trigger task sample from timer */
        err = nrfx_gppi_channel_alloc(&m_saadc_sample_ppi_channel);
        if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_gppi_channel_alloc error: %08x", err);
        return;
        }
    
    err = nrfx_gppi_channel_alloc(&m_saadc_start_ppi_channel);
        if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_gppi_channel_alloc error: %08x", err);
        return;
        }
    
     //   err = nrfx_gppi_channel_alloc(&m_saadc_stop_ppi_channel);
     //   if (err != NRFX_SUCCESS) {
     //   LOG_ERR("nrfx_gppi_channel_alloc error: %08x", err);
     //   return;
     //   }
    
    
        /* STEP 6.3 - Trigger task sample from timer */
        nrfx_gppi_channel_endpoints_setup(m_saadc_sample_ppi_channel, 
        nrfx_timer_compare_event_address_get(&timer_instance, NRF_TIMER_CC_CHANNEL0),
        nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE));
    
        /* STEP 6.4 - Trigger task start from end event */
        nrfx_gppi_channel_endpoints_setup(m_saadc_start_ppi_channel, 
        nrf_saadc_event_address_get(NRF_SAADC, NRF_SAADC_EVENT_END),
        nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_START));
    
        /* STEP 6.6 - End task sample from timer */
       /* nrfx_gppi_channel_endpoints_setup(m_saadc_stop_ppi_channel, 
        nrfx_timer_compare_event_address_get(&timer_instance, NRF_TIMER_CC_CHANNEL0),
        nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_STOP));
    */
        /* STEP 6.5 - Enable both (D)PPI channels */ 
        nrfx_gppi_channels_enable(BIT(m_saadc_sample_ppi_channel));
        nrfx_gppi_channels_enable(BIT(m_saadc_start_ppi_channel));
        // nrfx_gppi_channels_enable(BIT(m_saadc_stop_ppi_channel));
    
        
        
    }
    
    
    int main(void)
    {
       
     
    /* STEP 7 - Retrieve the API-specific device structure and make sure that the device is ready to use  */
    
    if (!device_is_ready(dev_i2c.bus)) {
    	printk("I2C bus %s is not ready!\n\r",dev_i2c.bus->name);
    	return;
    }
        configure_timer();
        configure_saadc();  
        configure_ppi();
       
       
       k_sleep(K_FOREVER);
       
    }
    

Related