STM32 programming – Bit or Byte ‘Banging’ on AD9850

Bit or Byte banging, what is that exactly?!

Sometimes device(s) has no standard serial or parallel protocols as are I2C, SPI and others. Instead, just series of bits or bytes and separate clock. Excellent example is DDS chip AD9850 – we may chose or serial or parallel interfacing. On serial interfacing we using ‘bit banging’ – we put one bit on GPIO port, then on another GPIO port one clock, then next bit on port… until all bites are transferred. Then we send frequency and phase update on third wire, brief pulse 1 then 0. If we want parallel (8 times faster) interfacing, we put whole byte on 8 pins, in our example GPIO A0 to A7, then on another wire we ‘fire’ clock pulse, and after transferring all data, also ‘firing’ update frequency and phase.  Before proceed to our program in Keil, we should to consult our datasheet about AD9850:

FM radio or Frequency Wobbler

In the codes below, there are two options: FM radio (chose for example 1/3 of the frequency, say 33 MHz, then ‘catch’ third harmonic on 99 MHz, and use comparator for getting almost square wave, so that odd harmonics are stronger), or “Frequency Wobbler”, excellent tool for RLC circuit characterization (testing band pass, low pass, notch and other filters as well as resonant circuits) from 0 to 62.5 MHz with AD9850 – or up to 90 MHz with AD9851, which is really hard to find.  You may change code so that sweep is only upward, and then program one pin before sweep to output short pulse for oscilloscope external trigger. Or leave as is and listen on SDR Software Defined Radio response from RLC circuits.

I made both options available in the same program, just pay attention to GPIOA registers – there are difference in the case of serial and in the case of parallel interfacing. Also, for serial or parallel, there are functions “dds_update_freqS” and “dds_update_freqP”, probably you correctly guessed, ‘P’ is for parallel, ‘S’ is for serial. Now, copy paste this code as usually onto your Keil editor:

STM programming ADC and true DAC

True DAC or PWM dac?!

Depends of which board we have. If chip is STM32f103c8, then there is no DAC on it, but we can mimic DAC by using PWM. If board has stm32f103vet6 on the other hand, it has DAC and we can  use both channels as stereo.  Please watch video first, then it will be clear why we need move SPI pins with AFIO_MAPR function to another place – both shares the same pins.

Sorry, but last file “sample.h” is too long for this page, so it is in separate window (just select all, copy and paste into your sample.h file:  sample

Logic analyzer – do we need it?

Logic analyzer and its use

When programming any MCU, no matter Arduino IDE, Keil, Atmel studio or other compilers and assemblers, many times we got intro problem not knowing what happening on our data transfer from and to MCU. For example, we want to use I2C protocol for communicating with some sensor, but it does not respond. Many things can be wrong, and without logic analyzer, we just don’t know whether our code is wrong, the sensor is broken, or maybe something else.

Cheap Chinese clone or professional one?

Good question, depend of many factors. Do you use it for your work, or do you program for fun? I am using for my personal projects, and this one that cost less than $50 US.:


It works fine, but there is limit in speed, especially with more than one channel. It is USB 2.0 product and has no analog part as it has original Saleae Logic analyzer. It is too much expensive for my pocket, especially because I am not professional. I just have dream that it will be mine one day, but until then… Anyway, here is video for anyone who are interested and does not know what I am talking about:

Recently I had problem programming STM32 and connecting OLED display. Despite spending hours googling what exact command should be implemented, and reading their documentation, I was not able to get picture on the OLED display. Then got idea – programmed Atmega 328p with Arduino example, then put logic analyzer to I2C bus, and got the codes for initialization of the display.

Another example is when I wanted to know toy grade quadcopters, how transmitter and receiver know where to ‘jump’ by using ‘frequency hopping’. Using SPI protocol and Logic analyzer, I was able to see exactly what is ‘the secret’. Aside many bytes that transmitter sending for moving flying device up/down, left and right, there is one byte that constantly changes even when remote sticks are still – that is information for next channel. So, TX sending information on current channel, then last bit is channel number for next transmission. Whole protocol is made so that if it goes briefly out of range, or missing one packet due to noise, receiver back to original ‘calling’ channel, and in the same time transmitter sending on this channel periodically next possible channel where will be next time. That is so cool to know.

STM32 example of DSP, ADC and DAC

DSP possible on small MCU?

Yes, DSP (Digital Signal Processing) is possible with some speed limitations. For example, if FIR filter (Finite Impulse Response) has too much taps, whole loop process will be slow, and sampling ratio depends strongly of number of those elements. Out there exist specialized MCUs with additional hardware for floating point calculation (FPU), but our STM 32 or whatever MCU you are using, can do DSP.

First, we need to find some math to calculate ‘taps’, you may use your GNU radio companion for that, or some free online calculators as is this one (really simple):

Just set parameter of wanted frequency filtering, and on the right side you have two choices: plain text or C/C++ code. Chose code and copy/paste into my codes in ‘coefficients.h’ file, replacing old ones (or just comment old one with ‘//’. Change “static double filter_taps[FILTER_TAP_NUM] = {…” into “static const float taps[] = {….”, that is because it is intended for PC and other high frequency CPUs instead our MCUs. Name in ‘[]’ square brackets is defined above by “#define FILTER_TAP_NUM”, so leave those brackets empty, else compiler may complain about re-definition.

The codes:


STM32 programming SPI for Si4432 transceiver

Si4432 transceiver

Using FTDI as power source

Before anything, if you are using STM32 with ST-Link, then MCU and Si4432 is powered by ST-Link. When done with programming, you can use USB FTDI adapter as power source for 3.3V, but first move jumper from 5V to 3.3V (!). Else you can damage both, MCU and SI4432. On block diagram, this wire connection is not shown for reason that some FTDI adapter has voltage selection on bottom side, then you need to solder jumper pads to 3.3V. Here is picture with recommended setting for FTDI for use on your computer and for powering MCU with Si4432:



To get it working properly, when typing into console, console should be able to send LF and/OR CR symbol (decimal 10 or 13), so rather use HTerm, it is free for Windows and Linux. Do not use both CR and LF (CR-LF), else one of those may be sent over the radio and at receiving site one may notice moving text two rows instead one. Here is screenshot:


Default setting in ‘printMsg.c’ is 115200 baud, but you can change to your value, just comment with ‘//’ this one and un-comment (remove ‘//’) one that is the best for you. If you chose less than 9600, then whole thing will be slower than transceiver. In HTerm, there is window with COM port, if it is already open, it will NOT refresh automatically new COM port, you need to click on ‘R’ button next to window with COM port names. Enable “Newline at” and chose LF, you may disable “Show newline characters”.

Codes for remote controller

The codes below is for remote terminal, for communication between two points at fixed frequency and fixer data rate in bauds. For remote controller, the code must be modified. I will do that too, but not sure how soon. If you want it sooner, please buy me a beer. 😀  Just because I have many things to do at once, and sometimes long time may pass between page update. This will kick me to do more.



STM32 write and read EEPROM over I2C bus

EEPROM write and read

EEPROM sounds intimidating for the beginners, probably because there are few rules to comply. First, all EEPROMs share the same address on I2C bus, at least first page, and that is 0x50. I will give example for Atmel 24C08 chip, which has 8 kbit (!) memory. This number is NOT killo-bytes, but 1024 x 8 bits. So, practically ‘only’ 1 KB of memory space. Second rule is that writing must be done in sequence(s) of 8 or 16 bytes, depending of memory type. 1k and 2k EEPROMs can write only 8 bytes at a time, but 4k/8k/16k can write 16 bytes at a time. Between each write cycles and write then read cycle should be about 2 mS delay. This delay is some intrinsic property of the memory, and we can’t do anything about that. Only follow the rule. Read is possible whole ‘page’ of 256 bytes at once. Also, there is no restriction between two readings. Only after writing even singly byte, must be some delay, experimentally found 1.68 ms, so better use 2 mS (2000 uS) for sure.

Splitting data into groups of 16 bytes

That is how it should works. I made relatively simple code for STM32f10x family of the MCUs. In this code, there is two examples, one writing just 16 bytes, another one writing more than that in few steps with delay of 2 mS between each ‘packets’ of 16 bytes. Second example uses second of four pages. First example is on first page. Each page has actually its own I2C address ranging from 0x50 to 0x57 for 16k EEPROMs. I have only one chip that has 8k, so it covers four pages; page 0 = 0x50, page 1 = 0x51, page 2 = 0x52, and page 3 = 0x53. I found this chip below board with STM32f103VET6, that was surprise for me. Did not found any data about that board, nor it is mentioned in STM32 literature. And since this STM32 board has no ‘name’ as is for example Arduino uno, no data about this one except few words on eBay (plus price tag 😀 ).

In the example code I did not make algorithm for writing whole chip, because in practice this type of memory is just for few variables, maybe some calibration data or whatever user need to change after programming MCU, or during. For example, some servo has offset where middle position is not exactly in the middle. So, we can make code that scan buttons which moves servo, and when servo is where we want to be, another button press save calibration data into EEPROM. Since I did not use this chip in the past, I can’t give any example for now, but for sure it will be here in the future.

Code(s) not complete. Why?!

Please look carefully the examples. First example is not implemented correctly. I have doubt – do I need finish everything to show you, or you can learn something and recognize how to solve ‘the puzzle’? Second example, just un-comment (remove ‘//’) two separate functions twiSend(), twiReceive() and one printMsg() . That is last printMsg() which read all 255 bytes from second page at 0x51.  Also, you may notice that there are three strange variables included: ‘num’, ‘mantissa’ and ‘fraction’. Variable ‘num’ uses function strlen(test2) to get number of characters needed for two ‘for(;;)’ loops. In for example we have 92 characters, then 92/16 =5.75. Mantissa is number 5 (currently no needed in those examples), 0.75 is fraction, but (!) expressed in remaining bytes, that is 0.75*16=12.

Very interesting first loop:

This one uses number of characters (for example 92), subtract fraction (say 12), then it goes NOT from 0 to 92, but from 0 to 80 in steps of 16. Then some conversion of characters into uint8_t form. Not ideal, but… Then function twiSend(0x51,p,16) sends first 16 bytes, then another 16 until reaches 80. Then it exits for(;;) loop, and send the remaining 12 bytes twiSend(0x51,(num-fraction),fraction). At this time, ‘num-fraction’ is 92-12=80, which means that it begins to write at position 80 in EEPROM memory, for next ‘fraction’, which is 12 bytes.  After you copy/paste those codes, please align everything, because operation copy/paste onto this page can ruing alignment.

Here are the codes:

Copy/paste all codes and save in the same directory for Keil. I am not sure but I think the same codes can work in other editors/compilers/assemblers, but I am not familiar with those.

STM32 I2C Scanner

I2C scanner for STM32f10x series

I2C scanner is fairly simple, yet fast and effective way to find whatever device you put onto I2C bus. Some devices (boards) comes with clear designation on the PCB, some with misleading designation – address is shifted to the left, so for example OLED display typical address is 0x3C/0x3D (depends of address selector jumper), but shifted to the left by 1 bit is 0x78 or 0x7A respectively. They made it as if zero bit is inserted at LSB place so that you ‘just’ send it as-is. But that is bad practice. Rather make your own shifting routine and insert 1 or 0, whether you want to read or write at this address.


scannerThe code is even simpler:

Whole thing scan all 127 addresses in 45 mS.

Here is how looks whole packet with six addresses found. After each address found, there is 5.5 mS delay until timeout.:


Almost standard wire.c library

Since I am beginner, I just begin to make few more or less standard libraries for STM32f10x series. Right now there are three functions in wire.c; twiScan(), twiSend(), and twiReceive(). So far I did not found need for anything else, but that may change, so stay tuned. Since I have none of other MCU that has different set of registers with also different syntax for those. Here is complete thing with example of main.c code that does nothing except scan.:

Implemented in wire.c with wireSend() and wireReceive() functions:

That is all. Happy scanning! 😀