Showing posts with label radio. Show all posts
Showing posts with label radio. Show all posts

Friday, October 27, 2023

Updated Radio NodeMini with STM32

Here comes the updated version of Radio Node Mini on STM32f103. There are only a few visual changes, like places for the required pull-up resistors for the I2C bus. I add them automatically when someone orders the optional HTU21D temperature/humidity sensor. Other than that, only silkscreen labels are enhanced. But the most important fact is the change of way I make those boards. 

The chip crisis is fading out and with it all the components are getting cheaper. This brought me to an idea to use fabrication services. And since I'm getting busier and I value my free time even more, I tried to compromise and I let the new nodes be assembled and soldered at the PCB shop. I invested the effort into making a small panel of the boards and created BOM and CPL files for the machine assembly. 

Make it short, the service is great. Actually it allows me to lower the price of the Mini Nodes, simply because it takes me much less time. And not only by saving my labor time, but also the components are priced similarly, or sometimes even cheaper, to my preferred shop TME. There are only a few cosmetic problems with the micro USB ports, or the micro buttons which are not always aligned, but the boards are nicely soldered and even cleaned of the residue flux.

To celebrate this accomplishment, I made a new graphical pin-out diagram for the STM32 Radio Nodes Mini. Take a look:


Tuesday, January 16, 2018

Wireless node configuration.

Wireless nodes are part of OHS ecosystem. They serve as source of data from sensors, and as receivers for inputs. Inputs represents relays or other devices waiting for incoming commands. If you want to connect wireless node to gateway you need to set it up first. Start with download of example sketch from GitHub. Here is code for hardware version 1.4 https://github.com/vysocan/remote_1_4_RFM69. If you have on hand version with on-board temperature sensor and USB charging circuit then you can use the code almost without change. Basically you need to modify just the setting for radio module. Here is the part for radio

// Radio
#define NODEID      14
#define NETWORKID   100
#define GATEWAYID   1
#define FREQUENCY   RF69_868MHZ //Match this with the version of your gateway 
#define KEY         "ABCDABCDABCDABCD" //has to be same 16 characters/bytes on all nodes, not more not less!
#define ENABLE_ATC  //comment out this line to disable AUTO TRANSMISSION CONTROL
#define ATC_RSSI -75 

From this you need to only change following:


NODEID      2     // is number from 2 .. 250, do not number the nodes with same NODEID!
FREQUENCY   RF69_868MHZ // depends on your country, leave it as is or put RF69_915MHZ
KEY         "ABCDABCDABCDABCD" // needs to match the KEY of gateway.
ENABLE_ATC        // leave as is for battery powered nodes
ATC_RSSI -75      // threshold for AUTO TRANSMISSION CONTROL, you can safely leave as it is.

To start with minimal changes only, change just NODEID to be unique and KEY to match the one from gateway.

Wireless nodes are programmable, as gateway, with 3V3 FTDI 6pin USB to Serial programmer. They can be also powered from the programmer, that means you do not need a battery or charger plugged in while experimenting. To upload your sketch into board you have choose the right board target:
Select Tools > Board menu > Arduino Pro or Pro Mini, then choose Tools > Processors > ATmega328P (5V / 16Mhz)

All nodes run on 3V3 but on 16Mhz, as there is no such option choose  always (5V / 16Mhz), it will not do any harm. But FTDI programmer should be always set to 3V3 or the radio module will be damaged!

If all is set, you should see four new sensors in Node tab of gateway web interface. Wireless node then report temperature, battery voltage if battery is connected, charging status and own radio power level. Power level is useful to see how good the signal is when Auto Transmission Control is enabled, lower is better.

If you want to add new hardware to any node you need to create a default configuration for it in software. Assume that you want to add another temperature sensor to above mentioned four. First locate and change the total number of elements on this node, highlighted as bold:

// Configuration struct
struct config_t {
  uint16_t version;
  char     reg[REG_LEN * 5]; // Number of elements on this node
} conf; 

Then locate function setDefault(), you can see it is starting with following:

conf.version = VERSION;   // Change VERSION to force EEPROM load
conf.reg[0]  = 'S';       // Sensor
conf.reg[1]  = 'T';       // Temperature
conf.reg[2]  = 0;         // Local address
conf.reg[3]  = B00000000; // Default setting
conf.reg[4]  = B00011110; // Default setting, group=16, disabled
for (uint8_t ii=0; ii < 17; ii++){ conf.reg[5+ii] = 0;}

conf.version is place holder for node EEPROM setting and is to be left as is. But conf.reg[0..20] is place for default element configuration. Every element size is 21 bytes and their meaning is as follows:
  • 0  means the major element type. First letter of Sensor, Input, Key or Zone.
  • 1 is minor type of element. First letter of iButton, Temperature, Humidity, Pressure, Voltage, Battery, Digital, Analog, Float, TX_Power or Gas. If others are needed they should be added to GW software, or they will be reported as Unknown.
  • 2 Is local address in range from 0..255. In case you need to have more then one device of same type.
  • 3..4 are default configuration place holder, it is always as is. In real it holds various status flags of current element, but it is configured through web interface of gateway after it connects.
  • 5..20 are storing element name. Here set to null, as real name is received from web interface of gateway.
To go back to adding a new element you need to add bellow 21 bytes to the end of  setDefault() function and increase the number in [] accordingly:


conf.reg[84] = 'S';       // Sensor
conf.reg[85] = 'T';       // Temperature
conf.reg[86] = 1;         // Local address
conf.reg[87] = B00000000; // Default setting
conf.reg[88] = B00011110; // Default setting, group=16, disabled
for (uint8_t ii=0; ii < 17; ii++){ conf.reg[89+ii] = 0;}

