[G0] Fix USART IRQ handler #1189
[G0] Fix Timer and USART IRQ definition #1141
USART4 issue on Nucleo-G071RB #1188
Category Archives: Uncategorized
David Ledger’s uSupply (STM32, C++17)
EEVblog
C++ for the Embedded Programmer
uSupply Firmware Released
Offtopic
STM32 macro for port and pin read and write
Peripheral register access using C Struct’s – part 1
YouTube
C++ for the Embedded Programmer
C/C++ Interrupt Undefined Behavior
GitHub
GitLab
gitlab.com/eevblog/usupply-firmware
gitlab.com/eevblog/usupply-library
gitlab.com/eevblog/usupply-usb
Other Libraries
Digikey Electronics – Getting Started with STM32 and Nucleo
Getting Started with STM32 and Nucleo
Getting Started with STM32 and Nucleo Part 1: Introduction to STM32CubeIDE and Blinky – Digi-Key
Getting Started With STM32 and Nucleo Part 2: How to Use I2C to Read Temperature Sensor TMP102
Getting Started With STM32 and Nucleo Part 3: FreeRTOS – How To Run Multiple Threads w/ CMSIS-RTOS
Getting Started With STM32 and Nucleo Part 4: Working with ADC and DMA – Maker.io
Getting Started with STM32 and Nucleo Part 5: How to Use SPI | Digi-Key Electronics
Getting Started with STM32 and Nucleo Part 6: Timers and Timer Interrupts | Digi-Key Electronics
Programming the Adafruit Feather STM32F405 Express with STM32CubeIDE – Maker.io
STM32duino SPI
STM32duino UART / Serial
STM32duino III. – How to use Serial (USART)
STM32duino Wiki
Welcome to the stm32duino wiki!
API HardwareSerial
PlatformIO
How to use stm32duino build_opt.h in PlatformIO?
How to use stm32duino (official STM32 core) build_opt.h in PlatformIO
Include header files using command line option?
build_flags =
-DENABLE_HWSERIAL3
-DPIN_SERIAL3_RX=PB11
-DPIN_SERIAL3_TX=PB10
or
build_flags =
-include build_opt.h
Variant
ldscript.ld PeripheralPins.c PinNamesVar.h variant.cpp variant.h
#define PC5 0 #define PC4 1 #define PA10 2 [...]
HAL_ADC_MODULE_ENABLED HAL_DAC_MODULE_ENABLED HAL_I2C_MODULE_ENABLED HAL_TIM_MODULE_ENABLED HAL_UART_MODULE_ENABLED HAL_SPI_MODULE_ENABLED
WEAK const PinMap PinMap_UART_TX[] = {
[...]
{PA_5, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)},
{PB_2, USART3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF4_USART3)},
[...]
^ ^
| |
STM_MODE_INPUT GPIO_NOPULL
STM_MODE_OUTPUT_PP GPIO_PULLUP
STM_MODE_OUTPUT_OD GPIO_PULLDOWN
STM_MODE_ANALOG
STM_MODE_AF_OD => Alternate Function, Open-Drain
STM_MODE_AF_PP => Alternate Function, Push-Pull
#define STM_PIN_DATA(FUNC_OD, PUPD, AFNUM) \
STM_PIN_DEFINE(FUNC_OD, PUPD, AFNUM)
#define STM_PIN_DATA_EXT(FUNC_OD, PUPD, AFNUM, CHANNEL, INVERTED) \
STM_PIN_DEFINE_EXT(FUNC_OD, PUPD, AFNUM, CHANNEL, INVERTED)
Digital
Arduino_Core_STM32—pinMode() implementation analysis
void pinMode(uint32_t ulPin, uint32_t ulMode)
{
PinName p = digitalPinToPinName(ulPin);
if (p != NC) {
[...]
switch (ulMode) {
case INPUT: /* INPUT_FLOATING */
pin_function(p, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
break;
case INPUT_PULLUP:
pin_function(p, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, 0));
break;
case INPUT_PULLDOWN:
pin_function(p, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLDOWN, 0));
break;
[...]
}
}
}
PinMap_UART_TX
typedef struct {
PinName pin;
void *peripheral;
int function;
} PinMap;
typedef enum {
// Not connected
NC = (int)0xFFFFFFFF,
// Pin name definition
PA_0 = (PortA << 4) + 0x00,
[...]
// Specific pin name define in the variant
#include "PinNamesVar.h"
P_END = NC
} PinName;
extern GPIO_TypeDef *GPIOPort[];
typedef enum {
FirstPort = 0x00,
PortA = FirstPort,
PortB,
#if defined GPIOC_BASE
PortC,
#endif
[...]
PortEND,
LastPort = PortEND - 1
} PortName;
#define MAX_NB_PORT (LastPort-FirstPort+1)
extern const PinName digitalPin[];
extern const uint32_t analogInputPin[];
[...]
#define digitalPinToPinName(p) (((uint32_t)p < NUM_DIGITAL_PINS) ? digitalPin[p] : \
((uint32_t)p >= NUM_ANALOG_FIRST) && ((uint32_t)p <= NUM_ANALOG_LAST) ? \
digitalPin[analogInputPin[p-NUM_ANALOG_FIRST]] : NC)
STM_PIN_DATA()STM_PIN_DATA_EXT()pin_in_pinmap()bool pin_in_pinmap(PinName pin, const PinMap *map)
Looppinmap_peripheral()void *pinmap_peripheral(PinName pin, const PinMap *map)pinmap_pinout()void pinmap_pinout(PinName pin, const PinMap *map)pinmap_pin()PinName pinmap_pin(void *peripheral, const PinMap *map)
./cores/arduino/pins_arduino.h: pin_in_pinmap(digitalPinToPinName(p), PinMap_UART_TX)) ./cores/arduino/stm32/PeripheralPins.h: extern const PinMap PinMap_UART_TX[]; ./libraries/SrcWrapper/src/stm32/uart.c: #define DEBUG_UART pinmap_peripheral(digitalPinToPinName(PIN_SERIAL_TX), PinMap_UART_TX) ./libraries/SrcWrapper/src/stm32/uart.c: USART_TypeDef *uart_tx = pinmap_peripheral(obj->pin_tx, PinMap_UART_TX); ./libraries/SrcWrapper/src/stm32/uart.c: pinmap_pinout(obj->pin_tx, PinMap_UART_TX); ./libraries/SrcWrapper/src/stm32/uart.c: serial_debug.pin_tx = pinmap_pin(DEBUG_UART, PinMap_UART_TX);
Serial3
HAVE_HWSERIAL3ENABLE_HWSERIAL3SERIAL_UART_INSTANCE
[...] extern HardwareSerial Serial3; extern HardwareSerial Serial4; [...]
[...]
#if defined(HAVE_HWSERIAL3)
HardwareSerial Serial3(USART3);
void serialEvent3() __attribute__((weak));
#endif
#if defined(HAVE_HWSERIAL4)
#if defined(USART4)
HardwareSerial Serial4(USART4);
#else
HardwareSerial Serial4(UART4);
#endif
void serialEvent4() __attribute__((weak));
#endif
[...]
// Constructors ////////////////////////////////////////////////////////////////
/* ex. PA0 from #define in variant.h */
HardwareSerial::HardwareSerial(uint32_t _rx, uint32_t _tx)
{
init(digitalPinToPinName(_rx), digitalPinToPinName(_tx));
}
/* ex. PA_0 from enum PinName in PinNames.h*/
HardwareSerial::HardwareSerial(PinName _rx, PinName _tx)
{
init(_rx, _tx);
}
/* ex. peripheral Serial2 (stm32g071xx.h: USART2 => USART2_BASE => 0x40004400) */
HardwareSerial::HardwareSerial(void *peripheral, HalfDuplexMode_t halfDuplex)
{
[...]
/* if pins are defined (variant.h or compiler flag -D), use them, otherwise use from PinMap */
#if defined(Serial) && defined(PIN_SERIAL_TX)
if ((void *)this == (void *)&Serial) {
#if defined(PIN_SERIAL_RX)
setRx(PIN_SERIAL_RX);
#endif
setTx(PIN_SERIAL_TX);
} else
#endif
[...]
#if defined(PIN_SERIAL3_TX) && defined(USART3_BASE)
if (peripheral == USART3) {
#if defined(PIN_SERIAL3_RX)
setRx(PIN_SERIAL3_RX);
#endif
setTx(PIN_SERIAL3_TX);
} else
#endif
[...]
// else get the pins of the first peripheral occurence in PinMap
{
_serial.pin_rx = pinmap_pin(peripheral, PinMap_UART_RX);
_serial.pin_tx = pinmap_pin(peripheral, PinMap_UART_TX);
}
[...]
}
[...]
void HardwareSerial::init(PinName _rx, PinName _tx)
{
[...]
}
/*!< Peripheral declaration */ #define USART2 ((USART_TypeDef *) USART2_BASE) #define USART3 ((USART_TypeDef *) USART3_BASE) #define USART4 ((USART_TypeDef *) USART4_BASE) [...] #define LPUART1 ((USART_TypeDef *) LPUART1_BASE) [...] /*!< APB peripherals */ #define USART2_BASE (APBPERIPH_BASE + 0x00004400UL) #define USART3_BASE (APBPERIPH_BASE + 0x00004800UL) #define USART4_BASE (APBPERIPH_BASE + 0x00004C00UL) [...] #define LPUART1_BASE (APBPERIPH_BASE + 0x00008000UL)
[...]
#if defined(ENABLE_HWSERIAL3)
#if defined(USART3_BASE)
#define HAVE_HWSERIAL3
#endif
#endif
#if defined(ENABLE_HWSERIAL4)
#if defined(USART4_BASE) || defined(UART4_BASE)
#define HAVE_HWSERIAL4
#endif
#endif
[...]
WEAK void serialEventRun(void)
{
[...]
#if defined(HAVE_HWSERIAL3)
if (serialEvent3 && Serial3.available()) {
serialEvent3();
}
#endif
#if defined(HAVE_HWSERIAL4)
if (serialEvent4 && Serial4.available()) {
serialEvent4();
}
#endif
[...]
}
Callstack
size_t HardwareSerial::write(uint8_t c)
{
[...]
if (!serial_tx_active(&_serial)) {
uart_attach_tx_callback(&_serial, _tx_complete_irq);
}
[...]
}
int HardwareSerial::_tx_complete_irq(serial_t *obj)
{
// If interrupts are enabled, there must be more data in the output
// buffer. Send the next byte
obj->tx_tail = (obj->tx_tail + 1) % SERIAL_TX_BUFFER_SIZE;
if (obj->tx_head == obj->tx_tail) {
return -1;
}
return 0;
}
typedef struct serial_s serial_t;
struct serial_s {
/* The 1st 2 members USART_TypeDef *uart
* and UART_HandleTypeDef handle should
* be kept as the first members of this struct
* to have get_serial_obj() function work as expected
*/
USART_TypeDef *uart;
UART_HandleTypeDef handle;
void (*rx_callback)(serial_t *);
int (*tx_callback)(serial_t *);
PinName pin_tx;
PinName pin_rx;
IRQn_Type irq;
uint8_t index;
uint8_t recv;
uint8_t *rx_buff;
uint8_t *tx_buff;
uint16_t rx_tail;
uint16_t tx_head;
volatile uint16_t rx_head;
volatile uint16_t tx_tail;
};
/**
* Begin asynchronous TX transfer.
*
* @param obj : pointer to serial_t structure
* @param callback : function call at the end of transmission
* @retval none
*/
void uart_attach_tx_callback(serial_t *obj, int (*callback)(serial_t *))
{
if (obj == NULL) {
return;
}
obj->tx_callback = callback;
/* Must disable interrupt to prevent handle lock contention */
HAL_NVIC_DisableIRQ(obj->irq);
/* The following function will enable UART_IT_TXE and error interrupts */
HAL_UART_Transmit_IT(uart_handlers[obj->index], &obj->tx_buff[obj->tx_tail], 1);
/* Enable interrupt */
HAL_NVIC_SetPriority(obj->irq, UART_IRQ_PRIO, UART_IRQ_SUBPRIO);
HAL_NVIC_EnableIRQ(obj->irq);
}
/**
* @brief Tx Transfer completed callback
* @param UartHandle pointer on the uart reference
* @retval None
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
serial_t *obj = get_serial_obj(huart);
if (obj && obj->tx_callback(obj) != -1) {
if (HAL_UART_Transmit_IT(huart, &obj->tx_buff[obj->tx_tail], 1) != HAL_OK) {
return;
}
}
}
Rust Programming
Developer Survey
Rust language: Stack Overflow Developer Survey, 22. Juni 2022
Stack Overflow Developer Survey 2023
Stack Overflow Developer Survey 2022
10 Most Loved Programming Languages: Rust, TypeScript, and More, May 29, 2020
Documentation
The Rust Reference
The Rust Programming Language
Asynchronous Programming in Rust
Rust by Example
github.com/rust-lang/rust-by-example
Rust By Practice
Blog
Fearless Concurrency with Rust
Abstraction without overhead: traits in Rust
Virtual Structs Part 1: Where Rust’s enum shines
Virtual Structs Part 2: Classes strike back
Virtual Structs Part 3: Bringing Enums and Structs Together
Unsafe
- the meaning of (un)safety
- unsafe primitives provided by the language and standard library
- techniques for creating safe abstractions with those unsafe primitives
- subtyping and variance
- exception-safety (panic/unwind-safety)
- working with uninitialized memory
- type punning
- concurrency
- interoperating with other languages (FFI)
- optimization tricks
- how constructs lower to compiler/OS/hardware primitives
- how to not make the memory model people angry
- how you’re going to make the memory model people angry
Books
Fullstack Rust – Adding State to Our Web App
Syntax
unit type
Primitive Type unit
What is the purpose of the unit type in Rust?
Option and Result
Module std::option
Module std::result
Understanding Rust Option and Result enums
static
fn spawn<F>(f: F) where F: 'static, ... fn scoped<'a, F>(f: F) -> JoinGuard<'a> where F: 'a, ...
constraint
'static |
no borrowed data is permitted in the closure |
'a |
cannot escape the scope of any data borrowed by the closure |
trait
trait ClickCallback {
fn on_click(&self, x: i64, y: i64);
}
struct Button {
listeners: Vec<Box<ClickCallback>>,
...
}
trait object
- traits are types, but they are “unsized”
- they are only allowed to show up behind a pointer like
Box(which points onto the heap) or&(which can point anywhere) - Static and dynamic dispatch
&ClickCallback |
no borrowed data is permitted in the closure |
Box |
cannot escape the scope of any data borrowed by the closure |
Future trait
The Future Trait
Build an Executor
Tutorials
NICLAS ROSSBERGER
Rust-01: Why am I learning Rust?
Rust-02: The beginning
Rust-03: Improving the simple program
Medium
C++ vs Rust: an async Thread-per-Core story
How to Idiomatically Use Global Variables in Rust
Java
ExecutorService – Waiting for Threads to Finish
Guide to java.util.concurrent.Future
YouTube
Andrew Sharp
Learn Rust Part 1: numbers, variables, types and functions
Learn Rust Part 2: Structs
Learn Rust Part 3: References
Learn Rust Part 4: Mutable References
Learn Rust Part 5: Ownership
Learn Rust Part 6: Borrowing
Learn Rust Part 7: Lifetimes
Learn Rust Part 8: Lifetimes with Structs
Learn Rust Part 9: Constant Items and the Static Lifetime
Learn Rust Part 10: Methods and Associated Functions
Dave Halter
Rust für Python Developers (english) | Swiss Python Summit 2022
github.com/davidhalter/rust-for-python-developers
Ghidra Xtensa ISA
Analyzing an esp32 flash dump with ghidra
Enter /home/dragon with Ghidra
github.com/Ebiroll/ghidra-xtensa, Tensilica Xtensa processor module for Ghidra
Implementing a New CPU Architecture for Ghidra (PDF)
Quick Guide to Creating a Processor in Ghidra
C:\Users\andreas\Downloads\ghidra_9.2.2_PUBLIC>support\sleigh.bat -a Ghidra\Processors\Xtensa INFO Using log config file: jar:file:/C:/Users/andreas/Downloads/ghidra_9.2.2_PUBLIC/Ghidra/Framework/Generic/lib/Generic.jar!/generic.log4j.xml (LoggingInitialization) INFO Using log file: C:\Users\andreas\.ghidra\.ghidra_9.2.2_PUBLIC\application.log (LoggingInitialization) Compiling Ghidra\Processors\Xtensa\data\languages\xtensa.slaspec: WARN 2 NOP constructors found (SleighCompile) WARN Use -n switch to list each individually (SleighCompile) 1 languages successfully compiled
github.com/pfalcon/ida-xtensa2/, IDAPython plugin for Tensilica Xtensa (as seen in ESP8266), version 2
ithub.com/pfalcon/ida-xtensa2/blob/master/xtensa.py
General Ghidra
What’re you telling me, Ghidra? An introduction to Ghidra’s primary components




