[Solved v0.4.4-rc.3] Antenna select Weirdness

Thank you @BDub for getting to the bottom on this one!

1 Like

Nice work. Is the antenna selection persistent over sleep/wakeup events ?

The system will boot with ANT_AUTO selected every time, so a System.sleep(SLEEP_MODE_DEEP, 10); would cause the system to wake up in ANT_AUTO.

I just came up with a Super Hack :tm: to test out being able to set the antenna to ANT_INTERNAL or ANT_EXTERNAL as close to when Wi-Fi comes up as possible. The antenna control lines cannot be set before the WiFi is enabled. If you tried to call WiFi.selectAntenna() in MANUAL mode… the antenna wouldn’t switch until Wi-Fi was turned on. This is a WICED thing. The following code is kind of a test routine I’ve been using. It uses the new RGB.onChange() LED handler to know when the RGB first lights up GREEN signaling Wi-Fi has just turned on. The handler is setup in the class constructor so that it’s listening to RGB events from the time the system boots. Not really the intended use of this onChange function, but then again it’s exactly what we need. I measured on the o’scope only 4.5ms in AUTO mode before INTERNAL or EXTERNAL takes over. You’ll have to keep me honest here, but I do believe it’s connecting to Wi-Fi much faster by forcing one of these INTERNAL or EXTERNAL modes as soon as Wi-Fi is enabled. We’ll definitely come up with a more elegant solution for setting the antenna from your application, but for now if you are playing with the develop branch code or after you get v0.4.4-rc.3 firmware you should be able to run the following example:

/*
 ******************************************************************************
  Copyright (c) 2013-2015 Particle Industries, Inc.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation, either
  version 3 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************
 */

#include "application.h"
#include "core_hal.h"

char myIpString[45];
uint8_t antenna = 3; // init with invalid option so we do force one on boot
IPAddress myIp;
system_tick_t startRSSI;
system_tick_t startSLEEP;
#define now() millis()

class ExternalRGB {
	public:
		ExternalRGB(pin_t r, pin_t g, pin_t b);
		void handler(uint8_t r, uint8_t g, uint8_t b);

	private:
		pin_t pin_r;
		pin_t pin_g;
		pin_t pin_b;
};

ExternalRGB::ExternalRGB(pin_t r, pin_t g, pin_t b) : pin_r(r), pin_g(g), pin_b(b) {
	// pinMode(pin_r, OUTPUT);
	// pinMode(pin_g, OUTPUT);
	// pinMode(pin_b, OUTPUT);
	using namespace std::placeholders;
	RGB.onChange(std::bind(&ExternalRGB::handler, this, _1, _2, _3));
}

void ExternalRGB::handler(uint8_t r, uint8_t g, uint8_t b) {
	// Mirror system RGB LED to external common cathode RGB LED
	// Called every 1ms, keep this as short as possible!
	// analogWrite(pin_r, r);
	// analogWrite(pin_g, g);
	// analogWrite(pin_b, b);

	// Right when the system starts flashing the green LED
	static bool already_done = 0;
	if (g>0 && b==0 && r==0 && !already_done) {
		already_done = 1;
		// Set your antenna mode, will be ANT_AUTO (default) for 4.5ms,
		// then switch to ANT_INTERNAL, ANT_EXTERNAL based on following call
		WiFi.selectAntenna(ANT_INTERNAL);
	}
}

// Create a new ExternalRGB instance on D0, D1 and D2 (R, G, and B)
ExternalRGB myRGB(D0, D1, D2);

void setup() {
	myIp = WiFi.localIP();
	sprintf(myIpString, "%d.%d.%d.%d at RSSI: %d(dB)", myIp[0], myIp[1], myIp[2], myIp[3], WiFi.RSSI());
#if PLATFORM_ID == 6
	Particle.variable("ipPhoton", myIpString, STRING);
#else
	Spark.variable("ipCore", myIpString, STRING);
#endif
	startRSSI = now();
	startSLEEP = startRSSI;
}

