This page discusses issues related to hw40_D51.c and hw40A_D51.c.

Note: We have recently switched from CVS to SVN. CVS maintains version numbers on specific files, while SVN uses revision numbers that refer to a snapshot of a collection of files. On this page, I will show the SVN revision number that includes the file (e.g. r16) and the older CVS version number (e.g. v1.1) as applicable.

New source: HW40A_D51.c, SVN r14, CVS Version 1.1

In order to improve range, the original Hw40 WISP was modified to twin the outputs of the 1.8V voltage supervisor. Doing this allowed me to make an important change in the firmware.

Previously, I was checking for low power situations in various places in firmware, and if found I'd drop into sleep, waiting for an interrupt to tell me when I had enough power to process requests again. The problem was that I wasn't always checking power at the most optimal times; ideally, I'd like to be able to handle both low-to-high and high-to-low events as they happen. I tried this on the original hardware, but found that I wasn't always able to change the interrupt direction as fast as I needed to. So, Alanson modified the #4 WISP to twin the outputs, and I changed the firmware to capture interrupts on the single VS going on both directions. Now the code sleeps as soon as it goes past the VS low-power threshold, rather than waiting for certain pieces of code to execute.

These changes get us over eight feet of range for query-ack and query-ack-sensor applications. The read command range is still bad, though.

