earlephilhower / arduino-pico

Raspberry Pi Pico Arduino core, for all RP2040 boards
GNU Lesser General Public License v2.1
1.87k stars 388 forks source link

Default pins for Serial/SPI/I2C not set properly #92

Closed PreciousRoy0 closed 3 years ago

PreciousRoy0 commented 3 years ago

I was having issues getting any i2c sensor to work so after a lot of testing and searching i came across this issue witch is unrelated but did help me https://github.com/earlephilhower/arduino-pico/issues/38#issuecomment-808835731 the tester that was pointed out also did not work.

no i saw that PICO_DEFAULT_I2C_SCL_PIN and PICO_DEFAULT_I2C_SDA_PIN ar defined but when correctly connected it does not work.

i fixed this by setting the pins at the beginring of my program Wire.setSCL(PICO_DEFAULT_I2C_SCL_PIN);//gp5 Wire.setSDA(PICO_DEFAULT_I2C_SDA_PIN);//gp4

now i don't know if this is an issue but seeing that they are defined you would expect it to use them if not explicitly told to use different pins right? I figured i would let you know.

Bodmer commented 3 years ago

By default the first available I2C interface was used: GPIO pin 0 = SDA GPIO pin 1 = SCL

So this is inconsistent with the PICO_DEFAULT_I2C_xxx_PINs unless there has been a recent update?

blurfl commented 3 years ago

The doc for Wire (I2C Master and Slave) is clear and concise. Adding the default values for sda and scl for the two I2C Devices would make it even better.

Bodmer commented 3 years ago

Making the library allocate pin 4 and 5 as default is required. This is then be consistent with the official RPi Pico pinout documentation. image

setSDA() etc should only be required to "allow" a user to move the pins, not set the defaults to the correct ones...

earlephilhower commented 3 years ago

Re: that picture, if you look at the full image you'll see that I2C0 SDA is replicated 3-4 times since it's really just showing possible GPIO mux options. At least, every pinout diagram I've seen is that way...

That said, using whatever defaults are in the SDK is the right thing to do, but not done yet. So some define needs to be added in the variant.h and it needs to be used in the object constructors for UART0/1, SPI0/1, and I2C0/1.

Bodmer commented 3 years ago

Yes, this is the official RPi Pico pinout. Sadly the default colour scheme is subtle: image

earlephilhower commented 3 years ago

:) I don't think I ever saw the official RPI foundation sheet until you pointed me to it just now. Weird, the GOOG gives everything but that document in my experience.

Anyway, it is a bug and we should be using the board-specific (variant) defaults. For now, the workaround by @PreciousRoy0 is safe and will continue to work even after this is fixed.

Bodmer commented 3 years ago

Each board supplier has it's own defaults, pins are set here in the SDK.

So that makes things a bit easier as the #defines are all there for the variants.

Bodmer commented 3 years ago

You would think the default #defines would be in the form RP2040... but it seems other board suppliers have to use PICO...

Some board suppliers appear to have allocated illegal pins to some function... oh well!

earlephilhower commented 3 years ago

The existing SDK pin board.h files are not 100%. They're maturing and doing PRs on them in the main pico-sdk.

JoshuaPeddle commented 3 years ago

Yeah I've just been using .setSCL() and .setSDA() for every i2c connection and SPI.setRX... for SPI as a workaround for this. So far it's working great with older librarys. I've currently got a Gy-91 module(I2C0), NRF24(SPI0) module, a GPS(UART1) and a PCA9685(I2C1) all running on the same pico.

vslinuxdotnet commented 3 years ago

About this problem, I have a problem with U8x8lib in SPI, in my 256x64 oled display the HW SPI dont work, I need to set SW SPI, by set the pins to get it works, but its some kind of slow speed... With overclock to 250mhz, do better performance, but a little far way from my Arduino nano in SPI.

JoshuaPeddle commented 3 years ago

About this problem, I have a problem with U8x8lib in SPI, in my 256x64 oled display the HW SPI dont work, I need to set SW SPI, by set the pins to get it works, but its some kind of slow speed... With overclock to 250mhz, do better performance, but a little far way from my Arduino nano in SPI.

What's the issue with the HwSPI? You might be able to tweak your SwSPI settings a little to get better preformance but the time may be better spent getting the HwSPI going.

