STM32 - How To: Difference between revisions

From Embedded Workshop
Jump to navigation Jump to search
Line 99: Line 99:
  https://deepbluembedded.com/stm32-usart-uart-tutorial/
  https://deepbluembedded.com/stm32-usart-uart-tutorial/
  https://deepbluembedded.com/how-to-receive-uart-serial-data-with-stm32-dma-interrupt-polling/
  https://deepbluembedded.com/how-to-receive-uart-serial-data-with-stm32-dma-interrupt-polling/
https://community.st.com/s/article/faq-stm32-hal-driver-api-and-callbacks


===Example Source Code===
===Example Source Code===

Revision as of 13:48, 24 May 2022

Fix Eclipse's Small Icon issue

1 Find the installation folder for your STM32CubeIDE_1.9.0.
    For me, this is C:\ST\STM32CubeIDE_1.9.0\STM32CubeIDE
2 Open stm32cubeide.ini in your favorite text editor
3 Add the following bolded line of text in the -vmargs section:
 -vmargs
 -Dswt.autoScale=quarter
 -Dosgi.requiredJavaVersion=1.8
 -Dosgi.instance.area.default=

printf()

The printf() function is commonly used for "C" programming to output formatted text to a terminal.
This allows easy debugging in that variables, intermediate values, entering/leaving functions can
be monitored and status displayed with the printf() stdio library function.
The STM32 development environment provides an stdio printf() library function, but some
"connecting glue" is required to provide the desired output.
The printf() function calls _write() to perform an output function.
See the _write() function in syscalls.c.  This function was given the (weak) attribute, allowing
the function to be over-written (without causing a warning or error message.)
This default _write() function calls __io_putchar() to output one character at a time.
Redefining either function to write characters to a serial port will produce a functioning
printf().
Here's some sample code to get your printf() functional:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define HAL_SMALL_DELAY  40
// Define serial input and output functions using UART2
int __io_putchar(int ch)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_SMALL_DELAY); // infinite delay value
    return 1;
}

// Read a character from the UART with small timeout
// If HAL_UART_Receive() returns error, return EOF (-1), else return the character read
int __io_getchar(void)
{
    uint8_t byte;
    HAL_StatusTypeDef hal_status = HAL_UART_Receive(&huart2, &byte, sizeof(byte), HAL_SMALL_DELAY);
    if(HAL_OK == hal_status)
    {
        return byte;
    }
    else
        return EOF;
}
/* USER CODE END 0 */

Alternate printf() output

There are times when you want to send formatted string output to some other device - 
 some serial port, some other display, etc.  Here's a way to accomplish this:

// Print function that writes to alternate output device (this would normally be in a private header file)
void dbg_printf(const char * format, ...);

// Print the formatted string to a buffer, then send the buffer to alternate output device
// Buffer used by vsprintf() to construct string for printing
// This buffer has been enlarged to support long strings
#define PRINT_BUFFER_SIZE  256
char dbg_buf[PRINT_BUFFER_SIZE];  // Place the buffer in global space vs stack space

void dbg_printf(const char * format, ...)
{
    va_list args;
    va_start(args, format);
    uint32_t length = (uint32_t)vsnprintf(dbg_buf,PRINT_BUFFER_SIZE,format,args); // print to buffer, return length
    alternate_write_bytes(dbg_buf,length); // write the buffer to alternate output device
    va_end(args);
}

--- The following macro, placed at the top of a file, will redefine all occurrences of printf() to use dbg_printf() instead:
// For this file, define printf() to call dbg_printf
#define printf(format, ...) dbg_printf(format,##__VA_ARGS__)

I2C

We will use the upper right two pins on the Arduino header.
These are mapped as follows: D15: P8_8 (SCL) and D14: P8_9 (SDA)
By default, STM's pin selector will map I2C1 to different pins.
To change this, open the project's .ioc file, select "Pinout & Configuration" tab
Select Connectivity category, and then I2C1
If not yet enabled, enable it in the "Mode" section as "I2C"
In the "GPIO Settings" section, we want it to display PB8 for I2C_SCL and PB9 for I2C_SDA.
If it doesn't, go to the Pinout view on the right, select the PB8 pin, and then select the "I2C1_SCL" function.
  Doing this will usually define both pins.  If not, repeat the process for PB9, with function I2C_SDA.

Here's my example of several interactive I2C commands that work with the command_line code:
 cl_i2c.c
 cl_i2c.h

USART Serial

Until recently, I've been assuming the USART serial interfaces each had both transmit and receive FIFO buffers.
Well, it seems there is no buffering.  The serial shift register has just one byte of storage for each RX and TX.
This helps explain why I tend to miss characters during reception.  To solve this issue, it appears DMA is the
best solution.  I'm still looking for a USART class that will manage interrupts, DMA, and provide the user with
APIs to get any serial job done, hopefully, without requiring an OS.
Links to web pages as I search for solutions:
https://deepbluembedded.com/stm32-usart-uart-tutorial/
https://deepbluembedded.com/how-to-receive-uart-serial-data-with-stm32-dma-interrupt-polling/
https://community.st.com/s/article/faq-stm32-hal-driver-api-and-callbacks

Example Source Code

Morse Code

When only a single LED is available, a trained Boy Scout can read the short and long pulses associated with Morse Code.

morse_code.c

hexdump

Memory / register display routine

// Here's the output I want from a hexdump(address, 23) routine:
//00000000  02 03 1f 00 0d 00 00 00  31 32 33 00 00 00 00 00  |........123.....|
//00000010  00 00 00 00 00 00 00                              |.......|
void hexdump(void * address, int32_t count);
hexdump.c