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

boards/feather-m0: add arduino feature #17335

Closed
wants to merge 4 commits into from

Conversation

jdavid
Copy link
Contributor

@jdavid jdavid commented Dec 3, 2021

Contribution description

Adds the arduino feature to the feather-m0 board.

The pins come from https://github.com/adafruit/ArduinoCore-samd/tree/master/variants/feather_m0

Testing procedure

I've tested with tests/periph_gpio_arduino and tests/sys_arduino_lib. Both work.

But examples/arduino_hello-world and tests/sys_arduino don't work, Serial does not print anything.
That's why I'm creating this PR as a draft.
Any help understanding why Serial doesn't work with the feather-m0 is much appreciated.

Issues/PRs references

None.

@github-actions github-actions bot added Area: boards Area: Board ports Area: Kconfig Area: Kconfig integration labels Dec 3, 2021
Copy link
Contributor

@gschorcht gschorcht left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pin mapping is a bit difficult since not all Arduino pins are available as external pins. Some of them are used as internal control signals for additional hardware, e.g., for the WiFi module, the LoRa modul or the BLE module, others doesn't exist at all.

There are several ways to solve this problem:

  1. All the pins that are not exposed as external pins are undefined (GPIO_UNDEF) to keep the order.
  2. Only the pins that are not used are defined as undefined (GPIO_UNDEF), pins that are used internally are defined to keep the order and the compatibility with existing Arduino libraries that control additional hardware.
  3. Pins are reordered to have at least the 13 digital pins as defined by Arduino Uno.

Furthermore, you have redefined a number of pins. Why?

Comment on lines 45 to 46
#define ARDUINO_PIN_7 GPIO_PIN(PA, 21) /**< D7 */
#define ARDUINO_PIN_8 GPIO_PIN(PA, 6) /**< D8 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above.

Comment on lines 40 to 42
#define ARDUINO_PIN_2 GPIO_PIN(PA, 14) /**< D2 */
#define ARDUINO_PIN_3 GPIO_PIN(PA, 9) /**< D3 */
#define ARDUINO_PIN_4 GPIO_PIN(PA, 8) /**< D4 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

D2...D4, D7, D8 can't be used as external pins. They could be defined as GPIO_UNDEF.

Another possible solution would be to try to use a pinout that differs from the official one to define at least all the pins that exist on Arduino Uno. For example, on Arduino Uni D11...D13 are used for SPI. So you could define the pins that are used for SPI on Feather M0 (your D22..D24) as D10...D13 and use your D10...D13 as D2...D4.

D4, D7, D8 are used on different Feather M0 variants to control additional hardware like the WiFi module, the BLE module and the LoRa module. They could be defined even though they are not exposed to keep compatibility with existing Arduino libraries.

#define ARDUINO_PIN_A3 ARDUINO_PIN_17 /**< A3 */
#define ARDUINO_PIN_A4 ARDUINO_PIN_18 /**< A4 */
#define ARDUINO_PIN_A5 ARDUINO_PIN_19 /**< A5 */
#define ARDUINO_PIN_A6 ARDUINO_PIN_8 /**< A6 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't exist and can't be used as ADC channel.

Suggested change
#define ARDUINO_PIN_A6 ARDUINO_PIN_8 /**< A6 */

#define ARDUINO_A3 ADC_LINE(4) /**< ADC 3 */
#define ARDUINO_A4 ADC_LINE(5) /**< ADC 4 */
#define ARDUINO_A5 ADC_LINE(10) /**< ADC 5 */
#define ARDUINO_A6 ADC_LINE(6) /**< ADC 6 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_A6 ADC_LINE(6) /**< ADC 6 */

The same here.

Comment on lines 63 to 65
#define ARDUINO_PIN_25 GPIO_PIN(PB, 3) /**< D25 */
#define ARDUINO_PIN_26 GPIO_PIN(PA, 27) /**< D26 */
#define ARDUINO_PIN_27 GPIO_PIN(PA, 28) /**< D27 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_PIN_25 GPIO_PIN(PB, 3) /**< D25 */
#define ARDUINO_PIN_26 GPIO_PIN(PA, 27) /**< D26 */
#define ARDUINO_PIN_27 GPIO_PIN(PA, 28) /**< D27 */

These pins are for an additional UART interface that is not broken out (AFAIK).

#define ARDUINO_PIN_35 GPIO_PIN(PA, 16) /**< D35 */
#define ARDUINO_PIN_36 GPIO_PIN(PA, 18) /**< D36 */
#define ARDUINO_PIN_37 GPIO_PIN(PA, 17) /**< D37 */
#define ARDUINO_PIN_38 GPIO_PIN(PA, 13) /**< D38 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_PIN_38 GPIO_PIN(PA, 13) /**< D38 */