earlephilhower commented 3 years ago

@vslinuxdotnet HW SPI is working for folks and there is even an optimized Adafruit GFX lib set: https://github.com/earlephilhower/arduino-pico/discussions/69

Bodmer commented 3 years ago

The HW SPI works but note that the default SPI pins are:

MISO: Pico pin D0 (GPIO 0)
MOSI: Pico pin D3 (GPIO 3)
SCK/SCLK: Pico pin D2 (GPIO 2) 
prenticedavid commented 3 years ago

EDIT. I have rewired "my current" Protoshield and changed my suggested schemes.

I2C defaults to I2C0 on GP4-5. changed SPI defaults to SPI0 on GP0-3. changed

Some alternative schemes to suit Uno Shields. Note that I have the 3 Analog channels on A1-A3. This is because Mcufriend Touch pins are on A1/2 or A2/3

PWM can be done on every pin. I suspect PCINT too.

Once that a preferred scheme is chosen it is straightforward to create a variant/pins_arduino.h to map GPxx to Dxx pins.
define the default I2C and SPI pin macros SPI.h and Wire.h can use the DEFAULT_xxx

Please offer comments, opinions, improvements, ... Which GPxx pins should go to D0, D1 ?

The third option looks promising. I might wire up a Protoshield.

################ MY CURRENT #################################
                             SCL o GP4 | I2C0
                             SDA o GP5 |
                            AREF o 
     o A6                    GND o 
     o IOREF                  13 o GP2  | SPI0 **rewired** 
     o RESET                  12 o GP0  | **rewired**
     o 3V3                    11 o GP3  | **rewired**
     o 5V                     10 o GP21 |
     o GND                     9 o GP7
     o GND                     8 o GP6
     o Vin                     7 o GP13
     o A7                      6 o GP12
GP16 o A0                      5 o GP11
GP26 o A1                      4 o GP10
GP27 o A2                      3 o GP9
GP28 o A3                      2 o GP8
GP22 o A4                      1 o 
GP14 o A5         GP2          0 o 
                 o o o GP0  **rewired**
                 o o o | SPI0
                  GP3

#################### 2 I2C, SPI0 #############################
                             SCL o GP5 | I2C0  **changed**
                             SDA o GP4 | **changed**
                            AREF o 
     o A6                    GND o 
     o IOREF                  13 o GP2 | SPI0
     o RESET                  12 o GP0 | **changed**
     o 3V3                    11 o GP3 |
     o 5V                     10 o GP1 | **changed**
     o GND                     9 o GP7
     o GND                     8 o GP6
     o Vin                     7 o GP13
     o A7                      6 o GP12
GP14 o A0                      5 o GP11
GP26 o A1                      4 o GP10
GP27 o A2                      3 o GP9
GP28 o A3                      2 o GP8
GP18 o A4 | I2C1               1 o 
GP19 o A5 |       GP2          0 o 
                 o o o GP0  **changed**
                 o o o | SPI0
                  GP3

################# 2 I2C, 2 SPI ################################
                             SCL o GP5 | I2C0 **changed**
                             SDA o GP4 | **changed**
                            AREF o 
     o A6                    GND o 
     o IOREF                  13 o GP10 | SPI1
     o RESET                  12 o GP12 |
     o 3V3                    11 o GP11 |
     o 5V                     10 o GP13 |
     o GND                     9 o GP9
     o GND                     8 o GP8
     o Vin                     7 o GP21
     o A7                      6 o GP20
GP14 o A0                      5 o GP19
GP26 o A1                      4 o GP18
GP27 o A2                      3 o GP17
GP28 o A3                      2 o GP16
GP6  o A4 | I2C1               1 o 
GP7  o A5 |       GP2          0 o 
                 o o o GP0 **changed**
                 o o o | SPI0
                  GP3

#################################################

David.

Bodmer commented 3 years ago

The pin name to GP and default interface mapping varies between board producers (Adafruit Pico mapping is different to RPi Pico, and Sparkfun Pro Micro). Arduino have not released their mapping so it is going to be guesswork what they will do but Dx to GPx seems sensible.

