Atom Feed
Comments Atom Feed

Similar Articles

2013-12-15 10:34
PICing up 433MHz Signals for OSS Home Automation - Part 1
2014-02-16 13:12
PICing up 433MHz Signals for OSS Home Automation - Part 5
2014-04-19 09:42
PICing up 433MHz Signals for OSS Home Automation - Part 6
2014-06-08 10:30
PICing up 433MHz Signals for OSS Home Automation - Part 7
2014-06-21 22:10
PICing up 433MHz Signals for OSS Home Automation - Part 8

Recent Articles

2019-07-28 16:35
git http with Nginx via Flask wsgi application (git4nginx)
2018-05-15 16:48
Raspberry Pi Camera, IR Lights and more
2017-04-23 14:21
Raspberry Pi SD Card Test
2017-04-07 10:54
DNS Firewall (blackhole malicious, like Pi-hole) with bind9
2017-03-28 13:07
Kubernetes to learn Part 4

Glen Pitt-Pladdy :: Blog

PICing up 433MHz Signals for OSS Home Automation - Part 2

After a free couple days to work on this there is now sufficient code to have some basics working. I've even been able to turn on and off the STATUS socket I have using the data encoder previously described.


The two 433MHZ RF modules are now connected to the USB-GPIO12 board with transistors to switch power. It did occur to me that the PIC might be able to supply enough current from a GPIO pin, but that will only be true of the RX module - I've measured 13mA to the TX module and that doesn't leave much wiggle room, risking that it may increase further once an antenna is fitted. Not worth messing around - a BC327 and a 10K resistor to the power control pins and I no longer need to worry about power.

USB-GPIO12 (PIC) based 433MHz Interface

I have deliberately soldered the TX module on at an angle since it keeps the antenna pads in a straight line with the RX Module and means that the TX side antenna pad is only ~3mm asymmetric from the RX pad. That should be good enough once I've got it boxed up.

Another refinement I've added is a small switch to make it easier to start the bootloader to update the firmware since that's something I'm doing a lot of right now.

Firmware Progress

This time round I built main.c from the ground up and also created high-level control routines for the RF Modules in a separate RFModule.c to keep things neat. The ISR is a bit heavy with code now and much of the encode/decode functionality needs to move into separate routines for manageability.

This is my first time using C on PIC microcontrollers - previously I've always used assembler. There are some distinct advantages, but it also adds a layer of complexity when things don't work as expected. I find myself having to go look at the assembler representation of program memory to figure out what is going on with some problems. In some cases the code being generated by the compiler is actually doing stuff that the docs warn against in special cases, so there are a few cases where a couple lines of assembler is needed to make things work.

Thorny Problems

Things have gone fairly smoothly but there are a few things that I've had to wrestle with.

Interrupt-on-Change Bug?

To accurately time things without eating CPU cycles I've been relying on the IOC function on PORTA & B (actually only on RB7), and was getting very bizarre and inconsistent results. After spending most of a day banging away on this I found that there are believed to be problems (and a workaround) with Interrupt-on-Change with PICs.

USB Throughput

With RX data there is a risk that the host communications (via USB) are not going to keep up with the rate that symbols are being sent. After all each symbol could be well under 1ms and so the rate they need to be transmitted is rather fast. Even if it should be fine with USB speeds, the PIC will need to buffer for any latency and that might be tricky with so little memory.

After a load of experimenting it looks like the biggest problem is CPU cycles soaked up by the ISR with fast transitioning data and calling CDCTxService() frequently enough. It doesn't appear that this can be interrupt driven, but rather needs calling frequently to keep data moving. That does limit what it is safe to do in the main() loop since putting in say a 500ms delay will severely impact USB throughput.

This is not a show stopper, just something that needs due consideration in the design of the code. Everything possible needs to be done to make all timing critical things use hardware timing and interrupts and the main() loop can then be used almost completely for pushing data over USB.

Next Steps...

The basic building blocks are in place now with initial planning having paid off with all hardware being configured exactly as expected. The biggest thing is to finalize the host communications and fully code that up so it can be made

