ATmega128RFA1 state transition detection issue

Go To Last Post
26 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With the exception of the wireless transceiver, I have my ATmega128RFA1 fully programmed. This transceiver thing is all new to me, and I'm struggling to program it through the datasheet and the code examples I can find online.

So to get started, I want to simply change the state by writing to a register, and then try to detect a state transition to verify I did that part right:

sbi(TRXPR,TRXRST);//reset
		
//a transition has occured
if(TRX_STATUS_struct.trx_status == STATE_TRANSITION_IN_PROGRESS)
		rprintf("\nwireless reset detected");

Unfortunately however that code snippet doesn't actually print anything out. (I'm using USB out another UART to view the data)

What am I doing wrong?

I also tried writing to the sleep register, but no luck:

sbi(TRXPR,SLPTR);//go to sleep

This is what the datasheet says:

Quote:
If TRX_STATUS = 0x1F (STATE_TRANSITION_IN_PROGRESS) the radio transceiver is on a state transition. Do not try to initiate a further state change while the radio transceiver is in STATE_TRANSITION_IN_PROGRESS.

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> sbi(TRXPR,TRXRST);//reset

You should be aware that this is /not/ going to be an SBI instruction.
The address of TRXPR if far beyond the region that could be reached with
SBI instructions. Better get used to C bit manipulation operators, and
write:

TXRPR |= (1 << TRXRST);

> What am I doing wrong?

