Axradio_set_channel() Leaves Device on Channel 0?

Hi,

Playing with a F143-MINI-2-GEVK eval kit. I set up a project using AXRadioLab with:

  • Carrier freq 868.3MHz
  • Channel Spacing 500kHz (but also tried with 100kHz - values chosen to make changes visible on an analyser)
  • Number of channels 2
  • Asynchronous transmit, no acknowledge
  • Periodic transmit every 2s

I’d like to see the device transmitting on each channel in turn. I’ve written code such that each time a transmission ends, a variable current_channel_number changes from 0 to 1 or 1 to 0.

Then in the main loop (within the forever for(;;)) I have:

    if(axradio_get_channel() != current_channel_number)
    {
        if (DBGLNKSTAT & 0x10)
        {
            dbglink_writestr("Mode: 0x");
            dbglink_writehex16(axradio_get_mode(), 4, WRNUM_PADZERO); 
            dbglink_writestr(" S: 0x");
            dbglink_writehex16(axradio_set_channel(current_channel_number), 4, WRNUM_PADZERO);
            dbglink_writestr(" C: 0x");
            dbglink_writehex16(axradio_get_channel(), 4, WRNUM_PADZERO);
            dbglink_writestr(" N: 0x");
            dbglink_writehex16(axradio_phy_nrchannels, 4, WRNUM_PADZERO);
            dbglink_tx('\n');
        }
    }

Mode is given as 0x10 - async transmit. The status from axradio_set_channel() comes back as 0x00 (no error). axradio_get_channel() returns the right channel number (1 / 0 / 1 / 0 …) each time. However, when I look at the output on a spectrum analyser the transmissions are on channel 0 (at 868.3MHz) every time.

It’s puzzling as the device seems to think it is changing channel…but that’s not matching the transmitted signals. I’ve undoubtedly missed something in the docs. Is there something I need to do around axradio_set_channel() to get the radio into the correct mode for the channel to be changed?

Thanks,

Andy

Moving the code into axradio_statuschange(…) within the AXRADIO_STAT_TRANSMITSTART case fixes the problem. So I would guess it’s something to do with the state of the radio not being right in the main loop?

@joknomirta

I wanted to let you know that we are still looking into this one on our end. I will share the relevant information here.

Thanks @martin.bela. I’m not sure having my code to change channels right in AXRADIO_STAT_TRANSMITSTART is a wise idea. I suspect there might be a race between the transmission going out and the channel actually changing under some conditions.

@joknomirta

I have attached AND9360 software manual , which consists of a header file, axradio.h, providing
functions for transmitting and receiving packets, and switching the radio into different modes.

AND9360-D.PDF (191.3 KB)

Hi @martin.bela. Thanks - I have re-read that document, but I still do not understand what I’m doing wrong by calling axradio_set_channel() in the main loop. Is there an explanation somewhere that the radio needs to be in a specific mode for channel changes to be successful?

I suspect I have a similar issue to the one described here: AXM0F343 - Changing Frequency’s without Re-Programing - Connectivity / Sub-GHz - onsemi Community Forums. I don’t have the large frequency changes the poster there was trying to achieve, though. Your colleague @georgi.gorine suggests:

As mentioned above, you shall use the set_channel() routine alternating it with correct power mode. If you are unsure which power mode you are in, you could intentionally set:

radio_write8(AX5043_REG_PWRMODE, AX5043_PWRSTATE_SYNTH_RX); //Pause the receiver
axradio_set_channel(1); //change channel
radio_write8(AX5043_REG_PWRMODE, AX5043_PWRSTATE_FULL_RX); //Re-enable the receiver

Maybe what I need to understand is if I have an asynchronous transmitter, what registers and to what values should I write around the axradio_set_channel() call?

@joknomirta

axradio_set_channel(axradio_curchannel)

This function sets the channel number to be used. The mapping between channel number and frequency is configured in AXRadioLab.

 axradio_get_channel(void)

This function returns the currently used channel number.