void loop() {
	// Button press needs to be 1 second long
	if (HAL_Core_Mode_Button_Pressed(1000)) {
		if (++antenna > 2) antenna = 0;
		RGB.control(true);
		switch (antenna) {
			case 0: RGB.color(255,0,0); break;
			case 1: RGB.color(0,255,0); break;
			case 2: RGB.color(0,0,255); break;
		}
		delay(500);
		RGB.control(false);
		HAL_Core_Mode_Button_Reset();
	}

	if (now() - startRSSI > 1000UL) {
		startRSSI = now();
		switch (antenna) {
		case 0:
			WiFi.selectAntenna(ANT_INTERNAL);
			sprintf(myIpString, "%d.%d.%d.%d at RSSI: %d(dB) on ANT_INTERNAL", myIp[0], myIp[1], myIp[2], myIp[3], WiFi.RSSI());
			break;
		case 1:
			WiFi.selectAntenna(ANT_EXTERNAL);
			sprintf(myIpString, "%d.%d.%d.%d at RSSI: %d(dB) on ANT_EXTERNAL", myIp[0], myIp[1], myIp[2], myIp[3], WiFi.RSSI());
			break;
		case 2:
			WiFi.selectAntenna(ANT_AUTO);
			sprintf(myIpString, "%d.%d.%d.%d at RSSI: %d(dB) on ANT_AUTO", myIp[0], myIp[1], myIp[2], myIp[3], WiFi.RSSI());
			break;
		default:
			break;
		}
	}

	if (now() - startSLEEP > 20000UL) {
		startSLEEP = now();
		System.sleep(SLEEP_MODE_DEEP,10);
	}
}
4 Likes

To do this for real, I think the photon HAL will cache the last value of selectAntenna() and apply this immediately after wiced_wlan_connectivity_init() is called.

I’m feeling that a macro like

WIFI_SELECT_ANTENNA(ANT_INTERNAL);

would allow the application code to set the antenna at the very start of code execution, so that the cached value is there ready when WiFi is connected.

2 Likes

I’ve updated my Photon to 0.4.4rc3 today and there’s still something weird with the antenna selection.
Details:
I’m operating the device outside my house to control my pool pumps. With 0.4.3 and antenna selection to ANT_AUTO the Photon connects to my WiFi (with around -70dB signal strength) using the external antenna. With 0.4.4rc3 the device does not connect to my network. I’ve added a repeater close to the device (approx. 20ft, but through a wall) and the connection succeeds, but with with ANT_AUTO it looks as if it uses the internal antenna resulting in a signal strength of -80dB. Switching to ANT_EXTERNAL in setup() results in -60dB which to me clearly indicates that the wrong antenna is selected during the WiFi connect phase. This would also explain why the device after update was not able to connect to my original access point anymore that worked fine with 0.4.3.
Could you please verify if the Photon really selects the strongest WiFi signal during startup?
UPDATE:
after looking at wlan_hal.cpp I found that with commit #8f417c6 the startup antenna selection was modified to ANT_INTERNAL and no longer ANT_AUTO as stated in the docs. That explains why my Photon in SYSTEM_AUTOMATIC mode no longer connects to my original access point which is too far away for the internal antenna. Obviously this results in a catch22: the setup code is not called before the connection to the cloud works, so my selectAntenna(ANT_EXTERNAL) call in setup does not work as expected. I think this is a principal issue with Photons connected to weak WLANs.
I’ve noticed there’s a STARTUP macro available now that allows to execute code in an early startup phase (before setup()??), but I could not find any documentation for that. Any hints?

Just to chime in here, I had the same problem when I tried to update my photon to the latest 0.4.4rc3 today. It appears to have defaulted to the internal antenna (I have an external attached since the router is out of range of the internal antenna) immediately after the firmware update and thus became unreachable and we had to have someone go get it (it’s remotely installed).

I’m assuming this is a bug and that it should actually default to ANT_AUTO, yes?

