Merge branch 'dev' into temp-profile-checker

This commit is contained in:
Mario Hüttel 2024-01-17 19:25:46 +01:00
commit 06893c21ab
60 changed files with 2648 additions and 1866 deletions

@ -1 +1 @@
Subproject commit cb937262aa71ee3d610900d7f14eef28e9f11dd0 Subproject commit aeb2707d80049094337742d0f62cd24dbef1c01d

View File

@ -16,3 +16,10 @@ reflow-controller.includes
*.files *.files
*.user.* *.user.*
*.user *.user
# VSCODE and CLANGD sepcific excludes
.vscode/
build/
.cache/
compile_commands.json

View File

@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CROSSCOMPILING 1) set(CMAKE_CROSSCOMPILING 1)
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.18)
set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake") set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake")
@ -38,31 +38,16 @@ if (GIT_FOUND)
) )
message("${BoldGreen}Git based version number: ${GIT_DESCRIBE}${ColorReset}") message("${BoldGreen}Git based version number: ${GIT_DESCRIBE}${ColorReset}")
else (GIT_FOUND) else (GIT_FOUND)
set(GIT_DESCRIBE "v0.0.0-unknown")
message("${BoldRed}No git installation found. It is highly recommended using git to generate the version number") message("${BoldRed}No git installation found. It is highly recommended using git to generate the version number")
message("Version is set to: ${GIT_DESCRIBE}${ColorReset}") message(FATAL_ERROR "Git is required")
endif (GIT_FOUND) endif (GIT_FOUND)
find_program(VIRTUALENV virtualenv) find_program(PATCHELFCRC patchelfcrc)
if (VIRTUALENV) if (PATCHELFCRC)
message("Python virtual environment found") message("patchelfcrc found: ${PATCHELFCRC}")
execute_process( else(PATCHELFCRC)
COMMAND ${VIRTUALENV} venv message(FATAL_ERROR "${BoldRed}Patchelfcrc not found. Cannot patch CRC checksum into ELF file: patchelfcrc: command not found! See: https://git.shimatta.de/mhu/patchelfcrc${ColorReset}")
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} endif (PATCHELFCRC)
OUTPUT_QUIET
COMMAND_ERROR_IS_FATAL ANY
)
set(VENV_BIN "${CMAKE_CURRENT_BINARY_DIR}/venv/bin")
execute_process(
COMMAND ./pip install -r "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/requirements.txt"
WORKING_DIRECTORY ${VENV_BIN}
OUTPUT_QUIET
COMMAND_ERROR_IS_FATAL ANY
)
message("${BoldGreen}python virtual environment set up!${ColorReset}")
else(VIRTUALENV)
message(FATAL_ERROR "${BoldRed}Python virtual environment not set up: virtualenv: command not found!${ColorReset}")
endif (VIRTUALENV)
set(ELFFILE ${PROJECT_NAME}.elf) set(ELFFILE ${PROJECT_NAME}.elf)
@ -71,11 +56,10 @@ set(MAPFILE ${PROJECT_NAME}.map)
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/stm32f407vet6_flash.ld) set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/stm32f407vet6_flash.ld)
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare) add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare)
set(GIT_DESCRIBE "${GIT_DESCRIBE}") add_definitions(-DBASE64_LOOKUP_TABLE_SECTION=\".ccm.bss\" -DSHELLMATTA_HELP_ALIAS=\"?\" -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4)
add_definitions(-DBASE64_LOOKUP_TABLE_SECTION=\".ccm.bss\" -DSHELLMATTA_HELP_ALIAS=\"?\" -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4)
add_subdirectory(doxygen) add_subdirectory(doxygen)
add_subdirectory(updater/ram-code) add_subdirectory(updater/ram-code)
@ -115,24 +99,35 @@ aux_source_directory("shellmatta/src" SHELLMATTA_SRCS)
aux_source_directory("updater" UPDATER_SRCS) aux_source_directory("updater" UPDATER_SRCS)
aux_source_directory("temp-profile" PROFILE_SRCS) aux_source_directory("temp-profile" PROFILE_SRCS)
set(GEN_VERSION_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated-version")
add_custom_target(
generate-version-header
COMMAND mkdir -p ${GEN_VERSION_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/create_version_header.sh" "${GEN_VERSION_HEADER_PATH}/version.h"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating version number using git"
)
add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS} add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS}
${FAT_SRCS} ${SDIO_SRCS} ${BOOT_SRCS} ${SETUP_SRCS} ${FAT_SRCS} ${SDIO_SRCS} ${BOOT_SRCS} ${SETUP_SRCS}
${STM_PERIPH_SRCS} ${SETTINGS_SRCS} ${SAFETY_SRCS} ${STM_PERIPH_SRCS} ${SETTINGS_SRCS} ${SAFETY_SRCS}
${SHELLMATTA_SRCS} ${UPDATER_SRCS} ${PROFILE_SRCS} ${SHELLMATTA_SRCS} ${UPDATER_SRCS} ${PROFILE_SRCS}
) )
add_dependencies(${ELFFILE} updater-ram-code-header-blob) add_dependencies(${ELFFILE} updater-ram-code-header-blob generate-version-header)
target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shellmatta/api ${CMAKE_CURRENT_SOURCE_DIR}/config-parser/include) target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/shellmatta/api ${CMAKE_CURRENT_SOURCE_DIR}/config-parser/include)
target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage) target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage)
target_link_libraries(${ELFFILE} base64-lib linklist-lib) target_link_libraries(${ELFFILE} base64-lib linklist-lib)
target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/") target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/" "${CMAKE_CURRENT_BINARY_DIR}/include/")
add_custom_command( add_custom_command(
TARGET ${ELFFILE} TARGET ${ELFFILE}
POST_BUILD POST_BUILD
COMMAND ./python "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/crc-patch-elf.py" "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" COMMAND ${PATCHELFCRC} --little-endian --verbose --granularity word --start-magic 0xa8be53f9 --end-magic 0xffa582ff -O .flashcrc -p crc-32-mpeg -S .text -S .data -S .ccmdata -S .vectors "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}"
WORKING_DIRECTORY ${VENV_BIN} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Running Flash CRC Patcher" COMMENT "Running Flash CRC Patcher"
) )

View File