The only common mappings so far seem to be TX0 and RX0 (DO, D1) to GP0 and 1 which is sensible. There are only 4 external ADC input pins, Sparkfun have mapped A0-3 to GP26-29 on the Pro Micro variant which seems very sensible, however the Pico uses GP29 for the supply voltage monitor and it is thus not easily available (but hackable with some PCB surgery to the ADC_REF pin).

For UNO TFT shields I would map the TFT data bus to consecutive GP pins to prevent the need for data bit swapping.

prenticedavid commented 3 years ago

Yes, I agree. It would be nice to know what pin mapping an Arduino board proposes. Mostly for their choice of default Wire and default SPI pins.

Then libraries and existing code will port very easily. Users do not mind configuring a CS pin. But you can't expect them to guess hardware MISO, MOSI, SCK pins.

i.e. this comes down to defining PIN_I2C_SDA, PIN_SPI_MOSI, etc in variant/pins_arduino.h or variant/variant.h

Wire.h and SPI.h libraries will use the default pins. But provide extra optional methods for changing pins e.g. Wire.setSDA()

Regarding mapping the TFT data bus. Consecutive GP pins are handy but not essential. ARM chips have a barrel-shifter. Teensy 3.x and 4.x boards provide standard Dx pins from random GPIO port pins. Nucleo64, Nucleo144 boards provide standard Dx pins from random GPIO port pins.

stuartdd commented 3 years ago

Hi. Trying to get I2C to work with an SSD1306 display. At the moment it works on GP0 and GP1 but I need it to work on different pins.

I am using Adafruit_SSD1306.h and the display is created using then following code:

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, 4);

I can see from your docs that I need to use

Wire.setSCL(MY_SCL_PIN);
Wire.setSDA(MY_SDA_PIN);

The docs indicate I have to do this before Wire.begin() but I do not have access to that.

Is there a simple way to re-define the default pins.

Sorry my c++ is very rusty and I have have tried various things like re-defining PICO_DEFAULT_I2C_SCL_PIN and PICO_DEFAULT_I2C_SDA_PIN but this has no impact. I need to create and configure Wire before passing it to Adafruit_SSD1306 display but cannot see how this is done.

It's such a relief to be back in Arduino-land with the RP2040 :-) This chip is brilliant but the standard cpp SDK is really a steep learning curve. MicroPython is much easier but who wants to code in Python!

I have been using Arduino for years and the work you have done here is really GREAT. Thank you very much.

Regards

Stuart

prenticedavid commented 3 years ago

Please note that I have only had Pico board for 1 day. I have a lot to learn.

I suggest that pins_arduino.h should contain default I2C pins e.g. put in variant/generic/common.h for the moment:

#define PIN_WIRE_SDA         (4) //.kbv
#define PIN_WIRE_SCL         (5) //.kbv

static const pin_size_t SDA = PIN_WIRE_SDA; //.kbv
static const pin_size_t SCL = PIN_WIRE_SCL; //.kbv

and edit C:\Users...\AppData\Local\Arduino15\packages\rp2040\hardware\rp2040\1.0.3\libraries\Wire\Wire.cpp

TwoWire Wire(i2c0, SDA, SCL); //.kbv
TwoWire Wire1(i2c1, 2, 3);

Ideally default SDA1 and SCL1 macros should also go into variant

This change makes Adafruit_SSD1306 library work ok for I2C. SPI displays are not working yet for Adafruit_SSD1306

SPI displays "work" for Adafruit_ILI9341 but are appallingly SLOW.

David.

blurfl commented 3 years ago

I've used one of the other pairs of I2C0 (4,5) by putting the calls in setup() just before the display.begin() call in the sketch.

  Wire.setSDA(4);
  Wire.setSCL(5);
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);

Haven't looked at getting the library to use one of the I2C1 pairs, though.

earlephilhower commented 3 years ago

@stuartdd , what @blurfl did is the right thing for your issue. You don't need to call it immediately before Wire.begin, just anytime in your code. The setXXX calls just set a class variable that's only used in the begin() method.

As for the whole "Which pinout to use" that's definitely on a per-board basis. The Arduino Connect Pico RP2040 board is not going to be the standard for the Rpi Pico board, for example, because the Arduino board has tons of IO hooked directly to onboard sensors and the onboard ESP32.

And the PICO_DEFAULT_XXX macros are not used by the core. The equivalent Arduino-cent4ric macros need to be defined in the variant headers and then used in the object creations. Not rocket science, but not yet there today.

