Stm32 Serial Communication Interface

Posted on

If there is absolutely no reaction once device is connected to PC, I would assume one of the following issues is present:– you have a wrong cable (I once used some cheap power supply usb cables without data wires) or other hardware issue.– your device configuration (code) is invalid or CPU don’t even do initialization due some error– one of other 341532 possible issues 😀I would first try to search for any visible hardware issues, than I would program the most basic (default) USB example (CubeMX HID device) and try to get this working. Than, when you are sure that the board is OK, move on with CDC.p.s.: Do yourself a favor and while asking for help, describe as much details as you possibly can. What do you wish to accomplish, what have you already tried and what are the results of that, what have you changed in a given example, what did you discover when debugging code, It is nearly impossible to help with no info. I wouldn’t do that. Standard peripheral libraries is already outdated, and as far as I know, STM32 does not develop it anymore. Not the case with STM8, but for STM32, stick to either old StdPeripheral library or port to HAL/LowLayer.In case of CubeMX generated USB files, they are based on HAL, so it would be really hard to port this files to StdPeripheral lib. Maybe you could include required HAL libraries in the project, but this would take time – I wouldn’t go this way.You would probably re-write/port whole application to HAL/LL much faster than re-implement USB to use StdPeripheral lib.

This would also alow you to regenerate project with CubeMX. “When I plug it in, it enumerates and shows up as a com port (Com8). It doesn’t show up in Teraterm, and if I try to open it, I get “Cannot be opened.”Are you sure you have only one connection to this port (If you connect with some other software/scripts to this port, port might not be accessible, although it is listed). Another question is: is your STM responsive (can CPU handle USB stack and data, or is in your while (1) loop or some hardfault handler?Also is there a real need for CRC’s and such over USB, or is that adequately handled at a lower level (in the USB communication stack)?The most honest answer I can give: I don’t know. But, first google look up lead me to a interesting forum topic. That’s cool!I found the issue; evidently my “init code” (check ADC voltages, etc) was “too busy” and it wasn’t initializing correctly (too much of a gap between “plugging in” and “MXUSBDEVICEInit”, so the PC was getting confused).Pulling DM & DP low for 1sec before the MXUSBDEVICEInit in main forced the computer to do an “unplug and replug” event and now it’s working well.

Onwards!Now I’m really liking the USB I’m not sure I’ll ever go back to normal serial:– Baud rate? Don’t care, but if I did, the STM32 can read what the PC wanted.– Which com port? Look at the USB info and find the “ThisPortIsMine” and I know which com port to open, no matter what the PC enumerates it as.– 2 Pins and I get CD/RTS/CTS and everything else and I can have multiple devices if I wanted to (so HID to send some control signals back and forth and); no need to “decode and handle” line breaks (for a forced reset), etc.

It resets the traffic (which disconnect windows), but it doesn’t do the “replug” event to cause the windows box to restart the connection. I fixed it by making the port GPIO and holding DM&DP “low” for 500ms before calling the MXUSBDEVICEInit function.It means that every time you restart the device, it “unplugs and replugs”, but it does work. You need to let the device run without breakpoints for a couple of seconds after the USBDEVICEInit so it will finalize the connection (you can put breakpoints in, but don’t stop the CPU for a little bit). Well, I must respond in the same way as with first comment – if you need help, make an effort and describe what is going on in details, what you already tried, I’m sorry, I didn’t notice your previous comment was sent to spam.I generated code in CubeMx as per above link.I can’t offer help for samples that are not part of this blog post.

It is hard to advise for a specific problems that are not this project specific. I can only offer (if at all) generic answers, which you could probably google faster than you read this:).2) What does work?First, try to achieve that your board is registered by PC. Do you have correct drivers?

In order to send/receive data, you must be sure your device is properly enumerated by PC OS.I tried to put in debug mode (In CubeMX enable SW in Debug optionsLogging is good. BUT, make sure your extensive logging does not cause delays – you should not block CPU to periodicaly handle USB stack.5) I have seen in the Log (Invalid Device/Class). I noticed the it’s unable to find the Device/class.This is your homework.

🙂 Research what could go wrong when device needs to be enumerated by PC. You must see it in device manager, as it is displayed in this blog post.

Universal Synchronous/Asynchronous Receiver TransmitterThe serial communication in asynchronous mode is one of the simplest and most used methods to exchange data between a microcontroller and other devices. Such kind of communication can be achieved through a Universal Synchronous/Asynchronous Receiver Transmitter (or USART) as well as UART peripheral which actually is a subset of USART. Each STM32 microcontroller is equipped with multiple instances of these peripherals (from 2 up to 8) depending on the microcontroller model.In this article, we are going to take an overview of serial communication protocols and peripherals putting some focus on UART and how to use it with the Serial Driver of ChibiOS/HAL. This driver offers an easy way to use USART providing buffer mechanisms as I/O queue and capability to print formatted strings. Parallel communication An example of 8-bit parallel communicationSince the outset of computer science, exchange data between computers has always been a need.

In the beginning, all the communication were Parallel.In a parallel communication, each bit is transmitted over a dedicated line: this means that such kind of communication requires a line per each bit plus a synchronization line to carry out the operation. Of course, we are intending that the transmitter and the receiver are sharing the same reference ground.Let us consider an 8-bit parallel communication where data is sampled on the positive edge. In such kind of communication, the transmitter properly changes the status of the data lines (D0 to D7) and toggles the synchronization line (TRG). On positive edge of TRG, the receiver samples data lines and operation completes.The parallel communication is reliable and fast but quite impractical as the number of wires required to carry out the transmission is almost proportional to the word size. Serial communicationNowadays, almost all communications are Serial. In such kind of communication, the bits are sequentially transmitted over a single line which usually is known as BUS. The idea itself is quite simple but such kind of communication requires a more complex synchronization between communication parties.From synchronization point of view, serial protocols can be split into two types:.

Synchronous Serial, whereas a clock signal is generated by one of the endpoint’s interface and provided to the others through a specific clock line. The communication part which generates the clock is named Master while other Slaves. Examples of such kind of communication are the SPI, the I2C or the USB. Asynchronous Serial, whereas there is not a common clock signal, but the synchronization is performed sending additional bits over the data line (like start and stop condition), and baud-rate is known to all the parties. Example of such kind of communication is Asynchronous RS-232 which can be implemented through the UART.An example of asynchronous communicationFrom the communication point of view, protocols can be split into three types:.

Simplex Communication, whereas communication is one way like in figure 2. Half-duplex Communication, whereas the communication is bidirectional on a single wire. In this case, it is not possible to send and receive data at the same moment. Example of such kind of communication is the I2C as well as the three-wires SPI.

Full-duplex Communication, whereas the communication is bidirectional on two separate wires. In this case, it is possible to exchange data in the two directions at the same moment. Examples of such kind of communication are the SPI and the UART.Even if synchronous buses can reach higher baud-rate in comparison to asynchronous one, they require an additional line for clock and the whole communication is strictly related to the reliability of that signal. Clock lines (especially at high frequency) can be affected by disturbances as line load effect which depends also by the bus length.Asynchronous protocols like the RS-232 are still widely used because of their simplicity and because they actually require just a couple o wire (RX and TX) plus reference ground to put two endpoints in touch communicating over relatively long distances. The RS-232In this article, we will give particular emphasis to Serial communication and in particular to th e Recommended Standard 232 (or RS-232 ). This standard has been introduced in 1960 and formally defines the connection between a Data Terminal Equipment (or DTE ) and a Data Communication Equipment ( DCE ). Such standard has been used for a long time to connect PC to peripherals (like modems, printers, and mice) using computer serial ports.

It has been gradually replaced by more functional Universal Serial Bus and TCP/IP standards but it remains still largely used in an embedded system where is usually implemented through the USART peripheral. Communication frameIn the beginning, the DTEs were electromechanical teletypewriters and DCEs were usually modems. The standard was based on the idea of transmitting characters and this explains why each RS-232 transfer operation has a data size 8-bit.Bits are encoded as Bipolar Non-Return to Zero Level also known as Bipolar NRZL. In this binary code ‘ ones‘ are represented by the high logic level ( VDD) and ‘ zeros‘ by low logic level ( -VDD). In NRZ, the idle condition is usually associated to the high logic level and logic levels are bipolar (+/-VDD with VDD from 3V to 25V) and this means that signal as not to return to zero before a new bit transmission. The actual VDD value depends on required disturb immunity.

In the case of PC COM ports, VDD is usually 9V or 5V but the circuitry is able to operate up to 25V as this voltage have been often adopted in a noisy environment like industry.The RS-232 protocol can be implemented through the USART peripheral but microcontroller are not able to manage bipolar signals. Instead, signals generated by STM32′ USART (but more in general from microcontrollers) are encoded as Unipolar NRZL: ‘ ones‘ are represented by a positive voltage ( VDD) while ‘ zeros‘ are represented by reference ground voltage ( GND). This is why Logic-Level Shifter like the ST3232 or the MAX3232 is required connecting a microcontroller to a PC COM Port through USART. A screenshot of Eclipse terminalAs the communication is asynchronous, the data line has to implement a synchronization mechanism: each data frame begins with a S tart Bit which actually is a transition from a high logical state to a low logical state.

This allows sender and receiver to synchronize each other (assuming the baud-rate and data frame format known). The length of the start bit is perfectly known and is equal to the time required to transmit one bit at a given baud rate. Each data frame ends with a Stop Bit which is a transition low to high. The duration of Stop Bit is configurable as 0.5, 1, 1.5 or 2-bit times: this because the stop bit actually can be intended as an idle time to allow the entire system to remain in sync.As said the synchronization can be achieved because baud-rate is known by both receiver and transmitter.

The RS-232 baud-rate is based on multiples of the rates for electromechanical teleprinters. Bit rates commonly supported include 75, 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600 and 115200 bit/s. A funny note is that some specific Crystal oscillator with a frequency of 1.843200 MHz has been sold specifically for this purpose for a long time.To reduce problems related to noise disturbance or clock tolerance there is the chance to add an additional bit to payload transmission to ensure that the total number of 1-bits in the string is always even or odd: this is known as the parity bit or the check bit and is the simplest form of error detecting code.

Consequently, there are two variants of parity bits: the even and odd parity bit.To conclude RS-232 allows also flow control using up to six extra signals to implement hardware handshake. However, manufacturers have over the years built many devices that implemented non-standard variations on the standard, for example, printers that use DTR as flow control. From RS-232 to USB CDCNowadays is almost rare to see a COM Port on the rear of a PC case: this because the USB has proven to be perfectly able to supersede the RS-232. To do that the USB provides also a specific profile known as Communication Device Class (or CDC). In USB CDC RX and TX streams are encapsulated in the USB protocol using a couple of USB Endpoints and the operating system on the USB side makes the USB device appears as a traditional RS-232 port usually named as Virtual COM Port.Such device class is implemented also by the ST-Link V2-1 debugger available on many STM32 development kits. Connecting this debugger on Windows the CDC will appear in device manager as ST-Link Virtual COM port.

From the device side, the ST-Link is physically connected to a couple of pin of the STM32 which can be rerouted as UART TX and UART RX via GPIO Alternate Functions. The information about this connection is on the board schematic and thus reported in the board user manual. For example looking at the STM32 Nucleo-64 User Manual you will find out that ST-Link is connected to USART2 through the pin PA2 (Arduino connector D1) and PA3 (Arduino connector D0).As we will see in a later article in ChibiOS there are also some examples to implement a CDC inside our code and use the STM32 USB as a Virtual COM Port. IF you are in that annoying case where you cannot use the ST-Link and your device does not have the USB peripheral you may think to use an FTDI chip which is easy to find on the internet in form of break-out boards. STM32 USARTSTM32 is equipped both with UART and USART: the last one is actually a super-set of the first one which is provided with a clock line and is able to perform full-duplex and half-duplex synchronous communication.

In such case, the USART actually acts like an SPI. Anyway, here we will focus on asynchronous communication and we will use always USART like a UART.The STM32’s UART is designed to implement many serial protocols: for example, it implements two different kinds of binary encoding which are the Unipolar NRZL and the Manchester Code. In the first case a ‘1’ is represented by a VDD and a ‘0’ by a GND, in the second case, a data signal is encoded in the raising and falling edges. Unipolar NRZL and Manchester encodingThe Manchester code is designed to avoid long permanency of a certain logical state: indeed in such code, a level state can persist half or one-bit times in comparison to NZRL.

This is very useful in those applications where communication channel reliability is non-guaranteed like the IrDA.In serial protocol like the Recommended Standard 485 there is room for an architecture single master multiple slaves: in such network, each slave has its own address and master can send two kinds of data: slave addresses and data. To distinguish between those two types of data protocol accept a ninth bit. Thus we have that. addresses have the 9th bit as ‘1’;. data have the 9th bit as ‘0’.To implement such kind of communication, the STM32 UART allows also to select data size choosing between 8-bit and 9-bit payload length.One of the problems of asynchronous communication is a lack of clock accuracy: as timing is generated internally and synchronization happens through the start bit a misalignment is possible. This condition is more critical the higher is baud-rate. To mitigate this effect, UART peripherals usually oversample data signal.

STM32’s UART is able to perform configurable 8/16 bit oversampling: this means that each bit is sampled 8/16 times to reduce error and mitigate noise effects.The baud rate generator is fractional and it is able to generate any transmit and receive baud-rate starting from the ARM Peripheral Bus (or APB) which supplies the clock to every STM32’s peripheral.Each STM32’s UART peripherals come with some dedicated I/O which can be rerouted using GPIO Alternate Function. Those IO are:. the transmission line ( UARTTX). the receiver line ( UARTRX). Clear to Send ( UARTCTS). Request to Send ( UARTRTS)It is possible to control the serial data flow between two devices using two additional I/O which are the Clear To Send (or CTS) and the Request To Send (or RTS): in such scenario receiver’s RTS is connected to the transmitter CTS; when the receiver lowers the line the transmitter sends a byte. The ChibiOS Serial DriverChibiOS/HAL offers a quick and easy way to use the UART through a software driver known as Serial Driver (often shortened as SD).The Serial Driver buffers input and output streams using I/O Queues and this offers a big benefit: the user application has not to handle Interrupt Requests because the driver does it internally storing data in these buffers.

This mechanism allows to easily implement a producer-consumer pattern without any effort from the application side: in this scenario, the driver fills a buffer and the user application consumes data. Such pattern allows to not lose any byte if the application consumes data faster than production rate and this condition is easily achievable considering serial baud rates and typical STM32 core speed.As a side note, ChibiOS/HAL offers another driver to deal with UART which is the UART Driver: this driver exposes IRQ to the application thus the user has to properly fill some driver callback to handle character reception, transmission and eventually operation errors.

This driver will be presented at a later moment and we will focus on Serial Driver only.Each API of the Serial Driver starts with the prefix “sd”. Function names are camel-case, pre-processor constants uppercase and variables lowercase. Driver enabling and peripheral allocationTo use the SD it shall be enabled in our project halconf.h file and we should assign at least a peripheral to it acting on mcuconf.h. We have already introduced this concept but we will recall this quickly here (if you want to read more maybe you should give a look ).Each ChibiOS driver can be enabled or disabled in the halconf.h file and each project have is own HAL configuration header.

