Feature/add memap cstack usage ports (#661)

* Added memap, avstack, and checkstackusage tools to STM32F4xx Makefile and CMake builds to calculate CSTACK depth and RAM usage

* Added memap, cstack, and ram-usage recipes to stm32f10x port Makefile.  Added Cmake build.

* Removed local dlmstp.c module from stm32f10x port, and used the common datalink dlmstp.c module with MS/TP extended frames and zero-config support.

* Added .nm and .su to .gitignore to skip the analysis file residue.
This commit is contained in:
Steve Karg
2024-05-31 14:39:25 -05:00
committed by GitHub
parent cf7eb7d98d
commit 4a7b7763c2
32 changed files with 3855 additions and 1974 deletions
+311
View File
@@ -0,0 +1,311 @@
# This is a CMake example for STM32 ARM Cortex-M3 STM32F103RGT6 on
# a STM32 Discovery Kit evaluation board using the ARM GCC compiler
# and STM32 CMSIS library.
#
# Board STM32F103 Discovery Kit
# MCU STM32F103RGT6
# CPU Cortex-M3
# RAM 96KB
# Flash 1024KB
#
# To build this project you need to install:
# - ARM GCC compiler
# - CMake
#
# To build this project you need to run:
# - cmake -S . -B build
# - cmake --build build
#
# To flash this project you need to run:
# - st-flash write build/bacnet-mstp.hex 0x8000000
#
# To debug this project you need to run:
# - arm-none-eabi-gdb -q build/bacnet-mstp.out
# - (gdb) target extended-remote localhost:3333
# - (gdb) monitor reset halt
# - (gdb) load
# - (gdb) monitor reset halt
# - (gdb) monitor reset init
# - (gdb) monitor reset run
# - (gdb) monitor reset exit
# - (gdb) quit
#
# You can also use VSCode with Cortex-Debug extension
#
# This example was tested with:
# - ARM GCC 10.3.1
# - CMake 3.22.1
# - stm32f10x_StdPeriph_Driver V1.0.0
# - BACnet Stack V1.3.2
#
cmake_minimum_required(VERSION 3.20)
# Cross compilers and tools
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(CMAKE_SIZE arm-none-eabi-size)
set(CMAKE_NM arm-none-eabi-nm)
set(CMAKE_CSTACK "${CMAKE_SOURCE_DIR}/../../tools/check-stack-usage/checkStackUsage.py")
set(CMAKE_MEMAP "${CMAKE_SOURCE_DIR}/../../tools/memap/memap.py")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(EXECUTABLE ${PROJECT_NAME}.elf)
project(bacnet-mstp)
enable_language(C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
# Specific ARM microcontroller compiler and linker settings
add_compile_options(-mcpu=cortex-m3)
add_compile_options(-mthumb -mno-thumb-interwork -mabi=aapcs)
add_link_options(-mcpu=cortex-m3)
add_link_options(-mthumb -mno-thumb-interwork -mabi=aapcs)
# Compiler and linker settings for garbage collection and memory usage
add_compile_options(-ffunction-sections -fdata-sections)
add_compile_options(-fno-common -fmessage-length=0)
add_compile_options(-fstack-usage -fdump-rtl-dfinish)
add_link_options(-Wl,-gc-sections,--print-memory-usage)
# Build types
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
message(STATUS "Maximum optimization for speed")
add_compile_options(-Ofast)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
message(STATUS "Maximum optimization for speed, debug info included")
add_compile_options(-Ofast -g)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
message(STATUS "Maximum optimization for size")
add_compile_options(-Os)
else ()
message(STATUS "Minimal optimization, debug info included")
add_compile_definitions(DEBUG)
add_compile_options(-Og -g3)
endif ()
# eliminate the deprecated function warnings
option(BACNET_STACK_DEPRECATED_DISABLE "Disable deprecation compile warnings" ON)
if(BACNET_STACK_DEPRECATED_DISABLE)
add_definitions(-DBACNET_STACK_DEPRECATED_DISABLE)
endif()
set(LIBRARY_BACNET_INC "${CMAKE_SOURCE_DIR}/../../src")
set(LIBRARY_BACNET_CORE "${CMAKE_SOURCE_DIR}/../../src/bacnet")
set(LIBRARY_BACNET_BASIC "${CMAKE_SOURCE_DIR}/../../src/bacnet/basic")
set(LIBRARY_STM32_SRC "${CMAKE_SOURCE_DIR}/drivers/src")
set(LIBRARY_STM32_INC "${CMAKE_SOURCE_DIR}/drivers/inc")
set(LIBRARY_CMSIS_INC "${CMAKE_SOURCE_DIR}/CMSIS")
set(LIBRARY_CMSIS_GCC_INC "${CMAKE_SOURCE_DIR}/CMSIS/gcc_ride7")
set(BACNET_PROJECT_SOURCE
${LIBRARY_STM32_SRC}/stm32f10x_adc.c
${LIBRARY_STM32_SRC}/stm32f10x_bkp.c
${LIBRARY_STM32_SRC}/stm32f10x_can.c
${LIBRARY_STM32_SRC}/stm32f10x_cec.c
${LIBRARY_STM32_SRC}/stm32f10x_crc.c
${LIBRARY_STM32_SRC}/stm32f10x_dac.c
${LIBRARY_STM32_SRC}/stm32f10x_dbgmcu.c
${LIBRARY_STM32_SRC}/stm32f10x_dma.c
${LIBRARY_STM32_SRC}/stm32f10x_exti.c
${LIBRARY_STM32_SRC}/stm32f10x_flash.c
${LIBRARY_STM32_SRC}/stm32f10x_fsmc.c
${LIBRARY_STM32_SRC}/stm32f10x_gpio.c
${LIBRARY_STM32_SRC}/stm32f10x_i2c.c
${LIBRARY_STM32_SRC}/stm32f10x_iwdg.c
${LIBRARY_STM32_SRC}/stm32f10x_misc.c
${LIBRARY_STM32_SRC}/stm32f10x_pwr.c
${LIBRARY_STM32_SRC}/stm32f10x_rcc.c
${LIBRARY_STM32_SRC}/stm32f10x_rtc.c
${LIBRARY_STM32_SRC}/stm32f10x_sdio.c
${LIBRARY_STM32_SRC}/stm32f10x_spi.c
${LIBRARY_STM32_SRC}/stm32f10x_tim.c
${LIBRARY_STM32_SRC}/stm32f10x_usart.c
${LIBRARY_STM32_SRC}/stm32f10x_wwdg.c
${LIBRARY_STM32_SRC}/syscalls.c
${CMAKE_SOURCE_DIR}/stm32f10x_conf.h
# main entry and STM32 hardware setup
${CMAKE_SOURCE_DIR}/main.c
${CMAKE_SOURCE_DIR}/stm32f10x_it.c
${CMAKE_SOURCE_DIR}/stm32f10x_it.h
${CMAKE_SOURCE_DIR}/system_stm32f10x.c
# BACnet specific hardware abstraction, configuration and tasks
${CMAKE_SOURCE_DIR}/bacnet.c
${CMAKE_SOURCE_DIR}/led.c
${CMAKE_SOURCE_DIR}/mstimer-init.c
${CMAKE_SOURCE_DIR}/rs485.c
# BACnet objects in this device
${CMAKE_SOURCE_DIR}/device.c
${CMAKE_SOURCE_DIR}/netport.c
${CMAKE_SOURCE_DIR}/bo.c
# BACnet services library
${LIBRARY_BACNET_BASIC}/service/h_dcc.c
${LIBRARY_BACNET_BASIC}/service/h_apdu.c
${LIBRARY_BACNET_BASIC}/npdu/h_npdu.c
${LIBRARY_BACNET_BASIC}/service/h_rd.c
${LIBRARY_BACNET_BASIC}/service/h_rp.c
${LIBRARY_BACNET_BASIC}/service/h_rpm.c
${LIBRARY_BACNET_BASIC}/service/h_whohas.c
${LIBRARY_BACNET_BASIC}/service/h_whois.c
${LIBRARY_BACNET_BASIC}/service/h_wp.c
${LIBRARY_BACNET_BASIC}/service/h_noserv.c
${LIBRARY_BACNET_BASIC}/service/s_iam.c
${LIBRARY_BACNET_BASIC}/service/s_ihave.c
${LIBRARY_BACNET_BASIC}/tsm/tsm.c
${LIBRARY_BACNET_BASIC}/sys/debug.c
${LIBRARY_BACNET_BASIC}/sys/ringbuf.c
${LIBRARY_BACNET_BASIC}/sys/fifo.c
${LIBRARY_BACNET_BASIC}/sys/mstimer.c
# BACnet core library
${LIBRARY_BACNET_CORE}/abort.c
${LIBRARY_BACNET_CORE}/bacaddr.c
${LIBRARY_BACNET_CORE}/bacapp.c
${LIBRARY_BACNET_CORE}/bacdcode.c
${LIBRARY_BACNET_CORE}/bacdest.c
${LIBRARY_BACNET_CORE}/bacdevobjpropref.c
${LIBRARY_BACNET_CORE}/bacerror.c
${LIBRARY_BACNET_CORE}/bacint.c
${LIBRARY_BACNET_CORE}/bacreal.c
${LIBRARY_BACNET_CORE}/bacstr.c
${LIBRARY_BACNET_CORE}/datalink/cobs.c
${LIBRARY_BACNET_CORE}/datalink/crc.c
${LIBRARY_BACNET_CORE}/datalink/dlmstp.c
${LIBRARY_BACNET_CORE}/datalink/mstp.c
${LIBRARY_BACNET_CORE}/datalink/mstptext.c
${LIBRARY_BACNET_CORE}/datetime.c
${LIBRARY_BACNET_CORE}/dcc.c
${LIBRARY_BACNET_CORE}/indtext.c
${LIBRARY_BACNET_CORE}/iam.c
${LIBRARY_BACNET_CORE}/ihave.c
${LIBRARY_BACNET_CORE}/hostnport.c
${LIBRARY_BACNET_CORE}/lighting.c
${LIBRARY_BACNET_CORE}/memcopy.c
${LIBRARY_BACNET_CORE}/npdu.c
${LIBRARY_BACNET_CORE}/proplist.c
${LIBRARY_BACNET_CORE}/rd.c
${LIBRARY_BACNET_CORE}/reject.c
${LIBRARY_BACNET_CORE}/rp.c
${LIBRARY_BACNET_CORE}/rpm.c
${LIBRARY_BACNET_CORE}/timestamp.c
${LIBRARY_BACNET_CORE}/weeklyschedule.c
${LIBRARY_BACNET_CORE}/dailyschedule.c
${LIBRARY_BACNET_CORE}/calendar_entry.c
${LIBRARY_BACNET_CORE}/special_event.c
${LIBRARY_BACNET_CORE}/bactimevalue.c
${LIBRARY_BACNET_CORE}/whohas.c
${LIBRARY_BACNET_CORE}/whois.c
${LIBRARY_BACNET_CORE}/wp.c
${LIBRARY_CMSIS_GCC_INC}/startup_stm32f10x_xl.s
CMSIS/stm32f10x.h
)
set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/stm32f10x.ld)
set(EXECUTABLE ${PROJECT_NAME}.elf)
add_executable(${EXECUTABLE} ${BACNET_PROJECT_SOURCE})
target_compile_definitions(${EXECUTABLE} PRIVATE
-DNDEBUG
# STM32 CMSIS library
-DUSE_STDPERIPH_DRIVER
-DSTM32F10X_CL
-DHSE_VALUE=25000000
# BACnet Stack library
-DBACDL_MSTP
-DMAX_APDU=1476
-DBIG_ENDIAN=0
-DMAX_TSM_TRANSACTIONS=0
-DBACAPP_MINIMAL
-DMAX_CHARACTER_STRING_BYTES=64
-DMAX_OCTET_STRING_BYTES=64
)
# inhibit pedantic warnings
target_compile_options(${EXECUTABLE} PRIVATE
-Wall -Wextra -pedantic
-Wfloat-equal -Wconversion -Wredundant-decls
-Wswitch-default
# don't warn about conversion, sign, compares, long long and attributes
# since they are common in embedded
-Wno-sign-conversion
-Wno-conversion
-Wno-sign-compare
-Wno-long-long
-Wno-attributes
# don't warn about implicit fallthrough since it is common in network protocols
-Wno-implicit-fallthrough
# the SDK does not meet coding guidelines
-Wno-comment
-Wno-missing-braces
-Wno-unused-variable
# reference the linker file for CSTACK size
-Wstack-usage=16384
-Wno-unused-parameter
-Wno-char-subscripts
)
target_include_directories(${EXECUTABLE} PRIVATE
${CMAKE_SOURCE_DIR}
${LIBRARY_CMSIS_INC}
${LIBRARY_CMSIS_GCC_INC}
${LIBRARY_STM32_INC}
${LIBRARY_BACNET_INC}
)
target_link_options(${EXECUTABLE} PRIVATE
-T${LINKER_SCRIPT}
-specs=nano.specs
-lm
-lnosys
-Wl,-Map=${PROJECT_NAME}.map,--cref
-Wl,--gc-sections
)
# Create hex and bin files
add_custom_command(TARGET ${EXECUTABLE}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE} ${PROJECT_NAME}.hex
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE} ${PROJECT_NAME}.bin
)
# Print executable size
add_custom_command(TARGET ${EXECUTABLE}
POST_BUILD
COMMAND ${CMAKE_SIZE} ${EXECUTABLE}
)
# sort the RAM usage by size and place into a file
add_custom_target(symbols
DEPENDS ${EXECUTABLE}
COMMENT "Print memory symbols by size"
COMMAND ${CMAKE_NM} -t d -S --size-sort ${EXECUTABLE} 1> ${PROJECT_NAME}.nm
COMMAND echo "RAM usage by size analysis in ${PROJECT_NAME}.nm"
COMMAND echo "=ADDRESS= ==RAM=== = ==VARIABLE-NAME=="
COMMAND tail ${PROJECT_NAME}.nm
)
# calculate the worst case CSTACK memory usage by size and place into a file
add_custom_target(cstack
DEPENDS ${EXECUTABLE}
COMMENT "Print CSTACK memory depth by size"
COMMAND ${CMAKE_CSTACK} ${EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR} 1> ${PROJECT_NAME}.su
COMMAND echo "C-Stack maxium depth analysis in ${PROJECT_NAME}.su"
COMMAND echo "==DEPTH== : == Functions called =="
COMMAND tail ${PROJECT_NAME}.su
)
# Print file and library sizes
add_custom_target(memmap
DEPENDS ${PROJECT_NAME}.map
COMMENT "Print file and library memory usage by size"
COMMAND ${CMAKE_MEMAP} -t GCC_ARM ${PROJECT_NAME}.map
)
+41 -22
View File
@@ -13,6 +13,9 @@ LIBRARY_STM32 = ./drivers/src
LIBRARY_STM32_INCLUDES = ./drivers/inc
LIBRARY_CMSIS = ./CMSIS
CSTACK_TOOL := $(BACNET_DIR)/tools/avstack/avstack.pl
MEMAP_TOOL := $(BACNET_DIR)/tools/memap/memap.py
INCLUDES = -I$(PLATFORM_DIR)
INCLUDES += -I$(LIBRARY_STM32_INCLUDES)
INCLUDES += -I$(LIBRARY_CMSIS)
@@ -23,7 +26,6 @@ PLATFORM_SRC = \
$(PLATFORM_DIR)/bacnet.c \
$(PLATFORM_DIR)/bo.c \
$(PLATFORM_DIR)/device.c \
$(PLATFORM_DIR)/dlmstp.c \
$(PLATFORM_DIR)/netport.c \
$(PLATFORM_DIR)/led.c \
$(PLATFORM_DIR)/rs485.c \
@@ -61,13 +63,15 @@ BACNET_SRC = \
$(BACNET_CORE)/bacint.c \
$(BACNET_CORE)/bacreal.c \
$(BACNET_CORE)/bacstr.c \
$(BACNET_CORE)/datalink/automac.c \
$(BACNET_CORE)/datalink/crc.c \
$(BACNET_CORE)/bactimevalue.c \
$(BACNET_CORE)/calendar_entry.c \
$(BACNET_CORE)/datetime.c \
$(BACNET_CORE)/dailyschedule.c \
$(BACNET_CORE)/dcc.c \
$(BACNET_CORE)/hostnport.c \
$(BACNET_CORE)/iam.c \
$(BACNET_CORE)/ihave.c \
$(BACNET_CORE)/hostnport.c \
$(BACNET_CORE)/indtext.c \
$(BACNET_CORE)/lighting.c \
$(BACNET_CORE)/memcopy.c \
$(BACNET_CORE)/npdu.c \
@@ -76,16 +80,20 @@ BACNET_SRC = \
$(BACNET_CORE)/reject.c \
$(BACNET_CORE)/rp.c \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/special_event.c \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/weeklyschedule.c \
$(BACNET_CORE)/dailyschedule.c \
$(BACNET_CORE)/bactimevalue.c \
$(BACNET_CORE)/calendar_entry.c \
$(BACNET_CORE)/special_event.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
$(BACNET_CORE)/wp.c
DATALINK_SRC = \
$(BACNET_CORE)/datalink/cobs.c \
$(BACNET_CORE)/datalink/crc.c \
$(BACNET_CORE)/datalink/dlmstp.c \
$(BACNET_CORE)/datalink/mstp.c \
$(BACNET_CORE)/datalink/mstptext.c
STM32_SRC = \
$(LIBRARY_STM32)/stm32f10x_adc.c \
$(LIBRARY_STM32)/stm32f10x_bkp.c \
@@ -115,17 +123,20 @@ STM32_SRC = \
CSRC = $(PLATFORM_SRC)
CSRC += $(BASIC_SRC)
CSRC += $(BACNET_SRC)
CSRC += $(DATALINK_SRC)
CSRC += $(STM32_SRC)
ASRC = $(LIBRARY_CMSIS)/gcc_ride7/startup_stm32f10x_xl.s
#Set the toolchain command names (only the ones needed are defined)
# sudo apt install gcc-arm-none-eabi
PREFIX ?= arm-none-eabi-
CC = $(PREFIX)gcc
OBJCOPY = $(PREFIX)objcopy
OBJDUMP = $(PREFIX)objdump
AR = $(PREFIX)ar
NM = $(PREFIX)nm
SIZE = $(PREFIX)size
LDSCRIPT = $(PLATFORM_DIR)/stm32f10x.ld
@@ -142,7 +153,7 @@ OPTIMIZE_FLAGS += -DNDEBUG
BACNET_FLAGS = -DBACDL_MSTP=1
BACNET_FLAGS += -DBACAPP_MINIMAL
BACNET_FLAGS += -DMAX_APDU=480
BACNET_FLAGS += -DMAX_APDU=1476
BACNET_FLAGS += -DBIG_ENDIAN=0
BACNET_FLAGS += -DMAX_TSM_TRANSACTIONS=0
BACNET_FLAGS += -DMAX_CHARACTER_STRING_BYTES=64
@@ -161,6 +172,8 @@ CFLAGS += $(BACNET_FLAGS)
CFLAGS += $(INCLUDES)
# enable garbage collection of unused functions and data to shrink binary
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
# enable stack usage tracking
CFLAGS += -fstack-usage
# function calls will not use any special __builtin_xx to allow debug/linking
CFLAGS += -fno-builtin
# place uninitialized global variables in the data section of the object file.
@@ -199,6 +212,7 @@ ODFLAGS = -x --syms
AOBJ = $(ASRC:.s=.o)
COBJ = $(CSRC:.c=.o)
CSTACK = $(CSRC:.c=.su)
all: $(TARGET).bin $(TARGET).elf
$(OBJDUMP) $(ODFLAGS) $(TARGET).elf > $(TARGET).dmp
@@ -210,18 +224,22 @@ $(TARGET).bin: $(TARGET).elf
$(TARGET).elf: $(COBJ) $(AOBJ) Makefile
$(CC) $(CFLAGS) $(AOBJ) $(COBJ) $(LDFLAGS) -o $@
# allow a single file to be unoptimized for debugging purposes
#dlmstp.o:
# $(CC) -c $(CFLAGS) $*.c -o $@
#
#main.o:
# $(CC) -c $(CFLAGS) $*.c -o $@
#
#$(BACNET_CORE)/npdu.o:
# $(CC) -c $(CFLAGS) $*.c -o $@
#
#$(BACNET_CORE)/apdu.o:
# $(CC) -c $(CFLAGS) $*.c -o $@
.PHONY: ram-usage
ram-usage:
@$(NM) -t d -S --size-sort $(TARGET).elf 1> $(TARGET).nm
@echo "=ADDRESS= ==SIZE== = ==VARIABLE NAME=="
@tail $(TARGET).nm
.PHONY: cstack
cstack:
@$(CSTACK_TOOL) $(COBJ) 2> /dev/null 1> $(TARGET).su
@head -n 25 $(TARGET).su
.PHONY: memap
memap:
# memmap needs Python and PrettyPrint and IntelHex
# sudo apt install python3-prettytable python3-intelhex
$(MEMAP_TOOL) -t GCC_ARM $(TARGET).map
.c.o:
$(CC) -c $(OPTIMIZATION) $(CFLAGS) $*.c -o $@
@@ -231,8 +249,9 @@ $(TARGET).elf: $(COBJ) $(AOBJ) Makefile
.PHONY: clean
clean:
-rm -rf $(COBJ) $(AOBJ) $(COREOBJ)
-rm -rf $(COBJ) $(AOBJ) $(COREOBJ) $(CSTACK)
-rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dmp $(TARGET).map
-rm -rf $(TARGET).su $(TARGET).nm
-rm -rf *.lst
## Other dependencies
+12 -3
View File
@@ -227,7 +227,7 @@
<state>STM32F10X_XL</state>
<state>USE_STDPERIPH_DRIVER</state>
<state>BACDL_MSTP</state>
<state>MAX_APDU=480</state>
<state>MAX_APDU=1476</state>
<state>MAX_TSM_TRANSACTIONS=0</state>
<state>BACAPP_MINIMAL</state>
</option>
@@ -1079,6 +1079,9 @@
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\dcc.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\indtext.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\iam.c</name>
</file>
@@ -1131,13 +1134,19 @@
<group>
<name>BACnet-Datalink</name>
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\datalink\automac.c</name>
<name>$PROJ_DIR$\..\..\src\bacnet\datalink\cobs.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\datalink\crc.c</name>
</file>
<file>
<name>$PROJ_DIR$\dlmstp.c</name>
<name>$PROJ_DIR$\..\..\src\bacnet\datalink\dlmstp.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\datalink\mstp.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\src\bacnet\datalink\mstptext.c</name>
</file>
</group>
<group>
-4
View File
@@ -45,10 +45,6 @@
#include "bacnet/basic/object/netport.h"
#endif
/* forward prototype */
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data);
static struct my_object_functions {
BACNET_OBJECT_TYPE Object_Type;
object_init_function Object_Init;
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -20,8 +20,6 @@
extern int errno;
extern int __io_putchar(int ch);
register char * stack_ptr asm("sp");
char *__env[1] = { 0 };
char **environ = __env;
@@ -61,6 +59,7 @@ int _write(int file, char *ptr, int len)
caddr_t _sbrk(int incr)
{
register char * stack_ptr asm("sp");
extern char end asm("end");
static char *heap_end;
char *prev_heap_end;
+63 -1
View File
@@ -27,13 +27,40 @@
#include <stdint.h>
#include "hardware.h"
#include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/sys/mstimer.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/datalink/dlmstp.h"
#include "bacnet/datalink/mstp.h"
#include "rs485.h"
#include "led.h"
#include "bacnet.h"
/* local version override */
char *BACnet_Version = "1.0";
/* MS/TP port */
static struct mstp_port_struct_t MSTP_Port;
static struct dlmstp_rs485_driver RS485_Driver = {
.init = rs485_init,
.send = rs485_bytes_send,
.read = rs485_byte_available,
.transmitting = rs485_rts_enabled,
.baud_rate = rs485_baud_rate,
.baud_rate_set = rs485_baud_rate_set,
.silence_milliseconds = rs485_silence_milliseconds,
.silence_reset = rs485_silence_reset
};
static struct dlmstp_user_data_t MSTP_User_Data;
static uint8_t Input_Buffer[DLMSTP_MPDU_MAX];
static uint8_t Output_Buffer[DLMSTP_MPDU_MAX];
/**
* @brief Called from _write() function from printf and friends
* @param[in] ch Character to send
*/
int __io_putchar(int ch)
{
(void)ch;
return 0;
}
#ifdef USE_FULL_ASSERT
@@ -102,6 +129,37 @@ void lse_init(void)
}
}
/**
* @brief Configure the MSTP datalink layer
*/
static void mstp_configure(void)
{
/* initialize MSTP datalink layer */
MSTP_Port.Nmax_info_frames = DLMSTP_MAX_INFO_FRAMES;
MSTP_Port.Nmax_master = DLMSTP_MAX_MASTER;
MSTP_Port.InputBuffer = Input_Buffer;
MSTP_Port.InputBufferSize = sizeof(Input_Buffer);
MSTP_Port.OutputBuffer = Output_Buffer;
MSTP_Port.OutputBufferSize = sizeof(Output_Buffer);
/* user data */
MSTP_Port.ZeroConfigEnabled = true;
MSTP_Port.SlaveNodeEnabled = false;
MSTP_User_Data.RS485_Driver = &RS485_Driver;
MSTP_Port.UserData = &MSTP_User_Data;
dlmstp_init((char *)&MSTP_Port);
if (MSTP_Port.ZeroConfigEnabled) {
dlmstp_set_mac_address(255);
} else {
/* FIXME: get the address from hardware DIP or from EEPROM */
dlmstp_set_mac_address(1);
}
/* FIXME: get the baud rate from hardware DIP or from EEPROM */
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
}
/**
* @brief Main entry point of the C application
*/
int main(void)
{
struct mstimer Blink_Timer;
@@ -116,9 +174,13 @@ int main(void)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE,
ENABLE);
/* initialize hardware layer */
mstimer_init();
lse_init();
led_init();
/* initialize MSTP datalink layer */
mstp_configure();
/* initialize application layer*/
bacnet_init();
mstimer_set(&Blink_Timer, 125);
for (;;) {
+95 -118
View File
@@ -45,70 +45,35 @@ static FIFO_BUFFER Receive_Buffer;
static struct mstimer Silence_Timer;
/* baud rate */
static uint32_t Baud_Rate = 38400;
/* flag to track RTS status */
static volatile bool Transmitting;
/* The minimum time after the end of the stop bit of the final octet of a */
/* received frame before a node may enable its EIA-485 driver: 40 bit times. */
/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */
/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */
/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */
/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
/* 40 bits is 4 octets including a start and stop bit with each octet */
#define Tturnaround (40UL)
/* statistics */
static volatile uint32_t RS485_Transmit_Bytes;
static volatile uint32_t RS485_Receive_Bytes;
/*************************************************************************
* Description: Reset the silence on the wire timer.
* Returns: nothing
* Notes: none
**************************************************************************/
/**
* @brief Reset the silence on the wire timer.
*/
void rs485_silence_reset(void)
{
mstimer_set(&Silence_Timer, 0);
}
/*************************************************************************
* Description: Determine the amount of silence on the wire from the timer.
* Returns: true if the amount of time has elapsed
* Notes: none
**************************************************************************/
bool rs485_silence_elapsed(uint32_t interval)
/**
* @brief Return the RS-485 silence time in milliseconds
* @return silence time in milliseconds
*/
uint32_t rs485_silence_milliseconds(void)
{
return (mstimer_elapsed(&Silence_Timer) > interval);
return mstimer_elapsed(&Silence_Timer);
}
/*************************************************************************
* Description: Baud rate determines turnaround time.
* Returns: amount of milliseconds
* Notes: none
**************************************************************************/
static uint16_t rs485_turnaround_time(void)
{
/* delay after reception before transmitting - per MS/TP spec */
/* wait a minimum 40 bit times since reception */
/* at least 2 ms for errors: rounding, clock tick */
if (Baud_Rate) {
return (2 + ((Tturnaround * 1000UL) / Baud_Rate));
} else {
return 2;
}
}
/*************************************************************************
* Description: Use the silence timer to determine turnaround time.
* Returns: true if turnaround time has expired.
* Notes: none
**************************************************************************/
bool rs485_turnaround_elapsed(void)
{
return (mstimer_elapsed(&Silence_Timer) > rs485_turnaround_time());
}
/*************************************************************************
* Description: Determines if an error occured while receiving
* Returns: true an error occurred.
* Notes: none
**************************************************************************/
/**
* @brief Determines if an error occured while receiving
* @return true an error occurred
*/
bool rs485_receive_error(void)
{
return false;
@@ -125,6 +90,7 @@ void USART2_IRQHandler(void)
/* Read one byte from the receive data register */
data_byte = USART_ReceiveData(USART2);
(void)FIFO_Put(&Receive_Buffer, data_byte);
RS485_Receive_Bytes++;
}
if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET) {
/* note: enabling RXNE interrupt also enables the ORE interrupt! */
@@ -134,11 +100,35 @@ void USART2_IRQHandler(void)
}
}
/*************************************************************************
* DESCRIPTION: Return true if a byte is available
* RETURN: true if a byte is available, with the byte in the parameter
* NOTES: none
**************************************************************************/
/**
* @brief Control the DE and /RE pins on the RS-485 transceiver
* @param enable - true to set DE and /RE high, false to set /DE and RE low
*/
void rs485_rts_enable(bool enable)
{
if (enable) {
led_tx_on_interval(10);
GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
} else {
GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);
}
}
/**
* @brief Determine the status of the transmit-enable line on the RS-485
* transceiver
* @return true if RTS is enabled, false if RTS is disabled
*/
bool rs485_rts_enabled(void)
{
return Transmitting;
}
/**
* @brief Return true if a byte is available
* @param data_register - byte in this parameter if there is one available
* @return true if a byte is available, with the byte in the parameter
*/
bool rs485_byte_available(uint8_t *data_register)
{
bool data_available = false; /* return value */
@@ -155,50 +145,37 @@ bool rs485_byte_available(uint8_t *data_register)
return data_available;
}
/*************************************************************************
* DESCRIPTION: Sends a byte of data
* RETURN: nothing
* NOTES: none
**************************************************************************/
void rs485_byte_send(uint8_t tx_byte)
{
led_tx_on_interval(10);
USART_SendData(USART2, tx_byte);
rs485_silence_reset();
}
/*************************************************************************
* Description: Determines if a byte in the USART has been shifted from
* register
* Returns: true if the USART register is empty
* Notes: none
**************************************************************************/
/**
* @brief Determines if a byte in the USART has been shifted from register
* @return true if the USART register is empty
*/
bool rs485_byte_sent(void)
{
return USART_GetFlagStatus(USART2, USART_FLAG_TXE);
}
/*************************************************************************
* Description: Determines if the entire frame is sent from USART FIFO
* Returns: true if the USART FIFO is empty
* Notes: none
**************************************************************************/
/**
* @brief Determines if the entire frame is sent from USART FIFO
* @brief true if the USART FIFO is empty
*/
bool rs485_frame_sent(void)
{
return USART_GetFlagStatus(USART2, USART_FLAG_TC);
}
/*************************************************************************
* DESCRIPTION: Send some data and wait until it is sent
* RETURN: true if a collision or timeout occurred
* NOTES: none
**************************************************************************/
/**
* @brief Transmit one or more bytes on RS-485.
* @param buffer - array of one or more bytes to transmit
* @param nbytes - number of bytes to transmit
* @return true if added to queue
*/
void rs485_bytes_send(uint8_t *buffer, /* data to send */
uint16_t nbytes)
{ /* number of bytes of data */
uint8_t tx_byte;
while (nbytes) {
rs485_rts_enable(true);
/* Send the data byte */
tx_byte = *buffer;
/* Send one byte */
@@ -208,22 +185,22 @@ void rs485_bytes_send(uint8_t *buffer, /* data to send */
}
buffer++;
nbytes--;
RS485_Transmit_Bytes++;
}
/* was the frame sent? */
while (!rs485_frame_sent()) {
/* do nothing - wait until the entire frame in the
Transmit Shift Register has been shifted out */
}
rs485_rts_enable(false);
rs485_silence_reset();
return;
}
/*************************************************************************
* Description: Configures the baud rate of the USART
* Returns: nothing
* Notes: none
**************************************************************************/
/**
* @brief Configures the baud rate of the USART
*/
static void rs485_baud_rate_configure(void)
{
USART_InitTypeDef USART_InitStructure;
@@ -240,11 +217,10 @@ static void rs485_baud_rate_configure(void)
USART_Init(USART2, &USART_InitStructure);
}
/*************************************************************************
* Description: Sets the baud rate to non-volatile storeage and configures USART
* Returns: true if a value baud rate was saved
* Notes: none
**************************************************************************/
/**
* @brief Sets the baud rate to non-volatile storeage and configures USART
* @return true if a value baud rate was saved
*/
bool rs485_baud_rate_set(uint32_t baud)
{
bool valid = true;
@@ -267,35 +243,36 @@ bool rs485_baud_rate_set(uint32_t baud)
return valid;
}
/*************************************************************************
* Description: Determines the baud rate in bps
* Returns: baud rate in bps
* Notes: none
**************************************************************************/
/**
* @brief Return the RS-485 baud rate
* @return baud - RS-485 baud rate in bits per second (bps)
*/
uint32_t rs485_baud_rate(void)
{
return Baud_Rate;
}
/*************************************************************************
* Description: Enable the Request To Send (RTS) aka Transmit Enable pin
* Returns: nothing
* Notes: none
**************************************************************************/
void rs485_rts_enable(bool enable)
/**
* @brief Return the RS-485 statistics for transmit bytes
* @return number of bytes transmitted
*/
uint32_t rs485_bytes_transmitted(void)
{
if (enable) {
GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
} else {
GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);
}
return RS485_Transmit_Bytes;
}
/*************************************************************************
* Description: Initialize the room network USART
* Returns: nothing
* Notes: none
**************************************************************************/
/**
* @brief Return the RS-485 statistics for receive bytes
* @return number of bytes received
*/
uint32_t rs485_bytes_received(void)
{
return RS485_Receive_Bytes;
}
/**
* @brief Initialize the room network USART
*/
void rs485_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
+14 -13
View File
@@ -36,33 +36,34 @@ extern "C" {
void rs485_init(
void);
void rs485_rts_enable(
bool enable);
bool rs485_rts_enabled(
void);
bool rs485_byte_available(
uint8_t * data_register);
bool rs485_receive_error(
void);
void rs485_bytes_send(
uint8_t * buffer, /* data to send */
uint16_t nbytes); /* number of bytes of data */
uint8_t * buffer,
uint16_t nbytes);
uint32_t rs485_baud_rate(
void);
bool rs485_baud_rate_set(
uint32_t baud);
/* a granular approach */
void rs485_byte_send(
uint8_t data_register);
bool rs485_byte_sent(
void);
bool rs485_frame_sent(
void);
bool rs485_turnaround_elapsed(
void);
uint32_t rs485_silence_milliseconds(
void);
void rs485_silence_reset(
void);
bool rs485_silence_elapsed(
uint32_t interval);
uint32_t rs485_bytes_transmitted(
void);
uint32_t rs485_bytes_received(
void);
#ifdef __cplusplus
}