-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Conversation
There was a problem hiding this 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:
- All the pins that are not exposed as external pins are undefined (
GPIO_UNDEF
) to keep the order. - 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. - 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?
#define ARDUINO_PIN_7 GPIO_PIN(PA, 21) /**< D7 */ | ||
#define ARDUINO_PIN_8 GPIO_PIN(PA, 6) /**< D8 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above.
#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 */ |
There was a problem hiding this comment.
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 */ |
There was a problem hiding this comment.
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.
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define ARDUINO_A6 ADC_LINE(6) /**< ADC 6 */ |
The same here.
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define ARDUINO_PIN_38 GPIO_PIN(PA, 13) /**< D38 */ |
Not connected
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#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.
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define ARDUINO_PIN_42 GPIO_PIN(PA, 3) /**< D42 */ |
AREF pin.
#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 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#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
I don't have the hardware with me, I can take a look next week. |
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. RIOT/sys/arduino/serialport.cpp Lines 47 to 52 in 2e0c02b
To make |
eb05c6f
to
f344758
Compare
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? |
f344758
to
b2f9289
Compare
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. Basically it implements Serial on top of https://doc.riot-os.org/group__sys__stdio.html There are a few issues though, aside from the missing implementations of the new functions. |
* | ||
* @return nr of available bytes | ||
*/ | ||
int stdio_avail(void); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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? |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
One question is whether we can rely on that |
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 |
Maybe, a possible solution could be to use different 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 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 |
Ok thanks. I'll close this PR and open a new one only for the feather-m0. |
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
andtests/sys_arduino_lib
. Both work.But
examples/arduino_hello-world
andtests/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.