axradio_set_channel & axradio_get_channel has to be in easy5043.c file not in the main.c file generated by AXRadiolab software.

uint8_t axradio_get_mode(void)
{
	return axradio_mode;
}

uint8_t axradio_set_channel(uint8_t chnum)
{
	uint8_t __autodata rng;
	if (chnum >= axradio_phy_nrchannels)
		return AXRADIO_ERR_INVALID;
	axradio_curchannel = chnum;
	rng = axradio_phy_chanpllrng[chnum];
	if (rng & 0x20)
		return AXRADIO_ERR_RANGING;
	{

I have attached AXRadioAPIManual.pdf (938.3 KB).

Hello @martin.bela,

I’ve dug into this issue some more. Could you mark my homework, please?

uint8_t axradio_set_channel(uint8_t chnum)
{
	uint8_t __autodata rng;
	if (chnum >= axradio_phy_nrchannels)
		return AXRADIO_ERR_INVALID;
	axradio_curchannel = chnum;
	rng = axradio_phy_chanpllrng[chnum];
	if (rng & 0x20)
		return AXRADIO_ERR_RANGING;
	{
		uint32_t __autodata f = axradio_phy_chanfreq[chnum];
		f += axradio_curfreqoffset;
		if (radio_read8(AX5043_REG_PLLLOOP) & 0x80) {
			radio_write8(AX5043_REG_PLLRANGINGA, (rng & 0x0F));
			radio_write8(AX5043_REG_FREQA0, f);
			radio_write8(AX5043_REG_FREQA1, f >> 8);
			radio_write8(AX5043_REG_FREQA2, f >> 16);
			radio_write8(AX5043_REG_FREQA3, f >> 24);
		} else {
			radio_write8(AX5043_REG_PLLRANGINGB, rng & 0x0F);
			radio_write8(AX5043_REG_FREQB0, f);
			radio_write8(AX5043_REG_FREQB1, f >> 8);
			radio_write8(AX5043_REG_FREQB2, f >> 16);
			radio_write8(AX5043_REG_FREQB3, f >> 24);
		}
	}
	radio_write8(AX5043_REG_PLLLOOP, radio_read8(AX5043_REG_PLLLOOP) ^ 0x80);
	return AXRADIO_ERR_NOERROR;
}

In this function, the code:

  1. Detects whether FREQAx or FREQBx registers are in use.
  2. Populates the required frequency values in the FREQnx registers that are not in use.
  3. Swaps the set of registers that are in use to the registers that have just been populated.

This avoids something interrupting part way through writing of the registers which could result in use of a poorly defined frequency value.

Unfortunately, in some operating modes, including AXRADIO_MODE_ASYNC_TRANSMIT, every time we come to transmit the following gets called:

__reentrantb void ax5043_set_registers_tx(void) __reentrant
{
	radio_write8(AX5043_REG_PLLLOOP        ,                              			0x09);
	radio_write8(AX5043_REG_PLLCPI         ,                              			0x02);
	radio_write8(AX5043_REG_PLLVCODIV      ,                              			0x20);
	radio_write8(AX5043_REG_XTALCAP        ,                              			0x00);
	radio_write8(AX5043_REG_0xF00          ,                              			0x0F);
	radio_write8(AX5043_REG_0xF18          ,                              			0x06);
}

This does not preserve the most significant bit in AX5043_REG_PLLLOOP. Therefore, every time we start transmitting we go back to the FREQAx registers. This makes it possible to change channel in:

void axradio_statuschange(struct axradio_status __xdata *st)

within the case AXRADIO_STAT_TRANSMITSTART since ax5043_set_registers_tx(void) has already been called. However, it is not possible to reliably change channels from main() since the change gets overwritten by the call to ax5043_set_registers_tx(void).

The only solutions I can think of involve modifying the file easyax5043.c. As this is a product of RadioLAB I’m not keen on doing that. Maybe there’s a better way?

Andy

There is a simple solution that does not require modifying easyax5043.c: call axradio_set_channel() twice from main(). Provided a transmission does not occur between the calls, that seems to work.