Bodmer commented 3 years ago

@prenticedavid Try the update here and here. The problem is that the SDK SPI write function is slow due to support for bursts, Earle's wrapper is fine but inherits the slow SDK code. The changes should not change compatiblity but give up to 12x performance improvement (on par with ESP32 or better). Adafruit are waiting for the "official" Arduino core package before accepting pull requests.

stuartdd commented 3 years ago

Thanks @blurfl and @earlephilhower seems so simple when you know what you are doing.

Regards

Stuart

prenticedavid commented 3 years ago

Arduino has released its MBED_PICO Core.

variant/pins_arduino.h say:

// Serial
#define PIN_SERIAL_TX (0ul)
#define PIN_SERIAL_RX (1ul)

// SPI
#define PIN_SPI_MISO  (4u)
#define PIN_SPI_MOSI  (3u)
#define PIN_SPI_SCK   (2u)
#define PIN_SPI_SS    (5u)

// Wire
#define PIN_WIRE_SDA        (6u)
#define PIN_WIRE_SCL        (7u)

#define SERIAL_HOWMANY      1
#define SERIAL_CDC          1
#define SPI_HOWMANY     (1)
#define WIRE_HOWMANY    (1)

So they make no attempt to support multiple SPI, Wire, ... and default to UART0, spi0, i2c1

I suggest that we follow the same plan for the Pico board. Which should make existing Arduino programs port painlessly to the Pico. But still allow custom use of different pins and also spi1, i2c0 if required.

Yes, Bodmer was correct. There is no GPxx to Dxx mapping. There are no Dxx symbols. GP23 is just a plain number 23.

David.

Bodmer commented 3 years ago

A0-3 are defined as GP26-29 as anticipated.

earlephilhower commented 3 years ago

103 implements the default pinout used on the RPI Pico datasheet and the Adafruit Feather RP2040 schematic.

These may not match the Arduino MBED core's chosen ones. My eyeballing seemed to show they chose non-RPI Pico pinouts for the SPI0 device. I can't say why that would be, but I'll stick w/the RPi guys' setup unless a consensus forms around others.

Anyone who can give it a try and report back, would be much appreciate.

nsilveri commented 3 years ago

Hi, I havo a code like this where i need to controll a rover with a PCA9685 and a vl53l0x for obstacle avoidance. I try to config i2c0 (PCA9685 ) and i2c1 (vl53l0x) but it doesn't work, i received acks on Serial but the motors doesn't works, i tried to run i2c_scanner too but it no find the PCA (that works with python code) and vl53l0x. Any solutions? Thanks

P.S. all my code was working good on an Arduino Nano, but i try to pass to Pico for a more power and memory space

#include <Wire.h>
  #include <Adafruit_PWMServoDriver.h>
  Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
  ...
  ...
  ...

  void setup() {
    Serial.begin(9600);
    Wire.setSDA(2);
    Wire.setSCL(3);
    Wire1.setSDA(4);
    Wire1.setSCL(5);
    Wire.begin();
    Wire1.begin();
    Serial.println( F("..."));
    Serial.println( F("..."));
    Serial.println( F("..."));
    pwm.begin();
    pwm.setOscillatorFrequency(27000000);
    pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
    ...
    ...
    ...

  }

  void loop() {
    // put your main code here, to run repeatedly:

  }
earlephilhower commented 3 years ago

First of all, I would not use the Adafruit PWM servo driver, it doesn't know about the RP2040. There is a Servo class which used the PIO hardware to run up to 8 servos w/0ns jitter and 0 CPU cycles.

Secondly, you're assigning invalid pins to the I2C ports. The RP2040 can't place them anywhere, only at specific pins as shown on the graphic in the docs. The setSDA/SCL() calls return bools which you're ignoring which indicate this failure.

Wire = I2C0 => SDA can be {0, 4, 8, 12, 16, 20, 24, 28}, for example.

earlephilhower commented 3 years ago

Also, you can enable full debugging in the IDE which will print error messages to the Serial port when illegal pins are selecter, amongst other useful things.

nsilveri commented 3 years ago

Also, you can enable full debugging in the IDE which will print error messages to the Serial port when illegal pins are selecter, amongst other useful things.

Thanks a lot, i will try