Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    LoPy4 - I2C - FRAM Memory - MicroPython Library

    Scheduled Pinned Locked Moved MicroPython
    i2cfram
    27 Posts 4 Posters 165 Views 4 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • E Offline
      Eric Tremblay
      last edited by

      Hi!,
      I am working on a project where I am building an industrial lubrication system controller, my application requires me to have a way to save user-selected parameters for the controller to access and config on boot. I got a custom-made shield for my project that takes a LoPy4 as a controller.
      my shield is equipped with a FRAM - MB85RC256VPF-G-JNERE2 chip SDA->P9, SCL->P10, and Write Protect on P2.
      It's my first project with MicroPython and Pycom. I managed to have all my other functionalities figured out from the documentation except my FRAM.
      I am having problems finding a library or information to help me achieve my results. at this point, I think I may need to write my own firmware which is way above my abilities for now.

      So far in my research, I found a discussion and a link to PeterHinch's Github repo that brings me to a dead end. I was looking at is GitHub projects and i did not see anything referring to FRAM I2C but he has is lots of other amazing work I am glad I found. I think it may have been deleted overtime.
      I also found a Repo from Adafruit but it is for circuit python. https://github.com/adafruit/Adafruit_CircuitPython_FRAM.

      I am wondering if anyone knows about or has seen something that could help me out.

      Thanks
      Eric

      E 1 Reply Last reply Reply Quote 0
      • E Offline
        Elizar @Eric Tremblay
        last edited by

        There is no need for a "firmware" when it comes to using an FRAM. You just need to understand how an I²C bus operates.

        Reading or writing is a straight forward process:

        1. Create and i2c-Object (see example in the pycom docs)
        2. Write data by
        i2c.writeto_mem(ADDR_FRAM, Offset, bytearray(Data), addrsize=16)
        DataByteArray = i2c.readfrom_mem(ADDR_FRAM, Offset, Size, addrsize=16)
        

        Page 8 of the datasheet explains which bytes sequence has to be sent: two bytes for the target address, then the data byte(s).

        Then write yourself two functions WriteFRAM(Offset, Byte) and ReadFRAM(Offset) and you are done. The whole thing may finally have just about 20 lines of code.

        Don't spend too much time on searching for an already working program. Writing your own FRAM code is a very instructive task and will also lead to a better understanding of the possible pitfalls. Just as an example: how do you plan to react when a bus transmission fails due to a temporary electrical interference?

        E 1 Reply Last reply Reply Quote 1
        • E Offline
          Eric Tremblay @Elizar
          last edited by

          @Elizar Thank you for the pointer I was definitely overthinking this. Altho I am still in a bind
          when I call a writeto_mem() method It returns a number of bytes written like intended and then when call readfrom_mem() it returns me a byte array representing all 0, I played with baud rates and also with toggle my Write Protect Pin H to L with no success.
          I'm a bit puzzled but I am learning a lot about i2c so it's a good thing :)

          >>> i2c.init(I2C.MASTER, baudrate=20000)
          >>> i2c.scan()
          [81]
          >>> i2c.writeto_mem(81,3,4,addrsize=8)
          1
          >>> i2c.readfrom_mem(81,2,6,addrsize=8)
          b'\x00\x00\x00\x00\x00\x00'
          >>> i2c.writeto_mem(0x51,0x2,bytearray(1),addrsize=8)
          1
          >>> i2c.readfrom_mem(81,2,6,addrsize=8)
          b'\x00\x00\x00\x00\x00\x00'
          >>> 
          
          1 Reply Last reply Reply Quote 0
          • E Offline
            Eric Tremblay
            last edited by

            I was reading the docs for the FRAM module and saw that the first byte that needs to be sent after the start condition is met is 4 bits for the device address which are always 0101 then 3 bits to address multiple FRAM which mine are not connected. so they are 000. the last bit is 0 for a write operation and 1 for a read operation. when I scan the 12C bus I get back. int81 so 01010001. That's the address that I pass in my writeto_mem. I tried passing a 01010000 thinking maybe it would require a 0 to allow a write operation and it returns a 12C bus error.

            Eric

            J 1 Reply Last reply Reply Quote 0
            • J Offline
              jcaron @Eric Tremblay
              last edited by

              @Eric-Tremblay the address pins on your FRAM module should not be left unconnected. That would result in unpredictable values.

              As specified in the datasheet they should be connected to either VSS (GND) or VDD (power supply) to achieve the right address. In your case they should probably all be connected to GND to achieve 000.

              E 1 Reply Last reply Reply Quote 0
              • E Offline
                Eric Tremblay @jcaron
                last edited by

                @jcaron thanks for the pointer.
                I went back to the person who designed my board and I had an old unfinished copy of the wiring schematics, the pins are actually A0 to VDD, A1, and A2 to VSS. If I read the docs correctly should give me an address of 0101001(0or1). I took a multimeter to confirm everything was effectively like on the schematics and that all pins are ok I also check to make sure my write protect was in fact going from L to H and it seems ok. I'm pretty confident the hardware side is ok.
                when I scan the bus I still get an Int 81 back as an address (01010001). I try to pass in 01010011 but I get an I2C bus exception.

                i Tried different Baudrate. i wonder what i should be running.

                J 1 Reply Last reply Reply Quote 0
                • J Offline
                  jcaron @Eric Tremblay
                  last edited by

                  @Eric-Tremblay An I2C address is 7 bits, in this case it is indeed 81 (0x51, 101 0001): 1010 fixed bits, 001 selected address. This is the address you should provide to the I2C functions, they will add the 0 or 1 to performs reads or writes.

                  The memory address is 16 bits (2 x 8 bits), so you should use addrsize=16..

                  This should write:

                  i2c.writeto_mem(0x51,0x2,bytearray(0x42),addrsize=16)
                  

                  This should read back the data:

                  i2c.readfrom_mem(0x51,0x2,1,addrsize=16)
                  
                  E 1 Reply Last reply Reply Quote 0
                  • E Offline
                    Eric Tremblay @jcaron
                    last edited by

                    @jcaron said in LoPy4 - I2C - FRAM Memory - MicroPython Library:

                    i2c.readfrom_mem(0x51,0x2,1,addrsize=16)

                    Does
                    this make any sense? What should I be using for baudrate?

                    >>> from machine import I2C
                    >>> i2c = I2C(0,I2C.MASTER, baudrate=100000)
                    >>> 
                    >>> i2c.scan()
                    [81]
                    >>> i2c.writeto_mem(0x51,0x2,bytearray(0x42),addrsize=16)
                    66
                    >>> i2c.readfrom_mem(0x51,0x2,1,addrsize=16)
                    b'\x00'
                    >>> 
                    
                    E 1 Reply Last reply Reply Quote 0
                    • E Offline
                      Eric Tremblay @Eric Tremblay
                      last edited by

                      Just check my WP pin status to make sure it was "L"

                      >>> wp = Pin("P2", mode = Pin.OUT)
                      >>> 
                      >>> wp()
                      0
                      >>> i2c.writeto_mem(0x51,0x2,bytearray(0x42),addrsize=16)
                      66
                      >>> i2c.readfrom_mem(0x51,0x2,1,addrsize=16)
                      b'\x00'
                      >>> 
                      
                      J 1 Reply Last reply Reply Quote 0
                      • J Offline
                        jcaron @Eric Tremblay
                        last edited by

                        @Eric-Tremblay do you have pull ups on SCL and SDA? Is the chip powered at 3.3V (rather than 5V)?

                        Do you have a scope you could use to capture SCL and SDA? Have you checked actual voltage on WP?

                        E 1 Reply Last reply Reply Quote 0
                        • E Offline
                          Eric Tremblay @jcaron
                          last edited by

                          @jcaron

                          There is 100k pull up on both SDA and SCL I checked voltage on wp and i get 3.3vdc when H and 0 when L

                          J 2 Replies Last reply Reply Quote 0
                          • J Offline
                            jcaron @Eric Tremblay
                            last edited by

                            @Eric-Tremblay can you check if VDD is 3.3V as well? Can you capture an exchange with a scope or other tool?

                            Just for reference, can you run:

                            i2c.readfrom_mem(0x51,0x0,32768,addrsize=16)
                            

                            That should read the whole memory. It would be interesting to see if there’s something other than zeroes in the output.

                            E 1 Reply Last reply Reply Quote 0
                            • E Offline
                              Eric Tremblay @jcaron
                              last edited by

                              @jcaron i dont have a scope but i think i may need one to help me troubleshoot this out. Will see if i can buy one. There is 13.3 on the VDD

                              E E 2 Replies Last reply Reply Quote 0
                              • E Offline
                                Eric Tremblay @Eric Tremblay
                                last edited by

                                Sorry typo i meant 3.3

                                J 1 Reply Last reply Reply Quote 0
                                • J Offline
                                  jcaron @Eric Tremblay
                                  last edited by

                                  @Eric-Tremblay you may want to try the “base” I2C commands instead of the memory commands, there may be something slightly different in the implementation which isn’t immediately apparent and wouldn’t be compatible with the *mem functions.

                                  Use:

                                  i2c.writeto(0x51, bytes(0,0,1,2,3,4))
                                  

                                  This should write bytes 1,2,3,4 at addresses 0,1,2,3.

                                  Then:

                                  i2c.writeto(0x51, bytes(0,0))
                                  

                                  This should reset the pointer to address 0

                                  Then:

                                  i2c.readfrom(0x51, 4)
                                  

                                  To read back the data.

                                  The result of the full read would be interesting as well.

                                  E 1 Reply Last reply Reply Quote 0
                                  • E Offline
                                    Elizar @Eric Tremblay
                                    last edited by Elizar

                                    @Eric-Tremblay Since the I²C bus can be clocked very slow, say 1 Hz (1 clk pulse per second), you may not need a scope. You can use two simple LEDs (each in series with a resistor of about 5 kohm. The LEDs will be a bit dark but not load the bus too much). Connect the LEDs from SDA via resistor to GND and do the same for SCL.

                                    Then you can follow the signals on the I²C bus and see what happens. Pay special attention to the final bit of each transmitted byte (the acknowledge bit). Then compare the results with the waveforms from the datasheet.

                                    Nevertheless, a scope with at least two channels would make the observation much, much simpler. If you can afford it, buy it. It will save you many painful hours of guessing.

                                    J robert-hhR 2 Replies Last reply Reply Quote 1
                                    • J Offline
                                      jcaron @Elizar
                                      last edited by

                                      @Elizar interesting idea! You probably want to use a camera to record that, though, it’ll make transcription easier.

                                      1 Reply Last reply Reply Quote 0
                                      • robert-hhR Offline
                                        robert-hh @Elizar
                                        last edited by

                                        @Elizar There are low cost logic analyzers available for about 10€, with 8 channels at 24MHz max sampling rate. Software is available as supporting the most common serial protocols. For I2C, UART, SPI that is extremely valuable. It does not help you though when there are analogue problems like with voltage levels.

                                        1 Reply Last reply Reply Quote 1
                                        • E Offline
                                          Eric Tremblay @jcaron
                                          last edited by

                                          @jcaron

                                          Base i2c gives me and TypeError when I pass in a byte array

                                          >>> i2c.writeto(0x51, 2,)
                                          1
                                          >>> i2c.readfrom(0x51, 5)
                                          b'\x00\x00\x00\x00\x00'
                                          >>> i2c.writeto(0x51, bytes(0,0,1,2,3,4))
                                          Traceback (most recent call last):
                                            File "<stdin>", line 1, in <module>
                                          TypeError: wrong number of arguments
                                          >>> 
                                          

                                          This returns the entire memory all zero

                                          >>> i2c.readfrom_mem(0x51,0x0,32768,addrsize=16)
                                          b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\........   Returns all memory 
                                          
                                          1 Reply Last reply Reply Quote 0
                                          • J Offline
                                            jcaron @Eric Tremblay
                                            last edited by

                                            @Eric-Tremblay 100K may be too weak (i.e. the numerical value is too high) for the pull-up. Can you easily change those to a different value? Usual recommandations are 4.7K or 10K, though some use much lower values.

                                            It seems weird that the scan still works if that is indeed the problem, but it might be an edge case due to rise/fall times.

                                            You may also want to try different speeds to see if that changes anything. Lower speeds are less sensitive to pull-up issues.

                                            E 2 Replies Last reply Reply Quote 0

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post

                                            Pycom on Twitter

                                            Pycom