feat(ds18b20-ds2480): добавь порт F407 и асинхронную подтяжку

This commit is contained in:
2026-09-15 22:32:30 +03:00
parent df02070cc4
commit 3020de7e0c
7 changed files with 223 additions and 9 deletions

View File

@@ -0,0 +1,52 @@
# STM32F407 / STM32F4 HAL
Порт UART для `ds2480.c`. Платформа настраивает тактирование и GPIO, порт
формирует BREAK через TX GPIO, восстанавливает UART 9600 8N1 и проверяет
ошибки приёма. DMA и обработчики UART-прерываний не нужны. HAL tick должен
работать; вызывать из прерывания или при запрещённых прерываниях нельзя.
```c
ds2480 bridge;
ds2480_port io;
ds2480_stm32f4_hal platform = {&huart6, GPIOC, GPIO_PIN_6, GPIO_AF8_USART6};
/* Before this point: enable GPIOC/USART6 clocks, configure PC6/PC7 as AF8. */
if (ds2480_stm32f4_hal_bind(&platform, &io) != DS2480_OK) return;
if (ds2480_init(&bridge, &io, 20) != DS2480_OK) return;
```
В сборку добавляются `ds2480_stm32f4_hal.c`, ядро библиотеки, путь к этому
каталогу и STM32F4 HAL/CMSIS. UART выделяется только для моста. Порт принимает
по одному байту за операцию: ответ сохраняется в DR во время завершения TX,
затем читается без сброса RX. FE/NE/ORE/PE означают ошибку обмена даже при RXNE.
## Подключение в climate F407VET6
| STM32 / питание | DS2480B |
|---|---|
| PC6, USART6_TX | TXD, вывод 7 (вход моста) |
| PC7, USART6_RX | RXD, вывод 8 (выход моста) |
| Общая земля | GND, вывод 1 |
| +5 В | VDD, вывод 4; VPP, вывод 5; POL, вывод 6 |
| DQ датчиков DS18B20 | 1-W, вывод 2 |
DS2480B работает от 5 В. Проверьте согласование логических уровней по
электрическим характеристикам конкретной платы/модуля; не считайте питание
DS2480B от 3,3 В допустимым. Для внешнего питания DS18B20 подключите VDD;
при паразитном питании VDD датчика соединяется с GND. В обоих случаях общий GND.
PC6/PC7 выбраны в `climate` (AF8). UART1/2 используются Modbus, SDIO использует
4-битную шину PC8..PC12/PD2. Пины для другой платы задаются её приложением.
## Неблокирующее питание датчиков
`ds2480_power_begin` посылает команду датчика с strong pullup на последнем
слоте. Приложение возвращается в главный цикл, отсчитывает 750 мс для
преобразования либо минимум 10 мс для EEPROM, затем вызывает
`ds2480_power_end`. До завершения импульса остальной обмен возвращает BUSY.
При отмене вызывайте `power_end`, при потере синхронизации — `ds2480_init`.
Используется в `climate_control_f407vet6_f4`: `ds2480_app.c` связывает порт
из сабмодуля с существующим каталогом датчиков и диагностикой Modbus.
Источники: [STM32F407, таблица alternate functions](https://www.st.com/resource/en/datasheet/stm32f407ve.pdf),
[DS2480B, выводы и UART](https://www.analog.com/media/en/technical-documentation/data-sheets/ds2480b.pdf).

View File

@@ -0,0 +1,85 @@
#include "ds2480_stm32f4_hal.h"
#define RX_ERRORS (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)
static int prepare(void *user)
{
ds2480_stm32f4_hal *p = (ds2480_stm32f4_hal *)user;
GPIO_InitTypeDef gpio = {0};
/* Abort resets HAL states after timeouts and disables UART IRQ/DMA. */
if (HAL_UART_Abort(p->uart) != HAL_OK) return -1;
__HAL_UART_DISABLE(p->uart);
HAL_GPIO_WritePin(p->tx_port, p->tx_pin, GPIO_PIN_RESET);
gpio.Pin = p->tx_pin;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(p->tx_port, &gpio);
HAL_Delay(2);
HAL_GPIO_WritePin(p->tx_port, p->tx_pin, GPIO_PIN_SET);
HAL_Delay(2);
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Alternate = p->tx_alternate;
HAL_GPIO_Init(p->tx_port, &gpio);
p->uart->Init.BaudRate = 9600;
p->uart->Init.WordLength = UART_WORDLENGTH_8B;
p->uart->Init.StopBits = UART_STOPBITS_1;
p->uart->Init.Parity = UART_PARITY_NONE;
p->uart->Init.Mode = UART_MODE_TX_RX;
p->uart->Init.HwFlowCtl = UART_HWCONTROL_NONE;
p->uart->Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(p->uart) != HAL_OK) return -1;
/* SR then DR: discard BREAK echo/stale RX and clear FE/NE/ORE/PE. */
__HAL_UART_CLEAR_OREFLAG(p->uart);
return 0;
}
static int write_byte(void *user, const uint8_t *data, uint32_t size, uint32_t timeout)
{
ds2480_stm32f4_hal *p = (ds2480_stm32f4_hal *)user;
if (!data || size != 1 || !timeout || timeout == HAL_MAX_DELAY) return -1;
/* One reply fits in DR while HAL waits for TX complete. Never flush RX
* here: a reply may already be present when HAL_UART_Transmit returns. */
if (p->uart->Instance->SR & RX_ERRORS) return -1;
return HAL_UART_Transmit(p->uart, data, 1, timeout) == HAL_OK ? 0 : -1;
}
static int read_byte(void *user, uint8_t *data, uint32_t size, uint32_t timeout)
{
ds2480_stm32f4_hal *p = (ds2480_stm32f4_hal *)user;
uint32_t start, flags;
if (!data || size != 1 || !timeout || timeout == HAL_MAX_DELAY) return -1;
start = HAL_GetTick();
for (;;) {
flags = p->uart->Instance->SR;
/* Test errors BEFORE reading DR, including when RXNE is already set. */
if (flags & RX_ERRORS) {
__HAL_UART_CLEAR_OREFLAG(p->uart);
return -1;
}
if (flags & USART_SR_RXNE) {
*data = (uint8_t)p->uart->Instance->DR;
return 0;
}
if ((uint32_t)(HAL_GetTick() - start) >= timeout) return -1;
}
}
static void delay_ms(void *user, uint32_t ms)
{
(void)user;
HAL_Delay(ms);
}
ds2480_status ds2480_stm32f4_hal_bind(ds2480_stm32f4_hal *p, ds2480_port *port)
{
if (!p || !port || !p->uart || !p->uart->Instance || !p->tx_port ||
!p->tx_pin || (p->tx_pin & (p->tx_pin - 1U)) || p->tx_alternate > 15U)
return DS2480_ARGUMENT;
port->user = p;
port->prepare = prepare;
port->write = write_byte;
port->read = read_byte;
port->delay_ms = delay_ms;
return DS2480_OK;
}

View File

@@ -0,0 +1,32 @@
#ifndef DS2480_STM32F4_HAL_H
#define DS2480_STM32F4_HAL_H
#include "ds2480.h"
#include "stm32f4xx_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Dedicated UART initialized by the board (clock, RX/TX AF, no IRQ/DMA).
* tx_port/pin/alternate let prepare generate a real >=2 ms BREAK, including
* recovery from a lost strong-pullup response. No reset pin is required.
* GPIO clock must stay enabled. UART must not be used by any other service.
*/
typedef struct {
UART_HandleTypeDef *uart;
GPIO_TypeDef *tx_port;
uint16_t tx_pin;
uint32_t tx_alternate;
} ds2480_stm32f4_hal;
/** Populate callbacks only; call ds2480_init afterwards to reset/calibrate.
* Thread/main-loop use only, with running HAL tick and interrupts enabled.
* UART baud rate is fixed at 9600 8N1; all transfers are single-byte.
*/
ds2480_status ds2480_stm32f4_hal_bind(ds2480_stm32f4_hal *context, ds2480_port *port);
#ifdef __cplusplus
}
#endif
#endif