@ -28,7 +28,14 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
/**
* @brief Config parser magic value used to check sanity of passed structs
*/
#define CONFIG_PARSER_MAGIC 0x464a6e2bUL #define CONFIG_PARSER_MAGIC 0x464a6e2bUL
/**
* @brief Config parser type casting macro
*/
#define CONFIG_PARSER(p) ((struct config_parser *)(p)) #define CONFIG_PARSER(p) ((struct config_parser *)(p))
/** /**
@ -37,10 +44,11 @@
* If the pointer is invalid, the function using this macro will return with * If the pointer is invalid, the function using this macro will return with
* CONFIG_PARSER_PARAM_ERR * CONFIG_PARSER_PARAM_ERR
*/ */
#define config_parser_check_handle(handle) do { if (!(handle) || \ #define config_parser_check_handle(handle) do { \
((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \ if (!(handle) || \
return CONFIG_PARSER_PARAM_ERR; \ ((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \
} while (0) return CONFIG_PARSER_PARAM_ERR; \
} while (0)
config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name, config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name,
char *working_buffer, size_t buff_size) char *working_buffer, size_t buff_size)
@ -92,17 +100,17 @@ static int parse_value(struct config_parser_entry *entry, char *value_start_toke
if (value_start_token[0] != '-') { if (value_start_token[0] != '-') {
/* Try parsing as ul */ /* Try parsing as ul */
entry->value.uint_val = strtoul(value_start_token, &endptr, 0); entry->value.uint_val = strtoul(value_start_token, &endptr, 0);
if (endptr == value_start_token) { if (endptr == value_start_token)
return -1; return -1;
}
entry->type = CONFIG_PARSER_TYPE_UINT; entry->type = CONFIG_PARSER_TYPE_UINT;
goto exit; goto exit;
} else { } else {
/* Try parsing as int */ /* Try parsing as int */
entry->value.int_val = strtod(value_start_token, &endptr); entry->value.int_val = strtod(value_start_token, &endptr);
if (endptr == value_start_token) { if (endptr == value_start_token)
return -1; return -1;
}
entry->type = CONFIG_PARSER_TYPE_INT; entry->type = CONFIG_PARSER_TYPE_INT;
} }
@ -110,14 +118,16 @@ exit:
return 0; return 0;
} }
enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, bool force_float) enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry,
bool force_float)
{ {
struct config_parser *p; struct config_parser *p;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);
char *token; char *token;
int token_round = 0; int token_round = 0;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);
if (!entry) if (!entry)
return CONFIG_PARSER_PARAM_ERR; return CONFIG_PARSER_PARAM_ERR;
@ -131,8 +141,7 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str
if (token[0] == '#') { if (token[0] == '#') {
if (token_round == 0) if (token_round == 0)
return CONFIG_PARSER_LINE_COMMENT; return CONFIG_PARSER_LINE_COMMENT;
else break;
break;
} }
switch (token_round) { switch (token_round) {
@ -140,9 +149,8 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str
entry->name = token; entry->name = token;
break; break;
case 1: /* = Symbol */ case 1: /* = Symbol */
if (strcmp(token, "=")) { if (strcmp(token, "="))
return CONFIG_PARSER_LINE_MALFORM; return CONFIG_PARSER_LINE_MALFORM;
}
break; break;
case 2: /* VALUE */ case 2: /* VALUE */
if (parse_value(entry, token)) if (parse_value(entry, token))
@ -172,6 +180,7 @@ enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handl
{ {
FRESULT res; FRESULT res;
struct config_parser *p; struct config_parser *p;
config_parser_check_handle(handle); config_parser_check_handle(handle);
p = CONFIG_PARSER(handle); p = CONFIG_PARSER(handle);
@ -194,6 +203,7 @@ enum config_parser_ret config_parser_close_file(config_parser_handle_t handle)
{ {
struct config_parser *p; struct config_parser *p;
FRESULT res; FRESULT res;
config_parser_check_handle(handle); config_parser_check_handle(handle);
p = CONFIG_PARSER(handle); p = CONFIG_PARSER(handle);

View File

@ -1,114 +0,0 @@
#!/bin/python
"""
This script patches the CRC checksums into an existing ELF file.
For this, it searches the follwoing sections:
1) .text
2) .data
3) .ccmdata
4) .vectors
All sections MUST be a multiple of 4 bytes long because the CRC calculation relies on whole 32 bit words.
The sections are excrated and the CRC is calculated for each section.
In the section .flashcrc, the script expects a single struct with the prototype:
struct flash_crcs {
uint32_t start_magic;
uint32_t crc_section_text;
uint32_t crc_section_data;
uint32_t crc_section_ccm_data;
uint32_t crc_section_vectors;
uint32_t end_magic;
};
It checks, if the start magic and end magic are set to the appropriate values and then patches in the CRC values of the sections.
The magic values checked for are: 0xA8BE53F9 and 0xFFA582FF
"""
from elftools.elf.elffile import ELFFile
from elftools.elf.segments import Segment
import elftools.elf.constants as elf_const
import sys
import crcmod
import crcmod.predefined
import struct
crc_calc = crcmod.predefined.mkCrcFun('crc-32-mpeg')
if len(sys.argv) < 2:
print("Usage:", sys.argv[0], ' <elf file>')
sys.exit(-1)
filename=sys.argv[1]
def section_calculate_crc(section):
data = bytearray(section.data())
be_data = bytearray([0 for k in range(0, len(data))])
# Rearrange data, because the STM controller sees it as 32 bit little endian words
for i in range(0, int(len(data)/4)):
be_data[i*4+0] = data[i*4+3]
be_data[i*4+1] = data[i*4+2]
be_data[i*4+2] = data[i*4+1]
be_data[i*4+3] = data[i*4+0]
return crc_calc(be_data)
with open(filename, 'r+b') as f:
elf = ELFFile(f)
sections = {}
sections['.text'] = elf.get_section_by_name('.text')
sections['.data'] = elf.get_section_by_name('.data')
sections['.ccmdata'] = elf.get_section_by_name('.ccmdata')
sections['.vectors'] = elf.get_section_by_name('.vectors')
for key, sec in sections.items():
if sec is None:
print("Error! Section", key, "not found in ELF file!")
sys.exit(-1)
print('Found section', key, 'Size:',
sec.data_size, 'Type:', sec['sh_type'])
if sec['sh_type'] != 'SHT_PROGBITS':
print('Error! Section must be of type SHT_PROGBITS')
sys.exit(-1)
if (sec.data_size % 4 != 0):
print("Section", key, "has wrong size. Must be a multiple of 4 bytes!")
sys.exit(-1)
text_crc = section_calculate_crc(sections['.text'])
print('CRC of .text section:', hex(text_crc))
data_crc = section_calculate_crc(sections['.data'])
print('CRC of .data section:', hex(data_crc))
ccmdata_crc = section_calculate_crc(sections['.ccmdata'])
print('CRC of .ccmdata section:', hex(ccmdata_crc))
vextors_crc = section_calculate_crc(sections['.vectors'])
print('CRC of .vectors section:', hex(vextors_crc))
# Check the flashcrc section
flashcrc_sec = elf.get_section_by_name('.flashcrc')
if flashcrc_sec is None:
print('Section for flash CRC missing!')
sys.exit(-1)
if flashcrc_sec.data_size != 6*4:
print("Error: .flashcrc section has wrong size:",flashcrc_sec.data_size)
sys.exit(-1);
crc_sec_data = bytearray(flashcrc_sec.data())
magic1 = struct.unpack('<I'*1, bytes(crc_sec_data[0:4]))[0]
magic2 = struct.unpack('<I'*1, bytes(crc_sec_data[-4:]))[0]
print("CRC section magic values:", hex(magic1), hex(magic2))
if magic1 != 0xA8BE53F9 or magic2 != 0xFFA582FF:
print("Wrong magics in CRC section. Data misalignment?")
sys.exit(-2)
crc_sec_offset = flashcrc_sec['sh_offset']
print('CRC section ELF file offset:', hex(crc_sec_offset))
crc_sec_data[4:8] = struct.pack('<I',text_crc)
crc_sec_data[8:12] = struct.pack('<I',data_crc)
crc_sec_data[12:16] = struct.pack('<I',ccmdata_crc)
crc_sec_data[16:20] = struct.pack('<I',vextors_crc)
f.seek(crc_sec_offset)
f.write(crc_sec_data)
print('CRCs patched successfully')

View File

@ -1,2 +0,0 @@
crcmod==1.7
pyelftools==0.27

View File

@ -6,7 +6,7 @@ import pathlib
license_header = """/* Reflow Oven Controller license_header = """/* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
@ -37,7 +37,7 @@ cpath = os.path.join(project_dir, sys.argv[1]+'.c')
hfile = sys.argv[1]+'.h' hfile = sys.argv[1]+'.h'
hpath = os.path.join(module_include_dir, hfile) hpath = os.path.join(module_include_dir, hfile)
h_define = '__'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'__' h_define = '_'+hfile.replace('.', '_').replace('-', '_').replace('/', '_').upper()+'_'
if os.path.exists(cpath) or os.path.exists(hpath): if os.path.exists(cpath) or os.path.exists(hpath):
print("File already exists! Abort!") print("File already exists! Abort!")

View File

@ -0,0 +1,15 @@
#!/bin/bash
if [[ -z $1 ]]; then
# Exit with error in case no output file is specified
exit -1
fi
firmware_version=`git describe --tags --always --dirty`
commit=`git rev-parse HEAD`
echo "#ifndef _VERSION_GENERATED_H_" > $1
echo "#define _VERSION_GENERATED_H_" >> $1
echo "#define GIT_VERSION_STRING \"$firmware_version\"" >> $1
echo "#define GIT_FULL_COMMIT \"$commit\"" >> $1
echo "#endif /* _VERSION_GENERATED_H_ */" >> $1

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +1,208 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */ /* A Sample Code of User Provided OS Dependent Functions for FatFs */
/* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <fatfs/ff.h> #include <fatfs/ff.h>
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Use dynamic memory allocation */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Allocate a memory block */ /* Allocate/Free a Memory Block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <stdlib.h> /* with POSIX API */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
return malloc(msize); /* Allocate a new memory block with POSIX API */ return malloc((size_t)msize); /* Allocate a new memory block */
} }
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */ void* mblock /* Pointer to the memory block to free (no effect if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block */
} }
#endif #endif
#if FF_FS_REENTRANT /* Mutal exclusion */ #if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Create a Synchronization Object */ /* Definitions of Mutex */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ #define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ #if OS_TYPE == 0 /* Win32 */
BYTE vol, /* Corresponding volume (logical drive number) */ #include <windows.h>
FF_SYNC_t* sobj /* Pointer to return the created sync object */ static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
)
{
/* Win32 */
*sobj = CreateMutex(NULL, FALSE, NULL);
return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */ #elif OS_TYPE == 1 /* uITRON */
// T_CSEM csem = {TA_TPRI,1,1}; #include "itron.h"
// *sobj = acre_sem(&csem); #include "kernel.h"
// return (int)(*sobj > 0); static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
/* uC/OS-II */ #elif OS_TYPE == 2 /* uc/OS-II */
// OS_ERR err; #include "includes.h"
// *sobj = OSMutexCreate(0, &err); static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */ #elif OS_TYPE == 3 /* FreeRTOS */
// *sobj = xSemaphoreCreateMutex(); #include "FreeRTOS.h"
// return (int)(*sobj != NULL); #include "semphr.h"
static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
/* CMSIS-RTOS */ #elif OS_TYPE == 4 /* CMSIS-RTOS */
// *sobj = osMutexCreate(&Mutex[vol]); #include "cmsis_os.h"
// return (int)(*sobj != NULL); static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
/* Win32 */
return (int)CloseHandle(sobj);
/* uITRON */
// return (int)(del_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// vSemaphoreDelete(sobj);
// return 1;
/* CMSIS-RTOS */
// return (int)(osMutexDelete(sobj) == osOK);
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
FF_SYNC_t sobj /* Sync object to wait */
)
{
/* Win32 */
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
/* uITRON */
// return (int)(wai_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
/* CMSIS-RTOS */
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
/* Win32 */
ReleaseMutex(sobj);
/* uITRON */
// sig_sem(sobj);
/* uC/OS-II */
// OSMutexPost(sobj);
/* FreeRTOS */
// xSemaphoreGive(sobj);
/* CMSIS-RTOS */
// osMutexRelease(sobj);
}
#endif #endif
/*------------------------------------------------------------------------*/
/* Create a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to create a new mutex
/ or semaphore for the volume. When a 0 is returned, the f_mount function
/ fails with FR_INT_ERR.
*/
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
Mutex[vol] = CreateMutex(NULL, FALSE, NULL);
return (int)(Mutex[vol] != INVALID_HANDLE_VALUE);
#elif OS_TYPE == 1 /* uITRON */
T_CMTX cmtx = {TA_TPRI,1};
Mutex[vol] = acre_mtx(&cmtx);
return (int)(Mutex[vol] > 0);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
Mutex[vol] = OSMutexCreate(0, &err);
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
Mutex[vol] = xSemaphoreCreateMutex();
return (int)(Mutex[vol] != NULL);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDef(cmsis_os_mutex);
Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex));
return (int)(Mutex[vol] != NULL);
#endif
}
/*------------------------------------------------------------------------*/
/* Delete a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to delete a mutex or
/ semaphore of the volume created with ff_mutex_create function.
*/
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
CloseHandle(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
del_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err);
#elif OS_TYPE == 3 /* FreeRTOS */
vSemaphoreDelete(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDelete(Mutex[vol]);
#endif
}
/*------------------------------------------------------------------------*/
/* Request a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on enter file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0);
#elif OS_TYPE == 1 /* uITRON */
return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err));
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK);
#endif
}
/*------------------------------------------------------------------------*/
/* Release a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leave file functions to unlock the volume.
*/
void ff_mutex_give (
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
ReleaseMutex(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
unl_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OSMutexPost(Mutex[vol]);
#elif OS_TYPE == 3 /* FreeRTOS */
xSemaphoreGive(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexRelease(Mutex[vol]);
#endif
}
#endif /* FF_FS_REENTRANT */

View File

@ -1,13 +1,13 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13+ */ /* Unicode Handling Functions for FatFs R0.13 and Later */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .rodata section when the */
/* FatFs is configured for LFN with DBCS. If the system has a Unicode */
/* library for the code conversion, this module should be modified to use */
/* it to avoid silly memory consumption. */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
/ utilitiy for the code conversion, this module should be modified to use /
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/* /*
/ Copyright (C) 2014, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -25,7 +25,7 @@
#include <fatfs/ff.h> #include <fatfs/ff.h>
#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */
#define MERGE2(a, b) a ## b #define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp) #define CVTBL(tbl, cp) MERGE2(tbl, cp)
@ -15214,8 +15214,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* SBCS fixed code page */ /* SBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
@ -15225,7 +15225,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII? */ if (uni < 0x80) { /* ASCII? */
@ -15247,7 +15247,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII? */ if (oem < 0x80) { /* ASCII? */
@ -15267,8 +15267,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* DBCS fixed code page */ /* DBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900 #if FF_CODE_PAGE >= 900
@ -15277,7 +15277,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15313,7 +15313,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15346,7 +15346,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for dynamic code page configuration */ /* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 0
@ -15360,7 +15360,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15412,7 +15412,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15458,14 +15458,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode up-case conversion */ /* Unicode Up-case Conversion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */ DWORD uni /* Unicode code point to be up-converted */
) )
{ {
const WORD *p; const WORD* p;
WORD uc, bc, nc, cmd; WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */ /* Basic Latin */
@ -15590,4 +15590,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
} }
#endif /* #if FF_USE_LFN */ #endif /* #if FF_USE_LFN != 0 */

View File

@ -27,10 +27,15 @@
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <stm32/stm32f4xx.h> #include <stm32/stm32f4xx.h>
#if HW_REV_DETECT_PIN_LOW > HW_REV_DETECT_PIN_HIGH
#error Configuration error for Hardware derection pins. Lowest position must be less than the highest pin position.
#endif
enum hw_revision get_pcb_hardware_version(void) enum hw_revision get_pcb_hardware_version(void)
{ {
uint8_t current_pin; uint8_t current_pin;
uint16_t port_bitmask = 0U; uint16_t port_bitmask = 0U; /* Use uint16_t because a port can have 16 IOs max. */
const uint16_t highest_bit_mask = (1 << (HW_REV_DETECT_PIN_HIGH - HW_REV_DETECT_PIN_LOW));
static enum hw_revision revision = HW_REV_NOT_DETECTED; static enum hw_revision revision = HW_REV_NOT_DETECTED;
/* If the revision has been previously detected, /* If the revision has been previously detected,
@ -53,7 +58,7 @@ enum hw_revision get_pcb_hardware_version(void)
*/ */
for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) { for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) {
port_bitmask >>= 1; port_bitmask >>= 1;
port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : 0x80; port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : highest_bit_mask;
} }
/* Resolve the read in bitmask to a hardware version */ /* Resolve the read in bitmask to a hardware version */

View File

@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14b / / FatFs - Generic FAT Filesystem module R0.15 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2021, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -20,7 +20,7 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 86631 /* Revision ID */ #define FF_DEFINED 80286 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -131,10 +131,11 @@ extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */ BYTE pdrv; /* Volume hosting physical drive */
BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] status (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */ WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */ WORD csize; /* Cluster size [sectors] */
@ -147,9 +148,6 @@ typedef struct {
#if FF_FS_EXFAT #if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif #endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY #if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */ DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */ DWORD free_clst; /* Number of free clusters */
@ -163,10 +161,10 @@ typedef struct {
#endif #endif
#endif #endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */ DWORD fsize; /* Number of sectors per FAT */
LBA_t volbase; /* Volume base sector */ LBA_t volbase; /* Volume base sector */
LBA_t fatbase; /* FAT base sector */ LBA_t fatbase; /* FAT base sector */
LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */
LBA_t database; /* Data base sector */ LBA_t database; /* Data base sector */
#if FF_FS_EXFAT #if FF_FS_EXFAT
LBA_t bitbase; /* Allocation bitmap base sector */ LBA_t bitbase; /* Allocation bitmap base sector */
@ -181,7 +179,7 @@ typedef struct {
typedef struct { typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume's mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
@ -250,7 +248,7 @@ typedef struct {
WORD ftime; /* Modified time */ WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */ BYTE fattrib; /* File attribute */
#if FF_USE_LFN #if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else #else
TCHAR fname[12 + 1]; /* File name */ TCHAR fname[12 + 1]; /* File name */
@ -298,8 +296,10 @@ typedef enum {
/*--------------------------------------------------------------*/
/* FatFs Module Application Interface */
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_close (FIL* fp); /* Close an open file object */
@ -336,6 +336,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
/* Some API fucntions are implemented as macro */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr) #define f_tell(fp) ((fp)->fptr)
@ -349,38 +351,43 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Additional user defined functions */ /* Additional Functions */
/*--------------------------------------------------------------*/
/* RTC function */ /* RTC function (provided by user) */
#if !FF_FS_READONLY && !FF_FS_NORTC #if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void); DWORD get_fattime (void); /* Get current time */
#endif #endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ /* LFN support functions (defined in ffunicode.c) */
#if FF_USE_LFN >= 1
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif #endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
/* Sync functions */
#if FF_FS_REENTRANT /* O/S dependent functions (samples available in ffsystem.c) */
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ void* ff_memalloc (UINT msize); /* Allocate memory block */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ void ff_memfree (void* mblock); /* Free memory block */
#endif
#if FF_FS_REENTRANT /* Sync functions */
int ff_mutex_create (int vol); /* Create a sync object */
void ff_mutex_delete (int vol); /* Delete a sync object */
int ff_mutex_take (int vol); /* Lock sync object */
void ff_mutex_give (int vol); /* Unlock sync object */
#endif #endif
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Flags and offset address */ /* Flags and Offset Address */
/*--------------------------------------------------------------*/
/* File access mode and open method flags (3rd argument of f_open) */ /* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01 #define FA_READ 0x01

View File

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs Functional Configurations / Configurations of FatFs Module
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 86631 /* Revision ID */ #define FFCONF_DEF 80286 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -68,7 +68,7 @@
/ 2: Enable with LF-CRLF conversion. / 2: Enable with LF-CRLF conversion.
/ /
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
makes f_printf() support floating point argument. These features want C99 or later. / makes f_printf() support floating point argument. These features want C99 or later.
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions. / to be read/written via those functions.
@ -178,7 +178,7 @@
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid / logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as: / not defined, a user defined volume string table is needed as:
/ /
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/ */
@ -190,7 +190,7 @@
/ number and only an FAT volume found on the physical drive will be mounted. / number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to / When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */ / function will be available. */
#define FF_MIN_SS 512 #define FF_MIN_SS 512
@ -240,10 +240,10 @@
#define FF_FS_NORTC 0 #define FF_FS_NORTC 0
#define FF_NORTC_MON 1 #define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2020 #define FF_NORTC_YEAR 2022
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have /* The option FF_FS_NORTC switches timestamp feature. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp / timestamp feature. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON, / added to the project to read current time form real-time clock. FF_NORTC_MON,
@ -253,7 +253,7 @@
#define FF_FS_NOFSINFO 0 #define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force / option, and f_getfree() function at the first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. / a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/ /
/ bit0=0: Use free cluster count in the FSINFO if available. / bit0=0: Use free cluster count in the FSINFO if available.
@ -275,26 +275,21 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different / module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function. / to the same volume is under control of this featuer.
/ /
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers, / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give()
/ function, must be added to the project. Samples are available in / function, must be added to the project. Samples are available in ffsystem.c.
/ option/syscall.c.
/ /
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, */
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */

View File

@ -48,7 +48,6 @@
*/ */
#define HW_REV_DETECT_PIN_HIGH (15U) #define HW_REV_DETECT_PIN_HIGH (15U)
/** /**
* @brief PCB/Hardware Revision Type * @brief PCB/Hardware Revision Type
*/ */

View File

@ -30,10 +30,16 @@
#include <stdint.h> #include <stdint.h>
/** /**
* @brief Initialize/Reset the main cycle counter to 0. * @brief Initialize the main cycle counter and reset to 0. This also enables the core cycle counter
* This function can be called multiple times. * This function can be called multiple times.
*/ */
void main_cycle_counter_init(void); void main_and_core_cycle_counter_init(void);
/**
* @brief Reset the main cycle counter.
* @note This does not reset the core cycle counter
*/
void main_cycle_counter_reset(void);
/** /**
* @brief Increment the main cycle counter by 1 * @brief Increment the main cycle counter by 1
@ -46,6 +52,18 @@ void main_cycle_counter_inc(void);
*/ */
uint64_t main_cycle_counter_get(void); uint64_t main_cycle_counter_get(void);
/**
* @brief Reset the core cycle counter to 0
*/
void core_cycle_counter_reset(void);
/**
* @brief Get the current value of the core cycle counter
*
* @return uint32_t Counter value
*/
uint32_t core_cycle_counter_get(void);
#endif /* __MAIN_CYCLE_COUNTER_H__ */ #endif /* __MAIN_CYCLE_COUNTER_H__ */
/** @} */ /** @} */

View File

@ -0,0 +1,37 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SAFETY_FLASH_CRC_STRUCT_H_
#define _SAFETY_FLASH_CRC_STRUCT_H_
#include <stdint.h>
struct flash_crcs {
uint32_t start_magic;
uint32_t crc_section_text;
uint32_t crc_section_data;
uint32_t crc_section_ccm_data;
uint32_t crc_section_vectors;
uint32_t end_magic;
};
extern const struct flash_crcs crcs_in_flash;
#endif /* _SAFETY_FLASH_CRC_STRUCT_H_ */

View File

@ -0,0 +1,56 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SAFETY_FLASH_CRC_H_
#define _SAFETY_FLASH_CRC_H_
#include <stdint.h>
enum flash_crc_section {
FLASH_CRC_VECTOR = 0,
FLASH_CRC_TEXT,
FLASH_CRC_DATA,
FLASH_CRC_CCMDATA,
N_FLASH_CRC,
};
/**
* @brief Perform a CRC check of the flash memory and set appropriate flags
* @return negative if internal error occured. Otherwise (independent from CRC check result) 0.
* @note This function requires the safety controller (and CRC unit) to be set up before calling!
*/
int flash_crc_trigger_check(void);
/**
* @brief Calculate CRC over flash section
* @param sec Section to calculate CRC over
* @param[out] crc_result Calculated CRC
* @return negative if internal error occured. Otherwise (independent from CRC check result) 0.
*/
int flash_crc_calc_section(enum flash_crc_section sec, uint32_t *crc_result);
/**
* @brief Get expected CRC value of a section
* @param sec Section
* @return Expected CRC
*/
uint32_t flash_crc_get_expected_crc(enum flash_crc_section sec);
#endif /* _SAFETY_FLASH_CRC_H_ */

View File

@ -27,6 +27,15 @@
#ifndef __SAFETY_CONFIG_H__ #ifndef __SAFETY_CONFIG_H__
#define __SAFETY_CONFIG_H__ #define __SAFETY_CONFIG_H__
/**
* @brief Weights of error flags.
*/
enum config_weight {
SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */
SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */
SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */
};
/** /**
* @brief Enum type representing safety flags. * @brief Enum type representing safety flags.
* *
@ -60,6 +69,7 @@ enum safety_flag {
ERR_FLAG_FLASH_CRC_DATA = (1<<20), ERR_FLAG_FLASH_CRC_DATA = (1<<20),
ERR_FLAG_CFG_CRC_MEAS_ADC = (1<<21), ERR_FLAG_CFG_CRC_MEAS_ADC = (1<<21),
ERR_FLAG_CFG_CRC_SAFETY_ADC = (1<<22), ERR_FLAG_CFG_CRC_SAFETY_ADC = (1<<22),
ERR_FLAG_CFG_CRC_MISC = (1<<23),
}; };
/** /**
@ -78,6 +88,7 @@ enum timing_monitor {
enum crc_monitor { enum crc_monitor {
ERR_CRC_MON_MEAS_ADC = 0, ERR_CRC_MON_MEAS_ADC = 0,
ERR_CRC_MON_SAFETY_ADC, ERR_CRC_MON_SAFETY_ADC,
ERR_CRC_MON_MISC,
N_ERR_CRC_MON N_ERR_CRC_MON
}; };
@ -115,7 +126,15 @@ enum analog_value_monitor {
#define WATCHDOG_HALT_DEBUG (0) #define WATCHDOG_HALT_DEBUG (0)
#endif #endif
#define WATCHDOG_PRESCALER 16 /**
* @brief Watchdog clock prescaler value
*/
#define WATCHDOG_PRESCALER (16)
/**
* @brief Watchdog reload value
*/
#define WATCHDOG_RELOAD_VALUE (2500)
/** /**
* @brief Minimum number of bytes that have to be free on the stack. If this is not the case, an error is detected * @brief Minimum number of bytes that have to be free on the stack. If this is not the case, an error is detected
@ -159,7 +178,13 @@ enum analog_value_monitor {
#define SAFETY_CRC_MON_SAFETY_ADC_PW 0xA8DF2368 #define SAFETY_CRC_MON_SAFETY_ADC_PW 0xA8DF2368
/** /**
* @brief Default persistence of safety flags. These values are loaded into the safety tables on startup * @brief Password for resetting ERR_CRC_MON_MISC
*
*/
#define SAFETY_CRC_MON_MISC_PW 0x9A62E96A
/**
* @brief Default persistence of safety flags. These values are loaded into the safety tables on startup.
*/ */
#define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \ #define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \
@ -184,8 +209,9 @@ enum analog_value_monitor {
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MISC, true),
/** /**
* @brief Default config weights of safety flags. These values are loaded into the safety tables on startup * @brief Default config weights of safety flags. These values are loaded into the safety tables on startup.
*/ */
#define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ #define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
@ -206,9 +232,10 @@ enum analog_value_monitor {
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MISC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
#endif /* __SAFETY_CONFIG_H__ */ #endif /* __SAFETY_CONFIG_H__ */

View File

@ -70,14 +70,14 @@ struct timing_monitor_info {
* You have to call safety_controller_handle * You have to call safety_controller_handle
* If this function fails, it will hang, because errors in the safety controller are not recoverable * If this function fails, it will hang, because errors in the safety controller are not recoverable
*/ */
void safety_controller_init(); void safety_controller_init(void);
/** /**
* @brief Handle the safety controller. * @brief Handle the safety controller.
* @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware * @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware
* @return 0 if successful * @returns Worst flag weigth that is currently set.
*/ */
int safety_controller_handle(); enum config_weight safety_controller_handle(void);
/** /**
* @brief Report one or multiple errors to the safety controller * @brief Report one or multiple errors to the safety controller
@ -170,13 +170,13 @@ bool safety_controller_get_flags_by_mask(enum safety_flag mask);
* @brief Get the count of error flags * @brief Get the count of error flags
* @return Error flag count * @return Error flag count
*/ */
uint32_t safety_controller_get_flag_count(); uint32_t safety_controller_get_flag_count(void);
/** /**
* @brief Get the count of analog monitors * @brief Get the count of analog monitors
* @return Analog monitor count * @return Analog monitor count
*/ */
uint32_t safety_controller_get_analog_monitor_count(); uint32_t safety_controller_get_analog_monitor_count(void);
/** /**
* @brief Get an error flag's name by its index. * @brief Get an error flag's name by its index.
@ -267,13 +267,6 @@ int safety_controller_set_overtemp_limit(float over_temperature);
*/ */
float safety_controller_get_overtemp_limit(void); float safety_controller_get_overtemp_limit(void);
/**
* @brief Perform a CRC check of the flash memory and set appropriate flags
* @return negative if internal error occured. Otherwise (independent from CRC check result) 0.
* @note This function requires the safety controller to be set up before!
*/
int safety_controller_trigger_flash_crc_check(void);
/** /**
* @brief Recalculate the CRC of a given CRC Monitor. This has to be done once the supervised registers update * @brief Recalculate the CRC of a given CRC Monitor. This has to be done once the supervised registers update
* @param mon Monitor to recalculate * @param mon Monitor to recalculate

View File

@ -24,6 +24,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <reflow-controller/safety/safety-config.h>
/** @addtogroup safety-memory /** @addtogroup safety-memory
* @{ * @{
@ -131,15 +132,6 @@ enum config_override_entry_type {
SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE = 2, SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE = 2,
}; };
/**
* @brief Weights of error flags.
*/
enum config_weight {
SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */
SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */
SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */
};
/** /**
* @brief representation of a config override memory entry * @brief representation of a config override memory entry
*/ */

View File

@ -27,11 +27,19 @@
/** /**
* @brief Setup the watchdog for the safety controller * @brief Setup the watchdog for the safety controller
* @param Prescaler to use for the 32 KHz LSI clock *
* The watchdog timeout can be calculated with:
* \f[ t = \frac{(\mathrm{RELOAD_VAL} + 1)\cdot \mathrm{PRESCALER}}{32000 } s\f]
*
* Valid prescaler values are: 4, 8, 16, 32, 64, 128, 256.
* @param prescaler Prescaler to use for the 32 KHz LSI clock
* @param reload_value Reload value to reload the timer with when reset. 0 to 0xFFF
* @return 0 if successful * @return 0 if successful
* @return -1 if prescaler is wrong
* @return -2 if a reload value > 0xFFF is selected. 0xFFF will be used in this case
* @note Once the watchdog is enabled, it cannot be turned off! * @note Once the watchdog is enabled, it cannot be turned off!
*/ */
int watchdog_setup(uint8_t prescaler); int watchdog_setup(uint16_t prescaler, uint16_t reload_value);
/** /**
* @brief Reset watchdog counter * @brief Reset watchdog counter

View File

@ -0,0 +1,42 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SD_H_
#define _SD_H_
#include <stdbool.h>
#include <fatfs/ff.h>
/**
* @brief Mount the SD card if available and not already mounted
* @param fs Filesystem to mount to.
* @return true if mounted, false if an error occured or the SD is not inserted and cannot be mounted
*/
bool mount_sd_card_if_avail(FATFS *fs);
/**
* @brief Return whether an SD card is inserted and mounted
*
* @return true SD inserted and mounted
* @return false No SD inserted or not mounted
*/
bool sd_card_is_mounted(void);
#endif /* _SD_H_ */

View File

@ -28,12 +28,12 @@
* @brief Initialize the SPI for the eeprom. * @brief Initialize the SPI for the eeprom.
* @return 0 if succesful * @return 0 if succesful
*/ */
int spi_eeprom_init(); int spi_eeprom_init(void);
/** /**
* @brief Uninitialize the SPI EEPROM * @brief Uninitialize the SPI EEPROM
*/ */
void spi_eeprom_deinit(); void spi_eeprom_deinit(void);
/** /**
* @brief Read from SPI EEPROM * @brief Read from SPI EEPROM

View File

@ -0,0 +1,29 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _VERSION_H_
#define _VERSION_H_
extern const char *version_git_version_string;
extern const char *version_git_full_commit_string;
extern const char *version_compile_date;
extern const char *version_compile_time;
#endif /* _VERSION_H_ */

View File

@ -33,7 +33,7 @@ enum random_number_error {
void random_number_gen_init(bool int_enable); void random_number_gen_init(bool int_enable);
void random_number_gen_deinit(); void random_number_gen_deinit(void);
void random_number_gen_reset(bool int_en); void random_number_gen_reset(bool int_en);

View File

@ -33,4 +33,6 @@ void stm_unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low);
void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id); void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id);
void stm_cpuid_get(uint8_t *implementer, uint8_t *variant, uint16_t *part_no, uint8_t *rev);
#endif /* __UNIQUE_ID_H__ */ #endif /* __UNIQUE_ID_H__ */

View File

@ -25,6 +25,7 @@
#include <reflow-controller/main-cycle-counter.h> #include <reflow-controller/main-cycle-counter.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm32/stm32f4xx.h>
/** /**
* @brief Variable storing the main cycle counter. * @brief Variable storing the main cycle counter.
@ -33,7 +34,22 @@
*/ */
static uint64_t IN_SECTION(.ccm.bss) main_cycle_counter; static uint64_t IN_SECTION(.ccm.bss) main_cycle_counter;
void main_cycle_counter_init(void) void main_and_core_cycle_counter_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* Enable the core cycle counter if available on current processor */
if (!(DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk)) {
/* Cycle counter is available. Enable */
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
/* Reset the counters to 0 */
main_cycle_counter_reset();
core_cycle_counter_reset();
}
void main_cycle_counter_reset(void)
{ {
main_cycle_counter = 0ULL; main_cycle_counter = 0ULL;
} }
@ -48,4 +64,14 @@ uint64_t main_cycle_counter_get(void)
return main_cycle_counter; return main_cycle_counter;
} }
void core_cycle_counter_reset(void)
{
DWT->CYCCNT = 0UL;
}
uint32_t core_cycle_counter_get(void)
{
return DWT->CYCCNT;
}
/** @} */ /** @} */

View File

@ -23,6 +23,7 @@
* @brief Main file for firmware * @brief Main file for firmware
*/ */
#include "reflow-controller/safety/safety-config.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -32,13 +33,13 @@
#include <reflow-controller/systick.h> #include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/digio.h> #include <reflow-controller/digio.h>
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
#include <stm-periph/stm32-gpio-macros.h> #include <stm-periph/stm32-gpio-macros.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <stm-periph/uart.h> #include <stm-periph/uart.h>
#include <reflow-controller/periph-config/shell-uart-config.h> #include <reflow-controller/periph-config/shell-uart-config.h>
#include <reflow-controller/oven-driver.h> #include <reflow-controller/oven-driver.h>
#include <fatfs/ff.h> #include <fatfs/ff.h>
#include <reflow-controller/sd.h>
#include <reflow-controller/ui/gui.h> #include <reflow-controller/ui/gui.h>
#include <reflow-controller/ui/shell.h> #include <reflow-controller/ui/shell.h>
#include <reflow-controller/ui/shell-uart.h> #include <reflow-controller/ui/shell-uart.h>
@ -88,40 +89,6 @@ static inline void uart_gpio_config(void)
#endif #endif
} }
/**
* @brief Mount the SD card if available and not already mounted
* @param mounted The current mounting state of the SD card
* @return true if mounted, false if an error occured or the SD is not inserted and cannot be mounted
*/
static bool mount_sd_card_if_avail(bool mounted)
{
FRESULT res;
static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0;
if (sdio_check_inserted() && mounted) {
memset(fs_ptr, 0, sizeof(FATFS));
sdio_stop_clk();
inserted_counter = 0;
return false;
}
if (!sdio_check_inserted() && inserted_counter < 255)
inserted_counter++;
if (!sdio_check_inserted() && !mounted && inserted_counter > 4) {
inserted_counter = 0;
res = f_mount(fs_ptr, "0:/", 1);
if (res == FR_OK) {
led_set(1, 1);
return true;
} else {
return false;
}
}
return mounted;
}
/** /**
* @brief Process the boot status structure in the safety (backup) RAM * @brief Process the boot status structure in the safety (backup) RAM
* Depending on the flags set there, this function will: * Depending on the flags set there, this function will:
@ -249,6 +216,9 @@ static inline void setup_system(void)
/** - Enable the ADC for PT1000 measurement */ /** - Enable the ADC for PT1000 measurement */
adc_pt1000_setup_meas(); adc_pt1000_setup_meas();
/** - Enable the misc CRC config monitor to supervise clock, systick and flash settings */
(void)safety_controller_set_crc_monitor(ERR_CRC_MON_MISC, SAFETY_CRC_MON_MISC_PW);
} }
/** /**
@ -286,6 +256,7 @@ int main(void)
shellmatta_handle_t shell_handle; shellmatta_handle_t shell_handle;
int menu_wait_request; int menu_wait_request;
uint64_t quarter_sec_timestamp = 0ULL; uint64_t quarter_sec_timestamp = 0ULL;
enum config_weight worst_safety_flag = SAFETY_FLAG_CONFIG_WEIGHT_NONE;
/** - Setup all the peripherals and external componets like LCD, EEPROM etc. and the safety controller */ /** - Setup all the peripherals and external componets like LCD, EEPROM etc. and the safety controller */
setup_system(); setup_system();
@ -301,8 +272,8 @@ int main(void)
/** - Print motd to shell */ /** - Print motd to shell */
shell_print_motd(shell_handle); shell_print_motd(shell_handle);
/** - Set the main cycle counter to 0 */ /** - Set the main cycle counter to 0 and activate the core cycle counter if available */
main_cycle_counter_init(); main_and_core_cycle_counter_init();
/** - Do a loop over the following */ /** - Do a loop over the following */
while (1) { while (1) {
@ -312,9 +283,9 @@ int main(void)
* it is tried to load it from SD card. * it is tried to load it from SD card.
*/ */
if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) { if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) {
led_set(1, 0); led_set(1u, 0);
sd_old = sd_card_mounted; sd_old = sd_card_mounted;
sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted); sd_card_mounted = mount_sd_card_if_avail(fs_ptr);
if (sd_card_mounted && !sd_old) { if (sd_card_mounted && !sd_old) {
adc_pt1000_get_resistance_calibration(NULL, NULL, &cal_active); adc_pt1000_get_resistance_calibration(NULL, NULL, &cal_active);
@ -325,6 +296,14 @@ int main(void)
} }
} }
/* Check if any flags are present, that disable the PID controller. Blink
* LED 0 in this case
*/
if (worst_safety_flag >= SAFETY_FLAG_CONFIG_WEIGHT_PID)
led_set(0u, led_get(0u) ? 0 : 1);
else
led_set(0u, 0);
quarter_sec_timestamp = systick_get_global_tick(); quarter_sec_timestamp = systick_get_global_tick();
} }
@ -338,7 +317,7 @@ int main(void)
temp_profile_executer_handle(); temp_profile_executer_handle();
/** - Handle the safety controller. This must be called! Otherwise a watchdog reset will occur */ /** - Handle the safety controller. This must be called! Otherwise a watchdog reset will occur */
safety_controller_handle(); worst_safety_flag = safety_controller_handle();
/** - If the Oven PID controller is running, we handle its sample function */ /** - If the Oven PID controller is running, we handle its sample function */
if (oven_pid_get_status() == OVEN_PID_RUNNING) if (oven_pid_get_status() == OVEN_PID_RUNNING)