Not connected

Comment on lines 70 to 75
#define ARDUINO_PIN_32 GPIO_PIN(PA, 22) /**< D32 */
#define ARDUINO_PIN_33 GPIO_PIN(PA, 23) /**< D33 */
#define ARDUINO_PIN_34 GPIO_PIN(PA, 19) /**< D34 */
#define ARDUINO_PIN_35 GPIO_PIN(PA, 16) /**< D35 */
#define ARDUINO_PIN_36 GPIO_PIN(PA, 18) /**< D36 */
#define ARDUINO_PIN_37 GPIO_PIN(PA, 17) /**< D37 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_PIN_32 GPIO_PIN(PA, 22) /**< D32 */
#define ARDUINO_PIN_33 GPIO_PIN(PA, 23) /**< D33 */
#define ARDUINO_PIN_34 GPIO_PIN(PA, 19) /**< D34 */
#define ARDUINO_PIN_35 GPIO_PIN(PA, 16) /**< D35 */
#define ARDUINO_PIN_36 GPIO_PIN(PA, 18) /**< D36 */
#define ARDUINO_PIN_37 GPIO_PIN(PA, 17) /**< D37 */

Redefinition of D20 (SDA), D21 (SCL), D12, D11, D10, D13.

Comment on lines 77 to 79
#define ARDUINO_PIN_39 GPIO_PIN(PA, 21) /**< D39 */
#define ARDUINO_PIN_40 GPIO_PIN(PA, 6) /**< D40 */
#define ARDUINO_PIN_41 GPIO_PIN(PA, 7) /**< D41 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_PIN_39 GPIO_PIN(PA, 21) /**< D39 */
#define ARDUINO_PIN_40 GPIO_PIN(PA, 6) /**< D40 */
#define ARDUINO_PIN_41 GPIO_PIN(PA, 7) /**< D41 */

Redefinition of D7, D8, D9

#define ARDUINO_PIN_39 GPIO_PIN(PA, 21) /**< D39 */
#define ARDUINO_PIN_40 GPIO_PIN(PA, 6) /**< D40 */
#define ARDUINO_PIN_41 GPIO_PIN(PA, 7) /**< D41 */
#define ARDUINO_PIN_42 GPIO_PIN(PA, 3) /**< D42 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_PIN_42 GPIO_PIN(PA, 3) /**< D42 */

AREF pin.

Comment on lines 81 to 83
#define ARDUINO_PIN_43 GPIO_PIN(PA, 2) /**< D43 */
#define ARDUINO_PIN_44 GPIO_PIN(PA, 6) /**< D44 */
#define ARDUINO_PIN_45 GPIO_PIN(PA, 7) /**< D45 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ARDUINO_PIN_43 GPIO_PIN(PA, 2) /**< D43 */
#define ARDUINO_PIN_44 GPIO_PIN(PA, 6) /**< D44 */
#define ARDUINO_PIN_45 GPIO_PIN(PA, 7) /**< D45 */

Redefinition of A0, D8, D9

@gschorcht
Copy link
Contributor

But examples/arduino_hello-world and tests/sys_arduino don't work, Serial does not print anything. That's why I'm creating this PR as a draft. Any help understanding why Serial doesn't work with the feather-m0 is much appreciated.

I don't have the hardware with me, I can take a look next week.

@aabadie
Copy link
Contributor

aabadie commented Dec 4, 2021

Any help understanding why Serial doesn't work with the feather-m0 is much appreciated.

In RIOT, this board is defined to use stdio over USB but at the moment the Arduino port can only work with stdio over UART. That's why it doesn't work.

void SerialPort::begin(long baudrate)
{
/* this clears the contents of the ringbuffer... */
ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
}

To make Serial work on feather-m0 (but also on the arduino-mkr boards), one has to adapt the Arduino port to work with stdio over USB.

@jdavid
Copy link
Contributor Author

jdavid commented Dec 7, 2021

Pins updated.

Is the stdio issue blocking this PR? Since it doesn't work for the mkr boards either, maybe it can be done in a different PR?

@jdavid jdavid requested a review from gschorcht December 7, 2021 09:46
@github-actions github-actions bot added Area: arduino API Area: Arduino wrapper API Area: sys Area: System Area: USB Area: Universal Serial Bus labels Dec 10, 2021
@jdavid
Copy link
Contributor Author

jdavid commented Dec 10, 2021

I've looked at the Serial problem.

