Mini STM32 Firmware Uploader

stm32_icon_bigAfter multiple Windows crashes caused by ST’s “Flash Loader Demonstrator” v2.7.0 I decided to write my own library that will allow me to talk to STM32’s on-chip bootloaders via USART in C# .net. This is the initial yet fully functional version: https://github.com/MightyDevices/STBootLib (binaries: here).  This implementation uses classic SerialPort class with no additional magic which allows for safe operation (no system hangs whatsoever, even with very cheap USB<->UART dongles). In addition I’ve written a simple firmware updater app that I use extensively without any problems.

User interface

Keep is simple, stupid. Simple, usable and operational.

screen

As you can see I’ve kept the interface to a minimum, just to make the application less demanding in terms of occupied space. Here’s the list of functionalities for version 1.0:

  • Initialization of communication – getting bootloader version, product ID, command list
  • Writing to a memory area
  • Reading from memory ares
  • Erasing Flash pages (with Flash erase or Extended flash erase commands – both supported)

Usage:

This small code snippet shows the basic usage of library functions:


/* bootloader class instance */
STBoot stb = new STBoot();

/* open the port */
stb.Open(portName, baudRate);
/* initialize communication */
await stb.Initialize();

/* write memory @ address, bin = binary file in byte array */
await stb.WriteMemory(address, bin, 0, bin.Length, null,
CancellationToken.None);

/* jump to user application */
await stb.Jump(address);

/* close port */
stb.Close();

RTL SDR Upconverter for Shortwaves (0-30MHz)

ne612_icon_bigThis is a simple yet completely functional upconverter for the popular SDR donlge. The construction was build around cheap and easily obtainable mixer IC marked as NE 612, manufactured by Phillips Semi. Despite its limitations, it performs outstandingly well, at least when price-to-quality factor is discussed. This IC is used to upconvert 0-30MHz to a region acceptable by SDR dongle: 100-130MHz, all of that was achieved by employing a 100MHz 4-pin crystal generator.

Here’s the electrical schematic of the apparatus itself ;]

Upconverter-1

Modus Operandi

Since I am using an active antenna (MiniWhip) I needed to provide a power supply to the input port. This is accomplished by parts: J3 C15, C16 and L5 that acts as a RF choke. Received signal is passed through an elliptic (Cauer) filter that rolls off at around 27MHz providing full coverage to all bands of my interest. R1 is to terminate filter which was designed to be a 50 Ohm in both input and output ports.

We are dealing with a broadband input (frequencies are spread across multiple octaves), so it would be very difficult to achieve a good match to NE612 input impedance without using a transformer or an active device, and since I wanted to stick with standard components (no DIY coils, etc.) I decided to go with R1 despite it being a very “sub optimal” solution. Your approach to this problem may vary.

Q1 generates 100MHz periodic signal which is far from being sinusoidal, so I took the effort of calculating a simple series resonant circuit: L4 and C13. Since NE612 requires the LO to stay in 200mVpp-300mVpp range I’ve inserted a simple resistive ‘pi’ attenuator that gives about 15dB of attenuation. R2 is a parallel combination of 75 Ohms and desired load impedance: 50 Ohms (pin 6 has much higher impedance than required 50Ohms).

Output matching (here implemented by C8-L3) was calculated to perform impedance transformation form 1.5kOhm to 50Ohm @ around 112MHz, and gives a nice broadband match.

L4-C14 is optional, and servers the sole purpose of LO feed-through suppression which can be problematic (LO can easily saturate RTL dongle). One needs to experiment with C14’s capacitance, as the circuit is very touchy (please mind the component tolerances), due to the high Q (this is in fact a narrow notch filter that tries to kill the LO and leave everything else). I found that even PCB stray capacitance plays a major role here. Fine tuning can be done by observing the magnitude of LO tone on any SDR software as one increases/decreases C14’s value.

Room for improvement

Some steps that might be undertaken in order to the improve overall performance:

  • Use a transformer to transform input signal form 50Ohms to NE612 input impedance (~1.5kOhm)
  • Use another transformer or LC-CL balun at the output port
  • Applying both points from above will result in full double-balanced operation (this is what NE612 is intended for) and will lead to significant LO feedthrough reduction, so no more crappy and hard to tune L4-C14.
  • Don’t be a cheap bastard like me and use a goddamn LDO for crystal generator supply voltage!
  • Use a 125MHz crystal generator: this will help to avoid FM broadcast stations getting in the way, remember to redesign LO and output LC circuits.
  • Use a better mixer: look for something with a decent IP3

Showtime!

.. and a picture that documents my mad SMD skills :]

IMG_0430

IN-12 Nixie Clock

nixie_icon_bigA time has come for me to say ‘hello’ to the mid-XX century technology of  Neon numerical displays, also known as Nixie tubes. Despite being quite hard to obtain and utilize I’ve decided to make a nice looking clock which (hopefully) would make a perfect Christmas present, and since the Christmas is all about sharing I thought It would be nice to go Open Source about it.

After few weeks of work I’ve ended up with neat single board design that makes the whole thing cheaper and easier to manufacture than the usual double board solutions (separate board for nixie lamps/divers, and another for microcontroller, power supply, high voltage dc/dc conversion, etc.). All of the circuitry is laid out on the back of the clock so it does not interfere with the old-school look of the Nixie displays.

Not a single LED was involved in that project, as I find those to be a disgrace when mixed up with neon indicators. (Geez, this is like, ‘your opinion’, man! :) )

nixie

The ‘Ne’ part

I wanted to keep the clock’s form factor as small as possible, so I chose it to be a standard HH:MM clock (without ‘seconds’ display) which requires only four Nixie tubes and two neon lamps for the separating colon.

I’ve decided to use IN-12 type Nixies as those are very popular here in Eastern Europe, but can also be easily bought on ebay and shipped worldwide. Those lamps are actually pretty cheap, mostly because they were manufactured in really large quantities back in the day.  One thing that’s worth mentioning: since those Nixies come straight from Soviet Union, where almost no one paid any attention to the quality of whatever they’ve been producing, it will be wise to buy, let’s say a 150% of lamps that you need for your project. This gives the possibility to compensate for all imperfections (and believe me, these can get ugly like: digits being tilted, pins not being centered, ‘funny’ frontal grid color, etc.) which can easily degrade the overall look of your Nixie clock.

As for the separating colon I went for INS-1 Neon lamp, which has the advantage of being similar in height as the glassy part of IN-12, so it will make a perfect separator.

Every clock needs a way of setting the time, and the simplest way of achieving this is to embed buttons (like micro-switches).  Since I’m aiming towards keeping the overall look to be as minimalistic as it is possible (well, Nixies don’t necessarily present themselves as ‘minimalistic’ to begin with.. ) I came up with a neat idea of placing the two buttons just under the INS-1 lamps, so when colon dots are pushed they, in fact, press the micro switches and, since the switches have the ‘springy’ action they move the colon lamps back to their original position as soon as user stops pushing.

The ‘Si’ part

Well, actually there is not much space left on the ‘bottom’ side of the PCB (which is in fact ‘back’ side, at least when the orientation of the Nixies is considered), so it became obvious that I need to go for SMD parts if I ever dreamed of fitting in.

After a few hours I came up with the following schematic:

Nixie-1

uC

For the uC I went a for good ol’ friend of mine: STM32L152 which is a really powerful device while still being affordable. The micro itself will be responsible for:

  • multiplexing the display (timing, signal driving, etc) (GPIO)
  • driving the high voltage DC/DC converter according to required voltage/current being drawn (TIMER to generate PWM, ADC to measure the output voltage)
  • measuring time  (RTC with external 32768Hz crystal resonator)
  • reading state of the buttons (GPIO, External Interrupts)
  • monitoring the main power supply, and sustaining the clock settings even when power fails, using external battery/super-capacitor. (GPIO, Cortex-M3 Stop Mode)

All of those tasks can be done with almost no effort in STM.

Nixie Drivers

Nixie lamps can be thought of being very similar to common anode LED displays, which means that every lamp has its own common anode, and ten separate cathodes (for digits ‘0’ – ‘9’). What’s important is that Nixies show very promising results when being used with technique called Multiplexing, which can lead to a considerable reduction of total number of driving signals. A naive approach for four Nixies would require 40 driving signals (40 catchodes, all anodes connected directly to high voltage rail) while multiplexing four tubes requires only 14 signals (10 cathodes, 4 anodes). One must remember that multiplexing comes at the expense of display intensity (or brightness) since a single Nixie is being powered on for only 1/4 of the cycle. That however, can be compensated by increasing the supply voltage.

Although there are some ICs dedicated for driving cathodes of Nixie lamps I decided to go for transistor level solution, so every cathode has its own transistor with a current limiting base resistor. This is actually quite beneficial, mainly because It gives the possibility to spread out the parts along the PCB, and since SMD transistors are small, they can be distributed almost anywhere on the PCB. Second reason for using transistors was that I wanted to avoid using parts that might be obsolete/hard to buy.

Anode side is driven by a two transistor circuit: PNP keys the anode voltage on and off, while NPN acts as the level-shifter, so that uC could interface the anodes. By the way: it is very important not to omit the resistors that connect the base of the PNP transistor to the supply line (R3-R6) as the PNPs will operate at the edge of being turned on. This is because of the leakage current of the NPN transistor, which although being very small (in range of nA) gets amplified by the factor of PNP’s beta which might be sufficient for the Nixie lamp to be ignited, resulting in unreadable display! (remember, we are using Mutliplexing here so we need to have a way of turning Nixie off completely!)

I used general purpose NPN/PNP transistors that have high Collector Emitter Breakdown Voltage. This is the most important parameter here – it tells us that transistor won’t get damaged when high voltage is applied nor will it leak any unwanted current.

Generating High Voltage

Many of the solutions available on the Internet are using large parts for DC/DC conversion like: beefy transistors that are capable of dissipating some serious power, bulky, high-inductance inductors, and near-audio frequency switching regulators. Seeing that, I knew it was at least worth a try to design my own converter, as those solutions would’t even fit onto my PCB!

Before I started the design process I wrote down some basic remarks about converters:

  • Output voltage – this is totally Nixie dependent. I’ve settled around 130V – 140V, which is good for Multiplexed IN-12, but you may need to experiment on this value, especially if you plan to use different tubes.
  • Output current – again, mostly Nixie dependent (datasheet tells us to keep the current under 2.5mA for the Nixie and 0.5mA for a single Neon lamp used in separator), BUT many different parts of the circuit will cause an increase in current being drawn. First of all: the step-up feedback network which is nothing more than ~1Meg Ohm resistor connected between the output and ground, so it adds 130V/1Meg = 130uA. Anode drivers will also use current, but since only one Nixie is being powered at time we can calculate the current as if there was only one Nixie present in the design: 130V/2Meg = 75uA. Let’s stick with 5mA total.
  • Input voltage – the bigger – the better! It’s best to keep the voltage ratio somewhere between 1:10 – 1:20. Using higher ratios will likely result in sudden drop in efficiency, and will involve high input current spikes, that may even get radiated from power cord! I went for voltage range of 10-16V, which is dictated by lowest acceptable operating voltage of MOSFET driver and by the voltage rating of the capacitors used for filtering input voltage.
  • Inductor – needs to be small (not much space on PCB!), which can either result in small inductance/small DC resistance/high current capabilities or just the opposite: low inductance/high DC resistance/low current.
  • MOSFET Trasistor – needs to withstand large voltage generated by inductor. Fast switching and low ‘on’ resistance are also required, as those parameters contribute greatly to power dissipation (power wasted into heat). Choosing the correct transistor for the job is always a compromise between low ‘on’ resistance and high voltage handling capabilities. There are some models that have both, but those can get expensive. Remember to check for drain current vs gate voltage. Many MOSFETs require high gate voltage (mine did) in order to open them fully (i.e. get high drain current), so adding a MOSFET driver is a good option, especially when even cheap (<$1) drivers can provide +/- 1.5A of driving current (bare GPIO pins max out at 20mA) which increases the switching speed tremendously (lower losses).
  • Diode – component responsible for transferring the energy from inductor to filtering capacitors. It’s contribution to whole circuit is often neglected which may lead to many problems. Most important factor is Reverse Breakdown Voltage which tells us about the maximal voltage that can be present between cathode and anode. Exceeding this voltage will essentially lead to voltage being fed back to input voltage rail! Another important factor is Reverse recovery Time which describes how much time it takes for a suddenly reverse polarized diode to start blocking the current flow. This parameter will have a very significant impact on the efficiency since it tells us about how much energy stored in output capacitors will leak back to input power rail after the switching cycle has completed. Remember to keep this parameter to minimum (use ‘fast’ diodes). Try to choose right diode for the job. Large diodes are not always the best choice as those often have higher conduction losses.
  • Controller – Since I had to keep the number of parts to the minimum I’ve decided to implement my own step-up (boost) converter regulator using the resources provided by the microcontroller. I chose to operate the converter in so called Discontinuous mode, which has the advantage of being easy to implement in software. The whole regulation process will be based on adjusting the frequency of MOSFET gate pulses that have constant width.

Now, lets make some assumptions: I chose to use 12V wall brick power supply, which are widely available, so that makes for the input voltage. The input voltage and the inductance will determine the rate at which the current is being build up in the inductor.

\[I[A]=\frac{V_{in}[V]*t[\mu s]}{L[\mu H]} \]

Inductor current should never exceed so called Saturation current. This is the point where inductance suddenly decreases (at least by a factor of 10% – 20%) because of the magnetic core being saturated. Inductor then starts to behave more and more like the pure resistance (heats up, stores little energy) as no more magnetic field can be build up!

A compromise needs to be made when choosing the inductor value especially for a given maximum size, which in my design is about 5x5mm. I did some research among different component suppliers and got my hands on SRN5040 Series from BOUNRS.

Low inductance would require very short (sub microsecond) gate pulses in order to stay below the saturation current. It would also cause a large current to flow through MOSFET, as well as being drawn from input voltage rail. The process of fully opening and closing the high voltage MOSFET is a sub microsecond manner is not an easy thing to do. Diode recovery times will contribute greatly to conversion losses, if they are becoming comparable to overall cycle length.

High value inductors will saturate later which eases the timing requirements, but they present higher DC resistance. Less current is required to store the same amount of energy as in low value inductors, so MOSFET does not need to handle large currents. Since the overall cycle will be longer the output voltage ripple will get higher for the same output capacitance. The only way around it is to add more capacitance to output, but keep in mind that high voltage capacitors can get pretty darn big!

Having said that I chose 15uH inductor (Part No.: SRN5040-150M) which offers a very good ratio of size/saturation current/inductance. In fact it offers the greatest energy storage capability of 60 micro Joules, at least when SRN5040 series is considered. Manufacturer claims that inductor has the saturation current level of 2A. Let’s crank the numbers:

\[E = \frac{I^2 * L}{2}  = \frac{4 A^2 * 15\mu H}{2} = 60\mu J\]

\[I = \frac{V * t}{L}, t=\frac{I*L}{V} = \frac{2A * 15\mu H}{12V}  = 2.5\mu s\]

The information about energy lets us derive the actual cycle period, knowing the golden rule of energy conservation. One needs to know that not all of the energy will be transferred to output. Some of that energy will be wasted, mostly into heat (can be problematic), some will be radiated as electromagnetic waves (can be very problematic). It is safe to assume the efficiency (often denoted with greek letter Eta, η), of such simple, discontinuous mode, converter to be around 60-70%. That leaves us with following portion of effective energy transferred during every cycle:

\[E_{eff} = E*\eta = 60\mu J * 60\% = 36\mu J\]

Since Nixies are consuming 5mA at 130V we calculate power to be:

\[P=I*V=5mA*130V=0.65W\]

Lets now calculate the time required for Nixies to consume all the energy provided:

\[E_{eff} = P * t, t=\frac{E_{eff}}{P} =\frac{36\mu J}{0.65W} = 55\mu s\]

Having done that we end up with nice, easy to generate, pulse train, Generating 2.5us pulses asks for uC clock to be at least 2MHz for 0.5us resolution, which is not a problem (Medium Speed Internal Oscillator, MSI, gives 2096kHz, close enough!). uC’s job will be to generate 2.5us pulses that will open the MOSFET and adjust the frequency of the pulses according to calculated base value of 55us  and the instantaneous demand on current. The frequency of pulses at maximal current (5mA) will therefore be:

\[f = 1/t = 1/55\mu s \approx 18.1kHz\]

This is just at the edge of audible frequencies range, and we know that circuit will not always draw full 5mA. When it uses less current this frequency will drop (energy portions from inductor will be required rarer) and become even more audible and annoying as well. One way around it is to make the pulses shorter, lets say 2uS, so the inductor stores less energy:

\[I = \frac{12V * 2\mu s}{15\mu H} = 1.6A\]

\[E_{eff}=\frac{2.56A^2*15\mu H}{2}*60\%= 19.2\mu J\]

\[t = \frac{19.2\mu J}{0.65W}=29.5\mu s, f \approx 33.9kHz\]

See? Well above audio frequencies, and all done in software. Neat! Just keep in mind that further decreasing pulse width will have an impact on efficiency and ‘60%’ assumption might no longer be valid.

So much for the theory. The best way to validate all the assumptions made is to simulate the converter circuit and do some measurements. To do so I often use LTSpice. Here’s the initial schematic.

stepup_sch

 and a plot that shows voltage at switching node (green) and output voltage (blue) ramping up.

stepup_v

Here’s a closeup of switching node voltage. Some serious ringing can be observed. This is bad. Really really bad.

stepup_vsw

Ringing is initiated by reverse recovery of the diode and sustained by resonant circuit, formed by the inductor and parasitic capacitance that is present in MOSFET transistor. These oscillations can cause quite a mess! They will get radiated and cause interference to all devices nearby. It’s a common practice to implement so called snubber circuit (parts C11, R36 on the main schematic). The ringing is almost entirely suppressed after being treated with a snubber.

stepup_vsw2

Incorporating snubber circuit will always come at the expense of efficiency, but please keep using it :) Another good practice is to keep the switching node as short as possible, and use a lot of good input filtering (low ESR caps). I’ve even added a ferrite bead on the input voltage rail, to prevent any high frequency garbage from traveling along the power cord.

Some remarks about measuring output voltage are needed. It’s a good practice to measure voltage just in between switching cycles, and not during current pulses. This will help to get around all the switching noise that might have some serious impact on accuracy. This can be easily achieved by triggering ADC conversion with Timer Output Channel Compare feature (one channel generates MOSFET pulses, the other, slightly delayed, generates ADC trigger pulses). ADC conversion results will therefore be produced at rate equal to conversion cycle frequency which might result in too much computational load used just for reading ADC data register. The best way around this is to employ DMA for readout fetching and calculate the mean value of readouts when DMA transfer complete/half-transfer complete interrupt fires. I’ve set the interrupt routine to be called every 16 readouts (transfer size: 32, half-transfer interrupt enabled). Here’s the interrupt routine:

/* adc samples buffer */
static uint16_t samples[32];

/* dma channel 1 isr */
static void StepUp_Dmac1Isr(void)
{
 /* get status */
 uint16_t isr = DMA1->ISR;
 /* buffer pointer */
 uint16_t *ptr = samples, cnt;
 /* accumulator */
 uint32_t a = 0;

 /* re-enable dma if needed */
 DMAC1->CCR |= DMA_CCR_EN;
 /* clear interrupt flags */
 DMA1->IFCR = DMA_IFCR_CGIF1;

 /* got transfer complete? */
 if (isr & DMA_ISR_TCIF1) {
     /* select second half of measurement buffer */
     ptr = samples + elems(samples) / 2;
 }

 cnt = elems(samples) / 2;
 /* sum all measurements */
 while (cnt--) {
     a += *(ptr++);
 }

 /* get current error vector */
 int32_t diff = (a - 2900) * 8;
 /* limit diff */
 diff = min(max(diff, -512), 512);

 /* update regulator output */
 reg += diff;
 /* limit range */
 reg = min(max(reg, (uint32_t)64 << 8), (uint32_t)150 << 8);

 /* apply regulation */
 TIM4->ARR = reg >> 8;
 /* set new sampling point */
 TIM4->CCR4 = (reg >> 8) - 16;

}

As it can be seen from the code above the regulation algorithm is very simple, in fact it is no more – no less than a simple Proportional Regulator which compares accumulated ADC readouts with the magic value of 2900. Why 2900? Because it makes Nixies look best! (at least in terms of light intensity) :). Feel free to adjust this value to match your expectations.

I’ve intentionally limited the possible values of  ‘reg’ variable so, if an error occurs (like bad solder joint in ADC’s voltage divider) it will prevent the MOSFET to be constantly turned on, shorting the input power rail to ground.

Keep in mind that ARR and CCRx registers must be preloaded (i.e. updated on every Update Event by Timer’s logic, not on register write access, APRE bit set in CR1 register, OCxP bit set in CCMRx register) or you’ll end up with very weird timer behavior.

Help, my clock is always late!

Oh well, that’s a common problem with crystals. They often give out very stable frequency but it does not necessarily be spot on 32768Hz. ST Microelectronics thought of that problem and prepared a nice detailed paper about their RTC that deals with calibration which could be done entirely in software.

I’ve placed a test point on PCB where you can measure your reference clock frequency with some accurate frequency counter.

Printed Circuit Board

Here’s the overall look of the PCB. The dimensions are: 124 x 40mm. All the components fitted on the back side.

pcbback

Not much going on on the front side since I don’t have the Nixie model, and I was too lazy to make one. Here you can see the micro-switches that are placed just beneath the neon lamps.

pcbfront

I used 0805 and 0603 for passive parts so the soldering shouldn’t be very hard. The only difficulty is encountered while dealing with MCU, but its manageable. Just apply a lot of flux and use a hot air gun.

Please make sure that, after soldering you’ve removed all the residual flux as it might disturb the operation of all high impedance networks present in this circuit (like step up feedback network).

Neon push-buttons

To make it happen we need to prepare neon bulbs to have springy action. We do that by bening their legs properly, like this:

IMG_0307

Soldering Nixies

That’s right, IN-12 lamps can be soldered easily (no acidic fluxes are required), so there is no need for sockets. Footprint present on PCB uses large pads, so it’s straightforward process of  ‘positioning and locking’. I needed to solder lamps as they would be SMD (as opposed to THT) components in order to match their height to the height of the whole micro switch – nixie lamp construction.

Final Remarks

As mentioned above I decided to give this project as my contribution to community, so here’s the link to my GitHub repository, where you can find all the schematics, PCB layout, source code for the uC, LTSpice Schematic, etc.. Feel free to use it to whatever purpose it might serve.

MightyHID – C# Lib for USB HID communication

usb_icon_bigFew days ago I’ve completed my work on C# library that I am planning to use for implementing communication with USB HID Devices. It’s called MightyHID. Why HID? Well, first of all HID class is one that does not require any drivers and works on any major operating system that I know. Furthermore, it is very easy to implement HID class support on any MCU that supports USB.

I’ve also prepared a small piece of code called ‘MightyHIDTest’ that demonstrates MightyHID capabilities. Goal was to keep the code at minimum level of complexity and thanks to that, you should have no problems re-using it in your projects.

Source code is hosted here: https://github.com/MightyDevices/MightyHID, and here is the dll itself: https://github.com/MightyDevices/MightyHID/releases

H4ck33D – hacking a 433MHz Remote Control

433_icon_bigMany of us live in so called ‘gated communities’ which are often surrounded by fences and/or walls built to provide to all residents some sense of security and isolation or (as it will be described later) an illusion of it. The access to such places is only possible through a limited number of dedicated gates which are often electronically controlled. Since I don’t possess a car, I wasn’t given a remote control which would allow me to open any of gates that lead to my house. Although it may not seem to be very problematic for a guy who still didn’t manage to get his own ride, but whenever any friend of mine (who often do have cars) wants to drop by, then he has to park his car outside which may sometimes be very inconvenient. As you can imagine, probably the best solution for this kind of situation would be to just ask some people who administer the spot, to give me one of those ‘cheap looking’ remote controls, but hey – where’s the fun in that? And so I’ve decided to hack my way into this system :)

Step 1. Gather all the tools you need

Almost all of those systems that are currently available on market use RF communication. I’ve never seen a gate opener that uses infra-red or any other communication medium. Many of those make use of ISM bands which in Europe are: 433MHz, 868MHz, 2.4GHz, 433MHz being the most popular one for such purposes. To be able to monitor ongoing communication one needs to have a receiver capable of tuning to 433MHz band and recording received signals on the go. There is no better tool for the job than SDR receiver. I’m using the most popular one (RTL-SDR), bought almost for peanuts, depicted below (plastic enclosure was removed for the ‘wow!’s).

  rtlsdr2

And now for the software, the one and only SDR#. User interface pretty much explains itself. Here you can see that my RTL SDR dongle pics up two FM broadcast stations around 105MHz. What’s most important: this marvelous piece of software allows you to tune into your band of interest and record baseband (or ‘received’ if you prefer)  signal in *.wav file format.

sdrsharp

So much for the reception. Now we need something to analyse incoming signals. I’ve used Audacity, as it works nicely with *.wav files produced by SDR#.

After capturing and analyzing incoming signals we will need some sort of radio transmitter that will behave just like the original remote control, and, for that matter, I’ve build my own from scratch.

Step 2. Capture

One needs to know what he is looking for, obviously. As I mentioned before jumping around 433MHz (433.82MHz to be exact, as it’s the most common SAW resonator frequency, often used in small remote controls) seems like a good idea. In my neighborhood there is quite a lot going on in that band, household weather stations, car alarms and  some sensor networks activity can be observed. Simple yet important question arises: How can I distinguish wanted signal from all that radio chatter? Well, answer won’t be straightforward, although there are some unique features that may indicate that we are right on spot:

  • Strong correlation to gate openings – doesn’t call for explanation :)
  • Signal strength – the closer to the gate you’ll get the stronger received signal should be. Just keep in mind that signal is not transmitted from the gate itself, but from remote control that is in use by people approaching the gate in their cars. Many remote controls produce a decent amount of RF power, so it’s possible to open the gate while still being distant. This is good, as you’ll probably won’t need to sit with your laptop and all RF tools in front of the object of your hacking, looking all suspicious and attracting unwanted attention :)

Here’s a screenshot of SDR# while receiving gate opening signal. (Care to know what WOW! signal is?)

wow

Step 3. Analyze

Quite a few things can be deduced from the picture above. First of all we can see that transmitter sends frames in periodic manner, and that all the frames being sent are of equal length. Small frequency drift can be observed. This leads to conclusion that transmitter does not use PLL nor any other form of hand effect (transmitter de-tuning caused by hand’s proximity) compensation. This indicates that we are dealing with some sort of cheap’n’simple circuitry. Needles to say – this is exactly what we were hoping for!

Using SDR# I’ve recorded baseband in the period during which transmission occured. Then, I’ve simply opened the recorded file in Audacity, and this is what I’ve got (after removing all moments of radio silence, etc.):

audacity

Well, look at that – a thing of beauty! Signal was so strong that I don’t even need to do any sort of processing, as one can see all the bits, 1’s and 0’s with his naked eye. We can clearly see that we are about to deal with OOK modulation scheme – needless to say, it’s the simplest modulation of all.

Every transmitted frame was always the same – this yields to conclusion that we are dealing with one-way communication here. This is to be expected from such a sleazy system, and it’s very good news. We won’t have to understand the encoding used, as we can simply mimic transmitter’s behavior, and the gate opening system won’t even notice that someone’s messing with it.

First part of this waveform is, so called ‘preamble’, and it consists of alternating pattern of ones and zeros. It is often used in radio communication as it helps the receiver to synchronize with transmitters clock. In the picture above 24 bits (twelve zeros and twelve ones) can be observed. Then there is a moment of silence, purpose of which still remains a mystery to me. Silence is followed by a specific bit pattern. What’s so specific about it? Let’s dive in into details:

symbols

We are dealing with two kinds of symbols here, just like in Morse Code: the short one (dit), and the long one (dash). Careful observer will notice that transmitting short symbol requires just as much time as the long one (time intervals between thick lines are always equal to each other):

symbols2

Every symbol’s interval is divided into three equal parts, and short symbol is transmitted in such way that carrier is on during first part, and the long symbol takes up to two parts of carrier activity. This is done to prevent constant carrier presence (or lack of) when one would like to transmit a long sequence of zeros or ones. Such approach gives the receiver possibility to re-synchronize after every symbol received at the expense of bit rate (symbol is build up of three ‘bits’ instead of one).

Let’s assume that short symbol represent binary zero, and the long one represent binary one. This assumption may be wrong, but it won’t matter in the end, as I am not planning to reverse-engineer every bit of every frame here. No need for that.

Important signal parameters that one should write down:

  • bit rate – duration of a single ‘bit’ – 380us
  • preamble length – 24 bits (1010101….)
  • radio ‘silence’ length – 9 bits (funny number, I know, but there is more funny numbers to come..)
  • bit sequence – sequence of dits and dashes…
  • interval between emitted frames – 105 ms

Having all the information needed to reproduce received signal, we can finally hit the radio waves!

Step 4. Build a transmitter

Since we are dealing with OOK modulation, I’ve managed to design and finally construct a simple 433.82MHz transmitter with modulation input. See the schematic below.

433txsch

Presented circuit can be divided into two parts: a Colpitts oscillator with MOD signal (that turns on/off oscillation) built around Q1 and stabilized with SAW resonator, and a simple power amplifier based on Q2. I’ve powered whole thing from 5V DC, and observed SDR# waterfall diagram when MOD pin was tied to VCC and then to GND. Here’s the whole thing soldered on small piece of PCB:

433tx

Modulation will be done by STM32L152 on DISCOVERY board. Here’s a picture showing a transmitter connected to DISCOVERY:

433tx2

Step 5. Hack your way into gated community

I’ve written simple code that will periodically send frames that I’ve previously collected. I am currently using three different payloads for three gates, all o which seem to work. What code does can be summarized as:

  • generating bit stream on pin PA12 – this is done in Timer6 interrupt to keep the timing tight!
  • encoding frames – changing symbols into ‘dits’ and ‘dashes’, preparing preamble
  • preparing one frame every 105 ms.

Resulting binary occupies around 3kB. Needless to say – it works outstandingly well.

Conclusion

It took me about 3-4 hours or so to hack into gate control system. I’ve used tools/parts that cost well under $20, many of which (software) were free. This in fact shows that gated communities do not provide decent security. Systems that are used nowadays are outdated, and therefore very insecure. What’s worth noticing is that often garage door openers are using the same technology, and what’s even worse – so do car alarm systems. I won’t even try to anticipate what those conclusions may lead to.

Source Code

  • h4ck33d – the complete source code for this project.

 

Christmas came early this year!

That’s right! Thanks to wonderful people from STMicroelectronics and with some help and support from Rutronik  I just received tons of electronic goodies. I lack of words to express my gratitude to all people from ST and Rutronik that I had pleasure meeting along my career. Hopefully I’ll find a way to pay those guys back by doing some awesome projects using their components :)

photo4

Weekend Project: Simple 20 meter Direct Conversion Receiver

dcr_icon_bigHello everyone! Yesterday I’ve finished my work on simple radio receiver that I was intended to develop from scratch all by myself, just to check if I am capable of doing some shortwave electronics. I’ve picked the Direct Conversion method as it occurred to me to be the most straightforward, and after some research on HAMs present on YouTube, I knew that very decent performance is to be expected when the job is done properly. So, here’s the whole story behind this simple rig.

Principle of operation

Direct Conversion Receiver (DCR) operating principle is very very simple if you know how a component called mixer operates. For those that do not know what mixer does: basically mixer is a component (an integrated circuit most likely, but other solutions also exist) that takes two input signals : RF (Radio Frequency) and LO (Local Oscillator) and produces output that contains both: the sum and the difference of frequencies present in RF and LO. So, as long as LO is in form of pure sinusoidal wave we can expect that signal at the output port will contain two copies of RF signal shifted in frequency domain by LO’s frequency. As an example, let us consider a case when RF is a sine wave with frequency of 1MHz and LO is also a sine but with frequency equal to 800kHz. We can expect that at the output of mixer two signals will be present: RF + LO = 1.8MHz and RF-LO = 0.2MHz. Here’s a picture to illustrate this:

text6519-0-4-2-21

Red arrows indicate what’s present at the output port. Ok, so how does the Direct Conversion make use of a mixer? Well, basically it uses LO that is equal to the frequency that you want to receive, and when you have LO equal to RF this is what happens:

text6519-0-4-2-22