View File

@ -78,5 +78,6 @@ void panic_mode(void)
} }
/* Let the watchdog do the rest */ /* Let the watchdog do the rest */
while (1); while (1)
;
} }

View File

@ -0,0 +1,31 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <reflow-controller/safety/flash-crc-struct.h>
#include <helper-macros/helper-macros.h>
const struct flash_crcs IN_SECTION(.flashcrc) crcs_in_flash = {
.start_magic = 0xA8BE53F9UL,
.crc_section_ccm_data = 0UL,
.crc_section_text = 0UL,
.crc_section_data = 0UL,
.crc_section_vectors = 0UL,
.end_magic = 0xFFA582FFUL,
};

View File

@ -0,0 +1,152 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <reflow-controller/safety/flash-crc.h>
#include <reflow-controller/safety/flash-crc-struct.h>
#include <reflow-controller/safety/safety-controller.h>
#include <stm-periph/crc-unit.h>
extern const uint32_t __ld_vectors_start;
extern const uint32_t __ld_vectors_end;
extern const uint32_t __ld_text_start;
extern const uint32_t __ld_text_end;
extern const uint32_t __ld_sdata_ccm;
extern const uint32_t __ld_edata_ccm;
extern const uint32_t __ld_load_ccm_data;
extern const uint32_t __ld_sdata;
extern const uint32_t __ld_edata;
extern const uint32_t __ld_load_data;
int flash_crc_trigger_check(void)
{
int ret = -1;
int res;
int any_err = 0;
uint32_t crc;
/* Perform CRC check over vector table */
res = flash_crc_calc_section(FLASH_CRC_VECTOR, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_VECTOR))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
any_err |= res;
/* Perform CRC check over text section */
res = flash_crc_calc_section(FLASH_CRC_TEXT, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_TEXT))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
any_err |= res;
/* Perform CRC check over data section */
res = flash_crc_calc_section(FLASH_CRC_DATA, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_DATA))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
any_err |= res;
/* Perform CRC check over ccm data section */
res = flash_crc_calc_section(FLASH_CRC_CCMDATA, &crc);
if (res || crc != flash_crc_get_expected_crc(FLASH_CRC_CCMDATA))
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
any_err |= res;
if (!any_err)
ret = 0;
return ret;
}
int flash_crc_calc_section(enum flash_crc_section sec, uint32_t *crc_result)
{
uint32_t len;
const uint32_t *startptr;
const uint32_t *endptr;
const uint32_t *load_addr = NULL;
if (!crc_result)
return -1002;
switch (sec) {
case FLASH_CRC_VECTOR:
startptr = &__ld_vectors_start;
endptr = &__ld_vectors_end;
break;
case FLASH_CRC_TEXT:
startptr = &__ld_text_start;
endptr = &__ld_text_end;
break;
case FLASH_CRC_DATA:
startptr = &__ld_sdata;
endptr = &__ld_edata;
load_addr = &__ld_load_data;
break;
case FLASH_CRC_CCMDATA:
startptr = &__ld_sdata_ccm;
endptr = &__ld_edata_ccm;
load_addr = &__ld_load_ccm_data;
break;
default:
return -1001;
}
len = (uint32_t)((void *)endptr - (void *)startptr);
if (!load_addr)
load_addr = startptr;
/* Not a multiple of 32bit words long. Cannot calculate CRC in this case! */
if (len % 4)
return -1;
/* Calculate word count */
len /= 4;
/* Reset CRC and calculate over data range */
crc_unit_reset();
crc_unit_input_array(load_addr, len);
*crc_result = crc_unit_get_crc();
return 0;
}
uint32_t flash_crc_get_expected_crc(enum flash_crc_section sec)
{
uint32_t crc;
switch (sec) {
case FLASH_CRC_VECTOR:
crc = crcs_in_flash.crc_section_vectors;
break;
case FLASH_CRC_TEXT:
crc = crcs_in_flash.crc_section_text;
break;
case FLASH_CRC_DATA:
crc = crcs_in_flash.crc_section_data;
break;
case FLASH_CRC_CCMDATA:
crc = crcs_in_flash.crc_section_ccm_data;
break;
default:
crc = 0xFFFFFFFFul;
break;
}
return crc;
}

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup safety-adc * @addtogroup safety-adc
@ -60,7 +60,8 @@ void safety_adc_init(void)
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN)); rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
if (hw_rev != HW_REV_V1_2) { if (hw_rev != HW_REV_V1_2) {
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK)); rcc_manager_enable_clock(&RCC->AHB1ENR,
BITMASK_TO_BITNO(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT_RCC_MASK));
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN); SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER &= MODER_DELETE(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN); SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PORT->MODER |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
} }
@ -72,7 +73,7 @@ void safety_adc_init(void)
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15; SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15;
/* Standard sequence. Measure all channels in one sequence */ /* Standard sequence. Measure all channels in one sequence */
SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20 ; SAFETY_ADC_ADC_PERIPHERAL->SQR1 = (SAFETY_ADC_NUM_OF_CHANNELS - 1) << 20;
SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SQR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SQR3 = 0UL;
@ -97,7 +98,8 @@ void safety_adc_init(void)
DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR; DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR;
DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions; DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions;
DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS; DMA2_Stream4->NDTR = SAFETY_ADC_NUM_OF_CHANNELS;
DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_EN; DMA2_Stream4->CR = DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC |
DMA_SxCR_TCIE | DMA_SxCR_EN;
NVIC_EnableIRQ(DMA2_Stream4_IRQn); NVIC_EnableIRQ(DMA2_Stream4_IRQn);
/* Enable ADC */ /* Enable ADC */
@ -175,7 +177,7 @@ void safety_adc_trigger_meas(void)
safety_adc_triggered = 1; safety_adc_triggered = 1;
} }
void DMA2_Stream4_IRQHandler() void DMA2_Stream4_IRQHandler(void)
{ {
uint32_t hisr; uint32_t hisr;

View File

@ -1,28 +1,29 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup safety-controller * @addtogroup safety-controller
* @{ * @{
*/ */
#include "stm32/stm32f407xx.h"
#include <reflow-controller/safety/safety-controller.h> #include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/safety/safety-config.h> #include <reflow-controller/safety/safety-config.h>
#include <reflow-controller/safety/watchdog.h> #include <reflow-controller/safety/watchdog.h>
@ -43,6 +44,7 @@
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <reflow-controller/temp-converter.h> #include <reflow-controller/temp-converter.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/safety/flash-crc.h>
#include <reflow-controller/periph-config/safety-adc-hwcfg.h> #include <reflow-controller/periph-config/safety-adc-hwcfg.h>
/** /**
@ -154,15 +156,6 @@ struct overtemp_config {
uint32_t crc; uint32_t crc;
}; };
struct flash_crcs {
uint32_t start_magic;
uint32_t crc_section_text;
uint32_t crc_section_data;
uint32_t crc_section_ccm_data;
uint32_t crc_section_vectors;
uint32_t end_magic;
};
struct crc_monitor_register { struct crc_monitor_register {
const volatile void *reg_addr; const volatile void *reg_addr;
uint32_t mask; uint32_t mask;
@ -171,9 +164,15 @@ struct crc_monitor_register {
#define CRC_MON_REGISTER_ENTRY(_addr, _mask, _size) {.reg_addr = &(_addr), .mask = (_mask), .size = (_size)} #define CRC_MON_REGISTER_ENTRY(_addr, _mask, _size) {.reg_addr = &(_addr), .mask = (_mask), .size = (_size)}
/**
* @brief Sentinel Element for crc monitor register list
*
*/
#define CRC_MON_REGISTER_SENTINEL {.reg_addr = NULL, .mask = 0, .size = 0}
struct crc_mon { struct crc_mon {
/** /**
* @brief Array of registers to monitor. Terminated by NULL sentinel! * @brief Array of registers to monitor. Terminated by NULL sentinel @ref CRC_MON_REGISTER_SENTINEL
*/ */
const struct crc_monitor_register *registers; const struct crc_monitor_register *registers;
const enum crc_monitor monitor; const enum crc_monitor monitor;
@ -212,11 +211,12 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA), ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA),
ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC), ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC),
ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC), ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC),
ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MISC),
}; };
/** /**
* @brief All timing monitors * @brief All timing monitors
*/ */
static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = { static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = {
TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID), TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID),
TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC),
@ -298,8 +298,8 @@ static const struct crc_monitor_register meas_adc_crc_regs[] = {
ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 | ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 |
ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4), ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4),
CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 | CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 |
ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4),
{NULL, 0, 0} CRC_MON_REGISTER_SENTINEL
}; };
static const struct crc_monitor_register safety_adc_crc_regs[] = { static const struct crc_monitor_register safety_adc_crc_regs[] = {
@ -314,12 +314,28 @@ static const struct crc_monitor_register safety_adc_crc_regs[] = {
ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 | ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 |
ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4), ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4),
CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 | CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 |
ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4),
{NULL, 0, 0} CRC_MON_REGISTER_ENTRY(RCC->APB2ENR, SAFETY_ADC_ADC_RCC_MASK, 4),
CRC_MON_REGISTER_SENTINEL
}; };
static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = static const struct crc_monitor_register misc_config_crc_regs[] = {
{ /* Check clock tree settings */
CRC_MON_REGISTER_ENTRY(RCC->CR, RCC_CR_PLLON | RCC_CR_HSEON | RCC_CR_PLLI2SON | RCC_CR_HSION, 4),
CRC_MON_REGISTER_ENTRY(RCC->CSR, RCC_CSR_LSION, 4),
CRC_MON_REGISTER_ENTRY(RCC->CFGR, RCC_CFGR_SWS | RCC_CFGR_HPRE | RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2, 4),
CRC_MON_REGISTER_ENTRY(RCC->PLLCFGR, RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLQ | RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLP | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLM , 4),
/* Check Flash settings */
CRC_MON_REGISTER_ENTRY(FLASH->ACR, FLASH_ACR_LATENCY | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_PRFTEN, 4),
/* Check vector table offset */
CRC_MON_REGISTER_ENTRY(SCB->VTOR, 0xFFFFFFFF, 4),
/* Check system tick configuration */
CRC_MON_REGISTER_ENTRY(SysTick->CTRL, SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk, 4),
CRC_MON_REGISTER_ENTRY(SysTick->LOAD, 0xFFFFFFFF, 4),
CRC_MON_REGISTER_SENTINEL
};
static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = {
{ {
.registers = meas_adc_crc_regs, .registers = meas_adc_crc_regs,
.monitor = ERR_CRC_MON_MEAS_ADC, .monitor = ERR_CRC_MON_MEAS_ADC,
@ -340,6 +356,16 @@ static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] =
.last_crc = 0UL, .last_crc = 0UL,
.active = false, .active = false,
}, },
{
.registers = misc_config_crc_regs,
.monitor = ERR_CRC_MON_MISC,
.pw = SAFETY_CRC_MON_MISC_PW,
.flag_to_set = ERR_FLAG_CFG_CRC_MISC,
.expected_crc = 0UL,
.expected_crc_inv = ~0UL,
.last_crc = 0UL,
.active = false,
}
}; };
/** /**
@ -360,16 +386,22 @@ static void set_overtemp_config(float over_temperature)
safety_controller_overtemp_config.crc_dummy_seed = 0xA4F5C7E6UL; safety_controller_overtemp_config.crc_dummy_seed = 0xA4F5C7E6UL;
safety_controller_overtemp_config.overtemp_deg_celsius = over_temperature; safety_controller_overtemp_config.overtemp_deg_celsius = over_temperature;
safety_controller_overtemp_config.overtemp_equiv_resistance = resistance; safety_controller_overtemp_config.overtemp_equiv_resistance = resistance;
crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, wordsize_of(struct overtemp_config) - 1); crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config,
wordsize_of(struct overtemp_config) - 1);
safety_controller_overtemp_config.crc = crc_unit_get_crc(); safety_controller_overtemp_config.crc = crc_unit_get_crc();
} }
/**
* @brief Check the overtemperature config structure's CRC
* @return true if check failed. false if CRC check successful
*/
static bool over_temperature_config_check(void) static bool over_temperature_config_check(void)
{ {
if (safety_controller_overtemp_config.crc_dummy_seed != 0xA4F5C7E6UL) if (safety_controller_overtemp_config.crc_dummy_seed != 0xA4F5C7E6UL)
return true; return true;
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config, wordsize_of(struct overtemp_config) - 1); crc_unit_input_array((const uint32_t *)&safety_controller_overtemp_config,
wordsize_of(struct overtemp_config) - 1);
if (crc_unit_get_crc() != safety_controller_overtemp_config.crc) if (crc_unit_get_crc() != safety_controller_overtemp_config.crc)
return true; return true;
@ -442,7 +474,7 @@ static int flag_weight_table_crc_check(void)
static int flag_persistence_table_crc_check(void) static int flag_persistence_table_crc_check(void)
{ {
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_persistencies, wordsize_of(flag_persistencies)); crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies));
if (crc_unit_get_crc() != flag_persistencies_crc) if (crc_unit_get_crc() != flag_persistencies_crc)
return -1; return -1;
@ -519,9 +551,8 @@ static int safety_controller_check_crc_monitors(void)
if (crc_monitor_calculate_crc(mon->registers, &crc)) if (crc_monitor_calculate_crc(mon->registers, &crc))
return -1; return -1;
if (mon->expected_crc != crc || ~mon->expected_crc_inv != crc) { if (mon->expected_crc != crc || ~mon->expected_crc_inv != crc)
safety_controller_report_error(mon->flag_to_set); safety_controller_report_error(mon->flag_to_set);
}
mon->last_crc = crc; mon->last_crc = crc;
} }
@ -548,7 +579,7 @@ static void init_safety_flag_weight_table_from_default(void)
} }
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights));
flag_weight_crc = crc_unit_get_crc(); flag_weight_crc = crc_unit_get_crc();
} }
@ -608,16 +639,14 @@ static void apply_config_overrides(void)
case SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT: case SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT:
flag_enum = flag_no_to_flag_enum(override.entry.weight_override.flag); flag_enum = flag_no_to_flag_enum(override.entry.weight_override.flag);
flag = find_error_flag(flag_enum); flag = find_error_flag(flag_enum);
if (flag && flag->weight) { if (flag && flag->weight)
flag->weight->weight = override.entry.weight_override.weight; flag->weight->weight = override.entry.weight_override.weight;
}
break; break;
case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE: case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE:
flag_enum = flag_no_to_flag_enum(override.entry.persistence_override.flag); flag_enum = flag_no_to_flag_enum(override.entry.persistence_override.flag);
flag = find_error_flag(flag_enum); flag = find_error_flag(flag_enum);
if (flag && flag->persistence) { if (flag && flag->persistence)
flag->persistence->persistence = override.entry.persistence_override.persistence; flag->persistence->persistence = override.entry.persistence_override.persistence;
}
break; break;
default: default:
continue; continue;
@ -629,7 +658,7 @@ static void apply_config_overrides(void)
crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies)); crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies));
flag_persistencies_crc = crc_unit_get_crc(); flag_persistencies_crc = crc_unit_get_crc();
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights));
flag_weight_crc = crc_unit_get_crc(); flag_weight_crc = crc_unit_get_crc();
} }
@ -647,11 +676,10 @@ static bool error_flag_get_status(const volatile struct error_flag *flag)
if (!flag) if (!flag)
return true; return true;
if (flag->error_state == flag->error_state_inv) { if (flag->error_state == flag->error_state_inv)
return true; return true;
} else { else
return flag->error_state; return flag->error_state;
}
} }
/** /**
@ -693,7 +721,7 @@ static volatile struct timing_mon *find_timing_mon(enum timing_monitor mon)
/** /**
* @brief Check the active timing monitors and set the appropriate flags in case of an error. * @brief Check the active timing monitors and set the appropriate flags in case of an error.
*/ */
static void safety_controller_process_active_timing_mons() static void safety_controller_process_active_timing_mons(void)
{ {
uint32_t i; uint32_t i;
volatile struct timing_mon *current_mon; volatile struct timing_mon *current_mon;
@ -716,7 +744,8 @@ static void safety_controller_process_active_timing_mons()
* Process the analog and timing monitors and set the relevant flags in case of a monitor outside its limits. * Process the analog and timing monitors and set the relevant flags in case of a monitor outside its limits.
* Furthermore, the PT1000 resistance is checked for overtemperature * Furthermore, the PT1000 resistance is checked for overtemperature
* *
* The checking of the analog monitors will only be armed after a startup delay of 1000 ms to allow the values to stabilize. * The checking of the analog monitors will only be armed after a startup delay of 1000 ms to
* allow the values to stabilize.
*/ */
static void safety_controller_process_monitor_checks(void) static void safety_controller_process_monitor_checks(void)
{ {
@ -731,21 +760,18 @@ static void safety_controller_process_monitor_checks(void)
if (startup_completed) { if (startup_completed) {
analog_mon_count = safety_controller_get_analog_monitor_count(); analog_mon_count = safety_controller_get_analog_monitor_count();
for (idx = 0; idx < analog_mon_count; idx++) { for (idx = 0; idx < analog_mon_count; idx++)
if (safety_controller_get_analog_mon_by_index(idx, &amon_info)) { if (safety_controller_get_analog_mon_by_index(idx, &amon_info)) {
panic_mode(); panic_mode();
}
if (amon_info.status != ANALOG_MONITOR_OK) { if (amon_info.status != ANALOG_MONITOR_OK)
safety_controller_report_error(amon_info.associated_flag); safety_controller_report_error(amon_info.associated_flag);
}
} }
} }
adc_pt1000_get_current_resistance(&pt1000_val); adc_pt1000_get_current_resistance(&pt1000_val);
if (pt1000_val > safety_controller_overtemp_config.overtemp_equiv_resistance) { if (pt1000_val > safety_controller_overtemp_config.overtemp_equiv_resistance)
safety_controller_report_error(ERR_FLAG_OVERTEMP); safety_controller_report_error(ERR_FLAG_OVERTEMP);
}
(void)safety_controller_check_crc_monitors(); (void)safety_controller_check_crc_monitors();
@ -779,7 +805,7 @@ static int report_error(enum safety_flag flag, uint32_t key, bool prevent_error_
flags[i].error_state_inv = !flags[i].error_state; flags[i].error_state_inv = !flags[i].error_state;
flags[i].key = key; flags[i].key = key;
if ((check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) || if ((check_flag_persistent(&flags[i]) && !old_state && !prevent_error_mem_enty) ||
get_flag_weight(&flags[i]) == SAFETY_FLAG_CONFIG_WEIGHT_PANIC) { get_flag_weight(&flags[i]) == SAFETY_FLAG_CONFIG_WEIGHT_PANIC) {
err_mem_entry.counter = 1; err_mem_entry.counter = 1;
err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag); err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag);
@ -820,9 +846,8 @@ void safety_controller_report_timing(enum timing_monitor monitor)
tim = find_timing_mon(monitor); tim = find_timing_mon(monitor);
if (tim) { if (tim) {
if (tim->enabled) { if (tim->enabled) {
if (!systick_ticks_have_passed(tim->last, tim->min_delta) && tim->min_delta > 0U) { if (!systick_ticks_have_passed(tim->last, tim->min_delta) && tim->min_delta > 0U)
safety_controller_report_error(tim->associated_flag); safety_controller_report_error(tim->associated_flag);
}
} }
tim->calculated_delta = timestamp - tim->last; tim->calculated_delta = timestamp - tim->last;
@ -870,9 +895,8 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags)
for (idx = 0; idx < count; idx++) { for (idx = 0; idx < count; idx++) {
res = safety_memory_get_error_entry(idx, &entry); res = safety_memory_get_error_entry(idx, &entry);
if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG) { if (entry.type == SAFETY_MEMORY_ERR_ENTRY_FLAG)
return_flags |= flag_no_to_flag_enum(entry.flag_num); return_flags |= flag_no_to_flag_enum(entry.flag_num);
}
} }
*flags = return_flags; *flags = return_flags;
@ -884,11 +908,12 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags)
* *
* The external harware watchdog has to be periodically reset or it will reset hte controller. * The external harware watchdog has to be periodically reset or it will reset hte controller.
* Because debugging is not possible, when the watchdog is active, it is only activated, if the application is * Because debugging is not possible, when the watchdog is active, it is only activated, if the application is
* compiled in release mode. Any interruption of the main programm will then trigger the internal and/or the external watchdog. * compiled in release mode. Any interruption of the main programm will then trigger the internal and/or
* the external watchdog.
* *
* @note When enabled, execute the @ref external_watchdog_toggle function to reset the external watchdog. * @note When enabled, execute the @ref external_watchdog_toggle function to reset the external watchdog.
*/ */
static void safety_controller_init_external_watchdog() static void safety_controller_init_external_watchdog(void)
{ {
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_EXT_WATCHDOG_RCC_MASK)); rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SAFETY_EXT_WATCHDOG_RCC_MASK));
SAFETY_EXT_WATCHDOG_PORT->MODER &= MODER_DELETE(SAFETY_EXT_WATCHDOG_PIN); SAFETY_EXT_WATCHDOG_PORT->MODER &= MODER_DELETE(SAFETY_EXT_WATCHDOG_PIN);
@ -899,7 +924,7 @@ static void safety_controller_init_external_watchdog()
__DSB(); __DSB();
} }
void safety_controller_init() void safety_controller_init(void)
{ {
enum safety_memory_state found_memory_state; enum safety_memory_state found_memory_state;
enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG; enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG;
@ -916,7 +941,7 @@ void safety_controller_init()
/* This is usually done by the safety memory already. But, since this module also uses the CRC... */ /* This is usually done by the safety memory already. But, since this module also uses the CRC... */
crc_unit_init(); crc_unit_init();
safety_controller_trigger_flash_crc_check(); flash_crc_trigger_check();
stack_check_init_corruption_detect_area(); stack_check_init_corruption_detect_area();
hw_rev = get_pcb_hardware_version(); hw_rev = get_pcb_hardware_version();
@ -948,7 +973,7 @@ void safety_controller_init()
MEAS_ADC_SAFETY_FLAG_KEY); MEAS_ADC_SAFETY_FLAG_KEY);
safety_adc_init(); safety_adc_init();
watchdog_setup(WATCHDOG_PRESCALER); (void)watchdog_setup(WATCHDOG_PRESCALER, WATCHDOG_RELOAD_VALUE);
if (rcc_manager_get_reset_cause(false) & RCC_RESET_SOURCE_IWDG) if (rcc_manager_get_reset_cause(false) & RCC_RESET_SOURCE_IWDG)
safety_controller_report_error(ERR_FLAG_WTCHDG_FIRED); safety_controller_report_error(ERR_FLAG_WTCHDG_FIRED);
@ -967,7 +992,7 @@ void safety_controller_init()
* 1) Checking the remaining free space at the moment between stack pointer and top of heap. * 1) Checking the remaining free space at the moment between stack pointer and top of heap.
* 2) Checking The CRC of the corruption detect area between heap and stack * 2) Checking The CRC of the corruption detect area between heap and stack
*/ */
static void safety_controller_check_stack() static void safety_controller_check_stack(void)
{ {
int32_t free_stack; int32_t free_stack;
@ -975,18 +1000,17 @@ static void safety_controller_check_stack()
if (free_stack < SAFETY_MIN_STACK_FREE) if (free_stack < SAFETY_MIN_STACK_FREE)
safety_controller_report_error(ERR_FLAG_STACK); safety_controller_report_error(ERR_FLAG_STACK);
if (stack_check_corruption_detect_area()) { if (stack_check_corruption_detect_area())
safety_controller_report_error(ERR_FLAG_STACK); safety_controller_report_error(ERR_FLAG_STACK);
}
} }
/** /**
* @brief Handle the Safety ADC * @brief Handle the Safety ADC
* *
* This function handles the safety ADC. * This function handles the safety ADC.
* If the safety ADC ius not executing a measurment and the time since the last measurement has * If the safety ADC is not executing a measurment and the time since the last measurement has
* passed @ref SAFETY_CONTROLLER_ADC_DELAY_MS, the safety ADC is retriggered and will automatically perform a measurement * passed @ref SAFETY_CONTROLLER_ADC_DELAY_MS, the safety ADC is retriggered and will automatically perform a
* on all of its channels. * measurement on all of its channels.
* When called again, this function will retrieve the data from the safety ADC and converts it into the * When called again, this function will retrieve the data from the safety ADC and converts it into the
* appropriate analog values for the analog value monitors. * appropriate analog values for the analog value monitors.
* *
@ -995,7 +1019,7 @@ static void safety_controller_check_stack()
* *
* The channels, the ssafety ADC will convert is defined in its header file using the define @ref SAFETY_ADC_CHANNELS. * The channels, the ssafety ADC will convert is defined in its header file using the define @ref SAFETY_ADC_CHANNELS.
*/ */
static void safety_controller_handle_safety_adc() static void safety_controller_handle_safety_adc(void)
{ {
static uint64_t last_result_timestamp = 0; static uint64_t last_result_timestamp = 0;
const uint16_t *channels; const uint16_t *channels;
@ -1066,9 +1090,8 @@ static void safety_controller_handle_memory_checks(void)
/* Check the safety memory */ /* Check the safety memory */
if (safety_memory_check()) { if (safety_memory_check()) {
(void)safety_memory_reinit(&found_state); (void)safety_memory_reinit(&found_state);
if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY)
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
}
} }
/* If flag weight table is broken, reinit to default and set flag */ /* If flag weight table is broken, reinit to default and set flag */
@ -1078,7 +1101,7 @@ static void safety_controller_handle_memory_checks(void)
} }
/* If persistence table is broken, reinit to default and set flag */ /* If persistence table is broken, reinit to default and set flag */
if(flag_persistence_table_crc_check()) { if (flag_persistence_table_crc_check()) {
safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_TAB_CORRUPT);
init_safety_flag_persistencies_from_default(); init_safety_flag_persistencies_from_default();
} }
@ -1097,7 +1120,7 @@ static void safety_controller_handle_memory_checks(void)
* If the systick stays constant for more than 1000 calls of this function, * If the systick stays constant for more than 1000 calls of this function,
* the @ref ERR_FLAG_SYSTICK flag is set. * the @ref ERR_FLAG_SYSTICK flag is set.
*/ */
static void safety_controller_do_systick_checking() static void safety_controller_do_systick_checking(void)
{ {
static uint64_t last_systick; static uint64_t last_systick;
static uint32_t same_systick_cnt = 0UL; static uint32_t same_systick_cnt = 0UL;
@ -1121,22 +1144,29 @@ static void safety_controller_do_systick_checking()
* is set, the appropriate action defined by the flag weight is executed. * is set, the appropriate action defined by the flag weight is executed.
* @note If no flag weigth is present for a given error flag, it is treated as the most critical category * @note If no flag weigth is present for a given error flag, it is treated as the most critical category
* (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC) * (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
*
* @returns Worst config weight set
*/ */
static void safety_controller_handle_weighted_flags() static enum config_weight safety_controller_handle_weighted_flags(void)
{ {
uint32_t flag_index; uint32_t flag_index;
volatile struct error_flag *current_flag; volatile struct error_flag *current_flag;
enum config_weight flag_weigth; enum config_weight flag_weigth;
enum config_weight worst = SAFETY_FLAG_CONFIG_WEIGHT_NONE;
for (flag_index = 0u; flag_index < COUNT_OF(flags); flag_index++) { for (flag_index = 0u; flag_index < COUNT_OF(flags); flag_index++) {
current_flag = &flags[flag_index]; current_flag = &flags[flag_index];
/* Continue if this flag is not set */ /* Continue if this flag is not set */
if (!error_flag_get_status(current_flag)) { if (!error_flag_get_status(current_flag))
continue; continue;
}
flag_weigth = get_flag_weight(current_flag); flag_weigth = get_flag_weight(current_flag);
/* Override the worst flag weigt set, if it is worse than the previous ones */
if (flag_weigth > worst)
worst = flag_weigth;
switch (flag_weigth) { switch (flag_weigth) {
case SAFETY_FLAG_CONFIG_WEIGHT_NONE: case SAFETY_FLAG_CONFIG_WEIGHT_NONE:
break; break;
@ -1152,18 +1182,20 @@ static void safety_controller_handle_weighted_flags()
} }
} }
return worst;
} }
#ifndef DEBUGBUILD #ifndef DEBUGBUILD
static void external_watchdog_toggle() static void external_watchdog_toggle(void)
{ {
SAFETY_EXT_WATCHDOG_PORT->ODR ^= (1<<SAFETY_EXT_WATCHDOG_PIN); SAFETY_EXT_WATCHDOG_PORT->ODR ^= (1<<SAFETY_EXT_WATCHDOG_PIN);
} }
#endif #endif
int safety_controller_handle() enum config_weight safety_controller_handle(void)
{ {
int ret = 0; enum config_weight worst_weight_set;
#ifndef DEBUGBUILD #ifndef DEBUGBUILD
static uint32_t watchdog_counter = 0UL; static uint32_t watchdog_counter = 0UL;
#endif #endif
@ -1173,9 +1205,10 @@ int safety_controller_handle()
safety_controller_handle_memory_checks(); safety_controller_handle_memory_checks();
safety_controller_do_systick_checking(); safety_controller_do_systick_checking();
safety_controller_process_monitor_checks(); safety_controller_process_monitor_checks();
safety_controller_handle_weighted_flags(); worst_weight_set = safety_controller_handle_weighted_flags();
ret |= watchdog_ack(WATCHDOG_MAGIC_KEY); /* Ignore error here. Will trigger restart anyway */
(void)watchdog_ack(WATCHDOG_MAGIC_KEY);
#ifndef DEBUGBUILD #ifndef DEBUGBUILD
if (get_pcb_hardware_version() != HW_REV_V1_2) { if (get_pcb_hardware_version() != HW_REV_V1_2) {
@ -1186,7 +1219,8 @@ int safety_controller_handle()
} }
} }
#endif #endif
return (ret ? -1 : 0);
return worst_weight_set;
} }
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable) int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable)
@ -1273,9 +1307,8 @@ int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key)
int ret = -1; int ret = -1;
volatile struct error_flag *found_flag; volatile struct error_flag *found_flag;
if (!is_power_of_two(flag)) { if (!is_power_of_two(flag))
return -1001; return -1001;
}
found_flag = find_error_flag(flag); found_flag = find_error_flag(flag);
if (found_flag) { if (found_flag) {
@ -1306,17 +1339,17 @@ bool safety_controller_get_flags_by_mask(enum safety_flag mask)
return ret; return ret;
} }
uint32_t safety_controller_get_flag_count() uint32_t safety_controller_get_flag_count(void)
{ {
return COUNT_OF(flags); return COUNT_OF(flags);
} }
uint32_t safety_controller_get_analog_monitor_count() uint32_t safety_controller_get_analog_monitor_count(void)
{ {
return COUNT_OF(analog_mons); return COUNT_OF(analog_mons);
} }
uint32_t safety_controller_get_timing_monitor_count() uint32_t safety_controller_get_timing_monitor_count(void)
{ {
return COUNT_OF(timings); return COUNT_OF(timings);
} }
@ -1423,9 +1456,8 @@ int safety_controller_get_timing_mon_by_index(uint32_t index, struct timing_moni
if (!info) if (!info)
return -1002; return -1002;
if (index >= COUNT_OF(timings)) { if (index >= COUNT_OF(timings))
return -1001; return -1001;
}
mon = &timings[index]; mon = &timings[index];
@ -1449,99 +1481,6 @@ float safety_controller_get_overtemp_limit(void)
return safety_controller_overtemp_config.overtemp_deg_celsius; return safety_controller_overtemp_config.overtemp_deg_celsius;
} }
extern const uint32_t __ld_vectors_start;
extern const uint32_t __ld_vectors_end;
extern const uint32_t __ld_text_start;
extern const uint32_t __ld_text_end;
extern const uint32_t __ld_sdata_ccm;
extern const uint32_t __ld_edata_ccm;
extern const uint32_t __ld_load_ccm_data;
extern const uint32_t __ld_sdata;
extern const uint32_t __ld_edata;
extern const uint32_t __ld_load_data;
int safety_controller_trigger_flash_crc_check()
{
/* This structs needs to be volatile!!
* This prevents the compiler form optimizing out the reads to the crcs which will be patched in later by
* a separate python script!
*/
static volatile const struct flash_crcs IN_SECTION(.flashcrc) crcs_in_flash =
{
.start_magic = 0xA8BE53F9UL,
.crc_section_ccm_data = 0UL,
.crc_section_text = 0UL,
.crc_section_data = 0UL,
.crc_section_vectors = 0UL,
.end_magic = 0xFFA582FFUL,
};
int ret = -1;
uint32_t len;
uint32_t crc;
/* Perform CRC check over vector table */
len = (uint32_t)((void *)&__ld_vectors_end - (void *)&__ld_vectors_start);
if (len % 4) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
} else {
len /= 4;
crc_unit_reset();
crc_unit_input_array(&__ld_vectors_start, len);
crc = crc_unit_get_crc();
if (crc != crcs_in_flash.crc_section_vectors) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
}
}
/* Perform CRC check over text section */
len = (uint32_t)((void *)&__ld_text_end - (void *)&__ld_text_start);
if (len % 4) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
} else {
len /= 4;
crc_unit_reset();
crc_unit_input_array(&__ld_text_start, len);
crc = crc_unit_get_crc();
if (crc != crcs_in_flash.crc_section_text) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
}
}
/* Perform CRC check over data section */
len = (uint32_t)((void *)&__ld_edata - (void *)&__ld_sdata);
if (len % 4) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
} else {
len /= 4;
crc_unit_reset();
crc_unit_input_array(&__ld_load_data, len);
crc = crc_unit_get_crc();
if (crc != crcs_in_flash.crc_section_data) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
}
}
/* Perform CRC check over ccm data section */
len = (uint32_t)((void *)&__ld_edata_ccm - (void *)&__ld_sdata_ccm);
if (len % 4) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
} else {
len /= 4;
crc_unit_reset();
crc_unit_input_array(&__ld_load_ccm_data, len);
crc = crc_unit_get_crc();
if (crc != crcs_in_flash.crc_section_ccm_data) {
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
}
}
ret = 0;
return ret;
}
int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password) int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password)
{ {
uint32_t i; uint32_t i;

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/safety/safety-memory.h> #include <reflow-controller/safety/safety-memory.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
@ -99,7 +99,8 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he
res = 0; res = 0;
if (header->boot_status_offset < wordsize_of(struct safety_memory_header)) if (header->boot_status_offset < wordsize_of(struct safety_memory_header))
res++; res++;
if (header->config_overrides_offset < header->boot_status_offset + wordsize_of(struct safety_memory_boot_status)) if (header->config_overrides_offset < header->boot_status_offset +
wordsize_of(struct safety_memory_boot_status))
res++; res++;
if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT) if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT)
res++; res++;
@ -107,7 +108,8 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he
res++; res++;
if (header->err_memory_offset < header->firmware_update_filename + (SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE / 4)) if (header->err_memory_offset < header->firmware_update_filename + (SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE / 4))
res++; res++;
if (header->err_memory_end >= backup_ram_get_size_in_words() || header->err_memory_end < header->err_memory_offset) if (header->err_memory_end >= backup_ram_get_size_in_words() ||
header->err_memory_end < header->err_memory_offset)
res++; res++;
if (res) { if (res) {
@ -148,7 +150,7 @@ static void safety_memory_write_new_header(void)
safety_memory_write_and_patch_header(&header); safety_memory_write_and_patch_header(&header);
} }
static int safety_memory_check_crc() static int safety_memory_check_crc(void)
{ {
struct safety_memory_header header; struct safety_memory_header header;
enum safety_memory_state state = safety_memory_get_header(&header); enum safety_memory_state state = safety_memory_get_header(&header);
@ -181,7 +183,7 @@ static int safety_memory_check_crc()
return 0; return 0;
} }
static int safety_memory_gen_crc() static int safety_memory_gen_crc(void)
{ {
struct safety_memory_header header; struct safety_memory_header header;
uint32_t word_addr; uint32_t word_addr;
@ -268,9 +270,8 @@ int safety_memory_get_boot_status(struct safety_memory_boot_status *status)
if (!status) if (!status)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (safety_memory_check_crc()) if (safety_memory_check_crc())
return -2001; return -2001;
@ -289,9 +290,8 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status
if (!status) if (!status)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (safety_memory_check_crc()) if (safety_memory_check_crc())
return -2001; return -2001;
@ -304,7 +304,7 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status
return 0; return 0;
} }
static int safety_memory_check_error_entries() static int safety_memory_check_error_entries(void)
{ {
struct safety_memory_header header; struct safety_memory_header header;
uint32_t addr; uint32_t addr;
@ -312,9 +312,8 @@ static int safety_memory_check_error_entries()
int ret = 0; int ret = 0;
int res; int res;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
for (addr = header.err_memory_offset; addr < header.err_memory_end; addr++) { for (addr = header.err_memory_offset; addr < header.err_memory_end; addr++) {
res = backup_ram_get_data(addr, &data, 1UL); res = backup_ram_get_data(addr, &data, 1UL);
@ -340,9 +339,8 @@ int safety_memory_get_error_entry_count(uint32_t *count)
if (!count) if (!count)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
*count = header.err_memory_end - header.err_memory_offset; *count = header.err_memory_end - header.err_memory_offset;
@ -354,9 +352,8 @@ int safety_memory_check(void)
int res; int res;
res = safety_memory_check_crc(); res = safety_memory_check_crc();
if (!res) { if (!res)
res |= safety_memory_check_error_entries(); res |= safety_memory_check_error_entries();
}
return -!!res; return -!!res;
} }
@ -372,9 +369,8 @@ int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry
if (!entry) if (!entry)
return -1001; return -1001;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
err_mem_count = header.err_memory_end - header.err_memory_offset; err_mem_count = header.err_memory_end - header.err_memory_offset;
if (idx < err_mem_count && err_mem_count > 0) { if (idx < err_mem_count && err_mem_count > 0) {
@ -410,9 +406,8 @@ int safety_memory_insert_error_entry(struct error_memory_entry *entry)
input_data = error_memory_entry_to_word(entry); input_data = error_memory_entry_to_word(entry);
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (entry->type == SAFETY_MEMORY_ERR_ENTRY_NOP) { if (entry->type == SAFETY_MEMORY_ERR_ENTRY_NOP) {
/* Append to end */ /* Append to end */
@ -510,9 +505,8 @@ int safety_memory_insert_config_override(struct config_override *config_override
int res; int res;
int ret = -3; int ret = -3;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (header.config_overrides_len == 0) if (header.config_overrides_len == 0)
return -1; return -1;
@ -550,9 +544,8 @@ int safety_memory_get_config_override_count(uint32_t *count)
*count = 0UL; *count = 0UL;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (header.config_overrides_len == 0) if (header.config_overrides_len == 0)
return 0; return 0;
@ -582,18 +575,15 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf
if (!config_override) if (!config_override)
return -1002; return -1002;
if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (safety_memory_get_header(&header) != SAFETY_MEMORY_INIT_VALID_MEMORY)
return -2000; return -2000;
}
if (idx >= header.config_overrides_len) { if (idx >= header.config_overrides_len)
return -1001; return -1001;
}
res = backup_ram_get_data(header.config_overrides_offset + idx, &data, 1UL); res = backup_ram_get_data(header.config_overrides_offset + idx, &data, 1UL);
if (res) { if (res)
return -1; return -1;
}
switch (data & 0xFF) { switch (data & 0xFF) {
case 0xA2: case 0xA2:
@ -649,8 +639,8 @@ int safety_memory_get_update_filename(char *filename, size_t *outlen)
{ {
struct safety_memory_header header; struct safety_memory_header header;
unsigned int i; unsigned int i;
volatile char *ptr;
size_t len = 0u; size_t len = 0u;
volatile char *ptr;
/* If filename and outlen are both NULL, we don't do anything */ /* If filename and outlen are both NULL, we don't do anything */
if (!filename && !outlen) if (!filename && !outlen)
@ -696,9 +686,9 @@ int safety_memory_set_update_filename(const char *filename)
ram_ptr = backup_ram_get_base_ptr(); ram_ptr = backup_ram_get_base_ptr();
ram_ptr += header.firmware_update_filename * 4; ram_ptr += header.firmware_update_filename * 4;
for (i = 0u; i < len; i++) { for (i = 0u; i < len; i++)
ram_ptr[i] = filename[i]; ram_ptr[i] = filename[i];
}
ram_ptr[i] = 0; ram_ptr[i] = 0;
ret = safety_memory_gen_crc(); ret = safety_memory_gen_crc();

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/safety/stack-check.h> #include <reflow-controller/safety/stack-check.h>
#include <stdint.h> #include <stdint.h>
@ -26,7 +26,7 @@
extern char __ld_top_of_stack; extern char __ld_top_of_stack;
extern char __ld_end_stack; extern char __ld_end_stack;
int32_t stack_check_get_usage() int32_t stack_check_get_usage(void)
{ {
uint32_t stack_top; uint32_t stack_top;
uint32_t stack_ptr; uint32_t stack_ptr;
@ -37,7 +37,7 @@ int32_t stack_check_get_usage()
return stack_top - stack_ptr; return stack_top - stack_ptr;
} }
int32_t stack_check_get_free() int32_t stack_check_get_free(void)
{ {
uint32_t upper_heap_boundary; uint32_t upper_heap_boundary;
uint32_t stack_ptr; uint32_t stack_ptr;
@ -102,9 +102,6 @@ int stack_check_corruption_detect_area(void)
&__ld_start_stack_corruption_detect_area; &__ld_start_stack_corruption_detect_area;
crc_unit_reset(); crc_unit_reset();
crc_unit_input_array(&__ld_start_stack_corruption_detect_area, area_size_in_words); crc_unit_input_array(&__ld_start_stack_corruption_detect_area, area_size_in_words);
if (crc_unit_get_crc() == 0UL) {
return 0; return crc_unit_get_crc() == 0UL ? 0 : -1;
} else {
return -1;
}
} }

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @addtogroup watchdog * @addtogroup watchdog
@ -42,52 +42,63 @@
*/ */
#define STM32_WATCHDOG_REGISTER_ACCESS_KEY 0x5555 #define STM32_WATCHDOG_REGISTER_ACCESS_KEY 0x5555
int watchdog_setup(uint8_t prescaler) int watchdog_setup(uint16_t prescaler, uint16_t reload_value)
{ {
uint32_t prescaler_reg_val; uint32_t prescaler_reg_val;
int ret = 0;
/** - Activate the LSI oscillator */ /** - Activate the LSI oscillator */
RCC->CSR |= RCC_CSR_LSION; RCC->CSR |= RCC_CSR_LSION;
__DSB(); __DSB();
/** - Wait for the oscillator to be ready */ /** - Wait for the oscillator to be ready */
while (!(RCC->CSR & RCC_CSR_LSIRDY)); while (!(RCC->CSR & RCC_CSR_LSIRDY))
;
if (prescaler == 4U) if (prescaler == 4U) {
prescaler_reg_val = 0UL; prescaler_reg_val = 0UL;
else if (prescaler == 8U) } else if (prescaler == 8U) {
prescaler_reg_val = 1UL; prescaler_reg_val = 1UL;
else if (prescaler == 16U) } else if (prescaler == 16U) {
prescaler_reg_val = 2UL; prescaler_reg_val = 2UL;
else if (prescaler == 32U) } else if (prescaler == 32U) {
prescaler_reg_val = 3UL; prescaler_reg_val = 3UL;
else if (prescaler == 64U) } else if (prescaler == 64U) {
prescaler_reg_val = 4UL; prescaler_reg_val = 4UL;
else if (prescaler == 128U) } else if (prescaler == 128U) {
prescaler_reg_val = 5UL; prescaler_reg_val = 5UL;
else } else if (prescaler == 256U) {
prescaler_reg_val = 6UL; prescaler_reg_val = 6UL;
} else {
prescaler_reg_val = 6UL;
ret = -1;
}
/** - (De)activate the watchdog during debug access according to @ref WATCHDOG_HALT_DEBUG */ /** - (De)activate the watchdog during debug access according to @ref WATCHDOG_HALT_DEBUG */
if (WATCHDOG_HALT_DEBUG) { if (WATCHDOG_HALT_DEBUG)
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP; DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP;
} else { else
DBGMCU->APB1FZ &= ~DBGMCU_APB1_FZ_DBG_IWDG_STOP; DBGMCU->APB1FZ &= ~DBGMCU_APB1_FZ_DBG_IWDG_STOP;
}
/** - Unlock registers */ /** - Unlock registers */
IWDG->KR = STM32_WATCHDOG_REGISTER_ACCESS_KEY; IWDG->KR = STM32_WATCHDOG_REGISTER_ACCESS_KEY;
/** - Wait until prescaler can be written */ /** - Wait until prescaler can be written */
while (IWDG->SR & IWDG_SR_PVU); while (IWDG->SR & IWDG_SR_PVU)
;
/** - Write prescaler value */ /** - Write prescaler value */
IWDG->PR = prescaler_reg_val; IWDG->PR = prescaler_reg_val;
/* - Wait until reload value can be written */ /* - Wait until reload value can be written */
while (IWDG->SR & IWDG_SR_RVU); while (IWDG->SR & IWDG_SR_RVU)
;
/** - Set reload value fixed to 0xFFF */ /** - Set reload value */
IWDG->RLR = 0xFFFU; if (reload_value > 0xFFFu) {
reload_value = 0xFFFFu;
ret = -2;
}
IWDG->RLR = reload_value;
/** - Write enable key */ /** - Write enable key */
IWDG->KR = STM32_WATCHDOG_ENABLE_KEY; IWDG->KR = STM32_WATCHDOG_ENABLE_KEY;
@ -95,7 +106,7 @@ int watchdog_setup(uint8_t prescaler)
/** - Do a first reset of the counter. This also locks the config regs */ /** - Do a first reset of the counter. This also locks the config regs */
watchdog_ack(WATCHDOG_MAGIC_KEY); watchdog_ack(WATCHDOG_MAGIC_KEY);
return 0; return ret;
} }
int watchdog_ack(uint32_t magic) int watchdog_ack(uint32_t magic)

65
stm-firmware/sd.c Normal file
View File

@ -0,0 +1,65 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <reflow-controller/sd.h>
#include "fatfs/ff.h"
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
#include <stdint.h>
#include <string.h>
#include <helper-macros/helper-macros.h>
#include <reflow-controller/digio.h>
static bool sd_card_mounted_state = false;
bool mount_sd_card_if_avail(FATFS *fs)
{
FRESULT res;
static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0;
if (sdio_check_inserted() && sd_card_mounted_state) {
memset(fs, 0, sizeof(FATFS));
sdio_stop_clk();
inserted_counter = 0;
sd_card_mounted_state = false;
goto ret;
}
if (!sdio_check_inserted() && inserted_counter < 255)
inserted_counter++;
if (!sdio_check_inserted() && !sd_card_mounted_state && inserted_counter > 4) {
inserted_counter = 0;
res = f_mount(fs, "0:/", 1);
if (res == FR_OK) {
led_set(1, 1);
sd_card_mounted_state = true;
} else {
sd_card_mounted_state = false;
}
}
ret:
return sd_card_mounted_state;
}
bool sd_card_is_mounted(void)
{
return sd_card_mounted_state;
}

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/settings/settings-eeprom.h> #include <reflow-controller/settings/settings-eeprom.h>
#include <reflow-controller/settings/spi-eeprom.h> #include <reflow-controller/settings/spi-eeprom.h>
@ -37,6 +37,7 @@ struct eeprom_calibration_settings {
}; };
#define EEPROM_OVER_TEMP_CONFIG_BASE_ADDR (EEPROM_CALIBRATION_BASE_ADDR + sizeof(struct eeprom_calibration_settings)) #define EEPROM_OVER_TEMP_CONFIG_BASE_ADDR (EEPROM_CALIBRATION_BASE_ADDR + sizeof(struct eeprom_calibration_settings))
struct eeprom_over_temp_config { struct eeprom_over_temp_config {
float over_temperature; float over_temperature;
uint32_t over_temp_crc; uint32_t over_temp_crc;
@ -54,7 +55,7 @@ static bool check_eeprom_header(void)
return true; return true;
} }
static void settings_eeprom_zero() static void settings_eeprom_zero(void)
{ {
settings_eeprom_save_calibration(0.0f, 0.0f, false); settings_eeprom_save_calibration(0.0f, 0.0f, false);
settings_eeprom_save_overtemp_limit(0.0f, false); settings_eeprom_save_overtemp_limit(0.0f, false);
@ -62,7 +63,7 @@ static void settings_eeprom_zero()
bool settings_eeprom_detect_and_prepare(void) bool settings_eeprom_detect_and_prepare(void)
{ {
bool eeprom_ready = false;; bool eeprom_ready = false;
int res; int res;
@ -77,7 +78,10 @@ bool settings_eeprom_detect_and_prepare(void)
if (check_eeprom_header() == false) { if (check_eeprom_header() == false) {
/* Try to write a new header and check it again */ /* Try to write a new header and check it again */
spi_eeprom_write(0, expected_header, sizeof(expected_header)); spi_eeprom_write(0, expected_header, sizeof(expected_header));
while (spi_eeprom_write_in_progress());
while (spi_eeprom_write_in_progress())
;
if (check_eeprom_header() == false) { if (check_eeprom_header() == false) {
goto ret_deinit_crc; goto ret_deinit_crc;
} else { } else {

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/settings/settings-sd-card.h> #include <reflow-controller/settings/settings-sd-card.h>
#include <stm-periph/unique-id.h> #include <stm-periph/unique-id.h>
@ -72,18 +72,12 @@ static int create_controller_folder(void)
ret = 0; ret = 0;
} else { } else {
filesystem_result = f_mkdir(foldername); filesystem_result = f_mkdir(foldername);
if (filesystem_result == FR_OK) { ret = filesystem_result == FR_OK ? 1 : -1;
ret = 1;
} else {
ret = -1;
}
} }
return ret; return ret;
} }
int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active) int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active)
{ {
char path[200]; char path[200];

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/settings/settings.h> #include <reflow-controller/settings/settings.h>
#include <reflow-controller/settings/settings-sd-card.h> #include <reflow-controller/settings/settings-sd-card.h>
@ -39,7 +39,7 @@ int settings_load_calibration(float *sens_dev, float *offset)
int res; int res;
if (settings_use_eeprom) { if (settings_use_eeprom) {
res =settings_eeprom_load_calibration(sens_dev, offset, &active); res = settings_eeprom_load_calibration(sens_dev, offset, &active);
if (!res && !active) if (!res && !active)
res = -1; res = -1;
} else { } else {

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <reflow-controller/settings/spi-eeprom.h> #include <reflow-controller/settings/spi-eeprom.h>
#include <stm-periph/spi.h> #include <stm-periph/spi.h>
@ -52,7 +52,7 @@ static void eeprom_cs_deactivate(void)
SPI_EEPROM_SPI_PORT->ODR |= (1<<SPI_EEPROM_CS_PIN); SPI_EEPROM_SPI_PORT->ODR |= (1<<SPI_EEPROM_CS_PIN);
} }
int spi_eeprom_init() int spi_eeprom_init(void)
{ {
static struct stm_spi_dev spi_dev; static struct stm_spi_dev spi_dev;
struct stm_spi_settings settings; struct stm_spi_settings settings;
@ -61,7 +61,8 @@ int spi_eeprom_init()
SPI_EEPROM_SPI_PORT->MODER &= MODER_DELETE(SPI_EEPROM_CS_PIN) & MODER_DELETE(SPI_EEPROM_MISO_PIN) & SPI_EEPROM_SPI_PORT->MODER &= MODER_DELETE(SPI_EEPROM_CS_PIN) & MODER_DELETE(SPI_EEPROM_MISO_PIN) &
MODER_DELETE(SPI_EEPROM_MOSI_PIN) & MODER_DELETE(SPI_EEPROM_SCK_PIN); MODER_DELETE(SPI_EEPROM_MOSI_PIN) & MODER_DELETE(SPI_EEPROM_SCK_PIN);
SPI_EEPROM_SPI_PORT->MODER |= ALTFUNC(SPI_EEPROM_MISO_PIN) | ALTFUNC(SPI_EEPROM_SCK_PIN) | ALTFUNC(SPI_EEPROM_MOSI_PIN); SPI_EEPROM_SPI_PORT->MODER |= ALTFUNC(SPI_EEPROM_MISO_PIN) | ALTFUNC(SPI_EEPROM_SCK_PIN) |
ALTFUNC(SPI_EEPROM_MOSI_PIN);
SPI_EEPROM_SPI_PORT->MODER |= OUTPUT(SPI_EEPROM_CS_PIN); SPI_EEPROM_SPI_PORT->MODER |= OUTPUT(SPI_EEPROM_CS_PIN);
SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_MISO_PIN, SPI_EEPROM_SPI_ALTFUNC_NO); SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_MISO_PIN, SPI_EEPROM_SPI_ALTFUNC_NO);
@ -85,7 +86,7 @@ int spi_eeprom_init()
return -1; return -1;
} }
void spi_eeprom_deinit() void spi_eeprom_deinit(void)
{ {
spi_deinit(eeprom_spi_handle); spi_deinit(eeprom_spi_handle);
@ -166,7 +167,8 @@ static void spi_eeprom_do_write_page(uint32_t addr, const uint8_t *data, uint8_t
uint8_t cmd[2]; uint8_t cmd[2];
/* Wait for the previous write to finish */ /* Wait for the previous write to finish */
while (spi_eeprom_write_in_progress()); while (spi_eeprom_write_in_progress())
;
/* Set the write enable latch */ /* Set the write enable latch */
spi_eeprom_set_write_enable_latch(true); spi_eeprom_set_write_enable_latch(true);

View File

@ -46,7 +46,8 @@ void backup_ram_init(bool use_backup_regulator)
PWR->CSR |= PWR_CSR_BRE; PWR->CSR |= PWR_CSR_BRE;
/* Wait until regulator is ready */ /* Wait until regulator is ready */
while (!(PWR->CSR & PWR_CSR_BRR)); while (!(PWR->CSR & PWR_CSR_BRR))
;
} }
/* Enable clock for backup ram interface */ /* Enable clock for backup ram interface */

View File

@ -37,11 +37,10 @@ static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_id
{ {
size_t fill_level; size_t fill_level;
if (put_idx >= get_idx) { if (put_idx >= get_idx)
fill_level = (put_idx - get_idx); fill_level = (put_idx - get_idx);
} else { else
fill_level = buffer_size - get_idx + put_idx; fill_level = buffer_size - get_idx + put_idx;
}
return fill_level; return fill_level;
} }
@ -49,7 +48,7 @@ static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_id
static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en) static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en)
{ {
int ret_val; int ret_val;
int (*clk_func)(volatile uint32_t *, uint8_t); int (*clk_func)(volatile uint32_t *reg, uint8_t bit_no);
if (clk_en) if (clk_en)
clk_func = rcc_manager_enable_clock; clk_func = rcc_manager_enable_clock;
@ -72,8 +71,9 @@ static int dma_ring_buffer_switch_clock_enable(uint8_t base_dma, bool clk_en)
} }
int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id, int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_buffer, uint8_t base_dma_id,
DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count,
volatile void *data_buffer, void* src_reg, uint8_t dma_trigger_channel) size_t element_size, volatile void *data_buffer,
void *src_reg, uint8_t dma_trigger_channel)
{ {
int ret_val = 0; int ret_val = 0;
@ -106,7 +106,8 @@ int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_
return 0; return 0;
} }
int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const volatile void **data_buff, size_t *len) int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const volatile void **data_buff,
size_t *len)
{ {
int ret_code = 0; int ret_code = 0;
uint32_t ndtr; uint32_t ndtr;
@ -167,7 +168,10 @@ int dma_ring_buffer_periph_to_mem_fill_level(struct dma_ring_buffer_to_mem *buff
return 0; return 0;
} }
int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id, DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size, volatile void *data_buffer, uint8_t dma_trigger_channel, void *dest_reg) int dma_ring_buffer_mem_to_periph_initialize(struct dma_ring_buffer_to_periph *dma_buffer, uint8_t base_dma_id,
DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count,
size_t element_size, volatile void *data_buffer,
uint8_t dma_trigger_channel, void *dest_reg)
{ {
if (!dma_buffer || !dma_stream || !data_buffer || !dest_reg) if (!dma_buffer || !dma_stream || !data_buffer || !dest_reg)
return -1000; return -1000;
@ -221,7 +225,8 @@ static void queue_or_start_dma_transfer(struct dma_ring_buffer_to_periph *buff)
buff->dma->CR |= DMA_SxCR_EN; buff->dma->CR |= DMA_SxCR_EN;
} }
int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert, size_t count) int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *buff, const void *data_to_insert,
size_t count)
{ {
int ret = 0; int ret = 0;
size_t free_item_count; size_t free_item_count;
@ -234,7 +239,8 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *
return -1000; return -1000;
/* Check if data fits into buffer minus one element. If not: try full-1 buffer and rest /* Check if data fits into buffer minus one element. If not: try full-1 buffer and rest
* Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a completely empty one * Buffer is not allowed to be completely full, because I cannot ddifferentiate a full buffer from a
* completely empty one
*/ */
if (count >= buff->buffer_count) { if (count >= buff->buffer_count) {
ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1); ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1);
@ -247,7 +253,9 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *
/* Wait for buffer to be able to handle input */ /* Wait for buffer to be able to handle input */
do { do {
free_item_count = buff->buffer_count - calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current, buff->sw_put_idx); free_item_count = buff->buffer_count -
calculate_ring_buffer_fill_level(buff->buffer_count, buff->dma_get_idx_current,
buff->sw_put_idx);
} while (free_item_count < count+1); } while (free_item_count < count+1);
/* Fillup buffer (max is buffer end, wrap around afterwards) */ /* Fillup buffer (max is buffer end, wrap around afterwards) */
@ -261,7 +269,7 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *
buff->sw_put_idx += count; buff->sw_put_idx += count;
/* If buffer is used up to last element, set put index to beginning */ /* If buffer is used up to last element, set put index to beginning */
if(buff->sw_put_idx >= buff->buffer_count) if (buff->sw_put_idx >= buff->buffer_count)
buff->sw_put_idx = 0; buff->sw_put_idx = 0;
} else { } else {
/* Fill up to end of buffer and fill rest after wrap around */ /* Fill up to end of buffer and fill rest after wrap around */

View File

@ -76,12 +76,14 @@ int stm_option_bytes_program(const struct option_bytes *opts)
reg |= (opts->read_protection << 8) & FLASH_OPTCR_RDP; reg |= (opts->read_protection << 8) & FLASH_OPTCR_RDP;
reg |= (opts->wdg_sw << 5) & FLASH_OPTCR_WDG_SW; reg |= (opts->wdg_sw << 5) & FLASH_OPTCR_WDG_SW;
while (FLASH->SR & FLASH_SR_BSY); while (FLASH->SR & FLASH_SR_BSY)
;
FLASH->OPTCR = reg; FLASH->OPTCR = reg;
FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT;
__DSB(); __DSB();
while (FLASH->SR & FLASH_SR_BSY); while (FLASH->SR & FLASH_SR_BSY)
;
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK;

View File

@ -95,9 +95,8 @@ int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit
int ret_val = 0; int ret_val = 0;
struct rcc_enable_count *entry; struct rcc_enable_count *entry;
if (!rcc_enable_register || bit_no > 31) { if (!rcc_enable_register || bit_no > 31)
return -1000; return -1000;
}
/* Enable the clock in any case, no matter what follows */ /* Enable the clock in any case, no matter what follows */
*rcc_enable_register |= (1U<<bit_no); *rcc_enable_register |= (1U<<bit_no);
@ -132,9 +131,8 @@ int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bi
int ret_val = -1; int ret_val = -1;
struct rcc_enable_count *entry; struct rcc_enable_count *entry;
if (!rcc_enable_register || bit_no > 31) { if (!rcc_enable_register || bit_no > 31)
return -1000; return -1000;
}
entry = search_enable_entry_in_list(rcc_enable_register, bit_no); entry = search_enable_entry_in_list(rcc_enable_register, bit_no);

View File

@ -30,7 +30,7 @@ void random_number_gen_init(bool int_enable)
random_number_gen_reset(int_enable); random_number_gen_reset(int_enable);
} }
void random_number_gen_deinit() void random_number_gen_deinit(void)
{ {
RNG->CR = 0; RNG->CR = 0;
__DSB(); __DSB();
@ -66,5 +66,5 @@ enum random_number_error random_number_gen_get_number(uint32_t *random_number, b
*random_number = RNG->DR; *random_number = RNG->DR;
/* Return from function with proper status */ /* Return from function with proper status */
return (value_ready ? RNG_ERROR_OK : RNG_ERROR_NOT_READY); return value_ready ? RNG_ERROR_OK : RNG_ERROR_NOT_READY;
} }

View File

@ -1,22 +1,22 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2021 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stm-periph/spi.h> #include <stm-periph/spi.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
@ -65,7 +65,8 @@ static struct stm_spi_dev *spi_handle_to_struct(stm_spi_handle handle)
return dev; return dev;
} }
stm_spi_handle spi_init(struct stm_spi_dev *spi_dev_struct, SPI_TypeDef *spi_regs, const struct stm_spi_settings *settings) stm_spi_handle spi_init(struct stm_spi_dev *spi_dev_struct, SPI_TypeDef *spi_regs,
const struct stm_spi_settings *settings)
{ {
stm_spi_handle ret_handle = NULL; stm_spi_handle ret_handle = NULL;
uint32_t reg_val; uint32_t reg_val;
@ -131,10 +132,14 @@ void spi_deinit(stm_spi_handle handle)
static uint8_t transfer_byte(uint8_t byte, struct stm_spi_dev *dev) static uint8_t transfer_byte(uint8_t byte, struct stm_spi_dev *dev)
{ {
while (dev->spi_regs->SR & SPI_SR_BSY); while (dev->spi_regs->SR & SPI_SR_BSY)
;
dev->spi_regs->DR = (uint16_t)byte; dev->spi_regs->DR = (uint16_t)byte;
__DSB(); __DSB();
while((dev->spi_regs->SR & SPI_SR_BSY) || !(dev->spi_regs->SR & SPI_SR_TXE));
while ((dev->spi_regs->SR & SPI_SR_BSY) || !(dev->spi_regs->SR & SPI_SR_TXE))
;
return (uint8_t)dev->spi_regs->DR; return (uint8_t)dev->spi_regs->DR;
} }

View File

@ -1,224 +1,227 @@
/* Reflow Oven Controller /* Reflow Oven Controller
* *
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net> * Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
* *
* This file is part of the Reflow Oven Controller Project. * This file is part of the Reflow Oven Controller Project.
* *
* The reflow oven controller is free software: you can redistribute it and/or modify * The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with the reflow oven controller project. * along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stm-periph/uart.h> #include <stm-periph/uart.h>
#include <stm32/stm32f4xx.h> #include <stm32/stm32f4xx.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <stm-periph/stm32-gpio-macros.h> #include <stm-periph/stm32-gpio-macros.h>
#include <stm-periph/dma-ring-buffer.h> #include <stm-periph/dma-ring-buffer.h>
#include <string.h> #include <string.h>
int uart_init(struct stm_uart *uart) int uart_init(struct stm_uart *uart)
{ {
int ret_val = 0; int ret_val = 0;
uint32_t cr3 = 0; uint32_t cr3 = 0;
uint32_t cr1 = 0; uint32_t cr1 = 0;
if (!uart) if (!uart)
return -1000; return -1000;
rcc_manager_enable_clock(uart->rcc_reg, uart->rcc_bit_no); rcc_manager_enable_clock(uart->rcc_reg, uart->rcc_bit_no);
/* Reset all config regs */ /* Reset all config regs */
uart->uart_dev->CR1 = uart->uart_dev->CR2 = uart->uart_dev->CR3 = 0UL; uart->uart_dev->CR1 = uart->uart_dev->CR2 = uart->uart_dev->CR3 = 0UL;
/* Set baud rate */ /* Set baud rate */
uart->uart_dev->BRR = uart->brr_val; uart->uart_dev->BRR = uart->brr_val;
/* If DMA buffers are present, configure for DMA use */ /* If DMA buffers are present, configure for DMA use */
if (uart->dma_rx_buff && uart->rx) { if (uart->dma_rx_buff && uart->rx) {
cr3 |= USART_CR3_DMAR; cr3 |= USART_CR3_DMAR;
ret_val = dma_ring_buffer_periph_to_mem_initialize(&uart->rx_ring_buff, ret_val = dma_ring_buffer_periph_to_mem_initialize(&uart->rx_ring_buff,
uart->base_dma_num, uart->base_dma_num,
uart->dma_rx_stream, uart->dma_rx_stream,
uart->rx_buff_count, uart->rx_buff_count,
1U, 1U,
uart->dma_rx_buff, uart->dma_rx_buff,
(char *)&uart->uart_dev->DR, (char *)&uart->uart_dev->DR,
uart->dma_rx_trigger_channel); uart->dma_rx_trigger_channel);
if (ret_val) if (ret_val)
return ret_val; return ret_val;
} }
if (uart->dma_tx_buff && uart->tx) { if (uart->dma_tx_buff && uart->tx) {
ret_val = dma_ring_buffer_mem_to_periph_initialize(&uart->tx_ring_buff, ret_val = dma_ring_buffer_mem_to_periph_initialize(&uart->tx_ring_buff,
uart->base_dma_num, uart->base_dma_num,
uart->dma_tx_stream, uart->dma_tx_stream,
uart->tx_buff_count, uart->tx_buff_count,
1U, 1U,
uart->dma_tx_buff, uart->dma_tx_buff,
uart->dma_tx_trigger_channel, uart->dma_tx_trigger_channel,
(void *)&uart->uart_dev->DR); (void *)&uart->uart_dev->DR);
if (ret_val) if (ret_val)
return ret_val; return ret_val;
cr3 |= USART_CR3_DMAT; cr3 |= USART_CR3_DMAT;
} }
uart->uart_dev->CR3 = cr3; uart->uart_dev->CR3 = cr3;
if (uart->tx) if (uart->tx)
cr1 |= USART_CR1_TE; cr1 |= USART_CR1_TE;
if (uart->rx) if (uart->rx)
cr1 |= USART_CR1_RE; cr1 |= USART_CR1_RE;
/* Enable uart */ /* Enable uart */
cr1 |= USART_CR1_UE; cr1 |= USART_CR1_UE;
uart->uart_dev->CR1 = cr1; uart->uart_dev->CR1 = cr1;
return 0; return 0;
} }
void uart_change_brr(struct stm_uart *uart, uint32_t brr) void uart_change_brr(struct stm_uart *uart, uint32_t brr)
{ {
if (!uart || !uart->uart_dev) if (!uart || !uart->uart_dev)
return; return;
uart->brr_val = brr; uart->brr_val = brr;
uart->uart_dev->BRR = brr; uart->uart_dev->BRR = brr;
} }
uint32_t uart_get_brr(struct stm_uart *uart) uint32_t uart_get_brr(struct stm_uart *uart)
{ {
if (!uart || !uart->uart_dev) if (!uart || !uart->uart_dev)
return 0; return 0;
return uart->brr_val; return uart->brr_val;
} }
void uart_disable(struct stm_uart *uart) void uart_disable(struct stm_uart *uart)
{ {
if (!uart) if (!uart)
return; return;
uart->uart_dev->CR1 = 0; uart->uart_dev->CR1 = 0;
uart->uart_dev->CR2 = 0; uart->uart_dev->CR2 = 0;
uart->uart_dev->CR3 = 0; uart->uart_dev->CR3 = 0;
if (uart->rx && uart->dma_rx_buff) if (uart->rx && uart->dma_rx_buff)
dma_ring_buffer_periph_to_mem_stop(&uart->rx_ring_buff); dma_ring_buffer_periph_to_mem_stop(&uart->rx_ring_buff);
if (uart->dma_tx_buff && uart->tx) if (uart->dma_tx_buff && uart->tx)
dma_ring_buffer_mem_to_periph_stop(&uart->tx_ring_buff); dma_ring_buffer_mem_to_periph_stop(&uart->tx_ring_buff);
rcc_manager_disable_clock(uart->rcc_reg, uart->rcc_bit_no); rcc_manager_disable_clock(uart->rcc_reg, uart->rcc_bit_no);
} }
void uart_send_char(struct stm_uart *uart, char c) void uart_send_char(struct stm_uart *uart, char c)
{ {
if (!uart || !uart->uart_dev) if (!uart || !uart->uart_dev)
return; return;
while(!(uart->uart_dev->SR & USART_SR_TXE)); while (!(uart->uart_dev->SR & USART_SR_TXE))
uart->uart_dev->DR = c; ;
}
uart->uart_dev->DR = c;
void uart_send_array(struct stm_uart *uart, const char *data, uint32_t len) }
{
uint32_t i; void uart_send_array(struct stm_uart *uart, const char *data, uint32_t len)
{
for (i = 0; i < len; i++) uint32_t i;
uart_send_char(uart, data[i]);
} for (i = 0; i < len; i++)
uart_send_char(uart, data[i]);
void uart_send_string(struct stm_uart *uart, const char *string) }
{
int i; void uart_send_string(struct stm_uart *uart, const char *string)
{
for (i = 0; string[i] != '\0'; i++) int i;
uart_send_char(uart, string[i]);
} for (i = 0; string[i] != '\0'; i++)
uart_send_char(uart, string[i]);
void uart_send_array_with_dma(struct stm_uart *uart, const char *data, uint32_t len) }
{
if (!uart || !uart->dma_tx_buff) void uart_send_array_with_dma(struct stm_uart *uart, const char *data, uint32_t len)
return; {
if (!uart || !uart->dma_tx_buff)
dma_ring_buffer_mem_to_periph_insert_data(&uart->tx_ring_buff, data, len); return;
}
dma_ring_buffer_mem_to_periph_insert_data(&uart->tx_ring_buff, data, len);
void uart_send_string_with_dma(struct stm_uart *uart, const char *string) }
{
size_t len; void uart_send_string_with_dma(struct stm_uart *uart, const char *string)
{
len = strlen(string); size_t len;
uart_send_array_with_dma(uart, string, (uint32_t)len);
} len = strlen(string);
uart_send_array_with_dma(uart, string, (uint32_t)len);
int uart_receive_data_with_dma(struct stm_uart *uart, const char **data, size_t *len) }
{
if (!uart) int uart_receive_data_with_dma(struct stm_uart *uart, const char **data, size_t *len)
return -1000; {
if (!uart)
return dma_ring_buffer_periph_to_mem_get_data(&uart->rx_ring_buff, (const volatile void **)data, len); return -1000;
}
return dma_ring_buffer_periph_to_mem_get_data(&uart->rx_ring_buff, (const volatile void **)data, len);
char uart_get_char(struct stm_uart *uart) }
{
if (!uart) char uart_get_char(struct stm_uart *uart)
return 0; {
/* Wait for data to be available */ if (!uart)
while (!(uart->uart_dev->SR & USART_SR_RXNE)); return 0;
/* Wait for data to be available */
return (char)uart->uart_dev->DR; while (!(uart->uart_dev->SR & USART_SR_RXNE))
} ;
int uart_check_rx_avail(struct stm_uart *uart) return (char)uart->uart_dev->DR;
{ }
if (!uart)
return 0; int uart_check_rx_avail(struct stm_uart *uart)
{
if (uart->uart_dev->SR & USART_SR_RXNE) if (!uart)
return 1; return 0;
else
return 0; if (uart->uart_dev->SR & USART_SR_RXNE)
} return 1;
else
void uart_tx_dma_complete_int_callback(struct stm_uart *uart) return 0;
{ }
if (!uart)
return; void uart_tx_dma_complete_int_callback(struct stm_uart *uart)
{
dma_ring_buffer_mem_to_periph_int_callback(&uart->tx_ring_buff); if (!uart)
} return;
size_t uart_dma_tx_queue_avail(struct stm_uart *uart) dma_ring_buffer_mem_to_periph_int_callback(&uart->tx_ring_buff);
{ }
size_t fill_level = 0UL;
size_t uart_dma_tx_queue_avail(struct stm_uart *uart)
if (!uart) {
return 0UL; size_t fill_level = 0UL;
(void)dma_ring_buffer_mem_to_periph_fill_level(&uart->tx_ring_buff, &fill_level); if (!uart)
return 0UL;
return fill_level;
} (void)dma_ring_buffer_mem_to_periph_fill_level(&uart->tx_ring_buff, &fill_level);
size_t uart_dma_rx_queue_avail(struct stm_uart *uart) return fill_level;
{ }
size_t fill_level = 0UL;
size_t uart_dma_rx_queue_avail(struct stm_uart *uart)
if (!uart) {
return 0UL; size_t fill_level = 0UL;
(void)dma_ring_buffer_periph_to_mem_fill_level(&uart->rx_ring_buff, &fill_level); if (!uart)
return 0UL;
return fill_level;
} (void)dma_ring_buffer_periph_to_mem_fill_level(&uart->rx_ring_buff, &fill_level);
return fill_level;
}

View File

@ -43,3 +43,23 @@ void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id)
if (revision_id) if (revision_id)
*revision_id = (DBGMCU->IDCODE & DBGMCU_IDCODE_REV_ID) >> 16; *revision_id = (DBGMCU->IDCODE & DBGMCU_IDCODE_REV_ID) >> 16;
} }
void stm_cpuid_get(uint8_t *implementer, uint8_t *variant, uint16_t *part_no, uint8_t *rev)
{
uint32_t cpuid;
cpuid = SCB->CPUID;
if (implementer)
*implementer = (uint8_t)((cpuid >> 24) & 0xFFU);
if (variant)
*variant = (uint8_t)((cpuid >> 20) & 0x0FU);
if (part_no)
*part_no = (uint16_t)((cpuid >> 4) & 0x0FFFU);
if (rev)
*rev = (uint8_t)(cpuid & 0x0FU);
}

