Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for RP2040 / Pico #115

Closed
mattjlewis opened this issue Jul 21, 2021 · 13 comments · Fixed by #117
Closed

Support for RP2040 / Pico #115

mattjlewis opened this issue Jul 21, 2021 · 13 comments · Fixed by #117

Comments

@mattjlewis
Copy link

I believe this to be the board definition for a standard Raspberry Pi Pico device, it would be great if this could be incorporated:

 // Raspberry Pi Pico
 // https://datasheets.raspberrypi.org/pico/Pico-R3-A4-Pinout.pdf
 #elif defined(TARGET_RP2040) || defined(TARGET_RASPBERRY_PI_PICO)
 #define TOTAL_ANALOG_PINS       4
 #define TOTAL_PINS              30
 #define VERSION_BLINK_PIN       LED_BUILTIN
 #define IS_PIN_DIGITAL(p)       (((p) >= 0 && (p) < 23) || (p) == LED_BUILTIN)
 #define IS_PIN_ANALOG(p)        ((p) >= 26 && (p) < 26 + TOTAL_ANALOG_PINS)
 #define IS_PIN_PWM(p)           digitalPinHasPWM(p)
 #define IS_PIN_SERVO(p)         (IS_PIN_DIGITAL(p) && (p) != LED_BUILTIN)
 // From the data sheet I2C-0 defaults to GP 4 (SDA) & 5 (SCL) (physical pins 6 & 7)
 // However, v2.3.1 of mbed_rp2040 defines WIRE_HOWMANY to 1 and uses the non-default GPs 6 & 7:
 //#define WIRE_HOWMANY	(1)
 //#define PIN_WIRE_SDA            (6u)
 //#define PIN_WIRE_SCL            (7u)
 #define IS_PIN_I2C(p)           ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL)
 // SPI-0 defaults to GP 16 (RX / MISO), 17 (CSn), 18 (SCK) & 19 (TX / MOSI) (physical pins 21, 22, 24, 25)
 #define IS_PIN_SPI(p)           ((p) == PIN_SPI_SCK || (p) == PIN_SPI_MOSI || (p) == PIN_SPI_MISO || (p) == PIN_SPI_SS)
 // UART-0 defaults to GP 0 (TX) & 1 (RX)
 #define IS_PIN_SERIAL(p)        ((p) == 0 || (p) == 1 || (p) == 4 || (p) == 5 || (p) == 8 || (p) == 9 || (p) == 12 || (p) == 13 || (p) == 16 || (p) == 17)
 #define PIN_TO_DIGITAL(p)       (p)
 #define PIN_TO_ANALOG(p)        ((p) - 26)
 #define PIN_TO_PWM(p)           (p)
 #define PIN_TO_SERVO(p)         (p)

I've done basic tests with the above using DIGITAL_INPUT, DIGITAL_OUTPUT and I2C.

@pgrawehr
Copy link
Contributor

@mattjlewis : Thanks for providing and testing this. I'll be looking forward to a PR. Did you use the Arduino IDE with https://github.com/earlephilhower/arduino-pico for programming the pico or some other way?

@mattjlewis
Copy link
Author

It's great to see new features being added to Firmata.
I installed support for "Arduino Mbed OS RP2040 Boards" using the Arduino Boards Manager in the Arduino IDE. Annoyingly I can't get ConfigurableFirmata to work (apologies, I thought that was the version that I'd used) - it works with StandardFirmata / StandardFirmataPlus. I'll do some further investigation.

/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.cpp: In member function 'void FirmataClass::sendStringf(FlashString*, int, ...)':
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.cpp:500:5: error: 'va_start' was not declared in this scope
     va_start (va, sizeOfArgs);
     ^~~~~~~~
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.cpp:500:5: note: suggested alternative: 'stat'
     va_start (va, sizeOfArgs);
     ^~~~~~~~
     stat
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.cpp:520:5: error: 'va_end' was not declared in this scope
     va_end (va);
     ^~~~~~
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.cpp:520:5: note: suggested alternative: 'rand'
     va_end (va);
     ^~~~~~
     rand
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp: In member function 'virtual boolean Frequency::handleSysex(byte, byte, byte*)':
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:110:77: error: no matching function for call to 'attachInterrupt(byte&, void (&)(), int&)'
       attachInterrupt(digitalPinToInterrupt(pin), FrequencyIsr, internalMode);
                                                                             ^
In file included from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/variants/RASPBERRY_PI_PICO/pinmode_arduino.h:30:0,
                 from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/Arduino.h:26,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/utility/Boards.h:23,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.h:18,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:19:
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/Common.h:111:6: note: candidate: void attachInterrupt(pin_size_t, voidFuncPtr, PinStatus) <near match>
 void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode);
      ^~~~~~~~~~~~~~~
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/Common.h:111:6: note:   conversion of argument 3 would be ill-formed:
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:110:77: error: invalid conversion from 'int' to 'PinStatus' [-fpermissive]
       attachInterrupt(digitalPinToInterrupt(pin), FrequencyIsr, internalMode);
                                                                             ^