I brought up this discussion today, and it looks like we should probably revert to ANT_AUTO by default.

Thanks–I agree. ANT_AUTO should be the ideal configuration (by default) for pretty much any application I would think yes?

Will this change back to ANT_AUTO as default be in the final 0.4.4 release? For now I just reverted back to 0.4.3.

The main issue with ANT_AUTO is that in WICED it sometimes stops on the wrong antenna.

We’re considering a fix where we alternate every 2nd wifi connection failure between INTERNAL and AUTO. This will ensure that anyone using an external antenna now isn’t locked out.

1 Like

Ah, that does complicate things. That sounds like a good compromise though, alternating between the two.

Something else that might help would be the ability to define the default antenna you wish to use before user code actually begins executing via a global define or something (this may be possible already, I’m not quite sure). I know you can take manual control of Wifi operation (versus automatic) to allow for execution of user code before Wifi connects but ideally I’d like to still be able to use the automatic wifi mode.

Totes! :slight_smile: When 0.4.4 is released, you’ll be able to define the default antenna in user code:

STARTUP(WiFi.selectAntenna(ANT_EXTERNAL))

Some interesting things at Chip antenna vs u.FL connector . I have 15 Photons which work great in the hall about 30 feet from the schools access point (wifi router). However behind steel doors to the classroom the Photons randomly will not connect. So I need to look into the antenna’s. I tried the syringe hack see image but it did not seem to help. I managed to get a u.fl connector whip style antenna from a laptop screen, but it also did not seem to be much better.

A friend gave me a duck style u.FL connected antenna. it seemed to be about 20% better than the chip antenna.

Something strange is that assigning the antenna also seems to make things another 20 percent better.

//STARTUP(WiFi.selectAntenna(ANT_INTERNAL));
//STARTUP(WiFi.selectAntenna(ANT_AUTO));
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));

Yesterday I could barely walk 20 feet from my front door with the chip antenna, today I could walk 100 feet, with the chip, 120 feet with the antenna defined, and 150 feet with the duck antenna. Kind of strange.

Another irritating part is that if you lose connectivity you have to return about 50% of the distance to get the connection, then you can walk the full distance again.

Hopefully the duck antenna can solve my classroom issue

So I tried both the whip antenna and a duck antenna at school. With either one and no software changes both worked great. Photon logged into the cloud in about 10 seconds. Without either antenna the photon took about 30 seconds to login and then randomly lost connectivity. So either antenna solved my school wifi dilemma (30 feet from access point but my classroom is behind steel doors).

Are you using firmware 0.4.5?

Yup 0.4.5

That makes sense. The default antenna since 0.4.4 is internal, which explains the lack of connectivity. To always use the external antenna, you’ll need to add the external antenna selection code to your app.

I hoep that’s clear! :smile:
mat.

Hi,
sorry for butting in but i am having problems trying to enable and use the external antenna.
i may be using this incorrectly, but the app works fine without the following command b ut errors in the middle of a commented section when it is included.
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL))

where should it be in the sketch outside setup () inside setup() or in the main loop() ?

Please see the docs - https://docs.particle.io/reference/firmware/photon/#wifi-selectantenna-
The placement of the STARTUP macro is shown clearly in the second example.

By the way, be careful removing the u.fl antenna. One of my students removed it and the surface mount connector popped off. Luckily the Photon still works fine, minus the ability to attach an antenna.

It does not work for me eather to select external.

Particle Build says

/tmp/cc8JgcLA.ltrans21.ltrans.o: In function spark::WiFiClass::selectAntenna(WLanSelectAntenna_TypeDef) [clone .isra.3]': /spark/compile_service/shared/workspace/0_core_hal_18_0/firmware/main/../wiring/inc/spark_wiring_wifi.h:171: undefined reference to wlan_select_antenna'
collect2: error: ld returned 1 exit status
make[1]: *** [f1a0ffc67dce5b883f01a6caac110369f271ce1f2befa80f235bc3e66522.elf] Error 1
make: *** [main] Error 2