View File

@ -18,10 +18,12 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "reflow-controller/version.h"
#include <reflow-controller/ui/gui.h> #include <reflow-controller/ui/gui.h>
#include <reflow-controller/ui/gui-config.h> #include <reflow-controller/ui/gui-config.h>
#include <reflow-controller/ui/menu.h> #include <reflow-controller/ui/menu.h>
#include <reflow-controller/ui/lcd.h> #include <reflow-controller/ui/lcd.h>
#include <reflow-controller/sd.h>
#include <reflow-controller/ui/rotary-encoder.h> #include <reflow-controller/ui/rotary-encoder.h>
#include <reflow-controller/systick.h> #include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
@ -166,9 +168,9 @@ static void gui_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry ent
break; break;
last_page = 1; last_page = 1;
menu_lcd_output(menu, 0, "Version Number:"); menu_lcd_output(menu, 0, "Version Number:");
menu_lcd_outputf(menu, 1, "%.*s", LCD_CHAR_WIDTH, xstr(GIT_VER)); menu_lcd_outputf(menu, 1, "%.*s", LCD_CHAR_WIDTH, version_git_version_string);
if (strlen(xstr(GIT_VER)) > LCD_CHAR_WIDTH) { if (strlen(version_git_version_string) > LCD_CHAR_WIDTH) {
menu_lcd_outputf(menu, 2, "%s", &xstr(GIT_VER)[LCD_CHAR_WIDTH]); menu_lcd_outputf(menu, 2, "%s", &version_git_version_string[LCD_CHAR_WIDTH]);
} }
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
menu_lcd_output(menu, 3, "Page 2/5 [DEBUG]"); menu_lcd_output(menu, 3, "Page 2/5 [DEBUG]");
@ -691,6 +693,37 @@ static void gui_update_firmware(struct lcd_menu *menu, enum menu_entry_func_entr
} }
} }
static void gui_connector_info(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
{
static void *my_parent;
enum button_state button;
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
my_parent = parent;
menu_display_clear(menu);
menu_lcd_output(menu, 0, "2,4: DIGIO[0,1]");
menu_lcd_output(menu, 1, "6: DIGIO2 (TX)");
menu_lcd_output(menu, 2, "8: DIGIO3 (RX)");
menu_lcd_output(menu, 3, "10:3V3 Rest:GND");
}
if (menu_get_button_ready_state(menu)) {
/* Buttons are ready. Read button */
button = menu_get_button_state(menu);
/* Throw away any rotation */
(void)menu_get_rotary_delta(menu);
if (button == BUTTON_SHORT_RELEASED || button == BUTTON_LONG ||
button == BUTTON_LONG_RELEASED) {
/* Exit menu */
menu_entry_dropback(menu, my_parent);
}
}
}
static char *overlay_heading = NULL; static char *overlay_heading = NULL;
static char *overlay_text = NULL; static char *overlay_text = NULL;
@ -740,6 +773,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
"Error Flags", "Error Flags",
"About", "About",
"Update", "Update",
"Connector Info",
NULL NULL
}; };
static const menu_func_t root_entry_funcs[] = { static const menu_func_t root_entry_funcs[] = {
@ -749,6 +783,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
gui_menu_err_flags, gui_menu_err_flags,
gui_menu_about, gui_menu_about,
gui_update_firmware, gui_update_firmware,
gui_connector_info,
}; };
enum button_state push_button; enum button_state push_button;
int16_t rot_delta; int16_t rot_delta;
@ -756,7 +791,6 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
if (entry_type != MENU_ENTRY_CONTINUE) { if (entry_type != MENU_ENTRY_CONTINUE) {
menu_changed = true; menu_changed = true;
menu_display_clear(menu); menu_display_clear(menu);
update_display_buffer(0, "Main Menu");
menu_ack_rotary_delta(menu); menu_ack_rotary_delta(menu);
if (entry_type == MENU_ENTRY_FIRST_ENTER) { if (entry_type == MENU_ENTRY_FIRST_ENTER) {
list.entry_names = root_entry_names; list.entry_names = root_entry_names;
@ -767,6 +801,8 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
} }
} }
update_display_buffer(0, sd_card_is_mounted() ? "Main Menu [SD]" : "Main Menu [--]");
push_button = menu_get_button_state(menu); push_button = menu_get_button_state(menu);
rot_delta = menu_get_rotary_delta(menu); rot_delta = menu_get_rotary_delta(menu);

