This commit is contained in:
kr rt 2025-04-07 03:34:21 +03:00
commit d4669d6cb7
62 changed files with 20001 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
build/
*.sh
local/

33
Makefile Normal file
View File

@ -0,0 +1,33 @@
SHELL=/bin/bash
# в этой папке храним все .mk файлы
DIR_MK=./tools/makefiles
include $(DIR_MK)/settings.mk
all: dir_build
make all --file=$(DIR_MK)/mc_firmware.mk DIR_MK=$(DIR_MK)
doc: dir_build
make doc --file=$(DIR_MK)/mc_firmware.mk DIR_MK=$(DIR_MK)
check: dir_build
make check --file=$(DIR_MK)/mc_firmware.mk DIR_MK=$(DIR_MK)
test: dir_build
@echo $(MC_UTESTS_OUTPATH_OBJS) $(MC_UTESTS_OUTPATH_LIB) $(MC_UTESTS)
make --file=$(DIR_MK)/utests.mk DIR_MK=$(DIR_MK)
dir_build:
mkdir -p ${MAIN_OUTPATH}
clean:
rm -rf ${MAIN_OUTPATH}
# для загрузи прошивки в мк, нужно забрать с репозитория microcontroller_flash_uploader и сделать переменную окружения
ifeq ($(strip $(MC_UPLOADER)),)
$(info Переменная MC_UPLOADER не задана)
else
include $(MC_UPLOADER)/flash_uploader.mk #monitor reset halt
endif

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# Программная часть проекта
### Кроме cmsis и xpintf.h всё написано руками.
Код в процессе, нужно много дописывать и переписывать.
Архитектура прошивки крайне проста, после инициализации мы попадаем в бесконечный
цикл где обрабатываем модас трафик, производим измерения, и т.д.
uart и i2c работают по DMA и не блокируют цикл. Все временные интервалы измеряются о системному таймеру.
Система сборки поддерживает разные сценарии:
```
make all #сборка прошивки
make check #пройти статическим анализатором
make doc #собрать doxygen
make test #сборка тестов
make flash #записать прошивку
make gdb #запуск отладчика
```
Структура проекта:
```
.
├── Makefile - ссылается на файлы в ./tools/makefiles
├── src
│ ├── core - cmsis, ld, startup
│ ├── lib - код в котором нет обращения к регистрам
│ ├── plib - код в отором идёт работа с регистрами
│ └── main.c - main прошики
├── src_tests
│ ├── tests - тесты
│ ├── mock_file - обёртки для тестов
│ └── main.cpp - main тестов
└── tools
├── cppcheck_conf - файлы статического анализатора
├── dockerfile - для запуска в контейнере
├── doxygen_conf - настройки для doxygen
├── Jenkinsfile - попытка в CI-CD
└── makefiles
├── mc_firmware.mk - сборка прошивка
├── settings.mk - все настройки, ключи файлы, директории
└── utests.mk - сборка тестов
```

View File

@ -0,0 +1,185 @@
/*
******************************************************************************
**
** @file : LinkerScript.ld
**
** @author : Auto-generated by STM32CubeIDE
**
** @brief : Linker script for STM32G030F6Px Device from STM32G0 series
** 32Kbytes FLASH
** 8Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
******************************************************************************
** @attention
**
** Copyright (c) 2022 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.
**
******************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 32K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

283
src/core/cmsis_compiler.h Normal file
View File

@ -0,0 +1,283 @@
/**************************************************************************//**
* @file cmsis_compiler.h
* @brief CMSIS compiler generic header file
* @version V5.1.0
* @date 09. October 2018
******************************************************************************/
/*
* Copyright (c) 2009-2018 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CMSIS_COMPILER_H
#define __CMSIS_COMPILER_H
#include <stdint.h>
/*
* Arm Compiler 4/5
*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*
* Arm Compiler 6.6 LTM (armclang)
*/
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100)
#include "cmsis_armclang_ltm.h"
/*
* Arm Compiler above 6.10.1 (armclang)
*/
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
#include "cmsis_armclang.h"
/*
* GNU Compiler
*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*
* IAR Compiler
*/
#elif defined ( __ICCARM__ )
#include <cmsis_iccarm.h>
/*
* TI Arm Compiler
*/
#elif defined ( __TI_ARM__ )
#include <cmsis_ccs.h>
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __STATIC_INLINE
#endif
#ifndef __NO_RETURN
#define __NO_RETURN __attribute__((noreturn))
#endif
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __attribute__((packed))
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT struct __attribute__((packed))
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION union __attribute__((packed))
#endif
#ifndef __UNALIGNED_UINT32 /* deprecated */
struct __attribute__((packed)) T_UINT32 { uint32_t v; };
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
#endif
#ifndef __UNALIGNED_UINT16_WRITE
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT16_READ
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
#endif
#ifndef __UNALIGNED_UINT32_WRITE
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __attribute__((aligned(x)))
#endif
#ifndef __RESTRICT
#define __RESTRICT __restrict
#endif
#ifndef __COMPILER_BARRIER
#warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.
#define __COMPILER_BARRIER() (void)0
#endif
/*
* TASKING Compiler
*/
#elif defined ( __TASKING__ )
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __STATIC_INLINE
#endif
#ifndef __NO_RETURN
#define __NO_RETURN __attribute__((noreturn))
#endif
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __packed__
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT struct __packed__
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION union __packed__
#endif
#ifndef __UNALIGNED_UINT32 /* deprecated */
struct __packed__ T_UINT32 { uint32_t v; };
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
#endif
#ifndef __UNALIGNED_UINT16_WRITE
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT16_READ
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
#endif
#ifndef __UNALIGNED_UINT32_WRITE
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __align(x)
#endif
#ifndef __RESTRICT
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
#define __RESTRICT
#endif
#ifndef __COMPILER_BARRIER
#warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.
#define __COMPILER_BARRIER() (void)0
#endif
/*
* COSMIC Compiler
*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#ifndef __ASM
#define __ASM _asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __STATIC_INLINE
#endif
#ifndef __NO_RETURN
// NO RETURN is automatically detected hence no warning here
#define __NO_RETURN
#endif
#ifndef __USED
#warning No compiler specific solution for __USED. __USED is ignored.
#define __USED
#endif
#ifndef __WEAK
#define __WEAK __weak
#endif
#ifndef __PACKED
#define __PACKED @packed
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT @packed struct
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION @packed union
#endif
#ifndef __UNALIGNED_UINT32 /* deprecated */
@packed struct T_UINT32 { uint32_t v; };
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
#endif
#ifndef __UNALIGNED_UINT16_WRITE
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT16_READ
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
#endif
#ifndef __UNALIGNED_UINT32_WRITE
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
#endif
#ifndef __ALIGNED
#warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored.
#define __ALIGNED(x)
#endif
#ifndef __RESTRICT
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
#define __RESTRICT
#endif
#ifndef __COMPILER_BARRIER
#warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored.
#define __COMPILER_BARRIER() (void)0
#endif
#else
#error Unknown compiler.
#endif
#endif /* __CMSIS_COMPILER_H */

2168
src/core/cmsis_gcc.h Normal file

File diff suppressed because it is too large Load Diff

39
src/core/cmsis_version.h Normal file
View File

@ -0,0 +1,39 @@
/**************************************************************************//**
* @file cmsis_version.h
* @brief CMSIS Core(M) Version definitions
* @version V5.0.3
* @date 24. June 2019
******************************************************************************/
/*
* Copyright (c) 2009-2019 ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined (__clang__)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CMSIS_VERSION_H
#define __CMSIS_VERSION_H
/* CMSIS Version definitions */
#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */
#define __CM_CMSIS_VERSION_SUB ( 3U) /*!< [15:0] CMSIS Core(M) sub version */
#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \
__CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */
#endif

1085
src/core/core_cm0plus.h Normal file

File diff suppressed because it is too large Load Diff

272
src/core/mpu_armv7.h Normal file
View File

@ -0,0 +1,272 @@
/******************************************************************************
* @file mpu_armv7.h
* @brief CMSIS MPU API for Armv7-M MPU
* @version V5.1.0
* @date 08. March 2019
******************************************************************************/
/*
* Copyright (c) 2017-2019 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined (__clang__)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef ARM_MPU_ARMV7_H
#define ARM_MPU_ARMV7_H
#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes
#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes
#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes
#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes
#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes
#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte
#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes
#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes
#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes
#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes
#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes
#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes
#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes
#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes
#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes
#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte
#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes
#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes
#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes
#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes
#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes
#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes
#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes
#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes
#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes
#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte
#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes
#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes
#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access
#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only
#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only
#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access
#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only
#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access
/** MPU Region Base Address Register Value
*
* \param Region The region to be configured, number 0 to 15.
* \param BaseAddress The base address for the region.
*/
#define ARM_MPU_RBAR(Region, BaseAddress) \
(((BaseAddress) & MPU_RBAR_ADDR_Msk) | \
((Region) & MPU_RBAR_REGION_Msk) | \
(MPU_RBAR_VALID_Msk))
/**
* MPU Memory Access Attributes
*
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
* \param IsShareable Region is shareable between multiple bus masters.
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
*/
#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \
((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \
(((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \
(((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \
(((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk))
/**
* MPU Region Attribute and Size Register Value
*
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_.
* \param SubRegionDisable Sub-region disable field.
* \param Size Region size of the region to be configured, for example 4K, 8K.
*/
#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \
((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \
(((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \
(((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \
(((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \
(((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \
(((MPU_RASR_ENABLE_Msk))))
/**
* MPU Region Attribute and Size Register Value
*
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
* \param IsShareable Region is shareable between multiple bus masters.
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
* \param SubRegionDisable Sub-region disable field.
* \param Size Region size of the region to be configured, for example 4K, 8K.
*/
#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \
ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)
/**
* MPU Memory Access Attribute for strongly ordered memory.
* - TEX: 000b
* - Shareable
* - Non-cacheable
* - Non-bufferable
*/
#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)
/**
* MPU Memory Access Attribute for device memory.
* - TEX: 000b (if shareable) or 010b (if non-shareable)
* - Shareable or non-shareable
* - Non-cacheable
* - Bufferable (if shareable) or non-bufferable (if non-shareable)
*
* \param IsShareable Configures the device memory as shareable or non-shareable.
*/
#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))
/**
* MPU Memory Access Attribute for normal memory.
* - TEX: 1BBb (reflecting outer cacheability rules)
* - Shareable or non-shareable
* - Cacheable or non-cacheable (reflecting inner cacheability rules)
* - Bufferable or non-bufferable (reflecting inner cacheability rules)
*
* \param OuterCp Configures the outer cache policy.
* \param InnerCp Configures the inner cache policy.
* \param IsShareable Configures the memory as shareable or non-shareable.
*/
#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U))
/**
* MPU Memory Access Attribute non-cacheable policy.
*/
#define ARM_MPU_CACHEP_NOCACHE 0U
/**
* MPU Memory Access Attribute write-back, write and read allocate policy.
*/
#define ARM_MPU_CACHEP_WB_WRA 1U
/**
* MPU Memory Access Attribute write-through, no write allocate policy.
*/
#define ARM_MPU_CACHEP_WT_NWA 2U
/**
* MPU Memory Access Attribute write-back, no write allocate policy.
*/
#define ARM_MPU_CACHEP_WB_NWA 3U
/**
* Struct for a single MPU Region
*/
typedef struct {
uint32_t RBAR; //!< The region base address register value (RBAR)
uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR
} ARM_MPU_Region_t;
/** Enable the MPU.
* \param MPU_Control Default access permissions for unconfigured regions.
*/
__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
{
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
#endif
__DSB();
__ISB();
}
/** Disable the MPU.
*/
__STATIC_INLINE void ARM_MPU_Disable(void)
{
__DMB();
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
#endif
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
}
/** Clear and disable the given MPU region.
* \param rnr Region number to be cleared.
*/
__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
{
MPU->RNR = rnr;
MPU->RASR = 0U;
}
/** Configure an MPU region.
* \param rbar Value for RBAR register.
* \param rsar Value for RSAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)
{
MPU->RBAR = rbar;
MPU->RASR = rasr;
}
/** Configure the given MPU region.
* \param rnr Region number to be configured.
* \param rbar Value for RBAR register.
* \param rsar Value for RSAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)
{
MPU->RNR = rnr;
MPU->RBAR = rbar;
MPU->RASR = rasr;
}
/** Memcopy with strictly ordered memory access, e.g. for register targets.
* \param dst Destination data is copied to.
* \param src Source data is copied from.
* \param len Amount of data words to be copied.
*/
__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
{
uint32_t i;
for (i = 0U; i < len; ++i)
{
dst[i] = src[i];
}
}
/** Load the given number of MPU regions from a table.
* \param table Pointer to the MPU configuration table.
* \param cnt Amount of regions to be configured.
*/
__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt)
{
const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
while (cnt > MPU_TYPE_RALIASES) {
ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);
table += MPU_TYPE_RALIASES;
cnt -= MPU_TYPE_RALIASES;
}
ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);
}
#endif

17
src/core/platform.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef HARDWARE_H_
#define HARDWARE_H_
#include "stm32g0xx.h"
#include "bool.h"
#define NOP() {__asm__ volatile("NOP");}
#define RESET_MK() NVIC_SystemReset();
#define P_SYSCLK 64000000
#define MODBUS_IRQ_PIOITY_LEVEL 1
#define I2C_IRQ_PIOITY_LEVEL 2
#endif

View File

@ -0,0 +1,270 @@
/**
******************************************************************************
* @file startup_stm32g030xx.s
* @author MCD Application Team
* @brief STM32G030xx devices vector table GCC toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M0+ processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 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.
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m0plus
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* Call the clock system initialization function.*/
bl SystemInit
/* Copy the data segment initializers from flash to SRAM */
ldr r0, =_sdata
ldr r1, =_edata
ldr r2, =_sidata
movs r3, #0
b LoopCopyDataInit
CopyDataInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyDataInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyDataInit
/* Zero fill the bss segment. */
ldr r2, =_sbss
ldr r4, =_ebss
movs r3, #0
b LoopFillZerobss
FillZerobss:
str r3, [r2]
adds r2, r2, #4
LoopFillZerobss:
cmp r2, r4
bcc FillZerobss
/* Call static constructors */
//bl __libc_init_array //не исользуем стандартную библиотеку, оэтому убрал
/* Call the application s entry point.*/
bl main
LoopForever:
b LoopForever
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M0. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word 0
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler /* Window WatchDog */
.word 0 /* reserved */
.word RTC_TAMP_IRQHandler /* RTC through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
.word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
.word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
.word 0 /* reserved */
.word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
.word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
.word DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler /* DMA1 Channel 4 to Channel 5, DMAMUX1 overrun */
.word ADC1_IRQHandler /* ADC1 */
.word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word 0 /* reserved */
.word TIM3_IRQHandler /* TIM3 */
.word 0 /* reserved */
.word 0 /* reserved */
.word TIM14_IRQHandler /* TIM14 */
.word 0 /* reserved */
.word TIM16_IRQHandler /* TIM16 */
.word TIM17_IRQHandler /* TIM17 */
.word I2C1_IRQHandler /* I2C1 */
.word I2C2_IRQHandler /* I2C2 */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word 0 /* reserved */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak RTC_TAMP_IRQHandler
.thumb_set RTC_TAMP_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_1_IRQHandler
.thumb_set EXTI0_1_IRQHandler,Default_Handler
.weak EXTI2_3_IRQHandler
.thumb_set EXTI2_3_IRQHandler,Default_Handler
.weak EXTI4_15_IRQHandler
.thumb_set EXTI4_15_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_3_IRQHandler
.thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
.weak DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler
.thumb_set DMA1_Ch4_5_DMAMUX1_OVR_IRQHandler,Default_Handler
.weak ADC1_IRQHandler
.thumb_set ADC1_IRQHandler,Default_Handler
.weak TIM1_BRK_UP_TRG_COM_IRQHandler
.thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM14_IRQHandler
.thumb_set TIM14_IRQHandler,Default_Handler
.weak TIM16_IRQHandler
.thumb_set TIM16_IRQHandler,Default_Handler
.weak TIM17_IRQHandler
.thumb_set TIM17_IRQHandler,Default_Handler
.weak I2C1_IRQHandler
.thumb_set I2C1_IRQHandler,Default_Handler
.weak I2C2_IRQHandler
.thumb_set I2C2_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler

7439
src/core/stm32g030xx.h Normal file

File diff suppressed because it is too large Load Diff

244
src/core/stm32g0xx.h Normal file
View File

@ -0,0 +1,244 @@
/**
******************************************************************************
* @file stm32g0xx.h
* @author MCD Application Team
* @brief CMSIS STM32G0xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32G0xx device used in the target application
* - To use or not the peripherals drivers in application code(i.e.
* code will be based on direct access to peripherals registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 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 stm32g0xx
* @{
*/
#ifndef STM32G0xx_H
#define STM32G0xx_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32G0)
#define STM32G0
#endif /* STM32G0 */
/* Uncomment the line below according to the target STM32G0 device used in your
application
*/
#if !defined (STM32G071xx) && !defined (STM32G081xx) && !defined (STM32G070xx) \
&& !defined (STM32G030xx) && !defined (STM32G031xx) && !defined (STM32G041xx) \
&& !defined (STM32G0B0xx) && !defined (STM32G0B1xx) && !defined (STM32G0C1xx) \
&& !defined (STM32G050xx) && !defined (STM32G051xx) && !defined (STM32G061xx)
/* #define STM32G0B0xx */ /*!< STM32G0B0xx Devices */
/* #define STM32G0B1xx */ /*!< STM32G0B1xx Devices */
/* #define STM32G0C1xx */ /*!< STM32G0C1xx Devices */
/* #define STM32G070xx */ /*!< STM32G070xx Devices */
/* #define STM32G071xx */ /*!< STM32G071xx Devices */
/* #define STM32G081xx */ /*!< STM32G081xx Devices */
/* #define STM32G050xx */ /*!< STM32G050xx Devices */
/* #define STM32G051xx */ /*!< STM32G051xx Devices */
/* #define STM32G061xx */ /*!< STM32G061xx Devices */
/* #define STM32G030xx */ /*!< STM32G030xx Devices */
/* #define STM32G031xx */ /*!< STM32G031xx Devices */
/* #define STM32G041xx */ /*!< STM32G041xx Devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number $VERSION$
*/
#define __STM32G0_CMSIS_VERSION_MAIN (0x01U) /*!< [31:24] main version */
#define __STM32G0_CMSIS_VERSION_SUB1 (0x04U) /*!< [23:16] sub1 version */
#define __STM32G0_CMSIS_VERSION_SUB2 (0x02U) /*!< [15:8] sub2 version */
#define __STM32G0_CMSIS_VERSION_RC (0x00U) /*!< [7:0] release candidate */
#define __STM32G0_CMSIS_VERSION ((__STM32G0_CMSIS_VERSION_MAIN << 24)\
|(__STM32G0_CMSIS_VERSION_SUB1 << 16)\
|(__STM32G0_CMSIS_VERSION_SUB2 << 8 )\
|(__STM32G0_CMSIS_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32G0B1xx)
#include "stm32g0b1xx.h"
#elif defined(STM32G0C1xx)
#include "stm32g0c1xx.h"
#elif defined(STM32G0B0xx)
#include "stm32g0b0xx.h"
#elif defined(STM32G071xx)
#include "stm32g071xx.h"
#elif defined(STM32G081xx)
#include "stm32g081xx.h"
#elif defined(STM32G070xx)
#include "stm32g070xx.h"
#elif defined(STM32G031xx)
#include "stm32g031xx.h"
#elif defined(STM32G041xx)
#include "stm32g041xx.h"
#elif defined(STM32G030xx)
#include "stm32g030xx.h"
#elif defined(STM32G051xx)
#include "stm32g051xx.h"
#elif defined(STM32G061xx)
#include "stm32g061xx.h"
#elif defined(STM32G050xx)
#include "stm32g050xx.h"
#else
#error "Please select first the target STM32G0xx device used in your application (in stm32g0xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_types
* @{
*/
typedef enum
{
RESET = 0,
SET = !RESET
} FlagStatus, ITStatus;
typedef enum
{
DISABLE = 0,
ENABLE = !DISABLE
} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum
{
SUCCESS = 0,
ERROR = !SUCCESS
} ErrorStatus;
/**
* @}
*/
/** @addtogroup Exported_macros
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
/* Use of interrupt control for register exclusive access */
/* Atomic 32-bit register access macro to set one or several bits */
#define ATOMIC_SET_BIT(REG, BIT) \
do { \
uint32_t primask; \
primask = __get_PRIMASK(); \
__set_PRIMASK(1); \
SET_BIT((REG), (BIT)); \
__set_PRIMASK(primask); \
} while(0)
/* Atomic 32-bit register access macro to clear one or several bits */
#define ATOMIC_CLEAR_BIT(REG, BIT) \
do { \
uint32_t primask; \
primask = __get_PRIMASK(); \
__set_PRIMASK(1); \
CLEAR_BIT((REG), (BIT)); \
__set_PRIMASK(primask); \
} while(0)
/* Atomic 32-bit register access macro to clear and set one or several bits */
#define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \
do { \
uint32_t primask; \
primask = __get_PRIMASK(); \
__set_PRIMASK(1); \
MODIFY_REG((REG), (CLEARMSK), (SETMASK)); \
__set_PRIMASK(primask); \
} while(0)
/* Atomic 16-bit register access macro to set one or several bits */
#define ATOMIC_SETH_BIT(REG, BIT) ATOMIC_SET_BIT(REG, BIT) \
/* Atomic 16-bit register access macro to clear one or several bits */
#define ATOMIC_CLEARH_BIT(REG, BIT) ATOMIC_CLEAR_BIT(REG, BIT) \
/* Atomic 16-bit register access macro to clear and set one or several bits */
#define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \
/*#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))*/
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32g0xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* STM32G0xx_H */
/**
* @}
*/
/**
* @}
*/

302
src/core/system_stm32g0xx.c Normal file
View File

@ -0,0 +1,302 @@
/**
******************************************************************************
* @file system_stm32g0xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-M0+ 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_stm32g0xx.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.
*
* After each device reset the HSI (8 MHz then 16 MHz) is used as system clock source.
* Then SystemInit() function is called, in "startup_stm32g0xx.s" file, to
* configure the system clock before to branch to main program.
*
* This file configures the system clock as follows:
*=============================================================================
*-----------------------------------------------------------------------------
* System Clock source | HSI
*-----------------------------------------------------------------------------
* SYSCLK(Hz) | 16000000
*-----------------------------------------------------------------------------
* HCLK(Hz) | 16000000
*-----------------------------------------------------------------------------
* AHB Prescaler | 1
*-----------------------------------------------------------------------------
* APB Prescaler | 1
*-----------------------------------------------------------------------------
* HSI Division factor | 1
*-----------------------------------------------------------------------------
* PLL_M | 1
*-----------------------------------------------------------------------------
* PLL_N | 8
*-----------------------------------------------------------------------------
* PLL_P | 7
*-----------------------------------------------------------------------------
* PLL_Q | 2
*-----------------------------------------------------------------------------
* PLL_R | 2
*-----------------------------------------------------------------------------
* Require 48MHz for RNG | Disabled
*-----------------------------------------------------------------------------
*=============================================================================
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 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 stm32g0xx_system
* @{
*/
/** @addtogroup STM32G0xx_System_Private_Includes
* @{
*/
#include "stm32g0xx.h"
#if !defined (HSE_VALUE)
#define HSE_VALUE (8000000UL) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
#if !defined (LSI_VALUE)
#define LSI_VALUE (32000UL) /*!< Value of LSI in Hz*/
#endif /* LSI_VALUE */
#if !defined (LSE_VALUE)
#define LSE_VALUE (32768UL) /*!< Value of LSE in Hz*/
#endif /* LSE_VALUE */
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Private_Defines
* @{
*/
/************************* Miscellaneous Configuration ************************/
/* 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 STM32G0xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Private_Variables
* @{
*/
/* The SystemCoreClock 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 = 16000000UL;
const uint32_t AHBPrescTable[16UL] = {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL, 6UL, 7UL, 8UL, 9UL};
const uint32_t APBPrescTable[8UL] = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL};
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system.
* @param None
* @retval None
*/
void SystemInit(void)
{
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation */
#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(**) / HSI division factor
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
*
* - If SYSCLK source is LSI, SystemCoreClock will contain the LSI_VALUE
*
* - If SYSCLK source is LSE, SystemCoreClock will contain the LSE_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 stm32g0xx_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 stm32g0xx_hal_conf.h file (default value
* 8 MHz), 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;
uint32_t pllvco;
uint32_t pllr;
uint32_t pllsource;
uint32_t pllm;
uint32_t hsidiv;
/* Get SYSCLK source -------------------------------------------------------*/
switch (RCC->CFGR & RCC_CFGR_SWS)
{
case RCC_CFGR_SWS_0: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case (RCC_CFGR_SWS_1 | RCC_CFGR_SWS_0): /* LSI used as system clock */
SystemCoreClock = LSI_VALUE;
break;
case RCC_CFGR_SWS_2: /* LSE used as system clock */
SystemCoreClock = LSE_VALUE;
break;
case RCC_CFGR_SWS_1: /* PLL used as system clock */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
SYSCLK = PLL_VCO / PLLR
*/
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL;
if(pllsource == 0x03UL) /* HSE used as PLL clock source */
{
pllvco = (HSE_VALUE / pllm);
}
else /* HSI used as PLL clock source */
{
pllvco = (HSI_VALUE / pllm);
}
pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL);
SystemCoreClock = pllvco/pllr;
break;
case 0x00000000U: /* HSI used as system clock */
default: /* HSI used as system clock */
hsidiv = (1UL << ((READ_BIT(RCC->CR, RCC_CR_HSIDIV))>> RCC_CR_HSIDIV_Pos));
SystemCoreClock = (HSI_VALUE/hsidiv);
break;
}
/* Compute HCLK clock frequency --------------------------------------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/

103
src/core/system_stm32g0xx.h Normal file
View File

@ -0,0 +1,103 @@
/**
******************************************************************************
* @file system_stm32g0xx.h
* @author MCD Application Team
* @brief CMSIS Cortex-M0+ Device System Source File for STM32G0xx devices.
******************************************************************************
* @attention
*
* Copyright (c) 2018-2021 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 stm32g0xx_system
* @{
*/
/**
* @brief Define to prevent recursive inclusion
*/
#ifndef SYSTEM_STM32G0XX_H
#define SYSTEM_STM32G0XX_H
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup STM32G0xx_System_Includes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Exported_types
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetSysClockFreq()
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.
*/
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
extern const uint32_t AHBPrescTable[16]; /*!< AHB prescalers table values */
extern const uint32_t APBPrescTable[8]; /*!< APB prescalers table values */
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Exported_Constants
* @{
*/
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Exported_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32G0xx_System_Exported_Functions
* @{
*/
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*SYSTEM_STM32G0XX_H */
/**
* @}
*/
/**
* @}
*/

17
src/lib/bool.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef BOOL_H_
#define BOOL_H_
#ifndef UTEST_BUILD
// #define true 1u
// #define false 0u
// typedef uint8_t bool;
typedef enum { false, true } bool;
#define TO_BOOL(n) ((n)!=0u)
#endif
#endif

229
src/lib/eeprom.c Normal file
View File

@ -0,0 +1,229 @@
/**
##############################################################################
@file eeprom.c
@brief Работаем с eeprom
@note eeprom_file_init читаем из памяти файл, если его нет то пишем свой
@note в eeprom_buf храним данные вычитанные
@note потом в eeprom_periodic_work сравниваем eeprom_buf и регистры модбаса
@note записывая в eepom значение в случае расхождения
##############################################################################
*/
#include "eeprom.h"
#include "i2c.h"
#include "modbus_regs_file.h"
#include "state_machine.h"
#include "modbus_config.h"
#define EEPROM_BUF_SIZE 50u //в байтах
#define I2C_WRITE_BUFER_SIZE 4u
#define EEPROM_ADR 0x50
static uint8_t init_data_check(uint8_t* data);
static bool eeprom_lock_read(uint16_t addr,uint8_t* data, uint8_t length);
static uint8_t init_end_data_check(uint8_t* data);
static void eeprom_write_file(void);
static bool write_regs(uint8_t* data);
static void eeprom_write_default_file(void);
static void save_reg_state(state_machine_dev* dev);
static void comparison_regs_state(state_machine_dev* dev);
static uint8_t i2c_write_bufer[I2C_WRITE_BUFER_SIZE];
static uint8_t reg_num; //количество регистров в файле
static uint8_t eeprom_buf[EEPROM_BUF_SIZE]; //зеркало i2c файла
static state_machine_dev st_dev = {plug_state, plug_state, 0u };
/**
@brief отправляем новое значение регистра
*/
static void save_reg_state(state_machine_dev* dev)
{
if(I2C_NOT_BUSY==i2c_write(EEPROM_ADR, &i2c_write_bufer, I2C_WRITE_BUFER_SIZE))
{
set_state_after_delay(comparison_regs_state,2u,&st_dev);
//xprintf("eeprom write\n");
}
return;
}
/**
@brief сравниваем eeprom_buf и регистры модбаса
*/
static void comparison_regs_state(state_machine_dev* dev)
{
for(uint8_t i=0;i<(reg_num*ONE_REG_SIZE);i+=ONE_REG_SIZE)
{
uint16_t reg_addr = (eeprom_buf[i]<<8)+eeprom_buf[i+1];
uint16_t buf_data = (eeprom_buf[i+3]<<8)+eeprom_buf[i+4];
uint8_t reg_type = eeprom_buf[i+2];
uint16_t reg_data;
MBRF_read_reg(reg_addr, &reg_data, reg_type);
//xprintf("reg write %x %d %x\n",reg_addr, reg_type, reg_data );
if(buf_data!=reg_data)
{
eeprom_buf[i+3] = (uint8_t)reg_data>>8;
eeprom_buf[i+4] = (uint8_t)reg_data;
i2c_write_bufer[0]=0u;
i2c_write_bufer[1]=i+LENGTH_INIT_DATA+3;
i2c_write_bufer[2]=eeprom_buf[i+3];
i2c_write_bufer[3]=eeprom_buf[i+4];
set_state(save_reg_state, &st_dev);
save_reg_state(&st_dev); //сразу выполняем
//xprintf("reg write %x %d %x\n",reg_addr, reg_type, reg_data);
break;
}
}
}
/**
@brief работа
*/
void eeprom_periodic_work(void)
{
execute_current_state(&st_dev);
return;
}
/**
@brief блокирущее чтение
@param addr адресс начала чтения
@param data указатель на массивкуда пишем из eeprom
@param length кол-во регистров
@return 0 в случае ошибки
*/
static bool eeprom_lock_read(uint16_t addr,uint8_t* data, uint8_t length)
{
bool ret = I2C_ERROR;
static uint8_t data_addr[2];
data_addr[0]=(uint8_t)addr>>8;
data_addr[1]=(uint8_t)addr;
if(I2C_OK==i2c_lock_write(EEPROM_ADR, &data_addr, 2u))
{
ret = i2c_lock_read(EEPROM_ADR,data,length);
}
return ret;
}
/**
@brief проверяем наличие файла
*/
void eeprom_file_init(void)
{
if(I2C_OK==eeprom_lock_read(0u, &eeprom_buf,LENGTH_INIT_DATA)) //если не получили NACK
{
reg_num = init_data_check(&eeprom_buf);
if(0u!=reg_num)
{
eeprom_lock_read(LENGTH_INIT_DATA+(reg_num*ONE_REG_SIZE), &eeprom_buf,LENGTH_END_DATA);
if(init_end_data_check(&eeprom_buf))
{
eeprom_lock_read((LENGTH_INIT_DATA), &eeprom_buf,reg_num*ONE_REG_SIZE);
if(write_regs(&eeprom_buf))
{
#ifdef DEBUG
xprintf("eeprom init end\n");
#endif
}
}
}else{
eeprom_write_default_file(); //если нету ничего запишем стандартные настройки
eeprom_file_init(); //плохое решение, переписать
#ifdef DEBUG
xprintf("eeprom default write\n");
#endif
}
set_state(comparison_regs_state, &st_dev);
}
#ifdef DEBUG
else {
#ifdef DEBUG
xprintf("eeprom NACK\n");
#endif
}
#endif
}
/**
@brief записывает значения в модбас регистры
@param уазатель на буфер с прочитанным файлом (в data[0] должны лежать данные регистра)
@retun 0 в случае если нашли регистр который не занесён в модбас файл
@retun 1 в случае если всё хорошо
@note в случае return 0 данные регистров до неизвечтного адресса будут записаны
*/
static bool write_regs(uint8_t* data)
{
bool ret =0u;
for(uint8_t i=0;i<(reg_num*ONE_REG_SIZE);i+=ONE_REG_SIZE)
{
uint16_t reg_addr = (data[i]<<8)+data[i+1];
uint16_t reg_data = (data[i+3]<<8)+data[i+4];
uint8_t reg_type = data[i+2];
if(MBR_OK!=MBRF_write_reg(reg_addr, reg_data, reg_type))
{
#ifdef DEBUG
xprintf("reg write eror %x %d %x\n",reg_addr, reg_type, reg_data);
#endif
break;
}
ret =1u;
}
return ret;
}
/**
@brief проверяем начало напяти на наличие ключевых битов
*/
static uint8_t init_data_check(uint8_t* data)
{
uint8_t ret =0u;
if((data[0]==EEPROM_S_DATA_FLAG)&&(data[1]==EEPROM_S_DATA_FLAG))
{
if(FIRMWARE_VERSION==data[2]) //пока это бесполезно, задел на будущее
{
#ifdef DEBUG
xprintf("FIRMWARE_VERSION 0x%02x\n",data[2]);
#endif
uint8_t reg_num = data[3];
if(reg_num<(EEPROM_BUF_SIZE/ONE_REG_SIZE))
{
ret=reg_num;
#ifdef DEBUG
xprintf("file_size %d\n",reg_num);
#endif
}
}
}
return ret;
}
/**
@brief проверяем конец файла на наличие ключевых битов
*/
static uint8_t init_end_data_check(uint8_t* data)
{
uint8_t ret =0u;
if((data[0]==EEPROM_E_DATA_FLAG)&&(data[1]==EEPROM_E_DATA_FLAG))
{
#ifdef DEBUG
xprintf("init_end_data_check successfully\n");
#endif
ret = 1u;
}
return ret;
}
/**
@brief записываем дефолтные настройки
*/
static void eeprom_write_default_file(void)
{
uint8_t buf[] = {DEFAULT_FILE_START_ADDR0,DEFAULT_FILE_START_ADDR1,DEFAULT_FILE};
i2c_lock_write(EEPROM_ADR,buf,sizeof(buf));
}

9
src/lib/eeprom.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef EEPROM_LIB_H_
#define EEPROM_LIB_H_
#include "platform.h"
void eeprom_file_init(void);
void eeprom_eeprom_periodic_work(void);
#endif

96
src/lib/modbus_config.h Normal file
View File

@ -0,0 +1,96 @@
/**
##############################################################################
@file modbus_config.h
@brief Все define для адресов, стандартных значений и типов регистров
##############################################################################
*/
#ifndef MODBUS_CONFIG_H_
#define MODBUS_CONFIG_H_
#include "platform.h"
#include "modbus_regs_file.h"
#define MBADDR_BAUD_RATE 0x006E
#define MBTYPE_BAUD_RATE MBR_holding
#define MBDDATA_BAUD_RATE 96u
#define MBADDR_PARITY_BIT 0x006F
#define MBTYPE_PARITY_BIT MBR_holding
#define MBDDATA_PARITY_BIT 0u
#define MBADDR_STOP_BIT 0x0070
#define MBTYPE_STOP_BIT MBR_holding
#define MBDDATA_STOP_BIT 2u
#define MBADDR_SLAVE_ADDR 0x0080
#define MBTYPE_SLAVE_ADDR MBR_holding
#define MBDDATA_SLAVE_ADDR 0x4A
#define MBADDR_TIME_SEC0 0x0068
#define MBADDR_TIME_SEC1 0x0069
#define MBTYPE_TIME_SEC MBR_input
#define MBADDR_STATE_DOUT 0x0012
#define MBDDATA_STATE_DOUT 0x0000 //modbus default data
#define MBTYPE_STATE_DOUT MBR_coils
#define MBADDR_STATUS_LED 0x0082
#define MBDDATA_STATUS_LED 0x0000 //modbus default data
#define MBTYPE_STATUS_LED MBR_holding
#define MBADDR_TEMPERATURE 0x0
#define MBDDATA_TEMPERATURE 0x7FFF
#define MBTYPE_TEMPERATURE MBR_input
#define MBADDR_TEMPERATURE_COMPENSATION 0x00F5
#define MBDDATA_TEMPERATURE_COMPENSATION 0x0
#define MBTYPE_TEMPERATURE_COMPENSATION MBR_holding
#define MBADDR_HUMIDITY 0x1
#define MBDDATA_HUMIDITY 0x7FFF
#define MBTYPE_HUMIDITY MBR_input
#define MBADDR_RESET 0x0078
#define MBDDATA_RESET 0x0000
#define MBTYPE_RESET MBR_holding
#define MBADDR_MODEL 0x00C8
#define MBDDATA_MODEL 0x5465,0x6D70,0x436F,0x6E74,0x726F,0x6C00 //Модель устройства (строка asci "TempControl") адресса 200-205
#define MBTYPE_MODEL MBR_input
//для записи в еепром если не нашли существующих настроек
//чтоб добавить регистр в файл измените DEFAULT_FILE_NUMS_ADDR и DEFAULT_FILE_NUMS_ADDR возможно нужно изменить EEPROM_BUF_SIZE
#define FIRMWARE_VERSION 0x0020 //это пока что для формальности. надо родумать и заменить/перенести
#define EEPROM_S_DATA_FLAG 0xA5
#define EEPROM_E_DATA_FLAG 0x6E
#define LENGTH_INIT_DATA 4u //EEPROM_S_DATA_FLAG*2 + DEFAULT_FILE_NUMS_ADDR + FIRMWARE_VERSION
#define LENGTH_END_DATA 2u //EEPROM_E_DATA_FLAG*2
#define ONE_REG_SIZE 5u //2 байта адреса + 2 байт типа + 2 байта данных
#define U16_TO_U8_OLDER_BYTE(b) ((uint8_t)((uint16_t)(b)>>8u))
#define OB(b) U16_TO_U8_OLDER_BYTE(b)
#define OJ(b) (uint8_t)(b)
#define DEFAULT_FILE_START_ADDR0 (uint8_t)0x0
#define DEFAULT_FILE_START_ADDR1 (uint8_t)0x0
#define DEFAULT_FILE_NUMS_ADDR 7u //кол-во регистров в файле
#define DEFAULT_FILE EEPROM_S_DATA_FLAG,EEPROM_S_DATA_FLAG,FIRMWARE_VERSION,DEFAULT_FILE_NUMS_ADDR, \
OB(MBADDR_BAUD_RATE),OJ(MBADDR_BAUD_RATE),MBTYPE_BAUD_RATE,OB(MBDDATA_BAUD_RATE),OJ(MBDDATA_BAUD_RATE), \
OB(MBADDR_PARITY_BIT),OJ(MBADDR_PARITY_BIT),MBTYPE_PARITY_BIT,OB(MBDDATA_PARITY_BIT),OJ(MBDDATA_PARITY_BIT), \
OB(MBADDR_STOP_BIT),OJ(MBADDR_STOP_BIT),MBTYPE_STOP_BIT,OB(MBDDATA_STOP_BIT),OJ(MBDDATA_STOP_BIT), \
OB(MBADDR_SLAVE_ADDR),OJ(MBADDR_SLAVE_ADDR),MBTYPE_SLAVE_ADDR,OB(MBDDATA_SLAVE_ADDR),OJ(MBDDATA_SLAVE_ADDR), \
OB(MBADDR_TEMPERATURE_COMPENSATION),OJ(MBADDR_TEMPERATURE_COMPENSATION),MBTYPE_TEMPERATURE_COMPENSATION,OB(MBDDATA_TEMPERATURE_COMPENSATION),OJ(MBDDATA_TEMPERATURE_COMPENSATION), \
OB(MBADDR_STATE_DOUT),OJ(MBADDR_STATE_DOUT),MBTYPE_STATE_DOUT,OB(MBDDATA_STATE_DOUT),OJ(MBDDATA_STATE_DOUT), \
OB(MBADDR_STATUS_LED),OJ(MBADDR_STATUS_LED),MBTYPE_STATUS_LED,OB(MBDDATA_STATUS_LED),OJ(MBDDATA_STATUS_LED), \
EEPROM_E_DATA_FLAG,EEPROM_E_DATA_FLAG
#endif

360
src/lib/modbus_regs_file.c Normal file
View File

@ -0,0 +1,360 @@
/**
##############################################################################
@file modbus_regs_file.c
@brief Инициализацция и работа с регистровым файлом, для модбас
@details Храним регистры в структуре modbus_regs_file, для каждого типа регистра есть своя "линия" (массив)
Для использования, в начале нужно вызвать MBRF_init_start, "создать" (инициальзировать) регистры
через MBRF_create_reg и вызвать MBRF_create_reg, ТОЛЬКО ПОСЛЕ этого разрешается ипользовать
функции чтения-записи регистров.
@note в текущей реализации в функциях чтения-записи нет проверки на то что инициализация файла была
закончена, ответственность лежит на программисте. Стоит вызывать init_start и init_end в одном месте
##############################################################################
*/
#include "platform.h"
#include "modbus_regs_file.h"
typedef struct{
uint16_t addr; //register address
uint16_t* data;
}MB_register;
typedef struct{
MB_register* line[4];
TYPE_LINE_LEN len[4];
TYPE_LINE_LEN len_max[4];
bool create_reg_en_flag; //если флаг = 1 то разрешенно "создавать" регистры
}modbus_regs_file;
#define R_DATA(indx, type) (*(MB_R_file.line[(type)][(indx)].data))
#define R_DATA_POINTER(indx, type) (MB_R_file.line[(type)][(indx)].data)
#define R_DATA_BOOL(indx, type) (((R_DATA((indx_start+i),reg_type)) != 0u) ? 1u : 0u) //равно либо 0u либо 1u, страшно, но соответствует равилам misra
#define R_ADDR(indx,type) (MB_R_file.line[(type)][(indx)].addr)
#define R_LEN(type) (MB_R_file.len[(type)])
static void MBRF_swap(TYPE_LINE_LEN len_position_reg_1,TYPE_LINE_LEN len_position_reg_2, MB_register reg[]);
static MBR_status MBRF_selection_sort(MB_register reg[],TYPE_LINE_LEN len);
static MBR_status MBRF_binary_search(const MB_register reg[],TYPE_LINE_LEN len, uint16_t seach_addr, uint16_t* return_id);
static modbus_regs_file MB_R_file={.create_reg_en_flag=false};
/**
@brief "начало" инициализации
@brief инициализируем ключевую структуру MB_R_file и ставим create_reg_en_flag
*/
void MBRF_init_start(void)
{
static MB_register holding_line[MAX_QUANTITY_HOLDING_REGS];
static MB_register input_line[MAX_QUANTITY_INPUT_REGS];
static MB_register input_discrete_line[MAX_QUANTITY_INPUT_DISCRETE_REGS];
static MB_register colis_line[MAX_QUANTITY_COLIS_REGS];
MB_R_file.line[MBR_holding]=holding_line;
MB_R_file.line[MBR_input]=input_line;
MB_R_file.line[MBR_input_discrete]=input_discrete_line;
MB_R_file.line[MBR_coils]=colis_line;
MB_R_file.len[MBR_holding]=0u;
MB_R_file.len[MBR_input]=0u;
MB_R_file.len[MBR_input_discrete]=0u;
MB_R_file.len[MBR_coils]=0u;
MB_R_file.len_max[MBR_holding]=MAX_QUANTITY_HOLDING_REGS;
MB_R_file.len_max[MBR_input]=MAX_QUANTITY_INPUT_REGS;
MB_R_file.len_max[MBR_input_discrete]=MAX_QUANTITY_INPUT_DISCRETE_REGS;
MB_R_file.len_max[MBR_coils]=MAX_QUANTITY_COLIS_REGS;
MB_R_file.create_reg_en_flag=true; //разрешаем создавать регистры
return;
}
/**
@brief "Конец" инициализации
@brief сортируем все "линии" регистров, выискивая дубликаты
@brief ставим create_reg_en_flag
@retun MBR_ADDR_ERROR если встретили одинаковые адресса
MBR_OK в нормальном случае
@note текущая реализация отыскивает дубликаты только в рамках одной строки,
@note например мы можем создать регистры с адрессом 0x23 типа coils и input одновременно
*/
MBR_status MBRF_init_end(void)
{
MBR_status ret = MBR_OK;
for(MBR_reg_type i=0;i<=MBR_coils;i++)
{
if(MBR_OK!=MBRF_selection_sort(MB_R_file.line[i], R_LEN(i)))
{
ret=MBR_ADDR_ERROR;
}
}
MB_R_file.create_reg_en_flag=false; //запрещаем создавать регистры
return ret;
}
/**
@brief Инициализирует регистр
@param addr modbus адресс регистра
@param data указатель на данные которые в него положим
@param тип регистра в который пишем
@retun MBR_CEATE_DISABLE если стоит блоировка
MBR_LEN_ERROR если регистров этого типа в файле больше чем MAX_QUANTITY
MBR_OK в нормальном случае
MBR_ERROR в случае других ошибок
*/
MBR_status MBRF_create_reg(uint16_t addr, uint16_t* data, MBR_reg_type reg_type)
{
MBR_status ret = MBR_ERROR;
if(MB_R_file.create_reg_en_flag==true)
{
if(data!=0u)
{
if(R_LEN(reg_type)<MB_R_file.len_max[reg_type])
{
R_DATA_POINTER(R_LEN(reg_type),reg_type)=data;
R_ADDR(R_LEN(reg_type),reg_type)=addr;
R_LEN(reg_type)++;
ret=MBR_OK;
}else{
ret=MBR_LEN_ERROR;
}
}
}else{
ret = MBR_CEATE_DISABLE;
}
return ret;
}
/**
@brief Читаем данные из регистра (он должен быть инициализирован)
@param read_addr modbus адресс регистра с которого читаем
@param return_data по этому указателю запишем данные в случае успеха
@param тип регистра в который пишем
@retun MBR_OK в нормальном случае, если не нашли регистр то MBR_ERROR
*/
MBR_status MBRF_read_reg(uint16_t read_addr, uint16_t* return_data, MBR_reg_type reg_type)
{
uint16_t indx;
MBR_status ret = MBRF_binary_search(MB_R_file.line[reg_type],R_LEN(reg_type), read_addr, &indx);
if(ret==MBR_OK)
{
*return_data=R_DATA(indx,reg_type);
}
return ret;
}
/**
@brief Читаем данные из регистров (они должен быть инициализированы и идти без "окон")
@param read_addr_start modbus адресс первого регистра
@param reg_len кол-во регистров
@param return_data указатель на массив в который запишем результат
@param тип регистра
@retun MBR_OK в нормальном случае, MBR_ERROR если не смогли найти
read_addr_start или read_addr_end или между ними есть "окно"
@note в текущей реализации нету проверки на размер return_data
@note например мы читаем 5 регистра начиная с 0x31:
@note все 3 регистра должны существовать, MBR_LEN_ERROR если хотим прочитать 0 регистров, иначе return MBR_ERROR
*/
MBR_status MBRF_multiple_read_reg(uint16_t read_addr_start, uint16_t reg_len, uint8_t return_data[], MBR_reg_type reg_type)
{
uint16_t indx_start; //indx_start_start не назван так, потому что в цикле потом с ним же работаем
uint16_t indx_end;
MBR_status ret=MBR_ERROR;
if(reg_len>0u)
{
ret = MBRF_binary_search(MB_R_file.line[reg_type],R_LEN(reg_type), read_addr_start, &indx_start);
if(ret==MBR_OK)
{
ret=MBRF_binary_search(MB_R_file.line[reg_type],R_LEN(reg_type), read_addr_start+(reg_len-1u), &indx_end);
if(MBR_OK==ret)
{
if((indx_end-indx_start)!=(reg_len-(uint16_t)1))
{
ret=MBR_ERROR;
}else{
for(TYPE_LINE_LEN i = 0; i<reg_len; i++)
{
return_data[i*2u]=(R_DATA((indx_start+i),reg_type))>>8u;
return_data[(i*2u)+1u]=(R_DATA((indx_start+i),reg_type));
}
ret=MBR_OK;
}
}
}
}else{
ret = MBR_LEN_ERROR;
}
return ret;
}
/**
@brief Читаем данные из регистров в формате bool (они должен быть инициализированы и идти без "окон")
@param read_addr_start modbus адресс первого регистра
@param reg_len кол-во регистров
@param return_data указатель на массив в который запишем результат
@param тип регистра
@retun MBR_OK в нормальном случае, MBR_ERROR если не смогли найти
read_addr_start или read_addr_end или между ними есть "окно"
@note в текущей реализации нету проверки на размер return_data
@note например мы читаем 5 регистра начиная с 0x31:
@note все 3 регистра должны существовать, MBR_LEN_ERROR если хотим прочитать 0 регистров, иначе return MBR_ERROR
@note текущая функция пишет данные в return_data[], в формате, нужном для 1 и 2 кодов функций modbus
@note например если мы читает 2 регистра то фунция запишет 1байт, где 1вый бит это значение 1го регистра а 2ой второго
*/
MBR_status MBRF_multiple_read_reg_bool(uint16_t read_addr_start, uint16_t reg_len, uint8_t return_data[], MBR_reg_type reg_type)
{
uint16_t indx_start; //indx_start_start не назван так, потому что в цикле потом с ним же работаем
uint16_t indx_end;
MBR_status ret=MBR_ERROR;
if(reg_len>0u)
{
ret = MBRF_binary_search(MB_R_file.line[reg_type],R_LEN(reg_type), read_addr_start, &indx_start);
if(ret==MBR_OK)
{
ret=MBRF_binary_search(MB_R_file.line[reg_type],R_LEN(reg_type), read_addr_start+(reg_len-1u), &indx_end);
if(MBR_OK==ret)
{
if((indx_end-indx_start)!=(reg_len-(uint16_t)1))
{
ret=MBR_ERROR;
}else{
for(uint8_t i =0;i<reg_len;i++)
{
return_data[i]=0u;
}
for(TYPE_LINE_LEN i = 0; i<reg_len; i++)
{
return_data[i/8u]|=(R_DATA_BOOL((indx_start+i),reg_type))<<(i%8u); //читай Modbus_Application_Protocol_V1_1b3.pdf и будет понятно
}
ret=MBR_OK;
}
}
}
}else{
ret = MBR_LEN_ERROR;
}
return ret;
}
/**
@brief Заисываем данные в регистр (он должен быть инициализирован)
@param addr modbus адресс регистра в который пишем
@param data данные которые нужно записать
@param тип регистра в который пишем
@retun MBR_OK в нормальном случае, если не нашли регистр то MBR_ERROR
*/
MBR_status MBRF_write_reg(uint16_t addr, uint16_t data, MBR_reg_type reg_type)
{
uint16_t indx;
MBR_status ret = MBRF_binary_search(MB_R_file.line[reg_type],R_LEN(reg_type), addr, &indx);
if(ret==MBR_OK)
{
R_DATA(indx,reg_type)=data;
}
return ret;
}
/**
@brief Простая сортировка массива регистров + проверка на одинаковые адресса
@param reg массив регистров
@param len длинна массива
@retun MBR_OK в нормальном случае, если встретили одинаковые адресса то MBR_ADDR_ERROR
*/
static MBR_status MBRF_selection_sort(MB_register reg[],TYPE_LINE_LEN len)
{
MBR_status ret = MBR_OK;
for(TYPE_LINE_LEN i=0;i<len;i++)
{
TYPE_LINE_LEN min_idx=i;
for(TYPE_LINE_LEN j=i+1u;j<len;j++)
{
if(reg[j].addr<reg[min_idx].addr)
{
min_idx=j;
}else {
if (reg[j].addr==reg[min_idx].addr)
{
ret = MBR_ADDR_ERROR;
}
}
}
if(min_idx != i)
{
MBRF_swap(min_idx,i,reg);
}
}
return ret;
}
/**
@brief бинарный поиск регистра с нужным адрессом в массиве
@param reg массив регистров
@param len длинна массива
@param addr ищем регистр с таким адрессом
@param return_idx сюда положим индекс массива, если нашли
@retun MBR_ERROR если не нашли и MBR_OK если нашли
*/
static MBR_status MBRF_binary_search(const MB_register reg[],TYPE_LINE_LEN len, uint16_t seach_addr, uint16_t* return_idx)
{
MBR_status ret=MBR_ERROR;
if(len>0u)
{
TYPE_LINE_LEN low=0;
TYPE_LINE_LEN high=len-1u;
while (low <= high)
{
TYPE_LINE_LEN mid = low + (high - low)/2u;
if (reg[mid].addr == seach_addr)
{
*return_idx=mid;
ret=MBR_OK;
break;
}
if ( (reg[mid].addr > seach_addr) && (mid!=0u) ) //больше и не дошли до конца
{
high = mid - 1u;
} else {
low = mid + 1u;
}
}
}
return ret;
}
/**
@brief перестановка регистров местами
*/
static void MBRF_swap(TYPE_LINE_LEN len_position_reg_1,TYPE_LINE_LEN len_position_reg_2, MB_register reg[])
{
MB_register bud_reg; //используем этот тип данных для всех типов регистров
bud_reg.data = reg[len_position_reg_1].data; //дата и аддрес 1го в буфер
bud_reg.addr = reg[len_position_reg_1].addr;
reg[len_position_reg_1].data = reg[len_position_reg_2].data; //дата и аддрес 1го = дата и аддрес 2го
reg[len_position_reg_1].addr = reg[len_position_reg_2].addr;
reg[len_position_reg_2].data = bud_reg.data; //дата и аддрес 1го = буфер
reg[len_position_reg_2].addr = bud_reg.addr;
}
#ifdef UTEST_BUILD
/**
@brief Очистка файла регистров. нужен только для тестов
*/
void MBRF_clear_file(void)
{
for(TYPE_LINE_LEN i=0;(MBR_reg_type)i<=MBR_coils;i++)
{
for(TYPE_LINE_LEN j=0;j<R_LEN(i);j++)
{
//printf("\n\n[d]=%04x [a]=%04x\n",R_DATA(j,i),R_ADDR(j,i));
R_DATA(j,i)=0u;
R_ADDR(j,i)=0u;
}
R_LEN(i)=0u;
}
}
TYPE_LINE_LEN MBRF_MAX_QUANTITY(MBR_reg_type reg_type)
{
return MB_R_file.len_max[reg_type];
}
#endif

View File

@ -0,0 +1,42 @@
#ifndef MB_REGS_F_LIB_H_
#define MB_REGS_F_LIB_H_
#include "platform.h"
#define MAX_QUANTITY_HOLDING_REGS 64u
#define MAX_QUANTITY_INPUT_REGS 16u
#define MAX_QUANTITY_INPUT_DISCRETE_REGS 16u
#define MAX_QUANTITY_COLIS_REGS 16u
#define TYPE_LINE_LEN uint8_t //ставить в зависимости от MAX_QUANTITY_HOLDING_REGS
typedef enum
{
MBR_holding = 0u,
MBR_input = 1u,
MBR_input_discrete = 2u,
MBR_coils = 3u,
} MBR_reg_type;
typedef enum
{
MBR_OK = 0x00U,
MBR_ERROR = 0x01U,
MBR_LEN_ERROR = 0x02U,
MBR_CEATE_DISABLE = 0x03U,
MBR_ADDR_ERROR = 0x04U, //в случае если адресс повторяется
} MBR_status;
void MBRF_init_start(void);
MBR_status MBRF_init_end(void);
MBR_status MBRF_create_reg(uint16_t addr, uint16_t* data, MBR_reg_type reg_type);
MBR_status MBRF_read_reg(uint16_t read_addr, uint16_t* return_data, MBR_reg_type reg_type);
MBR_status MBRF_write_reg(uint16_t addr, uint16_t data, MBR_reg_type reg_type);
MBR_status MBRF_multiple_read_reg(uint16_t read_addr_start, uint16_t reg_len, uint8_t* return_data, MBR_reg_type reg_type);
MBR_status MBRF_multiple_read_reg_bool(uint16_t read_addr_start, uint16_t reg_len, uint8_t* return_data, MBR_reg_type reg_type);
#ifdef UTEST_BUILD
void MBRF_clear_file(void);
TYPE_LINE_LEN MBRF_MAX_QUANTITY(MBR_reg_type reg_type);
#endif
#endif

74
src/lib/state_machine.c Normal file
View File

@ -0,0 +1,74 @@
/**
******************************************************************************
* @file state_machine.c
* @brief функции для удобной работы втутри бесонечного цикла
******************************************************************************
*/
#include "platform.h"
#include "sys_tim.h"
#include "state_machine.h"
/**
@brief "исполнить" текущее состояние
@param dev
*/
void execute_current_state(state_machine_dev* dev)
{
if(dev->current_state!=0u) //проверка в 3х метсах, пусть будет
{
dev->current_state(dev);
}
}
/**
@brief "неблокирущая" задержка))
@param dev
*/
void delay_state(state_machine_dev* dev)
{
if(time_get_ms()>=(dev->delay_cnt))
{
dev->current_state=dev->state_after_delay;
}
return;
}
/**
@brief установить состояние
@param state указатель на фунцию
@param dev
*/
void set_state(program_state state, state_machine_dev* dev)
{
if(state!=0u)
{
dev->current_state = state;
}
return;
}
/**
@brief установить состояние после задержи
@param state указатель на фунцию
@delay_ms задержка в ms
@param dev
*/
void set_state_after_delay(program_state state, uint32_t delay_ms, state_machine_dev* dev)
{
if(state!=0u)
{
dev->state_after_delay = state;
dev->delay_cnt = time_get_ms()+delay_ms;
dev->current_state = delay_state;
}
return;
}
/**
@brief заглушка
*/
void plug_state(state_machine_dev* dev)
{
return;
}

18
src/lib/state_machine.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef STATE_MACHINE_H_
#define STATE_MACHINE_H_
typedef struct{
void (*current_state)(uint32_t*); //указатель на program_state
void (*state_after_delay)(uint32_t*); //указатель на program_state
uint32_t delay_cnt;
}state_machine_dev;
typedef void (*program_state)(state_machine_dev*);
void execute_current_state(state_machine_dev* dev);
void delay_state(state_machine_dev*);
void plug_state(state_machine_dev* dev);
void set_state(program_state state, state_machine_dev*);
void set_state_after_delay(program_state state, uint32_t delay_ms, state_machine_dev*);
#endif

41
src/lib/system_handlers.c Normal file
View File

@ -0,0 +1,41 @@
#include "system_handlers.h"
/**
* @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)
{
while (1)
{
;
}
}
/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
void SVC_Handler(void)
{
}
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
void PendSV_Handler(void)
{
}

27
src/lib/system_handlers.h Normal file
View File

@ -0,0 +1,27 @@
/**
* @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);
/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
void SVC_Handler(void);
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
void PendSV_Handler(void);

131
src/lib/temp.c Normal file
View File

@ -0,0 +1,131 @@
/**
******************************************************************************
* @file i2c.c
* @brief измерение температуры
* @note написано на скорость, нужно processing_the_measurement_state доисать
* @note и добавит поддержу других сенсоров и режимы работы с подогревом
******************************************************************************
*/
#include "temp.h"
#include "i2c.h"
#include "crc.h"
#include "modbus_regs_file.h"
#include "sys_tim.h"
#include "state_machine.h"
#include "modbus_config.h"
#define SHT4X_ADR 0x44
#define DELAY_MEASUREMENT 976u // примерно 1000 с поправкой на DELAY_AFTER_PROCESSING и задержки в main
#define DELAY_AFTER_PROCESSING 10u
//Command
#define C_MEASURE_HIGH 0xFD
#define C_MEASURE_MEDIUM 0xF6
#define C_MEASURE_LOWEST 0xE0
#define C_SERIAL_NUMBER 0x89
#define C_SOFT_RESET 0x94
#define HEATER_200MW_1S 0x39
#define HEATER_200MW_01S 0x32
#define HEATER_110MW_1S 0x2F
#define HEATER_110MW_01S 0x24
#define HEATER_20MW_1S 0x1E
#define HEATER_20MW_01S 0x15
static void processing_the_measurement_state(state_machine_dev* dev);
static void read_the_measurement_state(state_machine_dev* dev);
static void init_the_measurement_state(state_machine_dev* dev);
static void ic_reset(void);
static uint16_t temperature = MBDDATA_TEMPERATURE;
static uint16_t temperature_compensation = MBDDATA_TEMPERATURE_COMPENSATION;
static uint16_t humidity = MBDDATA_HUMIDITY;
static uint8_t i2c_buf[8] = {0};
static state_machine_dev st_dev = {plug_state, plug_state, 0u};
/**
@brief init
*/
void temp_sensor_init(void)
{
ic_reset();
set_state_after_delay(init_the_measurement_state, DELAY_AFTER_PROCESSING, &st_dev);
}
/**
@brief работаем
*/
void temperature_sensor_periodic_work(void)
{
execute_current_state(&st_dev);
return;
}
/**
@brief обработка данных
@note тестовый вариант
@note нужно добавить проверку CRC и все вычисления обдумать
*/
static void processing_the_measurement_state(state_machine_dev* dev)
{
//мы не проверяем CRC, нужно исправить
uint16_t te = (i2c_buf[0]<<8)+i2c_buf[1];
float f_data = ((-45 + (175 * (te / 65536.0)))/0.1); //переисать в норманый вид
uint16_t data = (uint16_t)(f_data-((float)(temperature_compensation)*0.1));
temperature = data;
int te1 = (i2c_buf[3]<<8)+i2c_buf[4];
int data1 = (int)((-6 + 125 * te1/65535.0)/0.1); //переисать в норманый вид
humidity = data1;
set_state_after_delay(init_the_measurement_state, DELAY_MEASUREMENT, &st_dev);
return;
}
/**
@brief читаем измерение
*/
static void read_the_measurement_state(state_machine_dev* dev)
{
if(I2C_NOT_BUSY==i2c_read(SHT4X_ADR,&i2c_buf,6u))
{
set_state_after_delay(processing_the_measurement_state, 10u, &st_dev);
}
return;
}
/**
@brief посылаем запрос на измерение
*/
static void init_the_measurement_state(state_machine_dev* dev)
{
if(I2C_NOT_BUSY==i2c_write(SHT4X_ADR, i2c_buf, 1))
{
set_state_after_delay(read_the_measurement_state, 10u, &st_dev);
}
return;
}
/**
@brief перезагружаем микросхему
*/
static void ic_reset(void)
{
i2c_write(SHT4X_ADR, i2c_buf, 1);
return;
}
/**
@brief передаём указатели в модбас регистры
*/
uint8_t MBRF_temperature_sensor_init(void)
{
uint8_t MB_init_eror=0u;
MB_init_eror+=MBRF_create_reg(MBADDR_TEMPERATURE, &temperature, MBTYPE_TEMPERATURE); //0x0
MB_init_eror+=MBRF_create_reg(MBADDR_TEMPERATURE_COMPENSATION, &temperature_compensation, MBTYPE_TEMPERATURE_COMPENSATION); //0x00F5
MB_init_eror+=MBRF_create_reg(MBADDR_HUMIDITY, &humidity, MBTYPE_HUMIDITY); //0x0
return MB_init_eror;
}

11
src/lib/temp.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef SHT4X_LIB_H_
#define SHT4X_LIB_H_
#include "platform.h"
void temp_sensor_init(void);
void temperature_sensor_idle(void);
uint8_t MBRF_temperature_sensor_init(void);
#endif

432
src/lib/xprintf.c Normal file
View File

@ -0,0 +1,432 @@
/*------------------------------------------------------------------------/
/ Universal String Handler for Console Input and Output
/-------------------------------------------------------------------------/
/
/ Copyright (C) 2012, ChaN, all right reserved.
/
/ xprintf module is an open source software. Redistribution and use of
/ xprintf module in source and binary forms, with or without modification,
/ are permitted provided that the following condition is met:
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/-------------------------------------------------------------------------*/
#include "xprintf.h"
#if _USE_XFUNC_OUT
#include <stdarg.h>
void (*xfunc_out)(unsigned char); /* Pointer to the output stream */
static char *outptr;
/*----------------------------------------------*/
/* Put a character */
/*----------------------------------------------*/
void xputc (char c)
{
if (_CR_CRLF && c == '\n') xputc('\r'); /* CR -> CRLF */
if (outptr) { /* Destination is memory */
*outptr++ = (unsigned char)c;
return;
}
if (xfunc_out) { /* Destination is device */
xfunc_out((unsigned char)c);
}
}
/*----------------------------------------------*/
/* Put a null-terminated string */
/*----------------------------------------------*/
void xputs ( /* Put a string to the default device */
const char* str /* Pointer to the string */
)
{
while (*str) {
xputc(*str++);
}
}
void xfputs ( /* Put a string to the specified device */
void(*func)(unsigned char), /* Pointer to the output function */
const char* str /* Pointer to the string */
)
{
void (*pf)(unsigned char);
pf = xfunc_out; /* Save current output device */
xfunc_out = func; /* Switch output to specified device */
while (*str) { /* Put the string */
xputc(*str++);
}
xfunc_out = pf; /* Restore output device */
}
/*----------------------------------------------*/
/* Formatted string output */
/*----------------------------------------------*/
/* xprintf("%d", 1234); "1234"
xprintf("%6d,%3d%%", -200, 5); " -200, 5%"
xprintf("%-6u", 100); "100 "
xprintf("%ld", 12345678); "12345678"
xprintf("%llu", 0x100000000); "4294967296" <_USE_LONGLONG>
xprintf("%04x", 0xA3); "00a3"
xprintf("%08lX", 0x123ABC); "00123ABC"
xprintf("%016b", 0x550F); "0101010100001111"
xprintf("%s", "String"); "String"
xprintf("%-5s", "abc"); "abc "
xprintf("%5s", "abc"); " abc"
xprintf("%c", 'a'); "a"
xprintf("%f", 10.0); <xprintf lacks floating point support. Use regular printf.>
*/
static
void xvprintf (
const char* fmt, /* Pointer to the format string */
va_list arp /* Pointer to arguments */
)
{
unsigned int r, i, j, w, f;
char s[24], c, d, *p;
#if _USE_LONGLONG
_LONGLONG_t v;
unsigned _LONGLONG_t vs;
#else
long v;
unsigned long vs;
#endif
for (;;) {
c = *fmt++; /* Get a format character */
if (!c) break; /* End of format? */
if (c != '%') { /* Pass it through if not a % sequense */
xputc(c); continue;
}
f = 0; /* Clear flags */
c = *fmt++; /* Get first char of the sequense */
if (c == '0') { /* Flag: left '0' padded */
f = 1; c = *fmt++;
} else {
if (c == '-') { /* Flag: left justified */
f = 2; c = *fmt++;
}
}
for (w = 0; c >= '0' && c <= '9'; c = *fmt++) { /* Minimum width */
w = w * 10 + c - '0';
}
if (c == 'l' || c == 'L') { /* Prefix: Size is long */
f |= 4; c = *fmt++;
#if _USE_LONGLONG
if (c == 'l' || c == 'L') { /* Prefix: Size is long long */
f |= 8; c = *fmt++;
}
#endif
}
if (!c) break; /* End of format? */
d = c;
if (d >= 'a') d -= 0x20;
switch (d) { /* Type is... */
case 'S' : /* String */
p = va_arg(arp, char*);
for (j = 0; p[j]; j++) ;
while (!(f & 2) && j++ < w) xputc(' ');
xputs(p);
while (j++ < w) xputc(' ');
continue;
case 'C' : /* Character */
xputc((char)va_arg(arp, int)); continue;
case 'B' : /* Binary */
r = 2; break;
case 'O' : /* Octal */
r = 8; break;
case 'D' : /* Signed decimal */
case 'U' : /* Unsigned decimal */
r = 10; break;
case 'X' : /* Hexdecimal */
r = 16; break;
default: /* Unknown type (passthrough) */
xputc(c); continue;
}
/* Get an argument and put it in numeral */
#if _USE_LONGLONG
if (f & 8) { /* long long argument? */
v = va_arg(arp, _LONGLONG_t);
} else {
if (f & 4) { /* long argument? */
v = (d == 'D') ? (long)va_arg(arp, long) : (long)va_arg(arp, unsigned long);
} else { /* int/short/char argument */
v = (d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int);
}
}
#else
if (f & 4) { /* long argument? */
v = va_arg(arp, long);
} else { /* int/short/char argument */
v = (d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int);
}
#endif
if (d == 'D' && v < 0) { /* Negative value? */
v = 0 - v; f |= 16;
}
i = 0; vs = v;
do {
d = (char)(vs % r); vs /= r;
if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
s[i++] = d + '0';
} while (vs != 0 && i < sizeof s);
if (f & 16) s[i++] = '-';
j = i; d = (f & 1) ? '0' : ' ';
while (!(f & 2) && j++ < w) xputc(d);
do xputc(s[--i]); while (i != 0);
while (j++ < w) xputc(' ');
}
}
void xprintf ( /* Put a formatted string to the default device */
const char* fmt, /* Pointer to the format string */
... /* Optional arguments */
)
{
va_list arp;
va_start(arp, fmt);
xvprintf(fmt, arp);
va_end(arp);
}
void xsprintf ( /* Put a formatted string to the memory */
char* buff, /* Pointer to the output buffer */
const char* fmt, /* Pointer to the format string */
... /* Optional arguments */
)
{
va_list arp;
outptr = buff; /* Switch destination for memory */
va_start(arp, fmt);
xvprintf(fmt, arp);
va_end(arp);
*outptr = 0; /* Terminate output string with a \0 */
outptr = 0; /* Switch destination for device */
}
void xfprintf ( /* Put a formatted string to the specified device */
void(*func)(unsigned char), /* Pointer to the output function */
const char* fmt, /* Pointer to the format string */
... /* Optional arguments */
)
{
va_list arp;
void (*pf)(unsigned char);
pf = xfunc_out; /* Save current output device */
xfunc_out = func; /* Switch output to specified device */
va_start(arp, fmt);
xvprintf(fmt, arp);
va_end(arp);
xfunc_out = pf; /* Restore output device */
}
/*----------------------------------------------*/
/* Dump a line of binary dump */
/*----------------------------------------------*/
void put_dump (
const void* buff, /* Pointer to the array to be dumped */
unsigned long addr, /* Heading address value */
int len, /* Number of items to be dumped */
int width /* Size of the items (DF_CHAR, DF_SHORT, DF_LONG) */
)
{
int i;
const unsigned char *bp;
const unsigned short *sp;
const unsigned long *lp;
xprintf("%08lX ", addr); /* address */
switch (width) {
case DW_CHAR:
bp = buff;
for (i = 0; i < len; i++) /* Hexdecimal dump */
xprintf(" %02X", bp[i]);
xputc(' ');
for (i = 0; i < len; i++) /* ASCII dump */
xputc((unsigned char)((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.'));
break;
case DW_SHORT:
sp = buff;
do /* Hexdecimal dump */
xprintf(" %04X", *sp++);
while (--len);
break;
case DW_LONG:
lp = buff;
do /* Hexdecimal dump */
xprintf(" %08LX", *lp++);
while (--len);
break;
}
xputc('\n');
}
#endif /* _USE_XFUNC_OUT */
#if _USE_XFUNC_IN
unsigned char (*xfunc_in)(void); /* Pointer to the input stream */
/*----------------------------------------------*/
/* Get a line from the input */
/*----------------------------------------------*/
int xgets ( /* 0:End of stream, 1:A line arrived */
char* buff, /* Pointer to the buffer */
int len /* Buffer length */
)
{
int c, i;
if (!xfunc_in) return 0; /* No input function specified */
i = 0;
for (;;) {
c = xfunc_in(); /* Get a char from the incoming stream */
if (!c) return 0; /* End of stream? */
if (c == '\r') break; /* End of line? */
if (c == '\b' && i) { /* Back space? */
i--;
if (_LINE_ECHO) xputc((unsigned char)c);
continue;
}
if (c >= ' ' && i < len - 1) { /* Visible chars */
buff[i++] = c;
if (_LINE_ECHO) xputc((unsigned char)c);
}
}
buff[i] = 0; /* Terminate with a \0 */
if (_LINE_ECHO) xputc('\n');
return 1;
}
int xfgets ( /* 0:End of stream, 1:A line arrived */
unsigned char (*func)(void), /* Pointer to the input stream function */
char* buff, /* Pointer to the buffer */
int len /* Buffer length */
)
{
unsigned char (*pf)(void);
int n;
pf = xfunc_in; /* Save current input device */
xfunc_in = func; /* Switch input to specified device */
n = xgets(buff, len); /* Get a line */
xfunc_in = pf; /* Restore input device */
return n;
}
/*----------------------------------------------*/
/* Get a value of the string */
/*----------------------------------------------*/
/* "123 -5 0x3ff 0b1111 0377 w "
^ 1st call returns 123 and next ptr
^ 2nd call returns -5 and next ptr
^ 3rd call returns 1023 and next ptr
^ 4th call returns 15 and next ptr
^ 5th call returns 255 and next ptr
^ 6th call fails and returns 0
*/
int xatoi ( /* 0:Failed, 1:Successful */
char **str, /* Pointer to pointer to the string */
long *res /* Pointer to the valiable to store the value */
)
{
unsigned long val;
unsigned char c, r, s = 0;
*res = 0;
while ((c = **str) == ' ') (*str)++; /* Skip leading spaces */
if (c == '-') { /* negative? */
s = 1;
c = *(++(*str));
}
if (c == '0') {
c = *(++(*str));
switch (c) {
case 'x': /* hexdecimal */
r = 16; c = *(++(*str));
break;
case 'b': /* binary */
r = 2; c = *(++(*str));
break;
default:
if (c <= ' ') return 1; /* single zero */
if (c < '0' || c > '9') return 0; /* invalid char */
r = 8; /* octal */
}
} else {
if (c < '0' || c > '9') return 0; /* EOL or invalid char */
r = 10; /* decimal */
}
val = 0;
while (c > ' ') {
if (c >= 'a') c -= 0x20;
c -= '0';
if (c >= 17) {
c -= 7;
if (c <= 9) return 0; /* invalid char */
}
if (c >= r) return 0; /* invalid char for current radix */
val = val * r + c;
c = *(++(*str));
}
if (s) val = 0 - val; /* apply sign if needed */
*res = val;
return 1;
}
#endif /* _USE_XFUNC_IN */

40
src/lib/xprintf.h Normal file
View File

@ -0,0 +1,40 @@
/*------------------------------------------------------------------------*/
/* Universal string handler for user console interface (C)ChaN, 2012 */
/*------------------------------------------------------------------------*/
#ifndef _STRFUNC
#define _STRFUNC
#define _USE_XFUNC_OUT 1 /* 1: Use output functions */
#define _CR_CRLF 1 /* 1: Convert \n ==> \r\n in the output char */
#define _USE_LONGLONG 0 /* 1: Enable long long integer in type "ll". */
#define _LONGLONG_t long long /* Platform dependent long long integer type */
#define _USE_XFUNC_IN 1 /* 1: Use input function */
#define _LINE_ECHO 1 /* 1: Echo back input chars in xgets function */
#if _USE_XFUNC_OUT
#define xdev_out(func) xfunc_out = (void(*)(unsigned char))(func)
extern void (*xfunc_out)(unsigned char);
void xputc (char c);
void xputs (const char* str);
void xfputs (void (*func)(unsigned char), const char* str);
void xprintf (const char* fmt, ...);
void xsprintf (char* buff, const char* fmt, ...);
void xfprintf (void (*func)(unsigned char), const char* fmt, ...);
void put_dump (const void* buff, unsigned long addr, int len, int width);
#define DW_CHAR sizeof(char)
#define DW_SHORT sizeof(short)
#define DW_LONG sizeof(long)
#endif
#if _USE_XFUNC_IN
#define xdev_in(func) xfunc_in = (unsigned char(*)(void))(func)
extern unsigned char (*xfunc_in)(void);
int xgets (char* buff, int len);
int xfgets (unsigned char (*func)(void), char* buff, int len);
int xatoi (char** str, long* res);
#endif
#endif

132
src/main.c Normal file
View File

@ -0,0 +1,132 @@
/**
##############################################################################
@file main.c
@author Борисков Кирилл
@brief Архитектура прошивки крайне проста,
@brief работаем с i2c и uart по DMA, в цикле обрабатываем данные
##############################################################################
*/
#include "dout.h"
#include "uart_debug.h"
#include "xprintf.h"
#include "led.h"
#include "rcc.h"
#include "sys_tim.h"
#include "uart_modbus.h"
#include "modbus_regs_file.h"
#include "modbus_config.h"
#include "i2c.h"
#include "temp.h"
static void modbus_struc_init(void);
void check_reset_flag(void);
static uint16_t reset_flag=MBDDATA_RESET;
int main(void)
{
sysclk_LSI_setup(); //для работы собаки
watchdog_init(); //на 0.5 сек
sysclk_64mhz_from_hsi16_setup();
SysTick_Init();
#ifdef DEBUG
uart_debug_init();
xprintf("\n\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n START\n//////////////\n");
#endif
i2c_init();
temp_sensor_init();
dout_init();
led_config();
modbus_struc_init();
eeprom_file_init();
uart_modbus_init();
watchdog_refresh();
#ifdef DEBUG
xprintf("//////////////\n INIT SUCCESSFULLY\n uptime: %dms (%dsec)\n//////////////\n",time_get_ms(),time_get_sec());
#endif
while(1)
{
modbus_periodic_work();
check_reset_flag();
temperature_sensor_periodic_work();
led_periodic_work();
dout_periodic_work();
eeprom_periodic_work();
delay(1);
watchdog_refresh();
}
return 0;
}
/**
@brief инициализируем структуру modbus регистров перезагрузка МК в случае проблеммы
*/
static void modbus_struc_init(void)
{
uint8_t MB_init_eror = 0u;
MBRF_init_start();
uint8_t buf_model[] = {MBDDATA_MODEL};
//Модель устройства (строка asci "TempControl") адресса 200-205
for(uint8_t i =0; i<sizeof(buf_model);++i)
{
MB_init_eror+=MBRF_create_reg(MBADDR_MODEL+i, &buf_model[i], MBTYPE_MODEL);
}
MB_init_eror+=MBRF_create_reg(MBADDR_RESET, &reset_flag, MBTYPE_RESET);
MB_init_eror+=MBRF_led_init();
MB_init_eror+=MBRF_dout_init();
MB_init_eror+=MBRF_modbus_init();
MB_init_eror+=MBRF_temperature_sensor_init();
MB_init_eror+=MBRF_time_init();
#ifdef DEBUG //заглушка для дебага
static uint16_t humidity_plug = 0x7FFF;
MB_init_eror+=MBRF_create_reg(0x2, &humidity_plug, MBR_input); //0x2 заглушка reg_illumination
#endif
if((MB_init_eror!=MBR_OK)||(MBR_OK!=MBRF_init_end()))
{
#ifdef DEBUG
xprintf("MBRF_init_end eror\n");
#endif
RESET_MK(); //это очень спорно нужно обдумать //по идее это тольо на столе при дебаге может случиться
}else{
#ifdef DEBUG
xprintf("modbus file init\n");
#endif
}
xprintf("\n");
return;
}
/**
@brief проверяем reset_flag и перезагружаем МК
*/
void check_reset_flag(void)
{
if(reset_flag!=0x0)
{
//watchdog_refresh(); //по тестам мы успеваем ответить даже на 1200бод
while(MBRF_check_transfer_not_completed()) //ждём пока отет о успешной записи в reset_flag доедёт
{
NOP();
}
RESET_MK(); //перезагружаем МК
}
}

60
src/plib/crc.c Normal file
View File

@ -0,0 +1,60 @@
/**
******************************************************************************
* @file crc.c
* @brief CRC generation for modbus
******************************************************************************
*/
#include "platform.h"
#include "crc.h"
#define MB_POLY 0x8005 //reversed A001
#define SHT4X_POLY 0x13 //reversed 0x31
static void CRC_Init(void);
/**
@brief init
*/
static void CRC_Init(void)
{
RCC->AHBENR |= RCC_AHBENR_CRCEN;
CRC->CR &= ~(CRC_CR_POLYSIZE | CRC_CR_REV_IN);
CRC->CR |= (CRC_CR_POLYSIZE_0 | CRC_CR_REV_OUT | CRC_CR_REV_IN_0);
CRC->POL = MB_POLY;
CRC->CR |= CRC_CR_RESET;
}
/**
@brief считавем CRC
@param buffer указатель на массив с данными (предполагается modbus frame)
@param len длина массива buffer[len-1 должен указыть на последний байт CRC]
@param crc_h_byte указать, по которому положим h байт посчитанной CRC
@param crc_l_byte указать, по которому положим l байт посчитанной CRC
@note l byte это последний по счёту байт
*/
void CRC_get(uint8_t * buffer, uint32_t len, uint8_t* crc_h_byte, uint8_t* crc_l_byte)
{
CRC_Init();
for(uint32_t i = 0; i < (len-CRC_LEN); i++)
{
*((__IO uint8_t *)&CRC->DR) = buffer[i];
}
*crc_h_byte=(uint8_t)(CRC->DR);
*crc_l_byte=(uint8_t)(CRC->DR>>8);
return;
}
/**
@brief вычитает CRC из массива и сравнивает их c СRC внутри массива (последнии 2 байта)
@param buffer указатель на массив с данными (предполагается modbus frame)
@param len длина массива buffer[len-1 должен указыть на последний байт CRC]
@return 1 если CRC совпадают
*/
bool CRC_check(uint8_t * buffer, uint32_t len)
{
uint8_t crc_h_buf,crc_l_buf;
CRC_get(buffer, len,&crc_h_buf,&crc_l_buf);
return (crc_h_buf==buffer[len-CRC_LEN])&&(crc_l_buf==buffer[len-1u]);
}

13
src/plib/crc.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef CRC_H_
#define CRC_H_
#include "platform.h"
#define CRC_LEN 2u
void CRC_get(uint8_t * buffer, uint32_t len, uint8_t* crc_h_byte, uint8_t* crc_l_byte);
bool CRC_check(uint8_t * buffer, uint32_t len);
uint8_t MBRF_dout_init(void);
#endif

72
src/plib/dout.c Normal file
View File

@ -0,0 +1,72 @@
#include "platform.h"
#include "dout.h"
#include "modbus_regs_file.h"
#include "modbus_config.h"
static uint16_t dout_state_flag = MBDDATA_STATE_DOUT;
/**
@brief инициализируем пин
*/
void dout_init(void)
{
RCC -> IOPENR |= RCC_IOPENR_GPIOAEN ;
GPIOA -> MODER &= ~GPIO_MODER_MODE1_1;
GPIOA -> MODER |= GPIO_MODER_MODE1_0; //General purpose output mode
GPIOA -> OTYPER |=GPIO_OTYPER_OT1; //Output push-pul
GPIOA -> OSPEEDR &= ~GPIO_OSPEEDR_OSPEED1_1;
GPIOA -> OSPEEDR &= ~GPIO_OSPEEDR_OSPEED1_0; //Very low speed
GPIOA -> PUPDR &= ~ GPIO_PUPDR_PUPD1_1; //No pull-up, pull-down
GPIOA -> PUPDR |=GPIO_PUPDR_PUPD1_0;
dout_set(dout_state_flag);
return;
}
/**
@brief переключить состояние
@note меняет начение модбас регистра
*/
void dout_set(bool state)
{
if(state!=DOUT_CLOSED){
GPIOA -> ODR |=GPIO_ODR_OD1;
dout_state_flag = DOUT_OPEN;
}else{
GPIOA -> ODR &= ~GPIO_ODR_OD1;
dout_state_flag = DOUT_CLOSED;
}
return;
}
/**
@brief получить текущее состояние
*/
bool dout_get(void)
{
return !(dout_state_flag!=DOUT_CLOSED);
}
/**
@brief работаем
*/
void dout_periodic_work(void)
{
dout_set(TO_BOOL(dout_state_flag));
}
/**
@brief передаём указатели в модбас
*/
uint8_t MBRF_dout_init(void)
{
return MBRF_create_reg(MBADDR_STATE_DOUT, &dout_state_flag, MBTYPE_STATE_DOUT); //0x0012
}

15
src/plib/dout.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef DOUT_PLIB_H
#define DOUT_PLIB_H
#include "platform.h"
#define DOUT_OPEN 1u
#define DOUT_CLOSED 0u
void dout_init(void);
void dout_set(bool state);
bool dout_get(void);
void dout_periodic_work(void);
uint8_t MBRF_dout_init(void);
#endif

351
src/plib/i2c.c Normal file
View File

@ -0,0 +1,351 @@
/**
******************************************************************************
* @file i2c.c
* @brief i2c functions
******************************************************************************
*/
#include "platform.h"
#include "i2c.h"
#include "bool.h"
#include "xprintf.h"//delete
#include "sys_tim.h"//delete
#include "led.h" //delete
#define CHECK_NOT_BUSY() ((I2C2->ISR & I2C_ISR_BUSY)!=I2C_ISR_BUSY)
static void i2c_DMA_init_read(const uint8_t* data, uint8_t length);
static void i2c_DMA_init_write(const uint8_t* data, uint8_t length);
static void i2c_DMA_init(void);
static i2c_status last_transmit_nack =I2C_ERROR;
/**
@brief настройка i2c
@note текущая реализация расчитана на 64мгц тактирование
*/
#define DMAREQ_ID_I2C2_RX 12u
#define DMAREQ_ID_I2C2_TX 13u
i2c_status i2c_init(void)
{
RCC->APBENR1 |= RCC_APBENR1_I2C2EN; // Включаем тактирование I2C2
RCC->IOPENR |= RCC_IOPENR_GPIOAEN; // Включаем тактирование GPIO порта A
// Настройка PA11 и PA12
GPIOA->MODER &= ~(GPIO_MODER_MODE11_0 | GPIO_MODER_MODE12_0); // Сбросить биты
GPIOA->MODER |= (GPIO_MODER_MODE11_1 | GPIO_MODER_MODE12_1); // Установить режим альтернативной функции
GPIOA->OTYPER |= GPIO_OTYPER_OT12 | GPIO_OTYPER_OT11;
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD11_1 | GPIO_PUPDR_PUPD12_1);
GPIOA->PUPDR |= (GPIO_PUPDR_PUPD11_0 | GPIO_PUPDR_PUPD12_0);
GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL12_1 | GPIO_AFRH_AFSEL12_2 | GPIO_AFRH_AFSEL11_1 | GPIO_AFRH_AFSEL11_2); // Установить альтернативную функцию AF1
GPIOA->OSPEEDR |=(GPIO_OSPEEDR_OSPEED12 | GPIO_OSPEEDR_OSPEED11); // Настройка скорости GPIO
I2C2->CR1 &= ~I2C_CR1_PE; // Отключаем I2C на время настройки
I2C2->CR1 &= ~I2C_CR1_ANFOFF; // Включаем аналоговый фильтр
I2C2->CR1 &= ~I2C_CR1_DNF; // Отключаем цифровой фильтр
I2C2->CR1 |= I2C_CR1_TXDMAEN; //DMA transmission requests enable
I2C2->CR1 |= I2C_CR1_RXDMAEN;
I2C2->CR1 |= I2C_CR1_TCIE; //Transfer complete interrupt enable
I2C2->CR1 |= I2C_CR1_NACKIE; //NACK received interrupt enable
I2C2->CR1 &= ~I2C_CR1_NOSTRETCH; // Отключение растяжения тактового сигнала
// // Настройка таймингов, 100 кГц при 64 МГц тактировании
// //значения из 25.4.11 I2C_TIMINGR register configuration examples меняем только PRESC
// I2C2->TIMINGR |= (0x13 << I2C_TIMINGR_SCLL_Pos) |
// (0xf << I2C_TIMINGR_SCLH_Pos) |
// (0x2 << I2C_TIMINGR_SDADEL_Pos) |
// (0x4 << I2C_TIMINGR_SCLDEL_Pos) |
// (0x1D << I2C_TIMINGR_PRESC_Pos);
// Настройка таймингов, 35 кГц при 64 МГц тактировании
I2C2->TIMINGR |= (0x55 << I2C_TIMINGR_SCLL_Pos) |
(0x51 << I2C_TIMINGR_SCLH_Pos) |
(0x2 << I2C_TIMINGR_SDADEL_Pos) |
(0x4 << I2C_TIMINGR_SCLDEL_Pos) |
(0x9 << I2C_TIMINGR_PRESC_Pos);
I2C2->CR1 |= I2C_CR1_PE; // Включаем I2C
NVIC_EnableIRQ(I2C2_IRQn);
NVIC_SetPriority(I2C2_IRQn, I2C_IRQ_PIOITY_LEVEL);
i2c_DMA_init();
return I2C_OK;
}
/**
@brief прерывания i2c
*/
extern void I2C2_IRQHandler(void)
{
if(I2C2->ISR & I2C_ISR_TC )
{
I2C2->CR2 |= I2C_CR2_STOP;
last_transmit_nack=I2C_ACK;
}
if(I2C2->ISR & I2C_ISR_NACKF )
{
I2C2->CR2 |= I2C_CR2_STOP;
I2C2->ICR |= I2C_ICR_NACKCF;
DMA1_Channel1->CCR &=~ DMA_CCR_EN;
last_transmit_nack=I2C_NACK;
}
return;
}
/**
@brief прерываниe dma
*/
extern void DMA1_Channel1_IRQHandler(void)
{
if(DMA1->ISR & DMA_ISR_TCIF1 )
{
DMA1->IFCR |= DMA_IFCR_CTCIF1;
DMA1_Channel1->CCR &=~ DMA_CCR_EN;
}
return;
}
/**
@brief запускаем dma на чтение из массива
@param data указатель на массив откуда пишем в i2c
@param length длина data
*/
static void i2c_DMA_init_read(const uint8_t* data, uint8_t length)
{
DMA1_Channel1->CPAR = (&(I2C2->RXDR)); //указатель на передатчик
DMA1_Channel1->CMAR = data; //адресс на начало буфера
DMA1_Channel1->CNDTR = length; //счётчик
DMAMUX1_Channel0->CCR = (DMAREQ_ID_I2C2_RX&DMAMUX_CxCR_DMAREQ_ID);
DMA1_Channel1->CCR &=~ DMA_CCR_DIR; //Data transfer direction
DMA1_Channel1->CCR |= DMA_CCR_EN;
return;
}
/**
@brief запускаем dma на запись в массив
@param data указатель на массив куда пишем из i2c
@param length длина data
*/
static void i2c_DMA_init_write(const uint8_t* data, uint8_t length)
{
DMA1_Channel1->CPAR = (&(I2C2->TXDR)); //указатель на передатчик
DMA1_Channel1->CMAR = data; //адресс на начало буфера
DMA1_Channel1->CNDTR = length; /*Set number of bytes to transmit*/
DMAMUX1_Channel0->CCR = (DMAREQ_ID_I2C2_TX&DMAMUX_CxCR_DMAREQ_ID);
DMA1_Channel1->CCR |= DMA_CCR_DIR; //Data transfer direction
DMA1_Channel1->CCR |= DMA_CCR_EN;
return;
}
/**
@brief начальная настройка dma
*/
static void i2c_DMA_init(void)
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //включаем тактирование
DMA1_Channel1->CCR |= (DMA_CCR_PL //priority level hery high
| DMA_CCR_MINC //memory increment mode enable
| DMA_CCR_TCIE //transfer complete interrupt enable
//| DMA_CCR_TEIE //Transfer error interrupt enable
);
NVIC_SetPriority(DMA1_Channel1_IRQn, I2C_IRQ_PIOITY_LEVEL);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
DMA1_Channel1->CCR &=~ DMA_CCR_EN;
}
/**
@brief чтение регистров по DMA
@param addr адресс i2c slave
@param data указатель на массив куда пишем из i2c
@param length длина data
@return I2C_ERROR - непонятно что случилось
@return I2C_NOT_BUSY - шина не занята, чтение по дма запущенно
@return I2C_BUSY - шина не занята, ждите
*/
i2c_status i2c_read(uint8_t addr, uint8_t* data, uint8_t length)
{
i2c_status ret = I2C_ERROR;
if (length < 1u)
{
return I2C_LENGTH_ERROR; //не заданна длина data[]
}
if(CHECK_NOT_BUSY())
{
ret = I2C_NOT_BUSY;
I2C2->CR2 = ((addr << 1U) & I2C_CR2_SADD) | I2C_CR2_RD_WRN | (length << I2C_CR2_NBYTES_Pos);
i2c_DMA_init_read(data, length);
I2C2->CR2 |= I2C_CR2_START;
}else{
ret = I2C_BUSY;
}
return ret;
}
/**
@brief запись регистров по DMA
@param addr адресс i2c slave
@param data указатель на массив куда пишем из i2c
@param length длина data
@return I2C_ERROR - непонятно что случилось
@return I2C_NOT_BUSY - шина не занята, запись по дма запущенна
@return I2C_BUSY - шина не занята, ждите
*/
i2c_status i2c_write(uint8_t addr, uint8_t* data, uint8_t length)
{
i2c_status ret = I2C_ERROR;
if (length < 1u)
{
return I2C_LENGTH_ERROR; //не заданна длина data[]
}
if(CHECK_NOT_BUSY())
{
ret = I2C_NOT_BUSY;
I2C2->CR2 &=~ (I2C_CR2_SADD) | (I2C_CR2_NBYTES) | I2C_CR2_RD_WRN;
I2C2->CR2 = ((addr << 1U) & I2C_CR2_SADD) | (length << I2C_CR2_NBYTES_Pos);
i2c_DMA_init_write(data, length);
I2C2->CR2 |= I2C_CR2_START;
}else{
ret = I2C_BUSY;
}
return ret;
}
/**
@brief проверка, занята шина или нет
@return I2C_NOT_BUSY - шина не занята, запись по дма запущенна
@return I2C_BUSY - шина не занята, ждите
*/
i2c_status i2c_check_busy(void)
{
i2c_status ret = I2C_ERROR;
if(CHECK_NOT_BUSY())
{
ret=I2C_NOT_BUSY;
}else{
ret=I2C_BUSY;
}
return ret;
}
/**
@brief что выдало последние действия с i2c
@return I2C_ACK
@return I2C_NACK
*/
i2c_status i2c_check_last_transmit_ACK(void)
{
return last_transmit_nack;
}
/**
@brief блокирущее чтение регистров
@param addr адресс i2c slave
@param data указатель на массив куда пишем из i2c
@param length длина data
@return I2C_ERROR - не смогла я
@return I2C_OK - прочитали успешно
@note т.к. мы используем блокирущие функции только
@note во время инициалиации, принятно решение использовать
@note обёртки на DMA функции
@note
@note функция потенциально может зарять в бесконечном цикле
*/
i2c_status i2c_lock_read(uint8_t addr, uint8_t* data, uint8_t length)
{
i2c_status ret=I2C_ERROR;
while(i2c_check_busy()==I2C_BUSY)
{
NOP();
}
i2c_read( addr, data, length);
while(i2c_check_busy()==I2C_NOT_BUSY) //ждём запуска дма
{
NOP();
}
while(i2c_check_busy()==I2C_BUSY)
{
NOP();
}
if(I2C_ACK==i2c_check_last_transmit_ACK())
{
ret=I2C_OK;
}
return ret;
}
/**
@brief блокирущая запись регистров
@param addr адресс i2c slave
@param data указатель на массив откуда пишем в i2c
@param length длина data
@return I2C_ERROR - не смогла я
@return I2C_OK - прочитали успешно
@note т.к. мы используем блокирущие функции только
@note во время инициалиации, принятно решение использовать
@note обёртки на DMA функции
@note
@note функция потенциально может зарять в бесконечном цикле
*/
i2c_status i2c_lock_write(uint8_t addr, uint8_t* data,uint8_t length)
{
i2c_status ret=I2C_ERROR;
while(i2c_check_busy()==I2C_BUSY)
{
NOP();
}
i2c_write( addr, data, length);
while(i2c_check_busy()==I2C_NOT_BUSY)
{
NOP();
}
while(i2c_check_busy()==I2C_BUSY)
{
NOP();
}
if(I2C_ACK==i2c_check_last_transmit_ACK())
{
ret=I2C_OK;
}
return ret;
}
#ifdef FFF //не используем этот код
i2c_status i2c_ACK(uint8_t addr)
{
bool ret =false; //0-error 1-sess
I2C2 -> CR2 |= I2C_CR2_NBYTES; //The number of bytes to be transmitted/received is programmed there.
I2C2 -> CR2 |= I2C_CR2_RELOAD; // software end mode: TC flag is set when NBYTES data are transferred, stretching SCL low.
I2C2 -> CR2 &= ~I2C_CR2_SADD;
I2C2 -> CR2 |= ((addr<<1U)&I2C_CR2_SADD); //Slave address
//I2C2->ISR &= ~I2C_ISR_NACKF;
I2C2 -> CR2 |= I2C_CR2_START; //Start generation
delay(1);
//xprintf("Adr = 0x%02x ISR = 0x%08x\n",data,I2C2->ISR);
if( !((I2C2->ISR&I2C_ISR_NACKF)==I2C_ISR_NACKF) )
{
ret = true; //0-error 1-sess
}
I2C2->CR2 |= I2C_CR2_STOP;
//xprintf("0x%08x\n",((data<<1U)&I2C_CR2_SADD));
return ret;
}
#endif

28
src/plib/i2c.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef I2C_PLIB_H_
#define I2C_PLIB_H_
#include "platform.h"
#include "bool.h"
typedef enum
{
I2C_BUSY,
I2C_NOT_BUSY,
I2C_LENGTH_ERROR,
I2C_NACK,
I2C_ACK,
I2C_OK,
I2C_ERROR
} i2c_status;
i2c_status i2c_init(void);
i2c_status i2c_read(uint8_t addr, uint8_t* data, uint8_t length);
i2c_status i2c_write(uint8_t addr, uint8_t* data,uint8_t length);
i2c_status i2c_check_last_transmit_ACK(void);
i2c_status i2c_check_busy(void);
i2c_status i2c_lock_read(uint8_t addr, uint8_t* data, uint8_t length);
i2c_status i2c_lock_write(uint8_t addr, uint8_t* data,uint8_t length);
#endif

68
src/plib/led.c Normal file
View File

@ -0,0 +1,68 @@
#include "platform.h"
#include "led.h"
#include "modbus_regs_file.h"
#include "modbus_config.h"
static uint16_t led_state_flag = MBDDATA_STATUS_LED;
/**
@brief инициализируем светодиод
*/
void led_config(void)
{
RCC -> IOPENR |= RCC_IOPENR_GPIOAEN ;
GPIOA -> MODER &= ~GPIO_MODER_MODE7_1;
GPIOA -> MODER |= GPIO_MODER_MODE7_0; //General purpose output mode
GPIOA -> OTYPER |= GPIO_OTYPER_OT1; //Output open-drain
GPIOA -> OSPEEDR &= ~GPIO_OSPEEDR_OSPEED7_1;
GPIOA -> OSPEEDR &= ~GPIO_OSPEEDR_OSPEED7_0; //Very low speed
GPIOA -> PUPDR &= ~ GPIO_PUPDR_PUPD7_1; //Pull-up
GPIOA -> PUPDR |= GPIO_PUPDR_PUPD7_0;
led_set(led_state_flag);
return;
}
/**
@brief переключить светодиод
@note меняет начение модбас регистра
*/
void led_set(bool state)
{
if(state!=LED_OFF){
GPIOA -> ODR &= ~GPIO_ODR_OD7;
led_state_flag = LED_ON;
}else{
GPIOA -> ODR |=GPIO_ODR_OD7;
led_state_flag = LED_OFF;
}
return;
}
/**
@brief получить текущее состояние светодиода
*/
bool led_get(void)
{
return !(led_state_flag!=LED_OFF);
}
/**
@brief синхронизируем значение регистра модас со светом
*/
void led_periodic_work(void)
{
led_set(TO_BOOL(led_state_flag));
}
/**
@brief передаём указатели в модбас
*/
uint8_t MBRF_led_init(void)
{
return MBRF_create_reg(MBADDR_STATUS_LED, &led_state_flag, MBTYPE_STATUS_LED); //0x0012
}

16
src/plib/led.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef LED_PLIB_H_
#define LED_PLIB_H_
#include "platform.h"
#define LED_ON 1u
#define LED_OFF 0u
// Функции для настройки системы
void led_config(void);
void led_set(bool state);
bool led_get(void);
void led_periodic_work(void);
uint8_t MBRF_led_init(void);
#endif

85
src/plib/rcc.c Normal file
View File

@ -0,0 +1,85 @@
/**
******************************************************************************
* @file rcc.c
* @brief Clock setup
******************************************************************************
*/
#include "rcc.h"
#include "platform.h"
static uint32_t sysClockFreq = 0 ; //тут храним текущую частоту
/**
@brief Set SYSCLK 64mhz from PLL <- HSI16
*/
void sysclk_64mhz_from_hsi16_setup(void)
{
// RCC -> CR |= RCC_CR_HSIDIV_0; //поставить на 8мгц делитель HSI16
RCC -> CR &= ~RCC_CR_PLLON; //Disable the PLL
while((RCC -> CR&RCC_CR_PLLRDY)!=0) //Wait until PLLRDY is cleared. The PLL is now fully stopped
{NOP();}
RCC -> PLLCFGR =0U; //reset config PLL
RCC -> PLLCFGR |=RCC_PLLCFGR_PLLR_0; //PLL VCO division factor R for PLLRCLK clock output = 2
RCC -> PLLCFGR |=RCC_PLLCFGR_PLLN_3; // PLL frequency multiplication factor N = 8
RCC -> PLLCFGR |=RCC_PLLCFGR_PLLSRC_1; //PLL input clock source = HSI16
RCC -> CR |=RCC_CR_PLLON; //Enable the PLL
while((RCC -> CR&RCC_CR_PLLRDY)!=0) //Wait PLL start
{NOP();}
FLASH->ACR |= FLASH_ACR_LATENCY_2; //Flash memory access latency = Two wait states
RCC -> PLLCFGR |=RCC_PLLCFGR_PLLREN; //PLLRCLK clock output enable
RCC -> CFGR |= RCC_CFGR_SW_1; //System clock switch = PLLRCLK
sysClockFreq = 64000000; //устанавливаем частоту в 64мгц
return;
}
/**
@brief Enable LSI
*/
void sysclk_LSI_setup(void)
{
RCC -> CSR |= RCC_CSR_LSION; //LSI oscillator enable
while( (RCC -> CSR & RCC_CSR_LSIRDY) == 0x0)
{
NOP();
}
return;
}
/**
@brief Setup microcontroller clock output in PA8
prescaler = 2
bare-metal code because used at debug only
@param[selection] Microcontroller clock output clock selector
*/
void clock_output_pA8_enble(MSO_Sel_TypeDef selection)
{
RCC -> IOPENR |= RCC_IOPENR_GPIOAEN ; //enable rcc A port
GPIOA -> MODER |= GPIO_MODER_MODE8_1; // Alternate function mode (10)
GPIOA -> MODER &= ~GPIO_MODER_MODE8_0;
GPIOA -> OSPEEDR |= GPIO_OSPEEDR_OSPEED8_1;
GPIOA -> OSPEEDR |= GPIO_OSPEEDR_OSPEED8_0; //Very high speed
RCC -> CFGR &= ~RCC_CFGR_MCOPRE_Msk; //Microcontroller clock output prescaler = 2
RCC -> CFGR |=RCC_CFGR_MCOPRE_0;
RCC -> CFGR &= ~RCC_CFGR_MCOSEL_Msk; //Microcontroller clock output selector
RCC -> CFGR |=((selection << RCC_CFGR_MCOSEL_Pos)&RCC_CFGR_MCOSEL_Msk); //сдвигаем и по маске пишем
return;
}
/**
@brief return sysClockFreq
@return sysClockFreq
*/
uint32_t RCC_GetSysClockFreq(void)
{
return sysClockFreq;
}

28
src/plib/rcc.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef RCC_PLIB_H_
#define RCC_PLIB_H_
#include "platform.h"
typedef enum
{
DISABLED = 0x0,
SYSCLK = 0x1,
HSI48 = 0x2,
HSI16 = 0x3,
HSE = 0x4,
PLLRCLK = 0x5,
LSI = 0x6,
LSE = 0x7,
PLLPCLK = 0x8,
PLLQCLK = 0x9,
RTCCLK = 0xa,
WAKEUP = 0xb
} MSO_Sel_TypeDef; //Microcontroller clock output clock selection
void sysclk_64mhz_from_hsi16_setup(void);
void sysclk_LSI_setup(void);
void clock_output_pA8_enble(MSO_Sel_TypeDef selection);
uint32_t RCC_GetSysClockFreq(void);
#endif

72
src/plib/sys_tim.c Normal file
View File

@ -0,0 +1,72 @@
#include "sys_tim.h"
#include "platform.h"
#include "modbus_regs_file.h"
#include "modbus_config.h"
static uint32_t time_ms_cnt = 0;
static uint32_t time_sec_cnt = 0;
/**
@brief тут счётчики инкрементируем
*/
void SysTick_Handler(void)
{
static uint16_t sec_update_cnt=0;
time_ms_cnt++;
sec_update_cnt++;
if(sec_update_cnt==1000u) //если 1000 милисек отсчитали
{
sec_update_cnt=0u;
time_sec_cnt++;
}
return;
}
/**
@brief инициализируем системный таймер на 1ms
*/
void SysTick_Init(void)
{
SysTick_Config((P_SYSCLK/1000UL));
return;
}
/**
@brief блокирущая задержка
*/
void delay(uint32_t ms)
{
uint32_t tickstart = time_get_ms();
uint32_t wait = ms;
while ((time_get_ms() - tickstart) < wait)
{
}
}
/**
@brief получить время в ms
*/
uint32_t time_get_ms(void)
{
return time_ms_cnt;
}
/**
@brief получить время в сеундах
*/
uint32_t time_get_sec(void)
{
return time_sec_cnt;
}
/**
@brief передаём указатель на счётчи времени в модбас
*/
uint8_t MBRF_time_init(void)
{
uint8_t MB_init_eror = 0u;
MB_init_eror+=MBRF_create_reg(MBADDR_TIME_SEC0, ((uint16_t*)&time_sec_cnt)+1u, MBTYPE_TIME_SEC); //0x006E
MB_init_eror+=MBRF_create_reg(MBADDR_TIME_SEC1, &time_sec_cnt, MBTYPE_TIME_SEC); //0x006F
return MB_init_eror;
}

14
src/plib/sys_tim.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SYS_TIM_H_
#define SYS_TIM_H_
#include "platform.h"
void SysTick_Init(void);
void delay(uint32_t ms);
void SysTick_Handler(void);
uint32_t time_get_ms(void);
uint32_t time_get_sec(void);
uint8_t MBRF_time_init(void);
#endif

55
src/plib/uart_debug.c Normal file
View File

@ -0,0 +1,55 @@
#include "uart_debug.h"
#include "platform.h"
#include "xprintf.h"
static void uart_putc(uint8_t d);
static uint8_t uart_getc(void);
static void printf_config(void)
{
xdev_out(uart_putc);
xdev_in(uart_getc);
return;
}
static uint8_t uart_getc(void)
{
while ((USART2->ISR & USART_ISR_RXNE_RXFNE) == 0) { NOP();}
return USART2->RDR;
}
static void uart_putc(uint8_t ch)
{
while ((USART2->ISR & USART_ISR_TC) == 0) { NOP();}
USART2->TDR = ch;
}
/**
@brief инициализируем в uart в блокирующем режиме в передаём уазатели в xprintf
*/
void uart_debug_init(void)
{
RCC->APBENR1 |= RCC_APBENR1_USART2EN; // Включаем тактирование UART2
RCC->IOPENR |= RCC_IOPENR_GPIOAEN; // Включаем тактирование GPIO порта A
SYSCFG->CFGR2 |= SYSCFG_CFGR2_PA3_CDEN; //Clamping Diode Enable
SYSCFG->CFGR2 |= SYSCFG_CFGR2_PA13_CDEN; //Clamping Diode Enable на SWDIO //по хорошему это нужно делать не тут
// Настройка PA2 как TX и PA3 как RX
GPIOA->MODER &= ~(GPIO_MODER_MODE2_0 | GPIO_MODER_MODE3_0); // Режим альтернативной функции
GPIOA->MODER |= (GPIO_MODER_MODE2_1 | GPIO_MODER_MODE3_1); // Установить режим альтернативной функции
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL2_0 | GPIO_AFRL_AFSEL3_0; // Установить альтернативную функцию AF1 для PA2 и PA3
// Настройка скорости GPIO
GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED2 | GPIO_OSPEEDR_OSPEED3); // Настройка на очень низкую скорость
USART2->CR1 = 0; // Сбрасываем регистр CR1
USART2->BRR = 556; // Установка BRR для скорости 115200 при 64 МГц
USART2->CR1 |= USART_CR1_TE | USART_CR1_RE; // Разрешаем передатчик и приемник
USART2->CR1 |= USART_CR1_UE; // Включаем USART2
USART2->CR2 = 0; // Сбрасываем регистр CR2
USART2->CR3 = 0; // Сбрасываем регистр CR3
printf_config();
}

7
src/plib/uart_debug.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UART_DEBUG_H_
#define UART_DEBUG_H_
void uart_debug_init(void);
#endif

555
src/plib/uart_modbus.c Normal file
View File

@ -0,0 +1,555 @@
/**
******************************************************************************
* @file uart_modbus.c
* @brief modbus lol level func
* @note тут всё в процессе, очень грязно код написан, нужно рефакторинг глубокий
* @note разбить на 2 файла, чтоб логика и работа с регистрами МК была отдельна
* @note так же нужно добавить функциокал (отслеживание пропусков 1.5ch и т.д.)
* @note "логическую" часть покрыть тестами и к misrac всё привести
******************************************************************************
*/
#include "platform.h"
#include "uart_modbus.h"
#include "sys_tim.h"
#include "crc.h"
#include "modbus_regs_file.h"
#include "modbus_config.h"
#include "led.h"//delete
#include "dout.h"
static void MB_DMA_tx_start(uint16_t len);
static void MB_DMA_rx_start(uint16_t len);
static void MB_response_handler(bool unicast_flag);
extern void DMA1_Channel1_IRQHandler(void);
extern void DMA1_Channel2_3_IRQHandler(void);
extern void USART1_IRQHandler(void);
static uint8_t MB_make_frame_eror(uint8_t er_code);
static uint8_t MB_make_frame_w(MBR_reg_type reg_type);
static uint8_t MB_make_frame_r_bool(MBR_reg_type reg_type);
static uint8_t MB_make_frame_r_u16(MBR_reg_type reg_type);
static bool MB_check_request(bool *unicast_flag);
static void RE_DE_set_pin(bool state);
static void RE_DE_init_pin(void);
static uint32_t USART_BRR_calculate(uint16_t baud_rate);
static void USART_set_stop_bit(uint16_t stop_bit);
static void USART_set_parity_bit(uint16_t parity_bit);
static void USART_set_BRR(uint16_t* baud_rate);
#define MB_BROADCAST_ADDRESS 0x0
#define FRAME_MAX_LENGTH 257u
#define FRAME_MIN_LENGTH 3u//see MODBUS over serial line specification and implementation guide V1.02. 6.1.2
#define UNICAST 1u
#define BROADCAST 0u
//### MODBUS Exception Responses ###
#define MB_ER_ILLEGAL_FUNCTION 0x01 //The function code received in the query is not an allowable action for the server
#define MB_ER_ILLEGAL_DATA_ADDRESS 0x02
#define MB_ER_ILLEGAL_DATA_VALUE 0x03
#define MB_ER_SERVER_DEVICE_FAILURE 0x04
#define MB_ER_ACKNOWLEDGE 0x05
#define MB_ER_SERVER_DEVICE_BUSY 0x06
#define MB_ER_MEMORY_PARITY_ERROR 0x08
#define MB_ER_GATEWAY_PATH_UNAVAILABLE 0x0A
#define MB_ER_GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND 0x0B
#define MB_FUNC_FILED 0x80 //In an exception response, the server sets the MSB of the function code to 1. This makes the function codevalue in an exception response exactly 80 hexadecimal higher than the value would be for anormal response
#define MB_ER_LEN 0x05
//### MODBUS Function code ###
#define MB_FUNC_R_INPUT_DISCRETE 0x02
#define MB_FUNC_R_COILS_REG 0x01
#define MB_FUNC_R_INPUT_REG 0x04
#define MB_FUNC_R_HOLDING_REG 0x03
#define MB_FUNC_W_SINGLE_REG 0x06
#define MB_FUNC_W_SINGLE_COIL 0x05
#define MB_R_COILS_LEN 8u
#define MB_W_COIL_LEN 8u
#define MB_W_HOLDING_LEN 8u
#define MB_R_HOLDING_LEN (0x007D+CRC_LEN+2u) //максимальное кол-во регистров (125) + сrc + адресс + од функции
typedef enum
{
USART_BD_1200 = 12U, //12 — 1200 бит/с
USART_BD_2400 = 24U, //24 — 2400 бит/с,
USART_BD_4800 = 48U, //48 — 4800 бит/с,
USART_BD_9600 = 96U, //96 — 9600 бит/с,
USART_BD_19200 = 192U, //192 — 19 200 бит/с,
USART_BD_38400 = 384U, //384 — 38 400 бит/с,
USART_BD_57600 = 576U, //576 — 57 600 бит/с,
USART_BD_115200 = 1152U //1152 — 115 200 бит/с
} USART_baud_rate;
static uint16_t usart_slave_addr = MBDDATA_SLAVE_ADDR;
static uint16_t usart_bd =MBDDATA_BAUD_RATE;
static uint16_t usart_stop_bits = MBDDATA_STOP_BIT;
static uint16_t usart_parity_bit = MBDDATA_PARITY_BIT;
static bool busy_flag=0x0;
static struct modbus_frame
{
uint8_t bytes[FRAME_MAX_LENGTH];
uint16_t length; //текущая длина bytes[FRAME_MAX_LENGTH]
bool length_eror_flag; //если приняли больше FRAME_MAX_LENGTH
bool idle_3_5_ch_flag; //если на шине тишина в течении байт
bool idle_1_5_ch_flag;
bool frame_successful; //ставим этот флаг если нету ошибок с длинами и таймингами, далее нужно роверять на адресс и чётность
uint8_t* adr;
uint8_t* func_code;
} mb_frame;
static void RE_DE_init_pin(void)
{
RCC -> IOPENR |= RCC_IOPENR_GPIOAEN ;
GPIOA -> MODER &= ~GPIO_MODER_MODE8_1;
GPIOA -> MODER |= GPIO_MODER_MODE8_0; //General purpose output mode
GPIOA -> OSPEEDR &= ~ GPIO_OSPEEDR_OSPEED8_1;
GPIOA -> OSPEEDR &= ~ GPIO_OSPEEDR_OSPEED8_0;//Very low speed
GPIOA -> OTYPER |= (GPIO_OTYPER_OT8); //open drain
GPIOA -> PUPDR &= ~(GPIO_PUPDR_PUPD8_1); //pullup
GPIOA -> PUPDR |= (GPIO_PUPDR_PUPD8_0);
RE_DE_set_pin(0u);
return;
}
static void RE_DE_set_pin(bool state)
{
if(state!=0){
GPIOA -> ODR |=GPIO_ODR_OD8;
}else{
GPIOA -> ODR &= ~GPIO_ODR_OD8;
}
return;
}
/**
@brief init func
*/
void uart_modbus_init(void)
{
mb_frame.length=0;
mb_frame.bytes[0]=0;
mb_frame.length_eror_flag=0;
mb_frame.idle_3_5_ch_flag=0;
mb_frame.idle_1_5_ch_flag=0;
mb_frame.frame_successful=0;
mb_frame.adr=&mb_frame.bytes[0];
mb_frame.func_code=&mb_frame.bytes[1];
RE_DE_init_pin();
RCC->APBENR2 |= RCC_APBENR2_USART1EN; // Включаем тактирование UART2
RCC-> IOPENR |= RCC_IOPENR_GPIOBEN ; // Включаем тактирование GpioB
//Настройка PB3 как TX и PB7 как RX
GPIOB->MODER &= ~(GPIO_MODER_MODE6_0 | GPIO_MODER_MODE7_0); // Режим альтернативной функции
GPIOB->MODER |= (GPIO_MODER_MODE6_1 | GPIO_MODER_MODE7_1); // Установить режим альтернативной функции
GPIOB -> OTYPER |= (GPIO_OTYPER_OT6 | GPIO_OTYPER_OT7); //open drain
GPIOB -> PUPDR &= ~(GPIO_PUPDR_PUPD6_1 |GPIO_PUPDR_PUPD7_1); //pullup
GPIOB -> PUPDR |=(GPIO_PUPDR_PUPD6_0|GPIO_PUPDR_PUPD7_0);
//GPIOB->AFR[0] &= ~ (GPIO_AFRL_AFSEL6 | GPIO_AFRL_AFSEL7); // Установить альтернативную функцию AF1 для PA2 и PA3
// Настройка скорости GPIO
GPIOB->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED6 | GPIO_OSPEEDR_OSPEED7); // Настройка на очень низкую скорость
USART1->ICR |= USART_ICR_TCCF; //Transmission Complete Clear Flag
USART_set_BRR(&usart_bd);
USART1->CR1 = 0u; // Сбрасываем регистр CR1
USART_set_parity_bit(usart_parity_bit);
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE; // Разрешаем передатчик и приемник
//USART1->CR1 |= USART_CR1_DEAT_1 | USART_CR1_DEDT_1; //rs485 flow contol timing
USART1->CR1 |= USART_CR1_RTOIE ; //USART interrupt generated when the RTOF bit is set in the USART_ISR register.
USART1->CR1 |= USART_CR1_TCIE; //Transmission Complete Interrupt Enable
USART1->CR2 = 0u; // Сбрасываем регистр CR2
USART_set_stop_bit(usart_stop_bits);
USART1->CR2 |= USART_CR2_SWAP; //инверсия tx-rx
USART1->CR2 |= USART_CR2_RTOEN; //Receiver timeout feature enabled.
USART1->CR3 = 0u; // Сбрасываем регистр CR3
//USART1->CR3 |= USART_CR3_DEM; //DE function is enabled. The DE signal is output on the RTS pin.
USART1->ICR |= USART_ICR_TCCF; //Transmission Complete Clear Flag
//#####DMA#####
USART1->CR3 |= USART_CR3_DMAR; //DMA Enable Receiver
USART1->CR3 |= USART_CR3_DMAT; //DMA Enable Transmitter
USART1->RTOR = 22u; //Receiver timeout value
//#####DMA#####
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //включаем тактирование
DMA1_Channel3->CPAR = (&(USART1->RDR)); //указатель на приёмник
DMA1_Channel3->CMAR = mb_frame.bytes; //адресс на начало буфера
DMA1_Channel3->CNDTR = FRAME_MAX_LENGTH&DMA_CNDTR_NDT; //кол-во байт по которому сработает прерывание
DMA1_Channel3->CCR |= (DMA_CCR_PL //priority level hery high
| DMA_CCR_MINC //memory increment mode enable
| DMA_CCR_TCIE //transfer complete interrupt enable
| DMA_CCR_TEIE); //transfer eror interrupt enable
DMA1_Channel2->CPAR = (&(USART1->TDR)); //указатель на передатчик
DMA1_Channel2->CMAR = mb_frame.bytes; //адресс на начало буфера
DMA1_Channel2->CNDTR = 0; //счётчик
DMA1_Channel2->CCR |= (DMA_CCR_PL //priority level hery high
| DMA_CCR_MINC //memory increment mode enable
| DMA_CCR_TCIE //transfer complete interrupt enable
| DMA_CCR_TEIE
| DMA_CCR_DIR); //Data transfer direction
#define DMAREQ_ID_USART1_RX 50u
#define DMAREQ_ID_USART1_TX 51u
DMAMUX1_Channel2->CCR = (DMAREQ_ID_USART1_RX&DMAMUX_CxCR_DMAREQ_ID);
DMAMUX1_Channel1->CCR = (DMAREQ_ID_USART1_TX&DMAMUX_CxCR_DMAREQ_ID);
NVIC_SetPriority(DMA1_Channel2_3_IRQn, MODBUS_IRQ_PIOITY_LEVEL);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
DMA1_Channel3->CCR |= DMA_CCR_EN; //enable DMA
USART1->CR1 |= USART_CR1_UE; // Включаем USART
NVIC_SetPriority(USART1_IRQn, MODBUS_IRQ_PIOITY_LEVEL);
NVIC_EnableIRQ(USART1_IRQn);
#ifdef DEBUG
xprintf("baud rate = %d\n",usart_bd);
xprintf("usart_stop_bits = %d\n",usart_stop_bits);
xprintf("usart_parity_bit = %d\n",usart_parity_bit);
xprintf("usart_slave_addr = 0x%x\n",usart_slave_addr);
#endif
return;
}
/**
@brief проверка на занятость драйвера
@return 0x1 в случае если драйвер занят (идёт обмен по уарт)
*/
bool MBRF_check_transfer_not_completed(void)
{
return busy_flag;
}
uint8_t MBRF_modbus_init(void)
{
uint8_t MB_init_eror = 0u;
MB_init_eror+=MBRF_create_reg(MBADDR_BAUD_RATE, &usart_bd, MBTYPE_BAUD_RATE); //0x006E
MB_init_eror+=MBRF_create_reg(MBADDR_PARITY_BIT, &usart_parity_bit, MBTYPE_PARITY_BIT); //0x006F
MB_init_eror+=MBRF_create_reg(MBADDR_STOP_BIT, &usart_stop_bits, MBTYPE_STOP_BIT); //0x0070
MB_init_eror+=MBRF_create_reg(MBADDR_SLAVE_ADDR, &usart_slave_addr, MBTYPE_SLAVE_ADDR); //0x0080
return MB_init_eror;
}
static void USART_set_parity_bit(uint16_t parity_bit)
{
if(parity_bit==1u)
{
USART1->CR1 |= ( USART_CR1_PCE | USART_CR1_M0 | USART_CR1_PS );
}else if (parity_bit==2u)
{
USART1->CR1 |= ( USART_CR1_PCE | USART_CR1_M0 );
USART1->CR1 &= ~ ( USART_CR1_PS );
}else{
USART1->CR1 &= ~ ( USART_CR1_PCE | USART_CR1_M0 | USART_CR1_PS );
}
return;
}
static void USART_set_stop_bit(uint16_t stop_bit)
{
uint32_t ret =0;
if(stop_bit!=1u)
{
USART1->CR2 |= USART_CR2_STOP_1;
}else{
USART1->CR2 &= ~ USART_CR2_STOP_1;
}
return;
}
static void USART_set_BRR(uint16_t* baud_rate)
{
switch (*baud_rate) {
case USART_BD_1200:
USART1->BRR = (P_SYSCLK/((USART_BD_1200*100u))+1u);
break;
case USART_BD_2400:
USART1->BRR = (P_SYSCLK/((USART_BD_2400*100u))+1u);
break;
case USART_BD_4800:
USART1->BRR = (P_SYSCLK/((USART_BD_4800*100u))+1u);
break;
case USART_BD_9600:
USART1->BRR = (P_SYSCLK/((USART_BD_9600*100u))+1u);
break;
case USART_BD_19200:
USART1->BRR = (P_SYSCLK/((USART_BD_19200*100u))+1u);
break;
case USART_BD_38400:
USART1->BRR = (P_SYSCLK/((USART_BD_38400*100u))+1u);
break;
case USART_BD_57600:
USART1->BRR = (P_SYSCLK/((USART_BD_57600*100u))+1u);
break;
case USART_BD_115200:
USART1->BRR = (P_SYSCLK/((USART_BD_115200*100u))+1u);
break;
default:
*baud_rate = MBDDATA_BAUD_RATE;
USART1->BRR = (P_SYSCLK/((MBDDATA_BAUD_RATE*100u))+1u); //9600 в случае остального
break;
}
return;
}
extern void DMA1_Channel2_3_IRQHandler(void)
{
if(DMA1->ISR & DMA_ISR_TCIF3 )
{
DMA1->IFCR |= DMA_IFCR_CTCIF3;
MB_DMA_rx_start(FRAME_MAX_LENGTH);
mb_frame.length=0;
mb_frame.length_eror_flag=1;
}
if(DMA1->ISR & DMA_ISR_TEIF3)
{
DMA1->IFCR |= DMA_IFCR_CTEIF3;
MB_DMA_rx_start(FRAME_MAX_LENGTH);
mb_frame.length=0;
mb_frame.length_eror_flag=1;
}
if(DMA1->ISR & DMA_ISR_TCIF2 )
{
DMA1->IFCR |= DMA_IFCR_CTCIF2;
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
}
if(DMA1->ISR & DMA_ISR_TEIF2)
{
DMA1->IFCR |= DMA_IFCR_CTEIF2;
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
}
return;
}
extern void USART1_IRQHandler(void)
{
if(USART1->ISR&USART_ISR_RTOF) //timeoit flag
{
USART1->ICR |= USART_ICR_RTOCF; //чистим флаг
mb_frame.idle_3_5_ch_flag=1;
mb_frame.length=FRAME_MAX_LENGTH-(DMA1_Channel3->CNDTR)&DMA_CNDTR_NDT;
MB_DMA_rx_start(FRAME_MAX_LENGTH);
}
if((USART1->ISR&USART_ISR_TC)) //Transmission Complete Interrupt Enable
{
USART1->ICR |= USART_ICR_TCCF; //чистим флаг
USART_set_BRR(&usart_bd);
USART_set_parity_bit(usart_parity_bit);
USART_set_stop_bit(usart_stop_bits);
RE_DE_set_pin(0);
busy_flag=0x0;
}
return;
}
void modbus_periodic_work(void)
{
bool unicast_flag;
if(MB_check_request(&unicast_flag))
{
MB_response_handler(unicast_flag);
}
return;
}
static bool MB_check_request(bool *unicast_flag)
{
bool ret=0;
do{
if( (mb_frame.length_eror_flag)!=0u )
{
mb_frame.length_eror_flag=0u;
break;
}
if( (mb_frame.idle_1_5_ch_flag)!=0u )
{
mb_frame.idle_1_5_ch_flag=0u;
break;
}
if((mb_frame.idle_3_5_ch_flag)!=1u)
{
break;
}
if(mb_frame.length<FRAME_MIN_LENGTH)
{
break;
}
if(CRC_check(mb_frame.bytes, mb_frame.length)!=true)
{
break;
}
if(*mb_frame.adr==(uint8_t)usart_slave_addr)
{
ret=1;
*unicast_flag=UNICAST;
}else if (*mb_frame.adr==MB_BROADCAST_ADDRESS)
{
ret=1;
*unicast_flag=BROADCAST;
}
}while(0u);
return ret;
}
static void MB_response_handler(bool unicast_flag)
{
uint16_t tx_len=0;
switch (*mb_frame.func_code) {
case MB_FUNC_R_HOLDING_REG:
tx_len=MB_make_frame_r_u16(MBR_holding);
break;
case MB_FUNC_R_COILS_REG:
tx_len=MB_make_frame_r_bool(MBR_coils);
break;
case MB_FUNC_R_INPUT_REG:
tx_len=MB_make_frame_r_u16(MBR_input);
break;
case MB_FUNC_R_INPUT_DISCRETE:
tx_len=MB_make_frame_r_bool(MBR_input_discrete);
break;
case MB_FUNC_W_SINGLE_COIL:
tx_len=MB_make_frame_w(MBR_coils);
break;
case MB_FUNC_W_SINGLE_REG:
tx_len=MB_make_frame_w(MBR_holding);
break;
default:
tx_len=MB_make_frame_eror(MB_ER_ILLEGAL_FUNCTION);
break;
}
if((tx_len>=FRAME_MIN_LENGTH)&&(unicast_flag!=BROADCAST))
{
MB_DMA_tx_start(tx_len);
}
return;
}
static void MB_DMA_rx_start(uint16_t len)
{
DMA1_Channel3->CCR &=~ DMA_CCR_EN; //enable DMA
DMA1_Channel3->CNDTR = len;
DMA1_Channel3->CCR |= DMA_CCR_EN; //enable DMA
return;
}
static void MB_DMA_tx_start(uint16_t len)
{
busy_flag=0x1;
RE_DE_set_pin(1u);
DMA1_Channel2->CNDTR = len; /*Set number of bytes to transmit*/
DMA1_Channel2->CCR |= DMA_CCR_EN; /*Enable Tx DMA channel*/
return;
}
#define MB_FUNC_BYTE 0x2
static uint8_t MB_make_frame_eror(uint8_t er_code)
{
uint8_t ret = 0; //если не UNICAST возвращаем 0
ret = MB_ER_LEN;
*mb_frame.func_code+=MB_FUNC_FILED;
mb_frame.bytes[MB_FUNC_BYTE]=er_code; //код функции
CRC_get(mb_frame.bytes, MB_ER_LEN,&mb_frame.bytes[MB_ER_LEN-2],&mb_frame.bytes[MB_ER_LEN-1]);
return ret;
}
static uint8_t MB_make_frame_w(MBR_reg_type reg_type)
{
uint8_t ret =0;
uint16_t data_buf = (uint16_t)(mb_frame.bytes[4]<<8)+mb_frame.bytes[5]; //magic num
uint16_t reg_adr = (uint16_t)(mb_frame.bytes[2]<<8)+mb_frame.bytes[3]; //magic num
if(MB_W_HOLDING_LEN!=mb_frame.length)
{
ret = MB_make_frame_eror(MB_ER_ILLEGAL_DATA_VALUE);
}else
{
if(MBR_OK==MBRF_write_reg(reg_adr,data_buf,reg_type))
{
ret = mb_frame.length; //т.к. в случае успешной заиси мы должны вернуть тоже самое, не переисывает буфер вообще
}else
{
ret = MB_make_frame_eror(MB_ER_ILLEGAL_DATA_ADDRESS);
}
}
return ret;
}
static uint8_t MB_make_frame_r_u16( MBR_reg_type reg_type)
{
uint8_t ret =0u;
uint16_t data_buf;
uint16_t reg_adr_start = (uint16_t)(mb_frame.bytes[2u]<<8u)+mb_frame.bytes[3u]; //magic num
uint16_t reg_num = (uint16_t)mb_frame.bytes[5u]; //magic num
if(mb_frame.length>MB_R_HOLDING_LEN)
{
ret = MB_make_frame_eror(MB_ER_ILLEGAL_DATA_VALUE);
}else
{
if(MBR_OK==MBRF_multiple_read_reg(reg_adr_start, reg_num, &mb_frame.bytes[3u], reg_type))
{
mb_frame.bytes[2u]=2*(reg_num);
CRC_get(mb_frame.bytes, 5u+(reg_num*2u),&mb_frame.bytes[5u+((reg_num-1)*2)],&mb_frame.bytes[6u+((reg_num-1)*2)]);
ret = 5u+(reg_num*2);
}else
{
ret = MB_make_frame_eror(MB_ER_ILLEGAL_DATA_ADDRESS);
}
}
return ret;
}
static uint8_t MB_make_frame_r_bool(MBR_reg_type reg_type)
{
uint8_t ret =0u;
uint16_t data_buf;
uint16_t reg_adr_start = (uint16_t)(mb_frame.bytes[2u]<<8u)+mb_frame.bytes[3u]; //magic num
uint16_t reg_num = (uint16_t)mb_frame.bytes[5u]; //magic num
if(mb_frame.length>MB_R_HOLDING_LEN)
{
ret = MB_make_frame_eror(MB_ER_ILLEGAL_DATA_VALUE);
}else
{
if(MBR_OK==MBRF_multiple_read_reg_bool(reg_adr_start, reg_num, &mb_frame.bytes[3u], reg_type))
{
reg_num=(reg_num/8u)+((reg_num%8u)!=0);
mb_frame.bytes[2u]=(reg_num);
CRC_get(mb_frame.bytes, 5u+(reg_num),&mb_frame.bytes[3u+reg_num],&mb_frame.bytes[4u+reg_num]);
ret = 5u+(reg_num);
// mb_frame.bytes[2u]=(reg_num);
// CRC_get(mb_frame.bytes, 5u+(reg_num),&mb_frame.bytes[3u+reg_num],&mb_frame.bytes[4u+reg_num]);
// ret = 5u+(reg_num);
}else
{
ret = MB_make_frame_eror(MB_ER_ILLEGAL_DATA_ADDRESS);
}
}
return ret;
}

12
src/plib/uart_modbus.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef UART_MODBUS_H_
#define UART_MODBUS_H_
#include "platform.h"
extern void uart_modbus_init(void);
extern void modbus_periodic_work(void);
uint8_t MBRF_modbus_init(void);
bool MBRF_check_transfer_not_completed(void);
#endif

34
src/plib/watchdog.c Normal file
View File

@ -0,0 +1,34 @@
#include "platform.h"
#define WATCHDOG 1u
#define START_KEY (uint32_t)0xCCCC
#define ENABLE_ACCES_KEY (uint32_t)0x5555
#define REFRESH_VALUE (uint32_t)0xAAAA
/**
@brief инициализируем собаку
@brief 0,5 без вызова refresh перезагружает МК
*/
void watchdog_init(void)
{
IWDG -> KR = START_KEY&IWDG_KR_KEY ; //Writing the key value 0xCCCC starts the watchdog
IWDG -> KR = ENABLE_ACCES_KEY&IWDG_KR_KEY ; //Writing the key value 0x5555 to enable access to the IWDG_PR, IWDG_RLR and IWDG_WINR registers
IWDG -> PR |= 0x100; //divider /64
IWDG -> PR |= 0x1; //0.5 секунд
while( (IWDG -> SR) != (uint32_t)(0x0) ) //Wait for the registers to be updated (IWDG_SR = 0x0000 0000)
{
NOP();
}
return;
}
/**
@brief обновить пса
*/
void watchdog_refresh(void)
{
IWDG -> KR = REFRESH_VALUE&IWDG_KR_KEY ; //Refresh the counter value
return;
}

7
src/plib/watchdog.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef WATCHDOG_H_
#define WATCHDOG_H_
void watchdog_init(void);
void watchdog_refresh(void);
#endif

6
src_tests/main.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "CppUTest/CommandLineTestRunner.h"
int main(int ac, char** av)
{
return CommandLineTestRunner::RunAllTests(ac, av);
}

View File

@ -0,0 +1,5 @@
//stm32g0xx.h
#include <stdint.h>
#include <stdbool.h>
#define FIRMWARE_VERSION 0x0020

View File

@ -0,0 +1,813 @@
#include "CppUTest/TestHarness.h"
extern "C"
{
#include "modbus_regs_file.h"
}
#define U16_DATA_SIMPLE 0x3465
#define U16_DATA_MAX 0xFFFF
#define U16_DATA_ZERO 0x0000
#define ADDR_SIMPLE 0x0023
#define ADDR_MAX 0xFFFF
#define ADDR_ZERO 0x0000
TEST_GROUP(modbus_regs_file)
{
uint16_t u16_data_simple;
uint16_t u16_data_max;
uint16_t u16_data_zero;
void setup() {
u16_data_simple = U16_DATA_SIMPLE;
u16_data_max = U16_DATA_MAX;
u16_data_zero = U16_DATA_ZERO;
}
void teardown() {
MBRF_clear_file();
}
};
// TEST(modbus_regs_file, read_wire_non_init_i_reg_zero_addr)
// {
// MBRF_init_start();
// CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input), MBR_OK);
// CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input), MBR_OK);
// MBRF_init_end();
// }
// TEST(modbus_regs_file, read_i_reg)
// {
// MBRF_init_start();
// MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input);
// MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input);
// MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_input);
// MBRF_init_end();
// uint16_t data;
// CHECK_EQUAL(MBRF_read_reg(ADDR_SIMPLE,&data,MBR_input), MBR_OK);
// CHECK_EQUAL(data,U16_DATA_SIMPLE);
// CHECK_EQUAL(MBRF_read_reg(ADDR_ZERO,&data,MBR_input), MBR_OK);
// CHECK_EQUAL(data,U16_DATA_ZERO);
// CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_input), MBR_OK);
// CHECK_EQUAL(data,U16_DATA_MAX);
// }
// TEST(modbus_regs_file, read_multiple_i_reg)
// {
// #define START_ADDR 32u
// #define PLUS 23u
// uint16_t reg[6]={0,1,2,3,4,5};
// MBRF_init_start();
// //некрасиво но нормально
// MBRF_create_reg(START_ADDR,&reg[0],MBR_input);
// MBRF_create_reg(START_ADDR+1,&reg[1],MBR_input);
// MBRF_create_reg(START_ADDR+2,&reg[2],MBR_input);
// MBRF_create_reg(START_ADDR+3,&reg[3],MBR_input);
// MBRF_init_end();
// uint8_t data[8]={0};
// CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 4, data, MBR_input), MBR_OK);
// CHECK_EQUAL(data[0],(uint8_t)((reg[0])>>8));
// CHECK_EQUAL(data[1],(uint8_t)(reg[0]));
// CHECK_EQUAL(data[2],(uint8_t)((reg[1])>>8));
// CHECK_EQUAL(data[3],(uint8_t)(reg[1]));
// CHECK_EQUAL(data[4],(uint8_t)((reg[2])>>8));
// CHECK_EQUAL(data[5],(uint8_t)(reg[2]));
// CHECK_EQUAL(data[6],(uint8_t)((reg[3])>>8));
// CHECK_EQUAL(data[7],(uint8_t)(reg[3]));
// }
TEST(modbus_regs_file, read_wire_non_init_i_reg_zero_addr)
{
MBRF_init_start();
MBRF_init_end();
uint16_t data=0;
CHECK_EQUAL(MBRF_write_reg(ADDR_ZERO,data,MBR_input), MBR_ERROR);
CHECK_EQUAL(MBRF_read_reg(ADDR_ZERO,&data,MBR_input), MBR_ERROR);
CHECK_EQUAL(data,0);
}
///////////////////////////input////////////////////
TEST(modbus_regs_file, create_i_reg_before_init_file)
{
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input),MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_i_reg_defore_init_end)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input), MBR_OK);
MBRF_init_end();
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_input), MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_i_reg_simple)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_input), MBR_OK);
CHECK_EQUAL(MBRF_init_end(), MBR_OK);
}
TEST(modbus_regs_file, create_i_reg_len_max)
{
MBRF_init_start();
for(uint32_t i=0; i<MBRF_MAX_QUANTITY(MBR_input);i++)
{
CHECK_EQUAL(MBRF_create_reg(i,&u16_data_simple,MBR_input), MBR_OK);
}
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_input), MBR_LEN_ERROR);
MBRF_init_end();
}
TEST(modbus_regs_file, create_2_i_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input);
CHECK_EQUAL(MBRF_init_end(),MBR_ADDR_ERROR);
}
TEST(modbus_regs_file, read_i_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_input);
MBRF_init_end();
uint16_t data;
CHECK_EQUAL(MBRF_read_reg(ADDR_SIMPLE,&data,MBR_input), MBR_OK);
CHECK_EQUAL(data,U16_DATA_SIMPLE);
CHECK_EQUAL(MBRF_read_reg(ADDR_ZERO,&data,MBR_input), MBR_OK);
CHECK_EQUAL(data,U16_DATA_ZERO);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_input), MBR_OK);
CHECK_EQUAL(data,U16_DATA_MAX);
}
TEST(modbus_regs_file, read_wire_non_init_i_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input);
MBRF_create_reg(ADDR_SIMPLE,&u16_data_zero,MBR_input);
MBRF_init_end();
uint16_t data=0;
CHECK_EQUAL(MBRF_write_reg(ADDR_MAX,data,MBR_input), MBR_ERROR);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_input), MBR_ERROR);
CHECK_EQUAL(data,0);
}
TEST(modbus_regs_file, write_i_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_input);
MBRF_init_end();
uint16_t data_w=(U16_DATA_ZERO+0x675);//random num
uint16_t data_r;
CHECK_EQUAL(MBRF_write_reg(ADDR_ZERO,data_w,MBR_input), MBR_OK);
MBRF_read_reg(ADDR_ZERO,&data_r,MBR_input);
CHECK_EQUAL(data_r,data_w);
}
TEST(modbus_regs_file, read_multiple_i_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t reg[6]={0,1,2,3,4,5};
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&reg[0],MBR_input);
MBRF_create_reg(START_ADDR+1,&reg[1],MBR_input);
MBRF_create_reg(START_ADDR+2,&reg[2],MBR_input);
MBRF_create_reg(START_ADDR+3,&reg[3],MBR_input);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 4, data, MBR_input), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)((reg[0])>>8));
CHECK_EQUAL(data[1],(uint8_t)(reg[0]));
CHECK_EQUAL(data[2],(uint8_t)((reg[1])>>8));
CHECK_EQUAL(data[3],(uint8_t)(reg[1]));
CHECK_EQUAL(data[4],(uint8_t)((reg[2])>>8));
CHECK_EQUAL(data[5],(uint8_t)(reg[2]));
CHECK_EQUAL(data[6],(uint8_t)((reg[3])>>8));
CHECK_EQUAL(data[7],(uint8_t)(reg[3]));
}
TEST(modbus_regs_file, read_multiple_i_reg_zero_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_ZERO, 0, data, MBR_input), MBR_LEN_ERROR);
}
TEST(modbus_regs_file, read_multiple_i_reg_one_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_SIMPLE, 1, data, MBR_input), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)(U16_DATA_SIMPLE>>8));
CHECK_EQUAL(data[1],(uint8_t)(U16_DATA_SIMPLE));
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_window_i_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t buf=1;
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&buf,MBR_input);
MBRF_create_reg(START_ADDR+1,&buf,MBR_input);
MBRF_create_reg(START_ADDR+3,&buf,MBR_input);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 3, data, MBR_input), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_non_create_i_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_MAX, 1, data, MBR_input), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
///////////////////////////holding////////////////////
TEST(modbus_regs_file, create_h_reg_before_init_file)
{
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding),MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_h_reg_defore_init_end)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_holding), MBR_OK);
MBRF_init_end();
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_holding), MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_h_reg_simple)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_holding), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_holding), MBR_OK);
CHECK_EQUAL(MBRF_init_end(), MBR_OK);
}
TEST(modbus_regs_file, create_h_reg_len_max)
{
MBRF_init_start();
for(uint32_t i=0; i<MBRF_MAX_QUANTITY(MBR_holding);i++)
{
CHECK_EQUAL(MBRF_create_reg(i,&u16_data_simple,MBR_holding), MBR_OK);
}
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_holding), MBR_LEN_ERROR);
MBRF_init_end();
}
TEST(modbus_regs_file, create_2_h_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_holding);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_holding);
CHECK_EQUAL(MBRF_init_end(),MBR_ADDR_ERROR);
}
TEST(modbus_regs_file, read_h_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_holding);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_holding);
MBRF_init_end();
uint16_t data;
CHECK_EQUAL(MBRF_read_reg(ADDR_SIMPLE,&data,MBR_holding), MBR_OK);
CHECK_EQUAL(data,U16_DATA_SIMPLE);
CHECK_EQUAL(MBRF_read_reg(ADDR_ZERO,&data,MBR_holding), MBR_OK);
CHECK_EQUAL(data,U16_DATA_ZERO);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_holding), MBR_OK);
CHECK_EQUAL(data,U16_DATA_MAX);
}
TEST(modbus_regs_file, read_wire_non_init_h_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_holding);
MBRF_create_reg(ADDR_SIMPLE,&u16_data_zero,MBR_holding);
MBRF_init_end();
uint16_t data=0;
CHECK_EQUAL(MBRF_write_reg(ADDR_MAX,data,MBR_holding), MBR_ERROR);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_holding), MBR_ERROR);
CHECK_EQUAL(data,0);
}
TEST(modbus_regs_file, write_h_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_holding);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_holding);
MBRF_init_end();
uint16_t data_w=(U16_DATA_ZERO+0x675);//random num
uint16_t data_r;
CHECK_EQUAL(MBRF_write_reg(ADDR_ZERO,data_w,MBR_holding), MBR_OK);
MBRF_read_reg(ADDR_ZERO,&data_r,MBR_holding);
CHECK_EQUAL(data_r,data_w);
}
TEST(modbus_regs_file, read_multiple_h_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t reg[6]={0,1,2,3,4,5};
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&reg[0],MBR_holding);
MBRF_create_reg(START_ADDR+1,&reg[1],MBR_holding);
MBRF_create_reg(START_ADDR+2,&reg[2],MBR_holding);
MBRF_create_reg(START_ADDR+3,&reg[3],MBR_holding);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 4, data, MBR_holding), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)((reg[0])>>8));
CHECK_EQUAL(data[1],(uint8_t)(reg[0]));
CHECK_EQUAL(data[2],(uint8_t)((reg[1])>>8));
CHECK_EQUAL(data[3],(uint8_t)(reg[1]));
CHECK_EQUAL(data[4],(uint8_t)((reg[2])>>8));
CHECK_EQUAL(data[5],(uint8_t)(reg[2]));
CHECK_EQUAL(data[6],(uint8_t)((reg[3])>>8));
CHECK_EQUAL(data[7],(uint8_t)(reg[3]));
}
TEST(modbus_regs_file, read_multiple_h_reg_zero_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_holding);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_ZERO, 0, data, MBR_holding), MBR_LEN_ERROR);
}
TEST(modbus_regs_file, read_multiple_h_reg_one_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_SIMPLE, 1, data, MBR_holding), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)(U16_DATA_SIMPLE>>8));
CHECK_EQUAL(data[1],(uint8_t)(U16_DATA_SIMPLE));
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_window_h_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t buf=1;
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&buf,MBR_holding);
MBRF_create_reg(START_ADDR+1,&buf,MBR_holding);
MBRF_create_reg(START_ADDR+3,&buf,MBR_holding);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 3, data, MBR_holding), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_non_create_h_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_holding);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_holding);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_MAX, 1, data, MBR_holding), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
///////////////////////////input_discrete////////////////////
TEST(modbus_regs_file, create_id_reg_before_init_file)
{
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete),MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_id_reg_defore_init_end)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input_discrete), MBR_OK);
MBRF_init_end();
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_input_discrete), MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_id_reg_simple)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(MBRF_init_end(), MBR_OK);
}
TEST(modbus_regs_file, create_id_reg_len_max)
{
MBRF_init_start();
for(uint32_t i=0; i<MBRF_MAX_QUANTITY(MBR_input_discrete);i++)
{
CHECK_EQUAL(MBRF_create_reg(i,&u16_data_simple,MBR_input_discrete), MBR_OK);
}
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_input_discrete), MBR_LEN_ERROR);
MBRF_init_end();
}
TEST(modbus_regs_file, create_2_id_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input_discrete);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input_discrete);
CHECK_EQUAL(MBRF_init_end(),MBR_ADDR_ERROR);
}
TEST(modbus_regs_file, read_id_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input_discrete);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_input_discrete);
MBRF_init_end();
uint16_t data;
CHECK_EQUAL(MBRF_read_reg(ADDR_SIMPLE,&data,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(data,U16_DATA_SIMPLE);
CHECK_EQUAL(MBRF_read_reg(ADDR_ZERO,&data,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(data,U16_DATA_ZERO);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_input_discrete), MBR_OK);
CHECK_EQUAL(data,U16_DATA_MAX);
}
TEST(modbus_regs_file, read_wire_non_init_id_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input_discrete);
MBRF_create_reg(ADDR_SIMPLE,&u16_data_zero,MBR_input_discrete);
MBRF_init_end();
uint16_t data=0;
CHECK_EQUAL(MBRF_write_reg(ADDR_MAX,data,MBR_input_discrete), MBR_ERROR);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_input_discrete), MBR_ERROR);
CHECK_EQUAL(data,0);
}
TEST(modbus_regs_file, write_id_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input_discrete);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_input_discrete);
MBRF_init_end();
uint16_t data_w=(U16_DATA_ZERO+0x675);//random num
uint16_t data_r;
CHECK_EQUAL(MBRF_write_reg(ADDR_ZERO,data_w,MBR_input_discrete), MBR_OK);
MBRF_read_reg(ADDR_ZERO,&data_r,MBR_input_discrete);
CHECK_EQUAL(data_r,data_w);
}
TEST(modbus_regs_file, read_multiple_id_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t reg[6]={0,1,2,3,4,5};
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&reg[0],MBR_input_discrete);
MBRF_create_reg(START_ADDR+1,&reg[1],MBR_input_discrete);
MBRF_create_reg(START_ADDR+2,&reg[2],MBR_input_discrete);
MBRF_create_reg(START_ADDR+3,&reg[3],MBR_input_discrete);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 4, data, MBR_input_discrete), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)((reg[0])>>8));
CHECK_EQUAL(data[1],(uint8_t)(reg[0]));
CHECK_EQUAL(data[2],(uint8_t)((reg[1])>>8));
CHECK_EQUAL(data[3],(uint8_t)(reg[1]));
CHECK_EQUAL(data[4],(uint8_t)((reg[2])>>8));
CHECK_EQUAL(data[5],(uint8_t)(reg[2]));
CHECK_EQUAL(data[6],(uint8_t)((reg[3])>>8));
CHECK_EQUAL(data[7],(uint8_t)(reg[3]));
}
TEST(modbus_regs_file, read_multiple_id_reg_zero_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_input_discrete);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_ZERO, 0, data, MBR_input_discrete), MBR_LEN_ERROR);
}
TEST(modbus_regs_file, read_multiple_id_reg_one_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_SIMPLE, 1, data, MBR_input_discrete), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)(U16_DATA_SIMPLE>>8));
CHECK_EQUAL(data[1],(uint8_t)(U16_DATA_SIMPLE));
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_window_id_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t buf=1;
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&buf,MBR_input_discrete);
MBRF_create_reg(START_ADDR+1,&buf,MBR_input_discrete);
MBRF_create_reg(START_ADDR+3,&buf,MBR_input_discrete);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 3, data, MBR_input_discrete), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_non_create_id_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_input_discrete);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_input_discrete);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_MAX, 1, data, MBR_input_discrete), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
///////////////////////////coils////////////////////
TEST(modbus_regs_file, create_c_reg_before_init_file)
{
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils),MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_c_reg_defore_init_end)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_coils), MBR_OK);
MBRF_init_end();
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_coils), MBR_CEATE_DISABLE);
}
TEST(modbus_regs_file, create_c_reg_simple)
{
MBRF_init_start();
CHECK_EQUAL(MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_coils), MBR_OK);
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_coils), MBR_OK);
CHECK_EQUAL(MBRF_init_end(), MBR_OK);
}
TEST(modbus_regs_file, create_c_reg_len_max)
{
MBRF_init_start();
for(uint32_t i=0; i<MBRF_MAX_QUANTITY(MBR_coils);i++)
{
CHECK_EQUAL(MBRF_create_reg(i,&u16_data_simple,MBR_coils), MBR_OK);
}
CHECK_EQUAL(MBRF_create_reg(ADDR_MAX,&u16_data_simple,MBR_coils), MBR_LEN_ERROR);
MBRF_init_end();
}
TEST(modbus_regs_file, create_2_c_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_coils);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_coils);
CHECK_EQUAL(MBRF_init_end(),MBR_ADDR_ERROR);
}
TEST(modbus_regs_file, read_c_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_coils);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_coils);
MBRF_init_end();
uint16_t data;
CHECK_EQUAL(MBRF_read_reg(ADDR_SIMPLE,&data,MBR_coils), MBR_OK);
CHECK_EQUAL(data,U16_DATA_SIMPLE);
CHECK_EQUAL(MBRF_read_reg(ADDR_ZERO,&data,MBR_coils), MBR_OK);
CHECK_EQUAL(data,U16_DATA_ZERO);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_coils), MBR_OK);
CHECK_EQUAL(data,U16_DATA_MAX);
}
TEST(modbus_regs_file, read_wire_non_init_c_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_coils);
MBRF_create_reg(ADDR_SIMPLE,&u16_data_zero,MBR_coils);
MBRF_init_end();
uint16_t data=0;
CHECK_EQUAL(MBRF_write_reg(ADDR_MAX,data,MBR_coils), MBR_ERROR);
CHECK_EQUAL(MBRF_read_reg(ADDR_MAX,&data,MBR_coils), MBR_ERROR);
CHECK_EQUAL(data,0);
}
TEST(modbus_regs_file, write_c_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils);
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_coils);
MBRF_create_reg(ADDR_MAX,&u16_data_max,MBR_coils);
MBRF_init_end();
uint16_t data_w=(U16_DATA_ZERO+0x675);//random num
uint16_t data_r;
CHECK_EQUAL(MBRF_write_reg(ADDR_ZERO,data_w,MBR_coils), MBR_OK);
MBRF_read_reg(ADDR_ZERO,&data_r,MBR_coils);
CHECK_EQUAL(data_r,data_w);
}
TEST(modbus_regs_file, read_multiple_c_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t reg[6]={0,1,2,3,4,5};
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&reg[0],MBR_coils);
MBRF_create_reg(START_ADDR+1,&reg[1],MBR_coils);
MBRF_create_reg(START_ADDR+2,&reg[2],MBR_coils);
MBRF_create_reg(START_ADDR+3,&reg[3],MBR_coils);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 4, data, MBR_coils), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)((reg[0])>>8));
CHECK_EQUAL(data[1],(uint8_t)(reg[0]));
CHECK_EQUAL(data[2],(uint8_t)((reg[1])>>8));
CHECK_EQUAL(data[3],(uint8_t)(reg[1]));
CHECK_EQUAL(data[4],(uint8_t)((reg[2])>>8));
CHECK_EQUAL(data[5],(uint8_t)(reg[2]));
CHECK_EQUAL(data[6],(uint8_t)((reg[3])>>8));
CHECK_EQUAL(data[7],(uint8_t)(reg[3]));
}
TEST(modbus_regs_file, read_multiple_c_reg_zero_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_ZERO,&u16_data_zero,MBR_coils);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_ZERO, 0, data, MBR_coils), MBR_LEN_ERROR);
}
TEST(modbus_regs_file, read_multiple_c_reg_one_len)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_SIMPLE, 1, data, MBR_coils), MBR_OK);
CHECK_EQUAL(data[0],(uint8_t)(U16_DATA_SIMPLE>>8));
CHECK_EQUAL(data[1],(uint8_t)(U16_DATA_SIMPLE));
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_window_c_reg)
{
#define START_ADDR 32u
#define PLUS 23u
uint16_t buf=1;
MBRF_init_start();
//некрасиво но нормально
MBRF_create_reg(START_ADDR,&buf,MBR_coils);
MBRF_create_reg(START_ADDR+1,&buf,MBR_coils);
MBRF_create_reg(START_ADDR+3,&buf,MBR_coils);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(START_ADDR, 3, data, MBR_coils), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}
TEST(modbus_regs_file, read_multiple_non_create_c_reg)
{
MBRF_init_start();
MBRF_create_reg(ADDR_SIMPLE,&u16_data_simple,MBR_coils);
MBRF_create_reg(ADDR_ZERO,&u16_data_simple,MBR_coils);
MBRF_init_end();
uint8_t data[8]={0};
CHECK_EQUAL(MBRF_multiple_read_reg(ADDR_MAX, 1, data, MBR_coils), MBR_ERROR);
CHECK_EQUAL(data[0],0);
CHECK_EQUAL(data[1],0);
CHECK_EQUAL(data[2],0);
CHECK_EQUAL(data[3],0);
CHECK_EQUAL(data[4],0);
CHECK_EQUAL(data[5],0);
CHECK_EQUAL(data[6],0);
CHECK_EQUAL(data[7],0);
}

68
tools/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,68 @@
pipeline {
agent any
stages {
stage('Build Docker Container') {
steps {
script {
// Создаем Docker образ
docker.build("builder_temp_contoller_firmware", "-f ./tools/dockerfile .")
docker.image('builder_temp_contoller_firmware').inside { sh 'make clean MC_UPLOADER=/app/microcontroller_flash_uploader' }
}
}
}
stage('Check') {
steps {
script {
// Запускаем контейнер и выполняем тесты
docker.image('builder_temp_contoller_firmware').inside {
// Здесь вы можете выполнять команды внутри контейнера
sh 'make check MC_UPLOADER=/app/microcontroller_flash_uploader'
//sh 'while true; do sleep 1000; done'
// Например, запуск тестов:
// sh 'pytest tests/'
}
}
}
}
stage('Unit Unit Tests') {
steps {
script {
// Запускаем контейнер и выполняем тесты
docker.image('builder_temp_contoller_firmware').inside {
sh 'make test CPPUTEST=/app/cpputest MC_UPLOADER=/app/microcontroller_flash_uploader'
}
}
}
}
stage('Build') {
steps {
script {
// Запускаем контейнер и выполняем тесты
docker.image('builder_temp_contoller_firmware').inside {
// Здесь вы можете выполнять команды внутри контейнера
sh 'make all ARM_CC_PREFIX=/app/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi MC_UPLOADER=/app/microcontroller_flash_uploader'
// Например, запуск тестов:
// sh 'pytest tests/'
}
}
}
}
}
post {
always {
script {
// Удаляем все контейнеры после выполнения
sh 'docker container prune -f'
// Удаляем все образы, если нужно
sh 'docker rmi builder_temp_contoller_firmware || true'
}
}
}
}

View File

@ -0,0 +1,458 @@
Appendix A Summary of guidelines
Rule 1.1 Required
The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementations translation limits
Rule 1.2 Advisory
Language extensions should not be used
Rule 1.3 Required
There shall be no occurrence of undefined or critical unspecified behaviour
Rule 2.1 Required
A project shall not contain unreachable code
Rule 2.2 Required
There shall be no dead code
Rule 2.3 Advisory
A project should not contain unused type declarations
Rule 2.4 Advisory
A project should not contain unused tag declarations
Rule 2.5 Advisory
A project should not contain unused macro declarations
Rule 2.6 Advisory
A function should not contain unused label declarations
Rule 2.7 Advisory
There should be no unused parameters in functions
Rule 3.1 Required
The character sequences /* and // shall not be used within a comment
Rule 3.2 Required
Line-splicing shall not be used in // comments
Rule 4.1 Required
Octal and hexadecimal escape sequences shall be terminated
Rule 4.2 Advisory
Trigraphs should not be used
Dir 4.3 Required
Assembly language shall be encapsulated and isolated
Dir 4.4 Advisory
Sections of code should not be “commented out”
Dir 4.5 Advisory
Identifiers in the same name space with overlapping visibility should be typographically unambiguous
Dir 4.6 Advisory
typedefs that indicate size and signedness should be used in place of the basic numerical types
Dir 4.7 Required
If a function returns error information, then that error information shall be tested
Dir 4.8 Advisory
If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden
Dir 4.9 Advisory
A function should be used in preference to a function-like macro where they are interchangeable
Dir 4.10 Required
Precautions shall be taken in order to prevent the contents of a header file being included more than once
Dir 4.11 Required
The validity of values passed to library functions shall be checked
Dir 4.12 Required
Dynamic memory allocation shall not be used
Dir 4.13 Advisory
Functions which are designed to provide operations on a resource should be called in an appropriate sequence
Rule 5.1 Required
External identifiers shall be distinct
Rule 5.2 Required
Identifiers declared in the same scope and name space shall be distinct
Rule 5.3 Required
An identifier declared in an inner scope shall not hide an identifier declared in an outer scope
Rule 5.4 Required
Macro identifiers shall be distinct
Rule 5.5 Required
Identifiers shall be distinct from macro names
Rule 5.6 Required
A typedef name shall be a unique identifier
Rule 5.7 Required
A tag name shall be a unique identifier
Rule 5.8 Required
Identifiers that define objects or functions with external linkage shall be unique
Rule 5.9 Advisory
Identifiers that define objects or functions with internal linkage should be unique
Rule 6.1 Required
Bit-fields shall only be declared with an appropriate type
Rule 6.2 Required
Single-bit named bit fields shall not be of a signed type
Rule 7.1 Required
Octal constants shall not be used
Rule 7.2 Required
A “u” or “U” suffix shall be applied to all integer constants that are represented in an unsigned type
Rule 7.3 Required
The lowercase character “l” shall not be used in a literal suffix
Rule 7.4 Required
A string literal shall not be assigned to an object unless the objects type is “pointer to const-qualified char”
Rule 8.1 Required
Types shall be explicitly specified
Rule 8.2 Required
Function types shall be in prototype form with named parameters
Rule 8.3 Required
All declarations of an object or function shall use the same names and type qualifiers
Rule 8.4 Required
A compatible declaration shall be visible when an object or function with external linkage is defined
Rule 8.5 Required
An external object or function shall be declared once in one and only one file
Rule 8.6 Required
An identifier with external linkage shall have exactly one external definition
Rule 8.7 Advisory
Functions and objects should not be defined with external linkage if they are referenced in only one translation unit
Rule 8.8 Required
The static storage class specifier shall be used in all declarations of objects and functions that have internal linkage
Rule 8.9 Advisory
An object should be defined at block scope if its identifier only appears in a single function
Rule 8.10 Required
An inline function shall be declared with the static storage class
Rule 8.11 Advisory
When an array with external linkage is declared, its size should be explicitly specified
Rule 8.13 Advisory
A pointer should point to a const-qualified type whenever possible
Rule 8.14 Required
The restrict type qualifier shall not be used
Rule 9.1 Mandatory
The value of an object with automatic storage duration shall not be read before it has been set
Rule 9.2 Required
The initializer for an aggregate or union shall be enclosed in braces
Rule 9.3 Required
Arrays shall not be partially initialized
Rule 9.4 Required
An element of an object shall not be initialized more than once
Rule 9.5 Required
Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly
Rule 10.1 Required
Operands shall not be of an inappropriate essential type
Rule 10.2 Required
Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations
Rule 10.3 Required
The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category
Rule 10.4 Required
Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category
Rule 10.5 Advisory
The value of an expression should not be cast to an inappropriate essential type
Rule 10.6 Required
The value of a composite expression shall not be assigned to an object with wider essential type
Rule 10.7 Required
If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type
Rule 10.8 Required
The value of a composite expression shall not be cast to a different essential type category or a wider essential type
Rule 11.1 Required
Conversions shall not be performed between a pointer to a function and any other type
Rule 11.2 Required
Conversions shall not be performed between a pointer to an incomplete type and any other type
Rule 11.3 Required
A cast shall not be performed between a pointer to object type and a pointer to a different object type
Rule 11.4 Advisory
A conversion should not be performed between a pointer to object and an integer type
Rule 11.5 Advisory
A conversion should not be performed from pointer to void into pointer to object
Rule 11.6 Required
A cast shall not be performed between pointer to void and an arithmetic type
Rule 11.7 Required
A cast shall not be performed between pointer to object and a noninteger arithmetic type
Rule 11.8 Required
A cast shall not remove any const or volatile qualification from the type pointed to by a pointer
Rule 11.9 Required
The macro NULL shall be the only permitted form of integer null pointer constant
Rule 12.1 Advisory
The precedence of operators within expressions should be made explicit
Rule 12.2 Required
The right hand operand of a shift operator shall lie in the range zero to one less than the width in bits of the essential type of the left hand operand
Rule 12.3 Advisory
The comma operator should not be used
Rule 12.4 Advisory
Evaluation of constant expressions should not lead to unsigned integer wrap-around
Rule 13.1 Required
Initializer lists shall not contain persistent side effects
Rule 13.2 Required
The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders
Rule 13.3 Advisory
A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator
Rule 13.4 Advisory
The result of an assignment operator should not be used
Rule 13.5 Required
The right hand operand of a logical && or || operator shall not contain persistent side effects
Rule 13.6 Mandatory
The operand of the sizeof operator shall not contain any expression which has potential side effects
Rule 14.1 Required
A loop counter shall not have essentially floating type
Rule 14.2 Required
A for loop shall be well-formed
Rule 14.3 Required
Controlling expressions shall not be invariant
Rule 14.4 Required
The controlling expression of an if statement and the controlling expression of an iteration-statement shall have essentially Boolean type
Rule 15.1 Advisory
The goto statement should not be used
Rule 15.2 Required
The goto statement shall jump to a label declared later in the same function
Rule 15.3 Required
Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement
Rule 15.4 Advisory
There should be no more than one break or goto statement used to terminate any iteration statement
Rule 15.5 Advisory
A function should have a single point of exit at the end
Rule 15.6 Required
The body of an iteration-statement or a selection-statement shall be a compound-statement
Rule 15.7 Required
All if … else if constructs shall be terminated with an else statement
Rule 16.1 Required
All switch statements shall be well-formed
Rule 16.2 Required
A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement
Rule 16.3 Required
An unconditional break statement shall terminate every switch-clause
Rule 16.4 Required
Every switch statement shall have a default label
Rule 16.5 Required
A default label shall appear as either the first or the last switch label of a switch statement
Rule 16.6 Required
Every switch statement shall have at least two switch-clauses
Rule 16.7 Required
A switch-expression shall not have essentially Boolean type
Rule 17.1 Required
The features of <stdarg.h> shall not be used
Rule 17.2 Required
Functions shall not call themselves, either directly or indirectly
Rule 17.3 Mandatory
A function shall not be declared implicitly
Rule 17.4 Mandatory
All exit paths from a function with non-void return type shall have an explicit return statement with an expression
Rule 17.5 Advisory
The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements
Rule 17.6 Mandatory
The declaration of an array parameter shall not contain the static keyword between the [ ]
Rule 17.7 Required
The value returned by a function having non-void return type shall be used
Rule 17.8 Advisory
A function parameter should not be modified
Rule 18.1 Required
A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand
Rule 18.2 Required
Subtraction between pointers shall only be applied to pointers that address elements of the same array
Rule 18.3 Required
The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object
Rule 18.4 Advisory
The +, -, += and -= operators should not be applied to an expression of pointer type
Rule 18.5 Advisory
Declarations should contain no more than two levels of pointer nesting
Rule 18.6 Required
The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist
Rule 18.7 Required
Flexible array members shall not be declared
Rule 18.8 Required
Variable-length array types shall not be used
Rule 19.1 Mandatory
An object shall not be assigned or copied to an overlapping object
Rule 19.2 Advisory
The union keyword should not be used
Rule 20.1 Advisory
#include directives should only be preceded by preprocessor directives or comments
Rule 20.2 Required
The ', " or \ characters and the /* or // character sequences shall not occur in a header file name
Rule 20.3 Required
The #include directive shall be followed by either a <filename> or "filename" sequence
Rule 20.4 Required
A macro shall not be defined with the same name as a keyword
Rule 20.5 Advisory
#undef should not be used
Rule 20.7 Required
Expressions resulting from the expansion of macro parameters shall be enclosed in parentheses
Rule 20.8 Required
The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1
Rule 20.9 Required
All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be #defined before evaluation
Rule 20.10 Advisory
The # and ## preprocessor operators should not be used
Rule 20.11 Required
A macro parameter immediately following a # operator shall not immediately be followed by a ## operator
Rule 20.12 Required
A macro parameter used as an operand to the # or ## operators, which is itself subject to further macro replacement, shall only be used as an operand to these operators
Rule 20.13 Required
A line whose first token is # shall be a valid preprocessing directive
Rule 20.14 Required
All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if, #ifdef or #ifndef directive to which they are related
Rule 21.1 Required
#define and #undef shall not be used on a reserved identifier or reserved macro name
Rule 21.2 Required
A reserved identifier or macro name shall not be declared
Rule 21.3 Required
The memory allocation and deallocation functions of <stdlib.h> shall not be used
Rule 21.4 Required
The standard header file <setjmp.h> shall not be used
Rule 21.5 Required
The standard header file <signal.h> shall not be used
Rule 21.6 Required
The Standard Library input/output functions shall not be used
Rule 21.7 Required
The atof, atoi, atol and atoll functions of <stdlib.h> shall not be used
Rule 21.8 Required
The library functions abort, exit, getenv and system of <stdlib.h> shall not be used
Rule 21.9 Required
The library functions bsearch and qsort of <stdlib.h> shall not be used
Rule 21.10 Required
The Standard Library time and date functions shall not be used
Rule 21.11 Required
The standard header file <tgmath.h> shall not be used
Rule 21.12 Advisory
The exception handling features of <fenv.h> should not be used
Rule 22.1 Required
All resources obtained dynamically by means of Standard Library functions shall be explicitly released
Rule 22.2 Mandatory
A block of memory shall only be freed if it was allocated by means of a Standard Library function
Rule 22.3 Required
The same file shall not be open for read and write access at the same time on different streams
Rule 22.4 Mandatory
There shall be no attempt to write to a stream which has been opened as read-only
Rule 22.5 Mandatory
A pointer to a FILE object shall not be dereferenced
Rule 22.6 Mandatory
The value of a pointer to a FILE shall not be used after the associated stream has been closed

View File

@ -0,0 +1,6 @@
{
"script": "misra.py",
"args": [
"--rule-texts ./tools/cppcheck_conf/misra_rules.txt"
]
}

View File

@ -0,0 +1,17 @@
<?xml version="1"?>
<platform>
<char_bit>8</char_bit>
<default-sign>signed</default-sign>
<sizeof>
<short>2</short>
<int>4</int>
<long>4</long>
<long-long>8</long-long>
<float>4</float>
<double>8</double>
<long-double>8</long-double>
<pointer>4</pointer>
<size_t>4</size_t>
<wchar_t>2</wchar_t>
</sizeof>
</platform>

View File

@ -0,0 +1,5 @@
missingIncludeSystem:src/lib/xprintf.c
missingIncludeSystem:src/lib/xprintf.h
missingIncludeSystem:src/core/core_cm0plus.h
missingIncludeSystem:src/core/cmsis_compiler.h
missingInclude:src/core/stm32g0xx.h

10
tools/dockerfile Normal file
View File

@ -0,0 +1,10 @@
# Используем базовый образ Debian
FROM builder
# Копируем ваш проект в контейнер
WORKDIR /app
COPY . /app
# Запускаем Bash, чтобы контейнер оставался активным
CMD ["/bin/bash", "-c", "source ~/.bashrc"]
CMD ["bash", "-c", "while true; do sleep 1000; done"]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
# \file Makefile
# \brief Description of the STM32G030F6P6 project build process
SHELL=/bin/bash
include $(DIR_MK)/settings.mk
OBJS_C = $(addprefix $(MC_FIRMWARE_OUTPATH_OBJS),$(notdir $(MC_FIRMWARE_SOURCES_C:.c=.o) ))
OBJS_S = $(addprefix $(MC_FIRMWARE_OUTPATH_OBJS),$(notdir $(MC_FIRMWARE_SOURCES_S:.s=.o) ))
OBJS += $(OBJS_S) $(OBJS_C)
vpath %.c $(sort $(dir $(MC_FIRMWARE_SOURCES_C)))
vpath %.s $(sort $(dir $(MC_FIRMWARE_SOURCES_S)))
.PHONY: all dirs clean help doc check
all: dirs $(MC_FIRMWARE).elf $(MC_FIRMWARE).asm $(MC_FIRMWARE).bin
$(ARM_SIZE) -G $(MC_FIRMWARE).elf
ls -lh $(MC_FIRMWARE_OUTPATH)*.bin
@echo -e "\n \e[32msuccess\e[0m\n"
%.bin: %.elf
$(ARM_OBJCOPY) -O binary $< $@
%.elf: $(OBJS)
$(ARM_LD) $(OBJS) $(LDFLAGS) -o $@
#проерям только файлы входящие в $(CHECK_SOURCES_C)
${MC_FIRMWARE_OUTPATH_OBJS}%.o: %.c
$(ARM_CC) $(CFLAGS) -c -o $@ $<
@if [ ! -z "$(CHECKING_DURING_COMPILATION)" ]; then \
if echo "$(CHECK_SOURCES_C)" | grep -q "$<"; then \
$(STATIC_ANALYSIS) $(STATIC_ANALYSIS_FLAGS) $<; \
fi \
fi
${MC_FIRMWARE_OUTPATH_OBJS}%.o: %.s
$(ARM_CC) $(CFLAGS) -c -o $@ $<
%.asm: %.elf
$(ARM_OBJDUMP) -dwh $< > $@
check: dirs $(SOURCES_C)
$(STATIC_ANALYSIS) $(STATIC_ANALYSIS_FLAGS) $(CHECK_SOURCES_C)
doc: dirs
sed -i '45s#.*#PROJECT_NAME = "$(MC_FIRMWARE)"#' $(DOCUMENTATION_GENERATOR_CONF_FILE)
sed -i '71s#.*#OUTPUT_DIRECTORY = ./$(OUTPATH_DOCUMENTATION)#' $(DOCUMENTATION_GENERATOR_CONF_FILE)
sed -i '946s#.*#INPUT = $(DOCUMENTATION_FILE)#' $(DOCUMENTATION_GENERATOR_CONF_FILE)
$(DOCUMENTATION_GENERATOR) $(DOCUMENTATION_GENERATOR_CONF_FILE)
dirs:
mkdir -p ${MC_FIRMWARE_OUTPATH_OBJS}
mkdir -p $(STATIC_ANALYSIS_BUILD_DIR)
mkdir -p ${OUTPATH_DOCUMENTATION}

115
tools/makefiles/settings.mk Normal file
View File

@ -0,0 +1,115 @@
######
# Файл со всеми переменными.
# Тут задаются из каких папок, какие файлы доставать и с аими флагами омпилировать
######
SHELL=/bin/bash
PROJECT_NAME = temp_contoller
MAIN_OUTPATH = build/
MC_FIRMWARE_OUTPATH = $(MAIN_OUTPATH)mc_firmware/
MC_FIRMWARE_OUTPATH_OBJS = $(MC_FIRMWARE_OUTPATH)obj/
MC_UTESTS_OUTPATH = $(MAIN_OUTPATH)utests/
MC_UTESTS_OUTPATH_OBJS = $(MC_UTESTS_OUTPATH)obj # палочку не ставить
MC_UTESTS_OUTPATH_LIB = $(MC_UTESTS_OUTPATH)lib
OUTPATH_DOCUMENTATION = $(MC_FIRMWARE_OUTPATH)documentation/
MC_FIRMWARE = $(MC_FIRMWARE_OUTPATH)$(PROJECT_NAME)_mc_firmware
MC_UTESTS = $(MC_UTESTS_OUTPATH)$(PROJECT_NAME)_utests
MC_FIRMWARE_PATH_SRC = src/
MC_FIRMWARE_PATH_SRC_CORE = $(MC_FIRMWARE_PATH_SRC)core/
MC_FIRMWARE_PATH_SRC_PLIB = $(MC_FIRMWARE_PATH_SRC)plib/
MC_FIRMWARE_PATH_SRC_LIB = $(MC_FIRMWARE_PATH_SRC)lib/
MC_UTESTS_PATH_SRC = src_tests/
MC_UTESTS_PATHS_SRC = $(MC_UTESTS_PATH_SRC)mock_file
MC_UTESTS_PATHS_SRC += $(MC_FIRMWARE_PATH_SRC)lib
MC_UTESTS_PATHS_TEST_SRC = src_tests
MC_UTESTS_PATHS_TEST_SRC += $(MC_UTESTS_PATH_SRC)tests
MC_FIRMWARE_SOURCES_S = src/core/startup_stm32g030f6px.s
MC_FIRMWARE_SOURCES_SRC = $(wildcard $(MC_FIRMWARE_PATH_SRC)*.c)
MC_FIRMWARE_SOURCES_CORE = $(wildcard $(MC_FIRMWARE_PATH_SRC_CORE)*.c)
MC_FIRMWARE_SOURCES_PERIPH = $(wildcard $(MC_FIRMWARE_PATH_SRC_PLIB)*.c)
MC_FIRMWARE_SOURCES_LIB = $(wildcard $(MC_FIRMWARE_PATH_SRC_LIB)*.c)
MC_FIRMWARE_SOURCES_C += $(MC_FIRMWARE_SOURCES_SRC)
MC_FIRMWARE_SOURCES_C += $(MC_FIRMWARE_SOURCES_CORE)
MC_FIRMWARE_SOURCES_C += $(MC_FIRMWARE_SOURCES_PERIPH)
MC_FIRMWARE_SOURCES_C += $(MC_FIRMWARE_SOURCES_LIB)
MC_FIRMWARE_SOURCES = $(MC_FIRMWARE_SOURCES_S) $(MC_FIRMWARE_SOURCES_C)
MC_FIRMWARE_INC_CORE = -I$(MC_FIRMWARE_PATH_SRC_CORE)
MC_FIRMWARE_INC_LIB = -I$(MC_FIRMWARE_PATH_SRC_LIB)
MC_FIRMWARE_INC_PERIPH = -I$(MC_FIRMWARE_PATH_SRC_PLIB)
MC_FIRMWARE_INCLUDES += $(MC_FIRMWARE_INC_CORE)
MC_FIRMWARE_INCLUDES += $(MC_FIRMWARE_INC_LIB)
MC_FIRMWARE_INCLUDES += $(MC_FIRMWARE_INC_PERIPH)
MC_UTESTS_PATHS_INCLUDES = $(CPPUTEST_HOME)/include/
MC_UTESTS_PATHS_INCLUDES += $(MC_FIRMWARE_PATH_SRC_LIB)
MC_UTESTS_PATHS_INCLUDES += $(MC_FIRMWARE_PATH_SRC_PLIB)
MC_UTESTS_PATHS_INCLUDES += $(MC_UTESTS_PATH_SRC)mock_file/
ARM_CC_PREFIX = arm-none-eabi
ARM_CC = $(ARM_CC_PREFIX)-gcc
ARM_CXX = $(ARM_CC_PREFIX)-g++
ARM_LD = $(ARM_CC_PREFIX)-gcc
ARM_SIZE= $(ARM_CC_PREFIX)-size
ARM_OBJCOPY= $(ARM_CC_PREFIX)-objcopy
ARM_OBJDUMP = $(ARM_CC_PREFIX)-objdump
C_STANDART = 11 # мы используем си, но тесты комилируются под с++, поэтому тут задаём просто цифры а далее подсталяется либо c11 либо c++11
HEAP_SIZE = 0x400
DEFINES = -DSTM32 -DSTM32G0 -DSTM32G030xx -DHEAP_SIZE=$(HEAP_SIZE) -DDEBUG
MCUFLAGS = -mcpu=cortex-m0plus -mlittle-endian -mfloat-abi=soft -mthumb \
-mno-unaligned-access
DEBUG_OPTIMIZE_FLAGS = -O0 -ggdb -gdwarf-2
CFLAGS = -Wall -Wextra --pedantic #--std=c$(C_STANDART)
CFLAGS_EXTRA = -nostartfiles -nodefaultlibs -nostdlib \
-fdata-sections -ffunction-sections
CFLAGS += $(DEFINES) $(MCUFLAGS) $(DEBUG_OPTIMIZE_FLAGS) $(CFLAGS_EXTRA) $(MC_FIRMWARE_INCLUDES)
LDFLAGS =-static -Wl,--start-group -Wl,--end-group \
-Wl,--gc-sections -T src/core/STM32G030F6PX_FLASH.ld $(CFLAGS_EXTRA) $(MCUFLAGS) #-lgcc -lc -lg
ELF = $(MC_FIRMWARE).elf
BIN = $(MC_FIRMWARE).bin
OFFSET = 0x08000000
OPEN_OCD_PROGRAMMER_CFG = /usr/local/share/openocd/scripts/interface/stlink.cfg
OPEN_OCD_MK_CFG = /usr/local/share/openocd/scripts/target/stm32g0x.cfg
CHECK_SOURCES_C += $(MC_FIRMWARE_SOURCES_SRC)
CHECK_SOURCES_C += $(MC_FIRMWARE_SOURCES_PERIPH)
#CHECK_SOURCES_C += $(MC_FIRMWARE_SOURCES_LIB)
CHECK_SOURCES_C += src/lib/modbus_regs_file.c
STATIC_ANALYSIS =cppcheck
STATIC_ANALYSIS_BUILD_DIR =$(MC_FIRMWARE_OUTPATH)$(STATIC_ANALYSIS)
STATIC_ANALYSIS_SUPPRESSIONS =tools/cppcheck_conf/suppressions.txt
STATIC_ANALYSIS_ADDON = ./tools/cppcheck_conf/my_misra.json
#STATIC_ANALYSIS_FLAGS += --enable=all --std=$(C_STANDART) --cppcheck-build-dir=$(STATIC_ANALYSIS_BUILD_DIR)
#STATIC_ANALYSIS_FLAGS += --check-config --force --inconclusive $(INCLUDES)
STATIC_ANALYSIS_FLAGS += --suppressions-list=$(STATIC_ANALYSIS_SUPPRESSIONS)
STATIC_ANALYSIS_FLAGS += --addon=$(STATIC_ANALYSIS_ADDON) --template=gcc
STATIC_ANALYSIS_FLAGS += --platform=./tools/cppcheck_conf/platfom_cm0plus
DOCUMENTATION_GENERATOR = doxygen
DOCUMENTATION_GENERATOR_CONF_FILE = ./tools/doxygen_conf/doxygen_config
DOCUMENTATION_FILE = $(wildcard ./*)
DOCUMENTATION_FILE += $(MC_FIRMWARE_PATH_SRC)
DOCUMENTATION_FILE += $(MC_FIRMWARE_PATH_SRC_PLIB)
DOCUMENTATION_FILE += $(MC_FIRMWARE_PATH_SRC_LIB)

49
tools/makefiles/utests.mk Normal file
View File

@ -0,0 +1,49 @@
SHELL=/bin/bash
# Проверяем, задана ли переменная CPPTEST
# Поместить export CPPUTEST="/home/developer/Programs/cpputest в .bashrc"
ifeq ($(strip $(CPPUTEST)),)
$(error Переменная CPPTEST не задана)
endif
CPPUTEST_HOME = $(CPPUTEST)
include $(DIR_MK)/settings.mk
## CppUTest configurations ##
COMPONENT_NAME = ./build/utest_s/test-template
# COMPONENT_NAME = ./$(MC_UTESTS)
CPPUTEST_ENABLE_DEBUG = Y
CPPUTEST_USE_EXTENSIONS = Y
CPP_PLATFORM = Gcc
CPPUTEST_USE_GCOV = Y
CPPUTEST_OBJS_DIR = build/utest_s/obj
CPPUTEST_LIB_DIR = build/utest_s/lib
# CPPUTEST_OBJS_DIR = $(MC_UTESTS_OUTPATH_OBJS)
# CPPUTEST_LIB_DIR = $(MC_UTESTS_OUTPATH_LIB)
SRC_DIRS = $(MC_UTESTS_PATHS_SRC)
TEST_SRC_DIRS = $(MC_UTESTS_PATHS_TEST_SRC)
INCLUDE_TEST_DIRS = $(MC_UTESTS_PATHS_INCLUDES)
INCLUDE_DIRS = $(INCLUDE_TEST_DIRS)
CPPUTEST_CPPFLAGS = -DDISABLE_LOG -DUTEST_BUILD -DSTM32G030xx
CPPUTEST_CXXFLAGS = -std=c++$(C_STANDART) -O0
CPPUTEST_LDFLAGS = -pthread
CPPUTEST_WARNINGFLAGS = -Wall -Wextra -Wshadow -Wswitch-default -Wswitch-enum -Wconversion -Wno-long-long
## The real work ##
# including this file that will use configuration and have the make rules.
include $(CPPUTEST_HOME)/build/MakefileWorker.mk

25
tools/tools_list.txt Normal file
View File

@ -0,0 +1,25 @@
gcc-arm-none-eabi https://developer.arm.com/downloads/-/gnu-rm
arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release)
make https://www.gnu.org/software/make/#download
GNU Make 4.4.1
st-utils https://github.com/stlink-org/stlink
v1.7.0
openocd https://openocd.org
Open On-Chip Debugger 0.12.0+dev-00359-gc7d1f0dda (2023-10-21-08:41)
doxygen https://github.com/doxygen/doxygen.git
1.9.8 (cf818b6b68f247b40bafa74cdff15db3ee283c1e)
graphviz https://graphviz.org/download/source/
dot - graphviz version 8.0.5 (20230430.1635)
cppcheck http://cppcheck.net/#download
Cppcheck 2.10