This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

First I2C code on nRF Connect, I think I'm close

Crawling up the learning curve here, doing my best to solve my own problems, but I'm down to just permuting things on this one and I'm not making much progress and all the examples I can find just seem a  little different to what I want to do..
Trying to get an nRF52833 dev kit talking I2C to an eeprom.

Overlay file

&i2c0 {
  compatible = "nordic,nrf-twi";
  status = "okay";
  sda-pin = <26>;
  scl-pin = <27>;
  clock-frequency = <100000>;
   my_eeprom:nRF52833@28 {
     status = "okay";
     reg = <0x28>;
     label = "config_eeprom";
   };
 
};

proj.conf

CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_L2CAP_TX_BUF_COUNT=5
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Woggle"
CONFIG_BT_DEVICE_APPEARANCE=962
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_I2C=y
CONFIG_GPIO=y
# This example requires more workqueue stack

CONFIG_LOG=y

my code

#define twi0 DT_LABEL(DT_ALIAS(my_eeprom))

voi dmain(void)
{
        int err = 0;

   
    LOG_INF("Starting LiftlogDX\n");

    //init I2C
    const struct device *i2cdev=device_get_binding(twi0);
    i2c_configure(i2cdev, I2C_SPEED_SET(I2C_SPEED_STANDARD));

The Error:
DT_N_ALIAS_my_eeprom_P_label" is undefined 

I feel close, but it's eluding me..
Tips?

  • Hello Paul Kelly,

    Regarding your shared code excerpts, your device tree source looks good and so too your Kconfig settings from project source 'prj.conf'.  In your void main() routine, and the pound define involving Zephyr macros just above it, it appears that you are creating a device pointer ( I mean a C pointer to a Zephyr device that is your EEPROM ) and then you are calling a routine to set the I2C peripheral's clock rate using that EEPROM device pointer.

    I believe you may want or need to set I2C clock speed via the I2C device structure, or pointer to it, rather than the EEPROM device structure.

    You have the option to set your chosen I2C peripheral instance clock or bus speed in your board's DTS file, in the way that Nordic's nRF9160 DTS board file sets i2c2 clock frequency, using device tree source.  This obviates the need to call API routine i2c_configure().

    And actually on review I see you already have a DTS line to set I2C clock speed.  You can change the stanza 'clock-frequency = <100000>;' as needed.

    So a next question as you "try to get project talking with an EEPROM" would be, do you have a driver available for your particular EEPROM?  Most likely if you have one it will be a Zephyr "out of tree" driver.  Zephyr's "in tree" drivers, maybe you know this, are generally for peripherals which are found on most or many microcontrollers, e.g. peripherals like UART, I2C, ADC.  Peripherals which are most often on chip.  Your prj.conf line 'CONFIG_I2C=y' enables the compiling of Zephyr's in tree I2C drivers.  If your EEPROM has a driver already available, an initializing routine there will assign the i2c0 device you want to express in your line '#define twi0 DT_LABEL(DT_ALIAS(my_eeprom))'.  Also, if you have and can enjoy the EEPROM driver already written, that will shield you from having to call the I2C API routines directly.  The out-of-tree driver API will have things like "write_config_register()", "read_page()", etc, and your main line code won't have to deal with or know about the lower level bus protocol and I2C details.

    If the manufacture of your EEPROM and larger open source community have not yet written a driver for it, you have choices.  You could write your own out-of-tree driver -- not trivial! -- but an effort with many potential future returns if you plan on re-using and sharing your code, and developing long term with Zephyr.  You could also more or less "bit bang" your driver in main line code.  But in that case, the code is messier in its factoring, and you cannot easily share or port that kind of driver implementation to others to use, or even to other projects of your own.  You would then also miss out on some really cool features explained in Marti Bolivar's Zephyr and Device Tree Tutorial, especially some of the flexible things we can do with multiple device instances as described at about the 40 minute mark in this video.

    In your code above I'm not able to answer specifically why DT_N_ALIAS_my_eeprom_P_label is undefined.  I still have trouble often when tracking down the same kind of error when I amend project device tree sources.  But I hope this answer helps in the broader sense.  You are certainly close to setting your needed I2C clock speed.  The bigger question will probably be whether you have an EEPROM driver available or must write one.

    Take care,

    - Ted

  • Hi,

    "my_eeprom" is a node label, not an alias. Replace DT_ALIAS() with DT_NODELABEL().

  • So here's where I got to:
    I went through the fujitsu example and got my head around the difference between writing a driver and just spitting I2C out. You don't need the second bit in the overlay file:

    my_eeprom:nRF52833@28 {
         status = "okay";
         reg = <0x28>;
         label = "config_eeprom";
       };

    If you just want to drive the bus directly.

    Then I went over the tutorial and got aliases an nodelabels back in my head and managed to get a reference to the device. This got me past the problem that generated this post.

    Next I wrote a simple, blocking, library and that more or less just worked.

    So I'm moving forward again!

    I'm storing a whole bunch of config information on the eeprom, The product can't really do anything until this is loaded, so a blocking implementation is mostly OK. I can wear some delays on writes too.  

    I'll revisit this later and get it playing nice with threads...
    Many thanks to all...

Related