View File

@ -48,13 +48,11 @@
#include <stm-periph/option-bytes.h> #include <stm-periph/option-bytes.h>
#include <reflow-controller/ui/gui.h> #include <reflow-controller/ui/gui.h>
#include <reflow-controller/ui/shell-uart.h> #include <reflow-controller/ui/shell-uart.h>
#include <reflow-controller/safety/flash-crc.h>
#include <reflow-controller/version.h>
#include <stdio.h> #include <stdio.h>
#ifndef GIT_VER
#define GIT_VER "VERSION NOT SET"
#endif
static shellmatta_instance_t shell; static shellmatta_instance_t shell;
static char shell_buffer[512]; static char shell_buffer[512];
static char IN_SECTION(.ccm.bss) history_buffer[512]; static char IN_SECTION(.ccm.bss) history_buffer[512];
@ -70,14 +68,19 @@ static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
uint32_t high_id; uint32_t high_id;
uint32_t stm_rev_id; uint32_t stm_rev_id;
uint32_t stm_dev_id; uint32_t stm_dev_id;
uint8_t core_rev;
uint8_t core_implementer;
uint8_t core_variant;
uint16_t core_part_no;
const char *hw_rev_str; const char *hw_rev_str;
enum hw_revision pcb_rev; enum hw_revision pcb_rev;
stm_unique_id_get(&high_id, &mid_id, &low_id); stm_unique_id_get(&high_id, &mid_id, &low_id);
stm_dev_rev_id_get(&stm_dev_id, &stm_rev_id); stm_dev_rev_id_get(&stm_dev_id, &stm_rev_id);
shellmatta_printf(handle, "Reflow Oven Controller Firmware " xstr(GIT_VER) "\r\n" shellmatta_printf(handle, "Reflow Oven Controller Firmware %s\r\n"
"Compiled: " __DATE__ " at " __TIME__ "\r\n"); "Compiled: %s at %s\r\n",
version_git_version_string, version_compile_date, version_compile_time);
shellmatta_printf(handle, "Serial: %08X-%08X-%08X\r\n", high_id, mid_id, low_id); shellmatta_printf(handle, "Serial: %08X-%08X-%08X\r\n", high_id, mid_id, low_id);
pcb_rev = get_pcb_hardware_version(); pcb_rev = get_pcb_hardware_version();
@ -100,6 +103,12 @@ static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
shellmatta_printf(handle, "STM Device ID: 0x%04X\r\n", stm_dev_id); shellmatta_printf(handle, "STM Device ID: 0x%04X\r\n", stm_dev_id);
shellmatta_printf(handle, "STM Revision ID: 0x%04X\r\n", stm_rev_id); shellmatta_printf(handle, "STM Revision ID: 0x%04X\r\n", stm_rev_id);
stm_cpuid_get(&core_implementer, &core_variant, &core_part_no, &core_rev);
shellmatta_printf(handle, "CPU Implementer: 0x%02X\r\n", (unsigned int)core_implementer);
shellmatta_printf(handle, "CPU Variant: 0x%02X\r\n", (unsigned int)core_variant);
shellmatta_printf(handle, "CPU Part No.: 0x%04X\r\n", (unsigned int)core_part_no);
shellmatta_printf(handle, "CPU Revision: 0x%02X\r\n", (unsigned int)core_rev);
return SHELLMATTA_OK; return SHELLMATTA_OK;
} }
@ -849,6 +858,7 @@ shellmatta_retCode_t shell_cmd_execute(const shellmatta_handle_t handle, const c
shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, const char *args, uint32_t len) shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, const char *args, uint32_t len)
{ {
uint64_t counter; uint64_t counter;
uint32_t core_cycle_count;
(void)args; (void)args;
(void)len; (void)len;
char option; char option;
@ -856,8 +866,10 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con
uint32_t arg_len; uint32_t arg_len;
int opt_stat; int opt_stat;
bool clear = false; bool clear = false;
bool hex = false;
const shellmatta_opt_long_t options[] = { const shellmatta_opt_long_t options[] = {
{"clear", 'c', SHELLMATTA_OPT_ARG_NONE}, {"clear", 'c', SHELLMATTA_OPT_ARG_NONE},
{"hex", 'h', SHELLMATTA_OPT_ARG_NONE},
{NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, {NULL, '\0', SHELLMATTA_OPT_ARG_NONE},
}; };
@ -869,6 +881,8 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con
case 'c': case 'c':
clear = true; clear = true;
break; break;
case 'h':
hex = true;
default: default:
break; break;
} }
@ -876,10 +890,18 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con
counter = main_cycle_counter_get(); counter = main_cycle_counter_get();
shellmatta_printf(handle, "%"PRIu64"\r\n", counter); core_cycle_count = core_cycle_counter_get();
if (clear) if (hex) {
main_cycle_counter_init(); shellmatta_printf(handle, "Main loop: 0x%016"PRIX64"\r\n", counter);
shellmatta_printf(handle, "CPU cycles: 0x%08"PRIX32"\r\n", core_cycle_count);
} else {
shellmatta_printf(handle, "Main loop: %"PRIu64"\r\n", counter);
shellmatta_printf(handle, "CPU cycles: %"PRIu32"\r\n", core_cycle_count);
}
if (clear) {
main_cycle_counter_reset();
core_cycle_counter_reset();
}
return SHELLMATTA_OK; return SHELLMATTA_OK;
} }
@ -997,6 +1019,53 @@ shellmatta_retCode_t shell_cmd_set_baud(const shellmatta_handle_t handle, const
return SHELLMATTA_OK; return SHELLMATTA_OK;
} }
static void shell_print_crc_line(const shellmatta_handle_t handle, const char *name,
uint32_t crc, uint32_t crc_expected)
{
shellmatta_printf(handle, "%-15s0x%08x 0x%08x [%s]\r\n",
name,
crc,
crc_expected,
crc != crc_expected ? "\e[1;31mERR\e[m" : "\e[32mOK\e[m");
}
shellmatta_retCode_t shell_cmd_flash_crc(const shellmatta_handle_t handle, const char *args, uint32_t len)
{
(void)args;
(void)len;
uint32_t crc = 0;
uint32_t crc_expected = 0;
int res;
shellmatta_printf(handle, " Calculated Expected State\r\n\r\n");
res = flash_crc_calc_section(FLASH_CRC_VECTOR, &crc);
crc_expected = flash_crc_get_expected_crc(FLASH_CRC_VECTOR);
if (res)
shellmatta_printf(handle, "Error during calculation!\r\n");
shell_print_crc_line(handle, "Vector CRC:", crc, crc_expected);
res = flash_crc_calc_section(FLASH_CRC_TEXT, &crc);
crc_expected = flash_crc_get_expected_crc(FLASH_CRC_TEXT);
if (res)
shellmatta_printf(handle, "Error during calculation!\r\n");
shell_print_crc_line(handle, "Code CRC:", crc, crc_expected);
res = flash_crc_calc_section(FLASH_CRC_DATA, &crc);
crc_expected = flash_crc_get_expected_crc(FLASH_CRC_DATA);
if (res)
shellmatta_printf(handle, "Error during calculation!\r\n");
shell_print_crc_line(handle, "Data CRC:", crc, crc_expected);
res = flash_crc_calc_section(FLASH_CRC_CCMDATA, &crc);
crc_expected = flash_crc_get_expected_crc(FLASH_CRC_CCMDATA);
if (res)
shellmatta_printf(handle, "Error during calculation!\r\n");
shell_print_crc_line(handle, "CCM Data CRC:", crc, crc_expected);
return SHELLMATTA_OK;
}
//typedef struct shellmatta_cmd //typedef struct shellmatta_cmd
//{ //{
// char *cmd; /**< command name */ // char *cmd; /**< command name */
@ -1006,7 +1075,7 @@ shellmatta_retCode_t shell_cmd_set_baud(const shellmatta_handle_t handle, const
// shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */ // shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */ // struct shellmatta_cmd *next; /**< pointer to next command or NULL */
//} shellmatta_cmd_t; //} shellmatta_cmd_t;
static shellmatta_cmd_t cmd[25] = { static shellmatta_cmd_t cmd[26] = {
{ {
.cmd = "version", .cmd = "version",
.cmdAlias = "ver", .cmdAlias = "ver",
@ -1202,10 +1271,18 @@ static shellmatta_cmd_t cmd[25] = {
}, },
{ {
.cmd = "baudrate", .cmd = "baudrate",
.cmdAlias = "opt-bytes", .cmdAlias = "baud",
.helpText = "Set a new temporary baudrate for the UART", .helpText = "Set a new temporary baudrate for the UART",
.usageText = "baudrate <new baud>", .usageText = "baudrate <new baud>",
.cmdFct = shell_cmd_set_baud, .cmdFct = shell_cmd_set_baud,
.next = &cmd[25],
},
{
.cmd = "flashcrc",
.cmdAlias = "fcrc",
.helpText = "Calculate the Flash CRCs",
.usageText = "flashcrc",
.cmdFct = shell_cmd_flash_crc,
.next = NULL, .next = NULL,
}, },

View File

@ -31,7 +31,7 @@ add_executable(${ELFFILE} ${SRCS} ${FATFS_SRCS} ${SDIO_SRCS} ${STM_PERIPH_SRCS}
target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ../../include ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party) target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ../../include ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party)
target_compile_options(${ELFFILE} PRIVATE -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) target_compile_options(${ELFFILE} PRIVATE -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
target_compile_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare -Os -g3) target_compile_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare -Os -g3)
target_compile_definitions(${ELFFILE} PRIVATE -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DSAFETY_MEMORY_STRIPOUT_DUMP) target_compile_definitions(${ELFFILE} PRIVATE -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DSAFETY_MEMORY_STRIPOUT_DUMP)
target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage) target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage)
set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated") set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated")
set(GEN_HEADER_FILE "${GEN_HEADER_PATH}/${PROJECT_NAME}.bin.h") set(GEN_HEADER_FILE "${GEN_HEADER_PATH}/${PROJECT_NAME}.bin.h")