This is not finished, but I'd like to gather feedback, to know whether I'm heading in the right direction.
See the latest commit, with it Serial works with the feather-m0 board.

Basically it implements Serial on top of https://doc.riot-os.org/group__sys__stdio.html
To do that I added a couple of functions (stdio_avail and stdio_clear), but for now they're
only implemented in sys/usb/usbus/cdc/acm/cdc_acm_stdio.c

There are a few issues though, aside from the missing implementations of the new functions.
Like what to do with the baudrate parameter in SerialPort::begin(..)

*
* @return nr of available bytes
*/
int stdio_avail(void);
Copy link
Contributor

@gschorcht gschorcht Dec 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works only, if all stdio_* backends implement this function. std_uart does not at the moment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, this would be an API change and should at least be done in a separate PR. An API change should only be made if and when absolutely necessary. It would require that all stdio_* backends implement it.

ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
stdio_clear();
(void)baudrate; // FIXME Should we use the baudrate, somehow?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of std_uart backend, the baudrate is fixed and defined by STDIO_UART_BAUDRATE.

res = ringbuffer_get_one(&rx_buf);
if (stdio_avail()) {
char c;
ssize_t n = stdio_read((void*)&c, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of stdio_uart backend, this requires to enable module stdio_uart_rx to work.

/* this clears the contents of the ringbuffer... */
ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
stdio_clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of stdio_uart, it might be enough to call stdio_init. It depends on periph_uart implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether it is necessary to clear buffers here at all.

*
* @return nr of available bytes
*/
int stdio_avail(void);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, this would be an API change and should at least be done in a separate PR. An API change should only be made if and when absolutely necessary. It would require that all stdio_* backends implement it.

}

void SerialPort::begin(long baudrate)
{
stdio_init();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stdio_init is called during CPU initialization and should only be called once. Calling it again here might lead to problems. It should be sufficient to initialize members of the SerialPort object or variables of the module here if there are any.

/* this clears the contents of the ringbuffer... */
ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
stdio_clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether it is necessary to clear buffers here at all.

@@ -41,19 +42,21 @@ SerialPort::SerialPort(uart_t dev)

int SerialPort::available(void)
{
return (int)rx_buf.avail;
return stdio_avail();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be realized without extending the stdio_base API by using a ringbuffer as for direct used of periph_uart. In that case Serial::begin would clear the ringbuffer and stdio_base wouldn't be necessary.

@gschorcht
Copy link
Contributor

This is not finished, but I'd like to gather feedback, to know whether I'm heading in the right direction.

One question is whether we can rely on that Serial object in Arduino always means the interface which is used for stdio in RIOT (Arduino serial interfaces). Another question is how the signature of the constructor of Serial should look like. At the moment, it gets a UART_DEV defined ARDUINO_UART_DEV.

@aabadie
Copy link
Contributor

aabadie commented Dec 13, 2021

IMHO, the change related to Serial should be in its own PR as it affects more boards (also Arduino mkr and maybe others).

Similar to PWM and the assiocated arduino_pwm, maybe it's worth to have an arduino_serial module ?
I agree with @gschorcht that it's important to keep the possibility to use other UART port with Serial, to remain compatible with the Arduino API.

@gschorcht
Copy link
Contributor

Maybe, a possible solution could be to use different Serial implentations dpendent on slected modules that use different interfaces, for example

void SerialPort::begin(long baudrate)
{
#if IS_USED(MODULE_STDIO_CDC_ACM)
    ...
#else
    /* this clears the contents of the ringbuffer... */
    ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
    uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
#endif
}

or something like that. The question here would be whether it should be possible to use a specified UART_DEV even though module stdio_cdc_acm is used.

In that case, a possibility could be :

void SerialPort::begin(long baudrate)
{
    if (dev != UART_UNDEF) {
        /* this clears the contents of the ringbuffer... */
        ringbuffer_init(&rx_buf, rx_mem, SERIAL_RX_BUFSIZE);
        uart_init(dev, (uint32_t)baudrate, rx_cb, (void *)&rx_buf);
    }
    else {
         ... /* stdio case */
    }
}

This would make it possible to use an interface UART if defined or stdio if not. The board can control it by overriding the definition of ARDUINO_UART_DEV.

@jdavid
Copy link
Contributor Author

jdavid commented Dec 15, 2021

Ok thanks. I'll close this PR and open a new one only for the feather-m0.
And later open another PR for serial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: arduino API Area: Arduino wrapper API Area: boards Area: Board ports Area: Kconfig Area: Kconfig integration Area: sys Area: System Area: USB Area: Universal Serial Bus
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants