WiFi NINA with Pi Pico SDK

I have a code for Nano RP2040 written with the usage of Raspberry Pi SDK (it was written to use with Raspberry Pi Pico, but then I switched to Arduino Nano Connect RP2040).
Now I want to add WiFi functionality to it, so I want to control the WiFi NINA which is on the board. What would be the easiest way to do it? Is there any library that I could use with Raspberry Pi SDK?

try searching "rp2040 Nina W102 library" on google.

First things that would come up would be:

https://docs.arduino.cc/tutorials/communication/wifi-nina-examples/

Please use the forum for things you weren't able to finds answers of.

Best,

@asdfdsgtegb I spent pretty much time on googling for it. Of course I found those Arduino's WiFiNINA libraries, but they depend on Arduino's libraries. In my case I'm using Raspberry's libraries, so that WiFiNINA library won't work.

you can try

@Juraj
I'm looking at that library and it is also using Arduino's libraries:

#include <Arduino.h>
#include <SPI.h>

In my project I am using the Raspberry libraries, for example

#include "hardware/spi.h"

How do you suggest to use it?

I thought that I will adapt WiFiNINA library. i.e. replace Arduino's SPI functions with Raspberry's and adapt PIN numbers. But it is not so easy.
WiFiNINA library is quite complex and SPI function calls are in many different files. Adapting PIN numbers is even more difficult. Arduino is using mapping for GPIO pin numbers. For SPI, I2C etc. I figured out the not-mapped PIN numbers from the pinout diagram. However I can't find clear information about NINA pins.

This shouldn't be an issue, earlephihower's arduino-pico implementation is designed to bridge the gap between the sdk and arduino framework, I was able to use the libraries from both sides in harmony with little adjustments like mapping the serial i/o of spi before initiating the actual spi code (pico specific).

Just try the compile it and handle errors one by one method (the secret senior engineer sauce) and if it gets out of hand and leads to the compiler requesting you modify the library you might as well adapt it to suit the actual pico sdk code.

I did a realy surfaced search but as long as I am concerned WIFININA/src/utility/spi_drv.cpp should be the only place for you to modify for spi.

try searching nano rp2040 connect schematic, they are always open source.

Here is an example. check bottom right of the page for further pinout information.

1 Like

the ESPHost library is easy to modify to not to use Arduino. then you can integrate it with lwip in Pico SDK

Thank you all for the help. I started porting WiFiNINA.
Thanks to suggestion from @asdfdsgtegb to use the schematic I was able to map almost all the pins. However I don't know what is the Raspberry pin number for RESET. I think it might be 30, but haven't tested it yet.
It is also not clear to me why SLAVERESET is toggled every time when starting communication with NINA. Could you bring some light on it? Is there any good documentation for NINA on Arduino Nano RP2040?

I found the file where the mapping is defined!

  // Internal pins Nina - D24 - D29
  { p3,         NULL, NULL, NULL },    // RESET_NINA
  { p8,         NULL, NULL, NULL },    // SPI1_CIPO / UART1_TX
  { p9,         NULL, NULL, NULL },    // SPI1_CS / UART1_RX
  { p10,        NULL, NULL, NULL },    // SPI1_ACK / UART1_CTS
  { p11,        NULL, NULL, NULL },    // SPI1_COPI / UART1_RTS
  { p14,        NULL, NULL, NULL },    // SPI1_SCK

I'm trying to port Arduino's WIFININA to Raspberry Pi and I face a problem. Already when sending first SPI command it fails. Here is the code.

wifi_drv.cpp:

int8_t WiFiDrv::wifiSetPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len)
{
    WAIT_FOR_SLAVE_SELECT();
    // Send Command
    SpiDrv::sendCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_2);
    SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM);
    SpiDrv::sendParam((uint8_t*)passphrase, len, LAST_PARAM);
}

spi_drv.h:

#define WAIT_FOR_SLAVE_SELECT()	      \
	if (!SpiDrv::initialized) {           \
		SpiDrv::begin();      \
	}                             \
	SpiDrv::spiSlaveSelect();

class SpiDrv
{
private:
	static void getParam(uint8_t* param);
    static int transfer(uint8_t buf_to_write, uint8_t buf_to_read = 11);

public:
	static bool initialized;

    static void begin();
    static void spiSlaveSelect();
	static void spiSlaveDeselect();
    static void waitForSlaveReady(bool const feed_watchdog = false);
    static int waitSpiChar(unsigned char waitChar);
    static int readAndCheckChar(char checkChar, char* readChar);
    static char readChar();
    static int waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len);
	static void sendParam(uint8_t* param, uint8_t param_len, uint8_t lastParam = NO_LAST_PARAM);
    static uint8_t readParamLen8(uint8_t* param_len = NULL);
    static void sendParam(uint16_t param, uint8_t lastParam = NO_LAST_PARAM);
    static void sendCmd(uint8_t cmd, uint8_t numParam);
};

spi_drv.cpp:

// From NANO_RP2040_CONNECT/pins_arduino.h
#define PINS_COUNT      (30u)
#define NINA_RESETN		(3u)
#define NINA_GPIO0		(2u)
#define SPIWIFI_SS		(9u)
#define SPIWIFI_ACK		(10u)
#define SPIWIFI_RESET	(NINA_RESETN)
#define SPIWIFI 		spi1

#define SPI1_CIPO       (8u)
#define SPI1_COPI       (11u)
#define SPI1_SCK        (14u)


static uint8_t SLAVESELECT = SPIWIFI_SS; // ss
static uint8_t SLAVEREADY  = SPIWIFI_ACK;  // handshake pin
static uint8_t SLAVERESET  = SPIWIFI_RESET;  // reset pin
static bool inverted_reset = false;

bool SpiDrv::initialized = false;

void SpiDrv::begin()
{
    gpio_set_dir(SLAVESELECT, GPIO_OUT);
    gpio_set_dir(SLAVEREADY, GPIO_IN);
    gpio_set_dir(SLAVERESET, GPIO_OUT);
    gpio_set_dir(NINA_GPIO0, GPIO_OUT);

    gpio_put(NINA_GPIO0, 1);
    gpio_put(SLAVESELECT, 1);
    gpio_put(SLAVERESET, 0);
    sleep_ms(10);
    gpio_put(SLAVERESET, 1);
    sleep_ms(750);

    gpio_put(NINA_GPIO0, 0);
    gpio_set_dir(NINA_GPIO0, GPIO_IN);

    // initialize SPI
    spi_init(SPIWIFI, 8000000);
    spi_set_format(SPIWIFI, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
    gpio_set_function(SPI1_COPI, GPIO_FUNC_SPI);
    gpio_set_function(SPI1_SCK, GPIO_FUNC_SPI);

    gpio_init(SPIWIFI_SS);
    gpio_set_dir(SPIWIFI_SS, GPIO_OUT);
    gpio_put(SPIWIFI_SS, 1);
    sleep_ms(10);

    initialized = true;
}

#define waitSlaveReady() (gpio_get(SLAVEREADY) == 0)

void SpiDrv::spiSlaveSelect()
{
    gpio_put(SLAVESELECT, 0);

    // wait for up to 5 ms for the NINA to indicate it is not ready for transfer
    // the timeout is only needed for the case when the shield or module is not present
    uint32_t start_timestamp = to_ms_since_boot(get_absolute_time());
    while(!waitSlaveReady() && (to_ms_since_boot(get_absolute_time()) - start_timestamp) < 5)
    {
        printf("SpiDrv::spiSlaveSelect - wait for Slave Ready \n");   
    }
}

void SpiDrv::spiSlaveDeselect()
{
    gpio_put(SLAVESELECT, 1);
}

/* Cmd Struct Message */
/* _________________________________________________________________________________  */
/*| START CMD | C/R  | CMD  |[TOT LEN]| N.PARAM | PARAM LEN | PARAM  | .. | END CMD | */
/*|___________|______|______|_________|_________|___________|________|____|_________| */
/*|   8 bit   | 1bit | 7bit |  8bit   |  8bit   |   8bit    | nbytes | .. |   8bit  | */
/*|___________|______|______|_________|_________|___________|________|____|_________| */

void SpiDrv::sendCmd(uint8_t cmd, uint8_t numParam)
{
    printf("SpiDrv::sendCmd - cmd = %u, numParam = %u \n", cmd, numParam);

    uint8_t buf_to_write{START_CMD};
    transfer(buf_to_write);
    buf_to_write = cmd & ~(REPLY_FLAG);
    transfer(buf_to_write);
    buf_to_write = numParam;
    transfer(buf_to_write);

    if(numParam == 0)
    {
        printf("SpiDrv::sendCmd - END_CMD \n");
        buf_to_write = END_CMD;
        transfer(buf_to_write);
    }
}

int SpiDrv::transfer(uint8_t buf_to_write, uint8_t buf_to_read)
{
    printf("SpiDrv::transfer - buf_to_write = %u, buf_to_read = %u \n", buf_to_write, buf_to_read);
    int response{0};
    response = spi_write_read_blocking(SPIWIFI, &buf_to_write, &buf_to_read, 1);
    printf("SpiDrv::transfer - response = %u, buf_to_read = %u \n", response, buf_to_read);

    return response;
}

Here is the result of print:

SpiDrv::sendCmd - cmd = 17, numParam = 2 
SpiDrv::transfer - buf_to_write = 224, buf_to_read = 11 
SpiDrv::transfer - response = 1, buf_to_read = 0 
SpiDrv::transfer - buf_to_write = 17, buf_to_read = 11 
SpiDrv::transfer - response = 1, buf_to_read = 0 
SpiDrv::transfer - buf_to_write = 2, buf_to_read = 11 
SpiDrv::transfer - response = 1, buf_to_read = 0 

buf_to_read is always "0", but it should contain some response. When I run the same using Arduino's WIFININA, there is always some response. And for the response to command "17" is always "54". Any suggestions what am I doing wrong?

Hi,

I had a same problem with Pico4ML. Therefore i installed the WiFiNina-Generic. Even i changed the pin numbers, i faced with communication failed message.

I supposed that we should changed library directly. But i don’t know where we should start.

@firzen91 the OP had a different question. they want to use the WiFiNINA without Arduino.

1 Like

Opp sorry. I see.

P.S. we met again :slight_smile: and I could solve the WiFiNina Problem and Pico4ML with your suggestions :confused:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.