Strapping stm32 description and programming instructions. Connecting a COG LCD display to the ST7565R controller

It would seem a simple topic, but in the comments I was inundated with questions on how to connect a microcontroller. How to connect an LED, a button, power to it. What to do with AGND or AREF. Why is it needed? AVCC and stuff like that. So, since there are questions, it means the topic is not clear and it is necessary to give as comprehensive an answer as possible. I describe everything for AVR controllers, but for some PICs everything is very, very similar. Because the principles here are the same.

Nutrition
To operate, the microcontroller needs energy - electricity. To do this, of course, you need to start a feed on him. MK supply voltage Atmel AVR varies from 1.8 before 5 volts, depending on the series and model. All AVR can operate from 5 volts (if there are purely low-voltage series, please clarify in the comments, because I have not seen such ones). So we will assume that our controller supply voltage is always 5 volts or so. The plus of the supply voltage is usually designated as Vcc. The zero terminal (as well as the Earth, the Housing, and whatever they call it) is designated GND. If we take a computer power supply as an example. Then the black wire is GND (by the way, the ground wire is traditionally painted black), and the red one is +5, which will be ours Vcc. If you are going to power the microcontroller from batteries, then we will take the minus of the batteries as GND, and plus for Vcc(the main thing is that the supply voltage from the batteries is within the specified limits for a given MK, the problem is in the datasheet. The parameter is usually written on the first page in general description features:

Operating Voltages
–1.8 — 5.5V (ATtiny2313V)
–2.7 — 5.5V (ATtiny2313)
Speed ​​Grades
–ATtiny2313V: 0 - 4 MHz @ 1.8 - 5.5V, 0 - 10 MHz @ 2.7 - 5.5V
–ATtiny2313: 0 – 10 MHz @ 2.7 – 5.5V, 0 – 20 MHz @ 4.5 – 5.5V

Please note that there are special low-voltage series (for example 2313V low-voltage) in which the lower limit of the supply voltage is much lower. It is also worth paying attention to the next point about frequencies. This shows the dependence of the maximum frequency on the supply voltage. It can be seen that at low voltage the limiting frequencies are lower. And low-voltage series are two times slower than their high-voltage counterparts. However, all processors are submissive to overclocking ;)))))

For operation with series controllers AVR Just food is enough. To all entrances Vcc you need to apply our 5 (or whatever you have) volts, and all inputs GND must be planted on the ground. A microcontroller can have many inputs Vcc and many entrances GND(especially if it's in a square TQFP body. Which has pitalovo sticking out from all sides). Many pins are made not for ease of installation, but for the purpose of uniformly powering the crystal from all sides, so that the internal power circuits are not overloaded. Otherwise, imagine that you connected the power supply only on one side, and on the other side of the chip you hung an LED on each port line and lit them at once. The internal thin-film power bus, freaked out by such a current load, evaporated and the processor took SUDDENLY and, for seemingly no apparent reason, threw off its hooves. So ALL Vcc and GND OUTPUT MUST BE CONNECTED. Connect them accordingly and power them up.

Certain questions raise AGND And AVCC- This is the analog ground and power supply for the Analog-to-Digital Converter. The ADC is a very accurate voltage meter, so it is advisable to power it through additional filters so that interference, which is not uncommon in a conventional power supply circuit, does not affect the quality of the measurement. For this purpose, in precise circuits, the ground is divided into digital and analog (they must be connected only at one point), and on AVCC voltage is supplied through the filter choke. If you do not plan to use an ADC or do not intend to make accurate measurements, then it is quite acceptable to AVCC apply the same 5 volts as on Vcc, A AGND plant on the same ground as everyone else. But you must connect them!!! EMNIP from AVCC also powers port A.

Warning!!!

The Mega8 chip seems to have an error at the chip topology level - Vcc and AVcc are interconnected inside the chip. Between them the resistance is about (!!!) 5 Ohms. For comparison, in ATmega16 and ATmega168 between Vcc and AVcc the resistance is tens of MEGA ohms! There are still no indications in this regard in the datasheet, but in one of the topics from 2004 on AVRFreaks it is said that people were butting heads with the digital noise of the ADC, then they wrote to Atmel support saying WTF??? And those, they say, there is a bug in the chip and Vcc and AVcc are connected inside the crystal. In light of this information, I think that setting the throttle to AVcc for Mega8 is practically useless. But AVcc must be powered in any case - who knows how powerful this internal connection is?

The simplest connection diagram for the AVR Microcontroller is shown below:

As you can see, a choke has been added to the power circuit AVCC, as well as capacitors. It is good practice to place a hundred nanofarad ceramic capacitor between Vcc And GND each microcircuit (and if the microcircuit has many power inputs and grounds, then between each power supply and each ground) as close as possible to the power outputs - it will smooth out short pulse noise in the power bus caused by operation digital circuits. A 47mKF capacitor in the power circuit will smooth out deeper voltage surges. Capacitor between AVcc And GND will additionally calm down the nutrition ADC.

Entrance AREF this is the voltage reference input ADC. In general, you can apply a voltage relative to which it will be calculated ADC, but is usually used either internal source reference voltage at 2.56 volts, or voltage at AVCC, therefore on AREF It is recommended to hang a capacitor, which will slightly improve the quality of the reference voltage ADC(and the adequacy of the output readings depends on the quality of the support ADC).

Reset circuit
Resistor on RESET. Generally in AVR has its own internal reset circuit, and the signal RESET from the inside it is already pulled up with a 100 kOhm resistor to Vcc. BUT! The tightening is so bad that the microcontroller catches a reset from every sneeze. For example, from touching a leg with a finger RST, or even just from touching a finger for a fee. Therefore it is highly recommended RST pull up to power supply with a 10k resistor. It's not worth less, because... then there is a possibility that the in-circuit programmer will not be able to overcome this tightening and it will not be possible to flash the MK inside the circuit. 10k is just right.

There is also this reset scheme:

What makes it remarkable is that when the circuit is turned on, the capacitor is discharged and the voltage is RST close to zero - the microcontroller does not start, because him a continuous reset. But over time, through a resistor, the capacitor will charge and the voltage will be RST reaches log1 - the MK will start. Well, the button allows you to force a reset if necessary.

The delay will be approximately T=R*C for this example - about a second. Why this delay? Yes, at least so that the MK does not start before all the devices on the board are powered up and reach a steady state. In old MKs ( AT89S51, for example) without such a chain providing the initial reset, the MK might not start at all.

Basically, in AVR The start delay, if necessary, can be done programmatically - lower it for half a second before starting active actions. So the Conder can be thrown away. And the button... whatever you want. Do you need an external one? RESET? Then leave it. I usually leave it.

Clock source
The clock generator is the heart of the microcontroller. For each pulse, some kind of operation occurs inside the controller - data is sent through registers and buses, port pins are switched, timers are clicked. The faster the clock frequency, the faster the MK performs its actions and consumes more energy (switching logic gates requires energy, the more often they switch, the more energy is needed).

The pulses are set by a clock generator built into the microcontroller. However, there can also be an external generator, everything is very flexibly configured! The speed at which the internal generator ticks depends on the settings of the microcontroller and the harness.


The generator can be:

  • Internal with internal master RC circuit.
    In this case, no strapping is required at all! And the XTAL1 and XTAL2 pins can not be connected at all, or they can be used as regular input/output ports (if the MK allows this). Usually you can choose one of 4 internal frequency values. This mode is set by default.
  • Internal with external master RC circuit.
    Here you will need to connect a capacitor and resistor outside the microcontroller. Allows you to change on the go clock frequency, simply by adjusting the resistor value.
  • Internal with external master quartz.
    A quartz resonator and a pair of capacitors are placed outside. If the quartz is low-frequency (up to 1 MHz), then capacitors are not installed.
  • External.
    From some other device a rectangular signal is sent to the input of the MK, which sets the clock. This mode is useful, for example, if we need several microcontrollers to work in strict synchronization from one generator.

Different schemes have different advantages:
When internal RC circuit We save space on the board, we don’t need additional parts, but we can’t reach the maximum frequency and the frequency depends a little on the temperature and may fluctuate.

External quartz has excellent accuracy, but it costs an extra 15 rubles and requires additional parts and, what’s most offensive, often eats up a couple of I/O legs. Also on external quartz you can achieve maximum performance from MK. The MC frequency is determined by the frequency to which the selected quartz is sharpened. External RC circuit allows the MK oscillator to tick faster than the internal one, costs less than quartz, but has the same problems with frequency stability as the internal RC circuit.

Methods for clocking the MK are described in the datasheet in the section System Clock and Clock Options and are entirely determined by the configuration Fuse Bits. In the meantime, I highly recommend DO NOT TOUCH FUSE until you know for sure what you are doing and why. Because By setting something wrong, you can very quickly turn the microcontroller into a piece of useless silicon, bringing it back to life will be very difficult (but possible!)

Connecting LEDs and buttons to the microcontroller
By itself, without interaction with the outside world, the microcontroller is not interesting - who cares what it is ticking inside? But if you can somehow display this or influence it...

So, the button and LED are connected as follows:


For the button, you need to connect the selected I/O leg through the button to ground. The output itself must be configured as entrance with pull-up(DDRxy=0 PORTxy=1). Then, when the button is not pressed, through a pull-up resistor, the input will high level voltage, and from bits PINhu will give 1 when reading. If the button is pressed, the input will be put to ground, and the voltage on it will drop to zero, which means PINxy 0 will be read. Based on zeros in the register bits PINх we know that the buttons are pressed.

The dotted line shows an additional pull-up resistor. Despite the fact that a pull-up can be connected to the port inside the AVR, it is rather weak - 100 kOhm. This means that it can easily be pinned to the ground by interference or interference, which will cause a false alarm. And these internal pull-up resistors really like to burn from interference. I already have a dozen microcontrollers with killed PullUp resistors. Everything works, but there is no tightening - it burned out. You hang a resistor outside and it works as if nothing had happened. Therefore, for critical circuits, I strongly recommend adding an external pull-up of 10 kOhm - even if the internal one is covered, the external one will serve. During the learning process, you can forget about this.

Light-emitting diode connects to the port in two ways. According to the scheme Port-land or Port Power. In the first case, to ignite the diode, you need to output a high level to the log1 port (approximately equal to Vcc). In the second case, to light the diode, you need to output log0 to the port - a low level (near zero). For AVR There seems to be no difference, but many older series of microcontrollers pulled down much better than up, so the Port-Power circuit is more common. I use both schemes based on the convenience of PCB layout. Well, at the software level there is not much difference.
The port pin to work with the LED must be configured to exit(DDRxy=1) and then, depending on the value in PORTxy, the pin will have either a high or low voltage level.

Light-emitting diode must be connected via a resistor. The fact is that the direct resistance of the LED is very small. And if you don’t limit the current through it, then it can simply burn out. Or, what is more likely, burn the pin of the microcontroller, which, by the way, can draw something like 20-30mA. And for a normal LED to glow (we are not considering all kinds now, these monsters can eat up amps) you need about 3...15 mA.

So, offhand, we consider:

  • The voltage at the output of the MK leg is about 5 volts, the voltage drop across the LED is usually about 2.5 volts (it cannot be higher, otherwise the diode will consume more current than necessary and choke, emitting beautiful smoke)
  • Thus, the voltage that the limiting resistor must take on will be 5-2.5 = 2.5V.
  • We need a current of 5mA - there’s no point in feeding the LED, we need an indication, not lighting :)
  • R=U/I= 2.5/5E-3 = 500 Ohm. The closest one in the series is 510 Ohms. Let's take it. In principle, you can set from 220 Ohm to 680 Ohm whatever comes to hand - it will burn normally.

If you need to connect many LEDs, then each one has its own resistor. Of course, you can be greedy and put one resistor for everyone. But here it will be a bummer - there is only one resistor, but there are many diodes! Accordingly, the more diodes we fire, the less current each will receive - the current from one resistor will be divided between four. But you can’t put a smaller resistor - because when one diode is ignited, it will receive a portion of current for four and glue the fins together (or burn the port).

A few circuit design quirks or a few words about saving pins

What cannot be soldered has to be programmed. (C) folk wisdom.

It often happens that the controller’s memory seems to be more than enough for the task, and the performance is over the top, but there are not enough legs. So you have to install a redundant and more expensive microcontroller just because it simply has more pins. I'll show you a couple of examples of how to make it more complicated program code save on hardware.

The cornerstone of such savings is usually the principle of dynamic separation of pin assignments over time. That is, for example, an output can work on any bus, and when the bus is not active, then through the same output you can check the state of a button, or transmit something over another bus. By quickly (tens or even thousands of times per second) switching between two different assignments, you can achieve the effect of “simultaneous operation”.

The main thing here is to follow two rules:

  • The two different applications must not interfere with each other i.e. The time separation must be constructed in such a way that an adjacent function does not distort the result of the function being tested.
  • Under no circumstances should voltage levels conflict.

Let me give you an example:

  • We have a pin on which the output from a certain sensor and a button are hung. The output from the sensor can be 0, 1 in active mode and Hi-Z when the Enable signal does not arrive at the sensor.
  • The button gives a hard 0 to the line through a short circuit.

How it should work:
Let's say that most of the time we have the microcontroller input configured for the Hi-Z input and we take readings from the sensor to which the Enable signal is also applied. When we need to poll a button, we take Enable away from the sensor and its outputs go into Hi-Z mode and do not interfere with us. We switch the microcontroller output to Pull-Up mode and check whether there is a zero at the input - the signal of a pressed button. Have you checked? We transfer the MK input to the Hi-Z input and apply Enable to the sensor again. And so many times per second.

Here we have two contradictions:

  • Logical contradiction
    0 on the line can be in two cases from the sensor or from the button. But in this case, using common sense and the required functionality, we can ignore the logical contradiction.

    We’ll just know that pressing the button distorts the sensor readings, which means that when the sensor is working, we won’t press the button. And so that the sensor readings are not mistaken for a button press, we simply do not poll the button at the moment when we are waiting for data from the sensor. Of course, this will not protect against stupid actions. But to simplify the example, I’m not taking foolproofing into account now.

  • Electrical contradiction
    If the sensor sets 1, and we press the button, then it is obvious that GND and Vcc in the same wire will not get along and someone will die. IN in this case the sensor output will die, as it is weaker - there is no way for a frail transistor to compete with a copper button.

    Such a contradiction cannot be resolved by organizational methods - it is impossible to determine the voltage on the line by eye and decide whether to press the button or not. And one can only guess where the program is now. Therefore, we will solve it schematically.
    Let's add a resistor to the button circuit, the resistor is small, calculated based on the maximum current of the weakest terminal of the line.

    If, for example, the sensor output can provide no more than 10mA, then we need a resistor such that the current through it from Vcc to GND does not exceed this value. With a 5 volt supply it will be 510 ohms. Now, even if there is a log1, high level on the line from the sensor side, then pressing the button will not even cause distortion of the logical level because the resistor is designed taking into account the maximum load of the port

The example turned out to be a little chaotic, but I think the essence is clear. I want you to see and understand not only how it’s done, but also why it’s done :)

Well, a few examples of several functions on one leg:
Firstly, ISP connector. I forgot a long time ago what it was like to poke a microcontroller first into the programmer block, then into the board, then back, and so on many times until you debug the program. I have 6 pins of the ISP connector sticking out on the board, and when debugging, the programmer is always plugged into the board, and I sometimes change the program several times every 10 minutes. I asked and checked. Does not work? I corrected it, re-flashed it again... And so on until it works. MK's resource for flashing is calculated in thousands of times. But the ISP connector eats up the pins. As many as 3 pieces - MOSI, MISO, SCK.

In principle, you can also attach buttons to these pins. In this case, no one will bother anyone, the main thing is not to press these buttons during the firmware. You can also hang LEDs (although in this case the simplest one may fail, but well done!) then when flashing the firmware they will flicker very cheerfully :)))

You can also hang something else on the line under the ISP, the main thing is so that when flashing the firmware this SOMETHING doesn’t suddenly start to go weird. For example, the control of a 100-kilogram manipulator hangs on the ISP line and during the firmware it received a bunch of crazy data - so it can go crazy and smash someone’s head. You need to think in general. But with something that works via a bus interface, the following scheme will work:

We switch the output from 0 to 1 and turn on the upper and lower diode. If we need to light both, then we simply switch the microcontroller output to mode Hi-Z and it’s as if it’s not there, and the diodes will burn with a through current. Or quickly switch the diodes between each other, in which case they will both burn by eye. The disadvantage of the circuit is obvious - the diodes cannot be extinguished. But if, according to the plan, at least one should burn, then why not? UPD: Then I thought, it’s possible to select LEDs and resistors so that their total voltage drop is at the level of the supply voltage, and the total resistors in this case will drive the current to such a minuscule level that when the leg is in Hi-Z, the diodes will not light up at all. At least to the eye it will not be noticeable at all. Except in pitch darkness.

The next option does not save legs, but it allows you to simplify the layout of the printed circuit board without dragging a power or ground bus to the two diodes:

And by applying similar tactics to the buttons, you can either simplify the wiring, or distribute 6 buttons along three legs.
Here, too, everything is simple - one leg gives a lift, the second mows it down to the ground. Pressing the button causes a voltage drop on the pull-up leg. The program senses this and polls each button in turn. Then the roles of the legs change and the next button is polled.

In the six-button mode, the situation is similar - one leg gives the lift, the other the ground, and the third pretends to be a Hi-Z rag and does not reflect. But there is one side effect. For example, we are asking the “B” button. To do this, we place the top line at entrance with pull-up(PORTxy=1, DDRxy=0), average gives low output level(PORTxy=0, DDRxy=1), the lower one does not participate in the process because it is in Hi-Z(PORTxy=0, DDRxy=0). If we press the “B” button, then the top line will sag at that moment and the program will understand that the “B” button is pressed, but if we do not press “B”, but press “E” and “B” at the same time, then the top line will also sag, and the program will think that “B” was pressed, although it was not lying there. The disadvantages of this scheme are that clicks may be processed incorrectly. So if the device will be used by redneck operators who use everything indiscriminately, then it is better to abandon such a scheme.

And, finally, a diagram showing how you can combine a button and an LED:


It also works exclusively in dynamics. That is, we always display the status of the LED - that is, we output either 0 (the diode is on) or Hi-Z (the diode is not on) to the port. And when we need to poll a button, we temporarily (for a few microseconds) switch the output to pull-up input mode (DDRxy=0 PORTxy=1) and listen to the button. The mode when there is a strong high level at the output (DDRxy=1 PORTxy=1) cannot be enabled under any circumstances, because When you press the button, you can burn the port.

Cons - when you press the button, the LED lights up no matter how you look at it. However, this may not be a bug, but a feature :)

These are the pies. Now imagine a program that implements all these dynamic features + a bunch of its own algorithm. It turns out either an endless series of polls, or a legion of all sorts of flags. In such cases, the simplest dispatching or cooperative dispatch is just what the doctor ordered - you run each survey along the cycle of your task and don’t worry. But you use some ATTiny2313 everywhere and look sarcastically at those who shove Mega8 or something fatter into the same task :)

I don’t know anything and I’m afraid to burn something, what should I do???

Don't be afraid and do it. After all, a microcontroller is not such an expensive thing that you should bemoan its death. I threw it in the trash and took a new one out of the bag. At worst, if it’s really scary, then you can buy a ready-made demo board on which everything is already soldered and wired as it should. All you have to do is program and see the result.

And then, using the example of how the demo payment was made, try to make something of your own. The demo board itself is a microcontroller + some starting peripherals, which is enough for a number of simple experiments and can make it easier to connect and study other devices. There are different demo boards, for example, branded systems like STK500 or AVR Butterfly, or mine, which was designed based on my experience and on which the entire further training course will be based.

Recently, many articles on STM32 () have appeared on Habré. The comments repeatedly mention the complexity of the STM32 compared to the AVR. This topic especially affects beginners who want to start learning microcontrollers, and seeing this opinion, choose AVR to study. Let's see if this beast - STM32 - is so complicated?

To do this, we will choose an inexpensive version of the board and write the firmware in a dozen or two bytes (yes, blinking a 2 kilobyte LED is akin to “Hello world” in hundreds of kilobytes x86 for the incompetent). We will also learn how to write programs in any programming language for STM32.

Introduction

What type of microcontrollers should I study? This question, in my opinion, is similar to questions like “Which programming language should I learn?”, “Which foreign language should I learn?” IMHO, you need to study the one that is most needed at a given moment, for a given task. When you know one thing, learning the second will be much easier, and you won’t even think about the third.

So, what is the difficulty of STM32? The most common opinion is that programming its peripherals is difficult. The number and type of STM32 and AVR peripherals are approximately the same. Its configuration is also not much different. So what's the difficulty? In STM32 microcontrollers, all peripherals must first be turned on. That's the whole difficulty.

I compare AVR with public buildings: all the doors are wide open, everywhere monitors sparkle with advertising and the lights are on, and STM32 with a private home: if you want to watch TV, turn it on first, then change channels, if you want to pee-pee, open the door and turn on the lights, wash your hands - open the water, and so on. Don't believe me? Let's make sure together.

Board overview

I chose the cheapest board offered on aliexpress (picture above). A little more expensive $2, 180 rubles in December 2015. On board there is minimal equipment: two quartz resonators - high-frequency at 8 MHz and clock at 32.768 Hz, a reset button, two jumpers for selecting the boot mode, a pair of LEDs - for power and on the PC13 leg and a set connectors: microUSB, debug, two combs for all microcontroller pins.

It’s cheaper to just buy all the parts, make the board yourself and solder it. How to sew and debug? If you have ST-LINK, then it’s better for them, no, it doesn’t matter, there are several more options, for example, via a USB-USART adapter, there is no such thing - you can directly via USB, although you need to write a driver yourself for this case, no one has bothered yet. ST-LINK is quite cheap, and is included in all DISCOVERY series boards. So I used this one.

We connect the power, the LED flashes cheerfully, the board is working. Download and install the programmer program (oil-oil) “STM32 ST-LINK Utility” (we take all programs and documents from the manufacturer’s website). We are trying to read the firmware... The program is read-protected. Apparently, it’s not for nothing that everyone talks about the difficulty of writing programs for the STM32; even the Chinese have protected this extremely complex program from hacking. Or is there a virus bookmark hidden there? We won’t figure it out, we remove the protection and get a pristine STM32F103C8T6 microcontroller.

First program

Let's also blink the LED and do, so to speak, reverse engineering in the mind of the native firmware. How? In order not to create controversy regarding the choice of development environment, I will do this in my native Visual Studio Community. It seems to me that for Windows is better for a man no.

How is the blinking program for Arduino? We configure the output leg and switch it in a cycle from zero to one and back.
What will it look like for STM32? Much more difficult. First, let’s turn on the light in the microcontroller pin configuration room, and then “We configure the leg for output and switch it in a cycle from zero to one and back.” I understand it’s difficult... But we can handle it.

In the document “RM0008. Reference Manual" on our microcontroller, let's look at the memory map for the registers we need.

- Let's go in a simple and logical way.
- Let's go together.

1. Turn on port C clocking (our LED hangs on pin 13 of port C). Let's look at the document. The register we need is RCC_ABP2ENR (we translate: the reset and clock register is the second low-speed peripheral bus). The port address is 0x40021018, the required IOPCEN bit (I/O port C - enable bit) fourth is 0x00000010.

Retreat

Microcontrollers have everything like adult processors. There is a high-speed tire AHB aka “North Bridge” and a low-speed APB aka “South Bridge”. The microcontroller processor itself can do everything to speed up work: it has command prefetching and a command execution pipeline. There is no cache, but the processor is not much faster than memory, and reading and writing to memory can be completed in one clock cycle. So, we can say that the entire memory of the microcontroller is one big cache. Okay, okay, not one and not a big one. Two small caches.
All peripherals are mapped to the address space. Compared to x86, there are no in-out commands, but Intel left them only for compatibility; now they are practically not used.


2. Configure the pin for output. Let's look at the document. The register we need is GPIOC_CRH (we translate: the I/O port register C is the configuration register for the older half of the legs). The port address is 0x40011004, 4 bits are responsible for the configuration of each leg, the value for switching a leg to an output is 0001b, for pin 13 the value is 0x00100000.

3. How to switch a Boolean value on a pin. Let's look at the document. The register we need is GPIOC_ODR (we translate: I/O port register C - data output register). The port address is 0x4001100C, its value is directly output to the pins of the microcontroller, for pin 13 the value is 0x00002000. Everything is ready to write the program (don’t forget to post the project on github):

