Problem with Nina W102 startup on MKR 1010

Hello,

I have a problem when trying to access the WiFi Nina module from my Rust application. I have recreated all the steps that are required to boot the module:

    let mut nina_gpio0 = pins.pa27.into_push_pull_output();
    let nina_ack = pins.pa28.into_floating_input();
    let mut nina_reset = pins.pb08.into_push_pull_output();
    let mut nina_cs = pins.pa14.into_push_pull_output();

    nina_gpio0.set_high();
    nina_cs.set_high();
    nina_reset.set_low();
    delay.delay_ms(10_u16);
    nina_reset.set_high();
    delay.delay_ms(750_u16);
    nina_gpio0.set_low();
    let _ = nina_gpio0.into_floating_input();

This basically follows what I found in Arduino's WiFi Nina library:
pinMode(SLAVESELECT, OUTPUT);
pinMode(SLAVEREADY, INPUT);
pinMode(SLAVERESET, OUTPUT);
pinMode(NINA_GPIO0, OUTPUT);

  digitalWrite(NINA_GPIO0, HIGH);
  digitalWrite(SLAVESELECT, HIGH);
  digitalWrite(SLAVERESET, inverted_reset ? HIGH : LOW);
  delay(10);
  digitalWrite(SLAVERESET, inverted_reset ? LOW : HIGH);
  delay(750);

  digitalWrite(NINA_GPIO0, LOW);
  pinMode(NINA_GPIOIRQ, INPUT);

However I am getting no luck when waiting for the ACK pin (GPIO33 on Nina's side, PA28 on the MCU):
hprintln!("Waiting for ACK low").unwrap();
while self.busy.is_high().map_err(SpiError::Busy)? {}
self.cs.set_low().map_err(SpiError::ChipSelect)?;
while self.busy.is_low().map_err(SpiError::Busy)? {}

The equivalent code works in the WiFi Nina library.

When testing with Arduino IDE, the module works correctly, I have even logged the pinout (although I do not understand how the defines correspond to the real pinout):
10:19:54.546 -> MOSI: 8
10:19:54.546 -> MISO: 10
10:19:54.546 -> SCK: 9
10:19:54.546 -> SS: 4
10:19:54.546 -> NINA_GPIO0: 30
10:19:54.546 -> NINA_RESETN: 31
10:19:54.546 -> NINA_ACK: 3

Would anybody know what I am doing wrong?

Thanks in advance for your answers or suggestions.

AP

you have an arduino with esp32 or some original board with Nina module?

there are many details here. read it slow

I highlight

gpio0 is used to put the esp32 into flashing mode for firmware update
and it is used as 'heartbeat' signal of the firmware, so it must be wired

Hi @Juraj,

Thanks for your quick answer.

I am using an Arduino MKR 1010 WiFi board (but I have replaced the original firmware with my Rust app). To test if the Nina chip works fine I reprogrammed (several times) the original bootloader to be able to test the board with Arduino IDE (I got the pinout trace from there, using Serial.print()).

I will check the post you suggested, but normally GPIO0 is used by my software as explained here:

To me more clear - I do not want to touch the firmware on Nina, I want to program the main ATSAMD21G18A MCU to communicate with the original firmware that has been flashed on Nina.

sorry I missed the board in title and category :-(. so you want to use the Arduino nina-fw and rewrite the WiFiNINA library to Rust?

That is correct, yes. I have found a library (GitHub - dflemstr/wifi-nina), but it does not seem to handle this particular PCB/configuration (e.g. GPIO0 is not managed by it). Do you understand what I am missing when starting the communication with Nina?

this shouldn't be there:
let _ = nina_gpio0.into_floating_input();
in C++ it is
pinMode(NINA_GPIOIRQ, INPUT);

True!

But in the library sources, in the same file, we have this at the top:
#ifndef NINA_GPIOIRQ
#define NINA_GPIOIRQ NINA_GPIO0
#endif

I will check with Arduino IDE if NINA_GPIOIRQ is defined for MKR 1010 WiFi.

No, it was not defined:
Zrzut ekranu 2021-11-10 o 17.54.38

So it means that in this case GPIO0 = GPIOIRQ. Any other ideas about what could be wrong?

What I see is that the NINA_ACK pin is high until Nina is reset, then it stays low.
Then, before sending any command, the library does this:
WAIT_FOR_SLAVE_SELECT()
SpiDrv::waitForSlaveReady();
SpiDrv::spiSlaveSelect();

which boils down to:

  • wait for NINA_ACK to be low (OK)
  • set SPI CS to low (OK)
  • wait for NINA_ACK to be high (NOK)

Basically, setting the Chip Select pin to low does not make NINA_ACK to become high. What can it mean?

the SPI pin numbers are not right. those are number for SPI0 accessible on headrs.
I guess Nina is on SPI1

Hi @Juraj ,
Thanks for checking this. I do not understand however, why when I log the pins from Arduino IDE sketches, they are the following:

10:19:54.546 -> MOSI:8
10:19:54.546 -> MISO:10
10:19:54.546 -> SCK:9
10:19:54.546 -> SS:4
10:19:54.546 -> NINA_GPIO0:30
10:19:54.546 -> NINA_RESETN:31
10:19:54.546 -> NINA_ACK:35

(as if Nina was connected to SPI0).

The same goes for the schematics (available here: Arduino MKR WiFi 1010 — Arduino Official Store):

I have changed the SERCOM to sercom4 (without changing the pins), but the program is still stuck waiting for a high level on NINA_ACK.

Could you tell me what pins on the ATSAMD21G18A correspond to the values from the header file (namely 26, 27, 28, 29)?

OK, found them (below). So I can confirm that I use the correct pins (PA12 = MOSI, PA13 = MISO, PA14 = CS, PA15 = SCK, NINA_GPIO0 = PA27, NINA_RESETN = PB08) on the correct sercom (4).

What is strange are still the pins logged by Arduino IDE (they clearly correspond to SPI0 - and the sketch works with NINA!). The program is still stuck while waiting for NINA_ACK to be high...

OK, found it....

Active reset level is high, not low on MKR 1010... Everything works now!

@Juraj Thanks a lot for setting me on the right path!!!

I checked if the reset is inverted, because I know some boards have it that way, but it didn't look like MKR1010 has it inverted.

This code works:

        self.cs.set_high().map_err(SpiError::ChipSelect)?;
        self.reset.set_high().map_err(SpiError::Reset)?;
        self.delay(time::Duration::from_millis(10))?;
        self.reset.set_low().map_err(SpiError::Reset)?;
        self.delay(time::Duration::from_millis(750))?;

This does not:

        self.cs.set_high().map_err(SpiError::ChipSelect)?;
        self.reset.set_low().map_err(SpiError::Reset)?;
        self.delay(time::Duration::from_millis(10))?;
        self.reset.set_high().map_err(SpiError::Reset)?;
        self.delay(time::Duration::from_millis(750))?;

Also, when you look at the variant header file you provided:
#define SPIWIFI_SS PIN_SPI1_SS
#define SPIWIFI_ACK NINA_ACK
#define SPIWIFI_RESET (~NINA_RESETN) // fixme! Inverted logic

1 Like