In the original demos, all unused drivers are usually disabled. If you have launched the default demo you should have noticed that we use Serial Driver to print test suite results, and us most likely your project will be a copy of the default one most-likely you will find the SD already enabled. #define STM32SERIALUSART6PRIORITY 12Compile error while assigning same peripheral to multiple driversNote that is not possible to assign the same peripheral to a different driver because this would generate conflict on IRQ management and the project would not compile.For instance, it is not possible to assign USART 2 both to the Serial Driver and UART Driver and trying to do will result in a compile error. In figure 4 the problem window reports the compile error derived by such operation. The error is due to the tentative to assign the same IRQ line (VectorD8) to two different drivers.

The Serial Driver objectand each driver is represented by a structure. This implementation allows multiple instances of the same driver and so is for the SD.

There is a Serial Driver instance for each available USART but each instance becomes available only when a peripheral is assigned to the driver. #endifAs example assigning the STM32 USART 1 to the serial driver, the SD1 object would become available, SD2 assigning USART 2, SD3 assigning UART 3 and so on.Each driver in ChibiOSHAL implements a Finite State Machine and so it is for the Serial Driver. The current state of the driver is stored inside the object in a field named state (you can access it using structure syntax as example SD2.state).

The following image has been grabbed from the and illustrates the finite state machine of the SD The Serial Driver state machine Serial driver initializationComparing different ChibiOSHAL drivers we will find some similitudes which will help us get familiar with ChibiOS approach. All the drivers have an initialization function which for the Serial Driver is. This function is automatically called on HAL initialization if the driver is enabled in the HAL configuration file. The HAL initialization happens in the main of our application on halInit call. We have noticed a similar approach in the PAL driver and actually, this approach is adopted in every ChibiOS/HAL driver. The sdInit function initializes objects and variables moving the state of the driver from SDUNINIT to SDSTOP.Note that sdInit only initializes variables and objects related to the Serial Driver. User shall not confuse initialization with configuration.If a ChibiOS driver is enabled in the HAL configuration file, it is automatically initialized on HAL initialization. Initialization is related to variable initialization more than on hardware configuration.

Configuring serial driverBefore to use it, the serial driver shall be properly initialized and configured. This operation is carried out by another function: the start. This function shall be called at least once by the user application before to start the serial communion. Its purpose is to configure the peripheral and this involves setup of all that features we have introduced: the baud rate, the parity bit, the stop bit length, encoding and so on.In ChibiOS/HAL every driver except PAL shall be started before to be used.The sdStart function receives two parameters which are a pointer to the serial driver object we want to start (e.g. &SD1, &SD2 or whatever is the USART we are going to use) and a pointer to a structure which represents the related configuration. This structure contains all the dependencies which are strictly related to the underlying hardware.

This means that moving from an STM32 family to another which has different underlying hardware we most likely have to apply some changes to these configuration structures.Starting a driver we need a pointer to it and a pointer to its configuration structure. This structure contains all the HW dependencies and has to been reviewed if we port our application on a different microcontroller.The start function usually enables the peripheral clock. In certain applications (especially those addressed to low power) it is undesired to keep a peripheral clocked when it is not used. Because of that, there is another function we could use to stop the driver and stop the peripheral clock: the stop.

This function can be called by the user application when the peripheral is unnecessary. It is almost intuitive that after a stop we need a new start to be able to use again the driver.It is possible to stop a driver to reduce hardware power consumption when peripheral is used for a small percentage of execution time. After being stopped a the driver shall be re-started to be used again.A most common paradigm is to start the driver when needed and stop it when the operation has been completed. This offers advantage especially if peripheral is actually used in a small slice of the whole time amount of execution time.A similar approach is used when we need to change driver configuration on-the-fly. In such a scenario, we can start peripheral multiple time with a different configuration. Note that stop is not required, rather, it is discouraged because in case of multiple subsequent sdStart calls certain internal operations would be skipped.It is possible to start driver more than once with different configuration in case we need to change driver configuration on-the-fly. The configuration structureThe configuration structure is composed by two separated parts: the first part remains unchanged across all kind of hardware, the second is strictly hardware dependent.

SerialConfig;Considering SerialConfig, speed represents the independent part and is the baud rate expressed as an unsigned integer. The other three values represent the value which will be used to initialize the Control Register 1, Control Register 2 and Control Register 3 of USART driver on start. The meaning of each bit of these register is described inside the reference manual of the STM32 currently in use.Dealing with configuration there are some hints that can help you to figure out how to correctly compose them:. take a look to demos under the testhal folder and testex folders: in these demos, you can find some precomposed configuration that you can copy and use in your application. As the configuration depends on hardware be sure to pick a demo for the subfamily you are currently using.

those fields which are related to hardware are described in the reference manual, use it to spot the meaning of each bit. remember that the start function usually does some internal obvious modification to register values passed through the configuration. As instance bit 13 of CR1 of UART for STM32F401RE is an enable and shall be set as 1 to enable the peripheral: you can take for granted that sdStart force this bit to 1. There are some simple techniques to change a certain bit of the register leaving others unchanged. Such operation takes the name of bit-masking and the adopted paradigm to deal with registers read-modify-write. This is a knowledge you really should do have; if don’t, I highly suggest you read (even at later moment).

You do not have to define register bitmasks as they are already defined and available in CMSIS header files. You can find these files under the folder chibios182oscommonextST. For example, the following snippet of code has been extracted from the file chibios182oscommonextSTSTM32F4xxstm32f401xe.h and represent the bitmasks related to USART Control Registers. SdRead ( & SD3, buffer, 5 );Note that these functions work with an 8-bit unsigned integer instead of relying on a primitive type like the char. This makes the API compiler independent. Sometimes casts are required to avoid a warning at compile time. IO QueuesThe I/O functions just presented interact with the I/O queue as schematized in the next diagram A diagram representing how queues are used in Serial driverQueue size can be configured in your project’s HAL Configuration file and the default value is 16 bytes or 16 characters.

In asynchronous mode, the input and the output are completely independent.For instance, let us consider the RX side and the TX side separately focusing on the RX side only. The paradigm of this implementation is the Producer-Consumer. STM32 USART RX fills the Input Queue while the user application consumes data emptying the buffer. If data is not consumed at a faster rate than production the queue will be filled and characters arriving from the RX will be lost.With a proper application design, data is consumed faster than production rate and there is no data loss. This condition can be achieved:. increasing priority of thread which consumes the data.

reducing the sleeping time in its loop. reducing the UART baud rate.Anyway, if such condition is matched, it could happen that a thread calls sdGet or sdRead when the input queue is empty or has fewer elements than the quantity we want to read.

In such case the thread which has called the function is suspended indefinitely until new data coming from the RX line fills the input queue. A function like the sdPut, sdGet, sdWrite and sdRead are thus defined as blocking functions.A blocking function blocks the execution of the calling thread until the operation is completed. Such functions are executed in a smart way: if to complete the operation the function has to wait for an asynchronous event like, for example, the reception of a new character from the USART peripheral, the function suspends the calling thread waiting for an interrupt from USART. This means, i f we are trying to read a character using sdGet when the input queue is empty, the thread is suspended and will be resumed when the input queue becomes not empty.

In this way, RTOS executes other threads while this one is suspended. Such functions are also known as synchronous functions as the calling thread remains in sync with the operationA non-blocking function launches the operation and returns to the calling thread which continues to be executed. Such operation is executed in the background, usually in hardware, launching an interrupt on operation complete.

Such IRQ usually is exposed by driver API in form of a callback. Such functions are also known as asynchronous functions.If you are used to JavaScript you can see a non-blocking function like an asynchronous script. So far the Serial Driver does not implement non-blocking function thus we will deepen this concept in a later article. Put, Get, Read and Write with a timeoutIn certain application, blocking functions are not suitable.

Let’s consider for instance a condition in which the RX line is broken. If we try to do a sdGet our thread will be stuck there indefinitely. To manage such kind of scenario the same functions are available with a timeout.

SdReadTimeout ( & SD2, buffer, 4, TIMEMS2I ( 50 ) );Note also that TIMEIMMEDIATE and TIMEINFINITE are accepted as well. In the first case, the function will return immediately; in the second it will behave like functions without a timeout. GPIO related configurationTo use Serial Driver we need to reroute GPIO connections assigning them to UART through PAL driver (take a look to if you are not familiar with). For example, in case we decide to use SD6 on STM32 Nucleo-64 F401 we need to check on STM32F401xE datasheet which pin can be rerouted on USART6.

On the Alternate Function map, we can read that PC6 and PC7 can be remapped as USART6TX and USART6RX using Alternate Function 8.Thus we can use this code to change GPIO configuration right before to use SD functions. I use to configure pins right before the first sdStart./PA2 and PA3 are the pins actually connected to the ST-Link and are properly configured.

Indeed, looking back to previous articles we already used the serial driver in default demo with no call to palSetPadMode. The Serial Driver as BaseSequentialStreamChibiOS/HAL offers many abstraction interfaces: one of these could be interesting because it allows printing formatted strings. The interface we are talking about is the BaseSequentialStream.In object-oriented programming, an Interface is just an abstract API which is a behavioural description more than a code implementation. In the case of BaseSequentialStream the specified behaviour is that this interface has 4 methods. Msgt (. get ) ( void.

Stm32 Serial Communication Interface Pdf

instance );In other words, we are stating that a driver which implement this interface shall provide 4 methods (write, read, put and get). We are not quibbling about how those methods will be implemented but we are defining related parameters and return types.In ChibiOS the main purpose of interfaces is to generalize drivers.

In such a way, it is possible to implement methods which work on many different drivers.Serial Driver implements a BaseSequentialStream interface. As we will see later Serial Driver Over USB (also known as USB CDC) implements the same interface as well. It is possible to use BaseSequentialStream functions on both Serial and Serial Over USB driver indistinctly. Printing formatted strings using chprintfChibiOS offers an optional module named streams which offers some feature included the API chprintf: this API is the ChibiOS version of printf and prints formatted strings over BaseSequentialStream like printf does on the output stream. The stream module is located at chibios182/os/hal/lib/streams and, as it is considered an optional module, it is not included by default.To use it we have to edit the makefile and adding the inclusion of the file chibios182/os/hal/lib/streams/streams.mk. This can be done at the section named “Other files (optional)” (see the last line of next code box). Using the previous code we will see the string “Hello World 1st test” with a carriage return and newline printed three times.

Interface

Note that the first line will return a warning at compile time because &SD2 is actually a pointer to SerialDriver. This warning is easy to be solved with an explicit cast. Further readings and Hands-onYou can find a collection of example and use case for the Serial Driver here:More is coming and we suggest you follow us on to be up to date. In case you are using the STM32 Nucleo-64 F401RE development board some time ago, I have crafted a demo which shows how to use the ChibiOS Shell over Serial Driver.A shell is basically a textual interface which relies on an I/O stream, in this case, offered by the serial driver.

This demo has been copied by another ChibiOS demo about USB CDC (already mentioned above).Another interesting source of information is some demos under testex which uses chprintf to print sensor data. Those demos can be very interesting if you are using an STM32F3 Discovery or an STM32F4 Discovery or an STM32 Nucleo + a MEMS x-Nucleo like the IKS01A1 or the IKS01A2. Previous and nextThis article is part of a series of articles which are meant to be tutorials. I have composed them to be read in sequence.

Here the previous and next article of this series:. This section contains a series of articles which are meant to be tutorials.