I2C - Raspberry Pi, Pico and an Arduino

แชร์
ฝัง
  • เผยแพร่เมื่อ 26 ก.ย. 2024

ความคิดเห็น • 20

  • @Steven-jf4cs
    @Steven-jf4cs 2 ปีที่แล้ว

    Thanks for a well thought and presented tutorial.

  • @thrall1342
    @thrall1342 2 ปีที่แล้ว

    Thanks for the video !
    It's strange how hard this topic is to find online. Do you know whether this has had any updates in the meantime or where one would find these things ?

  • @debsarkar4893
    @debsarkar4893 หลายเดือนก่อน

    Just One Word. He is a Legend

  • @mrezahoseiny9861
    @mrezahoseiny9861 3 ปีที่แล้ว

    Hi Many thanks for very useful tutorial. Just have a question, if we want to setup a cluster of 3 or more (up to 9) Pico devices, then can we use SPI protocol/pins to enable all picos communicate with each other? In such case, do you think does it matter which one should take the master role? so, what if one of the slave wants to send some data to another slave? What if we replace all Picos with Pi zero (w)?

    • @PenguinTutor
      @PenguinTutor  3 ปีที่แล้ว

      SPI is based on controller to peripheral (master / slave) relationship. Peripheral devices would need to communicate via the controller. The controller can probe each device and if one of them wants to transfer data to another then it would send data to the controller, which would then be resent to the other peripheral.
      In I2C direct transfer would be possible, by having multiple controllers. One device would need to become a controller and then communicate with another device. This is done by looking for no traffic on the line, declaring that it wants to be a controller and then taking over the control of the bus. When that device goes quiet another controller can come along. I didn't cover that on the video as it adds complexity.
      Unless you have a lot of data to send then I would say that you are better having one device identified as the controller which polls all the devices for any data. You would then have the devices state where they want to send the data to and the controller would resend the data on.
      The Raspberry Pi would be the same, but you do have the advantage of additional technologies, including Bluetooth (some peer to peer support) or wifi (able to communicate with any other device directly).

  • @valloway
    @valloway ปีที่แล้ว

    Thanks, this helped!

  • @GrantMeStrength
    @GrantMeStrength 3 ปีที่แล้ว +1

    This is a very helpful video - it's hard to find any information on setting up peripheral mode at all! I am trying to set up my Pico in peripheral mode, using the Pi 4 to control it. So far I can see the Pico in i2cdetect, and send date from the Pi to the Pico. However, I cannot get the Pico to return any date - it always leads to time-out or other communication errors (e.g. Read error:[Errno 110] Connection timed out) . I can't see how my code differs from your code. Can I ask what speed you have set the Pi i2c bus to operate at? I have also tried 10K physical pull-up resistors when connecting the Pi and Pico, as well as gpio_pull_up Thanks!
    /* Pico code */
    #include
    #include "pico/stdlib.h"
    #include "hardware/i2c.h"
    #define I2C_ADDR 0x3e // The address of this Pico on the i2c bus
    #define IC2_1 8
    #define IC2_2 9
    int main() {
    // i2c setup
    i2c_init(i2c0, 10000);
    i2c_set_slave_mode(i2c0, true, I2C_ADDR);
    gpio_set_function(IC2_1, GPIO_FUNC_I2C);
    gpio_set_function(IC2_2, GPIO_FUNC_I2C);
    //gpio_pull_up(IC2_1);
    //gpio_pull_up(IC2_2);
    // Data for i2c
    uint8_t rxdata[4];
    uint8_t txdata[2];
    // Counter just to have something to return
    uint8_t counter = 0;
    // Set up LED for status
    const uint LED_PIN = PICO_DEFAULT_LED_PIN;
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);
    uint8_t blink = 0;
    // Do some power-up blinking
    for (int i=0; i1) blink = 0;
    sleep_ms(50);
    }
    // Main loop
    while (true) {
    // Receive data from controller
    // 3 bytes received - byte 0 is cmd (used as lower byte) byte 2 is higher - byte 3 is 0
    // Wait here until some data arrives
    if (i2c_get_read_available(i2c0) < 3) continue;
    i2c_read_raw_blocking (i2c0, rxdata, 3);
    int input_value = rxdata[0]+(rxdata[1]

    • @PenguinTutor
      @PenguinTutor  3 ปีที่แล้ว +1

      I can't see anything obviously wrong with your code. In fact other than using different pins on the Pico (in my case using i2c1 and you are using i2c0) then the I2C part is almost identical. That shouldn't be a problem as long as you've not got anything else on the same bus.
      The speed of the i2c bus is the second parameter to i2c_init = 10000 Hz.
      There is some good documentation at: raspberrypi.github.io/pico-sdk-doxygen/group__hardware__i2c.html#i2c_example
      I used a lower value for the pull-ups. Around 2 to 5kohms is probably better, but over short distances 10k should work fine. Make sure that is connected to 3.3V (either the Raspberry Pi or Pico end).
      When I was testing I found it really useful to get feedback from the Pico. If you setup a UART on the Pico then you can print messages to confirm which part of the code is running. This is why there is additional UART code in my source code.
      The other thing I experimented with was different I2C read and write commands from Python. There are slight differences in the way that they format the instructions, but the ones you have used are the ones that worked for me.
      The other problem I had was that if the write wasn't sent successfully then it would hang at the Pi end, but that is the reason why the write_i2c_block_data is in a try loop and the continue means that it will wait a second before trying again.
      Sorry I can't give anything more definite. My best suggestion is adding the UART code so you can monitor what is happening on the Pico.

    • @GrantMeStrength
      @GrantMeStrength 3 ปีที่แล้ว

      @@PenguinTutor Thanks! Yes, I will set up a UART and monitor the Pico to see what it thinks is going on. Appreciate you taking the time to respond.

    • @GrantMeStrength
      @GrantMeStrength 3 ปีที่แล้ว +1

      @@PenguinTutor Thank you - it's working now. I'm not sure why. It could be that changing the allocated pins around to make room for the UART did something. It could be the UART code itself (unlikely). Or, it's something I did wrong with my choice of power supply - whatever I changed, it's working and I can send/receive data from the Pico in Peripheral mode, so cheers!

    • @PenguinTutor
      @PenguinTutor  3 ปีที่แล้ว +1

      @@GrantMeStrength Glad to hear it's working.

    • @denisbourqui7374
      @denisbourqui7374 3 ปีที่แล้ว +1

      @@GrantMeStrength Had the same problem, really strange. Removing the uart_puts() function made errors again. I added a sleep after the i2c_read_raw_blocking() of 2 ms and now it's working.
      Thank you for the hint :-)

  • @IanSMoyes
    @IanSMoyes 3 ปีที่แล้ว

    Sorry, I'm back again. The Raspberry Pi 4 has 6 UART buses All addressable from the GPIO, not 1.

    • @PenguinTutor
      @PenguinTutor  3 ปีที่แล้ว

      There is only one UART that is enabled by default. The second is used for Bluetooth and the others have to be configured using device tree overlays. The additional UARTs are also multiplexed with the I2C serial connections.

  • @ivanrojas1475
    @ivanrojas1475 2 ปีที่แล้ว +1

    Hi there, thanks for the tutorial, which version of Python are u using in that video and which command u used to install the SMBus library. "Pip3 SMBus or pip SMBus"?

    • @PenguinTutor
      @PenguinTutor  2 ปีที่แล้ว

      I use Python 3 for all my coding. I believe the current version on the Raspberry Pi is Python 3.9.2.
      I used the dpkg version from the Repository. I think SMBus was installed by default on Raspberry Pi OS, if not then you can install using:
      sudo apt install python3-smbus

  • @IanSMoyes
    @IanSMoyes 3 ปีที่แล้ว

    2:47. I'm sorry to pick fault but UART is NOT designed for connecting one pair of devices. With my pathetic Python coding skills I have programmed a Raspberry Pi 4 to communicate with 18 Serial Bus Servos and a Raspberry Pi Pico, as a lighting controller. All you have to do is set each "channel" up with a seperate frame header and all of the devices ignore any communication on the bus that doesn't start with their frame header. Many industrial applications stretch this format to connect MANY devices to the same UART bus.

    • @PenguinTutor
      @PenguinTutor  3 ปีที่แล้ว +1

      UART has a very long history, but was designed for point-to-point communications between two devices.
      It is possible using multiplexing or through agreed communication protocol to have multiple devices on a single connection, but that is not what the UART was originally designed for. In most cases UART is intended for point-to-point communications between one pair of devices.
      If looking to connect to multiple devices using a Raspberry Pi then I would recommend I2C or SPI rather than trying to connect multiple devices to a single UART.

  • @j.p.denoyer7377
    @j.p.denoyer7377 3 ปีที่แล้ว

    No link for pico code. Too blurry to pause the video and type the code.

    • @PenguinTutor
      @PenguinTutor  3 ปีที่แล้ว

      Sorry about that. I'd put a link to the SPI page and not the I2C one.
      I've now updated the description.
      You can download the source code from: www.penguintutor.com/electronics/i2c