In file included from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/Arduino.h:114:0,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/utility/Boards.h:23,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.h:18,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:19:
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/overloads.h:35:6: note: candidate: void attachInterrupt(PinName, voidFuncPtr, PinStatus) <near match>
 void attachInterrupt(PinName interruptNumber, voidFuncPtr callback, PinStatus mode);
      ^~~~~~~~~~~~~~~
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/overloads.h:35:6: note:   conversion of argument 3 would be ill-formed:
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:110:77: error: invalid conversion from 'int' to 'PinStatus' [-fpermissive]
       attachInterrupt(digitalPinToInterrupt(pin), FrequencyIsr, internalMode);
                                                                             ^
In file included from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/ArduinoAPI.h:29:0,
                 from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/Arduino.h:27,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/utility/Boards.h:23,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.h:18,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:19:
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/Interrupts.h:38:27: note: candidate: template<class T> void arduino::attachInterrupt(pin_size_t, arduino::voidTemplateFuncPtrParam<T*>, PinStatus, T*)
 template<typename T> void attachInterrupt(pin_size_t interruptNum, voidTemplateFuncPtrParam<T*> userFunc, PinStatus mode, T* param) {
                           ^~~~~~~~~~~~~~~
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/Interrupts.h:38:27: note:   template argument deduction/substitution failed:
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:110:77: note:   candidate expects 1 argument, 0 provided
       attachInterrupt(digitalPinToInterrupt(pin), FrequencyIsr, internalMode);
                                                                             ^
In file included from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/ArduinoAPI.h:29:0,
                 from /Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/Arduino.h:27,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/utility/Boards.h:23,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/ConfigurableFirmata.h:18,
                 from /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:19:
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/Interrupts.h:21:27: note: candidate: template<class T> void arduino::attachInterrupt(pin_size_t, arduino::voidTemplateFuncPtrParam<T>, PinStatus, T&)
 template<typename T> void attachInterrupt(pin_size_t interruptNum, voidTemplateFuncPtrParam<T> userFunc, PinStatus mode, T& param) {
                           ^~~~~~~~~~~~~~~
/Users/xxx/Library/Arduino15/packages/arduino/hardware/mbed_rp2040/2.3.1/cores/arduino/api/Interrupts.h:21:27: note:   template argument deduction/substitution failed:
/Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata/src/Frequency.cpp:110:77: note:   candidate expects 1 argument, 0 provided
       attachInterrupt(digitalPinToInterrupt(pin), FrequencyIsr, internalMode);
                                                                             ^
Multiple libraries were found for "ConfigurableFirmata.h"
 Used: /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata
 Not used: /Users/xxx/Documents/Arduino/libraries/FirmataWithDeviceFeature
 Not used: /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata_2_10_1
 Not used: /Users/xxx/Documents/Arduino/libraries/ConfigurableFirmata.official
exit status 1
Error compiling for board Raspberry Pi Pico.

@mattjlewis
Copy link
Author

mattjlewis commented Jul 24, 2021

The first problem was fixed by adding #include <stdarg.h> within the Pico block in Boards.h. The attachInterrupt error is related to Frequency - temporarily removing Frequency.cpp and Frequency.h allowed me to upload ConfigurableFirmata to my Pico. The Pico defines attachInterrupt as follows which does match that expected by ConfigurableFirmata:

void attachInterrupt(PinName interruptNumber, voidFuncPtr callback, PinStatus mode);

@PizzaProgram
Copy link
Contributor

PizzaProgram commented Feb 2, 2025

@mattjlewis May I ask:

How to read built-in Temperature ?

Tried to read A0, A1, A2 -> all = ca. 220, A3 = ca. 510 (All 4 values are changing a bit rapidly. )

If I use this math formula for A3 (510) the result is ca. -400.

PS: I'm using Node-Red's built in "Arduino" module for reading the values.

Image

@pgrawehr
Copy link
Contributor

pgrawehr commented Feb 2, 2025

@PizzaProgram It seems that the python library you copied that information from does some stuff "behind the scenes". If you look at this code, you see that an additional adc_set_temp_sensor_enabled(true) is required to make sure that the temperature sensor is routed to the ADC4 pin. You probably need that, maybe even together with the adc_init() somewhere in the startup code. You might want to test whether you get reliable analog input from any pin as well (connect a potentiometer or a resistor bridge to one of those pins).

@PizzaProgram
Copy link
Contributor

PizzaProgram commented Feb 4, 2025

@pgrawehr Thank you for the tips and the quick answer!

I've copied these lines to the init void, but nothing changed:

void setup()
  initTransport();
  Firmata.sendString(F("Booting device. Stand by..."));
  initFirmata();

  adc_init();
  adc_set_temp_sensor_enabled(true);
  // Select ADC input 4 for internal temperature sensor
  adc_select_input(4);

You might want to test whether you get reliable analog input from any pin as well

A0, A1, A2 are continuously changing if I pull my finger over them (to shorten the circle) between 0-1000.
A3 is not changing, whatever I do, it fluctuates only between 518-520.

Image

  • Any other ideas?

  • Anyway, how could I set/reduce the read frequency? (currently ca 24 msg/sec)
    It is spamming the log, my PC can not keep up, the buffer is overflowing even after 10 sec.

It is not, that I could not reduce the amount of values printed, but I guess it is also using the whole bandwidth of Firmata's 57Kbaud, which will be problematic if I want to use other things on the same connection._

@PizzaProgram
Copy link
Contributor

@mattjlewis PS: did you see this? #176

Can you maybe Reopen this issue? (So other can see it too, and maybe give any ideas?)

@pgrawehr
Copy link
Contributor

pgrawehr commented Feb 4, 2025

@PizzaProgram Maybe you create a new ticket instead. This old one was for the general support for the RPI Pico, your issue is "only" related to analog input. The overloading seems to be an issue of the client, as the communication can easily catch up with 24msgs/sec. A single analog message transmits only 3 bytes.

@pgrawehr
Copy link
Contributor

pgrawehr commented Feb 4, 2025

On the other hand... The range of the values is limited to 14 bits in the protocol. Can you check what the actual reading would be? Maybe it's just cutting of the 2 top bits. What is the reported value of the ADC resolution in the cabability query?

@PizzaProgram
Copy link
Contributor

PizzaProgram commented Feb 25, 2025

"Maybe you create a new ticket instead."

I don't really think, spamming issues would help. The temperature chip is part of RP2040. So it should be part of "Support for it", as the topic here says. Please reopen the ticket, so other may see it ;-)

I was also thinking about how to address a query to the whole firmata community to suggest:

  • Having a new type of values/communication, called: temp . Not just "digital" and "analog" and "PWM" ...
    (This would keep the conversion on the board side, and transmit a floating value.)

"The overloading seems to be an issue of the client, as the communication can easily catch up with 24msgs/sec. A single analog message transmits only 3 bytes."

It is probably true. But that means, if a 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz laptop CPU can not handle it, an RPi4 or RPi3 will be able to do so even less. I have found the answer to my own question here . So it possible to set the sampling frequency from the host side, but NOT to a specific pin. (Only globally to all pins.)
The default analogue read freq. is 19ms/msg = 52msg/sec!

Reading the chip's temperature value more than 4x / sec would be absolutely unnecessary in any cases, so this limit could be hardcoded here for this specific pin from the beginning as default frequency.

@PizzaProgram
Copy link
Contributor

PizzaProgram commented Feb 25, 2025

"The range of the values is limited to 14 bits in the protocol. Can you check what the actual reading would be? Maybe it's just cutting of the 2 top bits. What is the reported value of the ADC resolution in the cabability query?"

I was searching for the answer for weeks now, but did not find it. Sorry.
As far as I understand, Javascript is not limiting values. Every variable is "variant", so typically 64bit, but minimum 32bit so there could be no "cutting off bits".

EDIT:
I've found the corresponding decode32BitSignedInteger() and decodeCustomFloat() functions in firmata-io.js.
These functions are all based on 32bit input values.
The float is maxed to: MAX_SIGNIFICAND = Math.pow(2, 23);

@PizzaProgram
Copy link
Contributor

I wonder:

  • if there is a decodeCustomFloat() functions available at firmata-io.js (but not used in node-red),
  • maybe the main problem could be that all analogue values are integer by default in node-red?

Should not all analogue ports reporting float values?

@pgrawehr
Copy link
Contributor

"The range of the values is limited to 14 bits in the protocol. Can you check what the actual reading would be? Maybe it's just cutting of the 2 top bits. What is the reported value of the ADC resolution in the cabability query?"

I was searching for the answer for weeks now, but did not find it. Sorry. As far as I understand, Javascript is not limiting values. Every variable is "variant", so typically 64bit, but minimum 32bit so there could be no "cutting off bits".

No, that won't work directly. The problem is that the protocol only transmits a 14 bit integer for each ADC reading. The conversion to float happens after that, in software. All known boards report ADC values as integers, because that is technically easier. The value needs to be interpreted as parts of the full voltage range.

Can you please try to flash this program to the RPI and see whether the console output shows reasonable temperatures? If so, can you print the value of the adc_read() call in float CPU::getTemperature()? That would make it easy to determine whether my assumption is true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants