Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cbffd3674 | ||
|
|
0692b21d9b | ||
|
|
ce169b9cb9 | ||
|
|
60d4d4d257 | ||
|
|
0db33b3837 | ||
|
|
41a50a1d1e | ||
|
|
cdd8fc3f71 | ||
|
|
f695867969 | ||
|
|
132055b177 | ||
|
|
c7aedab9cd | ||
|
|
d65a758c31 | ||
|
|
97a7bfeb07 | ||
|
|
b36ffe294c | ||
|
|
8552d8ee90 |
-48
@@ -1,48 +0,0 @@
|
||||
# ---> uVision
|
||||
# git ignore file for Keil µVision Project
|
||||
|
||||
# µVision 5 and µVision 4 Project screen layout file
|
||||
*.uvguix.*
|
||||
*.uvgui.*
|
||||
|
||||
# Listing Files
|
||||
*.i
|
||||
*.lst
|
||||
*.m51
|
||||
*.m66
|
||||
*.map
|
||||
|
||||
# Object Files
|
||||
*.axf
|
||||
*.b[0-2][0-9]
|
||||
*.b3[0-1]
|
||||
*.bak
|
||||
*.build_log.htm
|
||||
*.crf
|
||||
*.d
|
||||
*.dep
|
||||
*.elf
|
||||
*.htm
|
||||
*.iex
|
||||
*.lnp
|
||||
*.o
|
||||
*.obj
|
||||
*.sbr
|
||||
|
||||
# Firmware Files
|
||||
*.bin
|
||||
*.h86
|
||||
*.hex
|
||||
|
||||
# Build Files
|
||||
.bat
|
||||
|
||||
# Debugger Files
|
||||
.ini
|
||||
|
||||
# JLink Files
|
||||
JLinkLog.txt
|
||||
|
||||
# Other Files
|
||||
|
||||
/john103C6T6/MDK-ARM/john103C6T6.uvoptx
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
[submodule "external_flash_eeprom"]
|
||||
path = external_flash_eeprom
|
||||
url = https://git.arktika.cyou/set506/external_flash_eeprom.git
|
||||
[submodule "labview_proj"]
|
||||
path = labview_proj
|
||||
url = https://git.arktika.cyou/Andrey/labview_proj.git
|
||||
branch = master
|
||||
[submodule "core/STM32_Modbus"]
|
||||
path = core/STM32_Modbus
|
||||
url = https://git.arktika.cyou/set506/STM32_Modbus.git
|
||||
branch = release
|
||||
Submodule core/STM32_Modbus deleted from cba13802b1
Submodule external_flash_eeprom deleted from 6ec779c11d
@@ -1,127 +0,0 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.c
|
||||
* @brief This file provides code for the configuration
|
||||
* of the RTC instances.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "rtc.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* RTC init function */
|
||||
void MX_RTC_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN RTC_Init 0 */
|
||||
|
||||
/* USER CODE END RTC_Init 0 */
|
||||
|
||||
RTC_TimeTypeDef sTime = {0};
|
||||
RTC_DateTypeDef DateToUpdate = {0};
|
||||
|
||||
/* USER CODE BEGIN RTC_Init 1 */
|
||||
|
||||
/* USER CODE END RTC_Init 1 */
|
||||
|
||||
/** Initialize RTC Only
|
||||
*/
|
||||
hrtc.Instance = RTC;
|
||||
hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
|
||||
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
|
||||
if (HAL_RTC_Init(&hrtc) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Check_RTC_BKUP */
|
||||
|
||||
/* USER CODE END Check_RTC_BKUP */
|
||||
|
||||
/** Initialize RTC and set the Time and Date
|
||||
*/
|
||||
sTime.Hours = 0x0;
|
||||
sTime.Minutes = 0x0;
|
||||
sTime.Seconds = 0x0;
|
||||
|
||||
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
DateToUpdate.Month = RTC_MONTH_JANUARY;
|
||||
DateToUpdate.Date = 0x1;
|
||||
DateToUpdate.Year = 0x0;
|
||||
|
||||
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN RTC_Init 2 */
|
||||
|
||||
/* USER CODE END RTC_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 0 */
|
||||
HAL_PWR_EnableBkUpAccess();
|
||||
/* Enable BKP CLK enable for backup registers */
|
||||
__HAL_RCC_BKP_CLK_ENABLE();
|
||||
/* RTC clock enable */
|
||||
__HAL_RCC_RTC_ENABLE();
|
||||
|
||||
/* RTC interrupt Init */
|
||||
HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(RTC_IRQn);
|
||||
/* USER CODE BEGIN RTC_MspInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_RTC_DISABLE();
|
||||
|
||||
/* RTC interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(RTC_IRQn);
|
||||
/* USER CODE BEGIN RTC_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
@@ -0,0 +1,78 @@
|
||||
# Пины МК
|
||||
|
||||
Документ составлен по прошивке:
|
||||
|
||||
- `..\new rev\john103C8T6\john103C6T6.ioc`
|
||||
- `..\new rev\john103C8T6\Core\Inc\main.h`
|
||||
- `..\new rev\john103C8T6\Core\Src\gpio.c`
|
||||
- `..\new rev\john103C8T6\Core\Src\usart.c`
|
||||
- `..\new rev\john103C8T6\Core\Src\can.c`
|
||||
- `..\new rev\john103C8T6\Core\Src\i2c.c`
|
||||
- `..\new rev\john103C8T6\Core\Src\spi.c`
|
||||
- `..\new rev\john103C8T6\Core\Inc\ow_port.h`
|
||||
|
||||
МК: `STM32F103C8Tx`, корпус `LQFP48`.
|
||||
|
||||
## Основные интерфейсы
|
||||
|
||||
| Пин МК | Функция | Настройка | Назначение в проекте |
|
||||
|---|---|---|---|
|
||||
| `PB6` | `USART1_TX` | AF push-pull, remap USART1 | Modbus RTU slave TX |
|
||||
| `PB7` | `USART1_RX` | input, no pull, remap USART1 | Modbus RTU slave RX |
|
||||
| `PA2` | `USART2_TX` | AF push-pull | Modbus RTU master TX |
|
||||
| `PA3` | `USART2_RX` | input, no pull | Modbus RTU master RX |
|
||||
| `PA15` | `One_wire` | GPIO, динамически input/output | Шина 1-Wire для DS18B20 |
|
||||
| `PA10` | `Relay_dc5v` | GPIO output push-pull | Реле 5 В, управляется из Modbus coil `20` |
|
||||
| `PC13` | GPIO output | push-pull | Светодиод/индикация, используется в `led_blink()` |
|
||||
| `PA0` | GPIO input | no pull | Вход, назначение в коде не найдено |
|
||||
| `PA11` | `CAN_RX` | input | CAN RX |
|
||||
| `PA12` | `CAN_TX` | AF push-pull | CAN TX |
|
||||
| `PB8` | `I2C1_SCL` | AF open-drain, remap I2C1 | I2C1 SCL |
|
||||
| `PB9` | `I2C1_SDA` | AF open-drain, remap I2C1 | I2C1 SDA |
|
||||
| `PB3` | `SPI1_SCK` | AF push-pull, remap SPI1 | SPI1 SCK |
|
||||
| `PB4` | `SPI1_MISO` | input, no pull, remap SPI1 | SPI1 MISO |
|
||||
| `PB5` | `SPI1_MOSI` | AF push-pull, remap SPI1 | SPI1 MOSI |
|
||||
| `PA13` | `SWDIO` | Serial Wire | Отладка |
|
||||
| `PA14` | `SWCLK` | Serial Wire | Отладка |
|
||||
| `PD0` | `OSC_IN` | HSE oscillator | Внешний кварц |
|
||||
| `PD1` | `OSC_OUT` | HSE oscillator | Внешний кварц |
|
||||
|
||||
## GPIO output, сконфигурированные в `MX_GPIO_Init`
|
||||
|
||||
| Пин МК | Начальное состояние | Комментарий |
|
||||
|---|---:|---|
|
||||
| `PC13` | `RESET` | Индикация, мигает при старте через `led_blink(GPIOC, 13, ...)` |
|
||||
| `PA1` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA4` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA5` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA6` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA7` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA8` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA9` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PA10` | `RESET` | `Relay_dc5v`, в цикле main зависит от `MB_DATA.Coils.coils[1].state_val_bit.state_val_05` |
|
||||
| `PA15` | `RESET` | 1-Wire, затем драйвер меняет режим пина input/output |
|
||||
| `PB0` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB1` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB2` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB10` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB11` | `RESET` | Есть macro `GPIOB11_valve`, но прямой записи в `PB11` в текущем коде не найдено |
|
||||
| `PB12` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB13` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB14` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
| `PB15` | `RESET` | Выход сконфигурирован, активного использования в коде не найдено |
|
||||
|
||||
## Периферия без внешнего пина
|
||||
|
||||
| Периферия | Настройка | Назначение |
|
||||
|---|---|---|
|
||||
| `TIM1` | internal clock, period `65535`, prescaler `0` | Тайминги 1-Wire, `OW_TIM` |
|
||||
| `TIM2` | internal clock, period `65535`, prescaler `7199` | Таймер Modbus slave |
|
||||
| `TIM4` | internal clock, period `65535`, prescaler `7199` | Таймер Modbus master |
|
||||
| `ADC1` | `ADC_CHANNEL_VREFINT` | Внутренний Vref, внешних ADC-пинов нет |
|
||||
| `RTC` | LSI | Часы, доступны через Modbus-регистры |
|
||||
|
||||
## Замечания
|
||||
|
||||
- В `.ioc` пины `PA2/PA3` отмечены как GPIO output, но в актуальном `usart.c` они инициализируются как `USART2_TX/RX`. Для документации использована фактическая инициализация из исходников.
|
||||
- Функция `handle_valves()` содержит запись в `GPIOC` pin `14`, но `PC14` не инициализирован в `MX_GPIO_Init()` и сама функция в основном цикле закомментирована.
|
||||
- Для RS-485 direction control (`DE/RE`) отдельный GPIO в `modbus_config.h` не задан: `RS_EnableReceive()` и `RS_EnableTransmit()` закомментированы.
|
||||
@@ -0,0 +1,201 @@
|
||||
# Modbus Map
|
||||
|
||||
Документ составлен по прошивке:
|
||||
|
||||
- `..\new rev\john103C8T6\Modbus\modbus_config.h`
|
||||
- `..\new rev\john103C8T6\Modbus\modbus_data.h`
|
||||
- `..\new rev\john103C8T6\Modbus\modbus_data.c`
|
||||
- `..\new rev\john103C8T6\Core\Src\main.c`
|
||||
- `..\new rev\john103C8T6\Core\Inc\PROJ_setup.h`
|
||||
|
||||
Адреса ниже указаны в 0-based формате, как они используются в прошивке. В некоторых Modbus-терминалах эти же адреса отображаются как `30001`, `40001`, `00001` и т.п. В таком терминале к адресу обычно надо прибавить `1` и выбрать нужный тип таблицы.
|
||||
|
||||
## Общие параметры
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Протокол | Modbus RTU |
|
||||
| Slave ID | `3` |
|
||||
| Slave UART | `USART1`, `PB6 TX`, `PB7 RX` |
|
||||
| Slave UART настройки | `115200`, `8N1` |
|
||||
| Slave таймер | `TIM2` |
|
||||
| Master UART | `USART2`, `PA2 TX`, `PA3 RX` |
|
||||
| Master UART настройки | `115200`, `8N1` |
|
||||
| Master таймер | `TIM4` |
|
||||
| `MAX_SENSE` | `32` |
|
||||
| Включенные таблицы | Coils, Holding Registers, Input Registers |
|
||||
|
||||
## Input Registers, function `0x04`
|
||||
|
||||
Базовый массив: `MB_DATA.InRegs`, адресный диапазон прошивки `0..1999`.
|
||||
|
||||
| Адрес | Кол-во | Имя | Тип | Описание |
|
||||
|---:|---:|---|---|---|
|
||||
| `0` | `32` | `sens_Temp[0..31]` | `uint16_t` | Температура DS18B20, в коде записывается как `temperature * 10`. Рекомендуется читать как `int16_t / 10.0`, если возможны отрицательные температуры |
|
||||
| `32` | `968` | `reserve` | `uint16_t[]` | Резерв до адреса `999` |
|
||||
| `1000` | `128` | `ID.DevAddr[32][8]` | raw bytes as registers | ROM-коды DS18B20: 32 датчика по 8 байт. Для датчика `N`: базовый регистр `1000 + N * 4` |
|
||||
| `1128` | `72` | `reserve1` | `uint16_t[]` | Резерв до адреса `1199` |
|
||||
| `1200` | `1` | `num_Tsens` | `uint16_t` | Количество найденных датчиков DS18B20 |
|
||||
| `1201` | `1` | `rtc.hours` | `uint16_t` | Текущие часы RTC |
|
||||
| `1202` | `1` | `rtc.minutes` | `uint16_t` | Текущие минуты RTC |
|
||||
| `1203` | `1` | `rtc.seconds` | `uint16_t` | Текущие секунды RTC |
|
||||
| `1204` | `1` | `rtc.date` | `uint16_t` | День месяца |
|
||||
| `1205` | `1` | `rtc.month` | `uint16_t` | Месяц |
|
||||
| `1206` | `1` | `rtc.year` | `uint16_t` | Год в формате RTC проекта |
|
||||
| `1207` | `1` | `rtc.weekday` | `uint16_t` | День недели |
|
||||
| `1208` | `1` | `rtc.apply` | `uint16_t` | Для input-регистров обычно `0` |
|
||||
| `1209` | `1` | `rtc.status` | `uint16_t` | Статус RTC |
|
||||
| `1210` | `790` | reserved | `uint16_t[]` | Адреса доступны в общем диапазоне, прикладного поля нет |
|
||||
|
||||
## Holding Registers, functions `0x03`, `0x06`, `0x10`
|
||||
|
||||
Базовый массив: `MB_DATA.HoldRegs`, адресный диапазон прошивки `0..1999`.
|
||||
|
||||
| Адрес | Кол-во | Имя | Тип | Описание |
|
||||
|---:|---:|---|---|---|
|
||||
| `0` | `32` | `set_Temp[0..31]` | `uint16_t` | Уставки температуры для датчиков. В текущем коде используются как градусы без умножения на 10 |
|
||||
| `32` | `68` | `reserve` | `uint16_t[]` | Резерв до адреса `99` |
|
||||
| `100` | `32` | `set_hyst[0..31]` | `uint16_t` | Гистерезис температуры для датчиков. В текущем коде используется как градусы |
|
||||
| `132` | `68` | `reserve1` | `uint16_t[]` | Резерв до адреса `199` |
|
||||
| `200` | `1` | `rtc.hours` | `uint16_t` | Часы для установки RTC |
|
||||
| `201` | `1` | `rtc.minutes` | `uint16_t` | Минуты для установки RTC |
|
||||
| `202` | `1` | `rtc.seconds` | `uint16_t` | Секунды для установки RTC |
|
||||
| `203` | `1` | `rtc.date` | `uint16_t` | День месяца |
|
||||
| `204` | `1` | `rtc.month` | `uint16_t` | Месяц |
|
||||
| `205` | `1` | `rtc.year` | `uint16_t` | Год в формате RTC проекта |
|
||||
| `206` | `1` | `rtc.weekday` | `uint16_t` | День недели |
|
||||
| `207` | `1` | `rtc.apply` | `uint16_t` | Записать `1`, чтобы применить время RTC |
|
||||
| `208` | `1` | `rtc.status` | `uint16_t` | Статус установки RTC |
|
||||
| `209` | `1791` | reserved | `uint16_t[]` | Адреса доступны в общем диапазоне, прикладного поля нет |
|
||||
|
||||
RTC status:
|
||||
|
||||
| Значение | Имя | Описание |
|
||||
|---:|---|---|
|
||||
| `0` | `MB_RTC_STATUS_IDLE` | Нет операции |
|
||||
| `1` | `MB_RTC_STATUS_SET_OK` | Время установлено |
|
||||
| `2` | `MB_RTC_STATUS_VALUE_ERROR` | Ошибка значения времени/даты |
|
||||
| `3` | `MB_RTC_STATUS_HAL_ERROR` | Ошибка HAL RTC |
|
||||
|
||||
## Coils, functions `0x01`, `0x05`, `0x0F`
|
||||
|
||||
Базовый массив: `MB_DATA.Coils`, адресный диапазон прошивки `0..999`.
|
||||
|
||||
| Coil address | Кол-во | Имя | Описание |
|
||||
|---:|---:|---|---|
|
||||
| `0` | `48` | `coils[0..2]` | Общие управляющие биты `state_val_01..state_val_16` в трех 16-битных словах |
|
||||
| `20` | `1` | `coils[1].state_val_05` | Управляет `PA10 / Relay_dc5v` в основном цикле |
|
||||
| `48` | `80` | `reserve_coils` | Резерв до coil `127` |
|
||||
| `128` | `32` | `status_tSens[0..1]` | Статусы подключения DS18B20: `Temp1_isConnected..Temp32_isConnected` |
|
||||
| `160` | `96` | `reserve_status_tSens` | Резерв до coil `255` |
|
||||
| `256` | `16` | `relay_struct_on` | Расчетные биты включения реле по датчикам `Temp1..Temp16` |
|
||||
| `272` | `16` | `reserve_relay_struct_on` | Резерв |
|
||||
| `288` | `16` | `relay_struct_off` | Расчетные биты выключения реле по датчикам `Temp1..Temp16` |
|
||||
| `304` | `80` | reserved | Резерв до coil `383` |
|
||||
| `384` | `1` | `init_param` | При записи `1` прошивка применяет `set_Temp[]` и `set_hyst[]`, затем сбрасывает бит |
|
||||
| `385` | `1` | `init_Tsens` | При записи `1` прошивка повторно ищет DS18B20, затем сбрасывает бит |
|
||||
| `386` | `1` | `Save_Param_to_Flash` | Поле объявлено, активного использования в текущем `main.c` не найдено |
|
||||
| `387` | `13` | reserved2 | Резервные биты |
|
||||
| `400` | `600` | reserved | Адреса доступны в общем диапазоне, прикладного поля нет |
|
||||
|
||||
## Привязка температур и реле
|
||||
|
||||
В `value_control()` прошивка сравнивает `sens[i].temperature` с уставкой и гистерезисом:
|
||||
|
||||
- если `temperature < set_temp - hyst`, выставляется `relay_struct_off` для датчика `i`;
|
||||
- если `temperature > set_temp + hyst`, выставляется `relay_struct_on` для датчика `i`;
|
||||
- если `temperature == set_temp`, оба бита для датчика сбрасываются.
|
||||
|
||||
Эти расчетные биты лежат в coils `256..271` и `288..303`. Прямая аппаратная привязка этих расчетных битов к GPIO-выходам в текущем `main.c` не найдена. Прямое управление GPIO найдено только для `PA10 / Relay_dc5v` через coil `20`.
|
||||
|
||||
|
||||
## GUI binding to the real STM project
|
||||
|
||||
Source project checked: `..\new rev\john103C8T6`.
|
||||
|
||||
The PC GUI bridge is bound to the actual STM Modbus layout from:
|
||||
|
||||
- `Modbus\modbus_config.h`
|
||||
- `Modbus\modbus_data.h`
|
||||
- `Core\Src\main.c`
|
||||
- `Core\Inc\ds18b20_driver.h`
|
||||
- `Core\Inc\PROJ_setup.h`
|
||||
|
||||
Active STM settings:
|
||||
|
||||
| Item | Value |
|
||||
|---|---:|
|
||||
| Default slave ID | `3` |
|
||||
| `MAX_SENSE` in STM | `32` |
|
||||
| GUI channels used | first `16` |
|
||||
| STM protocol on COM | Modbus RTU |
|
||||
| Optional GUI network mode | Modbus TCP gateway/device with the same register map |
|
||||
|
||||
GUI runtime map:
|
||||
|
||||
| GUI value | STM source | Modbus function | 0-based address |
|
||||
|---|---|---:|---:|
|
||||
| Current temperature channel `N` | `MB_DATA.InRegs.sens_Temp[N]` | `0x04` | `0 + N` |
|
||||
| DS18B20 ROM ID channel `N` | `MB_DATA.InRegs.ID.DevAddr[N][8]` | `0x04` | `1000 + N * 4` |
|
||||
| Sensor connected channel `N` | `MB_DATA.Coils.status_tSens` | `0x01` | `128 + N` |
|
||||
| Setpoint channel `N` | `MB_DATA.HoldRegs.set_Temp[N]`, value = `degC * 10` | `0x03` / `0x06` | `0 + N` |
|
||||
| Apply setpoints | `MB_DATA.Coils.init_param` | `0x05` | `384` |
|
||||
| Open command/state channel `N` | `MB_DATA.Coils.relay_struct_on` | `0x01` / `0x05` | `256 + N` |
|
||||
| Close command/state channel `N` | `MB_DATA.Coils.relay_struct_off` | `0x01` / `0x05` | `288 + N` |
|
||||
|
||||
Notes:
|
||||
|
||||
- GUI channel `1` uses index `N = 0`; GUI channel `16` uses index `N = 15`.
|
||||
- Setpoints are written as tenths of a degree: GUI `28.5°C` -> Modbus holding value `285`; readback `285` -> GUI `28.5°C`.
|
||||
- DS18B20 IDs are stored by STM as `uint8_t DevAddr[32][8]` and exposed through 16-bit input registers. The bridge restores each register in little-endian byte order to display the ROM ID correctly.
|
||||
- The current STM project does not expose analog valve position or opening angle registers. GUI position/angle are therefore derived from binary relay state: open = `100% / 90°`, close = `0% / 0°`.
|
||||
- `value_control()` in `Core\Src\main.c` calculates `relay_struct_on/off` from temperature, setpoint, and hysteresis. Direct manual coil writes from GUI can be overwritten by that firmware logic unless STM firmware adds a manual override register/coil.
|
||||
|
||||
|
||||
## STM room/channel structure added for GUI
|
||||
|
||||
Added to Keil STM project `..\new rev\john103C8T6`.
|
||||
|
||||
### Input registers: room status block
|
||||
|
||||
Base address: `400`. One room/channel uses `18` registers. Channel `N` uses base `400 + N * 18`, where GUI channel 1 is `N = 0`.
|
||||
|
||||
| Offset | Field | Scale / meaning |
|
||||
|---:|---|---|
|
||||
| 0 | `channel` | 1-based channel number |
|
||||
| 1 | `location` | numeric location code |
|
||||
| 2..5 | `ds18b20_id[4]` | 8-byte DS18B20 ROM ID, little-endian bytes per register |
|
||||
| 6 | `temperature_x10` | current temperature, degC * 10 |
|
||||
| 7 | `setpoint_x10` | setpoint, degC * 10 |
|
||||
| 8 | `hysteresis_x10` | hysteresis, degC * 10 |
|
||||
| 9 | `valve_position_pct` | valve opening percent, 0..100 |
|
||||
| 10 | `valve_angle_deg` | opening angle in degrees |
|
||||
| 11 | `valve_angle_max_deg` | max opening angle, default 90 |
|
||||
| 12 | `is_connected` | DS18B20 connected flag |
|
||||
| 13 | `valve_open` | open relay/command state |
|
||||
| 14 | `valve_close` | close relay/command state |
|
||||
| 15 | `mode` | 0 auto, 1 manual |
|
||||
| 16 | `command_state` | 0 stop, 1 open, 2 close |
|
||||
| 17 | `reserved` | reserved |
|
||||
|
||||
### Holding registers: room control block
|
||||
|
||||
Base address: `300`. One room/channel uses `8` registers. Channel `N` uses base `300 + N * 8`.
|
||||
|
||||
| Offset | Field | Scale / meaning |
|
||||
|---:|---|---|
|
||||
| 0 | `setpoint_x10` | writable setpoint, degC * 10 |
|
||||
| 1 | `hysteresis_x10` | writable hysteresis, degC * 10 |
|
||||
| 2 | `valve_position_pct` | writable manual opening percent, 0..100 |
|
||||
| 3 | `valve_angle_max_deg` | max opening angle, default 90 |
|
||||
| 4 | `mode` | 0 auto, 1 manual |
|
||||
| 5 | `command` | 0 stop, 1 open, 2 close |
|
||||
| 6 | `location` | numeric location code |
|
||||
| 7 | `apply` | write 1 to apply room setpoint/hysteresis |
|
||||
|
||||
Compatibility:
|
||||
|
||||
- Legacy `set_Temp[0..31]` at holding `0..31` is kept.
|
||||
- Legacy `set_hyst[0..31]` at holding `100..131` is kept.
|
||||
- Legacy coils `256..271` and `288..303` are kept.
|
||||
- The Python bridge writes both the legacy map and the new room control block.
|
||||
@@ -0,0 +1,105 @@
|
||||
# Web GUI для датчиков температуры и клапанов
|
||||
|
||||
Веб-интерфейс для:
|
||||
- мониторинга температур,
|
||||
- установки уставок,
|
||||
- ручного и автоматического управления клапанами,
|
||||
- управления позицией клапана в `%`.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
1. Запустите демо backend:
|
||||
```bash
|
||||
python mock_server.py
|
||||
```
|
||||
2. Откройте страницу:
|
||||
- `http://127.0.0.1:8080/index.html`
|
||||
3. В поле `API endpoint` оставьте пустым для демо или укажите `http://127.0.0.1:8080`.
|
||||
|
||||
Если API не указан, интерфейс переходит в офлайн-режим (демо) и хранит состояние в `localStorage`.
|
||||
|
||||
## Привязка к вашему проекту
|
||||
|
||||
GUI читает и пишет данные через `API_PATHS` в `app.js`:
|
||||
|
||||
1. Датчики: `/api/sensors`, `/sensors`, `/api/data`, `/state`
|
||||
2. Клапаны: `/api/valves`, `/valves`, `/api/data`, `/state`
|
||||
3. Запись: сначала `PUT /api/*/:id`, затем `PUT /api/*` (без `:id`)
|
||||
|
||||
Если ваш контракт другой, правьте:
|
||||
- массив `API_PATHS` в `app.js`
|
||||
- функции `normalizeSensor`, `normalizeValve` в `app.js`
|
||||
|
||||
## Работа с COM-портом (MCU)
|
||||
|
||||
Для чтения с порта COM запущен `serial_bridge.py`:
|
||||
|
||||
```bash
|
||||
python serial_bridge.py --serial-port COM3 --baudrate 115200
|
||||
```
|
||||
|
||||
По умолчанию сервис доступен на `http://127.0.0.1:8080`.
|
||||
|
||||
Поддерживаемые входящие форматы с порта:
|
||||
|
||||
1) JSON-пакет:
|
||||
```json
|
||||
{"sensors":[{"id":"zone_1","value":24.5,"setpoint":28.0}], "valves":[{"id":"valve_1","mode":"auto","position":32,"targetTemp":28}]}
|
||||
```
|
||||
|
||||
2) Текстовый формат:
|
||||
```text
|
||||
T1=24.5;T1_SETPOINT=28.0;V1_MODE=auto;V1_POS=32;V1_TGT=28
|
||||
```
|
||||
|
||||
Исходящие команды от GUI (`PUT`) также отправляются в порт как JSON:
|
||||
```json
|
||||
{"type":"sensor","id":"zone_1","setpoint":28.0}
|
||||
{"type":"valve","id":"valve_1","mode":"manual","position":50}
|
||||
```
|
||||
|
||||
Если нужен другой протокол от/к MCU (Modbus/байт-структура), пришлите пример кадров — подгоню парсер в `serial_bridge.py`.
|
||||
|
||||
В GUI:
|
||||
- поле `COM порт` показывает список `/api/serial/ports`;
|
||||
- кнопка `Обновить порты` — принудительно перечитывает список COM;
|
||||
- кнопка `Подключить` / `Отключить` — вызывает `/api/serial/connect` и `/api/serial/disconnect` в `serial_bridge.py`.
|
||||
|
||||
## Форматы API
|
||||
|
||||
### GET
|
||||
- `GET /api/sensors` → массив:
|
||||
```json
|
||||
[
|
||||
{ "id": "zone_1", "name": "Термопара 1", "value": 24.6, "setpoint": 28, "unit": "°C", "zone": "1" }
|
||||
]
|
||||
```
|
||||
- `GET /api/valves` → массив:
|
||||
```json
|
||||
[
|
||||
{ "id": "valve_1", "name": "Клапан 1", "zone": "1", "mode": "auto", "position": 40, "targetTemp": 28, "isOpen": true }
|
||||
]
|
||||
```
|
||||
|
||||
### PUT
|
||||
- `PUT /api/sensors/{id}`:
|
||||
```json
|
||||
{ "setpoint": 29.5 }
|
||||
```
|
||||
- `PUT /api/valves/{id}`:
|
||||
- ручной:
|
||||
```json
|
||||
{ "mode": "manual", "position": 50 }
|
||||
```
|
||||
- авто:
|
||||
```json
|
||||
{ "mode": "auto", "targetTemp": 28.0 }
|
||||
```
|
||||
- или отдельные поля (`mode`, `position`, `targetTemp`).
|
||||
|
||||
## Файлы
|
||||
- `index.html` — разметка страницы
|
||||
- `styles.css` — стили
|
||||
- `app.js` — логика интерфейса
|
||||
- `mock_server.py` — демонстрационный backend
|
||||
- `serial_bridge.py` — backend для COM-порта
|
||||
@@ -0,0 +1,1640 @@
|
||||
const SENSOR_COUNT = 16;
|
||||
const VALVE_COUNT = 32;
|
||||
const DEFAULT_OPEN_DEGREES_MAX = 90;
|
||||
const CHANNEL_LOCATIONS = [
|
||||
"DUO прав",
|
||||
"DUO лев",
|
||||
"TRIO",
|
||||
"SOLO",
|
||||
"ОСНОВА 7",
|
||||
"ОСНОВА 6",
|
||||
"ОСНОВА 5",
|
||||
"ОСНОВА 4",
|
||||
"ОСНОВА 3",
|
||||
"ОСНОВА 2",
|
||||
"ОСНОВА 1",
|
||||
];
|
||||
|
||||
function defaultChannelLocation(index) {
|
||||
return CHANNEL_LOCATIONS[index % CHANNEL_LOCATIONS.length];
|
||||
}
|
||||
|
||||
function makeDefaultSensors() {
|
||||
return Array.from({ length: SENSOR_COUNT }, (_, index) => {
|
||||
const number = index + 1;
|
||||
return {
|
||||
id: `zone_${number}`,
|
||||
name: `Датчик ${number}`,
|
||||
value: 0,
|
||||
setpoint: 28,
|
||||
unit: "°C",
|
||||
zone: String(number),
|
||||
location: defaultChannelLocation(index),
|
||||
ds18b20Id: `28-00-00-00-00-00-00-${number.toString(16).toUpperCase().padStart(2, "0")}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function makeDefaultValves() {
|
||||
return Array.from({ length: VALVE_COUNT }, (_, index) => {
|
||||
const number = index + 1;
|
||||
const zone = (index % SENSOR_COUNT) + 1;
|
||||
return {
|
||||
id: `valve_${number}`,
|
||||
name: `Клапан ${number}`,
|
||||
zone: String(zone),
|
||||
mode: "auto",
|
||||
position: 0,
|
||||
targetTemp: 28,
|
||||
isOpen: false,
|
||||
openDegrees: 0,
|
||||
openDegreesMax: DEFAULT_OPEN_DEGREES_MAX,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const defaultSensors = makeDefaultSensors();
|
||||
const defaultValves = makeDefaultValves();
|
||||
|
||||
const API_PATHS = {
|
||||
sensorsRead: ["/api/sensors", "/sensors", "/api/data", "/state"],
|
||||
valvesRead: ["/api/valves", "/valves", "/api/data", "/state"],
|
||||
sensorWrite: [
|
||||
(id) => `/api/sensors/${encodeURIComponent(id)}`,
|
||||
(id) => `/sensors/${encodeURIComponent(id)}`,
|
||||
() => "/api/sensors",
|
||||
() => "/sensors",
|
||||
],
|
||||
valveWrite: [
|
||||
(id) => `/api/valves/${encodeURIComponent(id)}`,
|
||||
(id) => `/valves/${encodeURIComponent(id)}`,
|
||||
() => "/api/valves",
|
||||
() => "/valves",
|
||||
],
|
||||
valveCalibrate: [
|
||||
(id) => `/api/valves/${encodeURIComponent(id)}/calibrate`,
|
||||
(id) => `/valves/${encodeURIComponent(id)}/calibrate`,
|
||||
],
|
||||
valvesCalibrateAll: ["/api/valves/calibrate-all", "/api/calibration/all", "/calibration/all"],
|
||||
};
|
||||
|
||||
const SERIAL_API_PATHS = {
|
||||
ports: [
|
||||
"/api/serial/ports",
|
||||
"/api/ports",
|
||||
"/ports",
|
||||
"/serial/ports",
|
||||
"/status/ports",
|
||||
],
|
||||
status: [
|
||||
"/api/serial/status",
|
||||
"/api/state",
|
||||
"/state",
|
||||
"/serial/status",
|
||||
],
|
||||
connect: [
|
||||
"/api/serial/connect",
|
||||
"/api/connect",
|
||||
"/connect",
|
||||
"/serial/connect",
|
||||
],
|
||||
disconnect: [
|
||||
"/api/serial/disconnect",
|
||||
"/api/disconnect",
|
||||
"/disconnect",
|
||||
"/serial/disconnect",
|
||||
],
|
||||
};
|
||||
|
||||
const state = {
|
||||
sensors: [...defaultSensors],
|
||||
valves: [...defaultValves],
|
||||
apiBase: "",
|
||||
timer: null,
|
||||
};
|
||||
|
||||
let serialConnected = false;
|
||||
let selectedPort = "";
|
||||
|
||||
const sensorsEl = document.getElementById("sensors");
|
||||
const valvesEl = document.getElementById("valves");
|
||||
const statusEl = document.getElementById("status");
|
||||
const globalStatus = document.getElementById("globalStatus");
|
||||
const apiInput = document.getElementById("apiBase");
|
||||
const refreshBtn = document.getElementById("refreshBtn");
|
||||
const saveApiBtn = document.getElementById("saveApiBtn");
|
||||
const refreshPortsBtn = document.getElementById("refreshPortsBtn");
|
||||
const connectPortBtn = document.getElementById("connectPortBtn");
|
||||
const comPortSelect = document.getElementById("comPortSelect");
|
||||
const modbusTransport = document.getElementById("modbusTransport");
|
||||
const tcpHost = document.getElementById("tcpHost");
|
||||
const tcpPort = document.getElementById("tcpPort");
|
||||
const modbusSlaveId = document.getElementById("modbusSlaveId");
|
||||
const serialStatus = document.getElementById("serialStatus");
|
||||
const calibrateAllBtn = document.getElementById("calibrateAllBtn");
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
function parseGuiNumber(value, fallback = 0) {
|
||||
const parsed = Number(String(value ?? "").replace(",", "."));
|
||||
return Number.isFinite(parsed) ? parsed : fallback;
|
||||
}
|
||||
|
||||
function storageGet(name, fallback) {
|
||||
const raw = localStorage.getItem(name);
|
||||
if (!raw) return fallback;
|
||||
try {
|
||||
return JSON.parse(raw);
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function storageSet(name, value) {
|
||||
localStorage.setItem(name, JSON.stringify(value));
|
||||
}
|
||||
|
||||
function getModbusTransport() {
|
||||
return (modbusTransport?.value || storageGet("modbusTransport", "rtu") || "rtu").toLowerCase();
|
||||
}
|
||||
|
||||
function applyModbusTransportView() {
|
||||
const transport = getModbusTransport();
|
||||
const isTcp = transport === "tcp";
|
||||
|
||||
document.querySelectorAll(".rtu-field").forEach((element) => {
|
||||
element.classList.toggle("hidden", isTcp);
|
||||
});
|
||||
document.querySelectorAll(".tcp-field").forEach((element) => {
|
||||
element.classList.toggle("hidden", !isTcp);
|
||||
});
|
||||
|
||||
if (refreshPortsBtn) {
|
||||
refreshPortsBtn.disabled = isTcp;
|
||||
}
|
||||
if (serialStatus && !serialConnected) {
|
||||
serialStatus.textContent = isTcp ? "Modbus TCP: не подключен" : "COM: не подключен";
|
||||
}
|
||||
}
|
||||
|
||||
function initModbusTransportControls() {
|
||||
if (modbusTransport) {
|
||||
modbusTransport.value = storageGet("modbusTransport", "rtu");
|
||||
modbusTransport.addEventListener("change", () => {
|
||||
storageSet("modbusTransport", modbusTransport.value);
|
||||
applyModbusTransportView();
|
||||
});
|
||||
}
|
||||
if (tcpHost) {
|
||||
tcpHost.value = storageGet("tcpHost", tcpHost.value || "192.168.0.10");
|
||||
tcpHost.addEventListener("change", () => storageSet("tcpHost", tcpHost.value.trim()));
|
||||
}
|
||||
if (tcpPort) {
|
||||
tcpPort.value = storageGet("tcpPort", tcpPort.value || "502");
|
||||
tcpPort.addEventListener("change", () => storageSet("tcpPort", tcpPort.value || "502"));
|
||||
}
|
||||
if (modbusSlaveId) {
|
||||
modbusSlaveId.value = storageGet("modbusSlaveId", modbusSlaveId.value || "3");
|
||||
modbusSlaveId.addEventListener("change", () => storageSet("modbusSlaveId", modbusSlaveId.value || "3"));
|
||||
}
|
||||
applyModbusTransportView();
|
||||
}
|
||||
|
||||
function normalizeApiUrl(value) {
|
||||
const trimmed = (value || "").trim();
|
||||
if (trimmed && !/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) {
|
||||
return normalizeApiUrl(`http://${trimmed}`);
|
||||
}
|
||||
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
||||
try {
|
||||
const parsed = new URL(trimmed);
|
||||
return `${parsed.protocol}//${parsed.host}`;
|
||||
} catch {
|
||||
return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
||||
}
|
||||
}
|
||||
return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
||||
}
|
||||
|
||||
function ensureApiBase() {
|
||||
if (state.apiBase) {
|
||||
return state.apiBase;
|
||||
}
|
||||
if (window.location?.protocol?.startsWith("http") && window.location.host) {
|
||||
state.apiBase = `${window.location.protocol}//${window.location.host}`;
|
||||
} else {
|
||||
state.apiBase = "http://127.0.0.1:8080";
|
||||
}
|
||||
if (apiInput) {
|
||||
apiInput.value = state.apiBase;
|
||||
}
|
||||
storageSet("apiBase", state.apiBase);
|
||||
return state.apiBase;
|
||||
}
|
||||
|
||||
function endpoint(path) {
|
||||
if (!state.apiBase) {
|
||||
throw new Error("demo");
|
||||
}
|
||||
return `${state.apiBase}${path}`;
|
||||
}
|
||||
|
||||
async function parseResponseBody(response) {
|
||||
const body = await response.text();
|
||||
if (!body) {
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
return JSON.parse(body);
|
||||
} catch {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
async function apiGet(path) {
|
||||
const response = await fetch(endpoint(path), {
|
||||
method: "GET",
|
||||
headers: { accept: "application/json" },
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`HTTP ${response.status}: ${body}`);
|
||||
}
|
||||
return parseResponseBody(response);
|
||||
}
|
||||
|
||||
async function apiPut(path, payload) {
|
||||
const response = await fetch(endpoint(path), {
|
||||
method: "PUT",
|
||||
headers: { "content-type": "application/json", accept: "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`HTTP ${response.status}: ${body}`);
|
||||
}
|
||||
return parseResponseBody(response);
|
||||
}
|
||||
|
||||
async function apiPost(path, payload) {
|
||||
const response = await fetch(endpoint(path), {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json", accept: "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(`HTTP ${response.status}: ${body}`);
|
||||
}
|
||||
return parseResponseBody(response);
|
||||
}
|
||||
|
||||
function extractPorts(payload) {
|
||||
if (Array.isArray(payload)) return payload;
|
||||
if (Array.isArray(payload?.ports)) return payload.ports;
|
||||
return [];
|
||||
}
|
||||
|
||||
function extractSelectedPort(payload) {
|
||||
if (typeof payload?.selected === "string") return payload.selected;
|
||||
if (typeof payload?.port === "string") return payload.port;
|
||||
return "";
|
||||
}
|
||||
|
||||
async function apiGetFallback(paths) {
|
||||
let lastError;
|
||||
for (const path of paths) {
|
||||
try {
|
||||
return await apiGet(path);
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error("No available endpoint");
|
||||
}
|
||||
|
||||
async function apiPostFallback(paths, payload) {
|
||||
let lastError;
|
||||
for (const path of paths) {
|
||||
try {
|
||||
return await apiPost(path, payload);
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error("No available endpoint");
|
||||
}
|
||||
|
||||
function degreesFromPosition(position, maxDegrees = DEFAULT_OPEN_DEGREES_MAX) {
|
||||
const maxValue = Number(maxDegrees) > 0 ? Number(maxDegrees) : DEFAULT_OPEN_DEGREES_MAX;
|
||||
return Math.round(clamp(position, 0, 100) * maxValue / 100);
|
||||
}
|
||||
|
||||
function positionFromDegrees(degrees, maxDegrees = DEFAULT_OPEN_DEGREES_MAX) {
|
||||
const maxValue = Number(maxDegrees) > 0 ? Number(maxDegrees) : DEFAULT_OPEN_DEGREES_MAX;
|
||||
return Math.round(clamp(degrees, 0, maxValue) * 100 / maxValue);
|
||||
}
|
||||
|
||||
async function fetchComPorts() {
|
||||
if (!state.apiBase) {
|
||||
return { ports: [], selected: "" };
|
||||
}
|
||||
const payload = await apiGetFallback(SERIAL_API_PATHS.ports);
|
||||
return {
|
||||
ports: extractPorts(payload),
|
||||
selected: extractSelectedPort(payload),
|
||||
};
|
||||
}
|
||||
|
||||
function applyPortOptions(ports, preferredPort = "") {
|
||||
if (!comPortSelect) return;
|
||||
const current = comPortSelect.value;
|
||||
comPortSelect.innerHTML = "<option value=\"\">Порт не выбран</option>";
|
||||
for (const item of ports) {
|
||||
const entry = typeof item === "string" ? { device: item, description: "" } : item;
|
||||
const option = document.createElement("option");
|
||||
const value = entry.device || entry.port || "";
|
||||
if (!value) continue;
|
||||
option.value = value;
|
||||
option.textContent = `${entry.description ? `${entry.description} (${value})` : value}`;
|
||||
option.dataset.hwid = entry.hwid || "";
|
||||
comPortSelect.appendChild(option);
|
||||
}
|
||||
const targetPort = preferredPort || current;
|
||||
if (ports.find((item) => (typeof item === "string" ? item : item.device) === targetPort)) {
|
||||
comPortSelect.value = targetPort;
|
||||
} else if (current) {
|
||||
comPortSelect.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshPortsLegacy(silent = false) {
|
||||
const payload = await fetchComPorts();
|
||||
const ports = payload?.ports || [];
|
||||
applyPortOptions(ports, payload?.selected || "");
|
||||
if (!silent) {
|
||||
updateStatus(ports.length ? "Доступные порты обновлены" : "Порты не найдены", ports.length ? "ok" : "warn");
|
||||
}
|
||||
}
|
||||
|
||||
async function connectSelectedPortLegacyOld() {
|
||||
if (!state.apiBase) {
|
||||
updateStatus("Укажите API endpoint, чтобы работать с COM-портами", "warn");
|
||||
return;
|
||||
}
|
||||
const value = comPortSelect.value;
|
||||
if (!value) {
|
||||
updateStatus("Выберите COM порт", "warn");
|
||||
return;
|
||||
}
|
||||
selectedPort = value;
|
||||
try {
|
||||
const payload = { port: value, baud: 115200, baudrate: 115200, parity: "N", stopbits: 1, bytesize: 8, timeout: 0.3 };
|
||||
await apiPostFallback(SERIAL_API_PATHS.connect, payload);
|
||||
serialConnected = true;
|
||||
serialStatus.textContent = `COM: подключён (${value})`;
|
||||
serialStatus.className = "status status-ok";
|
||||
updateStatus(`COM ${value} подключён`, "ok");
|
||||
} catch (error) {
|
||||
serialConnected = false;
|
||||
serialStatus.textContent = "COM: ошибка подключения";
|
||||
serialStatus.className = "status status-error";
|
||||
updateStatus(`Ошибка подключения COM: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function disconnectPortLegacy() {
|
||||
if (!state.apiBase) return;
|
||||
try {
|
||||
await apiPostFallback(SERIAL_API_PATHS.disconnect, {});
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
serialConnected = false;
|
||||
serialStatus.textContent = "COM: не подключён";
|
||||
serialStatus.className = "status status-warn";
|
||||
selectedPort = "";
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeSensor(raw = {}) {
|
||||
const rawId = raw.id ?? raw.sensorId ?? raw.key ?? raw.code;
|
||||
const zone = String(raw.zone ?? raw.channel ?? raw.sensorZone ?? "").trim() || String(rawId ?? "").replace(/\D+/g, "");
|
||||
const fallbackZone = zone ? `zone_${zone}` : "zone_1";
|
||||
const id = rawId || fallbackZone;
|
||||
return {
|
||||
id: String(id),
|
||||
name: String(raw.name ?? raw.label ?? `Термопара ${zone || 1}`),
|
||||
zone: String(zone || "1"),
|
||||
value: Number(raw.value ?? raw.current ?? raw.temperature ?? raw.temp ?? 0),
|
||||
setpoint: Number(raw.setpoint ?? raw.target ?? raw.targetTemp ?? raw.tSet ?? 0),
|
||||
unit: raw.unit ?? raw.units ?? "°C",
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeValve(raw = {}) {
|
||||
const rawId = raw.id ?? raw.valveId ?? raw.key ?? raw.code;
|
||||
const zone = String(raw.zone ?? raw.channel ?? raw.controlZone ?? "").trim() || String(rawId ?? "").replace(/\D+/g, "");
|
||||
const id = rawId || `valve_${zone || "1"}`;
|
||||
const mode = String(raw.mode ?? raw.workMode ?? "auto").toLowerCase() === "manual" ? "manual" : "auto";
|
||||
const maxOpenDegrees = Number(raw.openDegreesMax ?? raw.maxOpenDegrees ?? raw.degMax ?? DEFAULT_OPEN_DEGREES_MAX);
|
||||
const maxDegrees = Number.isFinite(maxOpenDegrees) && maxOpenDegrees > 0 ? maxOpenDegrees : DEFAULT_OPEN_DEGREES_MAX;
|
||||
let position = Number(raw.position ?? raw.pos ?? raw.percent ?? raw.value);
|
||||
let openDegrees = Number(raw.openDegrees ?? raw.degree ?? raw.posDeg ?? raw.opening ?? raw.openAngle ?? raw.angle);
|
||||
|
||||
if (Number.isNaN(position)) {
|
||||
if (Number.isNaN(openDegrees)) {
|
||||
position = 0;
|
||||
openDegrees = 0;
|
||||
} else {
|
||||
position = positionFromDegrees(openDegrees, maxDegrees);
|
||||
}
|
||||
} else if (Number.isNaN(openDegrees)) {
|
||||
openDegrees = degreesFromPosition(position, maxDegrees);
|
||||
} else {
|
||||
position = positionFromDegrees(openDegrees, maxDegrees);
|
||||
}
|
||||
return {
|
||||
id: String(id),
|
||||
name: String(raw.name ?? raw.label ?? `Клапан ${zone || 1}`),
|
||||
zone: String(zone || "1"),
|
||||
mode,
|
||||
position: clamp(position, 0, 100),
|
||||
openDegrees: clamp(Math.round(openDegrees), 0, maxDegrees),
|
||||
openDegreesMax: maxDegrees,
|
||||
targetTemp: Number(raw.targetTemp ?? raw.targetTemperature ?? raw.setpoint ?? raw.tSet ?? 0),
|
||||
isOpen: Boolean(raw.isOpen ?? raw.open ?? position > 0),
|
||||
};
|
||||
}
|
||||
|
||||
function extractCollection(payload, key) {
|
||||
if (!payload) return null;
|
||||
if (Array.isArray(payload)) return payload;
|
||||
if (Array.isArray(payload[key])) return payload[key];
|
||||
if (Array.isArray(payload.data?.[key])) return payload.data[key];
|
||||
if (Array.isArray(payload.result?.[key])) return payload.result[key];
|
||||
if (Array.isArray(payload.state?.[key])) return payload.state[key];
|
||||
if (Array.isArray(payload.data?.[`temperature_${key}`])) return payload.data[`temperature_${key}`];
|
||||
return null;
|
||||
}
|
||||
|
||||
async function fetchCollection(paths, key, normalizer) {
|
||||
let lastError;
|
||||
for (const path of paths) {
|
||||
try {
|
||||
const payload = await apiGet(path);
|
||||
const collection = extractCollection(payload, key);
|
||||
if (!collection || !Array.isArray(collection)) continue;
|
||||
return collection.map(normalizer);
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error(`No available endpoint for ${key}`);
|
||||
}
|
||||
|
||||
async function sendWithFallback(paths, id, payload) {
|
||||
let lastError;
|
||||
for (const resolvePath of paths) {
|
||||
try {
|
||||
const route = typeof resolvePath === "function" ? resolvePath(id) : resolvePath;
|
||||
return await apiPut(route, payload);
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error("No available write endpoint");
|
||||
}
|
||||
|
||||
async function postWithFallback(paths, id, payload) {
|
||||
let lastError;
|
||||
for (const resolvePath of paths) {
|
||||
try {
|
||||
const route = typeof resolvePath === "function" ? resolvePath(id) : resolvePath;
|
||||
return await apiPost(route, payload);
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error("No available write endpoint");
|
||||
}
|
||||
|
||||
function writePayloadBase(id, type = "sensor") {
|
||||
const sensor = findSensorById(id);
|
||||
const valve = findValveById(id);
|
||||
const entity = type === "valve" ? valve : sensor;
|
||||
return {
|
||||
id,
|
||||
...(entity ? { zone: entity.zone, name: entity.name } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function mergeDefaults(stored, defaults, normalizer = (item) => item) {
|
||||
const source = Array.isArray(stored) ? stored : [];
|
||||
const byId = new Map(source.map((item) => [String(item.id), normalizer(item)]));
|
||||
return defaults.map((item) => ({
|
||||
...item,
|
||||
...(byId.get(String(item.id)) || {}),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildDemos() {
|
||||
state.sensors = mergeDefaults(storageGet("sensorState", []), defaultSensors, normalizeSensor);
|
||||
state.valves = mergeDefaults(storageGet("valveState", []), defaultValves, normalizeValve);
|
||||
storageSet("sensorState", state.sensors);
|
||||
storageSet("valveState", state.valves);
|
||||
}
|
||||
|
||||
function updateStatus(message, type = "ok") {
|
||||
globalStatus.textContent = message;
|
||||
globalStatus.className = `status-${type}`;
|
||||
}
|
||||
|
||||
function setConnectButtonText() {
|
||||
if (!connectPortBtn) {
|
||||
return;
|
||||
}
|
||||
connectPortBtn.textContent = serialConnected ? "Отключить" : "Подключить";
|
||||
}
|
||||
|
||||
function setSerialBusyState(isBusy, message) {
|
||||
if (refreshPortsBtn) {
|
||||
refreshPortsBtn.disabled = isBusy;
|
||||
}
|
||||
if (connectPortBtn) {
|
||||
connectPortBtn.disabled = isBusy;
|
||||
connectPortBtn.textContent = isBusy ? "..." : (serialConnected ? "Отключить" : "Подключить");
|
||||
}
|
||||
if (calibrateAllBtn) {
|
||||
calibrateAllBtn.disabled = isBusy || !serialConnected;
|
||||
}
|
||||
if (message) {
|
||||
serialStatus.textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
function applySerialStateFromPayload(payload = {}) {
|
||||
const connected = Boolean(payload?.connected);
|
||||
const transport = String(payload?.transport || getModbusTransport()).toLowerCase();
|
||||
const isTcp = transport === "tcp";
|
||||
const tcpAddress = payload?.address || (payload?.host || payload?.ip ? `${payload?.host || payload?.ip}:${payload?.tcpPort || payload?.tcp_port || 502}` : "");
|
||||
const port = isTcp ? (tcpAddress || payload?.port || "") : (payload?.port || payload?.selected || payload?.com || "");
|
||||
serialConnected = connected;
|
||||
selectedPort = connected && port ? port : "";
|
||||
if (comPortSelect && selectedPort) {
|
||||
comPortSelect.value = selectedPort;
|
||||
}
|
||||
if (serialStatus) {
|
||||
if (connected && selectedPort) {
|
||||
serialStatus.textContent = isTcp ? `Modbus TCP: connected (${selectedPort})` : `COM: connected (${selectedPort})`;
|
||||
serialStatus.className = "status status-ok";
|
||||
} else {
|
||||
serialStatus.textContent = isTcp ? "Modbus TCP: disconnected" : "COM: disconnected";
|
||||
serialStatus.className = "status status-warn";
|
||||
}
|
||||
}
|
||||
if (calibrateAllBtn) {
|
||||
calibrateAllBtn.disabled = !serialConnected;
|
||||
}
|
||||
setConnectButtonText();
|
||||
storageSet("comPort", selectedPort || "");
|
||||
}
|
||||
|
||||
async function loadState() {
|
||||
if (!state.apiBase) {
|
||||
buildDemos();
|
||||
simulateSensorPhysics();
|
||||
statusEl.textContent = "Режим: демо (без API)";
|
||||
statusEl.className = "status status-warn";
|
||||
globalStatus.textContent = "Демо: все изменения сохраняются в браузере";
|
||||
return;
|
||||
}
|
||||
const [sensors, valves] = await Promise.all([
|
||||
fetchCollection(API_PATHS.sensorsRead, "sensors", normalizeSensor),
|
||||
fetchCollection(API_PATHS.valvesRead, "valves", normalizeValve),
|
||||
]);
|
||||
state.sensors = sensors;
|
||||
state.valves = valves;
|
||||
statusEl.textContent = "Подключено к API";
|
||||
statusEl.className = "status status-ok";
|
||||
globalStatus.textContent = `API подключен: ${state.apiBase}`;
|
||||
}
|
||||
|
||||
function findSensorByZone(zone) {
|
||||
return state.sensors.find((s) => String(s.zone) === String(zone));
|
||||
}
|
||||
|
||||
function findValveByZone(zone) {
|
||||
return state.valves.find((v) => String(v.zone) === String(zone));
|
||||
}
|
||||
|
||||
function findSensorById(id) {
|
||||
return state.sensors.find((s) => s.id === id);
|
||||
}
|
||||
|
||||
function findValveById(id) {
|
||||
return state.valves.find((v) => v.id === id);
|
||||
}
|
||||
|
||||
function renderSensors() {
|
||||
const sensorsRoot = document.getElementById("sensors");
|
||||
if (!sensorsRoot) return;
|
||||
sensorsRoot.innerHTML = "";
|
||||
const sensorPanel = sensorsRoot.closest(".panel");
|
||||
if (sensorPanel) {
|
||||
sensorPanel.hidden = false;
|
||||
const title = sensorPanel.querySelector("h2");
|
||||
if (title) title.textContent = "Каналы обработки датчиков";
|
||||
}
|
||||
}
|
||||
|
||||
function renderValves() {
|
||||
const separateValvesRoot = document.getElementById("valves");
|
||||
if (separateValvesRoot) {
|
||||
separateValvesRoot.innerHTML = "";
|
||||
const separateValvesPanel = separateValvesRoot.closest(".panel");
|
||||
if (separateValvesPanel) separateValvesPanel.hidden = true;
|
||||
}
|
||||
|
||||
const valvesRoot = document.getElementById("sensors");
|
||||
if (!valvesRoot) return;
|
||||
valvesRoot.innerHTML = "";
|
||||
const valvePanel = valvesRoot.closest(".panel");
|
||||
if (valvePanel) {
|
||||
valvePanel.hidden = false;
|
||||
const title = valvePanel.querySelector("h2");
|
||||
if (title) title.textContent = "Каналы обработки датчиков";
|
||||
}
|
||||
|
||||
const sensorLocations = storageGet("sensorLocations", {});
|
||||
state.sensors.forEach((sensor, index) => {
|
||||
const channelNumber = index + 1;
|
||||
const openValve = state.valves[index * 2] || {};
|
||||
const closeValve = state.valves[index * 2 + 1] || {};
|
||||
const valve = openValve.id ? openValve : closeValve;
|
||||
const card = document.createElement("article");
|
||||
card.className = "item compact-item valve-item channel-card full-channel-card";
|
||||
card.dataset.id = valve.id || `valve_${channelNumber * 2 - 1}`;
|
||||
|
||||
const rawTemp = Number(sensor.value);
|
||||
const temp = Number.isFinite(rawTemp) ? rawTemp : 0;
|
||||
const tempText = Number.isFinite(rawTemp) ? temp.toFixed(1) : "--";
|
||||
let setpoint = Number(valve.targetTemp ?? sensor.setpoint ?? 28);
|
||||
const positionRaw = Number(valve.position ?? 0);
|
||||
const position = Number.isFinite(positionRaw) ? Math.max(0, Math.min(100, Math.round(positionRaw))) : 0;
|
||||
const maxDegreesRaw = Number(valve.openDegreesMax ?? DEFAULT_OPEN_DEGREES_MAX);
|
||||
const maxDegrees = Number.isFinite(maxDegreesRaw) && maxDegreesRaw > 0 ? maxDegreesRaw : DEFAULT_OPEN_DEGREES_MAX;
|
||||
const angleRaw = Number(valve.openDegrees ?? ((position / 100) * maxDegrees));
|
||||
const openDegrees = Number.isFinite(angleRaw) ? Math.max(0, Math.min(maxDegrees, Math.round(angleRaw))) : 0;
|
||||
const openActive = Boolean(openValve.isOpen || position > 0 || openDegrees > 0);
|
||||
const closeActive = Boolean(closeValve.isOpen || position <= 0);
|
||||
const connected = Boolean(valve.connected ?? valve.isConnected ?? sensor.connected ?? state.connected);
|
||||
const tempFill = Math.max(0, Math.min(100, ((temp + 5) / 55) * 100));
|
||||
const mode = valve.mode === "manual" ? "manual" : "auto";
|
||||
const modeText = mode === "manual" ? "ручной" : "авто";
|
||||
const sensorName = sensor.name || `Датчик ${channelNumber}`;
|
||||
const sensorId = sensor.id || `zone_${channelNumber}`;
|
||||
const setpointDrafts = storageGet("setpointDrafts", {});
|
||||
const draftValue = setpointDrafts[sensorId] ?? setpointDrafts[valve.id];
|
||||
if (draftValue !== undefined) {
|
||||
setpoint = parseGuiNumber(draftValue, setpoint);
|
||||
}
|
||||
const ds18b20Id = sensor.ds18b20Id || sensor.romId || sensor.rom || sensor.address || "--";
|
||||
const location = sensorLocations[sensorId] || sensor.location || defaultChannelLocation(index);
|
||||
const locationOptions = CHANNEL_LOCATIONS.map((name) => (
|
||||
`<option value="${name}" ${name === location ? "selected" : ""}>${name}</option>`
|
||||
)).join("");
|
||||
const openValveId = openValve.id || `valve_${channelNumber * 2 - 1}`;
|
||||
const closeValveId = closeValve.id || `valve_${channelNumber * 2}`;
|
||||
const openHex = (Number(String(openValveId).replace(/\D/g, "")) || channelNumber * 2 - 1).toString(16).toUpperCase().padStart(2, "0");
|
||||
const closeHex = (Number(String(closeValveId).replace(/\D/g, "")) || channelNumber * 2).toString(16).toUpperCase().padStart(2, "0");
|
||||
const setpointText = Number.isFinite(setpoint) ? setpoint.toFixed(1) : "--";
|
||||
const delta = Number.isFinite(rawTemp) && Number.isFinite(setpoint) ? temp - setpoint : NaN;
|
||||
const deltaText = Number.isFinite(delta) ? `${delta > 0 ? "+" : ""}${delta.toFixed(1)}°C` : "--";
|
||||
const deltaClass = !Number.isFinite(delta) || Math.abs(delta) <= 0.5 ? "ok" : delta > 0 ? "hot" : "cold";
|
||||
const stateText = openActive ? "открытие" : closeActive ? "закрытие" : "стоп";
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="channel-head">
|
||||
<div class="channel-title">
|
||||
<strong>Канал ${channelNumber}</strong>
|
||||
<small>${sensorName} · ${location} · зона ${sensor.zone || channelNumber}</small>
|
||||
</div>
|
||||
<span>связь <i class="channel-lamp ${connected ? "on" : "alarm"}"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="channel-id-grid full-channel-id-grid">
|
||||
<label>уставка
|
||||
<input class="targetTemp" type="number" step="0.5" value="${setpoint}">
|
||||
</label>
|
||||
<label>Расположение
|
||||
<select class="sensorLocation" data-id="${sensorId}">
|
||||
${locationOptions}
|
||||
</select>
|
||||
</label>
|
||||
<label>ID DS18B20
|
||||
<input readonly value="${ds18b20Id}">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="channel-body full-channel-body">
|
||||
<div class="temperature-widget" aria-label="Температура канала ${channelNumber}">
|
||||
<div class="temp-scale">
|
||||
<span>50</span><span>40</span><span>30</span><span>20</span><span>10</span><span>0</span><span>-5</span>
|
||||
</div>
|
||||
<div class="temp-bar"><b style="height: ${tempFill}%"></b></div>
|
||||
<div class="temp-now">${tempText}°C</div>
|
||||
</div>
|
||||
|
||||
<div class="channel-workarea">
|
||||
<div class="top-metrics-row">
|
||||
<div class="angle-panel">
|
||||
<span>угол открытия</span>
|
||||
<strong>${openDegrees}°</strong>
|
||||
<small>максимум ${Math.round(maxDegrees)}°</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="channel-data-grid full-channel-data-grid">
|
||||
<div><span>температура</span><strong>${tempText}°C</strong></div>
|
||||
<div><span>уставка</span><strong>${setpointText}°C</strong></div>
|
||||
<div><span>отклонение</span><strong class="delta ${deltaClass}">${deltaText}</strong></div>
|
||||
<div><span>расположение</span><strong>${location}</strong></div>
|
||||
<div><span>ID DS18B20</span><strong>${ds18b20Id}</strong></div>
|
||||
<div><span>режим</span><strong>${modeText}</strong></div>
|
||||
<div><span>угол/max</span><strong>${openDegrees}° / ${Math.round(maxDegrees)}°</strong></div>
|
||||
<div><span>команда</span><strong>${stateText}</strong></div>
|
||||
<div><span>связь</span><strong>${connected ? "есть" : "нет"}</strong></div>
|
||||
<div><span>канал</span><strong>${channelNumber}</strong></div>
|
||||
</div>
|
||||
|
||||
<label class="range-control channel-position">положение заслонки
|
||||
<input class="position" type="range" min="0" max="100" value="${position}">
|
||||
<strong>${position}%</strong>
|
||||
</label>
|
||||
|
||||
<div class="valve-state-row full-state-row">
|
||||
<span><i class="channel-lamp ${openActive ? "on" : "off"}"></i> клапан откр ${channelNumber}</span>
|
||||
<span><i class="channel-lamp ${closeActive ? "on" : "off"}"></i> клапан закр ${channelNumber}</span>
|
||||
</div>
|
||||
|
||||
<div class="channel-actions">
|
||||
<button class="quickPosition" data-position="100" type="button">откр ${channelNumber}</button>
|
||||
<button class="quickPosition" data-position="0" type="button">закр ${channelNumber}</button>
|
||||
</div>
|
||||
|
||||
<div class="channel-actions channel-mode-line">
|
||||
<div class="toggle channel-mode">
|
||||
<button class="modeBtn valveAuto ${mode === "auto" ? "active" : ""}" data-mode="auto" type="button">авто</button>
|
||||
<button class="modeBtn valveManual ${mode === "manual" ? "active" : ""}" data-mode="manual" type="button">ручное</button>
|
||||
</div>
|
||||
<button class="applyTarget mini-btn" type="button">SP</button>
|
||||
<button class="applyManual mini-btn" type="button">OK</button>
|
||||
<button class="calibrateValve mini-btn" type="button">CAL</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
valvesRoot.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderSensors();
|
||||
renderValves();
|
||||
}
|
||||
|
||||
async function applySetpoint(sensorId) {
|
||||
const sensor = findSensorById(sensorId);
|
||||
const input = document.querySelector(`.setpoint[data-id="${sensorId}"]`);
|
||||
const value = Number(input.value);
|
||||
if (Number.isNaN(value)) {
|
||||
updateStatus("Некорректное значение уставки", "warn");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.apiBase) {
|
||||
sensor.setpoint = value;
|
||||
storageSet("sensorState", state.sensors);
|
||||
render();
|
||||
updateStatus(`Демо: уставка ${sensor.name} = ${value.toFixed(1)} °C`, "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...writePayloadBase(sensorId, "sensor"),
|
||||
setpoint: value,
|
||||
id: sensorId,
|
||||
};
|
||||
|
||||
try {
|
||||
await sendWithFallback(API_PATHS.sensorWrite, sensorId, payload);
|
||||
await loadState();
|
||||
render();
|
||||
updateStatus(`Уставка ${sensor.name} обновлена`, "ok");
|
||||
} catch (error) {
|
||||
updateStatus(`Ошибка уставки ${sensor.name}: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function applyValveMode(valveId, mode) {
|
||||
const valve = findValveById(valveId);
|
||||
if (!valve) return;
|
||||
valve.mode = mode;
|
||||
|
||||
if (!state.apiBase) {
|
||||
storageSet("valveState", state.valves);
|
||||
render();
|
||||
updateStatus(`Демо: ${valve.name} → ${mode}`, "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
mode,
|
||||
id: valveId,
|
||||
};
|
||||
|
||||
try {
|
||||
await sendWithFallback(API_PATHS.valveWrite, valveId, payload);
|
||||
await loadState();
|
||||
render();
|
||||
updateStatus(`Режим ${valve.name}: ${mode}`, "ok");
|
||||
} catch (error) {
|
||||
updateStatus(`Ошибка режима ${valve.name}: ${error.message}`, "error");
|
||||
await loadState();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
async function applyValveTarget(valveId) {
|
||||
const valve = findValveById(valveId);
|
||||
const input = document.querySelector(`.targetTemp[data-id="${valveId}"]`);
|
||||
const value = Number(input.value);
|
||||
if (Number.isNaN(value)) {
|
||||
updateStatus("Некорректная целевая температура", "warn");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.apiBase) {
|
||||
valve.targetTemp = value;
|
||||
storageSet("valveState", state.valves);
|
||||
updateStatus(`Демо: цель ${valve.name} = ${value.toFixed(1)} °C`, "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
targetTemp: value,
|
||||
id: valveId,
|
||||
};
|
||||
|
||||
try {
|
||||
await sendWithFallback(API_PATHS.valveWrite, valveId, payload);
|
||||
await loadState();
|
||||
render();
|
||||
updateStatus(`Целевая температура ${valve.name} обновлена`, "ok");
|
||||
} catch (error) {
|
||||
updateStatus(`Ошибка цели ${valve.name}: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function applyValvePosition(valveId) {
|
||||
const valve = findValveById(valveId);
|
||||
const input = document.querySelector(`.position[data-id="${valveId}"]`);
|
||||
const value = Number(input.value);
|
||||
if (Number.isNaN(value)) {
|
||||
updateStatus("Некорректная позиция клапана", "warn");
|
||||
return;
|
||||
}
|
||||
valve.position = clamp(Math.round(value), 0, 100);
|
||||
valve.openDegrees = degreesFromPosition(valve.position, valve.openDegreesMax);
|
||||
valve.isOpen = valve.position > 0;
|
||||
|
||||
if (!state.apiBase) {
|
||||
storageSet("valveState", state.valves);
|
||||
render();
|
||||
updateStatus(`Демо: ручная позиция ${valve.name} = ${value}%`, "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
mode: "manual",
|
||||
position: valve.position,
|
||||
openDegrees: valve.openDegrees,
|
||||
openDegreesMax: valve.openDegreesMax,
|
||||
id: valveId,
|
||||
};
|
||||
|
||||
try {
|
||||
await sendWithFallback(API_PATHS.valveWrite, valveId, payload);
|
||||
await loadState();
|
||||
render();
|
||||
updateStatus(`Позиция ${valve.name} обновлена`, "ok");
|
||||
} catch (error) {
|
||||
updateStatus(`Ошибка позиции ${valve.name}: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function calibrateValve(valveId) {
|
||||
const valve = findValveById(valveId);
|
||||
if (!valve) return;
|
||||
|
||||
if (!state.apiBase) {
|
||||
valve.position = 0;
|
||||
valve.openDegrees = 0;
|
||||
valve.isOpen = false;
|
||||
storageSet("valveState", state.valves);
|
||||
render();
|
||||
updateStatus(`Демо: калибровка ${valve.name} выполнена`, "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await postWithFallback(API_PATHS.valveCalibrate, valveId, {});
|
||||
const updated = response?.valve || response;
|
||||
if (updated && updated.id) {
|
||||
const index = state.valves.findIndex((item) => item.id === valveId);
|
||||
if (index !== -1) {
|
||||
state.valves[index] = normalizeValve(updated);
|
||||
} else {
|
||||
await loadState();
|
||||
}
|
||||
} else {
|
||||
await loadState();
|
||||
}
|
||||
render();
|
||||
updateStatus(`Калибровка ${valve.name} выполнена`, "ok");
|
||||
} catch (error) {
|
||||
updateStatus(`Ошибка калибровки ${valve.name}: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function calibrateAllValves(silent = false) {
|
||||
if (!state.apiBase) {
|
||||
state.valves = state.valves.map((valve) => ({
|
||||
...valve,
|
||||
position: 0,
|
||||
openDegrees: 0,
|
||||
isOpen: false,
|
||||
}));
|
||||
render();
|
||||
if (!silent) {
|
||||
updateStatus("Демо: калибровка всех клапанов выполнена", "ok");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiPostFallback(API_PATHS.valvesCalibrateAll, {});
|
||||
const payload = Array.isArray(response?.valves) ? response.valves : null;
|
||||
if (payload) {
|
||||
state.valves = payload.map(normalizeValve);
|
||||
} else {
|
||||
await loadState();
|
||||
}
|
||||
render();
|
||||
if (!silent) {
|
||||
updateStatus("Калибровка всех клапанов выполнена", "ok");
|
||||
}
|
||||
} catch (error) {
|
||||
if (!silent) {
|
||||
updateStatus(`Ошибка калибровки всех клапанов: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function simulateSensorPhysics() {
|
||||
if (state.timer) clearInterval(state.timer);
|
||||
state.timer = setInterval(() => {
|
||||
for (const sensor of state.sensors) {
|
||||
const valve = findValveByZone(sensor.zone);
|
||||
const v = valve || {};
|
||||
let target;
|
||||
if (v.mode === "manual") {
|
||||
target = 20 + (clamp(v.position ?? 0, 0, 100) / 100) * 70;
|
||||
} else {
|
||||
target = v.targetTemp ?? sensor.setpoint ?? 30;
|
||||
}
|
||||
const drift = target - sensor.value;
|
||||
const noise = (Math.random() - 0.5) * 0.2;
|
||||
sensor.value = clamp(sensor.value + drift * 0.08 + noise, -40, 150);
|
||||
sensor.value = Number(sensor.value.toFixed(2));
|
||||
}
|
||||
for (const valve of state.valves) {
|
||||
const maxOpenDegrees = Number(valve.openDegreesMax) > 0 ? Number(valve.openDegreesMax) : DEFAULT_OPEN_DEGREES_MAX;
|
||||
valve.openDegrees = Math.round(degreesFromPosition(valve.position ?? 0, maxOpenDegrees));
|
||||
valve.isOpen = (valve.position ?? 0) > 0;
|
||||
}
|
||||
storageSet("sensorState", state.sensors);
|
||||
storageSet("valveState", state.valves);
|
||||
render();
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
function attachEvents() {
|
||||
refreshBtn.addEventListener("click", () => {
|
||||
const url = normalizeApiUrl(apiInput.value);
|
||||
state.apiBase = url;
|
||||
storageSet("apiBase", state.apiBase);
|
||||
refreshAll(true);
|
||||
refreshPorts(false);
|
||||
});
|
||||
|
||||
refreshPortsBtn.addEventListener("click", () => {
|
||||
refreshPorts();
|
||||
});
|
||||
|
||||
connectPortBtn.addEventListener("click", async () => {
|
||||
if (serialConnected) {
|
||||
await disconnectPort();
|
||||
setConnectButtonText();
|
||||
return;
|
||||
}
|
||||
await connectSelectedPort();
|
||||
setConnectButtonText();
|
||||
});
|
||||
|
||||
if (calibrateAllBtn) {
|
||||
calibrateAllBtn.addEventListener("click", () => {
|
||||
calibrateAllValves(false);
|
||||
});
|
||||
}
|
||||
|
||||
saveApiBtn.addEventListener("click", () => {
|
||||
const url = normalizeApiUrl(apiInput.value);
|
||||
state.apiBase = url;
|
||||
storageSet("apiBase", url);
|
||||
if (!url) {
|
||||
updateStatus("API отключён; переход в демо", "warn");
|
||||
statusEl.textContent = "Режим: демо (без API)";
|
||||
statusEl.className = "status status-warn";
|
||||
} else {
|
||||
updateStatus(`Сохранён API: ${state.apiBase}`, "ok");
|
||||
statusEl.textContent = "Сохранён адрес API";
|
||||
statusEl.className = "status status-ok";
|
||||
}
|
||||
render();
|
||||
refreshPorts(false);
|
||||
if (!url) {
|
||||
serialStatus.textContent = "COM: не подключён";
|
||||
serialStatus.className = "status status-warn";
|
||||
connectPortBtn.textContent = "Подключить";
|
||||
selectedPort = "";
|
||||
serialConnected = false;
|
||||
}
|
||||
});
|
||||
|
||||
sensorsEl.addEventListener("click", (event) => {
|
||||
const target = event.target;
|
||||
if (target.classList.contains("applySetpoint")) {
|
||||
applySetpoint(target.dataset.id);
|
||||
}
|
||||
});
|
||||
|
||||
valvesEl.addEventListener("click", (event) => {
|
||||
const target = event.target;
|
||||
if (target.classList.contains("modeBtn")) {
|
||||
const button = target.closest(".toggle");
|
||||
const valveId = button.dataset.id;
|
||||
const mode = target.dataset.mode;
|
||||
const card = button.closest(".item");
|
||||
if (!card) return;
|
||||
const autoBlock = card.querySelector(".valveAuto");
|
||||
const manualBlock = card.querySelector(".valveManual");
|
||||
const applyManualBtn = card.querySelector(".applyManual");
|
||||
|
||||
button.querySelectorAll(".modeBtn").forEach((b) => b.classList.remove("active"));
|
||||
target.classList.add("active");
|
||||
if (mode === "auto") {
|
||||
autoBlock.classList.remove("hidden");
|
||||
manualBlock.classList.add("hidden");
|
||||
applyManualBtn.classList.add("hidden");
|
||||
} else {
|
||||
autoBlock.classList.add("hidden");
|
||||
manualBlock.classList.remove("hidden");
|
||||
applyManualBtn.classList.remove("hidden");
|
||||
}
|
||||
applyValveMode(valveId, mode);
|
||||
}
|
||||
if (target.classList.contains("applyTarget")) {
|
||||
applyValveTarget(target.dataset.id);
|
||||
}
|
||||
if (target.classList.contains("applyManual")) {
|
||||
applyValvePosition(target.dataset.id);
|
||||
}
|
||||
if (target.classList.contains("calibrateValve")) {
|
||||
calibrateValve(target.dataset.id);
|
||||
}
|
||||
});
|
||||
|
||||
valvesEl.addEventListener("input", (event) => {
|
||||
const target = event.target;
|
||||
if (target.classList.contains("position")) {
|
||||
const label = target.closest("label");
|
||||
const span = label ? label.querySelector("strong") : null;
|
||||
if (span) span.textContent = `${target.value}%`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function refreshAll(silent = false) {
|
||||
try {
|
||||
await loadState();
|
||||
render();
|
||||
if (!silent) updateStatus("Данные обновлены", "ok");
|
||||
} catch (error) {
|
||||
if (state.apiBase) {
|
||||
statusEl.textContent = `Ошибка API: ${error.message}`;
|
||||
statusEl.className = "status status-error";
|
||||
globalStatus.textContent = "Не удалось получить данные с API. Откат в демо";
|
||||
globalStatus.className = "status-warn";
|
||||
await refreshPorts();
|
||||
render();
|
||||
} else {
|
||||
updateStatus(`Демо инициализирован: ${error.message}`, "warn");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function connectSelectedPortLegacy() {
|
||||
if (!state.apiBase) {
|
||||
updateStatus("Укажите API endpoint для работы с COM-портами", "warn");
|
||||
return;
|
||||
}
|
||||
const value = comPortSelect.value;
|
||||
if (!value) {
|
||||
updateStatus("Выберите COM порт", "warn");
|
||||
return;
|
||||
}
|
||||
const payload = { port: value, baud: 115200, baudrate: 115200, parity: "N", stopbits: 1, bytesize: 8, timeout: 0.3 };
|
||||
try {
|
||||
await apiPostFallback(SERIAL_API_PATHS.connect, payload);
|
||||
selectedPort = value;
|
||||
serialConnected = true;
|
||||
storageSet("comPort", value);
|
||||
serialStatus.textContent = `COM: подключен (${value})`;
|
||||
serialStatus.className = "status status-ok";
|
||||
connectPortBtn.textContent = "Отключить";
|
||||
updateStatus(`COM ${value} подключен`, "ok");
|
||||
} catch (error) {
|
||||
serialConnected = false;
|
||||
serialStatus.textContent = "COM: ошибка подключения";
|
||||
serialStatus.className = "status status-error";
|
||||
connectPortBtn.textContent = "Подключить";
|
||||
storageSet("comPort", "");
|
||||
selectedPort = "";
|
||||
updateStatus(`Ошибка подключения COM: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function disconnectPortLegacy() {
|
||||
if (!state.apiBase) return;
|
||||
try {
|
||||
await apiPostFallback(SERIAL_API_PATHS.disconnect, {});
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
serialConnected = false;
|
||||
selectedPort = "";
|
||||
storageSet("comPort", "");
|
||||
serialStatus.textContent = "COM: не подключен";
|
||||
serialStatus.className = "status status-warn";
|
||||
connectPortBtn.textContent = "Подключить";
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreSerialUiLegacy() {
|
||||
if (!state.apiBase) return;
|
||||
try {
|
||||
const status = await apiGetFallback(SERIAL_API_PATHS.status);
|
||||
serialConnected = Boolean(status?.connected);
|
||||
const port = status?.port || status?.selected;
|
||||
if (serialConnected && port) {
|
||||
selectedPort = port;
|
||||
comPortSelect.value = selectedPort;
|
||||
serialStatus.textContent = `COM: подключен (${selectedPort})`;
|
||||
serialStatus.className = "status status-ok";
|
||||
connectPortBtn.textContent = "Отключить";
|
||||
storageSet("comPort", selectedPort);
|
||||
} else {
|
||||
selectedPort = "";
|
||||
storageSet("comPort", "");
|
||||
serialStatus.textContent = "COM: не подключен";
|
||||
serialStatus.className = "status status-warn";
|
||||
connectPortBtn.textContent = "Подключить";
|
||||
}
|
||||
} catch {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshPorts(silent = false) {
|
||||
if (!state.apiBase) {
|
||||
ensureApiBase();
|
||||
}
|
||||
if (!state.apiBase) {
|
||||
if (!silent) {
|
||||
updateStatus("Set API base URL first", "warn");
|
||||
}
|
||||
return;
|
||||
}
|
||||
setSerialBusyState(true, "Scanning COM ports...");
|
||||
try {
|
||||
const payload = await fetchComPorts();
|
||||
const ports = Array.isArray(payload?.ports) ? payload.ports : [];
|
||||
const preferredPort = payload?.selected || selectedPort || storageGet("comPort", "");
|
||||
applyPortOptions(ports, preferredPort);
|
||||
if (!silent) {
|
||||
updateStatus(
|
||||
ports.length ? `Found COM ports: ${ports.length}` : "No COM ports found",
|
||||
ports.length ? "ok" : "warn"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
applyPortOptions([], "");
|
||||
updateStatus(`Port scan error: ${error.message}`, "error");
|
||||
} finally {
|
||||
setSerialBusyState(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function connectSelectedPort() {
|
||||
if (!state.apiBase) {
|
||||
updateStatus("Set API base URL first", "warn");
|
||||
return;
|
||||
}
|
||||
const requestedPort = comPortSelect.value;
|
||||
if (!requestedPort) {
|
||||
updateStatus("Select COM port", "warn");
|
||||
return;
|
||||
}
|
||||
setSerialBusyState(true, `Connecting ${requestedPort}...`);
|
||||
try {
|
||||
const payload = {
|
||||
port: requestedPort,
|
||||
baud: 115200,
|
||||
baudrate: 115200,
|
||||
parity: "N",
|
||||
stopBits: 1,
|
||||
stopbits: 1,
|
||||
byteSize: 8,
|
||||
bytesize: 8,
|
||||
timeout: 0.3,
|
||||
};
|
||||
const status = await apiPostFallback(SERIAL_API_PATHS.connect, payload);
|
||||
applySerialStateFromPayload({
|
||||
connected: true,
|
||||
port: status?.port || requestedPort,
|
||||
selected: status?.selected || requestedPort,
|
||||
});
|
||||
await calibrateAllValves(true);
|
||||
updateStatus(`COM ${requestedPort} connected`, "ok");
|
||||
await refreshPorts(true);
|
||||
} catch (error) {
|
||||
applySerialStateFromPayload({ connected: false });
|
||||
updateStatus(`COM connect error: ${error.message}`, "error");
|
||||
} finally {
|
||||
setSerialBusyState(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function connectRtuPort() {
|
||||
if (!state.apiBase) {
|
||||
updateStatus("Укажи API endpoint для Modbus RTU", "warn");
|
||||
return;
|
||||
}
|
||||
|
||||
const value = comPortSelect?.value || selectedPort;
|
||||
if (!value) {
|
||||
updateStatus("Выберите COM порт", "warn");
|
||||
return;
|
||||
}
|
||||
|
||||
const unitId = Number(modbusSlaveId?.value || 3);
|
||||
storageSet("modbusTransport", "rtu");
|
||||
storageSet("comPort", value);
|
||||
storageSet("modbusSlaveId", String(unitId));
|
||||
setSerialBusyState(true, `Modbus RTU: подключение ${value}, slave ${unitId}...`);
|
||||
try {
|
||||
const status = await apiPostFallback(SERIAL_API_PATHS.connect, {
|
||||
transport: "rtu",
|
||||
mode: "rtu",
|
||||
port: value,
|
||||
baud: 115200,
|
||||
baudrate: 115200,
|
||||
parity: "N",
|
||||
stopbits: 1,
|
||||
bytesize: 8,
|
||||
timeout: 0.8,
|
||||
unitId,
|
||||
slaveId: unitId,
|
||||
});
|
||||
applySerialStateFromPayload({
|
||||
...(status || {}),
|
||||
connected: Boolean(status?.connected ?? status?.ok),
|
||||
transport: "rtu",
|
||||
port: value,
|
||||
});
|
||||
updateStatus(`Modbus RTU connected: ${value}, slave ${unitId}`, "ok");
|
||||
} catch (error) {
|
||||
applySerialStateFromPayload({ connected: false, transport: "rtu" });
|
||||
updateStatus(`Modbus RTU error: ${error.message}`, "error");
|
||||
} finally {
|
||||
setSerialBusyState(false);
|
||||
applyModbusTransportView();
|
||||
}
|
||||
}
|
||||
|
||||
async function connectTcpPort() {
|
||||
if (!state.apiBase) {
|
||||
updateStatus("Укажи API endpoint для Modbus TCP", "warn");
|
||||
return;
|
||||
}
|
||||
|
||||
const host = (tcpHost?.value || "").trim();
|
||||
const port = Number(tcpPort?.value || 502);
|
||||
const unitId = Number(modbusSlaveId?.value || 3);
|
||||
if (!host) {
|
||||
updateStatus("Укажи IP адрес Modbus TCP", "warn");
|
||||
return;
|
||||
}
|
||||
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
||||
updateStatus("Некорректный TCP порт", "warn");
|
||||
return;
|
||||
}
|
||||
|
||||
storageSet("modbusTransport", "tcp");
|
||||
storageSet("tcpHost", host);
|
||||
storageSet("tcpPort", String(port));
|
||||
storageSet("modbusSlaveId", String(unitId));
|
||||
setSerialBusyState(true, `Modbus TCP: подключение ${host}:${port}, slave ${unitId}...`);
|
||||
try {
|
||||
const status = await apiPostFallback(SERIAL_API_PATHS.connect, {
|
||||
transport: "tcp",
|
||||
mode: "tcp",
|
||||
host,
|
||||
ip: host,
|
||||
tcpPort: port,
|
||||
tcp_port: port,
|
||||
port,
|
||||
unitId,
|
||||
slaveId: unitId,
|
||||
timeout: 0.8,
|
||||
});
|
||||
applySerialStateFromPayload({
|
||||
...(status || {}),
|
||||
connected: Boolean(status?.connected ?? status?.ok),
|
||||
transport: "tcp",
|
||||
host,
|
||||
tcpPort: port,
|
||||
address: `${host}:${port}`,
|
||||
});
|
||||
updateStatus(`Modbus TCP connected: ${host}:${port}, slave ${unitId}`, "ok");
|
||||
} catch (error) {
|
||||
applySerialStateFromPayload({ connected: false, transport: "tcp" });
|
||||
updateStatus(`Modbus TCP error: ${error.message}`, "error");
|
||||
} finally {
|
||||
setSerialBusyState(false);
|
||||
applyModbusTransportView();
|
||||
}
|
||||
}
|
||||
|
||||
if (connectPortBtn) {
|
||||
connectPortBtn.addEventListener("click", async (event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
if (serialConnected) {
|
||||
await disconnectPort();
|
||||
setConnectButtonText();
|
||||
applyModbusTransportView();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getModbusTransport() === "tcp") {
|
||||
await connectTcpPort();
|
||||
} else {
|
||||
await connectRtuPort();
|
||||
}
|
||||
setConnectButtonText();
|
||||
}, true);
|
||||
}
|
||||
|
||||
async function disconnectPort() {
|
||||
if (!state.apiBase) {
|
||||
applySerialStateFromPayload({ connected: false });
|
||||
return;
|
||||
}
|
||||
setSerialBusyState(true, "Disconnecting...");
|
||||
try {
|
||||
const status = await apiPostFallback(SERIAL_API_PATHS.disconnect, {});
|
||||
applySerialStateFromPayload(status || { connected: false });
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
applySerialStateFromPayload({ connected: false });
|
||||
setSerialBusyState(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreSerialUi() {
|
||||
if (!state.apiBase) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const status = await apiGetFallback(SERIAL_API_PATHS.status);
|
||||
applySerialStateFromPayload(status);
|
||||
if (status?.connected) {
|
||||
await calibrateAllValves(true);
|
||||
}
|
||||
} catch {
|
||||
applySerialStateFromPayload({ connected: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Channel location selector
|
||||
document.addEventListener("change", (event) => {
|
||||
const select = event.target.closest(".sensorLocation");
|
||||
if (!select) return;
|
||||
|
||||
const sensorId = select.dataset.id;
|
||||
const sensor = state.sensors.find((item) => item.id === sensorId);
|
||||
if (sensor) {
|
||||
sensor.location = select.value;
|
||||
storageSet("sensorState", state.sensors);
|
||||
}
|
||||
|
||||
const locations = storageGet("sensorLocations", {});
|
||||
locations[sensorId] = select.value;
|
||||
storageSet("sensorLocations", locations);
|
||||
|
||||
render();
|
||||
});
|
||||
|
||||
// Controls inside sensor processing channel cards
|
||||
document.addEventListener("input", (event) => {
|
||||
const targetInput = event.target.closest(".full-channel-card .targetTemp");
|
||||
if (targetInput) {
|
||||
const card = targetInput.closest(".full-channel-card");
|
||||
const valveId = card?.dataset.id;
|
||||
const targetTemp = parseGuiNumber(targetInput.value, 0);
|
||||
const valve = state.valves.find((item) => item.id === valveId);
|
||||
if (valve) {
|
||||
valve.targetTemp = targetTemp;
|
||||
}
|
||||
|
||||
const valveNumber = Number(String(valveId || "").replace(/\D/g, "")) || 1;
|
||||
const sensorIndex = Math.max(0, Math.floor((valveNumber - 1) / 2));
|
||||
const sensor = state.sensors[sensorIndex];
|
||||
if (sensor) {
|
||||
sensor.setpoint = targetTemp;
|
||||
}
|
||||
|
||||
const setpointDrafts = storageGet("setpointDrafts", {});
|
||||
if (sensor?.id) {
|
||||
setpointDrafts[sensor.id] = targetInput.value;
|
||||
}
|
||||
if (valveId) {
|
||||
setpointDrafts[valveId] = targetInput.value;
|
||||
}
|
||||
storageSet("setpointDrafts", setpointDrafts);
|
||||
storageSet("sensorState", state.sensors);
|
||||
storageSet("valveState", state.valves);
|
||||
return;
|
||||
}
|
||||
|
||||
const positionInput = event.target.closest(".full-channel-card .position");
|
||||
if (!positionInput) return;
|
||||
const label = positionInput.closest("label");
|
||||
const value = Number(positionInput.value || 0);
|
||||
const strong = label?.querySelector("strong");
|
||||
if (strong) strong.textContent = `${value}%`;
|
||||
});
|
||||
|
||||
document.addEventListener("click", async (event) => {
|
||||
const button = event.target.closest(".full-channel-card button");
|
||||
if (!button) return;
|
||||
|
||||
const card = button.closest(".full-channel-card");
|
||||
const valveId = card?.dataset.id;
|
||||
if (!card || !valveId) return;
|
||||
|
||||
if (button.classList.contains("modeBtn")) {
|
||||
const mode = button.dataset.mode === "manual" ? "manual" : "auto";
|
||||
card.querySelectorAll(".modeBtn").forEach((item) => item.classList.remove("active"));
|
||||
button.classList.add("active");
|
||||
const valve = state.valves.find((item) => item.id === valveId);
|
||||
if (valve) valve.mode = mode;
|
||||
storageSet("valveState", state.valves);
|
||||
await sendWithFallback(API_PATHS.valveWrite, valveId, {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
id: valveId,
|
||||
mode,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (button.classList.contains("applyTarget")) {
|
||||
const targetInput = card.querySelector(".targetTemp");
|
||||
const targetTemp = parseGuiNumber(targetInput?.value, 0);
|
||||
const valve = state.valves.find((item) => item.id === valveId);
|
||||
if (valve) valve.targetTemp = targetTemp;
|
||||
const valveNumber = Number(String(valveId || "").replace(/\D/g, "")) || 1;
|
||||
const sensorIndex = Math.max(0, Math.floor((valveNumber - 1) / 2));
|
||||
const sensor = state.sensors[sensorIndex];
|
||||
if (sensor) sensor.setpoint = targetTemp;
|
||||
const setpointDrafts = storageGet("setpointDrafts", {});
|
||||
if (sensor?.id) {
|
||||
setpointDrafts[sensor.id] = targetInput?.value ?? String(targetTemp);
|
||||
}
|
||||
setpointDrafts[valveId] = targetInput?.value ?? String(targetTemp);
|
||||
storageSet("setpointDrafts", setpointDrafts);
|
||||
storageSet("sensorState", state.sensors);
|
||||
storageSet("valveState", state.valves);
|
||||
await sendWithFallback(API_PATHS.valveWrite, valveId, {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
id: valveId,
|
||||
targetTemp,
|
||||
});
|
||||
await loadState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (button.classList.contains("applyManual")) {
|
||||
const positionInput = card.querySelector(".position");
|
||||
const position = Number(positionInput?.value || 0);
|
||||
const valve = state.valves.find((item) => item.id === valveId);
|
||||
if (valve) {
|
||||
valve.position = position;
|
||||
valve.isOpen = position > 0;
|
||||
}
|
||||
storageSet("valveState", state.valves);
|
||||
await sendWithFallback(API_PATHS.valveWrite, valveId, {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
id: valveId,
|
||||
position,
|
||||
});
|
||||
await loadState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (button.classList.contains("calibrateValve")) {
|
||||
await postWithFallback(API_PATHS.valveCalibrate, valveId, {
|
||||
...writePayloadBase(valveId, "valve"),
|
||||
id: valveId,
|
||||
});
|
||||
await loadState();
|
||||
}
|
||||
});
|
||||
|
||||
// Quick manual open/close buttons for channel cards
|
||||
document.addEventListener("click", (event) => {
|
||||
const quickButton = event.target.closest(".quickPosition");
|
||||
if (!quickButton) return;
|
||||
|
||||
const card = quickButton.closest(".valve-item");
|
||||
if (!card) return;
|
||||
|
||||
const manualButton = card.querySelector(".valveManual");
|
||||
if (manualButton && !manualButton.classList.contains("active")) {
|
||||
manualButton.click();
|
||||
}
|
||||
|
||||
const positionInput = card.querySelector(".position");
|
||||
if (positionInput) {
|
||||
positionInput.value = quickButton.dataset.position || "0";
|
||||
positionInput.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
}
|
||||
|
||||
const applyButton = card.querySelector(".applyManual");
|
||||
if (applyButton) applyButton.click();
|
||||
});
|
||||
window.addEventListener("load", async () => {
|
||||
apiInput.value = storageGet("apiBase", "");
|
||||
state.apiBase = normalizeApiUrl(apiInput.value);
|
||||
initModbusTransportControls();
|
||||
ensureApiBase();
|
||||
selectedPort = storageGet("comPort", "");
|
||||
attachEvents();
|
||||
await refreshAll(true);
|
||||
if (getModbusTransport() !== "tcp") {
|
||||
await refreshPorts(true);
|
||||
}
|
||||
render();
|
||||
if (selectedPort) {
|
||||
comPortSelect.value = selectedPort;
|
||||
}
|
||||
await restoreSerialUi();
|
||||
setInterval(() => {
|
||||
if (state.apiBase) {
|
||||
loadState().then(render).catch(() => {});
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Тепло и клапаны — управление</title>
|
||||
<link rel="stylesheet" href="styles.css?v=20260625-ds18b20-id-1" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<header class="header">
|
||||
<h1>Панель температуры и клапанов</h1>
|
||||
<p>Мониторинг датчиков, управление уставками и ручным/авто управлением клапанов.</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<label for="apiBase">API endpoint</label>
|
||||
<div class="api-row">
|
||||
<input id="apiBase" placeholder="http://127.0.0.1:1923 (пусто = демо)" value="" />
|
||||
<button id="refreshBtn">Обновить</button>
|
||||
<button id="saveApiBtn">Сохранить адрес API</button>
|
||||
<span id="status" class="status">Режим: не подключен</span>
|
||||
</div>
|
||||
<p class="hint">Если API не задан, интерфейс работает в автономном демо-режиме с локальным хранением.</p>
|
||||
<div class="serial-block">
|
||||
<div class="serial-row">
|
||||
|
||||
<label for="modbusTransport">Обмен</label>
|
||||
<select id="modbusTransport">
|
||||
<option value="rtu">Modbus RTU / COM</option>
|
||||
<option value="tcp">Modbus TCP / IP</option>
|
||||
</select>
|
||||
<label for="modbusSlaveId">Slave ID</label>
|
||||
<input id="modbusSlaveId" type="number" min="1" max="247" value="3">
|
||||
</select>
|
||||
<label class="rtu-field" for="comPortSelect">COM порт</label>
|
||||
<select id="comPortSelect" class="rtu-field">
|
||||
<option value="">Порт не выбран</option>
|
||||
</select>
|
||||
<button id="refreshPortsBtn" class="rtu-field">Обновить порты</button>
|
||||
<label class="tcp-field hidden" for="tcpHost">IP</label>
|
||||
<input id="tcpHost" class="tcp-field hidden" type="text" value="192.168.0.10" placeholder="192.168.0.10">
|
||||
<label class="tcp-field hidden" for="tcpPort">TCP порт</label>
|
||||
<input id="tcpPort" class="tcp-field hidden" type="number" min="1" max="65535" value="502">
|
||||
<button id="connectPortBtn">Подключить</button>
|
||||
<button id="calibrateAllBtn">Калибровать все</button>
|
||||
<span id="serialStatus" class="status status-warn">COM: не подключён</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel grid">
|
||||
<article class="card">
|
||||
<h2>Датчики температуры</h2>
|
||||
<div id="sensors" class="list"></div>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<h2>Клапаны</h2>
|
||||
<div id="valves" class="list"></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<footer class="footer">
|
||||
<span>Статус: </span>
|
||||
<span id="globalStatus">Ожидание...</span>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="app.js?v=20260625-setpoint-draft-1"></script>
|
||||
</body>
|
||||
</html>
|
||||
+1
@@ -0,0 +1 @@
|
||||
F:\set\workspace\setcorp\set506\git_project\ds128b20\new rev\john103C8T6\.codex-restored-sessions\codex_sessions_restored_20260609132029
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Restored Codex sessions
|
||||
|
||||
Source archive: `C:\Users\z\Documents\Codex\2026-06-09\c-users-z-codex-sessions\outputs\codex_sessions_restored_20260609132029`
|
||||
Project CWD: `F:\set\workspace\setcorp\set506\git_project\ds128b20\new rev\john103C8T6`
|
||||
Generated copy: `2026-06-09T16:29:15.1490867+03:00`
|
||||
|
||||
## Dialogues
|
||||
|
||||
| Started | Title | Transcript |
|
||||
|---|---|---|
|
||||
| 2026-05-28T16:32:05.792Z | собери проект убери ошибки ,если нужны библиотеки подтяни их уровнем выше | [transcript](transcripts/001_14220bef_session.md) |
|
||||
| 2026-05-28T16:47:52.141Z | настроить RTC с календарем и backup в modbuds сделать регистр времени часы минуты секунды дата | [transcript](transcripts/002_a30c80b2_RTC_backup_modbuds.md) |
|
||||
|
||||
## Restored files from patch records
|
||||
|
||||
Recovered embedded file contents, if any, are in `files_from_patches/`. Original project files were not overwritten.
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,53 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file dma.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the dma.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __DMA_H__
|
||||
#define __DMA_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* DMA memory to memory transfer handles -------------------------------------*/
|
||||
extern DMA_HandleTypeDef hdma_memtomem_dma1_channel1;
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_DMA_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DMA_H__ */
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
***************************************************************
|
||||
* 1 2 3 4 5 6 7 8 *
|
||||
* --- +++ *
|
||||
* *
|
||||
*****************************************************************
|
||||
|
||||
|
||||
******************************************************************************
|
||||
* @file : main.h
|
||||
* @brief : Header for main.c file.
|
||||
* This file contains the common defines of the application.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __MAIN_H
|
||||
#define __MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "Proj_setup.h"
|
||||
#include "dallas_tools.h"
|
||||
#include "modbus.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FuncOK=0,
|
||||
FuncERROR=1
|
||||
|
||||
}FuncStat;
|
||||
|
||||
|
||||
typedef enum {
|
||||
CONFIG_DEVICE_ID = 0,
|
||||
CONFIG_BAUDRATE,
|
||||
CONFIG_CALIBRATION,
|
||||
CONFIG_SETTINGS
|
||||
} ConfigParams;
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
STATE_OPEN_VALVE = 0, // open
|
||||
STATE_CLOSE_VALVE= 1 // close
|
||||
} ValveState;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t id[2];
|
||||
float temp;
|
||||
uint16_t location;
|
||||
uint8_t t_open;
|
||||
float t_set;
|
||||
uint8_t t_close;
|
||||
uint8_t status_T_sense:1 ;
|
||||
ValveState state;
|
||||
uint16_t count;
|
||||
}TEMP_TypeDef;
|
||||
typedef struct {
|
||||
uint32_t init_tsens : 1; // Update Interrupt Flag (бит 0) — флаг переполнения/обновления
|
||||
|
||||
// ... (другие биты могут быть зарезервированы или использоваться в расширенных таймерах)
|
||||
} Flags_TypeDef;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN ET */
|
||||
#define reset_blink_delay 50
|
||||
#define rest_iter 10
|
||||
#define GPIOB11_valve MB_DATA.Coils.coils[0].state_val_bit.state_val_01
|
||||
#define ralay_5v_on GPIOA->ODR&(1<<10);
|
||||
|
||||
|
||||
|
||||
extern void handle_command(char* cmd);
|
||||
typedef void (*FunctionPointer)(void);
|
||||
|
||||
uint16_t handle_valves(TEMP_TypeDef* temp_sense[MAX_SENSE]);
|
||||
void init_setpoint_all_T_sense(TEMP_TypeDef* temp_sense, int size_array);
|
||||
void iwdg_refresh(void);
|
||||
void led_blink(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,uint8_t iter,uint16_t delay);
|
||||
FuncStat Field_modbus(MB_DataStructureTypeDef* MB_DATA, Flags_TypeDef* flag);
|
||||
FuncStat packStruct(MB_DataStructureTypeDef* MB_DATA,int sizeARR);
|
||||
void Check_Tconnect(MB_DataStructureTypeDef* MB_DATA, Flags_TypeDef* flag ,DALLAS_HandleTypeDef* hdallas, int a[50]);
|
||||
FuncStat value_control(void );
|
||||
|
||||
void reinit_t_sens(void);
|
||||
HAL_StatusTypeDef ModbusMaster_Request(RS_MsgTypeDef *request,
|
||||
void (*callback)(RS_HandleTypeDef *, RS_MsgTypeDef *));
|
||||
|
||||
/* USER CODE END ET */
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EC */
|
||||
|
||||
/* USER CODE END EC */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EM */
|
||||
|
||||
/* USER CODE END EM */
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
void Error_Handler(void);
|
||||
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
||||
/* USER CODE END EFP */
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
#define Relay_dc5v_Pin GPIO_PIN_10
|
||||
#define Relay_dc5v_GPIO_Port GPIOA
|
||||
#define One_wire_Pin GPIO_PIN_15
|
||||
#define One_wire_GPIO_Port GPIOA
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAIN_H */
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ow_port.h
|
||||
* @brief This file includes the driver for port for OneWire purposes
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef ONEWIRE_PORT_H
|
||||
#define ONEWIRE_PORT_H
|
||||
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
/* I/O Port ------------------------------------------------------------------*/
|
||||
//#define LL_Driver ///< использовать CMSIS для управления ножкой
|
||||
#define CMSIS_Driver ///< использовать CMSIS для управления ножкой
|
||||
// если ничего не выбрано - используется HAL
|
||||
|
||||
|
||||
/**
|
||||
* @def OW_GPIO_Port
|
||||
* @brief Порт вывода для шины 1-Wire.
|
||||
* @details Указывает порт GPIO, к которому подключена линия данных 1-Wire (например, для DS18B20).
|
||||
*/
|
||||
#define OW_GPIO_Port GPIOA
|
||||
|
||||
/**
|
||||
* @def OW_Pin_Numb
|
||||
* @brief Номер пина в порту OW_GPIO_Port.
|
||||
* @details Используется для формирования маски пина и настройки ввода/вывода.
|
||||
*/
|
||||
#define OW_Pin_Numb 15
|
||||
|
||||
/**
|
||||
* @def OW_Pin
|
||||
* @brief Маска пина, соответствующая номеру OW_Pin_Numb.
|
||||
* @details Используется при доступе к регистрам порта для управления состоянием линии 1-Wire.
|
||||
*/
|
||||
#define OW_Pin (1<<OW_Pin_Numb)
|
||||
|
||||
/**
|
||||
* @def OW_TIM
|
||||
* @brief Аппаратный таймер для формирования временных интервалов протокола 1-Wire.
|
||||
* @details Применяется для создания точных задержек при обмене данными по шине 1-Wire.
|
||||
*/
|
||||
#define OW_TIM TIM1
|
||||
|
||||
/**
|
||||
* @def OW_TIM_1US_PERIOD
|
||||
* @brief Количество тактов таймера OW_TIM, соответствующее 1 микросекунде.
|
||||
* @details Вычисляется на основе частоты таймера. Например, для таймера с частотой 24 МГц значение будет равно 24.
|
||||
*/
|
||||
#define OW_TIM_1US_PERIOD 72
|
||||
|
||||
|
||||
/* OneWire Timings -----------------------------------------------------------*/
|
||||
void OneWire_Delay_us(uint32_t us);
|
||||
/* Common Register -----------------------------------------------------------*/
|
||||
#endif /* ONEWIRE_PORT_H */
|
||||
@@ -0,0 +1,65 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the rtc.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __RTC_H__
|
||||
#define __RTC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t hours;
|
||||
uint16_t minutes;
|
||||
uint16_t seconds;
|
||||
uint16_t date;
|
||||
uint16_t month;
|
||||
uint16_t year;
|
||||
uint16_t weekday;
|
||||
} RTC_CalendarTypeDef;
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_RTC_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
uint8_t RTC_CalendarIsValid(const RTC_CalendarTypeDef *calendar);
|
||||
HAL_StatusTypeDef RTC_CalendarGet(RTC_CalendarTypeDef *calendar);
|
||||
HAL_StatusTypeDef RTC_CalendarSet(const RTC_CalendarTypeDef *calendar);
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RTC_H__ */
|
||||
|
||||
@@ -0,0 +1,605 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_hal_conf.h
|
||||
* @author MCD Application Team
|
||||
* @brief HAL configuration file.
|
||||
*
|
||||
* @note modified by ARM
|
||||
* The modifications allow to use this file as User Code Template
|
||||
* within the Device Family Pack.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F4xx_HAL_CONF_H
|
||||
#define __STM32F4xx_HAL_CONF_H
|
||||
|
||||
#ifdef _RTE_
|
||||
#include "RTE_Components.h" /* Component selection */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/* ########################## Module Selection ############################## */
|
||||
/**
|
||||
* @brief This is the list of modules to be used in the HAL driver
|
||||
*/
|
||||
#ifdef RTE_DEVICE_HAL_COMMON
|
||||
#define HAL_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_ADC
|
||||
#define HAL_ADC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_CAN
|
||||
#define HAL_CAN_MODULE_ENABLED
|
||||
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_CRC
|
||||
#define HAL_CRC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_CEC
|
||||
#define HAL_CEC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_CRYP
|
||||
#define HAL_CRYP_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_DAC
|
||||
#define HAL_DAC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_DCMI
|
||||
#define HAL_DCMI_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_DMA
|
||||
#define HAL_DMA_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_DMA2D
|
||||
#define HAL_DMA2D_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_ETH
|
||||
#define HAL_ETH_MODULE_ENABLED
|
||||
#endif
|
||||
#if defined (RTE_DEVICE_HAL_FLASH) || defined (RTE_DEVICE_HAL_COMMON)
|
||||
#define HAL_FLASH_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_NAND
|
||||
#define HAL_NAND_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_NOR
|
||||
#define HAL_NOR_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_PCCARD
|
||||
#define HAL_PCCARD_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SRAM
|
||||
#define HAL_SRAM_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SDRAM
|
||||
#define HAL_SDRAM_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_HASH
|
||||
#define HAL_HASH_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_GPIO
|
||||
#define HAL_GPIO_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_EXTI
|
||||
#define HAL_EXTI_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_I2C
|
||||
#define HAL_I2C_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SMBUS
|
||||
#define HAL_SMBUS_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_I2S
|
||||
#define HAL_I2S_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_IWDG
|
||||
#define HAL_IWDG_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_LTDC
|
||||
#define HAL_LTDC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_DSI
|
||||
#define HAL_DSI_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_PWR
|
||||
#define HAL_PWR_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_QSPI
|
||||
#define HAL_QSPI_MODULE_ENABLED
|
||||
#endif
|
||||
#if defined (RTE_DEVICE_HAL_RCC) || defined (RTE_DEVICE_HAL_COMMON)
|
||||
#define HAL_RCC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_RNG
|
||||
#define HAL_RNG_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_RTC
|
||||
#define HAL_RTC_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SAI
|
||||
#define HAL_SAI_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SD
|
||||
#define HAL_SD_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SPI
|
||||
#define HAL_SPI_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_TIM
|
||||
#define HAL_TIM_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_UART
|
||||
#define HAL_UART_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_USART
|
||||
#define HAL_USART_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_IRDA
|
||||
#define HAL_IRDA_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SMARTCARD
|
||||
#define HAL_SMARTCARD_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_WWDG
|
||||
#define HAL_WWDG_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_CORTEX
|
||||
#define HAL_CORTEX_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_PCD
|
||||
#define HAL_PCD_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_HCD
|
||||
#define HAL_HCD_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_FMPI2C
|
||||
#define HAL_FMPI2C_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_FMPSMBUS
|
||||
#define HAL_FMPSMBUS_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_SPDIFRX
|
||||
#define HAL_SPDIFRX_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_DFSDM
|
||||
#define HAL_DFSDM_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_LPTIM
|
||||
#define HAL_LPTIM_MODULE_ENABLED
|
||||
#endif
|
||||
#ifdef RTE_DEVICE_HAL_MMC
|
||||
#define HAL_MMC_MODULE_ENABLED
|
||||
#endif
|
||||
|
||||
/* ########################## HSE/HSI Values adaptation ##################### */
|
||||
/**
|
||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSE is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSE_STARTUP_TIMEOUT)
|
||||
#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
|
||||
#endif /* HSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief Internal High Speed oscillator (HSI) value.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSI is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz */
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @brief Internal Low Speed oscillator (LSI) value.
|
||||
*/
|
||||
#if !defined (LSI_VALUE)
|
||||
#define LSI_VALUE 32000U /*!< LSI Typical Value in Hz */
|
||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
||||
The real value may vary depending on the variations
|
||||
in voltage and temperature. */
|
||||
/**
|
||||
* @brief External Low Speed oscillator (LSE) value.
|
||||
*/
|
||||
#if !defined (LSE_VALUE)
|
||||
#define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */
|
||||
#endif /* LSE_VALUE */
|
||||
|
||||
#if !defined (LSE_STARTUP_TIMEOUT)
|
||||
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
|
||||
#endif /* LSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief External clock source for I2S peripheral
|
||||
* This value is used by the I2S HAL module to compute the I2S clock source
|
||||
* frequency, this source is inserted directly through I2S_CKIN pad.
|
||||
*/
|
||||
#if !defined (EXTERNAL_CLOCK_VALUE)
|
||||
#define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External oscillator in Hz*/
|
||||
#endif /* EXTERNAL_CLOCK_VALUE */
|
||||
|
||||
/* Tip: To avoid modifying this file each time you need to use different HSE,
|
||||
=== you can define the HSE value in your toolchain compiler preprocessor. */
|
||||
|
||||
/* ########################### System Configuration ######################### */
|
||||
/**
|
||||
* @brief This is the HAL system configuration section
|
||||
*/
|
||||
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
|
||||
#define TICK_INT_PRIORITY 0x0FU /*!< tick interrupt priority */
|
||||
#define USE_RTOS 0U
|
||||
#define PREFETCH_ENABLE 0U /* The prefetch will be enabled in SystemClock_Config(), depending on the used
|
||||
STM32F405/415/07/417 device: RevA (prefetch must be off) or RevZ (prefetch can be on/off) */
|
||||
#define INSTRUCTION_CACHE_ENABLE 1U
|
||||
#define DATA_CACHE_ENABLE 1U
|
||||
|
||||
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
|
||||
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
|
||||
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
|
||||
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
|
||||
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
|
||||
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
|
||||
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
|
||||
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
|
||||
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
|
||||
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
|
||||
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
|
||||
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
|
||||
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
|
||||
#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */
|
||||
#define USE_HAL_FMPSMBUS_REGISTER_CALLBACKS 0U /* FMPSMBUS register callback disabled */
|
||||
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
|
||||
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
|
||||
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
|
||||
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
|
||||
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
|
||||
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
|
||||
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
|
||||
#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */
|
||||
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
|
||||
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
|
||||
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
|
||||
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
|
||||
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
|
||||
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
|
||||
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
|
||||
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
|
||||
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
|
||||
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
|
||||
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
|
||||
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
|
||||
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
|
||||
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
|
||||
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
|
||||
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
|
||||
|
||||
/* ########################## Assert Selection ############################## */
|
||||
/**
|
||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the
|
||||
* HAL drivers code
|
||||
*/
|
||||
/* #define USE_FULL_ASSERT 1U */
|
||||
|
||||
/* ################## Ethernet peripheral configuration ##################### */
|
||||
|
||||
/* Section 1 : Ethernet peripheral configuration */
|
||||
|
||||
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
|
||||
#define MAC_ADDR0 2U
|
||||
#define MAC_ADDR1 0U
|
||||
#define MAC_ADDR2 0U
|
||||
#define MAC_ADDR3 0U
|
||||
#define MAC_ADDR4 0U
|
||||
#define MAC_ADDR5 0U
|
||||
|
||||
/* Definition of the Ethernet driver buffers size and count */
|
||||
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
|
||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
|
||||
#define ETH_RXBUFNB 4U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
|
||||
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
|
||||
|
||||
/* Section 2: PHY configuration section */
|
||||
|
||||
/* DP83848 PHY Address*/
|
||||
#define DP83848_PHY_ADDRESS 0x01U
|
||||
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
|
||||
#define PHY_RESET_DELAY 0x000000FFU
|
||||
/* PHY Configuration delay */
|
||||
#define PHY_CONFIG_DELAY 0x00000FFFU
|
||||
|
||||
#define PHY_READ_TO 0x0000FFFFU
|
||||
#define PHY_WRITE_TO 0x0000FFFFU
|
||||
|
||||
/* Section 3: Common PHY Registers */
|
||||
|
||||
#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */
|
||||
#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */
|
||||
|
||||
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
|
||||
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
|
||||
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
|
||||
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
|
||||
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
|
||||
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
|
||||
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
|
||||
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
|
||||
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
|
||||
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
|
||||
|
||||
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
|
||||
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
|
||||
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
|
||||
|
||||
/* Section 4: Extended PHY Registers */
|
||||
|
||||
#define PHY_SR ((uint16_t)0x0010) /*!< PHY status register Offset */
|
||||
#define PHY_MICR ((uint16_t)0x0011) /*!< MII Interrupt Control Register */
|
||||
#define PHY_MISR ((uint16_t)0x0012) /*!< MII Interrupt Status and Misc. Control Register */
|
||||
|
||||
#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */
|
||||
#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */
|
||||
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */
|
||||
|
||||
#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */
|
||||
#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */
|
||||
|
||||
#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */
|
||||
#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */
|
||||
|
||||
/* ################## SPI peripheral configuration ########################## */
|
||||
|
||||
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
|
||||
* Activated: CRC code is present inside driver
|
||||
* Deactivated: CRC code cleaned from driver
|
||||
*/
|
||||
|
||||
#define USE_SPI_CRC 1U
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Include module's header file
|
||||
*/
|
||||
|
||||
#ifdef HAL_RCC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rcc.h"
|
||||
#endif /* HAL_RCC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_GPIO_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_gpio.h"
|
||||
#endif /* HAL_GPIO_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_EXTI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_exti.h"
|
||||
#endif /* HAL_EXTI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dma.h"
|
||||
#endif /* HAL_DMA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CORTEX_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cortex.h"
|
||||
#endif /* HAL_CORTEX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ADC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_adc.h"
|
||||
#endif /* HAL_ADC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_can.h"
|
||||
#endif /* HAL_CAN_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_can_legacy.h"
|
||||
#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_crc.h"
|
||||
#endif /* HAL_CRC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRYP_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cryp.h"
|
||||
#endif /* HAL_CRYP_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA2D_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dma2d.h"
|
||||
#endif /* HAL_DMA2D_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DAC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dac.h"
|
||||
#endif /* HAL_DAC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DCMI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dcmi.h"
|
||||
#endif /* HAL_DCMI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ETH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_eth.h"
|
||||
#endif /* HAL_ETH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FLASH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_flash.h"
|
||||
#endif /* HAL_FLASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SRAM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sram.h"
|
||||
#endif /* HAL_SRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NOR_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_nor.h"
|
||||
#endif /* HAL_NOR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NAND_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_nand.h"
|
||||
#endif /* HAL_NAND_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCCARD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pccard.h"
|
||||
#endif /* HAL_PCCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SDRAM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sdram.h"
|
||||
#endif /* HAL_SDRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HASH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_hash.h"
|
||||
#endif /* HAL_HASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2C_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_i2c.h"
|
||||
#endif /* HAL_I2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SMBUS_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_smbus.h"
|
||||
#endif /* HAL_SMBUS_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2S_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_i2s.h"
|
||||
#endif /* HAL_I2S_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IWDG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_iwdg.h"
|
||||
#endif /* HAL_IWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_LTDC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_ltdc.h"
|
||||
#endif /* HAL_LTDC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PWR_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pwr.h"
|
||||
#endif /* HAL_PWR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RNG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rng.h"
|
||||
#endif /* HAL_RNG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RTC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rtc.h"
|
||||
#endif /* HAL_RTC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SAI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sai.h"
|
||||
#endif /* HAL_SAI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sd.h"
|
||||
#endif /* HAL_SD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_spi.h"
|
||||
#endif /* HAL_SPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_TIM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_tim.h"
|
||||
#endif /* HAL_TIM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_UART_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_uart.h"
|
||||
#endif /* HAL_UART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_USART_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_usart.h"
|
||||
#endif /* HAL_USART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IRDA_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_irda.h"
|
||||
#endif /* HAL_IRDA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SMARTCARD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_smartcard.h"
|
||||
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_WWDG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_wwdg.h"
|
||||
#endif /* HAL_WWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pcd.h"
|
||||
#endif /* HAL_PCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HCD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_hcd.h"
|
||||
#endif /* HAL_HCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DSI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dsi.h"
|
||||
#endif /* HAL_DSI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_QSPI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_qspi.h"
|
||||
#endif /* HAL_QSPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CEC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cec.h"
|
||||
#endif /* HAL_CEC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FMPI2C_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_fmpi2c.h"
|
||||
#endif /* HAL_FMPI2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FMPSMBUS_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_fmpsmbus.h"
|
||||
#endif /* HAL_FMPSMBUS_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPDIFRX_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_spdifrx.h"
|
||||
#endif /* HAL_SPDIFRX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DFSDM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dfsdm.h"
|
||||
#endif /* HAL_DFSDM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_LPTIM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_lptim.h"
|
||||
#endif /* HAL_LPTIM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_MMC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_mmc.h"
|
||||
#endif /* HAL_MMC_MODULE_ENABLED */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief The assert_param macro is used for function's parameters check.
|
||||
* @param expr If expr is false, it calls assert_failed function
|
||||
* which reports the name of the source file and the source
|
||||
* line number of the call that failed.
|
||||
* If expr is true, it returns no value.
|
||||
* @retval None
|
||||
*/
|
||||
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void assert_failed(uint8_t* file, uint32_t line);
|
||||
#else
|
||||
#define assert_param(expr) ((void)0U)
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F4xx_HAL_CONF_H */
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Templates/Inc/stm32f4xx_it.h
|
||||
* @author MCD Application Team
|
||||
* @brief This file contains the headers of the interrupt handlers.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F4xx_IT_H
|
||||
#define __STM32F4xx_IT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void MemManage_Handler(void);
|
||||
void BusFault_Handler(void);
|
||||
void UsageFault_Handler(void);
|
||||
void SVC_Handler(void);
|
||||
void DebugMon_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F4xx_IT_H */
|
||||
+2
@@ -35,6 +35,7 @@ extern "C" {
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern TIM_HandleTypeDef htim4;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
@@ -42,6 +43,7 @@ extern TIM_HandleTypeDef htim2;
|
||||
|
||||
void MX_TIM1_Init(void);
|
||||
void MX_TIM2_Init(void);
|
||||
void MX_TIM4_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
+2
@@ -33,12 +33,14 @@ extern "C" {
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_USART1_UART_Init(void);
|
||||
void MX_USART2_UART_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file dma.c
|
||||
* @brief This file provides code for the configuration
|
||||
* of all the requested memory to memory DMA transfers.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "dma.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Configure DMA */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
DMA_HandleTypeDef hdma_memtomem_dma1_channel1;
|
||||
|
||||
/**
|
||||
* Enable DMA controller clock
|
||||
* Configure DMA for memory to memory transfers
|
||||
* hdma_memtomem_dma1_channel1
|
||||
*/
|
||||
void MX_DMA_Init(void)
|
||||
{
|
||||
|
||||
/* DMA controller clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
|
||||
/* Configure DMA request hdma_memtomem_dma1_channel1 on DMA1_Channel1 */
|
||||
hdma_memtomem_dma1_channel1.Instance = DMA1_Channel1;
|
||||
hdma_memtomem_dma1_channel1.Init.Direction = DMA_MEMORY_TO_MEMORY;
|
||||
hdma_memtomem_dma1_channel1.Init.PeriphInc = DMA_PINC_ENABLE;
|
||||
hdma_memtomem_dma1_channel1.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_memtomem_dma1_channel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_memtomem_dma1_channel1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_memtomem_dma1_channel1.Init.Mode = DMA_NORMAL;
|
||||
hdma_memtomem_dma1_channel1.Init.Priority = DMA_PRIORITY_LOW;
|
||||
if (HAL_DMA_Init(&hdma_memtomem_dma1_channel1) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
+6
-8
@@ -25,7 +25,6 @@
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Configure GPIO */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@@ -52,11 +51,10 @@ void MX_GPIO_Init(void)
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1|GPIO_PIN_4
|
||||
|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
|
||||
|GPIO_PIN_9|Relay_dc5v_Pin|One_wire_Pin, GPIO_PIN_RESET);
|
||||
|
||||
@@ -66,9 +64,9 @@ void MX_GPIO_Init(void)
|
||||
|GPIO_PIN_15, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin : PC13 */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_13;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
@@ -78,10 +76,10 @@ void MX_GPIO_Init(void)
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : PA1 PA2 PA3 PA4
|
||||
/*Configure GPIO pins : PA1 PA4
|
||||
PA5 PA6 PA7 PA8
|
||||
PA9 Relay_dc5v_Pin One_wire_Pin */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4
|
||||
|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
|
||||
|GPIO_PIN_9|Relay_dc5v_Pin|One_wire_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
@@ -0,0 +1,763 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.c
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "adc.h"
|
||||
#include "can.h"
|
||||
#include "i2c.h"
|
||||
#include "rtc.h"
|
||||
#include "spi.h"
|
||||
#include "tim.h"
|
||||
#include "usart.h"
|
||||
#include "gpio.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "dallas_tools.h"
|
||||
|
||||
#include "def.h"
|
||||
#include <stdio.h>
|
||||
#include "modbus.h"
|
||||
#include "eeprom_emul.h"
|
||||
#include "stdio.h"
|
||||
#include "flash_ring.h"
|
||||
#include "string.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
uint16_t iter, cnt = 5;
|
||||
uint8_t init_retries = 5;
|
||||
uint8_t ralay_5v_on_var = 0;
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
float temperature;
|
||||
uint8_t roms[MAX_DEVICES][8];
|
||||
Flags_TypeDef flag;
|
||||
//extern uint8_t devices_found ;
|
||||
uint8_t _debug_init = 0;
|
||||
TEMP_TypeDef temp_sense[30];
|
||||
float set_temp_old[30];
|
||||
char rx_buffer[64];
|
||||
uint8_t rx_index = 0;
|
||||
char command_ready = 0;
|
||||
uint8_t uart_byte = 0;
|
||||
uint8_t first_in = 1;
|
||||
DALLAS_SensorHandleTypeDef sens[30];
|
||||
int init_sens = 0;
|
||||
FlashRecord_t* record;
|
||||
uint8_t flash_buff[RECORD_SIZE - 4];
|
||||
|
||||
RS_HandleTypeDef hmodbus_master;
|
||||
RS_MsgTypeDef MODBUS_MASTER_MSG;
|
||||
static uint8_t hmodbus_master_buffer[MSG_SIZE_MAX];
|
||||
static uint8_t rtc_modbus_hold_initialized = 0U;
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
int last_page_addr = LAST_PAGE_ADDR;
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
/* USER CODE BEGIN PFP */
|
||||
static void RTC_ModbusService(MB_DataStructureTypeDef* mb_data);
|
||||
static void RTC_ReadCalendarFromRegs(const MB_RtcCalendarRegsTypeDef* regs, RTC_CalendarTypeDef* calendar);
|
||||
static void RTC_WriteCalendarToRegs(MB_RtcCalendarRegsTypeDef* regs, const RTC_CalendarTypeDef* calendar, uint16_t status);
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
HAL_StatusTypeDef ModbusMaster_Request(RS_MsgTypeDef *request,
|
||||
void (*callback)(RS_HandleTypeDef *, RS_MsgTypeDef *))
|
||||
{
|
||||
return MODBUS_MasterRequest(&hmodbus_master, request, callback);
|
||||
}
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/**
|
||||
* @brief The application entry point.
|
||||
* @retval int
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration--------------------------------------------------------*/
|
||||
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||
HAL_Init();
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Configure the system clock */
|
||||
SystemClock_Config();
|
||||
|
||||
/* USER CODE BEGIN SysInit */
|
||||
|
||||
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_TIM1_Init();
|
||||
MX_USART1_UART_Init();
|
||||
MX_USART2_UART_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_TIM4_Init();
|
||||
MX_ADC1_Init();
|
||||
MX_CAN_Init();
|
||||
MX_I2C1_Init();
|
||||
MX_RTC_Init();
|
||||
MX_SPI1_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
|
||||
|
||||
led_blink(GPIOC, 13, rest_iter, reset_blink_delay);
|
||||
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
|
||||
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
||||
// Запуск приема Modbus
|
||||
MODBUS_SlaveStart(&hmodbus1, NULL);
|
||||
if (MODBUS_FirstInit(&hmodbus_master, &huart2, &htim4) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
hmodbus_master.pBufferPtr = hmodbus_master_buffer;
|
||||
if (MODBUS_Config(&hmodbus_master, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
uint8_t uart_byte = 0;
|
||||
Dallas_BusFirstInit(&htim1);
|
||||
// ������������� �� ������� ��������� ��������
|
||||
// ������������� �� ������� (����������� ������ ���������� �������)
|
||||
reinit_t_sens();
|
||||
init_setpoint_all_T_sense(temp_sense, hdallas.onewire->RomCnt);
|
||||
|
||||
MB_DATA.InRegs.num_Tsens = hdallas.onewire->RomCnt;
|
||||
RTC_ModbusService(&MB_DATA);
|
||||
// BufferState_t buffer_state = buffer_init();
|
||||
for(int i=0;i<RECORD_SIZE;i++)
|
||||
{
|
||||
flash_buff[i]=i;
|
||||
|
||||
}
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1)
|
||||
{
|
||||
|
||||
|
||||
// if (MB_DATA.Coils.relay_struct[0].state_val_bit.Temp11_relay_isOn)
|
||||
// {
|
||||
// MB_DATA.Coils.relay_struct[0].state_val_bit.Temp11_relay_isOn = 0;
|
||||
// BufferState_t state = buffer_init();
|
||||
// uint32_t idx = (state.write_index ) % RECORDS_PER_PAGE;
|
||||
// FlashRecord_t* record = buffer_read_record(idx);
|
||||
|
||||
// }
|
||||
// if (MB_DATA.Coils.relay_struct[0].state_val_bit.Temp10_relay_isOn)
|
||||
// {
|
||||
// MB_DATA.Coils.relay_struct[0].state_val_bit.Temp10_relay_isOn = 0;
|
||||
// FlashRecord_t new_record;
|
||||
// new_record.timestamp = HAL_GetTick();
|
||||
// memcpy(new_record.data, flash_buff, sizeof(new_record.data));
|
||||
|
||||
// HAL_StatusTypeDef status = buffer_write_record(&new_record, &buffer_state);
|
||||
|
||||
// if (status == HAL_OK)
|
||||
// {
|
||||
// // printf("Record written successfully\n");
|
||||
// GPIOC->ODR |= 1 << 13;
|
||||
// }
|
||||
|
||||
// }
|
||||
temp_sense[0].t_close = 1;
|
||||
Field_modbus(&MB_DATA, &flag);
|
||||
Check_Tconnect(&MB_DATA, &flag, &hdallas, 0);
|
||||
value_control();
|
||||
init_setpoint_all_T_sense(temp_sense, hdallas.onewire->RomCnt);
|
||||
// handle_valves(temp_sense[]);
|
||||
Dallas_StartConvertTAll(&hdallas, DALLAS_WAIT_BUS, 0);
|
||||
for(int i = 0; i < hdallas.onewire->RomCnt; i++)
|
||||
{
|
||||
if(sens[i].isLost)
|
||||
{
|
||||
sens[i].lost_cnt ++;
|
||||
}
|
||||
Dallas_ReadTemperature(&sens[i]);
|
||||
MB_DATA.InRegs.sens_Temp[i] = sens[i].temperature * 10;
|
||||
/////////////////////////заменить на define ralay_5v_on_var GPIOA->ODR|=1<<10;
|
||||
ralay_5v_on_var = MB_DATA.Coils.coils[1].state_val_bit.state_val_05;
|
||||
if (ralay_5v_on_var)
|
||||
{
|
||||
GPIOA->ODR |= 1 << 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPIOA->ODR &= ~(1 << 10);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
//iwdg_refresh();
|
||||
|
||||
//HAL_Delay(200);
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
|
||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/** Initializes the CPU, AHB and APB buses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_ADC;
|
||||
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
|
||||
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
static void RTC_ReadCalendarFromRegs(const MB_RtcCalendarRegsTypeDef* regs, RTC_CalendarTypeDef* calendar)
|
||||
{
|
||||
if ((regs == NULL) || (calendar == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
calendar->hours = regs->hours;
|
||||
calendar->minutes = regs->minutes;
|
||||
calendar->seconds = regs->seconds;
|
||||
calendar->date = regs->date;
|
||||
calendar->month = regs->month;
|
||||
calendar->year = regs->year;
|
||||
calendar->weekday = regs->weekday;
|
||||
}
|
||||
|
||||
static void RTC_WriteCalendarToRegs(MB_RtcCalendarRegsTypeDef* regs, const RTC_CalendarTypeDef* calendar, uint16_t status)
|
||||
{
|
||||
if ((regs == NULL) || (calendar == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
regs->hours = calendar->hours;
|
||||
regs->minutes = calendar->minutes;
|
||||
regs->seconds = calendar->seconds;
|
||||
regs->date = calendar->date;
|
||||
regs->month = calendar->month;
|
||||
regs->year = calendar->year;
|
||||
regs->weekday = calendar->weekday;
|
||||
regs->apply = 0U;
|
||||
regs->status = status;
|
||||
}
|
||||
|
||||
static void RTC_ModbusService(MB_DataStructureTypeDef* mb_data)
|
||||
{
|
||||
RTC_CalendarTypeDef calendar = {0};
|
||||
uint16_t hold_status = MB_RTC_STATUS_IDLE;
|
||||
uint8_t copy_current_to_holding = 0U;
|
||||
|
||||
if (mb_data == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hold_status = mb_data->HoldRegs.rtc.status;
|
||||
|
||||
if (mb_data->HoldRegs.rtc.apply == MB_RTC_APPLY_SET)
|
||||
{
|
||||
RTC_ReadCalendarFromRegs(&mb_data->HoldRegs.rtc, &calendar);
|
||||
mb_data->HoldRegs.rtc.apply = 0U;
|
||||
|
||||
if (RTC_CalendarIsValid(&calendar) == 0U)
|
||||
{
|
||||
hold_status = MB_RTC_STATUS_VALUE_ERROR;
|
||||
}
|
||||
else if (RTC_CalendarSet(&calendar) != HAL_OK)
|
||||
{
|
||||
hold_status = MB_RTC_STATUS_HAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
hold_status = MB_RTC_STATUS_SET_OK;
|
||||
copy_current_to_holding = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
if (RTC_CalendarGet(&calendar) != HAL_OK)
|
||||
{
|
||||
mb_data->InRegs.rtc.status = MB_RTC_STATUS_HAL_ERROR;
|
||||
mb_data->HoldRegs.rtc.status = MB_RTC_STATUS_HAL_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
RTC_WriteCalendarToRegs(&mb_data->InRegs.rtc, &calendar, MB_RTC_STATUS_IDLE);
|
||||
|
||||
if ((rtc_modbus_hold_initialized == 0U) || (copy_current_to_holding != 0U))
|
||||
{
|
||||
RTC_WriteCalendarToRegs(&mb_data->HoldRegs.rtc, &calendar, hold_status);
|
||||
rtc_modbus_hold_initialized = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
mb_data->HoldRegs.rtc.status = hold_status;
|
||||
}
|
||||
}
|
||||
|
||||
void iwdg_refresh(void)
|
||||
{
|
||||
IWDG->KR = 0xAAAA; // �������� ������
|
||||
}
|
||||
void led_blink(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint8_t iter, uint16_t delay)
|
||||
{
|
||||
for(int i = 0; i < iter; i++)
|
||||
{
|
||||
GPIOx->ODR ^= (1 << GPIO_Pin);
|
||||
HAL_Delay(delay);
|
||||
}
|
||||
}
|
||||
|
||||
void Check_Tconnect(MB_DataStructureTypeDef* MB_DATA, Flags_TypeDef* flag, DALLAS_HandleTypeDef* hdallas, int a[0])
|
||||
{
|
||||
for(int i = 0; i < hdallas->onewire->RomCnt; i++)
|
||||
{
|
||||
if(sens[i].isLost)
|
||||
{
|
||||
//init_sens=1;
|
||||
}
|
||||
|
||||
}
|
||||
if (init_sens || flag->init_tsens)
|
||||
{
|
||||
init_sens = 0;
|
||||
flag->init_tsens = 0;
|
||||
//Dallas_BusFirstInit(&htim1);
|
||||
DS18B20_Search(&DS, &OW) ;
|
||||
reinit_t_sens();
|
||||
MB_DATA->InRegs.num_Tsens = hdallas->onewire->RomCnt;
|
||||
}
|
||||
}
|
||||
|
||||
void reinit_t_sens(void)
|
||||
{
|
||||
for ( int i = 0; i < hdallas.onewire->RomCnt; i++)
|
||||
{
|
||||
// ������������� �� ROM-������
|
||||
//sens[i].Init.init_func = &Dallas_SensorInitByROM;
|
||||
// sens[i].Init.InitParam.ROM = rom_address;
|
||||
sens[i].Init.InitParam.Ind = i;
|
||||
sens[i].Init.init_func = &Dallas_SensorInitByInd;
|
||||
sens[i].Init.Resolution = DALLAS_CONFIG_9_BITS; sens[i].set_temp = 20.;
|
||||
sens[i].hyst = 1;
|
||||
MB_DATA.HoldRegs.set_Temp[i] = (uint16_t)(sens[i].set_temp * MB_ROOM_TEMP_SCALE);
|
||||
MB_DATA.HoldRegs.set_hyst[i] = (uint16_t)(sens[i].hyst * MB_ROOM_TEMP_SCALE);
|
||||
MB_DATA.HoldRegs.room_cfg[i].setpoint_x10 = MB_DATA.HoldRegs.set_Temp[i];
|
||||
MB_DATA.HoldRegs.room_cfg[i].hysteresis_x10 = MB_DATA.HoldRegs.set_hyst[i];
|
||||
MB_DATA.HoldRegs.room_cfg[i].valve_position_pct = 0;
|
||||
MB_DATA.HoldRegs.room_cfg[i].valve_angle_max_deg = MB_ROOM_VALVE_ANGLE_MAX_DEFAULT;
|
||||
MB_DATA.HoldRegs.room_cfg[i].mode = ROOM_MODE_AUTO;
|
||||
MB_DATA.HoldRegs.room_cfg[i].command = ROOM_COMMAND_STOP;
|
||||
MB_DATA.HoldRegs.room_cfg[i].location = 1;
|
||||
MB_DATA.HoldRegs.room_cfg[i].apply = 0;
|
||||
Dallas_AddNewSensors(&hdallas, &sens[i]);
|
||||
|
||||
}
|
||||
}
|
||||
FuncStat packStruct(MB_DataStructureTypeDef* MB_DATA, int sizeARR)
|
||||
{
|
||||
for(int i = 0; i < sizeARR; i++)
|
||||
{
|
||||
for(int sens_num = 0; sens_num < hdallas.onewire->RomCnt; sens_num++)
|
||||
{
|
||||
switch(sens_num)
|
||||
{
|
||||
case 0:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp1_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 1:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp2_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 2:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp3_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 3:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp4_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 4:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp5_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 5:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp6_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 6:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp7_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 7:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp8_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 8:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp9_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 9:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp10_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 10:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp11_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 11:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp12_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 12:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp13_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 13:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp14_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 14:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp15_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
case 15:
|
||||
MB_DATA->Coils.status_tSens[i].state_val_bit.Temp16_isConnected = sens[i * 16 + sens_num ].isConnected;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FuncOK;
|
||||
|
||||
}
|
||||
|
||||
static uint16_t clamp_room_percent(uint16_t value)
|
||||
{
|
||||
return value > 100U ? 100U : value;
|
||||
}
|
||||
|
||||
static void update_room_modbus(MB_DataStructureTypeDef* MB_DATA)
|
||||
{
|
||||
for (int i = 0; i < MAX_SENSE; i++)
|
||||
{
|
||||
MB_RoomInputRegsTypeDef* room = &MB_DATA->InRegs.room[i];
|
||||
MB_RoomHoldingRegsTypeDef* cfg = &MB_DATA->HoldRegs.room_cfg[i];
|
||||
uint16_t open_state = 0U;
|
||||
uint16_t close_state = 0U;
|
||||
uint16_t position_pct;
|
||||
uint16_t angle_max;
|
||||
|
||||
if (cfg->valve_angle_max_deg == 0U)
|
||||
{
|
||||
cfg->valve_angle_max_deg = MB_ROOM_VALVE_ANGLE_MAX_DEFAULT;
|
||||
}
|
||||
|
||||
if (i < 16)
|
||||
{
|
||||
open_state = (MB_DATA->Coils.relay_struct_on.all >> i) & 0x1U;
|
||||
close_state = (MB_DATA->Coils.relay_struct_off.all >> i) & 0x1U;
|
||||
}
|
||||
|
||||
position_pct = clamp_room_percent(cfg->valve_position_pct);
|
||||
if (cfg->mode == ROOM_MODE_AUTO)
|
||||
{
|
||||
if (open_state)
|
||||
{
|
||||
position_pct = 100U;
|
||||
}
|
||||
else if (close_state)
|
||||
{
|
||||
position_pct = 0U;
|
||||
}
|
||||
}
|
||||
cfg->valve_position_pct = position_pct;
|
||||
angle_max = cfg->valve_angle_max_deg;
|
||||
|
||||
room->channel = (uint16_t)(i + 1);
|
||||
room->location = cfg->location;
|
||||
for (int reg = 0; reg < 4; reg++)
|
||||
{
|
||||
room->ds18b20_id[reg] = ((uint16_t)MB_DATA->InRegs.ID.DevAddr[i][reg * 2]) |
|
||||
((uint16_t)MB_DATA->InRegs.ID.DevAddr[i][reg * 2 + 1] << 8);
|
||||
}
|
||||
room->temperature_x10 = (i < hdallas.onewire->RomCnt) ? (uint16_t)((int16_t)(sens[i].temperature * MB_ROOM_TEMP_SCALE)) : 0U;
|
||||
room->setpoint_x10 = MB_DATA->HoldRegs.set_Temp[i];
|
||||
room->hysteresis_x10 = MB_DATA->HoldRegs.set_hyst[i];
|
||||
room->valve_position_pct = position_pct;
|
||||
room->valve_angle_deg = (uint16_t)((position_pct * angle_max) / 100U);
|
||||
room->valve_angle_max_deg = angle_max;
|
||||
room->is_connected = (i < hdallas.onewire->RomCnt) ? (uint16_t)sens[i].isConnected : 0U;
|
||||
room->valve_open = open_state;
|
||||
room->valve_close = close_state;
|
||||
room->mode = cfg->mode;
|
||||
room->command_state = cfg->command;
|
||||
room->reserved = 0U;
|
||||
}
|
||||
}
|
||||
FuncStat Field_modbus(MB_DataStructureTypeDef* MB_DATA, Flags_TypeDef* flag)
|
||||
{
|
||||
|
||||
MB_DATA->InRegs.ID = *hdallas.ds_devices;
|
||||
RTC_ModbusService(MB_DATA);
|
||||
flag->init_tsens = MB_DATA->Coils.init_Tsens;
|
||||
packStruct(MB_DATA, MAX_SENSE / 16);
|
||||
if (_debug_init || MB_DATA->Coils.init_param)
|
||||
{
|
||||
_debug_init = 0;
|
||||
|
||||
MB_DATA->Coils.init_param = 0;
|
||||
for(int i = 0; i < hdallas.onewire->RomCnt; i++)
|
||||
{ if (MB_DATA->HoldRegs.room_cfg[i].apply)
|
||||
{
|
||||
MB_DATA->HoldRegs.set_Temp[i] = MB_DATA->HoldRegs.room_cfg[i].setpoint_x10;
|
||||
MB_DATA->HoldRegs.set_hyst[i] = MB_DATA->HoldRegs.room_cfg[i].hysteresis_x10;
|
||||
MB_DATA->HoldRegs.room_cfg[i].apply = 0U;
|
||||
}
|
||||
MB_DATA->HoldRegs.room_cfg[i].setpoint_x10 = MB_DATA->HoldRegs.set_Temp[i];
|
||||
MB_DATA->HoldRegs.room_cfg[i].hysteresis_x10 = MB_DATA->HoldRegs.set_hyst[i];
|
||||
sens[i].set_temp = ((float)MB_DATA->HoldRegs.set_Temp[i]) / MB_ROOM_TEMP_SCALE;
|
||||
sens[i].hyst = ((float)MB_DATA->HoldRegs.set_hyst[i]) / MB_ROOM_TEMP_SCALE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
update_room_modbus(MB_DATA);
|
||||
return FuncOK;
|
||||
};
|
||||
|
||||
|
||||
FuncStat value_control(void )
|
||||
{
|
||||
|
||||
for(int i = 0; i < hdallas.onewire->RomCnt; i++)
|
||||
{
|
||||
if (i < 16 && MB_DATA.HoldRegs.room_cfg[i].mode == ROOM_MODE_MANUAL)
|
||||
{
|
||||
uint16_t manual_pct = clamp_room_percent(MB_DATA.HoldRegs.room_cfg[i].valve_position_pct);
|
||||
if (MB_DATA.HoldRegs.room_cfg[i].command == ROOM_COMMAND_CLOSE)
|
||||
{
|
||||
manual_pct = 0U;
|
||||
}
|
||||
else if (MB_DATA.HoldRegs.room_cfg[i].command == ROOM_COMMAND_OPEN && manual_pct == 0U)
|
||||
{
|
||||
manual_pct = 100U;
|
||||
}
|
||||
MB_DATA.HoldRegs.room_cfg[i].valve_position_pct = manual_pct;
|
||||
if (manual_pct > 0U)
|
||||
{
|
||||
MB_DATA.Coils.relay_struct_off.all &= ~(1 << i);
|
||||
MB_DATA.Coils.relay_struct_on.all |= 1 << i;
|
||||
}
|
||||
else
|
||||
{
|
||||
MB_DATA.Coils.relay_struct_on.all &= ~(1 << i);
|
||||
MB_DATA.Coils.relay_struct_off.all |= 1 << i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sens[i].temperature < sens[i].set_temp - sens[i].hyst)
|
||||
|
||||
{
|
||||
|
||||
MB_DATA.Coils.relay_struct_off.all |= 1 << i;
|
||||
MB_DATA.Coils.relay_struct_on.all &= ~(1 << i);
|
||||
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
if (sens[i].temperature > sens[i].set_temp + sens[i].hyst)
|
||||
{
|
||||
|
||||
MB_DATA.Coils.relay_struct_off.all &= ~(1 << i);
|
||||
MB_DATA.Coils.relay_struct_on.all |= 1 << i;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
if (sens[i].temperature == sens[i].set_temp )
|
||||
{
|
||||
MB_DATA.Coils.relay_struct_on.all &= ~(1 << i);
|
||||
MB_DATA.Coils.relay_struct_off.all &= ~(1 << i);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return FuncOK;
|
||||
}
|
||||
|
||||
|
||||
uint16_t handle_valves(TEMP_TypeDef* temp_sense[MAX_SENSE] )
|
||||
{
|
||||
|
||||
if (temp_sense[0]->state == STATE_OPEN_VALVE)
|
||||
{
|
||||
GPIOC->ODR |= 1 << 14;
|
||||
}
|
||||
else if (temp_sense[0]->state == STATE_CLOSE_VALVE)
|
||||
{
|
||||
GPIOC->ODR &= ~(1 << 14);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void init_setpoint_all_T_sense(TEMP_TypeDef* temp_sense, int size_array)
|
||||
{
|
||||
//ds_search_devices();
|
||||
for(int i = 0; i < size_array ; i++)
|
||||
{
|
||||
temp_sense[i].id[0] = roms[i][0] << 0 | roms[i][1] << 8 | roms[i][2] << 16 | roms[i][3] << 24;
|
||||
temp_sense[i].id[1] = roms[i][4] << 0 | roms[i][5] << 8 | roms[i][6] << 16 | roms[i][7] << 24;
|
||||
temp_sense[i].count = i + 1;
|
||||
temp_sense[i].location = 1;
|
||||
temp_sense[i].t_open = 22;
|
||||
temp_sense[i].t_close = 18;
|
||||
temp_sense[i].status_T_sense = 1;
|
||||
}
|
||||
}
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
* @brief Period elapsed callback in non blocking mode
|
||||
* @note This function is called when TIM3 interrupt took place, inside
|
||||
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
|
||||
* a global variable "uwTick" used as application time base.
|
||||
* @param htim : TIM handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
||||
{
|
||||
/* USER CODE BEGIN Callback 0 */
|
||||
|
||||
/* USER CODE END Callback 0 */
|
||||
if (htim->Instance == TIM3)
|
||||
{
|
||||
HAL_IncTick();
|
||||
}
|
||||
/* USER CODE BEGIN Callback 1 */
|
||||
|
||||
/* USER CODE END Callback 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @retval None
|
||||
*/
|
||||
void Error_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
__disable_irq();
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @retval None
|
||||
*/
|
||||
void assert_failed(uint8_t *file, uint32_t line)
|
||||
{
|
||||
/* USER CODE BEGIN 6 */
|
||||
/* User can add his own implementation to report the file name and line number,
|
||||
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
@@ -0,0 +1,333 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.c
|
||||
* @brief This file provides code for the configuration
|
||||
* of the RTC instances.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "rtc.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
#define RTC_BKP_CONFIGURED_MARKER 0x32A5U
|
||||
#define RTC_BKP_MARKER_REG RTC_BKP_DR1
|
||||
#define RTC_BKP_YEAR_MONTH_REG RTC_BKP_DR2
|
||||
#define RTC_BKP_DATE_WEEKDAY_REG RTC_BKP_DR3
|
||||
|
||||
static uint8_t RTC_NormalizeYear(uint16_t year, uint8_t *normalized_year)
|
||||
{
|
||||
if (year <= 99U)
|
||||
{
|
||||
*normalized_year = (uint8_t)year;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
if ((year >= 2000U) && (year <= 2099U))
|
||||
{
|
||||
*normalized_year = (uint8_t)(year - 2000U);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static uint8_t RTC_IsLeapYearFull(uint16_t year)
|
||||
{
|
||||
return (uint8_t)(((year % 4U) == 0U) && (((year % 100U) != 0U) || ((year % 400U) == 0U)));
|
||||
}
|
||||
|
||||
static uint8_t RTC_DaysInMonth(uint16_t year, uint8_t month)
|
||||
{
|
||||
static const uint8_t days_in_month[] = { 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U };
|
||||
|
||||
if ((month == 0U) || (month > 12U))
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if ((month == 2U) && RTC_IsLeapYearFull(year))
|
||||
{
|
||||
return 29U;
|
||||
}
|
||||
|
||||
return days_in_month[month - 1U];
|
||||
}
|
||||
|
||||
static uint8_t RTC_IsDateValid(uint16_t year, uint8_t month, uint8_t date)
|
||||
{
|
||||
uint8_t normalized_year = 0U;
|
||||
uint16_t full_year = year;
|
||||
uint8_t max_day = 0U;
|
||||
|
||||
if (RTC_NormalizeYear(year, &normalized_year) == 0U)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (year <= 99U)
|
||||
{
|
||||
full_year = 2000U + year;
|
||||
}
|
||||
|
||||
max_day = RTC_DaysInMonth(full_year, month);
|
||||
return (uint8_t)((date >= 1U) && (date <= max_day));
|
||||
}
|
||||
|
||||
static void RTC_SaveDateToBackup(const RTC_DateTypeDef *date)
|
||||
{
|
||||
uint32_t year_month = (((uint32_t)date->Year) << 8U) | date->Month;
|
||||
uint32_t date_weekday = (((uint32_t)date->Date) << 8U) | date->WeekDay;
|
||||
|
||||
if ((HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_YEAR_MONTH_REG) != year_month) ||
|
||||
(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DATE_WEEKDAY_REG) != date_weekday))
|
||||
{
|
||||
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_YEAR_MONTH_REG, year_month);
|
||||
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DATE_WEEKDAY_REG, date_weekday);
|
||||
}
|
||||
|
||||
if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_MARKER_REG) != RTC_BKP_CONFIGURED_MARKER)
|
||||
{
|
||||
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_MARKER_REG, RTC_BKP_CONFIGURED_MARKER);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t RTC_RestoreDateFromBackup(void)
|
||||
{
|
||||
RTC_DateTypeDef restored_date = {0};
|
||||
uint32_t year_month = 0U;
|
||||
uint32_t date_weekday = 0U;
|
||||
|
||||
if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_MARKER_REG) != RTC_BKP_CONFIGURED_MARKER)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
year_month = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_YEAR_MONTH_REG);
|
||||
date_weekday = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DATE_WEEKDAY_REG);
|
||||
|
||||
restored_date.Year = (uint8_t)((year_month >> 8U) & 0xFFU);
|
||||
restored_date.Month = (uint8_t)(year_month & 0xFFU);
|
||||
restored_date.Date = (uint8_t)((date_weekday >> 8U) & 0xFFU);
|
||||
restored_date.WeekDay = (uint8_t)(date_weekday & 0xFFU);
|
||||
|
||||
if (RTC_IsDateValid(restored_date.Year, restored_date.Month, restored_date.Date) == 0U)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (restored_date.WeekDay > RTC_WEEKDAY_SATURDAY)
|
||||
{
|
||||
restored_date.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
}
|
||||
|
||||
hrtc.DateToUpdate = restored_date;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* RTC init function */
|
||||
void MX_RTC_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN RTC_Init 0 */
|
||||
|
||||
/* USER CODE END RTC_Init 0 */
|
||||
|
||||
RTC_TimeTypeDef sTime = {0};
|
||||
RTC_DateTypeDef DateToUpdate = {0};
|
||||
|
||||
/* USER CODE BEGIN RTC_Init 1 */
|
||||
uint8_t rtc_backup_ready = 0U;
|
||||
|
||||
/* USER CODE END RTC_Init 1 */
|
||||
|
||||
/** Initialize RTC Only
|
||||
*/
|
||||
hrtc.Instance = RTC;
|
||||
hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
|
||||
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_SECOND;
|
||||
if (HAL_RTC_Init(&hrtc) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Check_RTC_BKUP */
|
||||
rtc_backup_ready = RTC_RestoreDateFromBackup();
|
||||
|
||||
/* USER CODE END Check_RTC_BKUP */
|
||||
|
||||
/** Initialize RTC and set the Time and Date
|
||||
*/
|
||||
if (rtc_backup_ready == 0U)
|
||||
{
|
||||
sTime.Hours = 0U;
|
||||
sTime.Minutes = 0U;
|
||||
sTime.Seconds = 0U;
|
||||
|
||||
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
DateToUpdate.Month = RTC_MONTH_JANUARY;
|
||||
DateToUpdate.Date = 1U;
|
||||
DateToUpdate.Year = 0U;
|
||||
|
||||
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
RTC_SaveDateToBackup(&DateToUpdate);
|
||||
}
|
||||
/* USER CODE BEGIN RTC_Init 2 */
|
||||
|
||||
/* USER CODE END RTC_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 0 */
|
||||
HAL_PWR_EnableBkUpAccess();
|
||||
/* Enable BKP CLK enable for backup registers */
|
||||
__HAL_RCC_BKP_CLK_ENABLE();
|
||||
/* RTC clock enable */
|
||||
__HAL_RCC_RTC_ENABLE();
|
||||
|
||||
/* RTC interrupt Init */
|
||||
HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(RTC_IRQn);
|
||||
/* USER CODE BEGIN RTC_MspInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_RTC_DISABLE();
|
||||
|
||||
/* RTC interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(RTC_IRQn);
|
||||
/* USER CODE BEGIN RTC_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
uint8_t RTC_CalendarIsValid(const RTC_CalendarTypeDef *calendar)
|
||||
{
|
||||
if (calendar == NULL)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
return (uint8_t)((calendar->hours <= 23U) &&
|
||||
(calendar->minutes <= 59U) &&
|
||||
(calendar->seconds <= 59U) &&
|
||||
RTC_IsDateValid(calendar->year, calendar->month, calendar->date));
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef RTC_CalendarGet(RTC_CalendarTypeDef *calendar)
|
||||
{
|
||||
RTC_TimeTypeDef time = {0};
|
||||
RTC_DateTypeDef date = {0};
|
||||
|
||||
if (calendar == NULL)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if (HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if (HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
RTC_SaveDateToBackup(&date);
|
||||
|
||||
calendar->hours = time.Hours;
|
||||
calendar->minutes = time.Minutes;
|
||||
calendar->seconds = time.Seconds;
|
||||
calendar->date = date.Date;
|
||||
calendar->month = date.Month;
|
||||
calendar->year = 2000U + date.Year;
|
||||
calendar->weekday = date.WeekDay;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef RTC_CalendarSet(const RTC_CalendarTypeDef *calendar)
|
||||
{
|
||||
RTC_TimeTypeDef time = {0};
|
||||
RTC_DateTypeDef date = {0};
|
||||
uint8_t normalized_year = 0U;
|
||||
|
||||
if ((calendar == NULL) || (RTC_CalendarIsValid(calendar) == 0U))
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if (RTC_NormalizeYear(calendar->year, &normalized_year) == 0U)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
time.Hours = (uint8_t)calendar->hours;
|
||||
time.Minutes = (uint8_t)calendar->minutes;
|
||||
time.Seconds = (uint8_t)calendar->seconds;
|
||||
|
||||
date.Year = normalized_year;
|
||||
date.Month = (uint8_t)calendar->month;
|
||||
date.Date = (uint8_t)calendar->date;
|
||||
date.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
|
||||
if (HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if (HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
RTC_SaveDateToBackup(&date);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/* USER CODE END 1 */
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Templates/Src/stm32f4xx_hal_msp.c
|
||||
* @author MCD Application Team
|
||||
* @brief HAL MSP module.
|
||||
*
|
||||
@verbatim
|
||||
===============================================================================
|
||||
##### How to use this driver #####
|
||||
===============================================================================
|
||||
[..]
|
||||
This file is generated automatically by STM32CubeMX and eventually modified
|
||||
by the user
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
/** @addtogroup STM32F4xx_HAL_Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup HAL_MSP
|
||||
* @brief HAL MSP module.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/** @defgroup HAL_MSP_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initializes the Global MSP.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_MspInit(void)
|
||||
{
|
||||
/* NOTE : This function is generated automatically by STM32CubeMX and eventually
|
||||
modified by the user
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DeInitializes the Global MSP.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_MspDeInit(void)
|
||||
{
|
||||
/* NOTE : This function is generated automatically by STM32CubeMX and eventually
|
||||
modified by the user
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_hal_timebase_tim_template.c
|
||||
* @author MCD Application Team
|
||||
* @brief HAL time base based on the hardware TIM Template.
|
||||
*
|
||||
* This file overrides the native HAL time base functions (defined as weak)
|
||||
* the TIM time base:
|
||||
* + Intializes the TIM peripheral generate a Period elapsed Event each 1ms
|
||||
* + HAL_IncTick is called inside HAL_TIM_PeriodElapsedCallback ie each 1ms
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
/** @addtogroup STM32F4xx_HAL_Driver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup HAL_TimeBase_TIM
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
TIM_HandleTypeDef TimHandle;
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void TIM6_DAC_IRQHandler(void);
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief This function configures the TIM6 as a time base source.
|
||||
* The time source is configured to have 1ms time base with a dedicated
|
||||
* Tick interrupt priority.
|
||||
* @note This function is called automatically at the beginning of program after
|
||||
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
|
||||
* @param TickPriority Tick interrupt priority.
|
||||
* @retval HAL status
|
||||
*/
|
||||
HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
|
||||
{
|
||||
RCC_ClkInitTypeDef clkconfig;
|
||||
uint32_t uwTimclock, uwAPB1Prescaler = 0U;
|
||||
uint32_t uwPrescalerValue = 0U;
|
||||
uint32_t pFLatency;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
/* Enable TIM6 clock */
|
||||
__HAL_RCC_TIM6_CLK_ENABLE();
|
||||
|
||||
/* Get clock configuration */
|
||||
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
|
||||
|
||||
/* Get APB1 prescaler */
|
||||
uwAPB1Prescaler = clkconfig.APB1CLKDivider;
|
||||
|
||||
/* Compute TIM6 clock */
|
||||
if (uwAPB1Prescaler == RCC_HCLK_DIV1)
|
||||
{
|
||||
uwTimclock = HAL_RCC_GetPCLK1Freq();
|
||||
}
|
||||
else
|
||||
{
|
||||
uwTimclock = 2 * HAL_RCC_GetPCLK1Freq();
|
||||
}
|
||||
|
||||
/* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */
|
||||
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);
|
||||
|
||||
/* Initialize TIM6 */
|
||||
TimHandle.Instance = TIM6;
|
||||
|
||||
/* Initialize TIMx peripheral as follow:
|
||||
+ Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base.
|
||||
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
|
||||
+ ClockDivision = 0
|
||||
+ Counter direction = Up
|
||||
*/
|
||||
TimHandle.Init.Period = (1000000U / 1000U) - 1U;
|
||||
TimHandle.Init.Prescaler = uwPrescalerValue;
|
||||
TimHandle.Init.ClockDivision = 0U;
|
||||
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
status = HAL_TIM_Base_Init(&TimHandle);
|
||||
if (status == HAL_OK)
|
||||
{
|
||||
/* Start the TIM time Base generation in interrupt mode */
|
||||
status = HAL_TIM_Base_Start_IT(&TimHandle);
|
||||
if (status == HAL_OK)
|
||||
{
|
||||
/* Enable the TIM6 global Interrupt */
|
||||
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
|
||||
|
||||
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
|
||||
{
|
||||
/* Enable the TIM6 global Interrupt */
|
||||
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority, 0);
|
||||
uwTickPrio = TickPriority;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = HAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return function status */
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend Tick increment.
|
||||
* @note Disable the tick increment by disabling TIM6 update interrupt.
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_SuspendTick(void)
|
||||
{
|
||||
/* Disable TIM6 update Interrupt */
|
||||
__HAL_TIM_DISABLE_IT(&TimHandle, TIM_IT_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume Tick increment.
|
||||
* @note Enable the tick increment by Enabling TIM6 update interrupt.
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_ResumeTick(void)
|
||||
{
|
||||
/* Enable TIM6 Update interrupt */
|
||||
__HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Period elapsed callback in non blocking mode
|
||||
* @note This function is called when TIM6 interrupt took place, inside
|
||||
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
|
||||
* a global variable "uwTick" used as application time base.
|
||||
* @param htim TIM handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
||||
{
|
||||
HAL_IncTick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles TIM interrupt request.
|
||||
* @retval None
|
||||
*/
|
||||
void TIM6_DAC_IRQHandler(void)
|
||||
{
|
||||
HAL_TIM_IRQHandler(&TimHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Templates/Src/stm32f4xx_it.c
|
||||
* @author MCD Application Team
|
||||
* @brief Main Interrupt Service Routines.
|
||||
* This file provides template for all exceptions handler and
|
||||
* peripherals interrupt service routine.
|
||||
*
|
||||
* @note modified by ARM
|
||||
* The modifications allow to use this file as User Code Template
|
||||
* within the Device Family Pack.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "stm32f4xx_it.h"
|
||||
|
||||
#ifdef _RTE_
|
||||
#include "RTE_Components.h" /* Component selection */
|
||||
#endif
|
||||
|
||||
/** @addtogroup STM32F4xx_HAL_Examples
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup Templates
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M4 Processor Exceptions Handlers */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief This function handles NMI exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard Fault exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Hard Fault exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Memory Manage exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Memory Manage exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Bus Fault exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void BusFault_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Bus Fault exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Usage Fault exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void UsageFault_Handler(void)
|
||||
{
|
||||
/* Go to infinite loop when Usage Fault exception occurs */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles SVCall exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
#ifndef RTE_CMSIS_RTOS2_RTX5
|
||||
void SVC_Handler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This function handles Debug Monitor exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void DebugMon_Handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles PendSVC exception.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
#ifndef RTE_CMSIS_RTOS2_RTX5
|
||||
void PendSV_Handler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This function handles SysTick Handler.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
#ifndef RTE_CMSIS_RTOS2_RTX5
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
HAL_IncTick();
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32F4xx Peripherals Interrupt Handlers */
|
||||
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
|
||||
/* available peripheral interrupt handler's name please refer to the startup */
|
||||
/* file (startup_stm32f4xx.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief This function handles PPP interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
/*void PPP_IRQHandler(void)
|
||||
{
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -0,0 +1,747 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f4xx.c
|
||||
* @author MCD Application Team
|
||||
* @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
|
||||
*
|
||||
* This file provides two functions and one global variable to be called from
|
||||
* user application:
|
||||
* - SystemInit(): This function is called at startup just after reset and
|
||||
* before branch to main program. This call is made inside
|
||||
* the "startup_stm32f4xx.s" file.
|
||||
*
|
||||
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
|
||||
* by the user application to setup the SysTick
|
||||
* timer or configure other parameters.
|
||||
*
|
||||
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
|
||||
* be called whenever the core clock is changed
|
||||
* during program execution.
|
||||
*
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f4xx_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
#include "stm32f4xx.h"
|
||||
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
|
||||
/************************* Miscellaneous Configuration ************************/
|
||||
/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
|
||||
|| defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
/* #define DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\
|
||||
STM32F412Zx || STM32F412Vx */
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* #define DATA_IN_ExtSDRAM */
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\
|
||||
STM32F479xx */
|
||||
|
||||
/* Note: Following vector table addresses must be defined in line with linker
|
||||
configuration. */
|
||||
/*!< Uncomment the following line if you need to relocate the vector table
|
||||
anywhere in Flash or Sram, else the vector table is kept at the automatic
|
||||
remap of boot address selected */
|
||||
/* #define USER_VECT_TAB_ADDRESS */
|
||||
|
||||
#if defined(USER_VECT_TAB_ADDRESS)
|
||||
/*!< Uncomment the following line if you need to relocate your vector Table
|
||||
in Sram else user remap will be done in Flash. */
|
||||
/* #define VECT_TAB_SRAM */
|
||||
#if defined(VECT_TAB_SRAM)
|
||||
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#else
|
||||
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#endif /* VECT_TAB_SRAM */
|
||||
#endif /* USER_VECT_TAB_ADDRESS */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
/* This variable is updated in three ways:
|
||||
1) by calling CMSIS function SystemCoreClockUpdate()
|
||||
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
|
||||
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
|
||||
Note: If you use this function to configure the system clock; then there
|
||||
is no need to call the 2 first functions listed above, since SystemCoreClock
|
||||
variable is updated automatically.
|
||||
*/
|
||||
uint32_t SystemCoreClock = 16000000;
|
||||
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
static void SystemInit_ExtMemCtl(void);
|
||||
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Setup the microcontroller system
|
||||
* Initialize the FPU setting, vector table location and External memory
|
||||
* configuration.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* FPU settings ------------------------------------------------------------*/
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
|
||||
#endif
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
SystemInit_ExtMemCtl();
|
||||
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
|
||||
|
||||
/* Configure the Vector Table location -------------------------------------*/
|
||||
#if defined(USER_VECT_TAB_ADDRESS)
|
||||
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
|
||||
#endif /* USER_VECT_TAB_ADDRESS */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update SystemCoreClock variable according to Clock Register Values.
|
||||
* The SystemCoreClock variable contains the core clock (HCLK), it can
|
||||
* be used by the user application to setup the SysTick timer or configure
|
||||
* other parameters.
|
||||
*
|
||||
* @note Each time the core clock (HCLK) changes, this function must be called
|
||||
* to update SystemCoreClock variable value. Otherwise, any configuration
|
||||
* based on this variable will be incorrect.
|
||||
*
|
||||
* @note - The system frequency computed by this function is not the real
|
||||
* frequency in the chip. It is calculated based on the predefined
|
||||
* constant and the selected clock source:
|
||||
*
|
||||
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
|
||||
*
|
||||
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
*
|
||||
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
|
||||
*
|
||||
* (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
|
||||
* 16 MHz) but the real value may vary depending on the variations
|
||||
* in voltage and temperature.
|
||||
*
|
||||
* (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
|
||||
* depends on the application requirements), user has to ensure that HSE_VALUE
|
||||
* is same as the real frequency of the crystal used. Otherwise, this function
|
||||
* may have wrong result.
|
||||
*
|
||||
* - The result of this function could be not correct when using fractional
|
||||
* value for HSE crystal.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
|
||||
|
||||
/* Get SYSCLK source -------------------------------------------------------*/
|
||||
tmp = RCC->CFGR & RCC_CFGR_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case 0x00: /* HSI used as system clock source */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
case 0x04: /* HSE used as system clock source */
|
||||
SystemCoreClock = HSE_VALUE;
|
||||
break;
|
||||
case 0x08: /* PLL used as system clock source */
|
||||
|
||||
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
|
||||
SYSCLK = PLL_VCO / PLL_P
|
||||
*/
|
||||
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
|
||||
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
|
||||
|
||||
if (pllsource != 0)
|
||||
{
|
||||
/* HSE used as PLL clock source */
|
||||
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* HSI used as PLL clock source */
|
||||
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
|
||||
}
|
||||
|
||||
pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
|
||||
SystemCoreClock = pllvco/pllp;
|
||||
break;
|
||||
default:
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
}
|
||||
/* Compute HCLK frequency --------------------------------------------------*/
|
||||
/* Get HCLK prescaler */
|
||||
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
|
||||
/* HCLK frequency */
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM)
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f4xx.s before jump to main.
|
||||
* This function configures the external memories (SRAM/SDRAM)
|
||||
* This SRAM/SDRAM will be used as program data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmp = 0x00;
|
||||
|
||||
register uint32_t tmpreg = 0, timeout = 0xFFFF;
|
||||
register __IO uint32_t index;
|
||||
|
||||
/* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */
|
||||
RCC->AHB1ENR |= 0x000001F8;
|
||||
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x00CCC0CC;
|
||||
GPIOD->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xAAAA0A8A;
|
||||
/* Configure PDx pins speed to 100 MHz */
|
||||
GPIOD->OSPEEDR = 0xFFFF0FCF;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00CC0CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA828A;
|
||||
/* Configure PEx pins speed to 100 MHz */
|
||||
GPIOE->OSPEEDR = 0xFFFFC3CF;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA800AAA;
|
||||
/* Configure PFx pins speed to 50 MHz */
|
||||
GPIOF->OSPEEDR = 0xAA800AAA;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOG->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0xAAAAAAAA;
|
||||
/* Configure PGx pins speed to 50 MHz */
|
||||
GPIOG->OSPEEDR = 0xAAAAAAAA;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PHx pins to FMC Alternate function */
|
||||
GPIOH->AFR[0] = 0x00C0CC00;
|
||||
GPIOH->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PHx pins in Alternate function mode */
|
||||
GPIOH->MODER = 0xAAAA08A0;
|
||||
/* Configure PHx pins speed to 50 MHz */
|
||||
GPIOH->OSPEEDR = 0xAAAA08A0;
|
||||
/* Configure PHx pins Output type to push-pull */
|
||||
GPIOH->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PHx pins */
|
||||
GPIOH->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PIx pins to FMC Alternate function */
|
||||
GPIOI->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOI->AFR[1] = 0x00000CC0;
|
||||
/* Configure PIx pins in Alternate function mode */
|
||||
GPIOI->MODER = 0x0028AAAA;
|
||||
/* Configure PIx pins speed to 50 MHz */
|
||||
GPIOI->OSPEEDR = 0x0028AAAA;
|
||||
/* Configure PIx pins Output type to push-pull */
|
||||
GPIOI->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PIx pins */
|
||||
GPIOI->PUPDR = 0x00000000;
|
||||
|
||||
/*-- FMC Configuration -------------------------------------------------------*/
|
||||
/* Enable the FMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
|
||||
FMC_Bank5_6->SDCR[0] = 0x000019E4;
|
||||
FMC_Bank5_6->SDTR[0] = 0x01115351;
|
||||
|
||||
/* SDRAM initialization sequence */
|
||||
/* Clock enable command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000011;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Delay */
|
||||
for (index = 0; index<1000; index++);
|
||||
|
||||
/* PALL command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000012;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Auto refresh command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000073;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* MRD register program */
|
||||
FMC_Bank5_6->SDCMR = 0x00046014;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Set refresh count */
|
||||
tmpreg = FMC_Bank5_6->SDRTR;
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
|
||||
|
||||
/* Disable write protection */
|
||||
tmpreg = FMC_Bank5_6->SDCR[0];
|
||||
FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
||||
#if defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001091;
|
||||
FMC_Bank1->BTCR[3] = 0x00110212;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F469xx || STM32F479xx */
|
||||
|
||||
(void)(tmp);
|
||||
}
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
|
||||
#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f4xx.s before jump to main.
|
||||
* This function configures the external memories (SRAM/SDRAM)
|
||||
* This SRAM/SDRAM will be used as program data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmp = 0x00;
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
|
||||
#if defined (DATA_IN_ExtSDRAM)
|
||||
register uint32_t tmpreg = 0, timeout = 0xFFFF;
|
||||
register __IO uint32_t index;
|
||||
|
||||
#if defined(STM32F446xx)
|
||||
/* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface
|
||||
clock */
|
||||
RCC->AHB1ENR |= 0x0000007D;
|
||||
#else
|
||||
/* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface
|
||||
clock */
|
||||
RCC->AHB1ENR |= 0x000001F8;
|
||||
#endif /* STM32F446xx */
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
|
||||
|
||||
#if defined(STM32F446xx)
|
||||
/* Connect PAx pins to FMC Alternate function */
|
||||
GPIOA->AFR[0] |= 0xC0000000;
|
||||
GPIOA->AFR[1] |= 0x00000000;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOA->MODER |= 0x00008000;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOA->OSPEEDR |= 0x00008000;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOA->OTYPER |= 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOA->PUPDR |= 0x00000000;
|
||||
|
||||
/* Connect PCx pins to FMC Alternate function */
|
||||
GPIOC->AFR[0] |= 0x00CC0000;
|
||||
GPIOC->AFR[1] |= 0x00000000;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOC->MODER |= 0x00000A00;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOC->OSPEEDR |= 0x00000A00;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOC->OTYPER |= 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOC->PUPDR |= 0x00000000;
|
||||
#endif /* STM32F446xx */
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x000000CC;
|
||||
GPIOD->AFR[1] = 0xCC000CCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xA02A000A;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOD->OSPEEDR = 0xA02A000A;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00000CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA800A;
|
||||
/* Configure PEx pins speed to 50 MHz */
|
||||
GPIOE->OSPEEDR = 0xAAAA800A;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA800AAA;
|
||||
/* Configure PFx pins speed to 50 MHz */
|
||||
GPIOF->OSPEEDR = 0xAA800AAA;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOG->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0xAAAAAAAA;
|
||||
/* Configure PGx pins speed to 50 MHz */
|
||||
GPIOG->OSPEEDR = 0xAAAAAAAA;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Connect PHx pins to FMC Alternate function */
|
||||
GPIOH->AFR[0] = 0x00C0CC00;
|
||||
GPIOH->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PHx pins in Alternate function mode */
|
||||
GPIOH->MODER = 0xAAAA08A0;
|
||||
/* Configure PHx pins speed to 50 MHz */
|
||||
GPIOH->OSPEEDR = 0xAAAA08A0;
|
||||
/* Configure PHx pins Output type to push-pull */
|
||||
GPIOH->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PHx pins */
|
||||
GPIOH->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PIx pins to FMC Alternate function */
|
||||
GPIOI->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOI->AFR[1] = 0x00000CC0;
|
||||
/* Configure PIx pins in Alternate function mode */
|
||||
GPIOI->MODER = 0x0028AAAA;
|
||||
/* Configure PIx pins speed to 50 MHz */
|
||||
GPIOI->OSPEEDR = 0x0028AAAA;
|
||||
/* Configure PIx pins Output type to push-pull */
|
||||
GPIOI->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PIx pins */
|
||||
GPIOI->PUPDR = 0x00000000;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
|
||||
|
||||
/*-- FMC Configuration -------------------------------------------------------*/
|
||||
/* Enable the FMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
|
||||
/* Configure and enable SDRAM bank1 */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCR[0] = 0x00001954;
|
||||
#else
|
||||
FMC_Bank5_6->SDCR[0] = 0x000019E4;
|
||||
#endif /* STM32F446xx */
|
||||
FMC_Bank5_6->SDTR[0] = 0x01115351;
|
||||
|
||||
/* SDRAM initialization sequence */
|
||||
/* Clock enable command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000011;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Delay */
|
||||
for (index = 0; index<1000; index++);
|
||||
|
||||
/* PALL command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000012;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Auto refresh command */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCMR = 0x000000F3;
|
||||
#else
|
||||
FMC_Bank5_6->SDCMR = 0x00000073;
|
||||
#endif /* STM32F446xx */
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* MRD register program */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCMR = 0x00044014;
|
||||
#else
|
||||
FMC_Bank5_6->SDCMR = 0x00046014;
|
||||
#endif /* STM32F446xx */
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Set refresh count */
|
||||
tmpreg = FMC_Bank5_6->SDRTR;
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1));
|
||||
#else
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
|
||||
#endif /* STM32F446xx */
|
||||
|
||||
/* Disable write protection */
|
||||
tmpreg = FMC_Bank5_6->SDCR[0];
|
||||
FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
|
||||
#endif /* DATA_IN_ExtSDRAM */
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */
|
||||
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
|
||||
|| defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
|
||||
#if defined(DATA_IN_ExtSRAM)
|
||||
/*-- GPIOs Configuration -----------------------------------------------------*/
|
||||
/* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
|
||||
RCC->AHB1ENR |= 0x00000078;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x00CCC0CC;
|
||||
GPIOD->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xAAAA0A8A;
|
||||
/* Configure PDx pins speed to 100 MHz */
|
||||
GPIOD->OSPEEDR = 0xFFFF0FCF;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00CC0CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA828A;
|
||||
/* Configure PEx pins speed to 100 MHz */
|
||||
GPIOE->OSPEEDR = 0xFFFFC3CF;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0x00CCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCC0000;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA000AAA;
|
||||
/* Configure PFx pins speed to 100 MHz */
|
||||
GPIOF->OSPEEDR = 0xFF000FFF;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0x00CCCCCC;
|
||||
GPIOG->AFR[1] = 0x000000C0;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0x00085AAA;
|
||||
/* Configure PGx pins speed to 100 MHz */
|
||||
GPIOG->OSPEEDR = 0x000CAFFF;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
/*-- FMC/FSMC Configuration --------------------------------------------------*/
|
||||
/* Enable the FMC/FSMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
||||
#if defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001091;
|
||||
FMC_Bank1->BTCR[3] = 0x00110212;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F469xx || STM32F479xx */
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
|
||||
|| defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FSMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FSMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF;
|
||||
#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */
|
||||
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\
|
||||
STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx */
|
||||
(void)(tmp);
|
||||
}
|
||||
#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user