You're expecting an intermediate state that simply doesn't happen here
(or is not observable). STATE_TRANSITION_IN_PROGRESS can only be
observed for state transitions that last longer. A transceiver reset
immediately gets you into state TRX_OFF (i.e. the 16 MHz oscillator is
running because it already ran before, and the reset didn't turn it off).

It's better to check for the result of the transition, like

TXRPR |= (1 << TRXRST);
while (TRX_STATUS_struct.trx_status != TRX_OFF)
  /* wait */;

You might want to have a look at the µracoli project to get some
proven code base that's not as big as the Atmel IEEE 802.15.4 MAC
software or the Bitcloud stack.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok that definitely helped.

But I'm still having some issues.

this code to reset:

TRXPR |= (1 << TRXRST);
while(TRX_STATUS_struct.trx_status != TRX_OFF);
rprintf("\nreset detected");

correctly results in 'reset detected' being outputted.

Now after the reset, I then try to enter sleep mode.

but this code to enter sleep mode:

TRXPR |= (1 << SLPTR);
while(TRX_STATUS_struct.trx_status != SLEEP);
rprintf("\nsleep state detected");

just hangs.

What mistake am I making?

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just found this in the manual:
"If the radio transceiver was in SLEEP state, the SLPTR bit in the TRXPR register must be cleared prior to clearing the TRXRST bit in order to enter the TRX_OFF state. Otherwise the radio transceiver enters the SLEEP state immediately."

Perhaps this is why my while loop hangs?

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could you take a current measurement and confirm whether or not the transceiver sleeps?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried measuring current (it seemed like a great idea!).

But the current isn't just some stable value, it oscillates around a lot within a 1mA range (according to my multi-meter).

Thats an issue, because (according to the datasheet) in sleep current consumption should be ~0.25mA, and about 0.4mA in TRX_OFF mode. Thats a difference of only 0.15mA, and I'm not even sure if my multi-meter is that accurate . . .

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried this below code, but still nothing happens. It just hangs, meaning its not going into SLEEP mode.

TRXPR_struct.slptr=SLPTR;

while(TRX_STATUS_struct.trx_status != SLEEP);
if(TRX_STATUS_struct.trx_status == SLEEP)
     rprintf("\nsleep state detected");

That said, I've managed to get it into PLL_ON and RX_ON modes, showing I'm at least doing something right lol.

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Offhand I'm not sure, but I don't think you'll be able to ever read
the "SLEEP" state back, because the sleep mode will cut off the clocking
from the respective logic. Whenever the transceiver has been in
TRX_OFF, *and* you activate the SLPTR bit, it enters sleep mode until
you deactivate that bit again.

Of course, the AVR core itself remains running, and continues to draw
current. You have to put that one into its own sleep. Both sleep modi
are fairly independent of each other, which makes some sense: if you put
the AVR core to sleep, you could still have the receiver active (which,
of course, draws quite a bit of current), and it will wake up the AVR
upon a successful frame reception. Likewise, if you don't need the
transceiver but the AVR core for some computational work, you can always
put the transceiver to sleep so the 16 MHz oscillator can be turned off.
Just remember the 16 MHz crystal oscillator takes some time to start up.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting theory . . . perhaps the electronics that contain the registry are cut off from the core in sleep mode to reduce leak current . . .

I'm still having trouble transmitting. I've verified that it correctly goes into PLL_ON with this code:

if(TRX_STATUS_struct.trx_status == PLL_ON)
		rprintf("\nPLL now ON");

But this PLL_LOCK interrupt never seems to get called:

boolean pll_locked=false;
while(pll_locked!=true);//hangs
ISR(TRX24_PLL_LOCK_vect)
	{
	pll_locked = true;
	}

I try to go to BUSY_TX but this code also hangs:

TRX_STATE_struct.trx_cmd = CMD_TX_START;
while(TRX_STATUS_struct.trx_status != BUSY_TX)

What mistake am I making?

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> But this PLL_LOCK interrupt never seems to get called:

Your "pll_locked" variable lacks a "volatile" qualifier.

No idea why you never reach BUSY_TX when transmitting, albeit
a loop to wait for TX_BUSY doesn't make any much sense.
Instead, you might want to catch the TX_END interrupt, and
wait until this one has been reached.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
> But this PLL_LOCK interrupt never seems to get called:

Your "pll_locked" variable lacks a "volatile" qualifier.


I changed:
boolean pll_locked=false;
to:
static volatile boolean pll_locked=false;

but it still doesn't work. Is that what you meant?

dl8dtl wrote:
> No idea why you never reach BUSY_TX when transmitting, albeit a loop to wait for TX_BUSY doesn't make any much sense.
Instead, you might want to catch the TX_END interrupt, and wait until this one has been reached.

I tried this, using the volatile variables, but nothing gets printed out:

ISR(TRX24_TX_END_vect)
	{
	tx_in_progress = false;
	rprintf("\nTX sent");
	}
ISR(TRX24_PLL_LOCK_vect)
	{
	pll_locked = true;
	rprintf("\nPLL Locked");
	}

This code however *does* say TX now ON:

if(TRX_STATUS_struct.trx_status == BUSY_TX)
	rprintf("\nTX now ON");

But thats really strange, because this code used in the same spot still hangs:

while(TRX_STATUS_struct.trx_status != BUSY_TX)

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you actually activate all the IRQs?

Could I convince you to start playing with µracoli, instead of
rolling everything your own?

http://www.nongnu.org/uracoli/

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
Did you actually activate all the IRQs?

hmmmm actually I didn't, lol. Took me awhile to figure out what you meant, but I now have them enabled.

Anyway, I'm stuck again.

On my transmitter, the TRX24_TX_END interrupt is successfully called. This means its reaching BUSY_TX and in theory transmitting something.

On my receiver, the PLL_LOCK interrupt is successfully called when I go into RX_ON (the status also says it's in RX_ON). However, PHY_RSSI_struct.rssi is always 0. And the RX_START and RX_END interrupts are never getting called.

Thinking that maybe I'm transmitting an empty buffer, is this the proper way to transmit data?

//already in PLL_ON mode
uint8_t data=5;//should this be a char?
TRXFBST=data;//fill buffer
TRX_STATE_struct.trx_cmd = CMD_TX_START;//send
wait_until_end_interrupt();//this interrupt DOES occur

This is the only code I have to enable the RX interrupts, so perhaps I'm missing something?

IRQ_MASK_struct.rx_start_en=1;
IRQ_MASK_struct.rx_end_en=1;

ISR(TRX24_RX_START_vect)
	{rprintf("rx start works");}
ISR(TRX24_RX_END_vect)
	{rprintf("rx end works");}

Quote:

Could I convince you to start playing with µracoli, instead of
rolling everything your own?

I've been looking at the uracoli project since the beginning. The issues:
a) it mixes the wireless code with everything else
b) it's distributed over a dozen files
c) it uses defines of defines of defines (obfuscated)
d) it uses non-open source code in pre-compiled .a files
e) not commented well enough for a weak programmer like me
f) mixed with code for a half dozen other unrelated microcontrollers

Because of these issues, its very hard for me to extract the useful wireless code out from all the other code. In the end I gave up and decided to just figure it out from scratch . . . painful, but educational and necessary . . .

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>a) it mixes the wireless code with everything else

There are 3 parts, transceiver low level, radio (high level) and a set of io util / timer functions / buffer handling. you can use libradio sole w/o out these functions, as it is done for arduino.

> b) it's distributed over a dozen files

It supports two dozens of plattforms.

> c) it uses defines of defines of defines (obfuscated)

The alternative option is copy & paste (& die).
The idea is to have a minimal set of macros to fill for adding a new board/plattform, all other stuff the compiler can do. It looks like you did jump in the middle of the engine instead to take seat on the drivers seat ;-)

