good day, stm32 nucleo board I want to write informative Log messages using.
For example, I want to display the message that the program has started by using the Log("Program started") function when the program starts during this period, or I want to give the error message to the screen by using the Log("Program Failed') function when the program fails.
I using C programming langue and stm32cubeide & Nucleo f207zg board thanks in advance for your help
Thanks I solved the problem
Given that:
You know what the UART/USART peripheral is
You connected the right pins to a serial interface
You connected the other end of the interface (for instance an FTDI chip) to your computer
You can implement the logging with printf as you would do in C. Why? Because printf already takes care for you the formatting of the strings, which no one wants to reimplement, and then you redirect the printf output to the UART peripheral that handles low level serial protocol.
Following this guide the steps are easy enough:
Add #include <stdio.h> to the Includes section at the top of the main.c
#include "stdio.h"
Copy and paste the following code into the main.c file before the main() function but after the UART handle declaration
Note that you need to replace the question mark with the actual UART handle declaration, for instance huart1
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart?, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
As pointed out by Fra93, you need to implement UART/USART protocol communication and print stuff to there. I'm writing this reply, because I'm getting a feeling you have some basic experience writing desktop applications, but not embedded, so I will clarify a few points.
There is no console to print to. There are no logs. They simply don't exist. At all. Not in a desktop app development sense.
What's usually done is that one of the UARTs of the MCU is used to print characters to the ST-Link, which converts it to USB (alternatively, can be FTDI IC, CP2102 or other USB-UART bridges/converters). So then your MCU will send out characters over UART, and the USB-UART converter will display them in a COM port terminal (programs like PuTTy)
If you start with empty project and no external libraries used, you will need 3 dozen lines of code alone just to be able to print stuff. Initially, you have nothing. You have to initialize UART, configure it, then implement how it handles characters, numbers. You need to literally write a basic UART driver. And you can call printing function whatever you want. You can call it Log("hello world"), you can call it Whisper("hi there"). Because you will actually create this function. You're the boss.
Now, given you are not very familiar with all of this, it may sound like a difficult task. And it most certainly is. Writing a driver from scratch on your day 1 is not a thing you want to do (unless you're into that kind of stuff on day 1).
I would strongly advise you to get some library, such as HAL by STMicroelectronics, and familiarize yourself with what it can do - including how to print stuff with UART. Internet is flooded with articles and videos of how to use UART with HAL, it's literally one of the first things to be implemented. Specifically for the reason, that it works like logs and simplifies further development/learning.
So, in order to get "logs" working, I would do the following:
Get HAL for your specific MCU
Familiarize yourself with UART - basic stuff about what it is and how it works. No need to be an expert, just learn what it is.
Familiarize yourself with how to use UART with HAL
From the schematic of the PCB of your nucleo board, find out which UART of the MCU is connected to ST-Link (I checked the schematic: it's USART3)
Get serial port (COM) terminal program for your computer
Use HAL to initialize USART3 and print to USART3. Whatever you print there will be visible in the terminal. Yes, you will not see anything in the IDE. You need a separate program to display what you receive via USB COM port.
In the end, your print function will be the one proposed by Fra93. HAL_UART_Transmit is the most basic HAL function to send stuff via UART. If you're very picky about using "Log" as a function you call to print via UART, you can always wrap HAL_UART_Transmit into your own function called Log.
Related
I am writing a kernel module to read and write to SPI device (CC1200).
My linux device does not have native SPI, so I am trying to bit-bang the bus.
I found that linux has built-in bitbang code (linux/spi/spi_bitbang.h), but I am confused how to set it up. It needs structs as spi_device and spi_master, each requiring struct device, which requires structs as kobject and many many more, most of them I have no idea what to do with them, and how they are needed for simple bit-banging.
I have looked online for examples, but i found literally none. Not a single use of the included bitbang code, only some references that it is "easy"
I will be very thankful for any help, maybe the bitbang lib is not even the good path. Maybe I can write my own (how to do it efficiently? I have 4 cores, but it is running lots of stuff in the background)
Thanks
Because of the nature of SPI where data is clocked and read by the master there is nothing wrong with the bit banging driver for the master, as the slave should not relay on a stable clock. But of course it depends on the slave device if this will work in practice or not.
If you are using the linux kernel there is no need to implement your own bit-banging driver as there already is one spi-gpio.c
My guess how to get it up and running would be by defining what GPIO pins to use in the devicetree, then the driver would be able to act as any of the other physical layer drivers.
I had a quick glance at drivers/spi/spi-gpio.c source code, and there is even a short user guide how to directly access the GPIO pins inline without using the generic GPIO layer overhead.
/*
* Because the overhead of going through four GPIO procedure calls
* per transferred bit can make performance a problem, this code
* is set up so that you can use it in either of two ways:
*
* - The slow generic way: set up platform_data to hold the GPIO
* numbers used for MISO/MOSI/SCK, and issue procedure calls for
* each of them. This driver can handle several such busses.
*
* - The quicker inlined way: only helps with platform GPIO code
* that inlines operations for constant GPIOs. This can give
* you tight (fast!) inner loops, but each such bus needs a
* new driver. You'll define a new C file, with Makefile and
* Kconfig support; the C code can be a total of six lines:
*
* #define DRIVER_NAME "myboard_spi2"
* #define SPI_MISO_GPIO 119
* #define SPI_MOSI_GPIO 120
* #define SPI_SCK_GPIO 121
* #define SPI_N_CHIPSEL 4
* #include "spi-gpio.c"
*/
PS are you sure your platform does not have spi, all the SoC I have worked with from HiSilicon have had one. I would double check this first
EDIT: It seems they've changed the interface and you can't do this any more in modern kernels from 4.19 and later, for the same reason you can't do it with i2c.
https://forum.openwrt.org/t/i2c-kernel-4-19-i2c-gpio-custom/49213
I will leave this here for now, perhaps it will be useful. I myself am using older kernels for home automation but it's on a private network.
My original answer:
Whilst you can probably get this working by hacking your own kernel module together instead you can investigate spi-gpio-custom, simply load the module and pass the pins you want to use as parameters, you can do everything at run-time and don't need to 'compile-in' the pins you want to use. You can find this module in the OpenWrt project:
https://github.com/openwrt/openwrt/tree/openwrt-19.07/package/kernel/spi-gpio-custom/src
I would expect that to give you some kind of SPI device when initialised that you can write to from user-space. Note that I haven't used this module myself, but some time ago I've used the i2c counterpart which works in similar way.
Alternatively, you could consider introducing an Arduino to talk to your SPI bus then translate the SPI data into something your Linux device understands.
The Nano board will probably do what you need and costs peanuts if you don't want to make up your own board.
Then for the interface, you would then have a few choices: USB, UART, i2c or 1wire even a parallel interface if you have the pins. There is a 1-wire slave library on github for instance: https://github.com/smurfix/owslave.
I have a Cincoze DE-1000 industrial PC, that features a Fintek F81866A chipset. I have to manage the DIO pins to read the input from a phisical button and to set on/off a LED. I have experience in C++ programming, but not at low/hardware level.
On the documentation accompanying the PC, there is the following C code:
#define AddrPort 0x4E
#define DataPort 0x4F
//<Enter the Extended Function Mode>
WriteByte(AddrPort, 0x87)
WriteByte(AddrPort, 0x87) //Must write twice to entering Extended mode
//<Select Logic Device>
WriteByte(AddrPort, 0x07)
WriteByte(DataPort, 0x06)
//Select logic device 06h
//<Input Mode Selection> //Set GP74 to GP77 input mode
WriteByte(AddrPort, 0x80) //Select configuration register 80h
WriteByte(DataPort, 0x0X)
//Set (bit 4~7) = 0 to select GP 74~77 as Input mode.
//<input Value>
WriteByte(AddrPort, 0x82) // Select configuration register 82h
ReadByte(DataPort, Value) // Read bit 4~7(0xFx)= GP74 ~77 as High.
//<Leave the Extended Function Mode>
WriteByte(AddrPort, 0xAA)
As far as I understood, the above code should read the value of the four input PINs (so it should read 1 for each PIN), but I am really struggling to understand how it actually works. I have understood the logic (selecting an address and reading/writing an hex value to it), but I cannot figure out what kind of C instructions WriteByte() and ReadByte() are. Also, I do not understand where Value in the line ReadByte(DataPort, Value) comes from. It should read the 4 PINs all together, so it should be some kind of "byte" type and it should contain 1 in its bits 4-7, but again I cannot really grasp the meaning of that line.
I have found an answer for a similar chip, but it did not help me in understanding.
Please advice me or point me to some relevant documentation.
That chip looks like a fairly typical Super I/O controller, which is basically the hub where all of the "slow" peripherals are combined into a single chipset.
Coreboot has a wiki page that talks about how to access the super I/O.
On the PC architecture, Port I/O is accomplished using special CPU instructions, namely in and out. These are privileged instructions, which can only be used from a kernel-mode driver (Ring 0), or a userspace process which has been given I/O privileges.
Luckily, this is easy in Linux. Check out the man page for outb and friends.
You use ioperm(2) or alternatively iopl(2) to tell the kernel to allow the user space application to access the I/O ports in question. Failure to do this will cause the application to receive a segmentation fault.
So we could adapt your function into a Linux environment like this:
/* Untested: Use at your own risk! */
#include <sys/io.h>
#include <stdio.h>
#define ReadByte(port) inb(port)
#define WriteByte(port, val) outb(val, port)
int main(void)
{
if (iopl(3) < 0) {
fprintf(stderr, "Failed to get I/O privileges (are you root?)\n");
return 2;
}
/* Your code using ReadByte / WriteByte here */
}
Warning
You should be very careful when using this method to talk directly to the Super IO, because your operating system almost certainly has device drivers that are also talking to the chip.
The right way to accomplish this is to write a device driver that properly coordinates with other kernel code to avoid concurrent access to the device.
The Linux kernel provides GPIO access to at least some Super I/O devices; it should be straightforward to port one of these to your platform. See this pull request for the IT87xx chipset.
WriteByte() and ReadByte() are not part of the C language. By the looks of things, they are functions intended to be placeholders for some form of system call for the OS kernel port IO (not macros doing memory mapped IO directly as per a previous version of this answer).
The prototypes for the functions would be something along the lines of:
#include <stdint.h>
void WriteByte(unsigned port, uint8_t value);
void ReadByte(unsigned port, uint8_t *value);
Thus the Value variable would be a pointer to an 8 bit unsigned integer (unsigned char could also be used), something like:
uint8_t realValue;
uint8_t *Value = &realValue;
Of course it would make much more sense to have Value just be a uint8_t and have ReadByte(DataPort, &Value). But then the example code also doesn't have any semicolons, so was probably never anything that actually ran. Either way, this is how Value would contain the data you are looking for.
I also found some more documentation of the registers here - https://www.electronicsdatasheets.com/download/534cf560e34e2406135f469d.pdf?format=pdf
Hope this helps.
Here is the setup. Arduino #1 has a w5100 ethernet shield running a webserver accepting GET strings. It then parses out the data and sends it wirelessly to the other nodes using nRF24l10 transceivers. I'm using maniacbug's RF24 and RF24Network libraries. Also due to having the ethernet shield and the wireless I had to use a modified RF24 for the base that supports soft SPI.
Arduino #2 is just the nRF24L10.
What is working. Sending GET's to Arduino #1 works. It parses the information. It then calls the send routine and that says it's ok.
On arduino #2 I get a "Received:" printout but no message. I'm not sure what is wrong. The code is taken right from maniacbug's tx and rx example. Except I had to convert my sendString to a char to send.
I'm wondering if it's one of the following things but I'm not quite sure how to debug.
That the addition of the RF24Network library broke the softSPI. I've been very careful to remove one libray and add the other when I compile. Though if this were the case I'd never see the "Received:" would i?
It doesn't like my conversion from string to char?
Here is the code.
Base Station: http://pastebin.com/Ehy8pz4Z
Receiver : http://pastebin.com/2mz9FjsR
Here is the modified RF24+ softspi library. https://github.com/shnae/rf24_plus_softSPI if that helps.
I don't think just adding the nrf24network library breaks that but since it calls SPI.begin() it might. That's beyond my skillset..
So as it turns out you need to put network.update(); in loop.... If you only call it per request like I did it will not work. Hence the //do this regularly comment that you see for this.
I built the code from the STM32CubeF4 for the USB CDC example. I added the missing receive code for CDC_Receive_FS() in usbd_cdc_if.c.
I loaded this into my STM32F4 Discovery and it works. A character typed on Tera Term returns and is displayed on Tera Term.
I am hoping that someone here, could give me some knowledge about how this USB CDC firmware works, specifically, is this being driven by an interrupt that is generated when there is a level shift in voltage on the USB -D and +D pins, or is there an infinite while loop that was launched somewhere, and it's just polling waiting for some data to appear?
What prompted my question is that I see that one can blink the LEDs on this board by toggling the state of the GPIO pins within an infinite while loop in main.c. However, there is nothing within this while loop at all within main.c for USB. So how does this USB CDC firmware get and send a character from/to Tera Term.
I will take the 2 minutes to answer you instead of lecturing you. Receive is done through interrupts. Very, very simply, the hardware sees the voltage change on the D+/D- and flags an interrupt based on the intialization functions. The interrupt calls HAL_PCD_IRQHandler, which calls USBD_LL_DataInStage in the usbd_conf.c file. That ends up calling the function USBD_CDC_DataIn in the usbd_cdc.c file. There is your starting point, but it is not simple. To do what you want you might have to stop the output to UART and just handle it in the main loop.
This question is to broad for this forum and not an actual question for a specific problem. However, as some hints, you might
Read the USB-specs, at least some basic overview (just start at wikipedia). USB does not work by toogling a GPIO in software (see next point)
Read the STM32F4xx reference manual. This is quite comprehensive.
Read the source code of the demo. This should answer all questions.
To track execution paths, you should remember that C always starts with the main() function, so this is a good start to see what's going on. (disclaimer: I know pretty well, it starts with startup, but this might confuse a beginner even more).
If you want to work with USB, you will have to do this all anyway, so you might start with it as well right now. Yes, this will take some time; no surprise, engineers have learned all this for years before they start with larger projects.
All information is available legal and for free on the web.
And, yes, USB is most likely interrupt-driven and might also use DMA to transfer data.
Im wondering the print statements in my code are taking up processing cycles when the robot isn't connected to the com port. I am running a time sensitive process and have reason to believe the execution of these lines could be slowing my bot down.
Yes It will take processing time even if no serial monitor or other device is connected.
A good practice is to a have a #define pre-processor directive in your code indicating whether you are debugging or not.
e.g.
#define DEBUG_PHASE
#ifdef DEBUG_PHASE
printf(...);
#endif
Of course they are. The MCU still goes through the actions of parsing the format string and sending serial data even when nothing is listening.