One of RF signal’s copies is present around 0Hz which makes it possible to directly put it into our headphones and enjoy whatever is currently going on air. Well, maybe not directly, cause some amplification will still be needed.

Schematic

I tried to keep things to be as simple (cheap and obtainable) as possible and this is the final result:

receiver

Input Filter

Remember that part when I mentioned that LO needs to be a pure sinusoidal wave, so it contains only one frequency component? In so called real life you can forget about that case, cause you’ll never be able to generate LO that is completely free of any distortion that occur as harmonic products in the frequency spectrum. And what happens when you inject such impure LO to mixer? You start to receive many frequencies at once! You’ll be lucky if there are no actual radio stations transmitting on any of your LO’s harmonics, but even if you are really-really lucky you’ll still receive noise present at those frequencies and that can totally ruin your reception. What can be done about it? Input filtering, that’s what!

Basically the job of input filter consists of:

  • filtering (duh!)
  • impedance matching – to achieve the best power transfer possible, since the signals that come from antenna are very weak you don’t want to lose any dB’s there!

As you can see on the schematic above it is made of two resonant circuits: first one being C13, C8, L2 and the second one L3 C12. First one is also an impedance transformer that rises the impedance from antenna’s 50 ohm to about 7k. This is done to achieve better frequency response (narrower filter) by the second resonant circuit.

More gain, please!

During tests it occurred to me that gain provided by the mixer might be not sufficient for convenient reception of amateur band as amateur’s rigs often emit output power that is lower by many orders of magnitude as opposed to broadcast stations. Therefore some simple stage of RF amplification had to be developed.

This RF amp is as simple as it could get: Q2, R13 R12. It introduces very little noise while boosting the signal by 20dB. Neat! I’ve used BC817-40 version for Q2, just to get the maximal gain possible with this type of transistor.

Mixing – theory meets practice

Yet another basic application of SA612 (a.k.a NE612 a.k.a NE602), no fooling around. This chip is an absolute classic, and any of young RF players should definitely get to know it better, as it offers great value for the money! Of course it has it disadvantages like low IP3, but those don’t really affect this receiver’s overall performance.

Local Oscillator a.k.a Tuning Knob

The beauty of SA612 reveals itself again when you try to build up Local oscillator. This IC has a spare transistor that can be used to build up a Colpitt’s Oscillator. All you need to do is to connect all the components that will determine it’s operating frequency, and since we are constructing Direct Conversion Receiver (so LO = RF, remember?) we need to be able to tune LO from 14MHz to 14.3MHz. This tuning range is determined by components: D1, C20, C24, L5, C17, C23. Diode D1 is so called Varicap and it changes it’s capacitance as the reverse voltage changes. This ‘reverse voltage’ can be adjusted by a potentiometer connected to J3.

When building this LO a frequency counter might become very handy. I’ve used my oscilloscope that shows trigger frequency to adjust all element values so LO does effectively tune exactly from 14.0MHz  to 14.35MHz when my tuning potentiometer is in outermost positions. If you use a frequency counter please connect it to LO’s buffered output present at J4. This simple JFET buffer is there just to provide isolation between LO and your meter so that connecting it wont affect LO’s frequency. If you are not planning to fine-tune LO’s components then you can leave C21, R10, R11, C22, C18, Q1 unpopulated.

Audio amplifier/filter

DCR selectivity (ability to receive only single station at time and filter out any others) is determined by filter included in audio amplifier stage. Here I’ve used cheap and well known opamp by Microchip: MCP6002. Overall gain of this stage is set to 40dB (10000 times) but, because of the presence of capacitors C1 and C3 it rolls off gently at around 2.5kHz. Voltage dividers constructed of R2, R7, and R4, R8, set the operating DC point to 2.5V so that audio signals have plenty of space to swing around.

The output of amplifier can be directly fed into headphones (32 Ohms) by DC blocking capacitor. No need of additional amplification/buffering, cause sound level is just fine.

Supply

No magic there. Five volts LDO and some caps. I’ve used TC1185, but if you are a big fan of 7805 then it should perform just as well. Just make sure that your LDO does not produce too much noise as it can (and will) be injected into many sensitive parts of this receiver.

The result

I’ve put this thing all together on one of my spare PCB’s for double conversion receiver, with some modifications of course. This is how it looks like:

dc

Voila! Not many components after all, isn’t there? Very attractive for RF beginners!

YouTube movie – or didn’t happen!

Yes..yes, I know 21th century calls for moving pictures. First one shows the DCR’s ability to correctly receive CW (Morse code) siganls that are often present in the lower part of 20m band.

And some SSB for dessert:

What’s worth noticing is that I used MiniWhip antenna to record all of this. If you don’t have one, you can just use a piece of wire connected to antenna port.

STM32 L1 Morse Code Beacon

morse_iconSince I’ve found STM32L uController series to be most amusing to play with I did some experiments that no one, not even the manufacturer himself would dare to call ‘normal’ use cases :). In this post I’m going to present you a way to turn your STM32L uC into fully-functional, transmitting actual RF signals, Morse code beacon. Beacon that could be picked up with nothing more than a standard FM Broadcast receiver (you know, the one that works in 87.5 – 108.0 MHz range).

How to get RF out of “non-RF” chip?

Basically what we call RF is no more no less than signal with alternating voltage. The rate at which this voltage alternates is called frequency. We need to find a way to generate a signal with frequency between 87.5 and 108MHz on one of uC pins. Surprisingly this can be done in a chip that claims to operate only at much lower frequencies. All we need to do is to make proper improper :) use of PLL (Phase Locked Loop).

Hardware

Well, not much going on there, all you need to have soldered is a crystal oscillator, in order to be able to use it as PLL’s source clock (HSE). To be completely honest, you don’t even need that for this chip to transmit, but when internal oscillator is used (HSI) a lot (and I mean: A LOT) of phase noise will be present at the output, and nobody likes phase noise of that magnitude. Believe me, things can get messy when your so called “transmitter” occupies 10% of total FM Broadcast Band, so please, please! use HSE, since it only adds three parts to your bill of materials (2 caps, 1 crystal) . Here’s the schematic:

Morse

Configuration of PLL

The frequency that I chose for operation is equal to 96MHz, which is 16MHz (my crystal oscillator, HSE) times six. STM’s PLL does not support divider that is less than two, so in order to generate 96MHz we have to multiply PLL’s source clock frequency to get 192MHz. This implies multiplying by a factor of 12 (16MHz * 12 = 192MHz). Then we set divider’s value to 2. All is done with following code

	/* start hsi clock */
	RCC_HSECmd(ENABLE);
	/* wait till it stabilizes */
	while (!RCC_GetHSEStatus());

	/* configure pll to give out 96 MHz */
	RCC_PLLConfig(RCC_PLLSOURCE_HSE, RCC_PLLMUL_12, RCC_PLLDIV_2);
	/* start pll */
	RCC_PLLCmd(ENABLE);
	/* stabilize pll */
	while (!RCC_GetPLLStatus());

Plain and simple. Only thing worth noticing is that we do not switch our MCU to operate on that what comes out of PLL. That would surely do us no good, since that frequency definitely exceeds IC’s capabilities.

Routing RF out of chip’s insides

There is a nice feature that comes with STM32L series, called MCO (Microcontroller Clock Output), that can be used to provide MCU’s clock to other system components. The real nice thing about it is that it can source not only MCU’s system clock, but any other clock (like HSI, HSE, and .. PLL!) as well. Brilliant! The only drawback is that only Pin PA8 can be configured to act as MCO. Here’s the code:

/* initialize gpio structure */
GPIO_StructInit(&gpio);
/* use pin 13 */
gpio.pins = GPIO_P8;
/* mode: alternate setting */
gpio.mode = GPIO_ALT;
/* system */
gpio.af = GPIO_AF_SYSTEM;
/* output speed: 40MHz */
gpio.speed = GPIO_OS_40M;
/* apply configuration */
GPIO_Init(GPIOA, &gpio);

/* configure mco pin */
RCC_MCOConfig(RCC_MCOSOURCE_PLLCLK, RCC_MCODIV_1);

As you can see MCO has it’s own divider, but we are not using it as it would require PLL to generate even higher frequencies and I don’t find it possible. Please keep in mind that this output pin needs to be configured for highest output speed possible, which, in case of STM32L is 40MHz.

Last thing to do is to find a way to control the RF emission by enabling/disabling MCO. The best way to do it is to use bit-band mapped to PA8 MODER bit number 1 (not 0). By altering it’s value user can switch between Anlternate Function (which is MCO) and General Output which will just set pin low. Here’s the mapping, done as a global variable:

/* bit that controls rf output */
static bitband_t rf = BITBAND_PERIPH(&GPIOA->MODER, 17);

Now setting rf to 1 (0) will start (stop) generation of RF.

Morse code generation

I’ve written a simple piece of code that generates all the dots and dashes form C string.  It uses a Look-Up Table for character generation. Every character in LUT was encoded on 8 bits in such manner that:

  • bits 0-2 are used to represent number of dots and dashes that represent character. This information is required because Morse letters have variable length.
  • bits 3-7 hold the actual letters representation, 1 represents a ‘dot’, 0 goes for a ‘dash’. Sequence should be processed from bit 7 to bit 3, and not the opposite. I stored it that way because it was easier for me to build up all those bits when looking at Morse Code Chart which is written from left to right, obviously.

Here’s the code of Morse code generation:

/* encoded morse letters from A to Z */
const uint8_t morse_letters[] = {
		0b10000010, 0b01110100, 0b01010100, 0b01100011,
		0b10000001, 0b11010100, 0b00100011, 0b11110100,
		0b11000010, 0b10000100, 0b01000011, 0b10110100,
		0b00000010, 0b01000010, 0b00000011, 0b10010100,
		0b00100100, 0b10100011, 0b11100011, 0b00000001,
		0b00100011, 0b11100100, 0b10000011, 0b01100100,
		0b01000100, 0b00110100
};

/* sends morse letter */
void send_morse(char c)
{
	/* get code */
	uint8_t code = morse_letters[c - 'a'], i = code & 0x7;
	/* process every bit of morse code */
	while (i--) {
		/* enable rf */
		*(rf) = 1;
		/* dot */
		if (code & 0x80) {
			simple_delay(DOT_DURATION);
		/* dash */
		} else {
			simple_delay(DOT_DURATION * 3);
		}
		/* disable rf */
		*(rf) = 0;
		/* dot space */
		simple_delay(DOT_DURATION);
		/* next bit */
		code = code << 1;
	}
}

Since it’s only a demo I didn’t go all the way to have support for numerals, spaces, commas, periods and all that stuff. Of course if you are in need of those, feel free to modify it anyway you like.

Outcome

A video says more than a thousand words:

In this video I am using PCB from one of my projects, but you only need to stick to what was told in “Hardware” section of this article. I’ve added some LED blinks for every dot and dash for convenience.

The software that I am using to monitor RF band is called SDR#, and I definitely recommend you getting one if you are planning to go for RF projects. It performs outstandingly well with my Realtek chip based DVB-T dongle.

Files

STM32 L1 Tutorial #2: Boost your code (Bit-Banding)

stm32_icon_bigToday I’m going to show you how to speed things up in your code by using marvelous feature called “Bit-Banding”. Basically bit-banding is a new way of addressing (and accessing) things in some parts of your Cortex-M3 uC address space. Well, you would probably ask if there is any room for any useful improvement in such simple and straightforward thing as addressing. Actually, there is.

Remember those moments when you tried to access and change value of separate bits in registers? It always involved three operations: read-update-write. Read operation was just to copy full register value to temporary variable, update was either ‘logical AND’ or ‘logical OR’ to clear or set bit of your interest respectively, and finally a write to update register’s value. As one can see, lots of computing power is involved in such simple thing as bit’s value altering. Bit-banding removes all that overhead by giving you the possibility to access register bits as separate memory locations. Neat!

Accessing bits as they were words!

To be able to access register bits with bit-banding programmer must locate that bit’s memory location. According to STM32L Reference Manual mapping is done by this formula:

bit_word_addr = bit_band_base + (byte_offset * 32) + (bit_number * 4)

where:

  • bit_band_base – a constant that indicates which memory area you are trying to access. For SRAM bits use 0x2200 0000, for peripheral registers use 0x4200 0000.
  • byte_offset – this is a byte offset of register that you are trying to access. Offset is derived from actual address minus starting address of its memory section. Example 1: byte_offset of SRAM (SRAM starts at 0x2000 0000) variable located at 0x2000 0100 is 0x2000 0100 – 0x2000 0000 = 0x0000 0100. Example 2: byte_offset of GPIOA->ODR (address: 0x4002 0014) register is 0x0002 0014, since peripheral memory section starts at 0x4000 0000.
  • bit_number – just the number of bit you are trying to map. Plain and simple.

Accessing bits as they were words! With my lib!

Using bit-banding wouldn’t be that much fun if you had to use and compute above’s formula value all the time, but hey, that’s what libraries are for. Mine does it all for you, with simple macros.