>d) it uses non-open source code in pre-compiled .a files

Nope, the .a files are the binary results of the source compile. The binary packages are meant for beginners to start with the examples and w/o the need to install python and scons.

> e) not commented well enough for a weak programmer like me

This is actually true.

> f) mixed with code for a half dozen other unrelated microcontrollers

h.m., other people may see the RFA1 as unrelated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

uracolix, you have good logical reasons for coding it the way you did. However, that doesn't make it easier for me to understand or use your code =P

If I send you the relevant code, would you be willing to look through it and find my mistake(s)? It's a single small file . . .

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The next days will be busy for me, but after thursday there will be time for a look into, either you place it here (so others can have look and write comment too) or you send it to uracolix (at) quantentunnel (dot) de, both options are fine, I think.

It would be good if the relevant part can be runnable on its own.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks =) Emailed.

Yeap, the wireless was kept as all one file. I also included my main file just so you can see the order that I'm calling the wireless functions.

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> However, PHY_RSSI_struct.rssi is always 0.

Keep in mind that the RSSI register is just a "snapshot". It is updated
each 1 µs (or so, see the datasheet), and really tells you the current
signal energy on the receiver. This is not necessarily energy generated
by IEEE 802.15.4 transmitters, but could as well be leakage energy by
a microwave oven, or energy transmitted by WiFi equipment.

Also, what kind of antenna are you using? If this is a shielded
setup (e.g. with an SMA connector), and your tx and rx are apart from
each other by more than ~ 50 cm, receiver energy could easily drop
below the RSSI minimum level (about -90 dBm).

If you want some averaging on the RF level, use the ED value. It
averages the RSSI across 128 µs. ED measurement can either be triggered
(in RX_ON state, where you already are) separately, or it will be
implicitly taken during the first 128 µs of each frame reception (once
you are able to actually receive something).

> And the RX_START and RX_END interrupts are never getting called.

Make sure the RF setup of both, the transmitter and the receiver matches,
in particular (obviously), both are using the same channel. As the
transceiver registers are mapped into the normal AVR memory space, if
you've got a JTAG ICE (or AVR Dragon in JTAG mode), you can easily
verify all the register settings online during a debugging session.

My reason for recommending µracoli was that you could get a successful
start first with minimal effort, so you can be sure all your hardware
is working as expected, by just setting up one of the simpler examples
that ship with µracoli (and using the binary libraries, you just have
to compile the example code, and link it against such a library, without
really being in need to rebuild all the low-level stuff itself).

Once you are there, you'll can walk step by step away from it, towards
your own application. For example, you could run the "diagradio"
application on one node, and have it continuously transmitting frames.
That way, you'll have a "known to work" source of valid frames (which
you could verify at first, using the "sniffer" application), so then
you can start debugging your receiver code until you see all the RSSI
(or ED) values, RX_START interrupts etc.

I think that step-by-step method will advance you much faster than
trying to write up *everything* from scratch.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks dl8dtl

I'm using both the Sparkfun ATmega128rfa1 dev board, and a custom board I made. Same issue on both.

You mentioned the diagradio test. I wasn't sure how to do it, and I couldn't find any documentation (can someone point me to it?), so here is what I tried:

I uploaded diag_rbb128rfa1.hex to what is my xmitter. Then I put sniffer_rbb128rfa1.hex on my receiver. Nothing seems to happen, although I'm not quite sure what to look for. I also tried rdiag_rbb128rfa1.hex and wuart_rbb128rfa1.hex on the receiver, but again, nothing.

So the question is, what hex files do I use for diagnostics, and what should I expect to happen?

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I would start with rather simple apps.

xmpl_trx_base.c blinks with 500ms, if IRQ and
transceiver access is Ok.

xmpl_trx_tx.c is sending every 500ms a frame,

xmpl_trx_rx.c is receiving.

Both should blink with a LED at PE2.

see also
http://uracoli.nongnu.org/manual...

HTH, Axel

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok thanks! Really helped. I get the 2Hz pin flipping on my Sparkfun boards (which I assume would only happen if the transmission is detected, right?).

uracolix, a quick favor . . . can you compile me a diagnostics rx and tx hex that flashes PD7? PE2 shorts a pin on my custom board . . .

I've made progress: I am using xmpl_trx_tx_rbb128rfa1.hex for my xmitter, and my custom code for the receiver.

The RX_START and RX_END interrupts are successfully getting called in my custom code.

However, this code always returns zeros for both variables:

