Incorrect pad mapping in Arduino Core

I guess the main purpose of this post is to warn anyone having difficulty getting obscure pin function combinations to work, that there may be errors in the core code defining errors for Serial0, Serial1, I2C, SPI, etc.

I’ve been trying to set Serial1 to work on pads 9 (RX) and 10 (TX), and I narrowed it down to pad 10 not functioning as TX1. Assigning the port to other pins worked fine (test code below - uses an FTDI plugged into a separate COM port and viewed in Termite serial monitor).

I dug into the core code, found 4 omissions plus 2 typos and made (untested) fixes to files:

  • ap3_uart_structures.c

  • am_hal_pin.h

  • ap3_uart_types.h

I’ve double checked and fixed all the assignments for UART0 and UART1 against the pin mapping Table 559 of the Apollo3 Blue datasheet, and a pull request is pending. Couldn’t quite bring myself to do the same for SPI/I2C/others at this stage.

Unfortunately, TX1 still doesn’t work on pad 10, so I’m a bit stumped. Any ideas?

Test code (worked successfully on Nano, Redboard and my custom board, I really need to get an ATP for stuff like this though - remember if using pad numbers instead of pin numbers, to select board “Artemis ATP” and cross-reference the schematic for the pad numbers vs pin numbers)

I think I’m having a similar problem. I have an Artemis Openlog which I 'm trying to connect to a NEO-M9N GPS board. When I run the examples it tells me it can’t find an I2C device at that address (0x42, which I think should be correct). I looked thru the Apollo3 cores and found a file called “ap3_iomaster.cpp” which has this inside it:

ap3_err_t ap3_iom_pad_funcsel(uint8_t instance, ap3_iom_pad_type_e type, ap3_gpio_pad_t *pad, uint8_t *funcsel)

{

ap3_err_t retval = AP3_OK;

switch (instance)

{

case 0:

switch (type)

{

case AP3_IOM_I2C_SCL:

*pad = 5;

*funcsel = AM_HAL_PIN_5_M0SCL;

break;

case AP3_IOM_I2C_SDA:

*pad = 6;

*funcsel = AM_HAL_PIN_6_M0SDAWIR3;

break;

case AP3_IOM_SPI_SCLK:

*pad = 5;

*funcsel = AM_HAL_PIN_5_M0SCK;

break;

case AP3_IOM_SPI_MOSI:

*pad = 7;

*funcsel = AM_HAL_PIN_7_M0MOSI;

break;

case AP3_IOM_SPI_MISO:

*pad = 6;

*funcsel = AM_HAL_PIN_6_M0MISO;

break;

default:

goto invalid_args;

break;

}

break;

case 1:

switch (type)

{

case AP3_IOM_I2C_SCL:

*pad = 8;

*funcsel = AM_HAL_PIN_8_M1SCL;

break;

case AP3_IOM_I2C_SDA:

*pad = 9;

*funcsel = AM_HAL_PIN_9_M1SDAWIR3;

break;

case AP3_IOM_SPI_SCLK:

*pad = 8;

*funcsel = AM_HAL_PIN_8_M1SCK;

break;

case AP3_IOM_SPI_MOSI:

*pad = 10;

*funcsel = AM_HAL_PIN_10_M1MOSI;

break;

case AP3_IOM_SPI_MISO:

*pad = 9;

*funcsel = AM_HAL_PIN_9_M1MISO;

break;

default:

goto invalid_args;

break;

}

break;

Case 1 would be correct, I think as my Artemis board has SDA at pin 9 and SCL at pin8. How do I force it to use these pin assignments? BTW, I’ve checked the config of the GPS board and its I2C port address is also set at 0x42. This is my first Arduino project, done plenty of PIC stuff in C. I had thought with the Qwiic system it would have been plug and play.

Is anyone able to help please?

Stu.

Solved!

I had to add this:

TwoWire myWire(1); //Will use pads 8/9

myWire.begin();

//Here’s the next trick. You need to pass this Wire port to your library.

//SparkFun libraries allow any Wire port to be passed in. Other folk’s libraries may not do this.

if (myGPS.begin(myWire) == false) {

Serial.println(“Not Connected. Please check connections and read the hookup guide.”);

while (1);

Now it is communicating with the GPS board and getting data from it.

Stu.

Nice one Stu.

I thought I had resolved this thread but maybe not - to confirm, the Serial1 issue is fixed (or will be in 1.0.31+) and it was due to errors in the code not matching the pin mapping table.

Thanks, Stephen! I was actually surprised I was able to fix it so quickly after almost giving up. I think in my case the Artemis Openlog is using the normal pins for I2C for SPI to communicate with the SD Ram and using the second I2C pins for I2C. I know Sparkfun probably expected most users to use the Openlog to purely grab serial data and not reprogram it but it would have been nice of them to include some code snippets showing how to connect via Qwiic to other devices. Perhaps they’ll read this and add something to their hookup guide.

Cheers,

Stu.

Another option would be for you to submit some potential examples via github? :slight_smile: There are a few folks actively contributing to the project (like stephenf). If you have something useful, I’m sure they’d love to include it!

Yep, anything searchable in the public domain is nice, but working examples in the core are absolutely golden. Especially for different configurations and some of the advanced functionality. People working on projects are well placed to be doing this, as we are the ones exploring the corners of the Artemis capabilities.

In regards to the original issue of pin mapping… does this fix it?

https://github.com/sparkfun/Arduino_Apollo3/pull/144

https://github.com/sparkfun/Arduino_Apollo3/pull/152

P.s. stephenf the errors you spotted in the code were confirmed as errors between the HAL and the datasheet, and the datasheet was confirmed to be correct wrt to the silicon. So PR 144 should have corrected the available peripheral pins.

Yep, this is the fix https://github.com/sparkfun/Arduino_Apollo3/pull/144

If that fix has not already been released to the Arduino Board Manager it will be very soon (within a day or two). Keep an eye out for an update within Arduino. You might be prompted to update or you may need to check manually.

The openlog board has Wire1 connected to qwiic.

Is there a way to point Wire to use pads 8/9 , so I don’t have to rewrite sensor libraries that use Wire?

For example something like (which obviously does not work)

TwoWire Wire(1); // Will use pads 8/9

Wire.begin()

myWire.begin();

Any help is apreciated,

Jur

I don’t think so - pretty sure the I2C pins are fixed to their corresponding wire port numbers.

A much better solution is to modify the library to use a TwoWire port - it’s really not that hard using example of libraries that do support this. (and ideally then make a pull request on Github so others can benefit from your changes) You will need to update the .h and the .cpp file in the src directory.

This library has an example of passing a TwoWire pointer

https://github.com/sparkfun/SparkFun_BM … master/src

Here is the function declaration with default argument:

bool beginI2C(TwoWire &wirePort = Wire);

Thank you Stephen,

I agree for simple libs. But I want to use the SHT85 sensor from Sensirion.

This library covers all diferent sensors form sensirion, and has classes and subclasses, and I dont know how to pass the pointer to wire1. Could you show me how that would work?

BTW, is there a way to define a new wire object (eg MyWire pointing to the right pads) globally (just like Wire is known to all libs) so I can change my lib by simply changing Wire in myWire?