mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-06-21 11:26:24 +03:00
Compare commits
3 Commits
d32fcbab9b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f79a43326 | |||
| 9096866812 | |||
| 21141c29b2 |
@@ -1,49 +1,280 @@
|
||||
IR allsky-camera project using 5 sensors MLX90640
|
||||
=================================================
|
||||
# IR All-Sky Camera Documentation
|
||||
|
||||
When attached, udev will create symlink /dev/ir-allsky0. This is the udev rule:
|
||||
## Project Overview
|
||||
|
||||
```
|
||||
This firmware implements an **infrared all-sky camera system** based on up to five **MLX90640**
|
||||
thermal imaging sensors (32×24 pixels each), designed for **cloud monitoring** at the Special
|
||||
Astrophysical Observatory of the Russian Academy of Sciences. The system automates sky quality
|
||||
assessment for 0.5-meter telescopes of the "Astro-M" complex.
|
||||
|
||||
ACTION=="add", ENV{USB_IDS}=="0483:5740", ATTRS{interface}=="?*", PROGRAM="/bin/bash -c \"ls /dev | grep $attr{interface} | wc -l \"", SYMLINK+="$attr{interface}%c", MODE="0666", GROUP="tty"
|
||||
The device continuously captures thermal images from multiple sensors (Zenith, East, South, West,
|
||||
North), processes environmental data from a **BMP280** pressure/humidity/temperature sensor, and
|
||||
controls **PWM heaters** to prevent dew formation on optics.
|
||||
|
||||
```
|
||||
**Repository:** [https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/MLX90640-allsky](https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/MLX90640-allsky)
|
||||
|
||||
Protocol:
|
||||
---
|
||||
|
||||
```
|
||||
|
||||
dn - draw nth image in ASCII
|
||||
gn - get nth image 'as is' - float array of 768x4 bytes
|
||||
l - list active sensors IDs
|
||||
mn - show temperature map of nth image
|
||||
tn - show nth image aquisition time
|
||||
B - reinit BME280
|
||||
E - get environment parameters (temperature etc)
|
||||
G - get MLX state
|
||||
R - reset device
|
||||
T - print current Tms
|
||||
Debugging options:
|
||||
aa - change I2C address to a (a should be non-shifted value!!!)
|
||||
c - continue MLX
|
||||
i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)
|
||||
p - pause MLX
|
||||
s - stop MLX (and start from zero @ 'c')
|
||||
C - "cartoon" mode on/off (show each new image) - USB only!!!
|
||||
Dn - dump MLX parameters for sensor number n
|
||||
Ia addr [n] - set device address for interactive work or (with n) change address of n'th sensor
|
||||
Ir reg n - read n words from 16-bit register
|
||||
Iw words - send words (hex/dec/oct/bin) to I2C
|
||||
Is - scan I2C bus
|
||||
Us - send string 's' to other interface
|
||||
|
||||
|
||||
```
|
||||
|
||||
To call this help just print '?', 'h' or 'H' in terminal.
|
||||
## Hardware Requirements
|
||||
|
||||
### Microcontroller
|
||||
- **STM32F303** series (tested on F303)
|
||||
- 72 MHz system clock (HSE) or 48 MHz (HSI)
|
||||
|
||||
### Sensors
|
||||
| Sensor | Interface | Purpose |
|
||||
|--------|-----------|---------|
|
||||
| MLX90640 (up to 5) | I²C (400 kHz) | Thermal imaging (32×24 pixels, -40..+300°C) |
|
||||
| BMP280 / BME280 | SPI | Ambient temperature, pressure, humidity |
|
||||
| NTC thermistors (4) | ADC (12-bit) | Heater feedback / backup temperature |
|
||||
|
||||
### Outputs
|
||||
- **DAC output** (PA5) – Onboard heater control (0–3.3V)
|
||||
- **PWM channels** (TIM3) – External heaters (PA6, PA7, PB0, PB1)
|
||||
- **UART1** – Main debug/auxiliary interface
|
||||
- **USB** (CDC class) – Secondary interface
|
||||
|
||||
|
||||
### Pin Assignment (STM32F303)
|
||||
|
||||
| Pin | Function | Notes |
|
||||
|-----|----------|-------|
|
||||
| PA0–PA3 | NTC1–NTC4 | ADC inputs |
|
||||
| PA4 | DAC_OUT1 | Onboard heater |
|
||||
| PA5 | ADC_IN2 | DAC feedback |
|
||||
| PA6, PA7 | PWM CH1, CH2 | TIM3_CH1, TIM3_CH2 (external heaters) |
|
||||
| PA9, PA10 | UART1 TX/RX | Controlling interface |
|
||||
| PA11, PA12 | USB DP/DM | CDC virtual COM |
|
||||
| PA13, PA14 | SWD | Programming/debug |
|
||||
| PA15 | USB DP pullup | USB pullup management for development board |
|
||||
| PB0, PB1 | PWM CH3, CH4 | TIM3_CH3, CH4 (sky-quality + T-proportional) |
|
||||
| PB3, PB4, PB5 | SPI SCK, MISO, MOSI | BMP280 interface |
|
||||
| PB6, PB7 | I²C1 SCL/SDA | MLX90640 bus |
|
||||
| PB9 | SPI CS | BMP280 chip select |
|
||||
|
||||
---
|
||||
|
||||
## Firmware Architecture
|
||||
|
||||
The firmware is **event-driven** with a **state machine** for MLX90640 data acquisition and a
|
||||
**command parser** for bidirectional communication over USB and UART.
|
||||
|
||||
### Core Modules
|
||||
|
||||
| File | Responsibility |
|
||||
|------|----------------|
|
||||
| `main.c` | Main loop, SysTick, initialization, state machine orchestration |
|
||||
| `adc.c/h` | ADC setup (DMA, median filtering), NTC reading, Vdd measurement |
|
||||
| `i2c.c/h` | I²C low-level + DMA, multi-word transfers, bus scanning |
|
||||
| `mlxproc.c/h` | MLX90640 state machine (5 sensors), parameter caching, image processing |
|
||||
| `mlx90640.c/h` | MLX90640 calibration math (from Melexis datasheet) |
|
||||
| `BMP280.c/h` | SPI-based BMP280/BME280 driver |
|
||||
| `heater.c/h` | PWM heater control, dew-point avoidance logic |
|
||||
| `commproto.cpp/h` | Command parser (USB/UART), ASCII maps, binary image export |
|
||||
| `usb_dev.c/h` | USB CDC stack (bulk endpoints, ring buffers) |
|
||||
| `usart.c/h` | UART driver with DMA and ring buffers |
|
||||
| `spi.c/h` | SPI driver for BMP280 |
|
||||
| `ringbuffer.c/h` | Circular buffers |
|
||||
| `strfunc.c/h` | Number/string conversions, hexdumps |
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
MLX90640 sensors (I²C DMA)
|
||||
↓
|
||||
mlxproc.c (state machine, 5× parameter loading)
|
||||
↓
|
||||
mlx90640.c (pixel-by-pixel temperature calculation)
|
||||
↓
|
||||
user requests via USB/UART (ASCII map, binary, temperature map)
|
||||
|
||||
BMP280 (SPI)
|
||||
↓
|
||||
Temperature, Pressure, Humidity, Dew point
|
||||
↓
|
||||
Heater logic (auto or setpoint) → PWM outputs
|
||||
|
||||
ADC (DMA + median filter)
|
||||
↓
|
||||
NTC temperatures, MCU temperature, Vdd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MLX90640 Processing
|
||||
|
||||
### State Machine (`mlxproc.c`)
|
||||
|
||||
The firmware manages up to **5 sensors** (addresses 0x10..0x14 left-shifted for I²C). The state
|
||||
machine cycles through:
|
||||
|
||||
1. **NOTINIT** – Read calibration parameters (832 words) from each sensor over I²C DMA.
|
||||
2. **WAITPARAMS** – Wait for DMA completion, calculate parameters via `get_parameters()`.
|
||||
3. **WAITSUBPAGE** – Poll `REG_STATUS` for `NEWDATA` flag, skip subpage 0.
|
||||
4. **READSUBPAGE** – Read image data (832 words) via DMA, process with `process_image()`.
|
||||
|
||||
**Key features:**
|
||||
- Automatic sensor exclusion after `MLX_MAX_ERRORS` (default 11) consecutive errors.
|
||||
- `Tlastimage[]` timestamps for each sensor (used by "cartoon mode" and timeout recovery).
|
||||
- Supports changing sensor I²C addresses at runtime (`mlx_sethwaddr()`).
|
||||
|
||||
### Temperature Calculation (`mlx90640.c`)
|
||||
|
||||
Implementation follows **Melexis MLX90640 Datasheet (Section 11)**:
|
||||
- Supply voltage compensation (`kVdd`, `vdd25`)
|
||||
- Ambient temperature (`KvPTAT`, `KtPTAT`, `vPTAT25`)
|
||||
- Gain normalization
|
||||
- Offset correction (per-pixel `offset[]`, `kta[]`, `kv[]`)
|
||||
- TGC (temperature gradient compensation)
|
||||
- Pixel sensitivity (`alpha[]`) + KsTa, KsTo, range detection (CT3, CT4)
|
||||
- **Extended temperature range** (up to 400°C) via `alphacorr[]`
|
||||
|
||||
Output: **float array of 768 temperatures** (°C) per sensor.
|
||||
|
||||
---
|
||||
|
||||
## Environmental & Heater Control
|
||||
|
||||
### BMP280/BME280 Readings
|
||||
- **Temperature** (°C)
|
||||
- **Pressure** (Pa, also converted to hPa and mmHg)
|
||||
- **Humidity** (%)
|
||||
- **Dew point** (°C) – calculated via Magnus formula.
|
||||
|
||||
Measurements are triggered every `ENV_MEAS_PERIOD` (10 seconds) in forced mode.
|
||||
|
||||
### Heater Modes
|
||||
|
||||
| Mode | Activation | Behavior |
|
||||
|------|------------|----------|
|
||||
| **Auto** (`autoheater=1`) | Humidity > 90% | Sets holding temperature = ambient + dew_over_delta (7°C) + 0.5°C (min 5°C) |
|
||||
| **Hold** (`setheater N`) | Manual command | Maintains N°C ±5°C hysteresis using PWM |
|
||||
| **Off** | Default | All heaters disabled |
|
||||
|
||||
**PWM channels:**
|
||||
- `ch0`, `ch1` – External heaters (controlled identically for symmetry)
|
||||
- `ch2` – Proportional to ambient temperature: `(T_ambient + 20) × 2` %, clamped 0–100
|
||||
- `ch3` – Proportional to `(35°C – T_ambient + T_sky) × 2.5` %, clamped 0–100
|
||||
|
||||
**Anti-overheating:** If any NTC exceeds setpoint by >5°C, PWM is reduced to `PWM_HOLD_VAL` (10%).
|
||||
|
||||
---
|
||||
|
||||
## Command Protocol
|
||||
|
||||
The device presents a **virtual COM port** (CDC) over USB and a second UART interface. Both share
|
||||
the same command set.
|
||||
|
||||
### Command Syntax
|
||||
```
|
||||
<command> [parameter] [= value]
|
||||
```
|
||||
- Commands are **case-sensitive** (lowercase).
|
||||
- Parameters are **decimal** (or hex with `0x`, binary with `b`).
|
||||
- Use `help` for full list.
|
||||
- Lines end with `\n` (newline).
|
||||
|
||||
### Core Commands
|
||||
|
||||
#### MLX90640 Image Commands
|
||||
|
||||
| Command | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `ascii n` | Draw ASCII-art thermal map (16 grayscale levels) | `ascii 0` |
|
||||
| `tempmap n` | Print numeric temperature grid (°C) | `tempmap 1` |
|
||||
| `binary n` | Dump raw float array (768×4 bytes) | `binary 2` |
|
||||
| `acqtime n` | Show last image acquisition timestamp (ms) | `acqtime 3` |
|
||||
| `cartoon` | Toggle live ASCII animation over USB | `cartoon` |
|
||||
|
||||
#### Sensor Management
|
||||
|
||||
| Command | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `listids` | List active I²C addresses of all sensors | `listids` |
|
||||
| `mlxaddr n [= addr]` | Get/set I²C address for sensor n (0–4) | `mlxaddr 2 = 0x15` |
|
||||
| `mlxdump n` | Dump all calibration parameters for sensor n | `mlxdump 0` |
|
||||
| `state` | Show MLX90640 state machine status | `state` |
|
||||
| `mlxpause` / `mlxcont` / `mlxstop` | Control acquisition | – |
|
||||
|
||||
#### Environment
|
||||
|
||||
| Command | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `environ` | Print T, P, H, dew point, Tsky | `environ` |
|
||||
| `bmereinit` | Reinitialize BMP280 | – |
|
||||
| `ntc [n]` | Get NTC temperature (°C) for channel n (0–3) | `ntc 1` |
|
||||
|
||||
#### Heater Control
|
||||
|
||||
| Command | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `autoheater [= 0/1]` | Enable/disable automatic dew avoidance | `autoheater = 1` |
|
||||
| `setheater [= N]` | Set holding temperature (°C) | `setheater = 25` |
|
||||
| `clearheater` | Disable holding, turn off heaters | – |
|
||||
| `pwm [n] [= val]` | Get/set PWM duty cycle (0–100%) for channel n | `pwm 0 = 50` |
|
||||
|
||||
#### System & Debug
|
||||
|
||||
| Command | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `adc [n]` | Get raw ADC value (0–4095) for channel n | `adc 4` |
|
||||
| `dac [= val]` | Get/set DAC output (0–4095) | `dac = 2048` |
|
||||
| `mcutemp` | Show MCU internal temperature (°C) | – |
|
||||
| `mcuvdd` | Show Vdd (V) | – |
|
||||
| `time` | Show SysTick counter (ms) | – |
|
||||
| `reset` | Software reset | – |
|
||||
| `sendstr = text` | Forward string to other interface | `sendstr = "hello"` |
|
||||
|
||||
#### Raw I²C (for debugging)
|
||||
|
||||
| Command | Description | Example |
|
||||
|---------|-------------|---------|
|
||||
| `iicscan` | Scan I²C bus, report found addresses | – |
|
||||
| `iicaddr [= addr]` | Get/set current I²C target address (non-shifted) | `iicaddr = 0x33` |
|
||||
| `iicspeed [= n]` | Set I²C speed: 0=10k,1=100k,2=400k,3=1M,4=2M | – |
|
||||
| `readreg reg [= n]` | Read n 16-bit registers | `readreg 0x8000` |
|
||||
| `writedata = v1 v2 ...` | Write 16-bit values | `writedata = 0x1234 0x5678` |
|
||||
| `hwaddr addr` | Change hardware I²C address of MLX90640 (non-shifted) | `hwaddr 0x15` |
|
||||
|
||||
### Output Formats
|
||||
|
||||
#### ASCII Thermal Map (`ascii`)
|
||||
```
|
||||
RANGE=12.345
|
||||
MIN=-5.67
|
||||
MAX=6.78
|
||||
.':;+*oxX#&%B$@
|
||||
.':;+*oxX#&%B$@
|
||||
...
|
||||
```
|
||||
Uses 16‑character grayscale ramp: space (coldest) → `@` (hottest).
|
||||
|
||||
#### Numeric Map (`tempmap`)
|
||||
```
|
||||
-2.3 1.2 3.4 ...
|
||||
5.6 7.8 9.0 ...
|
||||
...
|
||||
```
|
||||
|
||||
#### Binary Image (`binary n`)
|
||||
```
|
||||
BINARY0=<768×4 bytes raw float array>ENDIMAGE\n
|
||||
```
|
||||
Little-endian IEEE 754 `float` values. Exact size: 3072 bytes per image.
|
||||
|
||||
#### Environment Output
|
||||
```
|
||||
TEMPERATURE=22.34
|
||||
SKYTEMPERATURE=-15.67
|
||||
PRESSURE_HPA=1013.25
|
||||
PRESSURE_MM=759.98
|
||||
HUMIDITY=65.20
|
||||
TEMP_DEW=15.60
|
||||
T_MEASUREMENT=12345678
|
||||
```
|
||||
|
||||
|
||||
### Sensors location
|
||||
|
||||
| N | ID | Cardinal direction |
|
||||
|---|------|--------------------|
|
||||
@@ -53,3 +284,132 @@ To call this help just print '?', 'h' or 'H' in terminal.
|
||||
| 3 | 0x13 | West |
|
||||
| 4 | 0x14 | North |
|
||||
---------------------------------
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Building & Flashing
|
||||
|
||||
### Prerequisites
|
||||
- ARM GCC toolchain (`arm-none-eabi-gcc`)
|
||||
- Make
|
||||
- [st-flash](https://github.com/texane/stlink),
|
||||
[stm32flash](https://sourceforge.net/projects/stm32flash/) or
|
||||
[OpenOCD](https://openocd.sourceforge.io) (for flashing MCU)
|
||||
|
||||
### Build
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/eddyem/stm32samples.git
|
||||
cd stm32samples/F3:F303/MLX90640-allsky
|
||||
make
|
||||
```
|
||||
|
||||
### Configuration
|
||||
- `EBUG` flag in Makefile enables debug output (slower, but verbose).
|
||||
- `NOCAN` – define if CAN peripheral not used (increases USB buffer).
|
||||
- `BUILD_NUMBER` and `BUILD_DATE` in `version.inc` are auto-generated.
|
||||
|
||||
### Flashing
|
||||
```bash
|
||||
make flash # for flashing over st-link
|
||||
# make boot - for flashing over USART1 bootloader
|
||||
# make dfuboot - for flashing over USB-DFU
|
||||
```
|
||||
or manually (over st-link):
|
||||
```bash
|
||||
openocd -f interface/stlink.cfg -f target/stm32f3x.cfg -c "program build/firmware.elf verify reset exit"
|
||||
```
|
||||
|
||||
### udev Rule (Linux)
|
||||
Create `/etc/udev/rules.d/99-USBiinterface.rules`:
|
||||
```
|
||||
ACTION=="add", ENV{USB_IDS}=="0483:5740", ATTRS{interface}=="?*", PROGRAM="/bin/bash -c \"ls /dev | grep $attr{interface} | wc -l \"", SYMLINK+="$attr{interface}%c", MODE="0666", GROUP="tty"
|
||||
```
|
||||
After replug, device appears as `/dev/ir-allsky0`.
|
||||
|
||||
---
|
||||
|
||||
## Calibration & Tuning
|
||||
|
||||
### NTC Thermistors
|
||||
The firmware includes a **lookup table (LUT)** for NTC with B=3950, R25=1000Ω, covering -10..+59°C.
|
||||
If a sensor reads `<5 ADC` → short circuit; `>4090 ADC` → open circuit.
|
||||
|
||||
To calibrate your NTCs, modify `Rlut[]` in `adc.c`.
|
||||
|
||||
### MLX90640
|
||||
Calibration data is **per-sensor** and stored in EEPROM. The firmware reads it automatically on
|
||||
startup.
|
||||
No user calibration is required – the factory data is used.
|
||||
|
||||
### Vdd Measurement
|
||||
Internal Vrefint (1.2V typical) and factory calibration value `*VREFINT_CAL_ADDR` are used:
|
||||
```
|
||||
Vdd = (VREFINT_CAL * 3.3) / ADC_VREF
|
||||
```
|
||||
|
||||
### MCU Temperature
|
||||
Internal sensor (ADC1_IN16) uses factory calibration `TEMP30_CAL_ADDR` and `TEMP110_CAL_ADDR`.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No USB device detected
|
||||
- Check `USBPU_ON()` in `main.c` – some boards need pull-up control, others constant.
|
||||
- Verify PA11/PA12 are configured as AF14.
|
||||
- Try different USB cable / port.
|
||||
|
||||
### I²C communication errors
|
||||
- Reduce speed: `iicspeed = 1` (100 kHz).
|
||||
- Check pull-up resistors (2.2k–10kΩ on SCL/SDA).
|
||||
- Use `iicscan` to verify sensor addresses.
|
||||
|
||||
### BMP280 not responding
|
||||
- Check SPI wiring (PB3–PB5, PB9 CS).
|
||||
- Try software reset: `bmereinit`.
|
||||
- Verify chip ID: should be 0x58 (BMP280) or 0x60 (BME280).
|
||||
|
||||
### Heater not working
|
||||
- Check `autoheater` status: `autoheater`.
|
||||
- Verify NTC readings: `ntc`.
|
||||
- For manual mode: `setheater = 25`, observe `pwm`.
|
||||
|
||||
### Cartoon mode stops updating
|
||||
- Cartoon mode works **only over USB**, not UART.
|
||||
- If no new images, check `state` – may be paused or in error.
|
||||
|
||||
### Watchdog resets
|
||||
- IWDG period is 2 seconds. Long operations (e.g., full calibration dump) may trigger reset.
|
||||
- Disable in debug builds (remove `IWDG_REFRESH` calls or undefine `EBUG`).
|
||||
|
||||
---
|
||||
|
||||
## Performance & Limitations
|
||||
|
||||
| Parameter | Value |
|
||||
|-----------|-------|
|
||||
| Image update rate (5 sensors) | ~1–2 Hz (depends on I²C speed) |
|
||||
| RAM usage | ~39 kB (image buffers + parameters) |
|
||||
| Flash usage | ~26 kB |
|
||||
| Maximum sensors | 5 (limited by I²C address space 0x10–0x14) |
|
||||
| Temperature range | -40..+300°C (MLX90640) |
|
||||
| Accuracy | ±1°C (typical after calibration) |
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
All source files are licensed under **GNU General Public License v3.0** unless stated otherwise.
|
||||
The BMP280 driver includes MIT-licensed code from sheinz (2016).
|
||||
|
||||
---
|
||||
|
||||
## Credits & References
|
||||
|
||||
- **Author:** Edward V. Emelianov <edward.emelianoff@gmail.com>
|
||||
- **MLX90640 Datasheet:** Melexis (Document REV 10)
|
||||
- **BMP280 Datasheet:** Bosch Sensortec
|
||||
- **STM32F303 Reference Manual:** STMicroelectronics (RM0316)
|
||||
|
||||
For questions, bug reports, or contributions, please use the GitHub issue tracker.
|
||||
|
||||
@@ -46,19 +46,20 @@ TRUE_INLINE void calADC(ADC_TypeDef *chnl){
|
||||
chnl->CR = ADC_CR_ADVREGEN_0;
|
||||
// wait for 10us
|
||||
uint16_t ctr = 0;
|
||||
while(++ctr < 1000){nop();}
|
||||
while(++ctr < 1000){IWDG->KR = IWDG_REFRESH;}
|
||||
// ADCALDIF=0 (single channels)
|
||||
if((chnl->CR & ADC_CR_ADEN)){
|
||||
chnl->CR |= ADC_CR_ADSTP;
|
||||
chnl->CR |= ADC_CR_ADDIS;
|
||||
}
|
||||
chnl->CR |= ADC_CR_ADCAL;
|
||||
while((chnl->CR & ADC_CR_ADCAL) != 0 && ++ctr < 0xfff0){};
|
||||
while((chnl->CR & ADC_CR_ADCAL) != 0 && ++ctr < 0xfff0){IWDG->KR = IWDG_REFRESH;};
|
||||
chnl->CR = ADC_CR_ADVREGEN_0;
|
||||
// enable ADC
|
||||
ctr = 0;
|
||||
do{
|
||||
chnl->CR |= ADC_CR_ADEN;
|
||||
chnl->CR |= ADC_CR_ADEN;
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
}while((chnl->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0);
|
||||
}
|
||||
|
||||
@@ -80,14 +81,16 @@ void adc_setup(){
|
||||
ADC12_COMMON->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN | ADC_CCR_CKMODE; // enable Tsens and Vref, HCLK/4
|
||||
calADC(ADC1);
|
||||
calADC(ADC2);
|
||||
// ADC1: channels 1,2,3,4,16,18
|
||||
ADC1->SMPR1 = ADC_SMPR1_SMP0 | ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3;
|
||||
ADC1->SMPR2 = ADC_SMPR2_SMP15 | ADC_SMPR2_SMP17;
|
||||
// ADC1: channels 1,2,3,4,16,18; 601.5 clock cycles
|
||||
//ADC1->SMPR1 = ADC_SMPR1_SMP0 | ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3;
|
||||
ADC1->SMPR1 = ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3 | ADC_SMPR1_SMP4;
|
||||
//ADC1->SMPR2 = ADC_SMPR2_SMP15 | ADC_SMPR2_SMP17;
|
||||
ADC1->SMPR2 = ADC_SMPR2_SMP16 | ADC_SMPR2_SMP18;
|
||||
// 6 conversions in group: 1->2->3->4->16->18
|
||||
ADC1->SQR1 = (1<<6) | (2<<12) | (3<<18) | (4<<24) | (NUMBER_OF_ADC1_CHANNELS-1);
|
||||
ADC1->SQR2 = (16<<0) | (18<<6);
|
||||
// ADC2: channel 2
|
||||
ADC2->SMPR1 = ADC_SMPR1_SMP1;
|
||||
ADC2->SMPR1 = ADC_SMPR1_SMP2;
|
||||
ADC2->SQR1 = (2<<6) | (NUMBER_OF_ADC2_CHANNELS-1);
|
||||
// configure DMA for ADC
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
|
||||
@@ -122,12 +125,12 @@ void adc_setup(){
|
||||
*/
|
||||
uint16_t getADCval(uint8_t nch){
|
||||
if(nch >= NUMBER_OF_ADC_CHANNELS) return 0;
|
||||
register uint16_t temp;
|
||||
uint16_t temp;
|
||||
#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
|
||||
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
|
||||
uint16_t p[9];
|
||||
int adval = (nch >= NUMBER_OF_ADC1_CHANNELS) ? NUMBER_OF_ADC2_CHANNELS : NUMBER_OF_ADC1_CHANNELS;
|
||||
int addr = (nch >= NUMBER_OF_ADC1_CHANNELS) ? nch - NUMBER_OF_ADC2_CHANNELS + ADC2START: nch;
|
||||
int addr = (nch >= NUMBER_OF_ADC1_CHANNELS) ? nch - NUMBER_OF_ADC1_CHANNELS + ADC2START: nch;
|
||||
for(int i = 0; i < 9; ++i, addr += adval) // first we should prepare array for optmed
|
||||
p[i] = ADC_array[addr];
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
|
||||
Binary file not shown.
@@ -595,9 +595,8 @@ static constexpr uint32_t hash(const char* str, uint32_t h = 0) {
|
||||
return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h;
|
||||
}
|
||||
|
||||
|
||||
const char *parse_cmd(int (*sendfun)(const char*), char *buf) {
|
||||
if(!buf || !*buf || !sendfun) return NULL;
|
||||
// set temporary sender
|
||||
void set_sender(sendfun_t sendfun){
|
||||
SEND = sendfun;
|
||||
if(sendfun == usb_sender){
|
||||
putb = usb_putb;
|
||||
@@ -606,6 +605,15 @@ const char *parse_cmd(int (*sendfun)(const char*), char *buf) {
|
||||
putb = usart_putb;
|
||||
sendbin = usart_sendbin;
|
||||
}
|
||||
}
|
||||
|
||||
sendfun_t get_sender(){
|
||||
return SEND;
|
||||
}
|
||||
|
||||
const char *parse_cmd(sendfun_t sendfun, char *buf) {
|
||||
if(!buf || !*buf || !sendfun) return NULL;
|
||||
set_sender(sendfun);
|
||||
char command[CMD_MAXLEN+1];
|
||||
int i = 0;
|
||||
while(*buf > '@' && i < CMD_MAXLEN) command[i++] = *buf++;
|
||||
|
||||
@@ -49,10 +49,14 @@ typedef enum{
|
||||
// maximal available parameter number (for 16-bit registers is 0xffff
|
||||
#define MAXPARNO 0xffff
|
||||
|
||||
typedef int (*sendfun_t)(const char*);
|
||||
|
||||
extern const char *EQ;
|
||||
const char *parse_cmd(int (*sendfun)(const char*), char *buf);
|
||||
const char *parse_cmd(sendfun_t sendfun, char *buf);
|
||||
void set_senders(int (*usbs)(const char*), int (*usbb)(uint8_t), int (*usbbin)(const uint8_t*, int),
|
||||
int (*usarts)(const char*), int (*usartb)(uint8_t), int (*usartbin)(const uint8_t*, int));
|
||||
void set_sender(sendfun_t sendfun);
|
||||
sendfun_t get_sender();
|
||||
|
||||
extern const char *const Timage;
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#ifdef EBUG
|
||||
#include "strfunc.h"
|
||||
#include "usb_dev.h"
|
||||
#endif
|
||||
#include "usb_dev.h"
|
||||
|
||||
// turn on/off automatic cover heater in case of high humidity
|
||||
uint8_t AutoHeater = 0;
|
||||
|
||||
@@ -116,6 +116,8 @@ void i2c_setup(i2c_speed_t speed){
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
NVIC_EnableIRQ(DMA1_Channel6_IRQn);
|
||||
NVIC_EnableIRQ(DMA1_Channel7_IRQn);
|
||||
NVIC_SetPriority(DMA1_Channel6_IRQn, 3);
|
||||
NVIC_SetPriority(DMA1_Channel7_IRQn, 3);
|
||||
I2Cbusy = 0;
|
||||
i2c_curspeed = speed;
|
||||
}
|
||||
@@ -153,7 +155,7 @@ static uint8_t waitISRbit(uint32_t bit, uint8_t isset){
|
||||
}
|
||||
return 1;
|
||||
goterr:
|
||||
I2C1->ICR = 0xff;
|
||||
I2C1->ICR = 0x3f38; // clear all errors
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 19.0.1, 2026-05-20T22:25:52. -->
|
||||
<!-- Written by QtCreator 19.0.2, 2026-06-01T09:34:42. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{7bd84e39-ca37-46d3-be9d-99ebea85bc0d}</value>
|
||||
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
@@ -32,7 +32,7 @@
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">true</value>
|
||||
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
@@ -40,9 +40,9 @@
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
@@ -51,10 +51,10 @@
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">false</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||
</valuemap>
|
||||
@@ -79,8 +79,8 @@
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">2</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">false</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
@@ -96,12 +96,12 @@
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Big/Data/00__Electronics/STM32/F303-nolib/blink</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Yandex.Disk/Projects/stm32samples/F3:F303/MLX90640-allsky</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||
@@ -153,8 +153,10 @@
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
||||
<value type="QList<int>" key="Analyzer.Valgrind.VisibleErrorKinds"></value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
@@ -167,6 +169,7 @@
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
@@ -187,8 +190,10 @@
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
||||
<value type="QList<int>" key="Analyzer.Valgrind.VisibleErrorKinds"></value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
@@ -201,6 +206,7 @@
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
BMP280.c
|
||||
BMP280.h
|
||||
Readme.md
|
||||
adc.c
|
||||
adc.h
|
||||
commproto.cpp
|
||||
|
||||
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 382 B |
@@ -83,16 +83,19 @@ int main(void){
|
||||
usart_sendstr(foundid); usart_sendstr(straddr); usart_putbyte('\n');
|
||||
}
|
||||
}
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
mlx_process();
|
||||
if(cartoon) for(int i = 0; i < N_SENSORS; ++i){ // USB-only
|
||||
if(cartoon && CDCready) for(int i = 0; i < N_SENSORS; ++i){ // USB-only
|
||||
uint32_t Tnow = mlx_lastimT(i);
|
||||
if(Tnow != Tlastima[i]){
|
||||
fp_t *im = mlx_getimage(i);
|
||||
if(im){
|
||||
//U(Sensno); UN(i2str(i));
|
||||
sendfun_t cursender = get_sender();
|
||||
set_sender(USB_sendstr);
|
||||
U(Timage); USB_putbyte('0'+i); USB_putbyte('='); UN(u2str(Tnow));
|
||||
drawIma(im);
|
||||
Tlastima[i] = Tnow;
|
||||
set_sender(cursender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ static void occacc(int8_t *arr, int l, const uint16_t *regstart){
|
||||
int n = l >> 2; // divide by 4
|
||||
int8_t *p = arr;
|
||||
for(int i = 0; i < n; ++i){
|
||||
register uint16_t val = *regstart++;
|
||||
uint16_t val = *regstart++;
|
||||
*p++ = (val & 0x000F) >> 0;
|
||||
*p++ = (val & 0x00F0) >> 4;
|
||||
*p++ = (val & 0x0F00) >> 8;
|
||||
@@ -123,7 +123,7 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){
|
||||
int idx = (row&1)<<1;
|
||||
for(int col = 0; col < MLX_W; ++col){
|
||||
// offset
|
||||
register uint16_t rv = *pu16++;
|
||||
uint16_t rv = *pu16++;
|
||||
i16 = (rv & 0xFC00) >> 10;
|
||||
if(i16 > 0x1F) i16 -= 0x40;
|
||||
*offset++ = (fp_t)offavg + (fp_t)occRow[row]*occRowScale + (fp_t)occColumn[col]*occColumnScale + (fp_t)i16*occRemScale;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
// hex line number for hexdumps
|
||||
void u16s(uint16_t n, char *buf){
|
||||
for(int j = 3; j > -1; --j){
|
||||
register uint8_t q = n & 0xf;
|
||||
uint8_t q = n & 0xf;
|
||||
n >>= 4;
|
||||
if(q < 10) buf[j] = q + '0';
|
||||
else buf[j] = q - 10 + 'a';
|
||||
@@ -40,7 +40,7 @@ void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len){
|
||||
char buf[64] = "0000 ", *bptr = &buf[6];
|
||||
for(uint16_t l = 0; l < len; ++l, ++arr){
|
||||
for(int16_t j = 1; j > -1; --j){
|
||||
register uint8_t half = (*arr >> (4*j)) & 0x0f;
|
||||
uint8_t half = (*arr >> (4*j)) & 0x0f;
|
||||
if(half < 10) *bptr++ = half + '0';
|
||||
else *bptr++ = half - 10 + 'a';
|
||||
}
|
||||
@@ -66,7 +66,7 @@ void hexdump16(int (*sendfun)(const char *s), uint16_t *arr, uint16_t len){
|
||||
//uint16_t val = *arr;
|
||||
u16s(*arr, bptr);
|
||||
/*for(int16_t j = 3; j > -1; --j){
|
||||
register uint8_t q = val & 0xf;
|
||||
uint8_t q = val & 0xf;
|
||||
val >>= 4;
|
||||
if(q < 10) bptr[j] = q + '0';
|
||||
else bptr[j] = q - 10 + 'a';
|
||||
@@ -297,8 +297,8 @@ const char *getint(const char *txt, int32_t *I){
|
||||
int32_t sign = 1;
|
||||
uint32_t U;
|
||||
if(*s == '-'){
|
||||
sign = -1;
|
||||
++s;
|
||||
sign = -1;
|
||||
++s;
|
||||
}
|
||||
const char *nxt = getnum(s, &U);
|
||||
if(nxt == s) return txt;
|
||||
@@ -341,7 +341,7 @@ char *float2str(float x, uint8_t prec){
|
||||
uint8_t m = 0;
|
||||
if(pow < 0){pow = -pow; m = 1;}
|
||||
while(pow){
|
||||
register int p10 = pow/10;
|
||||
int p10 = pow/10;
|
||||
*s-- = '0' + (pow - 10*p10);
|
||||
pow = p10;
|
||||
}
|
||||
@@ -355,7 +355,7 @@ char *float2str(float x, uint8_t prec){
|
||||
uint32_t decimals = (uint32_t)((x-units+rounds[prec])*pwr10[prec]);
|
||||
// print decimals
|
||||
while(prec){
|
||||
register int d10 = decimals / 10;
|
||||
int d10 = decimals / 10;
|
||||
*s-- = '0' + (decimals - 10*d10);
|
||||
decimals = d10;
|
||||
--prec;
|
||||
@@ -368,7 +368,7 @@ char *float2str(float x, uint8_t prec){
|
||||
// print main units
|
||||
if(units == 0) *s-- = '0';
|
||||
else while(units){
|
||||
register uint32_t u10 = units / 10;
|
||||
uint32_t u10 = units / 10;
|
||||
*s-- = '0' + (units - 10*u10);
|
||||
units = u10;
|
||||
}
|
||||
|
||||
@@ -149,8 +149,9 @@ int usart_setup(uint32_t speed){
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
|
||||
NVIC_EnableIRQ(DMA1_Channel5_IRQn);
|
||||
NVIC_SetPriority(DMA1_Channel5_IRQn, 0);
|
||||
NVIC_SetPriority(USART1_IRQn, 4); // set character match priority lower
|
||||
NVIC_SetPriority(DMA1_Channel4_IRQn, 4);
|
||||
NVIC_SetPriority(DMA1_Channel5_IRQn, 4);
|
||||
NVIC_SetPriority(USART1_IRQn, 5); // set character match priority lower
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ void usart_stop(){
|
||||
void usart1_exti25_isr(){
|
||||
DMA1_Channel5->CCR &= ~DMA_CCR_EN; // temporaly disable DMA
|
||||
USART1->ICR = USART_ICR_CMCF; // clear character match flag
|
||||
register int l = UARTBUFSZI - DMA1_Channel5->CNDTR - 1; // substitute '\n' with '\0', omit empty strings!
|
||||
int l = UARTBUFSZI - DMA1_Channel5->CNDTR - 1; // substitute '\n' with '\0', omit empty strings!
|
||||
if(l > 0){
|
||||
if(recvdatalen){ // user didn't read old data - mark as buffer overflow
|
||||
bufovr = 1;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#define BUILD_NUMBER "65"
|
||||
#define BUILD_DATE "2026-05-06"
|
||||
#define BUILD_NUMBER "68"
|
||||
#define BUILD_DATE "2026-06-01"
|
||||
|
||||
106
Readme.md
106
Readme.md
@@ -1,10 +1,104 @@
|
||||
Some working code examples for STM32
|
||||
====================================
|
||||
# Repository Overview
|
||||
|
||||
Built without any third-party library.
|
||||
The `stm32samples` repository is a collection of low-level, bare-metal code examples and complete
|
||||
projects for various STM32 microcontroller series (F0, F1, F3, F4, G0). It uses CMSIS header files
|
||||
from `modm-io/cmsis-header-stm32` for register definitions.
|
||||
|
||||
Supported F0, F1, F3, F4 and G0 series.
|
||||
## Project Structure by MCU Series
|
||||
|
||||
### STM32F0 (F030, F042, F072)
|
||||
- **3steppersLB** – Controls 3 stepper motors with encoders via USB/CAN bus
|
||||
- **blink** – Simple LED toggling
|
||||
- **CANbus4BTA** – CAN replacement for PEP-CAN
|
||||
- **CANBUS_SSI** – Works with BTA SSI azimuth encoder
|
||||
- **Chiller** – Basic chiller temperature controller
|
||||
- **F0_testbrd** – Tests STM32F0x2 on custom board
|
||||
- **htu21d_nucleo** – Reads HTU-21D sensor on Nucleo-F042K
|
||||
- **morze** – Echoes USART1 data as Morse code on TIM3CH1 (PA6)
|
||||
- **NUCLEO_SPI** – SSI over SPI on Nucleo-F042K
|
||||
- **PL2303_ringbuffer** – USB CDC ACM with ring buffers
|
||||
- **QuadEncoder** – Quadrature encoder via timer
|
||||
- **Servo** – Controls SG-90 style servos
|
||||
- **Socket_fans** – Manages multiple fans
|
||||
- **TM1637** – Drives 7‑segment displays
|
||||
- **tsys01_nucleo** – Reads two TSYS01 sensors
|
||||
- **uart_blink & uart_blink_dma** – USART echo with DMA
|
||||
- **usbcan_relay** – Relay board over CAN bus
|
||||
- **usbcan_ringbuffer** – USB‑CAN adapter with ring buffers
|
||||
- **USBHID** – USB HID keyboard + mouse
|
||||
|
||||
CMSIS-headers:
|
||||
https://github.com/modm-io/cmsis-header-stm32
|
||||
### STM32F1 (F103)
|
||||
- **BMP180, BMP280** – I²C temperature/pressure sensors
|
||||
- **Canon_managing_device** – Controls Canon lenses
|
||||
- **canUART** – UART‑CAN bridge
|
||||
- **DHT22_DHT11** – Humidity sensors using timer+DMA
|
||||
- **DS18** – DS18x20 temperature sensors
|
||||
- **F1_testbrd** – Test board for LQFP48 packages
|
||||
- **I2Cscan** – I²C scanner with register R/W
|
||||
- **LED_Screen** – Drives 32×16 LED matrices (P10)
|
||||
- **MAX7219_screen** – Controls 8×8 LED matrices
|
||||
- **RGB_LED_Screen** – HUB75E RGB panel with 8.8.4 color
|
||||
- **SevenCDCs** – Seven USB‑CDC ACM instances on one MCU (joke project)
|
||||
- **shutter** – Bistable shutter via USB/external signal
|
||||
- **Tetris** – Tetris on HUB75E panel
|
||||
- **USB_HID** – USB HID mouse+keyboard
|
||||
- **ws2815** – Rainbow effect on WS2815 strips
|
||||
|
||||
### STM32F3 (F303)
|
||||
- **ADC** – Works with ADC peripheral
|
||||
- **blink** – Toggles LEDs on PB0/PB1
|
||||
- **CANusb** – USB‑CAN adapter
|
||||
- **floatPrintf** – Converts floats to strings
|
||||
- **Multistepper** – Controls up to 64 multiplexed steppers
|
||||
- **NitrogenFlooding** – Automatic nitrogen flooding
|
||||
- **PL2303** – PL2303 emulator (old)
|
||||
- **Seven_CDCs** – Seven USB CDC ACM interfaces
|
||||
- **usart1fullDMA** – USART1 Rx/Tx DMA with match detection
|
||||
- **USB_template_CDC** – USB‑CDC template
|
||||
|
||||
### STM32F4 (F401)
|
||||
- **blink** – Simple LED toggling
|
||||
|
||||
### STM32G0 (G070, G0B1)
|
||||
- **blink** – Basic LED blink
|
||||
- **RTC** – Real‑time clock
|
||||
- **flash** – Flash memory operations
|
||||
- **g0b1** – USB‑CDC working on G0B1
|
||||
- **i2c** – I²C operations
|
||||
- **usart** – USART communication
|
||||
|
||||
### Other Directories
|
||||
- **deprecated** – Archive of older, no‑longer‑maintained code
|
||||
- **snippets** – Small reusable code fragments
|
||||
- **testboard** – KiCad 8 design files
|
||||
|
||||
## Development Environment
|
||||
|
||||
- **Toolchain**: arm-none-eabi‑gcc with `-flto` optimisations
|
||||
- **Build**: Structured Makefiles per series
|
||||
- **Debug**: OpenOCD configuration files provided
|
||||
- **Libraries**: No third‑party libraries; only CMSIS‑SVD headers
|
||||
|
||||
## Project Maturity
|
||||
|
||||
- **Alpha**: USB template for F303, MLX90640 all‑sky camera
|
||||
- **Stable**: LED blink, UART echo, sensor interfaces, USB‑CDC
|
||||
- **Draft**: CANbus4BTA, MLX90640multi
|
||||
- **Deprecated**: Older code in `deprecated/`
|
||||
|
||||
## Summary
|
||||
|
||||
This repository is a valuable resource for learning low‑level STM32 programming without vendor
|
||||
libraries. It covers practical applications:
|
||||
- **Industrial control**: Stepper motors, CAN bus, relay boards
|
||||
- **Sensor interfacing**: Temperature, pressure, humidity, encoders
|
||||
- **Human‑machine interfaces**: LED matrices, 7‑segment displays, USB HID
|
||||
- **Communication**: UART, SPI, I²C, USB‑CDC, USB‑HID, CAN
|
||||
- **Prototyping**: Test boards for F0, F1, F3, G0
|
||||
|
||||
For the latest updates, check the repository on GitHub.
|
||||
|
||||
## License
|
||||
|
||||
This repository is provided under the GNU General Public License v3 or later.
|
||||
Full text of the GPLv3 is available at <https://www.gnu.org/licenses/gpl-3.0.html>.
|
||||
|
||||
Reference in New Issue
Block a user