Because this code will work only on modified WISPs (currently, just WISP #4) I gave this source a new name. (Since it was still so close to Hw4.0, I decided to keep it as one implementation page.) While I was at it, I cleaned up some of the query-ack-sensor code. This cleanup will manifest itself in no more "empty" sensor readings, which is to say that every returned EPC will have a valid sensor reading in it.

Update: There's plenty of discussion going on about why read commands updates and range are as bad as they are. I'm collecting all the screen grabs from our experiments over at this new power lab notebook page. If you're the sort of person who wonders, "how much power does a single query-ack-request-rn-read of one word using the Mach1 app on an Impinj reader consume?", then take a look.

SVN r14, CVS Version 1.5

In this version, I fixed some state machine bugs, of which the most important was correctly detecting queryrep packets. A surprising effect of this was that we got a nice boost in range for query-acks and query-ack-sensor applications. I also fixed a nasty bug where we weren't reverting the clock to the correct receive state values when we were finished sampling the accelerometer, which garbaged up our incoming data for a chunk of time. I also turned off duty cycling and send the same sample data four times for the query-ack-sensor application.

From here, I'm likely to continue trying to improve range, including trying some voltage supervisor changes for read commands. Based on feedback I got at the meeting today, I'll backburner Alien reader compatibility.

Update: Alanson asked for a high level flow diagram of the current incarnation. Here it is: WISP4.0-StdFW-HighLevelFlow-v1.5.ppt (Powerpoint deck -- sorry!)

CVS Version 1.4

My goal for this version was to fix another incoming packet delimiter bug and clean up a little code. Nothing major, just a little minor surgery. But that's not what happened.

When I started looking at the packet delimiting bug -- very much like the query delimiting bug described in CVS version 1.3 below, but this time involving request_rn packets -- I saw that the state machine we were using really needed some serious work. Let me explain.

When we first started developing WISPs, we were working on constrained devices that didn't give us much code space. Basically, there was no way we could implement the full state machine as laid out in the spec. So instead we brewed up our own state machine, based on the real world packets we were getting from the readers we were testing against. So, we had the query state and the ack state, instead of the arbitrate state and the reply state. For the access commands, this got messy, because it turned out that different reader firmware versions sent different sequences of packets. We dealt with this by duct taping our homebrew state machine (metaphorically speaking). But nonetheless readers would sometimes send us sequences we weren't expecting, and we'd stop responding until we hit the next reset. The code was brittle and inefficient.

In the course of looking at the delimiting bug, I saw that instead of adding more duct tape, I should take advantage of the improved code space situation and put in a state machine that matched the spec. This was something I had in mind for down the line, but now I saw that I should get this big change over with now, rather than wasting time with this workaround to the original state machine and that workaround to the original state machine. So that's what I did.

From a purely functional point of view, there's not much difference between CVS version 1.3 and 1.4, except that I've lost some ground in the range war. (I expect to be making more changes to the state machine in the future to address that, as well test a proposed hardware change that I hope will extend range in access command cases.) But if you want to experiment with the Gen2 protocol, I think I just made your life a whole lot easier.

CVS Version 1.3

This version does three things: it adds in read-command-with-sensor-reading functionality; it adds support for queryrep commands and fixes problems with mangled query packets, dramatically improving the response-to-query ratio; and it improves the range for simple hardcoded query-acks. It also corrects the ID code back to D51; in CVS version 1.2 it went out as 52A.

New in this version is the ability to retrieve six bytes of accelerometer sensor data within a read command. To do this, set both the ENABLE_READS and READ_SENSOR #defines to 1. All other applications are configured the same way they were in version 1.2: To do a hardcoded query-ack, set both the ENABLE_READS and READ_SENSOR #defines to 0. To do a query-ack with accelerometer sampling, set the ENABLE_READS #define to 0 and READ_SENSOR #define to 1. To do a read, set the ENABLE_READS #define to 1 and READ_SENSOR #define to 0.

Let me expand a bit on the discussion of power management in the "more update" section of CVS version 1.2. With this version, we have 65" of range for hardcoded query-acks, which is a nearly 20% improvement over what we had in version 1.1. I think most of that is due to much improved handling of query packets, and support for queryrep commands. Previously, the code wasn't handling queryreps and was appending those four bits onto the next packet. The result was mangled data and a poor response rate. Now the code handles queryreps appropriately and so the following packets aren't mangled and so they get handled appropriately too. In other words, now I get four bits and send a response, instead of getting 25 bits and dropping the bits on the floor because I don't understand the packet.

All the other applications have considerably shorter ranges, about 27". They all do more work than a simple query-ack, and so they need more power to stay up through a chain of actions. So to build up this power, I use the clock to duty cycle off at LPM3 before beginning a new chain of commands. But if we're going to push significantly past the current range for these applications, then I think we need to figure out how to duty cycle off at LPM4, which means that the WISP needs an external interrupt to manage it. One method would be to base the timer off a crystal. But the better approach is Alanson's idea about adding another voltage supervisor. With the timer, we're just guessing about when we're ready to start responding; with another voltage supervisor, we can start responding as soon as we've got enough power to roll.

Another thing about range: in my query-ack testing, I found that I got considerably better range using the Impinj web app instead of the SDK app. The difference was 65" versus 48". (I couldn't run the same test with the read command code, because the Impinj web app doesn't really do the full sequence of commands all the time.) That strongly suggests that there's room to alter the SDK app to drive the reader at a faster pace and get more range out of the WISP.

I still haven't check Alien reader compatibility.

Right now, the sensor read sequence happens at the end of a chain of commands. That means that if this is the first response after slipping below the RAM retention mode, no real data is being sent back. And even if the WISP stays at or above RAM retention mode, the sensor data matches the previous query, not the current one. So it would be nice to experiment with moving the sensor sampling to the beginning of a command chain.

The code could use some tidying up.

CVS Version 1.2

CVS version 1.2 takes the power management tweaks described in the CVS version 1.1 update section below, adds in the query-ack-accel sensor changes I first made in hw40_D52A.c, and has a preliminary cut at a read command.

To do a hardcoded query-ack, set both the ENABLE_READS and READ_SENSOR #defines to 0. A scope grab of this sequence follows.

v 1.2 query-ack

To do a query-ack with accelerometer sampling, set the ENABLE_READS #define to 0 and READ_SENSOR #define to 1.

To do a read, set the ENABLE_READS #define to 1 and READ_SENSOR #define to 0. In this first cut, you will get back a hardcoded value of 0x030x04. Here is a scope grab:

Hardcoded read

Note: in this scope grab, the read is happening only once, about 90 ms into the receive/response sequence, where there's a tiny green spike. That's because the Impinj web interface caches read data.

The constant resets are gone, but you still see a lot of queries responses that aren't followed up with ack responses. I need to figure out what's going on there.

I still haven't check Alien reader compatibility.

The range has gone down. In the hardcoded query-ack case, it went from about 56 inches down to around 32 inches. The device I've been testing on (WISP #4) got dropped yesterday, so it might be that the WISP has gone a little flaky. Or it might be that I did something to kill the range in the firmware.

The read returns a two byte hardcoded value. The next step would be to fold in the variable length read work that's been done for the G2.0 WISP.

Update: Well, like good software engineers everywhere, I tried to blame to decreased range for hardcoded query-ack on the hardware. But my plan was tharted by actual, you know, facts. I regressed to CVS version 1.1 on the same hardware, and I had around a 40% increase in range. So obviously I introduced a power leak for query-ack in this release. :^(

More update: OK, now I have a version of the query-ack code that supports cold starts at up to 65." That's better than what I had for version 1.1. I chalk this up to two things.

Thing #1 was to remove the power build up code for the simple query case. The power build up code goes into LPM3 for fixed periods of time; apparently, for simple query-ack code, it was substantially more power efficient to continuously execute a mixture of AM and LPM4 code than to go into fixed LPM3 sleeps. Simple query acks don't need a lot of excess voltage to operate, since they only send out two packets to complete a round, so they don't really need the power build code anyway. They run well right at redline anyway.

Thing #2 is about doing a better job of interpreting the incoming bits, and thus wasting less power looking at mangled packets and recovering from them. In the original version of code I was working from, it was checking that it had 25 bits before it went to see if it had a query packet. The spec has query packets at a fixed length of 22 bits. That's odd, I thought, how did this code ever work? And why are so few queries getting responses? The answer turns out to be that the Impinj reader sends out a lot more queryrep commands than queries. The code wasn't handling the 4-bit queryrep, so the bits were getting appended to the following query packet, usually mangling the packet and getting it dropped on the floor. I've added code to handle the queryrep, so now nearly every packet is getting interpreted correctly and responded to.

Reads still have a terrible range compared to the simple query acks, and because it involves a chain of four packets to process an entire sequence, I can't just junk the power build up code. So, ultimately, I have to figure out a way to duty cycle in LPM4 rather than LPM3 if I ever want to see decent range on access commands. And that means an external interrupt -- a crystal, or maybe a second, higher voltage supervisor that I'd use for complex chains of commands. The second SV would be the most efficient solution, because you'd get going as soon as you had enough juice to do your work.

CVS Version 1.1

CVS version 1.1 demonstrates a simple hardcoded query/ack. It's based on the version of firmware that Dan and Richa worked on in mid 2008 that ran on WISP 4.0DLs equipped with a 3v voltage supervisor. This version has modifications that allow it to run on WISP 4.0 DLs that have the 1.8v voltage supervisor (in addition to continuing to run on the 3v version).

Since it is derived from code that worked with both Impinj and Alien readers with recompilation, in theory that should be true of this version too. Compatibility with alien readers in addition to Impinj readers needs to be verified, though.

The big change in this version is that the voltage supervisor port interrupt is left on all the time, and if it receives an interrupt outside of a sleep context, the device resets. This was done to eliminate a race condition where the device samples the supervisor and decides it has enough power to continue operating, but actually goes into a brown out state before it resamples the supervisor pin. Problem: the device will reset after nearly every ACK, which means that we'll never get through a query/ack/request_rn/read cycle with this voltage supervisor.

A problem I've noticed is that even though the throughput looks good on the web interface, the code is responding to ACKs a pretty small percentage of the time. The timing for ACKs needs some tweaking.

Update: I've dug into the poor ACK rate problem a bit more, and this scope grab shows the real problem. Blue shows the incoming packets from the reader, and yellow are the response packets. The thin yellow packets are QUERY responses, and the fat packets that follow are ACK responses. As you can see, only one of the four queries gets an ACK. Look at the purple and green lines to see why -- purple is Vcc. and the two green boxes are debug lines that get toggled whenever the device boots up. I added the red line after the fact to indicate what the voltage supervisor's looking for. The reader antenna is about 16 inches away from the WISP, and I'm using the web interface.

Poor ACK response problem

So the problem with the poor ACK rate is that the device just doesn't have enough power to complete the response chain most of the time. In fact, this device is trying to answer a lot more queries than it can handle, and consequently never builds up enough of a store to handle the sequence. Forget handling access commands under these circumstances.

Time to throw some duty cycling into the mix!

Update 2: Here is a reworked copy of CVS version 1.1 with some duty cycling baked in. Green goes high when it is duty cycling; blue, yellow, and purple mean request, response, and Vout, respectively. It duty cycles at bootup, after sleeping in the timeout code at the top of the main while loop, and when it sends out an ACK response.
version 1.1 + some duty cycling

It's not resetting all the time anymore. However, the range is still awful and it still spends around a volt answering a sequence that goes like this: QUERY, no followup ACK, QUERY, ACK. What's up with that missing first ACK? (This is pretty consistent, BTW.) Just think how much power we could save if we could compress that.

With a little more investigating, I found out that the reason why I'm not sending an ACK back is because the incoming packet is another QUERY request, not an ACK request.

Firmware status

Note: This section describes the status of the latest versions of each release. See the release-specific implementation notes for status of previous versions.
Fw src
RFID protocol
Range (cold start)
known issues
hw40A_D51.c - r14/v1.1
Impinj 3.0.2
98" in query-ack and query-ack-sensor; 27" in read; 30" in read-sensor
used modified wisp #4 in test; wisp #4 X-axis is broken

hw40_D51.c - r14/v1.5
Impinj 3.0.2
71" in query-ack and query-ack-sensor; 30" in read; 29" in read-sensor
used wisp #4 in test; wisp #4 X-axis is broken

hw40_D51.c - v. 1.4
Impinj 3.0.2
50" in query-ack; 31" in query-ack-sensor; 16" in read; 19" in read-sensor
used wisp #4 in test; wisp #4 X-axis is broken

hw40_D51.c - v. 1.3
Impinj 3.0.2
65" in query-ack; about 27" in all other apps
used wisp #4 in test; wisp #4 X-axis is broken

hw40_D51.c - v. 1.2
Impinj 3.0.2
32" in read; 36" in query-ack
used wisp #4 in test; wisp #4 X-axis is broken

hw40_D51.c - v. 1.1
Impinj 3.0.2
used wisp #4 in test