uint8_t pRSSI=0;
uint8_t pEnergy=0;
pRSSI=PHY_RSSI_struct.rssi;
if(TRX_STATUS_struct.trx_status == RX_ON || TRX_STATUS_struct.trx_status == BUSY_RX)
	pEnergy=PHY_ED_LEVEL_struct.ed_level;

And this code always prints "bad data":

ISR(TRX24_RX_END_vect)
	{
	if(PHY_RSSI_struct.rx_crc_valid == CRC_VALID)
		rprintf("good data");
	else
		rprintf("bad data");

What mistake am I making?

Quote:
Is TRX_STATUS_struct.trx_status volatile ?

uracolix, I am using that from iom128rfa1.h that came with WinAVR. Here is a relevant snippet of it:
http://avr-libc.sourcearchive.co...

/* Transceiver Status Register */
#define TRX_STATUS                      _SFR_MEM8(0x141)

#if !(defined(__ASSEMBLER__) || defined(__NOSTRUCT__))

struct __reg_TRX_STATUS {
        unsigned int trx_status : 5;	/* Transceiver Main Status */
        unsigned int tst_status : 1;	/* Test mode status */
        unsigned int cca_status : 1;	/* CCA Status Result */
        unsigned int cca_done : 1;	/* CCA Algorithm Status */
};

#define TRX_STATUS_struct _SFR_MEM8_STRUCT(0x141, struct __reg_TRX_STATUS)

/* symbolic names */

#define P_ON                            0
#define BUSY_RX                         1
#define BUSY_TX                         2
#define RX_ON                           6
#define TRX_OFF                         8

This code also shows that my custom TX code isn't actually xmitting something, but I guess one thing at a time . . .

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I figured out why RSSI wasn't working before . . . apparently it can only be read after an RX_START interrupt and before an RX_END interrupt.

No luck for anything else yet . . .

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

UPDATE

Now that I have RX working, I tried my code back on my own custom boards again, and suddenly the CRC error disappears. Turns out the SF boards are total crap lol . . .

That said, I got a new problem . . . The RX_END interrupt gets triggered properly whenever I transmit data . . . however my code just reads out '222222222' (per frame).

I'm either filling my buffer wrong, or reading the buffer wrong. My tx code:

uint8_t data=5;//should this be a char? 
TRXFBST=data;//fill buffer
char data1=a;
TRXFBST=data1;

so in theory, the buffer should have '5a' and not '222222222', right?

Now for my receiver,

#define MAX_FRAME_SIZE (127)
static char wireless_recieved_frame[MAX_FRAME_SIZE];
//CRC check
if(PHY_RSSI_struct.rx_crc_valid == CRC_VALID)
	{
	uint8_t frame_length=0;
	uint8_t i=0;

	//get recieved frame length size
	frame_length=TST_RX_LENGTH_struct.rx_length;

	//read in frame from frame buffer
	for(i=0;i

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've discovered something . . .

Whatever uint8_t data equals, that determines frame_length. For example, if data is 8, then frame_length ends up as 8.

It's obvious I'm not writing/reading to the buffer correctly on a fundamental level . . . I found this in the manual:

"The Frame Buffer is located within the controller I/O address space above of the transceiver register set. The first byte of the Frame Buffer can be accessed with the symbolical address TRXFBST and the last byte can be accessed with the symbolical address TRXFBEND. Random access to single frame bytes is possible with “TRXFBST + byte index” or “TRXFBEND – byte index”. In contrast to the transceiver register access, the Frame Buffer allows single cycle read/write operations for all controller clock speeds."

and

"On received frames, the frame length byte is not stored in the Frame Buffer, but can be accessed over the TST_FRAME_LENGTH register. During frame receive, the Link Quality Indication (LQI) value (refer to "Link Quality Indication (LQI)" on page 72 ) is appended to the frame data in the Frame Buffer."

Now . . . how does that translate to code? lol

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I figured it out, mostly.

I wrongly assumed there was a single register I could read from to access the buffer. The solution is to read from each individual byte in the buffer memory one by one.

How do YOU make a robot?
http://www.societyofrobots.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, glad you finally found your mistake.

> apparently it can only be read after an RX_START interrupt and before
> an RX_END interrupt.

RSSI is a "snapshot" from the detector taken (I believe) each 1 µs. As
such, the value is not persistent. If you want a persistent value, use
the ED measurement. While it can be explicitly started at any time by
a specific command, it will also implicitly happen (in all the Atmel
802.15.4 transceivers, not just in the ATmega128RFA1 only) at the start
of a frame reception. ED is nothing else but an RSSI measurement averaged
across 128 µs, and its register value is persistent even after the frame
reception completed, until the next measurement is taken (either explicitly
or implicitly).

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.