View File

@ -1,35 +1,45 @@
#!env python #!env python
# Convert a file to a c array """
# bin2carray <output file> <input file> Convert a file to a c array
bin2carray <output file> <input file>
"""
import os import os
import os.path import os.path
import sys import sys
if len(sys.argv) < 3: def main():
sys.exit(-1) """
Main script function
"""
if len(sys.argv) < 3:
return -1
source_file = sys.argv[2] source_file = sys.argv[2]
dest_file = sys.argv[1] dest_file = sys.argv[1]
print("%s --> %s" % (source_file, dest_file)) print(f'{source_file} --> {dest_file}')
with open(source_file, "rb") as src: with open(source_file, 'rb') as src:
data = src.read() data = src.read()
with open(dest_file, "w") as dest: with open(dest_file, 'w', encoding='utf-8') as dest:
header_guard = "__" + os.path.basename(dest_file).replace('.', '_').replace('-', '_') + "_H__" header_guard = '_' + os.path.basename(dest_file).replace('.', '_').replace('-', '_') + '_H_'
dest.write("#ifndef %s\n" % (header_guard)) header_guard = header_guard.upper()
dest.write("#define %s\n" % (header_guard)) dest.write(f'#ifndef {header_guard}\n')
dest.write("static const char binary_blob[%d] = {\n" % (len(data))) dest.write(f'#define {header_guard}\n')
for current,idx in zip(data, range(len(data))): dest.write(f'static const char binary_blob[{len(data)}] = {{\n')
if ((idx+1) % 4 == 0): for idx, current in enumerate(data, start=1):
dest.write(hex(current)+",\n") if idx % 4 == 0:
else: dest.write(hex(current)+',\n')
dest.write(hex(current)+",") else:
dest.write(hex(current)+',')
dest.write("};\n") dest.write('};\n')
dest.write("#endif /* %s */\n" % (header_guard)) dest.write(f'#endif /* {header_guard} */\n')
sys.exit(0) return 0
if __name__ == '__main__':
sys.exit(main())

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +1,208 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */ /* A Sample Code of User Provided OS Dependent Functions for FatFs */
/* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <fatfs/ff.h> #include <fatfs/ff.h>
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Use dynamic memory allocation */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Allocate a memory block */ /* Allocate/Free a Memory Block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <stdlib.h> /* with POSIX API */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
return malloc(msize); /* Allocate a new memory block with POSIX API */ return malloc((size_t)msize); /* Allocate a new memory block */
} }
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */ void* mblock /* Pointer to the memory block to free (no effect if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block */
} }
#endif #endif
#if FF_FS_REENTRANT /* Mutal exclusion */ #if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Create a Synchronization Object */ /* Definitions of Mutex */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ #define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ #if OS_TYPE == 0 /* Win32 */
BYTE vol, /* Corresponding volume (logical drive number) */ #include <windows.h>
FF_SYNC_t* sobj /* Pointer to return the created sync object */ static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
)
{
/* Win32 */
*sobj = CreateMutex(NULL, FALSE, NULL);
return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */ #elif OS_TYPE == 1 /* uITRON */
// T_CSEM csem = {TA_TPRI,1,1}; #include "itron.h"
// *sobj = acre_sem(&csem); #include "kernel.h"
// return (int)(*sobj > 0); static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
/* uC/OS-II */ #elif OS_TYPE == 2 /* uc/OS-II */
// OS_ERR err; #include "includes.h"
// *sobj = OSMutexCreate(0, &err); static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */ #elif OS_TYPE == 3 /* FreeRTOS */
// *sobj = xSemaphoreCreateMutex(); #include "FreeRTOS.h"
// return (int)(*sobj != NULL); #include "semphr.h"
static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
/* CMSIS-RTOS */ #elif OS_TYPE == 4 /* CMSIS-RTOS */
// *sobj = osMutexCreate(&Mutex[vol]); #include "cmsis_os.h"
// return (int)(*sobj != NULL); static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
/* Win32 */
return (int)CloseHandle(sobj);
/* uITRON */
// return (int)(del_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// vSemaphoreDelete(sobj);
// return 1;
/* CMSIS-RTOS */
// return (int)(osMutexDelete(sobj) == osOK);
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
FF_SYNC_t sobj /* Sync object to wait */
)
{
/* Win32 */
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
/* uITRON */
// return (int)(wai_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
/* CMSIS-RTOS */
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
/* Win32 */
ReleaseMutex(sobj);
/* uITRON */
// sig_sem(sobj);
/* uC/OS-II */
// OSMutexPost(sobj);
/* FreeRTOS */
// xSemaphoreGive(sobj);
/* CMSIS-RTOS */
// osMutexRelease(sobj);
}
#endif #endif
/*------------------------------------------------------------------------*/
/* Create a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to create a new mutex
/ or semaphore for the volume. When a 0 is returned, the f_mount function
/ fails with FR_INT_ERR.
*/
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
Mutex[vol] = CreateMutex(NULL, FALSE, NULL);
return (int)(Mutex[vol] != INVALID_HANDLE_VALUE);
#elif OS_TYPE == 1 /* uITRON */
T_CMTX cmtx = {TA_TPRI,1};
Mutex[vol] = acre_mtx(&cmtx);
return (int)(Mutex[vol] > 0);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
Mutex[vol] = OSMutexCreate(0, &err);
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
Mutex[vol] = xSemaphoreCreateMutex();
return (int)(Mutex[vol] != NULL);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDef(cmsis_os_mutex);
Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex));
return (int)(Mutex[vol] != NULL);
#endif
}
/*------------------------------------------------------------------------*/
/* Delete a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to delete a mutex or
/ semaphore of the volume created with ff_mutex_create function.
*/
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
CloseHandle(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
del_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err);
#elif OS_TYPE == 3 /* FreeRTOS */
vSemaphoreDelete(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDelete(Mutex[vol]);
#endif
}
/*------------------------------------------------------------------------*/
/* Request a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on enter file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0);
#elif OS_TYPE == 1 /* uITRON */
return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err));
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK);
#endif
}
/*------------------------------------------------------------------------*/
/* Release a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leave file functions to unlock the volume.
*/
void ff_mutex_give (
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
ReleaseMutex(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
unl_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OSMutexPost(Mutex[vol]);
#elif OS_TYPE == 3 /* FreeRTOS */
xSemaphoreGive(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexRelease(Mutex[vol]);
#endif
}
#endif /* FF_FS_REENTRANT */

View File

@ -1,13 +1,13 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13+ */ /* Unicode Handling Functions for FatFs R0.13 and Later */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .rodata section when the */
/* FatFs is configured for LFN with DBCS. If the system has a Unicode */
/* library for the code conversion, this module should be modified to use */
/* it to avoid silly memory consumption. */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
/ utilitiy for the code conversion, this module should be modified to use /
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/* /*
/ Copyright (C) 2014, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -22,10 +22,9 @@
/ by use of this software. / by use of this software.
*/ */
#include <fatfs/ff.h> #include <fatfs/ff.h>
#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */
#define MERGE2(a, b) a ## b #define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp) #define CVTBL(tbl, cp) MERGE2(tbl, cp)
@ -15214,8 +15213,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* SBCS fixed code page */ /* SBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
@ -15225,7 +15224,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII? */ if (uni < 0x80) { /* ASCII? */
@ -15247,7 +15246,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII? */ if (oem < 0x80) { /* ASCII? */
@ -15267,8 +15266,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* DBCS fixed code page */ /* DBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900 #if FF_CODE_PAGE >= 900
@ -15277,7 +15276,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15313,7 +15312,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15346,7 +15345,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for dynamic code page configuration */ /* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 0
@ -15360,7 +15359,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15412,7 +15411,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15458,14 +15457,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode up-case conversion */ /* Unicode Up-case Conversion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */ DWORD uni /* Unicode code point to be up-converted */
) )
{ {
const WORD *p; const WORD* p;
WORD uc, bc, nc, cmd; WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */ /* Basic Latin */
@ -15590,4 +15589,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
} }
#endif /* #if FF_USE_LFN */ #endif /* #if FF_USE_LFN != 0 */

View File

@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14b / / FatFs - Generic FAT Filesystem module R0.15 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2021, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -20,7 +20,7 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 86631 /* Revision ID */ #define FF_DEFINED 80286 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -131,10 +131,11 @@ extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */ BYTE pdrv; /* Volume hosting physical drive */
BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] status (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */ WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */ WORD csize; /* Cluster size [sectors] */
@ -147,9 +148,6 @@ typedef struct {
#if FF_FS_EXFAT #if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif #endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY #if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */ DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */ DWORD free_clst; /* Number of free clusters */
@ -163,10 +161,10 @@ typedef struct {
#endif #endif
#endif #endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */ DWORD fsize; /* Number of sectors per FAT */
LBA_t volbase; /* Volume base sector */ LBA_t volbase; /* Volume base sector */
LBA_t fatbase; /* FAT base sector */ LBA_t fatbase; /* FAT base sector */
LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */
LBA_t database; /* Data base sector */ LBA_t database; /* Data base sector */
#if FF_FS_EXFAT #if FF_FS_EXFAT
LBA_t bitbase; /* Allocation bitmap base sector */ LBA_t bitbase; /* Allocation bitmap base sector */
@ -181,7 +179,7 @@ typedef struct {
typedef struct { typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume's mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
@ -250,7 +248,7 @@ typedef struct {
WORD ftime; /* Modified time */ WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */ BYTE fattrib; /* File attribute */
#if FF_USE_LFN #if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else #else
TCHAR fname[12 + 1]; /* File name */ TCHAR fname[12 + 1]; /* File name */
@ -298,8 +296,10 @@ typedef enum {
/*--------------------------------------------------------------*/
/* FatFs Module Application Interface */
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_close (FIL* fp); /* Close an open file object */
@ -336,6 +336,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
/* Some API fucntions are implemented as macro */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr) #define f_tell(fp) ((fp)->fptr)
@ -349,38 +351,43 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Additional user defined functions */ /* Additional Functions */
/*--------------------------------------------------------------*/
/* RTC function */ /* RTC function (provided by user) */
#if !FF_FS_READONLY && !FF_FS_NORTC #if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void); DWORD get_fattime (void); /* Get current time */
#endif #endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ /* LFN support functions (defined in ffunicode.c) */
#if FF_USE_LFN >= 1
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif #endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
/* Sync functions */
#if FF_FS_REENTRANT /* O/S dependent functions (samples available in ffsystem.c) */
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ void* ff_memalloc (UINT msize); /* Allocate memory block */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ void ff_memfree (void* mblock); /* Free memory block */
#endif
#if FF_FS_REENTRANT /* Sync functions */
int ff_mutex_create (int vol); /* Create a sync object */
void ff_mutex_delete (int vol); /* Delete a sync object */
int ff_mutex_take (int vol); /* Lock sync object */
void ff_mutex_give (int vol); /* Unlock sync object */
#endif #endif
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Flags and offset address */ /* Flags and Offset Address */
/*--------------------------------------------------------------*/
/* File access mode and open method flags (3rd argument of f_open) */ /* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01 #define FA_READ 0x01

View File

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs Functional Configurations / Configurations of FatFs Module
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 86631 /* Revision ID */ #define FFCONF_DEF 80286 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -68,7 +68,7 @@
/ 2: Enable with LF-CRLF conversion. / 2: Enable with LF-CRLF conversion.
/ /
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
makes f_printf() support floating point argument. These features want C99 or later. / makes f_printf() support floating point argument. These features want C99 or later.
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions. / to be read/written via those functions.
@ -178,7 +178,7 @@
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid / logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as: / not defined, a user defined volume string table is needed as:
/ /
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/ */
@ -190,7 +190,7 @@
/ number and only an FAT volume found on the physical drive will be mounted. / number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to / When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */ / function will be available. */
#define FF_MIN_SS 512 #define FF_MIN_SS 512
@ -240,10 +240,10 @@
#define FF_FS_NORTC 0 #define FF_FS_NORTC 0
#define FF_NORTC_MON 1 #define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2020 #define FF_NORTC_YEAR 2022
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have /* The option FF_FS_NORTC switches timestamp feature. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp / timestamp feature. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON, / added to the project to read current time form real-time clock. FF_NORTC_MON,
@ -253,7 +253,7 @@
#define FF_FS_NOFSINFO 0 #define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force / option, and f_getfree() function at the first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. / a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/ /
/ bit0=0: Use free cluster count in the FSINFO if available. / bit0=0: Use free cluster count in the FSINFO if available.
@ -275,26 +275,21 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different / module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function. / to the same volume is under control of this featuer.
/ /
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers, / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give()
/ function, must be added to the project. Samples are available in / function, must be added to the project. Samples are available in ffsystem.c.
/ option/syscall.c.
/ /
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, */
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */

27
stm-firmware/version.c Normal file
View File

@ -0,0 +1,27 @@
/* Reflow Oven Controller
*
* Copyright (C) 2022 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of the Reflow Oven Controller Project.
*
* The reflow oven controller is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the reflow oven controller project.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <reflow-controller/version.h>
#include <generated-version/version.h>
const char *version_git_version_string = GIT_VERSION_STRING;
const char *version_git_full_commit_string = GIT_FULL_COMMIT;
const char *version_compile_date = __DATE__;
const char *version_compile_time = __TIME__;