Last time (Tutorial #1) we were experimenting with GPIO pin that was used to drive LED. Let’s see how it could be done with bit-banding.

/* system entry point */
int main(void)
{
	/* gpio init struct */
	gpio_init_t gpio;

	/* reset rcc */
	RCC_DeInit();

	/* enable clock to GPIOC */
	RCC_AHBPeriphClockCmd(AHB_GPIOC, ENABLE);

	/* initialize gpio structure */
	GPIO_StructInit(&gpio);
	/* use pin 13 */
	gpio.pins = GPIO_P13;
	/* mode: output */
	gpio.mode = GPIO_OUTPUT;
	/* output type: push-pull */
	gpio.otype = GPIO_OT_PP;
	/* apply configuration */
	GPIO_Init(GPIOC, &gpio);

	/* bit-band definition */
	bitband_t pin = BITBAND_PERIPH(&GPIOC->ODR, 13);

	/* main program loop */
	for (;;) {
		/* set led on */
		*(pin) = 1;
		/* clear led */
		*(pin) = 0;
	}

	/* never reached */
	return 0;
}

Here (line #25) we have defined variable of type bitband_t which now represents bit 13 in GPIOC ODR (Output Data Register). bitband_t is a pointer to mapped memory location, so writing/reading values is done in a ‘pointer-ish’ way, with use of ‘*’ operator.  Simple as that. Using bit-banding with SRAM bits is very similar:

	uint32_t sram_flags;
	/* bit-band definition */
	bitband_t sram_flags_bit_0 = BITBAND_SRAM(&sram_flags, 0);
	/* change value */
	for (;;) {
		*(sram_flags_bit_0) = 1;
		*(sram_flags_bit_0) = 0;
	}

Pros and Cons.

As it was mentioned before bit-banding speeds things up. By what factor? Well, it will probably depend on whole context, but one can easily find many different use-cases that are perfectly tailored for this technique, such as:

  • Clearing Interrupt status bits – saves you some cycles during interrupt routine execution
  • Fast GPIO toggling – pretty much explains itself, useful when implementing bit-banging (with ‘G’ :) ) interfaces
  • Preemption safe bit value changing – no read-update-write, just write, good for dealing with data that is processed by interrupt routines and main program loop simultaneously.

In above’s example frequency of LED toggling with bit-banding as opposed to GPIO_SetPin(), GPIO_ClearPin() increased by over 170% (was 96kHz, is 262kHz, using Os level of GCC optimization, 1MHz MSI clock (default one)). Definitely worth the effort!

There are some situations that make the use of bit-banding not practical. Those include:

  • Complex Initialization – things done only once per device’s power cycle, like GPIO inits. Using bit-banding there makes hard code hard to read and debug.
  • Updating multiple bit fields in registers – many of those exist, updating those bits one-by-one may lead to unwanted (and, in some cases, even unpredictable) device’s behavior.

Limitations

Two that I am aware of. Bit-banding is available only for SRAM and Peripheral section, so no funny business operations in FLASH. Bit-banding  accesses are only legit if done by Cortex-M3 core itself. What that means is, that you cannot use DMA transfers to bit-band memory locations.

Files

STM32 L1 Tutorial #1: Hello, World! (LED Blink)

stm32_icon_bigToday I’m about to show you how to make any use of my version of STM32L Standard Peripheral Library (post, .zip). First order of business for everyone that starts using MCU that he never used before is to get into controlling states of MCUs General Purpose Input/Output (GPIO) pins which translates to setting the voltage high or low on those pins. This can (and will) be used to lit up a LED directly connected to leads of our STM32L. I am assuming that reader has some basic knowledge about C Programming language, because I’m not planning to describe every line in every file, but to focus on what’s important. Here’s the code that does all that magic:

/* system entry point */
int main(void)
{
	/* gpio init struct */
	gpio_init_t gpio;

	/* reset rcc */
	RCC_DeInit();

	/* enable clock to GPIOC */
	RCC_AHBPeriphClockCmd(AHB_GPIOC, ENABLE);

	/* initialize gpio structure */
	GPIO_StructInit(&gpio);
	/* use pin 13 */
	gpio.pins = GPIO_P13;
	/* mode: output */
	gpio.mode = GPIO_OUTPUT;
	/* output type: push-pull */
	gpio.otype = GPIO_OT_PP;
	/* apply configuration */
	GPIO_Init(GPIOC, &gpio);

	/* main program loop */
	for (;;) {
		/* set led on */
		GPIO_SetPins(GPIOC, GPIO_P13);
		/* delay */
		simple_delay(100000);
		/* clear led */
		GPIO_ClearPins(GPIOC, GPIO_P13);
		/* delay */
		simple_delay(100000);
	}

	/* never reached */
	return 0;
}

Preparing the MCU

First step when you are dealing with STM32L will be resetting the RCC, which is done in line #8. RCC is that little MCU fragment that is responsible for enabling/disabling clock to all other modules, such as GPIO, as well as controlling MCU clock speed. After a reset we need to bring it to a known state and that’s why we call RCC_Deinit() routine.

Configuring GPIO

In order to be able to use GPIO port (MCU pins are grouped in ports, every port can have up to 16 pins) we need to enable it’s clock. It is a common pitfall to forget about enabling particular peripheral’s clock, so keep in mind that this should be the first step before using any of peripheral’s registers.

Since we’ve got our GPIO up and running, we need to configure the operation of pin that will drive our LED. This is accomplished with the use of gpio_init_t structure. First thing that should be done here is to reset it’s contents by calling GPIO_StructInit() which will set all fields to their default values. Why bother using this function? Well, since our struct is stored on stack (it is defined inside main() function, not as a global variable) it will contain rubbish values, because stack variables aren’t initialized just as global variables are. Several fields of that data structure have been used to define pin’s behavior:

  • gpio.pins – selects which pin we are about to configure. In this case it’s pin 13.
  • gpio.mode – chooses pin mode of operation, which can be input, output, alternate function (pin driven by some other peripheral) or analog (pin used by analog to digital converter), in this case, since we want to *drive* LED we need to go for GPIO_OUTPUT.
  • gpio.otype – output pins can operate in two modes: push-pull (MCU can set pin high and low) or open-drain (MCU can set pin low and high-impedance). We choose push-pull mode to be able to set pin high.

After setting all the fields we need to apply this configuration to given port. My LED is connected to pin PC13, I used GPIO_Init() with the first argument set to GPIOC.

Using GPIO pin

Now the eye-candy. I have written a simple loop (lines 25 – 34) that will turn-on and turn-off the LED just to demonstrate that this tutorial actually does something. As you can see the simplest way of altering pin output states is to use GPIO_SetPin() and GPIO_ClearPin() respectively. I have also inserted some wait-sates just so the LED doesn’t blink too fast.

Files

  • Source Code – all that you need to run this example, just compile, upload to your mcu and observe the magic!