General Control

Outside of TX and RX the module needs to be generally configurable. The main thing initially will be mode switching. Additionally some sort of basic "are you alive" or "ping" is also going to be useful for the host to make informed decisions. The initial General Commands needed are:

  • Ping - 0x00, 0xHH (identifier): Responds with 0x00 (General Acknowledge), followed by the same identifier. The identifier response is something I may change - just inverting it would provide a layer of safety against direct echos confusing things.
  • Check Mode - 0x01: Responds with 0x00 (General Acknowledge), followed by the corresponding mode command for the current state. This will allow us to find out if everything is as we left it or the unit has reset.
  • Idle - 0x02: Powers off all RF Modules, disables internal timer modules, interrupts etc. Responds with 0x00 (General Acknowledge).
  • RX Mode - 0x03, 0xHH (Prescaler), 0xHHHH (NEW: De-glitch length, MSB first): Power up and configure the Timer (Prescaler) for receive. The instruction clock is 12MHz and Prescalers of 0x00 - 0x07 turn this into Timer ticks of 16MHz - 46.875KHz with corresponding overflows (timeout) of 11ms - 1.4s. In practice the fastest that would comfortably cover all protocols being decoded would be the best option. RX Timing will be done with the top 15bits of the timer, leaving the bottom bit for the data state. The high resolution allows allowing easier handling of multiple protocols with different data rates using one configuration. Responds with 0x00 (General Acknowledge).
  • TX Mode - 0x04, 0xHH (Prescaler), 0xHHHH (packet gap): Power up and configure the Timer (Prescaler) for transmit. Same timing applies as RX (same timer), but as TX Mode will be configured for the one specific protocol being transmitted at the time, only 8-bit timing resolution will be used instead of the 15-bit for receive. This may be called when already active to reset the Prescaler configuration. Responds with 0x00 (General Acknowledge).
  • Reset - 0xff: Any invalid command will cause buffers to be flushed and the command interpreter to reset. This explicitly tells the unit to reset which includes disabling the RF Modules - effectively going into Idle, clearing all buffers, and responding with 0x00 (General Acknowledge).
TX Control

When transmitting we essentially want to be able to configure the bit encoding (4 stages with their own states and times), load the data, and then trigger transmissions of the data repeatedly (with open loop devices we would probably want to send a packet several times to get the best chance of it being actioned).

  • Set Bit Encoding - 0x10, 0xH (0-states), 0xH (1-states), 4x 0xHH (0-times), 4x 0xHH (1-times): Responds with 0x00 (General Acknowledge)
  • Set Data Length in bits - 0xxx, : This Responds with 0x00 (General Acknowledge).
  • Set Data - 0x11, 0xHH (length - 1), up to 32x 0xHH (data, LSB first): This will work out the number of bytes that are needed to represent the number of bits specified. The single byte length specifier allows maximum lengths of 256 bits (or 32 bytes) to be transmitted which is the maximum spec of the system currently. Responds with 0x00 (General Acknowledge).
  • Send - 0x12, 0xHH (number of packets): Starts data send. Responds with 0x00 (General Acknowledge), but only after the data has been sent. The host will need to do any timing (eg. deadtime) relating to the spacing of transmissions.
RX Control

This is very straight forward since we are simply putting the device in RX Mode and then it will listen for symbols being transmitted and return data to the host. The only special thing that is worth having is a sequence counter to give a measure of protection against buffer overruns.

  • Received symbols will start with 0xff to avoid them being confused with other responses.
  • Sequence - an 8-bit counter for verification
  • Time - 15 most significant bits is the timer value (LSb should be zeroed for time). 0xfe will be used to communicate timeouts (timer overflow)
  • State - the least significant bit will be the previous logic state pertaining to the time period being measured

That provides a 4-byte data for each symbol received, which for devices like the STATUS plug (~300us shortest symbol) translates to 107Kb/s, though that's never sustained as a longer (~900us) period would accompany that making the average 53Kb/s.