Int Main (VOID) ( *((int *) 0x40021018) = 0x00000010; // RCC_apb2enr = RCC_APB2ENR_IOPCEN *((Int *) 0x40011004) = 0x00100000; // GPIOC_CRH = MODER_UTER_OV (1) ( *((Volatile int *) 0x4001100C) ^= 0x00002000; // GPIOC_ODR ^= BIT_13 int i; for (i=1000000; i>0; i--) ; ) ) extern int _eram; __attribute__ ((section(".isr_vector"))) int g_pfnVectors = ( (int)&_eram, // initial stack value (int)main // Reset Handler );
With interrupt vectors, I hope everything is clear? We only use two of them, so there's no need to waste memory with dummies. All other interrupts are enabled by software; if not enabled, it means they will never work. The exception is the third HardFault vector, if it happens - the microcontroller is faulty or malfunctions, for simple projects (not space aviation, not medicine) it can not be processed.

This is an educational project, of course you should format all addresses as symbolic constants in separate h-file With big amount defines, as is done in CMSIS. You can take them and adapt them to your needs. For compilation I use gcc, firmware using “STM32 ST-LINK Utility”. The firmware took 56 bytes (hello, assembler).

Another retreat

Another statement about the complexity of STM32 is that there is little documentation in Russian. Debatable. Only two documents are needed - Datasheet and Reference Manual for the desired microcontroller. The language in which it is written can hardly be called English. I studied the language using untranslated toys, my level of English remained at the same level, but I read datasheets without problems, unfamiliar terms are clear from the context.



It seems like a lot has happened, then that’s all for today.

In the second half I will talk about programming STM32 in any programming language.

Tags: STM32, microcontrollers-are-easy, arduino-not-needed

One day, I decided to upgrade my line of development boards. At the moment I don’t feel any particular need to work with new controllers, so it was decided to do a fundamentally different debugging. In it I wanted to implement the following features:

Opportunity battery life. Sometimes you really want to take some device with you “for a walk” or to work, but previous boards required external power. I would like the power supply to be on the board itself.

Use a sufficiently powerful chip. Since I used my debugging on the stm32f100 for a long time, as projects progressed I realized that I wanted to use the chips to the maximum. Since the capabilities of the latter were not enough for me (few legs and a low frequency of 24 MHz), I decided to switch to a slightly larger chip: STM32F103, on which I already had successful debugging, but which was not very widely used.

Use 18650 batteries, which I love so much for their capacity/price ratio.

Use the built-in mini-usb power controller on the MCP73833. I wanted to try to make a factory board with good heat removal from the chip, and see what I can overclock this controller charge without an external radiator.

Use my favorite TPS63000 to create a 3.3V line. It is not a very efficient power controller in terms of idle current, but it works as a boost/buck converter, allowing all of the battery power to be used while outputting high current (units of amps).

Mark all signal pins of the board.

Well, the little things:

Quartz 5032 (not a single failure during the entire operation)

Smd0603+conders 0805 on the smallest footprints.

Separation of analog and digital grounds in the device

Connectors with a pitch of 2.54 type female (PBS20) so that in my breadboards made with loot I can install the ones I have in large quantities The connectors are the same type, but male (cheaper).

Completely one-sided soldering (except for battery connectors).

Testing the DC-DC converter.

After that I started testing. For this purpose, I specially bought a resistor SQP5-4R7 to test the DC-DC controller for a current of ~1A. As a result of the tests, the resistor warmed up to 110 * C (recognized by the pyrometer), which led to some drop in resistance and an increase in current to 1A.

As a result, it was found that there was no additional noise, and the entire system worked like a clock. At the same time the temperature DC-DC converter is in the range of 35-40*C at an external temperature of +27*C. Of course, I understand that as the load increases, pulsations will also increase, but I think that when there is a sufficient power load working from the microcontroller’s power line, then special precision of the analog part will not be required.

Testing the charger.

Honestly this is the first time I decided to make a commercially produced board with MCP73833. Last time I looked at how this controller generally charges and works + got acquainted in practice with the algorithm of its operation. In this case, since the graduation was approaching, and I really wanted to try, I simply took apart previous fee and carefully transferred all the components to the new one. As a result, when charging the battery after the previous test, I recorded that with a charging current of 375 mA, the temperature of the charge controller did not even reach 45 * C. This suggests that you can safely resolder the charge control resistor to increase the charging current. I'll raise it to 500mA, but I won't go any further. This is not due to the heat that will be released on the chip, but to the fact that not all of my five volt blocks power supplies for mobile phones provide more than 500mA. There are no special protections in those that I looked at, and this can lead to problems in the electrical network.

Disadvantages of the developed board.

Having carried out these tests, and also imagining how I would work in the future with this board, a number of factors became clear that I did not take into account in this project:

I did not have enough experience in tracing to install an on/off switch on the battery in this printed circuit board. Of course, I can do this very well by pulling the 18650 out of the connector or installing a special plastic plate. But this is a crutch, my friends. It would be nice to finish the switch.

There is no BMS for the battery on the board, although it is needed. Purely technically, the TPS63000 operates in the input voltage range of 1.8-6V. This is possible if the battery is deeply discharged and will lead to its damage. This problem can be solved by some modification of the battery itself and installing a cheap bms directly onto the battery with pushing/cutting one of the contacts. Again, not critical, but with crutches.

IN USB connector Nothing is connected via digital lines. This controller has a built-in USB interface, but I did not connect it to the connector. This is due to the fact that in current projects this is not necessary and normal piping must be installed usb interface on the board (with protective diodes and a level matching microcircuit, I’ve never seen it before).

There is no PowerGood LED on the board. When the chip is working, it doesn't say anything about it. This was done intentionally to extend the life of the battery, but sometimes it is not convenient. In the future, I’m thinking of making an LED on a little-used pin and providing a link to the code for turning on the LED when the controller is operating

Insufficient compactness of the board. The current dimensions of the board are 34x80 mm. You always want a more compact solution. Maybe it will work out. Although, on the other hand, there is not much space on the back side of the printed circuit board.

Some people find the programming connector and reset button not very convenient. It’s difficult to reach it when the board is inside, but again you can use a screwdriver (crutches).

The price of the device is quite high. I did prototype production in a panel, so the price is reduced, but the devil is far from a Chinese arduino/stmka for 200 rubles.

Anyone who wants such a thing for themselves.

Currently there are 2 such boards, so anyone can purchase it for 1,700 rubles without shipping and an 18650 battery. Why don’t I send the battery? – it’s a matter of Russian Post. I would be happy if they sent the batteries, although I will try to send one 18650 can with the device for free to the first person who orders.

You can contact me by mail: [email protected]

From my point of view about the price: now for this money you can buy an original Arduino or discovery from China. But you can’t take either one or the other with you for the whole day without an external body kit and batteries. And here you get a ready-made thing into which you can insert your board and get a very rigid structure that you can safely carry with you without worrying that the solder will come off somewhere or the device will experience a short circuit.

Figure 1. STM32F103RC_board circuit diagram

Some refinement. Version 1.0.

It just so happened that while preparing the board for the first sale (not my soldered sample above), I decided to add a number of features to it for the consumer.

At first glance the following things stand out:

There is no PBS-30 “comb” for insertion into printed circuit board. To my regret, there are 2 factors at work here (I ran out of them and the customer asked not to install them.

The programming connector is made with different angular pins. Last time I also wanted to use such pins, but the store available to me did not have them. As a result, I was accidentally brought to one of the Moscow radio markets, where I found the widest selection of these connectors and bought the ones I needed.

LEDs are a little different. To my regret, I take SMD LEDs from a large pile, and I don’t always know what color they are. This time there are two green and one white LEDs.

But the devil is often in the details, and so it turns out here. On this board I tried different resistors to control the charging current. As a result, it was revealed that the MCP73833 microcircuit on this board normally holds a current of 800 mA and, when charged with 2.5 V Li-Ion batteries, warms up to 65-70 * C. Of course, according to the datasheet, it works with currents up to 2A, but I honestly can’t yet imagine how to implement them on the msop-10 case. Maybe in the next case, in which this problem is solved better, it will be possible to pull out 2A.

An additional small detail that few will even notice is the installation of the Murata inductor and not its Chinese twin brother with an unknown name. They look similar, only this one is better shielded.

Precaution.

While performing a full diagnostic test, I burned out one STM32F103RCT6. How I did it:

I took a regular multimeter and poked it at the resistor feedback. In this case, the TPS63000 sees a voltage drop in the feedback and begins to quickly increase the voltage at its output. As a result, according to the test carried out with a sealed controller: the voltage in the pulse increased to 7V. In this case, the controller experienced overvoltage and died.

A funny thing happened later: at the 3.6V input, the controller began to consume 0.6A. This is due to the fact that the TPS63000 has built-in 2A current protection. It was this current that flowed through the dead microcontroller. At the same time, the functionality of the entire remaining circuit was maintained.

It’s easy to diagnose this problem: just connect an individual measuring thermometer (finger) to the controller, and if it starts to warm up, it means it’s dead.

Packaging of the sent board

When sending this board to my colleague, I decided to pack it better so that R. Post wouldn’t break everything. In the end it turned out like this:





How to attach a capacitive touch sensor to a microcontroller. This idea seemed quite promising to me; for some devices, touch keys would be much better suited than mechanical ones. In this article I will talk about my implementation of this useful technology based on the STM32 Discovery development board.

So, just starting to master the STM32, I decided to add touch detection to the device as an exercise. Having started to understand the theory and practice in the above-mentioned article, I repeated the circuit of comrade "a. It worked perfectly, but I, a lover of minimalism, wanted to simplify it by getting rid of unnecessary elements. In my opinion, an external resistor and a power supply path turned out to be superfluous. All this already found in most microcontrollers, including AVR and STM32. I mean pull-up resistors of I/O ports. Why not charge the plate and our fingers through them? In anticipation of the catch, I assembled a circuit on a breadboard, which, to my To my surprise, it worked the first time. In fact, it’s even funny to call it a circuit, because all we need is to simply connect the contact plate to the leg of the debug board. The microcontroller will do all the work.

What is the program? First two functions:
The first outputs a logical “0” to the sensor pin (zero pin of register C)

Void Sensor_Ground (void) ( GPIOC->CRL = 0x1; GPIOC->BRR |= 0x1; )

The second configures the same output as an input, with a pull-up to the power supply.

Void Sensor_InPullUp (void) ( GPIOC->CRL = 0x8; GPIOC->BSRR |= 0x1; )

Now at the beginning of the polling cycle we will call Sensor_Ground(), and wait a while to discharge all the residual charge on the sensor to the ground. Then we will reset the count variable, which will be used to calculate the charging time of the sensor, and call Sensor_InPullUp().

Sensor_Ground(); Delay(0xFF); //simple empty counter count = 0; Sensor_InPullUp();

Now the sensor begins to charge through an internal pull-up resistor with a nominal value of about tens of KOhms (30..50KOhms for STM32). The time constant of such a circuit will be equal to a few clock cycles, so I changed the quartz resonator on the debug board to a faster one, 20 MHz (by the way, I did not immediately notice that on the STM32 Discovery the quartz is changed without soldering). So we count the processor cycles until a logical one appears at the input:

While(!(GPIOC->IDR & 0x1)) ( count++; )

After exiting this loop, the count variable will store a number proportional to the capacity of the sensor plate. In my case with a 20 MHz chip, the count value is 1 when there is no pressure, 7-10 with the lightest touch, 15-20 with a normal touch. All that remains is to compare it with the threshold value and do not forget to call Sensor_Ground() again, so that by the next polling cycle the sensor will already be discharged.
The resulting sensitivity is enough to confidently detect touches on bare metal pads. When covering the sensor with a sheet of paper or plastic, the sensitivity drops three to four times; only confident presses are clearly detected. To increase sensitivity in cases where the sensor needs to be covered with protective material, you can increase the clock frequency of the microcontroller. With the STM32F103 series chip, capable of operating at frequencies up to 72 MHz, millimeter barriers between the finger and the sensor will not be an obstacle.
Compared to implementation "a, my approach works much faster (about a dozen clock cycles per poll of one sensor), so I did not complicate the program by setting up timer interrupts.

Finally, a video demonstrating how the sensor works.

Main.c test program.

To microcontroller

Thanks to the user for the very useful article ARM microcontrollers STM32F. Quick start with STM32-Discovery, to the user for the idea and intelligible theoretical description.

UPD. After comments "a I decided to look into the clocking and found that by default the STM32 Discovery is set to the clock frequency
(HSE / 2) * 6 = 24 MHz, where HSE is the external crystal frequency. Accordingly, changing the quartz from 8 to 20 MHz, I forced the poor STM to work at 60 MHz. So, firstly, some of the conclusions are obviously not entirely correct, and secondly, what I was doing could lead to chip failures. In case of such failures in the microcontroller there is a HardFault interrupt, using it, I checked more high frequencies. So, the chip starts to fail only at 70 MHz. But although the controller processes this particular program at 60 MHz, when using peripherals or working with Flash memory it can behave unpredictably. Conclusion: treat this topic as an experiment, repeat only at your own peril and risk.

Recently, many articles on STM32 () have appeared on Habré. The comments repeatedly mention the complexity of the STM32 compared to the AVR. This topic especially affects beginners who want to start learning microcontrollers, and seeing this opinion, choose AVR to study. Let's see if this beast - STM32 - is so complicated?

To do this, we will choose an inexpensive version of the board and write the firmware in a dozen or two bytes (yes, blinking a 2 kilobyte LED is akin to “Hello world” in hundreds of kilobytes x86 for the incompetent). We will also learn how to write programs in any programming language for STM32.

Introduction

What type of microcontrollers should I study? This question, in my opinion, is similar to questions like “Which programming language should I learn?”, “Which foreign language should I learn?” IMHO, you need to study the one that is most needed at a given moment, for a given task. When you know one thing, learning the second will be much easier, and you won’t even think about the third.

So, what is the difficulty of STM32? The most common opinion is that programming its peripherals is difficult. The number and type of STM32 and AVR peripherals are approximately the same. Its configuration is also not much different. So what's the difficulty? In STM32 microcontrollers, all peripherals must first be turned on. That's the whole difficulty.

I compare AVR with public buildings: all the doors are wide open, everywhere monitors sparkle with advertising and the lights are on, and STM32 with a private home: if you want to watch TV, turn it on first, then change channels, if you want to pee-pee, open the door and turn on the lights, wash your hands - open the water, and so on. Don't believe me? Let's make sure together.

Board overview

I chose the cheapest board offered on aliexpress (picture above). A little more expensive $2, 180 rubles in December 2015. On board there is minimal equipment: two quartz resonators - high-frequency at 8 MHz and clock at 32.768 Hz, a reset button, two jumpers for selecting the boot mode, a pair of LEDs - for power and on the PC13 leg and a set connectors: microUSB, debug, two combs for all microcontroller pins.

It’s cheaper to just buy all the parts, make the board yourself and solder it. How to sew and debug? If you have ST-LINK, then it’s better for them, no, it doesn’t matter, there are several more options, for example, via a USB-USART adapter, there is no such thing - you can directly via USB, although you need to write a driver yourself for this case, no one has bothered yet. ST-LINK is quite cheap, and is included in all DISCOVERY series boards. So I used this one.

We connect the power, the LED flashes cheerfully, the board is working. Download and install the programmer program (oil-oil) “STM32 ST-LINK Utility” (we take all programs and documents from the manufacturer’s website). We are trying to read the firmware... The program is read-protected. Apparently, it’s not for nothing that everyone talks about the difficulty of writing programs for the STM32; even the Chinese have protected this extremely complex program from hacking. Or is there a virus bookmark hidden there? We won’t figure it out, we remove the protection and get a pristine STM32F103C8T6 microcontroller.

First program

Let's also blink the LED and do, so to speak, reverse engineering in the mind of the native firmware. How? In order not to create controversy regarding the choice of development environment, I will do this in my native Visual Studio Community. It seems to me that there is no better Windows for a man.

How is the blinking program for Arduino? We configure the output leg and switch it in a cycle from zero to one and back.
What will it look like for STM32? Much more difficult. First, let’s turn on the light in the microcontroller pin configuration room, and then “We configure the leg for output and switch it in a cycle from zero to one and back.” I understand it’s difficult... But we can handle it.

In the document “RM0008. Reference Manual" on our microcontroller, let's look at the memory map for the registers we need.

- Let's go in a simple and logical way.
- Let's go together.

1. Turn on port C clocking (our LED hangs on pin 13 of port C). Let's look at the document. The register we need is RCC_ABP2ENR (we translate: the reset and clock register is the second low-speed peripheral bus). The port address is 0x40021018, the required IOPCEN bit (I/O port C - enable bit) fourth is 0x00000010.

Retreat

Microcontrollers have everything like adult processors. There is a high-speed tire AHB aka “North Bridge” and a low-speed APB aka “South Bridge”. The microcontroller processor itself can do everything to speed up work: it has command prefetching and a command execution pipeline. There is no cache, but the processor is not much faster than memory, and reading and writing to memory can be completed in one clock cycle. So, we can say that the entire memory of the microcontroller is one big cache. Okay, okay, not one and not a big one. Two small caches.
All peripherals are mapped to the address space. Compared to x86, there are no in-out commands, but Intel left them only for compatibility; now they are practically not used.


2. Configure the pin for output. Let's look at the document. The register we need is GPIOC_CRH (we translate: the I/O port register C is the configuration register for the older half of the legs). The port address is 0x40011004, 4 bits are responsible for the configuration of each leg, the value for switching a leg to an output is 0001b, for pin 13 the value is 0x00100000.

3. How to switch a Boolean value on a pin. Let's look at the document. The register we need is GPIOC_ODR (we translate: I/O port register C - data output register). The port address is 0x4001100C, its value is directly output to the pins of the microcontroller, for pin 13 the value is 0x00002000. Everything is ready to write the program (don’t forget to post the project on github):

Int Main (VOID) ( *((int *) 0x40021018) = 0x00000010; // RCC_apb2enr = RCC_APB2ENR_IOPCEN *((Int *) 0x40011004) = 0x00100000; // GPIOC_CRH = MODER_UTER_OV (1) ( *((Volatile int *) 0x4001100C) ^= 0x00002000; // GPIOC_ODR ^= BIT_13 int i; for (i=1000000; i>0; i--) ; ) ) extern int _eram; __attribute__ ((section(".isr_vector"))) int g_pfnVectors = ( (int)&_eram, // initial stack value (int)main // Reset Handler );
With interrupt vectors, I hope everything is clear? We only use two of them, so there's no need to waste memory with dummies. All other interrupts are enabled by software; if not enabled, it means they will never work. The exception is the third HardFault vector, if it happens - the microcontroller is faulty or malfunctions, for simple projects (not space aviation, not medicine) it can not be processed.

This is an educational project, of course you should format all addresses as symbolic constants in a separate h-file with a large number of definitions, as is done in CMSIS. You can take them and adapt them to your needs. For compilation I use gcc, firmware using “STM32 ST-LINK Utility”. The firmware took 56 bytes (hello, assembler).

Another retreat

Another statement about the complexity of STM32 is that there is little documentation in Russian. Debatable. Only two documents are needed - Datasheet and Reference Manual for the desired microcontroller. The language in which it is written can hardly be called English. I studied the language using untranslated toys, my level of English remained at the same level, but I read datasheets without problems, unfamiliar terms are clear from the context.



It seems like a lot has happened, then that’s all for today.

In the second half I will talk about programming STM32 in any programming language.

Tags: STM32, microcontrollers-are-easy, arduino-not-needed