Notice the local address is increased by one. Last thing after adding new element is to force the node to reset its EEPROM configuration and load the data from setDefault(). This is done by increasing the VERSION in top of sketch:
 
#define VERSION     140 // <- increase by 1

If you upload above changes to node gateway should recognize the new sensor and you will see it in Nodes tab. You can then configure it as any other element. Gateway will send the configuration back node and it will store it in its own EEPROM. This configuration persist even if you power off the node.

Next thing would be to actually add the code to handle your new sensor data. I skip the part of how you get the temperature value, as it will depend on which temperature sensor you are actually using. And I go directly to sending. Gateway receives various packets, but similar to registration structure mentioned above, sensor data need to follow data structure:
  • 0 identifies type of payload. First letter of  Sensor, Input or Zone.
  • 1 is minor type of element as defined in setDefault() function.
  • 2 Is local address as defined in setDefault() function.
  • 3..6 are the actual data.
For example following code:

// Temperature 
u.fval = (((float)analogRead(A6) * 0.003223)-0.5)*100; 
msg[0] = 'S'; // Sensor
msg[1] = 'T'; // Temperature
msg[2] = 0;   // local address
msg[3] = u.b[0]; msg[4] = u.b[1]; msg[5] = u.b[2]; msg[6] = u.b[3];
// Send to GW 
radio.sendWithRetry(GATEWAYID, msg, 7); 

It will read the analog value from A6 pin, then do some necessary calculation depending on this exact temperature sensor, and store it in special float variable u.fval. All data for sensors and inputs are type float, that is they are 4 bytes long. First part of msg[0..2] create the header describing the source of data and msg[3..6] reads the data converted from float u.fval to 4x u.b[0..3] byte values. Calling radio.sendWithRetry then sends the data stored in msg array to gateway. Length of data is set to 7 as it contains bytes stored in array msg[0..6].
In one packet you can send more then one payload of same major type, here as 'S' in msg[0]. As shown here:

// Temperature 
u.fval = (((float)analogRead(A6) * 0.003223)-0.5)*100; 
msg[0] = 'S'; // Sensor
msg[1] = 'T'; // Temperature
msg[2] = 0;   // local address
msg[3] = u.b[0]; msg[4] = u.b[1]; msg[5] = u.b[2]; msg[6] = u.b[3];
// BATT Voltage 
u.fval = 0.0064453125 * (float)analogRead(A7); // Voltage divider 2:1
msg[7] = 'V'; // Voltage
msg[8] = 0;   // local address
msg[9] = u.b[0]; msg[10] = u.b[1]; msg[11] = u.b[2]; msg[12] = u.b[3];
// Send to GW 
radio.sendWithRetry(GATEWAYID, msg, 13); 

All that is needed, is to prepare the data in msg buffer and increase the length of message. Radio message length cannot exceed 62 bytes, or the actual size of bytes allocated in sketch for array msg[].

And that should be all :).

Wednesday, August 27, 2014

RFM12B Radio

The radio part was left out a bit since beginning of the project. I believe in wires in such way that they are more reliable, and also can carry the power for the remote nodes. But the radio is important for future expansions as well. It can be used for remote self-powered PIR sensors, authorization nodes or for data gathering.
Yesterday I have decided to give them a try, because I had two RFM12B at home along with one bought antenna for the main station. Main station is build in metal enclosure and connected to earth that would block the radio waves. I put together one node with ATMega168 and soldered a radio on it. Then the 1/4 wave length antenna made out of single wire:

Wire lengths:

433 1/4 wave = 164.7mm
433 1/2 wave = 329.4mm
433 full wave = 692.7mm

868 1/4 wave = 82.2mm
868 1/2 wave = 164.3mm
868 full wave = 345.5mm

915 1/4 wave = 77.9mm
915 1/2 wave = 155.9mm
915 full wave = 327.8mm


And went for a search for library. I have found this library from LowPowerLab that looked good and suitable to my needs. Radios didn't work out of the box, but I had suspected it because my wiring are not using the ports the library expect. Main Board uses different pin for radio interrupt.

#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
  #define RFM_IRQ     10    // PCINT 10 / INT2

Allowing the PINCHG_IRQ instead of attachInterrupt did not work as well. But luckily changing the attachInterrupt form 0 to 2:

#else
  if (nodeID != 0)
    #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
      attachInterrupt(2, RFM12B::InterruptHandler, LOW);
    #else
      attachInterrupt(0, RFM12B::InterruptHandler, LOW);
    #endif 
  else
    #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
      detachInterrupt(2);
    #else
      detachInterrupt(0);
    #endif 
#endif

And packets started for flow through. For a short while, or they would go on on the main board, but the Ethernet stopped working. They both work on the SPI and the RTOS has no direct driver for it. A solution  worked fine:

#elif defined(__AVR_ATmega1284P__)
  #warning W5200 for AlarmBoard only!
  inline static void initSS()    { DDRB  |=  _BV(1); };
  inline static void setSS()     { cli(); PORTB &= ~_BV(1); };  // no interrupt while the SPI bus is busy
  inline static void resetSS()   { PORTB |=  _BV(1); sei();};   // no interrupt while the SPI bus is busy

Edit the Arduino Ethernet library file W5100.h so that it doesn’t allow RFM12b to interrupt while the SPI bus is busy handling Wiznet5100. Just add a cli(); and sei();. I will publish the modified libraies to GitHub.