10 Commits

Author SHA1 Message Date
4efa5ae797 Update 'Jenkinsfile' 2021-10-10 23:21:02 +02:00
5e90cd39fa Update 'Jenkinsfile' 2021-10-10 23:18:13 +02:00
015028bde2 Add build step to jenkinsfile 2021-10-10 23:12:22 +02:00
4e6e5db2c3 Fix bug in jenkinsfile 2021-10-10 23:03:58 +02:00
a2bcd37800 Edir configure step in jenkinsfile 2021-10-10 23:01:31 +02:00
ed936cf9f9 Add quotes to jenkinsfile 2021-10-10 22:58:26 +02:00
e595e398d4 jenkinsfile test 2021-10-10 22:56:00 +02:00
86446e1b22 jenkinsfile test 2021-10-10 22:54:47 +02:00
b26233d5e3 jenkinsfile test 2021-10-10 22:53:20 +02:00
0ab13edced jenkinsfile test 2021-10-10 22:49:53 +02:00
75 changed files with 2225 additions and 4458 deletions

20
Jenkinsfile vendored
View File

@@ -2,9 +2,22 @@ pipeline {
agent any
stages {
stage('Build') {
stage('Configure') {
steps {
echo 'Configuring Cmake...'
sh '''
mkdir "build" &&
cd "build" &&
cmake "../stm-firmware"
'''
}
}
stage('Build') {
steps {
echo 'Building..'
sh '''
cd "build" &&
make
'''
}
}
stage('Test') {
@@ -13,8 +26,9 @@ pipeline {
}
}
stage('Deploy') {
when { tag "*" }
steps {
echo 'Deploying....'
echo 'Deploying tag...'
}
}
}

View File

@@ -15,4 +15,4 @@ mechanisms and the behavior. For a detailed code documentation see the doxygen o
safety/index
code/index
hw-version-detect
peripherals

View File

@@ -1,44 +0,0 @@
.. _peripherals:
Used Peripheral Modules
=======================
This section lists all the used peripheral modules of the ``STM32F407VxT6``.
Core Peripherals
----------------
- ``SysTick``: Generating a 100us tick for the LCD routine and 1ms base system tick.
- ``NVIC``: Interrupt controller
- ``FPU``: The Flaoting Point Unit is activated and used in this formware.
AHB Peripherals
---------------
- ``DMA2``
- ``Stream0``: DMA transfer of PT1000 measurement ADC to memory
- ``Stream4``: DMA transfer of Safety ADC measurement values
- ``Stream5``: Shell UART RX
- ``Stream7``: Shell UART TX
- ``RNG``: Random number generation for stack corruption / overflow checker.
- ``CRC``: CRC verfication of various data (Safety structures, EEPROM data, Safety RAM)
- ``Backup RAM``: Backup RAM storing errors and bootloader information beyond system resets. The memory is cleared by a power cycle!
ABP1 Peripherals
----------------
- ``IWDG``: Independent Watchdog
- ``TIM2``: PT1000 measurement ADC sample time generation timer. Genewrates the 1 KHz sample trigger to the ADC peripheral via the internal event routing system.
- ``TIM3``: PWM timer for oven relais output.
- ``TIM5``: Input capture for rotary encoder.
- ``TIM7``: Timer for loudspeaker tone generation.
APB2 Peripherals
----------------
- ``SPI1``: SPI for external SPI-EEPROM
- ``SDIO``: SD card interface
- ``USART1``: Shell UART
- ``ADC1``: Safety ADC for monitoring voltages
- ``ADC3``: PT1000 measurement ADC

View File

@@ -16,10 +16,3 @@ reflow-controller.includes
*.files
*.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_PROCESSOR arm)
set(CMAKE_CROSSCOMPILING 1)
cmake_minimum_required(VERSION 3.18)
cmake_minimum_required(VERSION 3.0)
set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake")
@@ -43,12 +43,26 @@ else (GIT_FOUND)
message("Version is set to: ${GIT_DESCRIBE}${ColorReset}")
endif (GIT_FOUND)
find_program(PATCHELFCRC patchelfcrc)
if (PATCHELFCRC)
message("patchelfcrc found: ${PATCHELFCRC}")
else(PATCHELFCRC)
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}")
endif (PATCHELFCRC)
find_program(VIRTUALENV virtualenv)
if (VIRTUALENV)
message("Python virtual environment found")
execute_process(
COMMAND ${VIRTUALENV} venv
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
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)
@@ -57,7 +71,7 @@ set(MAPFILE ${PROJECT_NAME}.map)
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(-mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare)
add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare)
set(GIT_DESCRIBE "${GIT_DESCRIBE}")
@@ -110,15 +124,15 @@ add_executable(${ELFFILE} ${MAIN_SOURCES} ${CFG_PARSER_SRCS} ${UI_SRCS}
add_dependencies(${ELFFILE} updater-ram-code-header-blob)
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 -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)
target_link_libraries(${ELFFILE} base64-lib linklist-lib)
target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/")
add_custom_command(
TARGET ${ELFFILE}
POST_BUILD
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 ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ./python "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/crc-patch-elf.py" "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}"
WORKING_DIRECTORY ${VENV_BIN}
COMMENT "Running Flash CRC Patcher"
)

View File

@@ -324,6 +324,7 @@ void __attribute__((noreturn)) Reset_Handler(void) {
/* Move the stack and the stack pointer to CCMRAM
* This allows us to perform a RAM test on the main RAM.
*/
/* R2 holds the amount of bytes / words on the stack. */
__asm__ __volatile__ (
"mov r2, sp\n" /* Move stack pointer to register 2 */
"sub r2, %[stacktop], r2\n" /* Subtract stackpointer from top of ram => byte usage */

View File

@@ -31,17 +31,10 @@
#define CONFIG_PARSER_MAGIC 0x464a6e2bUL
#define CONFIG_PARSER(p) ((struct config_parser *)(p))
/**
* @brief Check if the supplied pointer is a valid @ref config_parser_handle_t
*
* If the pointer is invalid, the function using this macro will return with
* CONFIG_PARSER_PARAM_ERR
*/
#define config_parser_check_handle(handle) do { \
if (!(handle) || \
((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \
return CONFIG_PARSER_PARAM_ERR; \
} while (0)
#define config_parser_check_handle(handle) do { if (!(handle) || \
((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \
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,
char *working_buffer, size_t buff_size)
@@ -63,18 +56,9 @@ config_parser_handle_t config_parser_open_file(struct config_parser *config_pars
return (config_parser_handle_t)config_parser;
}
/**
* @brief Token delimiters for the config parser.
*/
static const char * const token_delim = " \t";
/**
* @brief Parse a value in the configuration
* @param entry Entry to parse the value in to
* @param value_start_token char pointer holding the value. Must be null-terminated
* @return 0 if successful
*/
static int parse_value(struct config_parser_entry *entry, char *value_start_token)
static int parse_value(struct config_parser_entry *entry, char *value_start_token)
{
char *dot;
char *endptr;
@@ -92,18 +76,19 @@ static int parse_value(struct config_parser_entry *entry, char *value_start_toke
if (value_start_token[0] != '-') {
/* Try parsing as ul */
/* Try parsing as int */
entry->value.uint_val = strtoul(value_start_token, &endptr, 0);
if (endptr == value_start_token)
if (endptr == value_start_token) {
return -1;
}
entry->type = CONFIG_PARSER_TYPE_UINT;
goto exit;
} else {
/* Try parsing as int */
entry->value.int_val = strtod(value_start_token, &endptr);
if (endptr == value_start_token)
if (endptr == value_start_token) {
return -1;
}
entry->type = CONFIG_PARSER_TYPE_INT;
}
@@ -111,15 +96,13 @@ exit:
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;
char *token;
int token_round = 0;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);
char *token;
int token_round = 0;
if (!entry)
return CONFIG_PARSER_PARAM_ERR;
@@ -134,7 +117,8 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str
if (token[0] == '#') {
if (token_round == 0)
return CONFIG_PARSER_LINE_COMMENT;
break;
else
break;
}
switch (token_round) {
@@ -142,8 +126,9 @@ enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, str
entry->name = token;
break;
case 1: /* = Symbol */
if (strcmp(token, "="))
if (strcmp(token, "=")) {
return CONFIG_PARSER_LINE_MALFORM;
}
break;
case 2: /* VALUE */
if (parse_value(entry, token))
@@ -173,7 +158,6 @@ enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handl
{
FRESULT res;
struct config_parser *p;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);
@@ -196,7 +180,6 @@ enum config_parser_ret config_parser_close_file(config_parser_handle_t handle)
{
struct config_parser *p;
FRESULT res;
config_parser_check_handle(handle);
p = CONFIG_PARSER(handle);

View File

@@ -33,68 +33,44 @@
#include <stdbool.h>
#include <fatfs/ff.h>
/**
* @brief Confi parser instance struct
*/
struct config_parser {
uint32_t magic; /**< @brief Magic value. Checked by each function to verify if the passed pointer is valid */
bool write; /**< @brief File opened in write / read mode */
FIL file; /**< @brief FatFS file */
char *buffer; /**< @brief Working buffer */
size_t buff_size; /** @brief Size of the working buffer config_parser::buffer */
uint32_t magic;
bool write;
FIL file;
char *buffer;
size_t buff_size;
};
/**
* @brief handle type for the config parser. Never dereference this pointer directly!
*/
typedef void * config_parser_handle_t;
/**
* @brief Differnet value types a config entry can hold
*/
enum config_parser_value_type {
CONFIG_PARSER_TYPE_UINT = 0,
CONFIG_PARSER_TYPE_INT,
CONFIG_PARSER_TYPE_FLOAT,
};
/**
* @brief Error return code of config parser functions
*/
enum config_parser_ret {
CONFIG_PARSER_OK = 0, /**< @brief Operation succeeded */
CONFIG_PARSER_PARAM_ERR, /**< @brief Function parameter error */
CONFIG_PARSER_GENERIC_ERR, /**< @brief Generic unspecified error */
CONFIG_PARSER_IOERR, /**< @brief I/O Error while file handling */
CONFIG_PARSER_LINE_COMMENT, /**< @brief The parser encountered a line starting with a comment. */
CONFIG_PARSER_LINE_TOO_LONG, /**< @brief The read line is too long for the parser to process. */
CONFIG_PARSER_LINE_MALFORM, /**< @brief Malfoirmed line. Line is neither a commenbt nor a key=value string */
CONFIG_PARSER_END_REACHED, /**< @brief The config parser has reached the end of the file */
CONFIG_PARSER_WRONG_MODE, /**< @brief Read or write requested on config parser instance that is opened in a different mode */
CONFIG_PARSER_OK = 0,
CONFIG_PARSER_PARAM_ERR,
CONFIG_PARSER_GENERIC_ERR,
CONFIG_PARSER_IOERR,
CONFIG_PARSER_LINE_COMMENT,
CONFIG_PARSER_LINE_TOO_LONG,
CONFIG_PARSER_LINE_MALFORM,
CONFIG_PARSER_END_REACHED,
CONFIG_PARSER_WRONG_MODE,
};
/**
* @brief Represents a configuration key-value-pair used by the config parser
*/
struct config_parser_entry {
const char *name; /**< @brief Pointer to the name of the config entry (key) */
enum config_parser_value_type type; /**< @brief Type of the value held by this struct */
const char *name;
enum config_parser_value_type type;
union {
uint32_t uint_val;
int32_t int_val;
float float_val;
} value; /**< @brief Value of the config entry. For correct processing, config_parser_entry::type has to be taken into account */
} value;
};
/**
* @brief Open a config file
* @param config_parser Struict holding the config parser isntance. Will be filled by this function
* @param write Open the config file for writing (true) or reading (false)
* @param file_name File name to open
* @param working_buffer A working buffer used by the config parser to process the file.
* @param buff_size Size of \p working_buffer. Must be large enough to hold a full line of the config file
* @return Config parser error
*/
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);
@@ -107,37 +83,13 @@ config_parser_handle_t config_parser_open_file(struct config_parser *config_pars
* @return Config parser error
*/
enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry, bool force_float);
/**
* @brief Reset the config parser instance to the beginning of the config file
* @param handle Config parser
* @return Config parser error
*/
enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handle);
/**
* @brief Write a config entry to a config file
* @param handle Handle to the config parser. This must be opened in write mode.
* @param entry
* @return Config parser error
* @warning This function is currently not implemented and will return with a success!
*/
enum config_parser_ret config_parser_write_entry(config_parser_handle_t handle, const struct config_parser_entry *entry);
/**
* @brief Close a config parser handle
* @param handle Config parser
* @return Config parser error
*/
enum config_parser_ret config_parser_close_file(config_parser_handle_t handle);
/**
* @brief Check if the \p return_val is a abort condition to stop parsing a file.
*
* This function will return true if a disk error occured or the end of file is reached.
*
* @param return_val
* @return
*/
bool config_parser_ret_is_abort_condition(enum config_parser_ret return_val);
#endif /* _CONFIG_PARSER_H_ */

View File

@@ -0,0 +1,113 @@
#!/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("Warning!!! .flashcrc section has wrong size:",flashcrc_sec.data_size)
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,124 +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 extracted 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
"""
import sys
import struct
from elftools.elf.elffile import ELFFile
import crcmod
import crcmod.predefined
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):
"""
Calculate CRC of ELF file 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)
def main():
"""
Main function. Patches CRCs into ELF file
"""
with open(filename, 'r+b') as elf_file:
elf = ELFFile(elf_file)
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)
elf_file.seek(crc_sec_offset)
elf_file.write(crc_sec_data)
print('CRCs patched successfully')
if __name__ == '__main__':
main()

View File

@@ -1,623 +0,0 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-allow-list=
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
# for backward compatibility.)
extension-pkg-whitelist=
# Return non-zero exit code if any of these messages/categories are detected,
# even if score is above --fail-under value. Syntax same as enable. Messages
# specified are enabled, while categories only check already-enabled messages.
fail-on=
# Specify a score threshold to be exceeded before program exits with error.
fail-under=10.0
# Files or directories to be skipped. They should be base names, not paths.
ignore=CVS
# Add files or directories matching the regex patterns to the ignore-list. The
# regex matches against paths.
ignore-paths=
# Files or directories matching the regex patterns are skipped. The regex
# matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
jobs=1
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[REPORTS]
# Python expression which should return a score less than or equal to 10. You
# have access to the variables 'error', 'warning', 'refactor', and 'convention'
# which contain the number of messages in each category, as well as 'statement'
# which is the total number of statements analyzed. This score is used by the
# global evaluation report (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages.
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit,argparse.parse_error
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=no
# This flag controls whether the implicit-str-concat should generate a warning
# on implicit string concatenation in sequences defined over several lines.
check-str-concat-over-line-jumps=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Ignore function signatures when computing similarities.
ignore-signatures=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[BASIC]
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style.
#argument-rgx=
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Bad variable names regexes, separated by a comma. If names match any regex,
# they will always be refused
bad-names-rgxs=
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
#class-attribute-rgx=
# Naming style matching correct class constant names.
class-const-naming-style=UPPER_CASE
# Regular expression matching correct class constant names. Overrides class-
# const-naming-style.
#class-const-rgx=
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style.
#class-rgx=
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style.
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names.
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style.
#function-rgx=
# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_
# Good variable names regexes, separated by a comma. If names match any regex,
# they will always be accepted
good-names-rgxs=
# Include a hint for the correct naming format with invalid-name.
include-naming-hint=no
# Naming style matching correct inline iteration names.
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
#inlinevar-rgx=
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style.
#method-rgx=
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style.
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style.
#variable-rgx=
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string='\t'
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module.
max-module-lines=1000
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
# Regular expression of note tags to take in consideration.
#notes-rgx=
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it work,
# install the 'python-enchant' package.
spelling-dict=
# List of comma separated words that should be considered directives if they
# appear and the beginning of a comment and should not be checked.
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains the private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to the private dictionary (see the
# --spelling-private-dict-file option) instead of raising a message.
spelling-store-unknown-words=no
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of names allowed to shadow builtins
allowed-redefined-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
[LOGGING]
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style=old
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
# List of decorators that change the signature of a decorated function.
signature-mutators=
[CLASSES]
# Warn about protected attribute access inside special methods
check-protected-access-in-special-methods=no
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp,
__post_init__
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls
[DESIGN]
# Maximum number of arguments for function / method.
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in an if statement (see R0916).
max-bool-expr=5
# Maximum number of branch for function / method body.
max-branches=12
# Maximum number of locals for function / method body.
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body.
max-returns=6
# Maximum number of statements in function / method body.
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[IMPORTS]
# List of modules that can be imported at any level, not just the top level
# one.
allow-any-import-level=
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=
# Output a graph (.gv or any supported image format) of external dependencies
# to the given file (report RP0402 must not be disabled).
ext-import-graph=
# Output a graph (.gv or any supported image format) of all (i.e. internal and
# external) dependencies to the given file (report RP0402 must not be
# disabled).
import-graph=
# Output a graph (.gv or any supported image format) of internal dependencies
# to the given file (report RP0402 must not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
# Couples of modules and preferred modules, separated by a comma.
preferred-modules=
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "BaseException, Exception".
overgeneral-exceptions=BaseException,
Exception

View File

@@ -6,7 +6,7 @@ import pathlib
license_header = """/* Reflow Oven Controller
*
* Copyright (C) 2022 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.
*
@@ -37,7 +37,7 @@ cpath = os.path.join(project_dir, sys.argv[1]+'.c')
hfile = sys.argv[1]+'.h'
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):
print("File already exists! Abort!")

View File

@@ -18,11 +18,6 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @addtogroup digio
* @{
*/
#include <reflow-controller/digio.h>
#include <stm32/stm32f4xx.h>
#include <stm-periph/rcc-manager.h>
@@ -52,10 +47,17 @@ static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func
}
void digio_init(void)
void digio_setup_default_all(void)
{
unsigned int i;
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(DIGIO_RCC_MASK));
digio_set_default_values();
for (i = 0; i < COUNT_OF(digio_pins); i++) {
digio_setup_pin_int(digio_pins[i], digio_default_io[i], digio_default_altfunc[i]);
if (digio_default_io[i] == 1)
digio_set(i, 0);
}
}
void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func)
@@ -67,22 +69,12 @@ void digio_setup_pin(uint8_t num, uint8_t in_out, uint8_t alt_func)
void digio_set(uint8_t num, int val)
{
uint8_t pin;
if (num >= COUNT_OF(digio_pins))
return;
pin = digio_pins[num];
/* Check if port is an output. If not, do noting. */
if ((DIGIO_PORT->MODER & (0x3<<pin)) != OUTPUT(pin)) {
return;
}
if (val)
DIGIO_PORT->ODR |= (1<<pin);
DIGIO_PORT->ODR |= (1<<digio_pins[num]);
else
DIGIO_PORT->ODR &= ~(1<<pin);
DIGIO_PORT->ODR &= ~(1<<digio_pins[num]);
}
int digio_get(uint8_t num)
@@ -127,12 +119,7 @@ int led_get(uint8_t num)
return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0);
}
/**
* @brief Initialize the timer for the beeper to generate the output frequency
*
* TIM7 is used as the frequency generating timer. If @ref LOUDSPEAKER_MULTIFREQ
* is 0, the timer is unused and this function does nothing.
*/
static void loudspeaker_freq_timer_init(void)
{
#if LOUDSPEAKER_MULTIFREQ
@@ -156,13 +143,6 @@ void loudspeaker_setup(void)
loudspeaker_set(0U);
}
/**
* @brief Start the beeper
* @param val frequency value of the speaker in 'Timer relaod values'
* @note If @ref LOUDSPEAKER_MULTIFREQ isn't set,
* the speaker output will be set to high and no frequency is generated.
* The value of @p val is ignored in this case
*/
static void loudspeaker_start_beep(uint16_t val)
{
#if LOUDSPEAKER_MULTIFREQ
@@ -175,9 +155,6 @@ static void loudspeaker_start_beep(uint16_t val)
#endif
}
/**
* @brief Stop the beeping of the loudspeaker
*/
static void loudspeaker_stop_beep(void)
{
#if LOUDSPEAKER_MULTIFREQ
@@ -207,12 +184,6 @@ uint16_t loudspeaker_get(void)
}
#if LOUDSPEAKER_MULTIFREQ
/**
* @brief Timer7 IRQ Handler
*
* This IRQ Handler is used by the loudspeaker to synthesize the output frequency.
* If @ref LOUDSPEAKER_MULTIFREQ is 0, TIM7 and this interrupt will not be used.
*/
void TIM7_IRQHandler(void)
{
TIM7->SR = 0UL;
@@ -220,16 +191,3 @@ void TIM7_IRQHandler(void)
LOUDSPEAKER_PORT->ODR ^= (1<<LOUDSPEAKER_PIN);
}
#endif
/** @} */
void digio_set_default_values()
{
unsigned int i;
for (i = 0; i < COUNT_OF(digio_pins); i++) {
digio_setup_pin_int(digio_pins[i], digio_default_io[i], digio_default_altfunc[i]);
if (digio_default_io[i] == 1)
digio_set(i, 0);
}
}

View File

@@ -463,7 +463,7 @@ LOOKUP_CACHE_SIZE = 0
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 0
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
@@ -968,8 +968,7 @@ EXCLUDE = ../include/stm32 \
../linklist-lib/test \
../base64-lib/test \
../shellmatta/doc/main.dox \
../updater/ram-code \
./
../updater/ram-code
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded

View File

@@ -1,24 +0,0 @@
FatFs License
FatFs has being developped as a personal project of the author, ChaN. It is free from the code anyone else wrote at current release. Following code block shows a copy of the FatFs license document that heading the source files.
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module Rx.xx /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 20xx, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/----------------------------------------------------------------------------*/
Therefore FatFs license is one of the BSD-style licenses, but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, do not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses include GNU GPL. When you redistribute the FatFs source code with changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that not conflict with FatFs license.

File diff suppressed because it is too large Load Diff

View File

@@ -27,20 +27,12 @@
#include <stm-periph/rcc-manager.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)
{
uint8_t current_pin;
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));
uint16_t port_bitmask = 0U;
static enum hw_revision revision = HW_REV_NOT_DETECTED;
/* If the revision has been previously detected,
* just return it and don't do the whole detection stuff
*/
if (revision != HW_REV_NOT_DETECTED)
return revision;
@@ -53,15 +45,12 @@ enum hw_revision get_pcb_hardware_version(void)
HW_REV_DETECT_GPIO->PUPDR |= PULLUP(current_pin);
}
/* Loop again and read in the pin mask.
* Because we use GND-Shorts on the pins to detect the version, the pins are read inverted.
*/
/* Loop again and read in the pin mask */
for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) {
port_bitmask >>= 1;
port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : highest_bit_mask;
port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : 0x80;
}
/* Resolve the read in bitmask to a hardware version */
switch (port_bitmask) {
case 0U:
revision = HW_REV_V1_2;
@@ -69,9 +58,6 @@ enum hw_revision get_pcb_hardware_version(void)
case 1U:
revision = HW_REV_V1_3;
break;
case 2U:
revision = HW_REV_V1_3_1;
break;
default:
revision = HW_REV_ERROR;
}

View File

@@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14b /
/ FatFs - Generic FAT Filesystem module R0.14a /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2021, ChaN, all right reserved.
/ Copyright (C) 2020, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@@ -20,7 +20,7 @@
#ifndef FF_DEFINED
#define FF_DEFINED 86631 /* Revision ID */
#define FF_DEFINED 80196 /* Revision ID */
#ifdef __cplusplus
extern "C" {
@@ -35,14 +35,10 @@ extern "C" {
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Windows VC++ (for development only) */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#include <float.h>
#define isnan(v) _isnan(v)
#define isinf(v) (!_finite(v))
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
@@ -52,7 +48,6 @@ typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
typedef WORD WCHAR; /* UTF-16 character type */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
@@ -63,29 +58,28 @@ typedef WORD WCHAR; /* UTF-16 character type */
#endif
/* Type of file size and LBA variables */
/* Definitions of volume management */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
#endif
typedef QWORD FSIZE_t;
#if FF_LBA64
typedef QWORD LBA_t;
#else
typedef DWORD LBA_t;
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#else
#if FF_LBA64
#error exFAT needs to be enabled when enable 64-bit LBA
#endif
typedef DWORD FSIZE_t;
typedef DWORD LBA_t;
#endif
/* Type of path name strings on FatFs API (TCHAR) */
/* Type of path name strings on FatFs API */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
@@ -107,22 +101,28 @@ typedef char TCHAR;
#define _TEXT(x) x
#endif
/* Definitions of volume management */
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
/* Type of file size and LBA variables */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#endif
typedef QWORD FSIZE_t;
#if FF_LBA64
typedef QWORD LBA_t;
#else
typedef DWORD LBA_t;
#endif
#else
#if FF_LBA64
#error exFAT needs to be enabled when enable 64-bit LBA
#endif
typedef DWORD FSIZE_t;
typedef DWORD LBA_t;
#endif

View File

@@ -2,7 +2,7 @@
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 86631 /* Revision ID */
#define FFCONF_DEF 80196 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@@ -25,6 +25,14 @@
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
@@ -56,30 +64,6 @@
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
#define FF_USE_STRFUNC 1
#define FF_PRINT_LLI 0
#define FF_PRINT_FLOAT 0
#define FF_STRF_ENCODE 0
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
/ 1: Enable without 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
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
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
@@ -153,6 +137,19 @@
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 2
/* This option configures support for relative path.
/
@@ -197,7 +194,7 @@
#define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk, but a larger value may be required for on-board flash memory and some
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
@@ -231,7 +228,7 @@
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 1
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */

View File

@@ -65,19 +65,11 @@
#define BEEPER_RCC_MASK RCC_AHB1ENR_GPIOBEN
/**
* @brief Enable all clocks and setup pins in default setting.
* @brief Enable all clocks and setup pins in default setting
* @warning This function uses @ref rcc_manager_enable_clock to enable the clocks. Therefore, it must not be called
* multiple times.
* @note Calls @ref digio_set_default_values() internally.
*/
void digio_init(void);
/**
* @brief Setup or restore the default DIGIO settings.
*
* This function can be called multiple times.
*/
void digio_set_default_values(void);
void digio_setup_default_all(void);
/**
* @brief Set up a DIGIO pin.
@@ -154,7 +146,7 @@ int led_get(uint8_t num);
#define LOUDSPEAKER_PIN 1
/**
* @brief The loudpseaker requires a frequency signal instead of a simple on/off signal.
* @brief The loudpseaker requires a frequncy signal instead of a simple on/off signal.
*/
#define LOUDSPEAKER_MULTIFREQ 1
@@ -170,14 +162,7 @@ void loudspeaker_setup(void);
/**
* @brief Set the loudspeaker value
*
* Zero turns off the beeper. 1 is a special value
* and will set the @ref LOUDSPEAKER_MULTIFREQ_DEFAULT value.
*
* If @ref LOUDSPEAKER_MULTIFREQ is 0, then no actual frequency is produced.
* Instead any @p val unequal to zero turns the output pin high and 0 will turn it low.
*
* @param val Value.
* @param val Value
*/
void loudspeaker_set(uint16_t val);

View File

@@ -48,6 +48,7 @@
*/
#define HW_REV_DETECT_PIN_HIGH (15U)
/**
* @brief PCB/Hardware Revision Type
*/
@@ -56,7 +57,6 @@ enum hw_revision {
HW_REV_ERROR = 1, /**< @brief The hardware revision could not be detected due to an internal error */
HW_REV_V1_2 = 120, /**< @brief Hardware Revision v1.2 */
HW_REV_V1_3 = 130, /**< @brief Hardware Revision v1.3 */
HW_REV_V1_3_1 = 131, /**< @brief Hardware revision v1.3.1 */
};
/**
@@ -70,7 +70,6 @@ enum hw_revision {
* The function returns the HW revision as an enum hw_revision.
* For v1.2 the return value is 120 (HW_REV_V1_2).
* For v1.3 the return value is 130 (HW_REV_V1_3).
* For v1.3.1 the return value is 131 (HW_REV_V1_3_1).
*
* Other return values are not defined yet.
*

View File

@@ -18,34 +18,15 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @defgroup main-cycle-counter Main Cycle Counter
* The main cycle counter is incremented after every loop run of the main loop in main.c
* @{
*/
#ifndef __MAIN_CYCLE_COUNTER_H__
#define __MAIN_CYCLE_COUNTER_H__
#include <stdint.h>
/**
* @brief Initialize/Reset the main cycle counter to 0.
* This function can be called multiple times.
*/
void main_cycle_counter_init(void);
/**
* @brief Increment the main cycle counter by 1
*/
void main_cycle_counter_inc(void);
/**
* @brief Get the current main cycle counter value
* @return Value
*/
uint64_t main_cycle_counter_get(void);
#endif /* __MAIN_CYCLE_COUNTER_H__ */
/** @} */

View File

@@ -21,93 +21,32 @@
#ifndef __OVEN_DRIVER_H__
#define __OVEN_DRIVER_H__
/**
* @defgroup oven-driver Oven SSR Driver and PID Controller
* @{
*/
#include <stdint.h>
#include <stdbool.h>
#include <reflow-controller/pid-controller.h>
/**
* @brief Status of the PID controlling the oven
*/
enum oven_pid_status {
OVEN_PID_DEACTIVATED, /**< @brief The PID of the oven is deactivated. */
OVEN_PID_RUNNING, /**< @brief The PID of the oven is currently active and running. */
OVEN_PID_ABORTED, /**< @brief The PID of the oven has been aborted due to an error and is not running. */
};
enum oven_pid_status {OVEN_PID_DEACTIVATED,
OVEN_PID_RUNNING,
OVEN_PID_ABORTED};
/**
* @brief Initialize the oven driver.
*
* This will initialize the Timer for the PWM output to the SSR.
* If the hardware revision is >= v1.3 the SSR safety enable line will also be initialized.
*/
void oven_driver_init(void);
/**
* @brief Set a power level on the oven control output
* @param power Power level between 0 to 100
* @note This will not actually set the output. For this, @ref oven_driver_apply_power_level() has to be called.
* It will be called in the main loop.
*/
void oven_driver_set_power(uint8_t power);
/**
* @brief Disable the oven driver.
*
* This shuts down the oven driver timer and the corresponding clocks.
*/
void oven_driver_disable(void);
/**
* @brief Initialize the PID controller for the oven output
* @param PID controller holding the settings
*/
void oven_pid_init(struct pid_controller *controller_to_copy);
/**
* @brief Handle the PID controller.
* This must be called cyclically. When the sampling period has passed, the function will process the PT1000
* resistance and do a PID cycluilation for this sample.
* @note This function must be called with a frequency greater or equal to the PID's sampling frequency
*/
void oven_pid_handle(void);
/**
* @brief Stop the oven PID controller
*/
void oven_pid_stop(void);
/**
* @brief Abort the oven PID controller. This is the same as oven_pid_stop() but will set the abort flag.
* @note this function is called by the safety controller to disable the PID controller in case of an error.
*/
void oven_pid_abort(void);
/**
* @brief Set the target temperature of the PID controller.
* @param temp
*/
void oven_pid_set_target_temperature(float temp);
/**
* @brief Output the power level currently configured to the SSR.
*
* This function is separated from oven_driver_set_power() because it is called in the main loop after the
* safety controller has run. This ensures, that if the safety controller decides to stop the PID no glitch makes it
* out to the SSR.
*/
void oven_driver_apply_power_level(void);
/**
* @brief Get the current status of the oven's PID controller
* @return
*/
enum oven_pid_status oven_pid_get_status(void);
/** @} */
#endif /* __OVEN_DRIVER_H__ */

View File

@@ -25,11 +25,9 @@
#endif
/* UART_DIV is 45.5625 => 115200 @ 84 MHz */
#define SHELL_UART_DEFAULT_DIV_FRACTION 9U /* Equals 9/16 = 0.5625 */
#define SHELL_UART_DEFAULT_DIV_MANTISSA 45U /* Equals 45 */
#define SHELL_UART_DIV_FRACTION 9U /* Equals 9/16 = 0.5625 */
#define SHELL_UART_DIV_MANTISSA 45U /* Equals 45 */
#define SHELL_UART_DEFAULT_BRR_REG_VALUE ((SHELL_UART_DEFAULT_DIV_MANTISSA<<4) | SHELL_UART_DEFAULT_DIV_FRACTION);
#define SHELL_UART_PERIPHERAL_CLOCK (84000000UL)
#define SHELL_UART_BRR_REG_VALUE ((SHELL_UART_DIV_MANTISSA<<4) | SHELL_UART_DIV_FRACTION);
#endif /* __SHELL_UART_CONFIG_H__ */

View File

@@ -1,37 +0,0 @@
/* 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

@@ -1,56 +0,0 @@
/* 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,15 +27,6 @@
#ifndef __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.
*
@@ -131,6 +122,12 @@ enum analog_value_monitor {
*/
#define SAFETY_MIN_STACK_FREE 0x100
#define PID_CONTROLLER_ERR_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP | ERR_FLAG_AMON_VREF | \
ERR_FLAG_TIMING_PID | ERR_FLAG_TIMING_MEAS_ADC | ERR_FLAG_MEAS_ADC_OFF | \
ERR_FLAG_MEAS_ADC_OVERFLOW)
#define HALTING_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP)
#define SAFETY_ADC_VREF_MVOLT (2500.0f)
#define SAFETY_ADC_VREF_TOL_MVOLT (100.0f)
#define SAFETY_ADC_TEMP_LOW_LIM (0.0f)

View File

@@ -70,14 +70,14 @@ struct timing_monitor_info {
* You have to call safety_controller_handle
* If this function fails, it will hang, because errors in the safety controller are not recoverable
*/
void safety_controller_init(void);
void safety_controller_init();
/**
* @brief Handle the safety controller.
* @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware
* @returns Worst flag weigth that is currently set.
* @return 0 if successful
*/
enum config_weight safety_controller_handle(void);
int safety_controller_handle();
/**
* @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
* @return Error flag count
*/
uint32_t safety_controller_get_flag_count(void);
uint32_t safety_controller_get_flag_count();
/**
* @brief Get the count of analog monitors
* @return Analog monitor count
*/
uint32_t safety_controller_get_analog_monitor_count(void);
uint32_t safety_controller_get_analog_monitor_count();
/**
* @brief Get an error flag's name by its index.
@@ -267,6 +267,13 @@ int safety_controller_set_overtemp_limit(float over_temperature);
*/
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
* @param mon Monitor to recalculate

View File

@@ -24,7 +24,6 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <reflow-controller/safety/safety-config.h>
/** @addtogroup safety-memory
* @{
@@ -132,6 +131,15 @@ enum config_override_entry_type {
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
*/

View File

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

View File

@@ -25,8 +25,7 @@
* @brief Convert PT1000 resistance to temperature in degrees celsius
* @param resistance PT1000 resistance value
* @param[out] temp_out Temperature output
* @return 0 if ok, -1 if value is below conversion range, 1 if value is above conversion range,
* -1000 in case of pointer error
* @return 0 if ok, -1 if value is below conversion range, 1 if value is above conversion range,-1000 in case of pointer error
*/
int temp_converter_convert_resistance_to_temp(float resistance, float *temp_out);

View File

@@ -44,9 +44,9 @@ enum tpe_status {
};
/**
* @brief The execution state of the temperature profile
* @brief The current execution state of the temperature profile
*/
struct tpe_exec_state {
struct tpe_current_state {
enum tpe_status status; /**< @brief Execution status */
float setpoint; /**< @brief Temperature setpoint in degrees Celsius */
uint64_t start_timestamp; /**< @brief The millisicend tick timestamp, the profile execution was started */
@@ -78,7 +78,7 @@ int temp_profile_executer_handle(void);
* @warning The returned state structure is static and used internally. You must not modify it.
* @return Execution state
*/
const struct tpe_exec_state *temp_profile_executer_status(void);
const struct tpe_current_state *temp_profile_executer_status(void);
/**
* @brief Stop the temperature profile execution.

View File

@@ -19,7 +19,7 @@
*/
/**
* @defgroup temp-profile Temperature Profile Parser and Executer
* @addtogroup temp-profile
* @{
*/
@@ -41,9 +41,6 @@ enum pl_command_type {
PL_LOUDSPEAKER_SET, /**< @brief Set the loudspeaker/beeper */
PL_OFF, /**< @brief Disable the temperature output and shutdown the PID controller */
PL_CLEAR_FLAGS, /**< @brief Try clear all flags */
PL_DIGIO_CONF, /**< @brief Configure a DIGIO pin */
PL_DIGIO_SET, /**< @brief Set a DIGIO pin */
PL_DIGIO_WAIT, /**< @brief Wait until a DIGIO pin is set to the specified level */
_PL_NUM_CMDS, /**< @brief Sentinel to determine the total amount of commands */
};
@@ -59,7 +56,7 @@ enum pl_ret_val {
};
/**
* @brief Maximum parameter count of a command.
* @brief Maximum parameter count of a command
*/
#define PROFILE_LANG_MAX_NUM_ARGS (8)
@@ -92,7 +89,7 @@ enum pl_ret_val temp_profile_parse_from_file(const char *filename,
uint32_t *cmds_parsed);
/**
* @brief Fully free a comamnd list including hte stored command structures.
* @brief Fully free a comamnd list including hte sotred command structures.
*
* \p list's destination is set to NULL to indicate the empty list.
*

View File

@@ -22,7 +22,6 @@
#define _GUI_H_
#include <stdint.h>
#include <stddef.h>
/**
* @brief Handle the reflow controller's LCD Menu
@@ -30,39 +29,10 @@
*/
int gui_handle(void);
/**
* @brief Initialize the GUI (LCD, button, and rotary encoder)
*/
void gui_init(void);
/**
* @brief Set a overlay message displayed on top of the root menu
* @param heading Heading of the overlay message (1st line)
* @param text Text of the overlay (the two bottom lines, 2 times 16 chars)
*/
void gui_root_menu_message_set(const char *heading, const char *text);
/**
* @brief Directly write to the LCD
*
* This function writes directly to the LCD and doesn't use the handling FSM in the
* background. Therefore, the function will block until all data is written to the LCD.
*
* @param line line to write to. Starts at 0
* @param text Text to write to the line
*/
void gui_lcd_write_direct_blocking(uint8_t line, const char *text);
/**
* @brief Get the vertical size of the display
* @return Count of rows
*/
size_t gui_get_line_count(void);
/**
* @brief Return the const char disp[][21] array contianing all display rows
* @note This directly returns the working buffer pointer. Do not change it!
*/
const char (*gui_get_current_display_content(void))[21];
#endif /* _GUI_H_ */

View File

@@ -1,51 +0,0 @@
/* Reflow Oven Controller
*
* Copyright (C) 2021 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 __SHELL_UART_H__
#include <shellmatta.h>
#include <stddef.h>
#include <stdint.h>
/**
* @brief Configure the UART for the shellmatta shell.
*
* This will configure the UART for use with a DMA ring buffer.
* @param uart
*/
void shell_uart_setup(void);
shellmatta_retCode_t shell_uart_write_callback(const char *data, uint32_t len);
int shell_uart_receive_data_with_dma(const char **data, size_t *len);
/**
* @brief Configure a new connection speed.
* @param new_baud Baudrate. E.g: 115200
* @return Error in permille (1/1000). A return value of 2 means a baudrate error of: 0.002 or 0.2%.
* Return value is negative in case of a hard error.
*/
int32_t shell_uart_reconfig_baud(uint32_t new_baud);
uint32_t shell_uart_get_current_baudrate(void);
#define __SHELL_UART_H__
#endif /* __SHELL_UART_H__ */

View File

@@ -1,45 +0,0 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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 _OPTION_BYTES_H_
#define _OPTION_BYTES_H_
#include <stdint.h>
struct option_bytes {
/* Word 1 */
uint32_t read_protection;// : 8;
uint32_t nrst_standby;// : 1;
uint32_t nrst_stop;// : 1;
uint32_t wdg_sw;// : 1;
uint32_t brown_out_level;// : 2;
/* Word 2 */
uint32_t nwrpi;// : 12;
};
/**
* @brief Read out the option bytes to structs
* @param opts
*/
void stm_option_bytes_read(struct option_bytes *opts);
int stm_option_bytes_program(const struct option_bytes *opts);
#endif /* _OPTION_BYTES_H_ */

View File

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

View File

@@ -50,8 +50,6 @@ int uart_init(struct stm_uart *uart);
void uart_change_brr(struct stm_uart *uart, uint32_t brr);
uint32_t uart_get_brr(struct stm_uart *uart);
void uart_disable(struct stm_uart *uart);
void uart_send_char(struct stm_uart *uart, char c);

View File

@@ -29,10 +29,6 @@
* @param mid mid word of ID
* @param low low word of ID
*/
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_cpuid_get(uint8_t *implementer, uint8_t *variant, uint16_t *part_no, uint8_t *rev);
void unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low);
#endif /* __UNIQUE_ID_H__ */

View File

@@ -18,19 +18,9 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @addtogroup main-cycle-counter
* @{
*/
#include <reflow-controller/main-cycle-counter.h>
#include <helper-macros/helper-macros.h>
/**
* @brief Variable storing the main cycle counter.
* @note This variable should not be accessed directly.
* Use the main_cycle_counter_get() or main_cycle_counter_inc() functions.
*/
static uint64_t IN_SECTION(.ccm.bss) main_cycle_counter;
void main_cycle_counter_init(void)
@@ -47,5 +37,3 @@ uint64_t main_cycle_counter_get(void)
{
return main_cycle_counter;
}
/** @} */

View File

@@ -31,6 +31,7 @@
#include <setup/system_stm32f4xx.h>
#include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h>
#include <reflow-controller/shell.h>
#include <reflow-controller/digio.h>
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
#include <stm-periph/stm32-gpio-macros.h>
@@ -40,8 +41,6 @@
#include <reflow-controller/oven-driver.h>
#include <fatfs/ff.h>
#include <reflow-controller/ui/gui.h>
#include <reflow-controller/ui/shell.h>
#include <reflow-controller/ui/shell-uart.h>
#include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/settings/settings.h>
#include <reflow-controller/safety/safety-memory.h>
@@ -50,7 +49,6 @@
#include <reflow-controller/temp-profile/temp-profile-executer.h>
#include <reflow-controller/settings/spi-eeprom.h>
#include <reflow-controller/main-cycle-counter.h>
#include <stm-periph/option-bytes.h>
static void setup_nvic_priorities(void)
{
@@ -69,13 +67,13 @@ static void setup_nvic_priorities(void)
FATFS fs;
#define fs_ptr (&fs)
/**
* @brief Configure UART GPIOs
* In case the application is build in debug mode, use the TX/RX Pins on the debug header
* else the Pins on the DIGIO header are configured in the digio module and this function does nothing.
*/
static inline void uart_gpio_config(void)
{
/*
* In case the application is build in debug mode, use the TX/RX Pins on the debug header
* else the Pins on the DIGIO header are configured in the digio module
*/
#if defined(DEBUGBUILD) || defined(UART_ON_DEBUG_HEADER)
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(SHELL_UART_PORT_RCC_MASK));
SHELL_UART_PORT->MODER &= MODER_DELETE(SHELL_UART_TX_PIN) & MODER_DELETE(SHELL_UART_RX_PIN);
@@ -88,11 +86,39 @@ static inline void uart_gpio_config(void)
#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 char shell_uart_tx_buff[256];
static char shell_uart_rx_buff[48];
struct stm_uart shell_uart;
static shellmatta_retCode_t write_shell_callback(const char *data, uint32_t len)
{
uart_send_array_with_dma(&shell_uart, data, len);
return SHELLMATTA_OK;
}
static inline void setup_shell_uart(struct stm_uart *uart)
{
uart->rx = 1;
uart->tx = 1;
uart->brr_val = SHELL_UART_BRR_REG_VALUE;
uart->rcc_reg = &SHELL_UART_RCC_REG;
uart->rcc_bit_no = BITMASK_TO_BITNO(SHELL_UART_RCC_MASK);
uart->uart_dev = SHELL_UART_PERIPH;
uart->dma_rx_buff = shell_uart_rx_buff;
uart->dma_tx_buff = shell_uart_tx_buff;
uart->rx_buff_count = sizeof(shell_uart_rx_buff);
uart->tx_buff_count = sizeof(shell_uart_tx_buff);
uart->base_dma_num = 2;
uart->dma_rx_stream = SHELL_UART_RECEIVE_DMA_STREAM;
uart->dma_tx_stream = SHELL_UART_SEND_DMA_STREAM;
uart->dma_rx_trigger_channel = SHELL_UART_RX_DMA_TRIGGER;
uart->dma_tx_trigger_channel = SHELL_UART_TX_DMA_TRIGGER;
uart_init(uart);
NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}
static bool mount_sd_card_if_avail(bool mounted)
{
FRESULT res;
@@ -122,13 +148,6 @@ static bool mount_sd_card_if_avail(bool mounted)
return mounted;
}
/**
* @brief Process the boot status structure in the safety (backup) RAM
* Depending on the flags set there, this function will:
* - Reboot into the ram code for reflashing
* - Display the PANIC message
* - Display if the flash has been successfully updated
*/
static inline void handle_boot_status(void)
{
struct safety_memory_boot_status status;
@@ -164,101 +183,34 @@ static inline void handle_boot_status(void)
}
}
/**
* @brief Read out the option bytes of the STM32 and program them to the desired values.
*
* - This function currently forces the brown out level to Level 3.
*/
static void check_and_program_opt_bytes(void)
{
struct option_bytes opts;
int err;
/** - Read option bytes */
stm_option_bytes_read(&opts);
if (opts.brown_out_level != 0) {
/* Set the brown out level to level 3 => highest brown out limit. */
opts.brown_out_level = 0;
/** - Program the option bytes if brown out level was not set correctly */
err = stm_option_bytes_program(&opts);
/** - If programming failes, enter panic mode */
if (err)
panic_mode();
/** - If programming is successful, reset the system to apply new settings */
NVIC_SystemReset();
}
}
/**
* @brief Setup the system.
*
* This function does all basic initializations of the MCU and its peripherals
*/
static inline void setup_system(void)
{
float tmp;
/** - Read the option bytes and if necessary program them to the desired values */
check_and_program_opt_bytes();
/** - Setup the NVIC priorities of the core peripherals using interrupts */
setup_nvic_priorities();
/** - Init safety controller and safety memory */
/* Init safety controller and safety memory */
safety_controller_init();
/** - Setup the systick module generating the 100us tick fort the GUI and
* the 1ms tick for the global systick timestamp
*/
systick_setup();
/** - Initialize the oven output driver outputting the wavepacket control signal for the SSR and */
oven_driver_init();
/** - Initialize all DIGIO Pins to their default state and pin functions */
digio_init();
/** - Set-up the LED outputs */
digio_setup_default_all();
led_setup();
/** - Set-up the loudspeaker / beeper output */
loudspeaker_setup();
/** - Initialize the GUI */
gui_init();
/** - Initialize the pins for the uart interface. */
uart_gpio_config();
/** - Set-up the settings module */
settings_setup();
/** - Load the overtemperature limit from eeprom if available. Otherwise the default value will be used */
/* Load the overtemperature limit from eeprom if available. Otherwise the default value will be used */
if (settings_load_overtemp_limit(&tmp) == SETT_LOAD_SUCCESS)
safety_controller_set_overtemp_limit(tmp);
/** - Handle the boot status struct in the safety memory */
handle_boot_status();
/** - Initialize the shell UART */
shell_uart_setup();
/** - Enable the ADC for PT1000 measurement */
setup_shell_uart(&shell_uart);
adc_pt1000_setup_meas();
}
/**
* @brief Handle the input for the shell instance.
*
* This function will check if the RX ring buffer of the UART contains data.
* If so, it will prowvide it to the shellmatta shell.
*
* @param shell_handle Handle to the shellmatta instance
*/
static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
{
int uart_receive_status;
@@ -266,15 +218,11 @@ static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
size_t uart_input_len;
/* Handle UART input for shell */
uart_receive_status = shell_uart_receive_data_with_dma(&uart_input, &uart_input_len);
uart_receive_status = uart_receive_data_with_dma(&shell_uart, &uart_input, &uart_input_len);
if (uart_receive_status >= 0)
shell_handle_input(shell_handle, uart_input, uart_input_len);
}
/**
* @brief This is the main function containing the initilizations and the cyclic main loop
* @return Don't care. This function will never return. We're on an embedded device...
*/
int main(void)
{
bool cal_active;
@@ -286,34 +234,24 @@ int main(void)
shellmatta_handle_t shell_handle;
int menu_wait_request;
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();
/** - Try load the calibration. This will only succeed if there's an EEPROM */
/* Try load the calibration. This will only succeed if there's an EEPROM */
status = settings_load_calibration(&sens, &offset);
if (!status)
adc_pt1000_set_resistance_calibration(offset, sens, true);
/** - Initialize the shellmatta shell */
shell_handle = shell_init(shell_uart_write_callback);
/** - Print motd to shell */
shell_handle = shell_init(write_shell_callback);
shell_print_motd(shell_handle);
/** - Set the main cycle counter to 0 */
main_cycle_counter_init();
/** - Do a loop over the following */
while (1) {
/** - If 250 ms have passed since the last time this step was reached, we try to initialize the
* SD card. If the card has been mounted and there is no current resistance calibration,
* it is tried to load it from SD card.
*/
if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) {
led_set(1u, 0);
led_set(1, 0);
sd_old = sd_card_mounted;
sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted);
@@ -326,59 +264,46 @@ 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();
}
/** - Handle the GUI */
menu_wait_request = gui_handle();
/** - Handle the uart input for the shell */
handle_shell_uart_input(shell_handle);
/** - Execute current profile step, if a profile is active */
/* Execute current profile step, if a profile is active */
temp_profile_executer_handle();
/** - Handle the safety controller. This must be called! Otherwise a watchdog reset will occur */
worst_safety_flag = safety_controller_handle();
/** - If the Oven PID controller is running, we handle its sample function */
safety_controller_handle();
if (oven_pid_get_status() == OVEN_PID_RUNNING)
oven_pid_handle();
/** - Apply the power level of the oven driver */
oven_driver_apply_power_level();
/** - Report the main loop timing to the timing monitor to detect a slowed down main loop */
safety_controller_report_timing(ERR_TIMING_MAIN_LOOP);
/** - If the menu requests a directly following loop run, the main loop will continue.
* Otherwise it will wait for the next interrupt
*/
if (menu_wait_request)
__WFI();
else
__NOP();
/** - Increment the main cycle counter */
main_cycle_counter_inc();
}
return 0;
}
/**
* @brief Callback function for the SDIO driver to wait \p ms milliseconds
* @param ms
* @warning This function relies on the systick and must not be used in interrupt context.
*/
void sdio_wait_ms(uint32_t ms)
{
systick_wait_ms(ms);
}
/**
* @brief Handles the TX of UART1 (Shellmatta)
*/
void DMA2_Stream7_IRQHandler(void)
{
uint32_t hisr = DMA2->HISR & (0x3F << 22);
DMA2->HIFCR = hisr;
if (hisr & DMA_HISR_TCIF7)
uart_tx_dma_complete_int_callback(&shell_uart);
}

View File

@@ -18,11 +18,6 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @addtogroup oven-driver
* @{
*/
#include <reflow-controller/oven-driver.h>
#include <reflow-controller/periph-config/oven-driver-hwcfg.h>
#include <stm-periph/rcc-manager.h>
@@ -33,42 +28,13 @@
#include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/hw-version-detect.h>
/**
* @brief PID controller instance of the oven driver
*/
static struct pid_controller IN_SECTION(.ccm.bss) oven_pid;
/**
* @brief Oven PID is currently running
*/
static bool IN_SECTION(.ccm.bss) oven_pid_running;
/**
* @brief Oven PID has been aborted / abnormally stopped.
*/
static bool IN_SECTION(.ccm.bss) oven_pid_aborted;
/**
* @brief Power level [0..100] of the oven to be applied
*/
static bool oven_pid_running;
static bool oven_pid_aborted;
static uint8_t IN_SECTION(.ccm.bss) oven_driver_power_level;
/**
* @brief Current target temperature of the oven PID controller in degC
*/
static float IN_SECTION(.ccm.bss) target_temp;
/**
* @brief The millisecond timestamp of the last run of the PID controller
*/
static uint64_t IN_SECTION(.ccm.bss) timestamp_last_run;
/**
* @brief Enable or disable the safety enable line of the oven control relay.
* @param enable
* @note This function is only working for hardware revisions >= v1.3. Below,
* the safety enable is unavailable.
*/
static void ssr_safety_en(bool enable)
{
if (get_pcb_hardware_version() >= HW_REV_V1_3) {
@@ -199,5 +165,3 @@ enum oven_pid_status oven_pid_get_status(void)
return ret;
}
/** @} */

View File

@@ -24,12 +24,6 @@
#include <reflow-controller/safety/safety-memory.h>
#include <helper-macros/helper-macros.h>
/**
* @brief Handler for hard faults.
*
* This hard fault handler will turn of the oven output and go to panic mode.
* @note Depending on the fault condition some of the things done here could fail.
*/
void HardFault_Handler(void)
{
/* This is a non recoverable fault. Stop the oven */
@@ -44,26 +38,11 @@ void HardFault_Handler(void)
}
/* Overwrite default handler. Go to panic mode */
/**
* @brief Default interrupt handler. This will trigger a panic.
* @note This function should never be called during normal operation.
*/
void __int_default_handler(void)
{
panic_mode();
}
/**
* @brief Put the device into panic mode.
*
* This function can be used when a irrecoverable error is encountered.
* The function will:
* - Disable the oven output
* - Set the panic flag in the safety memory
* - Hang and wait for the watchdog to trigger a system reset.
*
* The panic state will be entered after the reset due to the set panic flag in the safety memory
*/
void panic_mode(void)
{
/* This variable is static, because I don't want it to be on the stack */
@@ -78,6 +57,5 @@ void panic_mode(void)
}
/* Let the watchdog do the rest */
while (1)
;
while (1);
}

View File

@@ -1,31 +0,0 @@
/* 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

@@ -1,152 +0,0 @@
/* 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
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/>.
*/
/**
* @addtogroup safety-adc
@@ -31,22 +31,8 @@
#include <reflow-controller/safety/safety-controller.h>
static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS};
/**
* @brief Safety ADC conversion complete. Set in interrupt.
*/
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_conversion_complete;
/**
* @brief Safety ADC has been started. It will perform all specified conversions and
* set @ref safety_adc_conversion_complete afterwards
*/
static volatile uint8_t IN_SECTION(.ccm.bss) safety_adc_triggered;
/**
* @brief Safety ADC conversion storage. This is filled by DMA.
* @note Do not move this to CCM RAM as the DMA won't be able to access it.
*/
static volatile uint8_t safety_adc_conversion_complete;
static volatile uint8_t safety_adc_triggered;
static volatile uint16_t safety_adc_conversions[SAFETY_ADC_NUM_OF_CHANNELS];
void safety_adc_init(void)
@@ -60,8 +46,7 @@ void safety_adc_init(void)
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN));
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 |= ANALOG(SAFETY_ADC_SUPPLY_VOLTAGE_MONITOR_PIN);
}
@@ -73,7 +58,7 @@ void safety_adc_init(void)
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15;
/* 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->SQR3 = 0UL;
@@ -98,8 +83,7 @@ void safety_adc_init(void)
DMA2_Stream4->PAR = (uint32_t)&SAFETY_ADC_ADC_PERIPHERAL->DR;
DMA2_Stream4->M0AR = (uint32_t)safety_adc_conversions;
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);
/* Enable ADC */
@@ -177,7 +161,7 @@ void safety_adc_trigger_meas(void)
safety_adc_triggered = 1;
}
void DMA2_Stream4_IRQHandler(void)
void DMA2_Stream4_IRQHandler()
{
uint32_t hisr;

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/>.
*/
/**
* @addtogroup safety-controller
@@ -43,7 +43,6 @@
#include <stm-periph/rcc-manager.h>
#include <reflow-controller/temp-converter.h>
#include <reflow-controller/adc-meas.h>
#include <reflow-controller/safety/flash-crc.h>
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
/**
@@ -155,6 +154,15 @@ struct overtemp_config {
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 {
const volatile void *reg_addr;
uint32_t mask;
@@ -207,8 +215,8 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
};
/**
* @brief All timing monitors
*/
* @brief All timing monitors
*/
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_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC),
@@ -290,7 +298,7 @@ static const struct crc_monitor_register meas_adc_crc_regs[] = {
ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 |
ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4),
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}
};
@@ -306,11 +314,12 @@ static const struct crc_monitor_register safety_adc_crc_regs[] = {
ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 |
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 |
ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4),
ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4),
{NULL, 0, 0}
};
static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = {
static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] =
{
{
.registers = meas_adc_crc_regs,
.monitor = ERR_CRC_MON_MEAS_ADC,
@@ -351,22 +360,16 @@ static void set_overtemp_config(float over_temperature)
safety_controller_overtemp_config.crc_dummy_seed = 0xA4F5C7E6UL;
safety_controller_overtemp_config.overtemp_deg_celsius = over_temperature;
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();
}
/**
* @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)
{
if (safety_controller_overtemp_config.crc_dummy_seed != 0xA4F5C7E6UL)
return true;
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)
return true;
@@ -439,7 +442,7 @@ static int flag_weight_table_crc_check(void)
static int flag_persistence_table_crc_check(void)
{
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)
return -1;
@@ -516,8 +519,9 @@ static int safety_controller_check_crc_monitors(void)
if (crc_monitor_calculate_crc(mon->registers, &crc))
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);
}
mon->last_crc = crc;
}
@@ -544,7 +548,7 @@ static void init_safety_flag_weight_table_from_default(void)
}
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();
}
@@ -604,14 +608,16 @@ static void apply_config_overrides(void)
case SAFETY_MEMORY_CONFIG_OVERRIDE_WEIGHT:
flag_enum = flag_no_to_flag_enum(override.entry.weight_override.flag);
flag = find_error_flag(flag_enum);
if (flag && flag->weight)
if (flag && flag->weight) {
flag->weight->weight = override.entry.weight_override.weight;
}
break;
case SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTENCE:
flag_enum = flag_no_to_flag_enum(override.entry.persistence_override.flag);
flag = find_error_flag(flag_enum);
if (flag && flag->persistence)
if (flag && flag->persistence) {
flag->persistence->persistence = override.entry.persistence_override.persistence;
}
break;
default:
continue;
@@ -623,7 +629,7 @@ static void apply_config_overrides(void)
crc_unit_input_array((uint32_t *)flag_persistencies, wordsize_of(flag_persistencies));
flag_persistencies_crc = crc_unit_get_crc();
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();
}
@@ -641,10 +647,11 @@ static bool error_flag_get_status(const volatile struct error_flag *flag)
if (!flag)
return true;
if (flag->error_state == flag->error_state_inv)
if (flag->error_state == flag->error_state_inv) {
return true;
else
} else {
return flag->error_state;
}
}
/**
@@ -686,7 +693,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.
*/
static void safety_controller_process_active_timing_mons(void)
static void safety_controller_process_active_timing_mons()
{
uint32_t i;
volatile struct timing_mon *current_mon;
@@ -709,8 +716,7 @@ static void safety_controller_process_active_timing_mons(void)
* 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
*
* 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)
{
@@ -725,18 +731,21 @@ static void safety_controller_process_monitor_checks(void)
if (startup_completed) {
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)) {
panic_mode();
}
if (amon_info.status != ANALOG_MONITOR_OK)
if (amon_info.status != ANALOG_MONITOR_OK) {
safety_controller_report_error(amon_info.associated_flag);
}
}
}
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);
}
(void)safety_controller_check_crc_monitors();
@@ -770,7 +779,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].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) {
err_mem_entry.counter = 1;
err_mem_entry.flag_num = flag_enum_to_flag_no(flags[i].flag);
@@ -811,8 +820,9 @@ void safety_controller_report_timing(enum timing_monitor monitor)
tim = find_timing_mon(monitor);
if (tim) {
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);
}
}
tim->calculated_delta = timestamp - tim->last;
@@ -860,8 +870,9 @@ static int get_safety_flags_from_error_mem(enum safety_flag *flags)
for (idx = 0; idx < count; idx++) {
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);
}
}
*flags = return_flags;
@@ -873,12 +884,11 @@ 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.
* 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.
*/
static void safety_controller_init_external_watchdog(void)
static void safety_controller_init_external_watchdog()
{
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);
@@ -889,7 +899,7 @@ static void safety_controller_init_external_watchdog(void)
__DSB();
}
void safety_controller_init(void)
void safety_controller_init()
{
enum safety_memory_state found_memory_state;
enum safety_flag flags_in_err_mem = ERR_FLAG_NO_FLAG;
@@ -906,7 +916,7 @@ void safety_controller_init(void)
/* This is usually done by the safety memory already. But, since this module also uses the CRC... */
crc_unit_init();
flash_crc_trigger_check();
safety_controller_trigger_flash_crc_check();
stack_check_init_corruption_detect_area();
hw_rev = get_pcb_hardware_version();
@@ -957,7 +967,7 @@ void safety_controller_init(void)
* 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
*/
static void safety_controller_check_stack(void)
static void safety_controller_check_stack()
{
int32_t free_stack;
@@ -965,17 +975,18 @@ static void safety_controller_check_stack(void)
if (free_stack < SAFETY_MIN_STACK_FREE)
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);
}
}
/**
* @brief Handle the Safety ADC
*
* This function handles the safety ADC.
* 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 on all of its channels.
* If the safety ADC ius 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
* on all of its channels.
* 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.
*
@@ -984,7 +995,7 @@ static void safety_controller_check_stack(void)
*
* 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(void)
static void safety_controller_handle_safety_adc()
{
static uint64_t last_result_timestamp = 0;
const uint16_t *channels;
@@ -1055,8 +1066,9 @@ static void safety_controller_handle_memory_checks(void)
/* Check the safety memory */
if (safety_memory_check()) {
(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);
}
}
/* If flag weight table is broken, reinit to default and set flag */
@@ -1066,7 +1078,7 @@ static void safety_controller_handle_memory_checks(void)
}
/* 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);
init_safety_flag_persistencies_from_default();
}
@@ -1085,7 +1097,7 @@ static void safety_controller_handle_memory_checks(void)
* If the systick stays constant for more than 1000 calls of this function,
* the @ref ERR_FLAG_SYSTICK flag is set.
*/
static void safety_controller_do_systick_checking(void)
static void safety_controller_do_systick_checking()
{
static uint64_t last_systick;
static uint32_t same_systick_cnt = 0UL;
@@ -1109,29 +1121,22 @@ static void safety_controller_do_systick_checking(void)
* 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
* (@ref SAFETY_FLAG_CONFIG_WEIGHT_PANIC)
*
* @returns Worst config weight set
*/
static enum config_weight safety_controller_handle_weighted_flags(void)
static void safety_controller_handle_weighted_flags()
{
uint32_t flag_index;
volatile struct error_flag *current_flag;
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++) {
current_flag = &flags[flag_index];
/* Continue if this flag is not set */
if (!error_flag_get_status(current_flag))
if (!error_flag_get_status(current_flag)) {
continue;
}
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) {
case SAFETY_FLAG_CONFIG_WEIGHT_NONE:
break;
@@ -1147,20 +1152,18 @@ static enum config_weight safety_controller_handle_weighted_flags(void)
}
}
return worst;
}
#ifndef DEBUGBUILD
static void external_watchdog_toggle(void)
static void external_watchdog_toggle()
{
SAFETY_EXT_WATCHDOG_PORT->ODR ^= (1<<SAFETY_EXT_WATCHDOG_PIN);
}
#endif
enum config_weight safety_controller_handle(void)
int safety_controller_handle()
{
enum config_weight worst_weight_set;
int ret = 0;
#ifndef DEBUGBUILD
static uint32_t watchdog_counter = 0UL;
#endif
@@ -1170,10 +1173,9 @@ enum config_weight safety_controller_handle(void)
safety_controller_handle_memory_checks();
safety_controller_do_systick_checking();
safety_controller_process_monitor_checks();
worst_weight_set = safety_controller_handle_weighted_flags();
safety_controller_handle_weighted_flags();
/* Ignore error here. Will trigger restart anyway */
(void)watchdog_ack(WATCHDOG_MAGIC_KEY);
ret |= watchdog_ack(WATCHDOG_MAGIC_KEY);
#ifndef DEBUGBUILD
if (get_pcb_hardware_version() != HW_REV_V1_2) {
@@ -1184,8 +1186,7 @@ enum config_weight safety_controller_handle(void)
}
}
#endif
return worst_weight_set;
return (ret ? -1 : 0);
}
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable)
@@ -1272,8 +1273,9 @@ int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key)
int ret = -1;
volatile struct error_flag *found_flag;
if (!is_power_of_two(flag))
if (!is_power_of_two(flag)) {
return -1001;
}
found_flag = find_error_flag(flag);
if (found_flag) {
@@ -1304,17 +1306,17 @@ bool safety_controller_get_flags_by_mask(enum safety_flag mask)
return ret;
}
uint32_t safety_controller_get_flag_count(void)
uint32_t safety_controller_get_flag_count()
{
return COUNT_OF(flags);
}
uint32_t safety_controller_get_analog_monitor_count(void)
uint32_t safety_controller_get_analog_monitor_count()
{
return COUNT_OF(analog_mons);
}
uint32_t safety_controller_get_timing_monitor_count(void)
uint32_t safety_controller_get_timing_monitor_count()
{
return COUNT_OF(timings);
}
@@ -1421,8 +1423,9 @@ int safety_controller_get_timing_mon_by_index(uint32_t index, struct timing_moni
if (!info)
return -1002;
if (index >= COUNT_OF(timings))
if (index >= COUNT_OF(timings)) {
return -1001;
}
mon = &timings[index];
@@ -1446,6 +1449,99 @@ float safety_controller_get_overtemp_limit(void)
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)
{
uint32_t i;

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/safety-memory.h>
#include <helper-macros/helper-macros.h>
@@ -99,8 +99,7 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he
res = 0;
if (header->boot_status_offset < wordsize_of(struct safety_memory_header))
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++;
if (header->config_overrides_len > SAFETY_MEMORY_CONFIG_OVERRIDE_COUNT)
res++;
@@ -108,8 +107,7 @@ static enum safety_memory_state safety_memory_get_header(struct safety_memory_he
res++;
if (header->err_memory_offset < header->firmware_update_filename + (SAFETY_MEMORY_UPDATE_FILENAME_MAXSIZE / 4))
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++;
if (res) {
@@ -150,7 +148,7 @@ static void safety_memory_write_new_header(void)
safety_memory_write_and_patch_header(&header);
}
static int safety_memory_check_crc(void)
static int safety_memory_check_crc()
{
struct safety_memory_header header;
enum safety_memory_state state = safety_memory_get_header(&header);
@@ -183,7 +181,7 @@ static int safety_memory_check_crc(void)
return 0;
}
static int safety_memory_gen_crc(void)
static int safety_memory_gen_crc()
{
struct safety_memory_header header;
uint32_t word_addr;
@@ -270,8 +268,9 @@ int safety_memory_get_boot_status(struct safety_memory_boot_status *status)
if (!status)
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;
}
if (safety_memory_check_crc())
return -2001;
@@ -290,8 +289,9 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status
if (!status)
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;
}
if (safety_memory_check_crc())
return -2001;
@@ -304,7 +304,7 @@ int safety_memory_set_boot_status(const struct safety_memory_boot_status *status
return 0;
}
static int safety_memory_check_error_entries(void)
static int safety_memory_check_error_entries()
{
struct safety_memory_header header;
uint32_t addr;
@@ -312,8 +312,9 @@ static int safety_memory_check_error_entries(void)
int ret = 0;
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;
}
for (addr = header.err_memory_offset; addr < header.err_memory_end; addr++) {
res = backup_ram_get_data(addr, &data, 1UL);
@@ -339,8 +340,9 @@ int safety_memory_get_error_entry_count(uint32_t *count)
if (!count)
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;
}
*count = header.err_memory_end - header.err_memory_offset;
@@ -352,8 +354,9 @@ int safety_memory_check(void)
int res;
res = safety_memory_check_crc();
if (!res)
if (!res) {
res |= safety_memory_check_error_entries();
}
return -!!res;
}
@@ -369,8 +372,9 @@ int safety_memory_get_error_entry(uint32_t idx, struct error_memory_entry *entry
if (!entry)
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;
}
err_mem_count = header.err_memory_end - header.err_memory_offset;
if (idx < err_mem_count && err_mem_count > 0) {
@@ -406,8 +410,9 @@ int safety_memory_insert_error_entry(struct error_memory_entry *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;
}
if (entry->type == SAFETY_MEMORY_ERR_ENTRY_NOP) {
/* Append to end */
@@ -505,8 +510,9 @@ int safety_memory_insert_config_override(struct config_override *config_override
int res;
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;
}
if (header.config_overrides_len == 0)
return -1;
@@ -544,8 +550,9 @@ int safety_memory_get_config_override_count(uint32_t *count)
*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;
}
if (header.config_overrides_len == 0)
return 0;
@@ -575,15 +582,18 @@ int safety_memory_get_config_override(uint32_t idx, struct config_override *conf
if (!config_override)
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;
}
if (idx >= header.config_overrides_len)
if (idx >= header.config_overrides_len) {
return -1001;
}
res = backup_ram_get_data(header.config_overrides_offset + idx, &data, 1UL);
if (res)
if (res) {
return -1;
}
switch (data & 0xFF) {
case 0xA2:
@@ -639,8 +649,8 @@ int safety_memory_get_update_filename(char *filename, size_t *outlen)
{
struct safety_memory_header header;
unsigned int i;
size_t len = 0u;
volatile char *ptr;
size_t len = 0u;
/* If filename and outlen are both NULL, we don't do anything */
if (!filename && !outlen)
@@ -686,9 +696,9 @@ int safety_memory_set_update_filename(const char *filename)
ram_ptr = backup_ram_get_base_ptr();
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] = 0;
ret = safety_memory_gen_crc();

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/stack-check.h>
#include <stdint.h>
@@ -26,7 +26,7 @@
extern char __ld_top_of_stack;
extern char __ld_end_stack;
int32_t stack_check_get_usage(void)
int32_t stack_check_get_usage()
{
uint32_t stack_top;
uint32_t stack_ptr;
@@ -37,7 +37,7 @@ int32_t stack_check_get_usage(void)
return stack_top - stack_ptr;
}
int32_t stack_check_get_free(void)
int32_t stack_check_get_free()
{
uint32_t upper_heap_boundary;
uint32_t stack_ptr;
@@ -102,6 +102,9 @@ int stack_check_corruption_detect_area(void)
&__ld_start_stack_corruption_detect_area;
crc_unit_reset();
crc_unit_input_array(&__ld_start_stack_corruption_detect_area, area_size_in_words);
return crc_unit_get_crc() == 0UL ? 0 : -1;
if (crc_unit_get_crc() == 0UL) {
return 0;
} else {
return -1;
}
}

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/>.
*/
/**
* @addtogroup watchdog
@@ -50,8 +50,7 @@ int watchdog_setup(uint8_t prescaler)
RCC->CSR |= RCC_CSR_LSION;
__DSB();
/** - Wait for the oscillator to be ready */
while (!(RCC->CSR & RCC_CSR_LSIRDY))
;
while (!(RCC->CSR & RCC_CSR_LSIRDY));
if (prescaler == 4U)
prescaler_reg_val = 0UL;
@@ -68,25 +67,17 @@ int watchdog_setup(uint8_t prescaler)
else
prescaler_reg_val = 6UL;
/** - (De)activate the watchdog during debug access according to @ref WATCHDOG_HALT_DEBUG */
if (WATCHDOG_HALT_DEBUG)
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP;
else
DBGMCU->APB1FZ &= ~DBGMCU_APB1_FZ_DBG_IWDG_STOP;
/** - Unlock registers */
IWDG->KR = STM32_WATCHDOG_REGISTER_ACCESS_KEY;
/** - Wait until prescaler can be written */
while (IWDG->SR & IWDG_SR_PVU)
;
while (IWDG->SR & IWDG_SR_PVU);
/** - Write prescaler value */
IWDG->PR = prescaler_reg_val;
/* - 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 */
IWDG->RLR = 0xFFFU;

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/settings/settings-eeprom.h>
#include <reflow-controller/settings/spi-eeprom.h>
@@ -37,7 +37,6 @@ 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 {
float over_temperature;
uint32_t over_temp_crc;
@@ -55,15 +54,15 @@ static bool check_eeprom_header(void)
return true;
}
static void settings_eeprom_zero(void)
static void settings_eeprom_zero()
{
settings_eeprom_save_calibration(0.0f, 0.0f, false);
settings_eeprom_save_overtemp_limit(0.0f, false);
settings_eeprom_save_overtemp_limit(0.0, false);
}
bool settings_eeprom_detect_and_prepare(void)
{
bool eeprom_ready = false;
bool eeprom_ready = false;;
int res;
@@ -78,10 +77,7 @@ bool settings_eeprom_detect_and_prepare(void)
if (check_eeprom_header() == false) {
/* Try to write a new header and check it again */
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) {
goto ret_deinit_crc;
} else {

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/settings/settings-sd-card.h>
#include <stm-periph/unique-id.h>
@@ -38,7 +38,7 @@ static void get_controller_folder_path(char *path, size_t size)
if (!path)
return;
stm_unique_id_get(&high, &mid, &low);
unique_id_get(&high, &mid, &low);
snprintf(path, size, "/%08X-%08X-%08X",
(unsigned int)high, (unsigned int)mid, (unsigned int)low);
@@ -72,12 +72,18 @@ static int create_controller_folder(void)
ret = 0;
} else {
filesystem_result = f_mkdir(foldername);
ret = filesystem_result == FR_OK ? 1 : -1;
if (filesystem_result == FR_OK) {
ret = 1;
} else {
ret = -1;
}
}
return ret;
}
int sd_card_settings_save_calibration(float sens_deviation, float offset, bool active)
{
char path[200];

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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/>.
*/
*
* Copyright (C) 2020 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/settings/settings.h>
#include <reflow-controller/settings/settings-sd-card.h>
@@ -39,7 +39,7 @@ int settings_load_calibration(float *sens_dev, float *offset)
int res;
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)
res = -1;
} else {

View File

@@ -1,22 +1,22 @@
/* Reflow Oven Controller
*
* Copyright (C) 2021 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/>.
*/
*
* Copyright (C) 2021 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/settings/spi-eeprom.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);
}
int spi_eeprom_init(void)
int spi_eeprom_init()
{
static struct stm_spi_dev spi_dev;
struct stm_spi_settings settings;
@@ -61,8 +61,7 @@ int spi_eeprom_init(void)
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);
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);
SETAF(SPI_EEPROM_SPI_PORT, SPI_EEPROM_MISO_PIN, SPI_EEPROM_SPI_ALTFUNC_NO);
@@ -86,7 +85,7 @@ int spi_eeprom_init(void)
return -1;
}
void spi_eeprom_deinit(void)
void spi_eeprom_deinit()
{
spi_deinit(eeprom_spi_handle);
@@ -167,8 +166,7 @@ static void spi_eeprom_do_write_page(uint32_t addr, const uint8_t *data, uint8_t
uint8_t cmd[2];
/* Wait for the previous write to finish */
while (spi_eeprom_write_in_progress())
;
while (spi_eeprom_write_in_progress());
/* Set the write enable latch */
spi_eeprom_set_write_enable_latch(true);

View File

@@ -20,7 +20,7 @@
#include <stm32/stm32f4xx.h>
#include <cmsis/core_cm4.h>
#include <reflow-controller/ui/shell.h>
#include <reflow-controller/shell.h>
#include <stm-periph/uart.h>
#include <string.h>
#include <reflow-controller/adc-meas.h>
@@ -45,11 +45,6 @@
#include <reflow-controller/temp-profile/temp-profile-executer.h>
#include <reflow-controller/updater/updater.h>
#include <reflow-controller/main-cycle-counter.h>
#include <stm-periph/option-bytes.h>
#include <reflow-controller/ui/gui.h>
#include <reflow-controller/ui/shell-uart.h>
#include <reflow-controller/safety/flash-crc.h>
#include <stdio.h>
#ifndef GIT_VER
@@ -69,20 +64,13 @@ static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
uint32_t low_id;
uint32_t mid_id;
uint32_t high_id;
uint32_t stm_rev_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;
enum hw_revision pcb_rev;
stm_unique_id_get(&high_id, &mid_id, &low_id);
stm_dev_rev_id_get(&stm_dev_id, &stm_rev_id);
unique_id_get(&high_id, &mid_id, &low_id);
shellmatta_printf(handle, "Reflow Oven Controller Firmware " xstr(GIT_VER) "\r\n"
"Compiled: " __DATE__ " at " __TIME__ "\r\n");
"Compiled: " __DATE__ " at " __TIME__ "\r\n");
shellmatta_printf(handle, "Serial: %08X-%08X-%08X\r\n", high_id, mid_id, low_id);
pcb_rev = get_pcb_hardware_version();
@@ -93,23 +81,11 @@ static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
case HW_REV_V1_3:
hw_rev_str = "Hardware: v1.3";
break;
case HW_REV_V1_3_1:
hw_rev_str = "Hardware: v1.3.1";
break;
default:
hw_rev_str = "Hardware: Unknown Revision. You might have to update the firmware!";
break;
}
shellmatta_printf(handle, "%s\r\n", hw_rev_str);
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);
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);
shellmatta_printf(handle, "%s", hw_rev_str);
return SHELLMATTA_OK;
}
@@ -497,11 +473,6 @@ static shellmatta_retCode_t shell_cmd_ui_emulation(const shellmatta_handle_t han
uint32_t i;
uint32_t len;
char *buff;
uint8_t row;
uint8_t col;
bool disp_content_differs = false;
static char IN_SECTION(.ccm.bss) display_buffer[4][21] = {0};
const char (*current_display)[21];
shellmatta_read(handle, &buff, &len);
@@ -530,39 +501,6 @@ static shellmatta_retCode_t shell_cmd_ui_emulation(const shellmatta_handle_t han
case 'R':
button_override_event(BUTTON_LONG_RELEASED);
break;
case '\x03':
/* CTRL-C received. Delete the display buffer so it will be updated the next time
* This function is called.
* Otherwise the diplay might not be printed to the console if nothing has changed
*/
display_buffer[0][0] = 0;
display_buffer[1][0] = 0;
display_buffer[2][0] = 0;
display_buffer[3][0] = 0;
return SHELLMATTA_OK;
break;
}
}
current_display = gui_get_current_display_content();
for (row = 0; row < 4; row++) {
for (col = 0; col < 21; col++) {
if (current_display[row][col] != display_buffer[row][col]) {
display_buffer[row][col] = current_display[row][col];
disp_content_differs = true;
}
}
display_buffer[row][20] = 0;
}
if (disp_content_differs) {
/* Clear the display */
shellmatta_printf(handle, "\e[2J\e[H");
/* Print out the rows of the LCD to console */
for (row = 0; row < 4; row++) {
shellmatta_printf(handle, "%s\r\n", &display_buffer[row][0]);
}
}
@@ -779,7 +717,7 @@ shellmatta_retCode_t shell_cmd_overtemp_cfg(const shellmatta_handle_t handle, co
shellmatta_retCode_t shell_cmd_execute(const shellmatta_handle_t handle, const char *args, uint32_t len)
{
enum pl_ret_val res;
const struct tpe_exec_state *state;
const struct tpe_current_state *state;
static bool running = false;
char *data;
uint32_t dlen;
@@ -860,7 +798,6 @@ 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)
{
uint64_t counter;
uint32_t core_cycle_count;
(void)args;
(void)len;
char option;
@@ -868,10 +805,8 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con
uint32_t arg_len;
int opt_stat;
bool clear = false;
bool hex = false;
const shellmatta_opt_long_t options[] = {
{"clear", 'c', SHELLMATTA_OPT_ARG_NONE},
{"hex", 'h', SHELLMATTA_OPT_ARG_NONE},
{NULL, '\0', SHELLMATTA_OPT_ARG_NONE},
};
@@ -883,8 +818,6 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con
case 'c':
clear = true;
break;
case 'h':
hex = true;
default:
break;
}
@@ -892,18 +825,10 @@ shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, con
counter = main_cycle_counter_get();
core_cycle_count = DWT->CYCCNT;
if (hex) {
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) {
shellmatta_printf(handle, "%"PRIu64"\r\n", counter);
if (clear)
main_cycle_counter_init();
DWT->CYCCNT = 0UL;
}
return SHELLMATTA_OK;
}
@@ -952,122 +877,6 @@ shellmatta_retCode_t shell_cmd_filter_alpha(const shellmatta_handle_t handle, co
return SHELLMATTA_OK;
}
shellmatta_retCode_t shell_cmd_print_opt_bytes(const shellmatta_handle_t handle,
const char *args, uint32_t len)
{
(void)args;
(void)len;
struct option_bytes opts;
stm_option_bytes_read(&opts);
shellmatta_printf(handle, "Brown-out Level: 0x%x\r\n", opts.brown_out_level);
shellmatta_printf(handle, "nRST Standby: 0x%x\r\n", opts.nrst_standby);
shellmatta_printf(handle, "nRST Stop: 0x%x\r\n", opts.nrst_stop);
shellmatta_printf(handle, "Write Protection: 0x%x\r\n", opts.nwrpi);
shellmatta_printf(handle, "Read Protection: 0x%x\r\n", opts.read_protection);
shellmatta_printf(handle, "SW Watchdog: 0x%x\r\n", opts.wdg_sw);
return SHELLMATTA_OK;
}
shellmatta_retCode_t shell_cmd_set_baud(const shellmatta_handle_t handle, const char *args, uint32_t len)
{
shellmatta_retCode_t opt_stat;
char option;
char *argument;
uint32_t arg_len;
char *baud_string = NULL;
uint32_t baud;
(void)len;
(void)args;
const shellmatta_opt_long_t options[] = {
{NULL, '\0', SHELLMATTA_OPT_ARG_NONE},
};
while (1) {
opt_stat = shellmatta_opt_long(handle, options, &option, &argument, &arg_len);
if (opt_stat != SHELLMATTA_OK)
break;
switch (option) {
case '\0':
baud_string = argument;
break;
default:
break;
}
}
shellmatta_printf(handle, "Current baudrate: %u\r\n", (unsigned int)shell_uart_get_current_baudrate());
if (!baud_string) {
shellmatta_printf(handle, "Please specify a baudrate\r\n");
return SHELLMATTA_OK;
}
baud = strtoul(baud_string, NULL, 0);
if (baud < 38400) {
shellmatta_printf(handle, "38400 is the minimum recommended baudrate!\r\n");
}
shellmatta_printf(handle, "Setting baud to: %u\r\n", (unsigned int)baud);
if (shell_uart_reconfig_baud(baud) < 0) {
shellmatta_printf(handle,"Setting baudrate not possible. Error greater than 2%%\r\n");
}
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
//{
// char *cmd; /**< command name */
@@ -1077,7 +886,7 @@ shellmatta_retCode_t shell_cmd_flash_crc(const shellmatta_handle_t handle, const
// shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */
//} shellmatta_cmd_t;
static shellmatta_cmd_t cmd[26] = {
static shellmatta_cmd_t cmd[24] = {
{
.cmd = "version",
.cmdAlias = "ver",
@@ -1261,33 +1070,8 @@ static shellmatta_cmd_t cmd[26] = {
.helpText = "Sets the filter constant",
.usageText = "filter-alpha <alpha>",
.cmdFct = shell_cmd_filter_alpha,
.next = &cmd[23],
},
{
.cmd = "print-option-bytes",
.cmdAlias = "opt-bytes",
.helpText = "Print the currently set option bytes of the STM32",
.usageText = "",
.cmdFct = shell_cmd_print_opt_bytes,
.next = &cmd[24],
},
{
.cmd = "baudrate",
.cmdAlias = "baud",
.helpText = "Set a new temporary baudrate for the UART",
.usageText = "baudrate <new 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,
},
}
};
shellmatta_handle_t shell_init(shellmatta_write_t write_func)

View File

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

View File

@@ -37,10 +37,11 @@ static size_t calculate_ring_buffer_fill_level(size_t buffer_size, size_t get_id
{
size_t fill_level;
if (put_idx >= get_idx)
if (put_idx >= get_idx) {
fill_level = (put_idx - get_idx);
else
} else {
fill_level = buffer_size - get_idx + put_idx;
}
return fill_level;
}
@@ -48,7 +49,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)
{
int ret_val;
int (*clk_func)(volatile uint32_t *reg, uint8_t bit_no);
int (*clk_func)(volatile uint32_t *, uint8_t);
if (clk_en)
clk_func = rcc_manager_enable_clock;
@@ -71,9 +72,8 @@ 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,
DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count,
size_t element_size, volatile void *data_buffer,
void *src_reg, uint8_t dma_trigger_channel)
DMA_Stream_TypeDef *dma_stream, size_t buffer_element_count, size_t element_size,
volatile void *data_buffer, void* src_reg, uint8_t dma_trigger_channel)
{
int ret_val = 0;
@@ -106,8 +106,7 @@ int dma_ring_buffer_periph_to_mem_initialize(struct dma_ring_buffer_to_mem *dma_
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;
uint32_t ndtr;
@@ -168,10 +167,7 @@ int dma_ring_buffer_periph_to_mem_fill_level(struct dma_ring_buffer_to_mem *buff
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)
return -1000;
@@ -225,8 +221,7 @@ static void queue_or_start_dma_transfer(struct dma_ring_buffer_to_periph *buff)
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;
size_t free_item_count;
@@ -239,8 +234,7 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *
return -1000;
/* 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) {
ret = dma_ring_buffer_mem_to_periph_insert_data(buff, data_to_insert, buff->buffer_count - 1);
@@ -253,9 +247,7 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *
/* Wait for buffer to be able to handle input */
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);
/* Fillup buffer (max is buffer end, wrap around afterwards) */
@@ -269,7 +261,7 @@ int dma_ring_buffer_mem_to_periph_insert_data(struct dma_ring_buffer_to_periph *
buff->sw_put_idx += count;
/* 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;
} else {
/* Fill up to end of buffer and fill rest after wrap around */

View File

@@ -1,92 +0,0 @@
/* Reflow Oven Controller
*
* Copyright (C) 2021 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 <stm-periph/option-bytes.h>
#include <stm32/stm32f4xx.h>
/**
* @brief First key for unlocking hte option byte write access
*/
#define FLASH_OPTION_KEY1 (0x08192A3BUL)
/**
* @brief Second key for unlocking hte option byte write access
*/
#define FLASH_OPTION_KEY2 (0x4C5D6E7FUL)
void stm_option_bytes_read(struct option_bytes *opts)
{
uint32_t opt_reg;
if (!opts)
return;
opt_reg = FLASH->OPTCR;
opts->brown_out_level = (opt_reg & FLASH_OPTCR_BOR_LEV) >> 2;
opts->nrst_standby = (opt_reg & FLASH_OPTCR_nRST_STDBY) >> 7;
opts->nrst_stop = (opt_reg & FLASH_OPTCR_nRST_STOP) >> 6;
opts->nwrpi = (opt_reg & FLASH_OPTCR_nWRP) >> 16;
opts->read_protection = (opt_reg & FLASH_OPTCR_RDP) >> 8;
opts->wdg_sw = (opt_reg & FLASH_OPTCR_WDG_SW) >> 5;
}
int stm_option_bytes_program(const struct option_bytes *opts)
{
uint32_t reg;
FLASH->OPTKEYR = FLASH_OPTION_KEY1;
FLASH->OPTKEYR = FLASH_OPTION_KEY2;
__DSB();
if (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) {
/* Unlocking failed */
return -1;
}
reg = FLASH->OPTCR;
reg &= ~FLASH_OPTCR_BOR_LEV;
reg &= ~FLASH_OPTCR_nRST_STDBY;
reg &= ~FLASH_OPTCR_nRST_STOP;
reg &= ~FLASH_OPTCR_nWRP;
reg &= ~FLASH_OPTCR_RDP;
reg &= ~FLASH_OPTCR_WDG_SW;
reg |= (opts->brown_out_level << 2) & FLASH_OPTCR_BOR_LEV;
reg |= (opts->nrst_standby << 7) & FLASH_OPTCR_nRST_STDBY;
reg |= (opts->nrst_stop << 6) & FLASH_OPTCR_nRST_STOP;
reg |= (opts->nwrpi << 16) & FLASH_OPTCR_nWRP;
reg |= (opts->read_protection << 8) & FLASH_OPTCR_RDP;
reg |= (opts->wdg_sw << 5) & FLASH_OPTCR_WDG_SW;
while (FLASH->SR & FLASH_SR_BSY)
;
FLASH->OPTCR = reg;
FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT;
__DSB();
while (FLASH->SR & FLASH_SR_BSY)
;
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK;
__DSB();
return 0;
}

View File

@@ -95,8 +95,9 @@ int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit
int ret_val = 0;
struct rcc_enable_count *entry;
if (!rcc_enable_register || bit_no > 31)
if (!rcc_enable_register || bit_no > 31) {
return -1000;
}
/* Enable the clock in any case, no matter what follows */
*rcc_enable_register |= (1U<<bit_no);
@@ -131,8 +132,9 @@ int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bi
int ret_val = -1;
struct rcc_enable_count *entry;
if (!rcc_enable_register || bit_no > 31)
if (!rcc_enable_register || bit_no > 31) {
return -1000;
}
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);
}
void random_number_gen_deinit(void)
void random_number_gen_deinit()
{
RNG->CR = 0;
__DSB();
@@ -66,5 +66,5 @@ enum random_number_error random_number_gen_get_number(uint32_t *random_number, b
*random_number = RNG->DR;
/* 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
*
* Copyright (C) 2021 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/>.
*/
*
* Copyright (C) 2021 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 <stm-periph/spi.h>
#include <helper-macros/helper-macros.h>
@@ -65,8 +65,7 @@ static struct stm_spi_dev *spi_handle_to_struct(stm_spi_handle handle)
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;
uint32_t reg_val;
@@ -132,14 +131,10 @@ void spi_deinit(stm_spi_handle handle)
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;
__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;
}

View File

@@ -1,227 +1,216 @@
/* Reflow Oven Controller
*
* Copyright (C) 2020 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 <stm-periph/uart.h>
#include <stm32/stm32f4xx.h>
#include <stm-periph/rcc-manager.h>
#include <stm-periph/stm32-gpio-macros.h>
#include <stm-periph/dma-ring-buffer.h>
#include <string.h>
int uart_init(struct stm_uart *uart)
{
int ret_val = 0;
uint32_t cr3 = 0;
uint32_t cr1 = 0;
if (!uart)
return -1000;
rcc_manager_enable_clock(uart->rcc_reg, uart->rcc_bit_no);
/* Reset all config regs */
uart->uart_dev->CR1 = uart->uart_dev->CR2 = uart->uart_dev->CR3 = 0UL;
/* Set baud rate */
uart->uart_dev->BRR = uart->brr_val;
/* If DMA buffers are present, configure for DMA use */
if (uart->dma_rx_buff && uart->rx) {
cr3 |= USART_CR3_DMAR;
ret_val = dma_ring_buffer_periph_to_mem_initialize(&uart->rx_ring_buff,
uart->base_dma_num,
uart->dma_rx_stream,
uart->rx_buff_count,
1U,
uart->dma_rx_buff,
(char *)&uart->uart_dev->DR,
uart->dma_rx_trigger_channel);
if (ret_val)
return ret_val;
}
if (uart->dma_tx_buff && uart->tx) {
ret_val = dma_ring_buffer_mem_to_periph_initialize(&uart->tx_ring_buff,
uart->base_dma_num,
uart->dma_tx_stream,
uart->tx_buff_count,
1U,
uart->dma_tx_buff,
uart->dma_tx_trigger_channel,
(void *)&uart->uart_dev->DR);
if (ret_val)
return ret_val;
cr3 |= USART_CR3_DMAT;
}
uart->uart_dev->CR3 = cr3;
if (uart->tx)
cr1 |= USART_CR1_TE;
if (uart->rx)
cr1 |= USART_CR1_RE;
/* Enable uart */
cr1 |= USART_CR1_UE;
uart->uart_dev->CR1 = cr1;
return 0;
}
void uart_change_brr(struct stm_uart *uart, uint32_t brr)
{
if (!uart || !uart->uart_dev)
return;
uart->brr_val = brr;
uart->uart_dev->BRR = brr;
}
uint32_t uart_get_brr(struct stm_uart *uart)
{
if (!uart || !uart->uart_dev)
return 0;
return uart->brr_val;
}
void uart_disable(struct stm_uart *uart)
{
if (!uart)
return;
uart->uart_dev->CR1 = 0;
uart->uart_dev->CR2 = 0;
uart->uart_dev->CR3 = 0;
if (uart->rx && uart->dma_rx_buff)
dma_ring_buffer_periph_to_mem_stop(&uart->rx_ring_buff);
if (uart->dma_tx_buff && uart->tx)
dma_ring_buffer_mem_to_periph_stop(&uart->tx_ring_buff);
rcc_manager_disable_clock(uart->rcc_reg, uart->rcc_bit_no);
}
void uart_send_char(struct stm_uart *uart, char c)
{
if (!uart || !uart->uart_dev)
return;
while (!(uart->uart_dev->SR & USART_SR_TXE))
;
uart->uart_dev->DR = c;
}
void uart_send_array(struct stm_uart *uart, const char *data, uint32_t len)
{
uint32_t 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;
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)
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;
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)
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)
return 0;
/* Wait for data to be available */
while (!(uart->uart_dev->SR & USART_SR_RXNE))
;
return (char)uart->uart_dev->DR;
}
int uart_check_rx_avail(struct stm_uart *uart)
{
if (!uart)
return 0;
if (uart->uart_dev->SR & USART_SR_RXNE)
return 1;
else
return 0;
}
void uart_tx_dma_complete_int_callback(struct stm_uart *uart)
{
if (!uart)
return;
dma_ring_buffer_mem_to_periph_int_callback(&uart->tx_ring_buff);
}
size_t uart_dma_tx_queue_avail(struct stm_uart *uart)
{
size_t fill_level = 0UL;
if (!uart)
return 0UL;
(void)dma_ring_buffer_mem_to_periph_fill_level(&uart->tx_ring_buff, &fill_level);
return fill_level;
}
size_t uart_dma_rx_queue_avail(struct stm_uart *uart)
{
size_t fill_level = 0UL;
if (!uart)
return 0UL;
(void)dma_ring_buffer_periph_to_mem_fill_level(&uart->rx_ring_buff, &fill_level);
return fill_level;
}
/* Reflow Oven Controller
*
* Copyright (C) 2020 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 <stm-periph/uart.h>
#include <stm32/stm32f4xx.h>
#include <stm-periph/rcc-manager.h>
#include <stm-periph/stm32-gpio-macros.h>
#include <stm-periph/dma-ring-buffer.h>
#include <string.h>
int uart_init(struct stm_uart *uart)
{
int ret_val = 0;
uint32_t cr3 = 0;
uint32_t cr1 = 0;
if (!uart)
return -1000;
rcc_manager_enable_clock(uart->rcc_reg, uart->rcc_bit_no);
/* Reset all config regs */
uart->uart_dev->CR1 = uart->uart_dev->CR2 = uart->uart_dev->CR3 = 0UL;
/* Set baud rate */
uart->uart_dev->BRR = uart->brr_val;
/* If DMA buffers are present, configure for DMA use */
if (uart->dma_rx_buff && uart->rx) {
cr3 |= USART_CR3_DMAR;
ret_val = dma_ring_buffer_periph_to_mem_initialize(&uart->rx_ring_buff,
uart->base_dma_num,
uart->dma_rx_stream,
uart->rx_buff_count,
1U,
uart->dma_rx_buff,
(char *)&uart->uart_dev->DR,
uart->dma_rx_trigger_channel);
if (ret_val)
return ret_val;
}
if (uart->dma_tx_buff && uart->tx) {
ret_val = dma_ring_buffer_mem_to_periph_initialize(&uart->tx_ring_buff,
uart->base_dma_num,
uart->dma_tx_stream,
uart->tx_buff_count,
1U,
uart->dma_tx_buff,
uart->dma_tx_trigger_channel,
(void *)&uart->uart_dev->DR);
if (ret_val)
return ret_val;
cr3 |= USART_CR3_DMAT;
}
uart->uart_dev->CR3 = cr3;
if (uart->tx)
cr1 |= USART_CR1_TE;
if (uart->rx)
cr1 |= USART_CR1_RE;
/* Enable uart */
cr1 |= USART_CR1_UE;
uart->uart_dev->CR1 = cr1;
return 0;
}
void uart_change_brr(struct stm_uart *uart, uint32_t brr)
{
if (!uart || !uart->uart_dev)
return;
uart->brr_val = brr;
uart->uart_dev->BRR = brr;
}
void uart_disable(struct stm_uart *uart)
{
if (!uart)
return;
uart->uart_dev->CR1 = 0;
uart->uart_dev->CR2 = 0;
uart->uart_dev->CR3 = 0;
if (uart->rx && uart->dma_rx_buff)
dma_ring_buffer_periph_to_mem_stop(&uart->rx_ring_buff);
if (uart->dma_tx_buff && uart->tx)
dma_ring_buffer_mem_to_periph_stop(&uart->tx_ring_buff);
rcc_manager_disable_clock(uart->rcc_reg, uart->rcc_bit_no);
}
void uart_send_char(struct stm_uart *uart, char c)
{
if (!uart || !uart->uart_dev)
return;
while(!(uart->uart_dev->SR & USART_SR_TXE));
uart->uart_dev->DR = c;
}
void uart_send_array(struct stm_uart *uart, const char *data, uint32_t len)
{
uint32_t 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;
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)
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;
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)
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)
return 0;
/* Wait for data to be available */
while (!(uart->uart_dev->SR & USART_SR_RXNE));
return (char)uart->uart_dev->DR;
}
int uart_check_rx_avail(struct stm_uart *uart)
{
if (!uart)
return 0;
if (uart->uart_dev->SR & USART_SR_RXNE)
return 1;
else
return 0;
}
void uart_tx_dma_complete_int_callback(struct stm_uart *uart)
{
if (!uart)
return;
dma_ring_buffer_mem_to_periph_int_callback(&uart->tx_ring_buff);
}
size_t uart_dma_tx_queue_avail(struct stm_uart *uart)
{
size_t fill_level = 0UL;
if (!uart)
return 0UL;
(void)dma_ring_buffer_mem_to_periph_fill_level(&uart->tx_ring_buff, &fill_level);
return fill_level;
}
size_t uart_dma_rx_queue_avail(struct stm_uart *uart)
{
size_t fill_level = 0UL;
if (!uart)
return 0UL;
(void)dma_ring_buffer_periph_to_mem_fill_level(&uart->rx_ring_buff, &fill_level);
return fill_level;
}

View File

@@ -19,13 +19,12 @@
*/
#include <stm-periph/unique-id.h>
#include <stm32/stm32f4xx.h>
#define LOW_WORD_ADDR (0x1FFF7A10UL)
#define MID_WORD_ADDR (LOW_WORD_ADDR+4U)
#define HIGH_WORD_ADDR (LOW_WORD_ADDR+8U)
void stm_unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low)
void unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low)
{
if (!high || !mid || !low)
return;
@@ -34,32 +33,3 @@ void stm_unique_id_get(uint32_t *high, uint32_t *mid, uint32_t *low)
*mid = *((uint32_t *)MID_WORD_ADDR);
*high = *((uint32_t *)HIGH_WORD_ADDR);
}
void stm_dev_rev_id_get(uint32_t *device_id, uint32_t *revision_id)
{
if (device_id)
*device_id = DBGMCU->IDCODE & DBGMCU_IDCODE_DEV_ID;
if (revision_id)
*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

@@ -33,7 +33,7 @@
#include <reflow-controller/safety/safety-controller.h>
static struct tpe_exec_state IN_SECTION(.ccm.data) current_state = {
static struct tpe_current_state IN_SECTION(.ccm.data) state = {
.status = TPE_OFF,
.start_timestamp = 0,
};
@@ -46,7 +46,7 @@ static SlList *command_list = NULL;
static void tpe_abort(void)
{
temp_profile_executer_stop();
current_state.status = TPE_ABORT;
state.status = TPE_ABORT;
}
enum pl_ret_val temp_profile_executer_start(const char *filename)
@@ -54,16 +54,16 @@ enum pl_ret_val temp_profile_executer_start(const char *filename)
uint32_t parsed_count = 0;
enum pl_ret_val res;
current_state.setpoint = 0.0f;
current_state.start_timestamp = 0ULL;
current_state.setpoint = 0.0f;
current_state.step = 0;
current_state.profile_steps = 0;
state.setpoint = 0.0f;
state.start_timestamp = 0ULL;
state.setpoint = 0.0f;
state.step = 0;
state.profile_steps = 0;
oven_pid_stop();
pid_should_run = false;
current_state.status = TPE_OFF;
current_state.profile_steps = 0;
state.status = TPE_OFF;
state.profile_steps = 0;
cmd_continue = false;
/* This should never happen... But who knows */
@@ -73,9 +73,9 @@ enum pl_ret_val temp_profile_executer_start(const char *filename)
res = temp_profile_parse_from_file(filename, &command_list, MAX_PROFILE_LENGTH, &parsed_count);
if (res == PL_RET_SUCCESS) {
current_state.profile_steps = parsed_count;
current_state.status = TPE_RUNNING;
current_state.start_timestamp = systick_get_global_tick();
state.profile_steps = parsed_count;
state.status = TPE_RUNNING;
state.start_timestamp = systick_get_global_tick();
} else {
if (command_list)
temp_profile_free_command_list(&command_list);
@@ -132,7 +132,7 @@ static bool cmd_set_temp(struct pl_command *cmd)
{
reactivate_pid_if_suspended();
oven_pid_set_target_temperature(cmd->params[0]);
current_state.setpoint = cmd->params[0];
state.setpoint = cmd->params[0];
return true;
}
@@ -146,21 +146,21 @@ static bool cmd_ramp(struct pl_command *cmd, bool cmd_continue)
if (!cmd_continue) {
/* Init of command */
start_temp = current_state.setpoint;
start_temp = state.setpoint;
slope = (cmd->params[0] - start_temp) / cmd->params[1];
reactivate_pid_if_suspended();
oven_pid_set_target_temperature(start_temp);
start_timestamp = systick_get_global_tick();
} else {
secs_passed = ((float)(systick_get_global_tick() - start_timestamp)) / 1000.0f;
if ((current_state.setpoint <= cmd->params[0] && start_temp < cmd->params[0]) ||
(current_state.setpoint >= cmd->params[0] && start_temp > cmd->params[0])) {
current_state.setpoint = start_temp + secs_passed * slope;
if ((state.setpoint <= cmd->params[0] && start_temp < cmd->params[0]) ||
(state.setpoint >= cmd->params[0] && start_temp > cmd->params[0])) {
state.setpoint = start_temp + secs_passed * slope;
} else {
current_state.setpoint = cmd->params[0];
state.setpoint = cmd->params[0];
ret = true;
}
oven_pid_set_target_temperature(current_state.setpoint);
oven_pid_set_target_temperature(state.setpoint);
}
return ret;
@@ -185,36 +185,6 @@ static void cmd_ack_flags(void)
}
static void cmd_digio_conf(uint8_t digio_num, uint8_t mode)
{
uint8_t pin_mode;
uint8_t alt_func = 0;
if (mode == 0 || mode == 1) {
pin_mode = mode;
} else if (mode >= 0x80 && mode <= 0x87) {
/* Alternate function */
pin_mode = 2;
alt_func = mode - 0x80;
} else {
return;
}
digio_setup_pin(digio_num, pin_mode, alt_func);
}
bool cmd_digio_wait(uint8_t digio_num, uint8_t digio_state)
{
bool advance = false;
int res;
res = digio_get(digio_num);
if (res < 0 || (uint8_t)res == digio_state)
advance = true;
return advance;
}
int temp_profile_executer_handle(void)
{
struct pl_command *current_cmd;
@@ -225,7 +195,7 @@ int temp_profile_executer_handle(void)
/* Return if no profile is currently executed */
if (current_state.status != TPE_RUNNING)
if (state.status != TPE_RUNNING)
return -1;
/* Abort profile execution if oven PID is aborted. This is most likely due to some error flags */
@@ -239,8 +209,8 @@ int temp_profile_executer_handle(void)
if (!systick_ticks_have_passed(last_tick, 100))
return 0;
current_cmd = (struct pl_command *)sl_list_nth(command_list, current_state.step)->data;
next_step = current_state.step;
current_cmd = (struct pl_command *)sl_list_nth(command_list, state.step)->data;
next_step = state.step;
switch (current_cmd->cmd) {
case PL_WAIT_FOR_TIME:
@@ -280,17 +250,6 @@ int temp_profile_executer_handle(void)
cmd_ack_flags();
advance = true;
break;
case PL_DIGIO_CONF:
advance = true;
cmd_digio_conf((uint8_t)current_cmd->params[0], (uint8_t)current_cmd->params[1]);
break;
case PL_DIGIO_SET:
digio_set((uint8_t)current_cmd->params[0], current_cmd->params[1] ? 1u : 0u);
advance = true;
break;
case PL_DIGIO_WAIT:
advance = cmd_digio_wait((uint8_t)current_cmd->params[0], current_cmd->params[1] ? 1u : 0u);
break;
default:
tpe_abort();
advance = true;
@@ -300,9 +259,9 @@ int temp_profile_executer_handle(void)
if (advance)
next_step++;
if (next_step != current_state.step) {
current_state.step = next_step;
if (next_step >= current_state.profile_steps) {
if (next_step != state.step) {
state.step = next_step;
if (next_step >= state.profile_steps) {
(void)temp_profile_executer_stop();
} else {
cmd_continue = false;
@@ -315,15 +274,15 @@ int temp_profile_executer_handle(void)
return 0;
}
const struct tpe_exec_state *temp_profile_executer_status(void)
const struct tpe_current_state *temp_profile_executer_status(void)
{
return &current_state;
return &state;
}
int temp_profile_executer_stop(void)
{
if (current_state.status == TPE_RUNNING) {
current_state.status = TPE_OFF;
if (state.status == TPE_RUNNING) {
state.status = TPE_OFF;
oven_pid_stop();
}
@@ -331,9 +290,7 @@ int temp_profile_executer_stop(void)
if (command_list)
temp_profile_free_command_list(&command_list);
/* Reset loudspeaker and reset default state of DIGIO channels */
loudspeaker_set(0);
digio_set_default_values();
return 0;
}

View File

@@ -48,9 +48,6 @@ static const struct pl_command_list_map cmd_list_map[_PL_NUM_CMDS] = {
{PL_LOUDSPEAKER_SET, "beep", 1u},
{PL_OFF, "temp_off", 0u},
{PL_CLEAR_FLAGS, "clear_flags", 0u},
{PL_DIGIO_CONF, "digio_conf", 2u},
{PL_DIGIO_SET, "digio_set", 2u},
{PL_DIGIO_WAIT, "digio_wait", 2u},
};
/**
@@ -111,13 +108,6 @@ static const struct pl_command_list_map *string_to_command(const char *str)
return ret;
}
/**
* @brief Parse a line in the temperature profile to a command.
* @param line Line to parse
* @param[out] cmd Command parsed
* @return negative in case of an error (Invalid command, invalid line);
* 1 in case the line is an empty line.
*/
static int parse_line(char *line, struct pl_command *cmd)
{
uint8_t token_idx = 0;
@@ -133,10 +123,7 @@ static int parse_line(char *line, struct pl_command *cmd)
token = strtok(line, delim);
if (!token) {
/* Empty line.
* Note: The comments in the lines are already filteed out before calling this function.
* Therefore, the empty line case covers lines containing just a comment
*/
/* Empty line or command line */
return 1;
}
@@ -144,10 +131,6 @@ static int parse_line(char *line, struct pl_command *cmd)
switch (token_idx) {
case 0:
map = string_to_command(token);
if (!map) {
/* No valid command found */
return -1;
}
c.cmd = map->command;
break;
default:
@@ -179,23 +162,12 @@ static int parse_line(char *line, struct pl_command *cmd)
return 0;
}
/**
* @brief Append a command to a singly linked list.
*
* The the list item is newly allocated and the command is copied. Therefore, \p cmd can be overwritten after
* a call to this function.
*
* @param list List to add the command to
* @param cmd Command to add to list
* @return The new head of the list. If an error occured */
static SlList *copy_and_append_command_to_list(SlList *list, const struct pl_command *cmd)
{
struct pl_command *alloced_cmd;
alloced_cmd = (struct pl_command *)malloc(sizeof(struct pl_command));
memcpy(alloced_cmd, cmd, sizeof(struct pl_command));
/* This will go catastrophically wrong, if the heap is full... just saying. */
list = sl_list_append(list, alloced_cmd);
return list;
@@ -263,10 +235,6 @@ exit:
return ret;
}
/**
* @brief Free an allocated pl_command structure
* @param cmd command struct. Tolerates NULL.
*/
static void delete_pl_command(void *cmd)
{
if (cmd)

View File

@@ -53,7 +53,6 @@ void button_init()
enum button_state button_read_event()
{
uint64_t time_delta;
uint64_t activation_stmp;
enum button_state temp_state;
if (override_state != BUTTON_IDLE) {
@@ -67,13 +66,7 @@ enum button_state button_read_event()
int_state = BUTTON_IDLE;
return temp_state;
} else {
/* Unfortunately I don't jave a better idea for now to ensure,
* that to_active_timestamp is read atomically
*/
__disable_irq();
activation_stmp = to_active_timestamp;
__enable_irq();
time_delta = systick_get_global_tick() - activation_stmp;
time_delta = systick_get_global_tick() - to_active_timestamp;
if (time_delta >= BUTTON_LONG_ON_TIME_MS)
return BUTTON_LONG;
else if (time_delta >= BUTTON_SHORT_ON_TIME_MS)

View File

@@ -189,7 +189,7 @@ static void gui_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry ent
if (last_page == 3)
break;
last_page = 3;
stm_unique_id_get(&ser1, &ser2, &ser3);
unique_id_get(&ser1, &ser2, &ser3);
menu_lcd_outputf(menu, 0, "Serial: %08X", ser1);
menu_lcd_outputf(menu, 1, " %08X", ser2);
@@ -414,7 +414,7 @@ static SlList *load_file_list_from_sdcard(int *error, const char *file_pattern)
static void gui_menu_temp_profile_execute(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void* parent)
{
static void *my_parent;
const struct tpe_exec_state *state;
const struct tpe_current_state *state;
static uint64_t last_tick;
float temperature;
float resistance;
@@ -663,26 +663,21 @@ static void gui_update_firmware(struct lcd_menu *menu, enum menu_entry_func_entr
}
}
if (list_length) {
if (entry_type == MENU_ENTRY_FIRST_ENTER ||
previously_selected_file != currently_selected_file) {
fname = sl_list_nth(file_list, currently_selected_file)->data;
menu_lcd_output(menu, 0, "Select File:");
if (fname)
menu_lcd_output(menu, 1, fname);
}
if (button == BUTTON_SHORT_RELEASED) {
fname = sl_list_nth(file_list, currently_selected_file)->data;
menu_display_clear(menu);
updater_update_from_file(fname);
/* This code is here for completeness. It will never be reached! */
sl_list_free_full(file_list, delete_file_list_entry);
}
} else {
menu_lcd_output(menu, 0, "No files!");
if (entry_type == MENU_ENTRY_FIRST_ENTER ||
previously_selected_file != currently_selected_file) {
fname = sl_list_nth(file_list, currently_selected_file)->data;
menu_lcd_output(menu, 0, "Select File:");
if (fname)
menu_lcd_output(menu, 1, fname);
}
if (button == BUTTON_LONG) {
if (button == BUTTON_SHORT_RELEASED) {
fname = sl_list_nth(file_list, currently_selected_file)->data;
menu_display_clear(menu);
file_list = NULL;
updater_update_from_file(fname);
/* This code is here for completeness. It will never be reached! */
sl_list_free_full(file_list, delete_file_list_entry);
} else if (button == BUTTON_LONG) {
sl_list_free_full(file_list, delete_file_list_entry);
file_list = NULL;
menu_entry_dropback(menu, my_parent);
@@ -691,37 +686,6 @@ 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_text = NULL;
@@ -771,7 +735,6 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
"Error Flags",
"About",
"Update",
"Connector Info",
NULL
};
static const menu_func_t root_entry_funcs[] = {
@@ -781,7 +744,6 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
gui_menu_err_flags,
gui_menu_about,
gui_update_firmware,
gui_connector_info,
};
enum button_state push_button;
int16_t rot_delta;
@@ -829,7 +791,7 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr
}
}
int gui_handle(void)
int gui_handle()
{
int32_t rot_delta;
enum button_state button;
@@ -851,18 +813,12 @@ int gui_handle(void)
return 1;
}
void gui_init(void)
void gui_init()
{
/** - Setup the rotary encoder input */
rotary_encoder_setup();
/** - Setup the push button */
button_init();
/** - Setup the LCD */
lcd_init();
/** - If an overlay has been previously set, clear it */
if (overlay_heading)
free(overlay_heading);
if (overlay_text)
@@ -871,7 +827,6 @@ void gui_init(void)
overlay_heading = NULL;
overlay_text = NULL;
/** - Init the GUI menu */
menu_init(reflow_menu_ptr, gui_menu_root_entry, update_display_buffer);
}
@@ -898,13 +853,3 @@ void gui_lcd_write_direct_blocking(uint8_t line, const char *text)
lcd_setcursor(0, line);
lcd_string(text);
}
size_t gui_get_line_count(void)
{
return (size_t)LCD_ROW_COUNT;
}
const char (*gui_get_current_display_content(void))[21]
{
return display_buffer;
}

View File

@@ -1,130 +0,0 @@
/* Reflow Oven Controller
*
* Copyright (C) 2021 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/ui/shell-uart.h>
#include <reflow-controller/periph-config/shell-uart-config.h>
#include <stm-periph/stm32-gpio-macros.h>
#include <stm-periph/uart.h>
#include <helper-macros/helper-macros.h>
/**
* @brief TX buffer for the shell's uart
*/
static char shell_uart_tx_buff[4096];
/**
* @brief RX buffer for the shell's uart
*/
static char shell_uart_rx_buff[128];
/**
* @brief The uart instance handling the shellmatta shell.
*/
struct stm_uart shell_uart;
void shell_uart_setup(void)
{
struct stm_uart *uart = &shell_uart;
uart->rx = 1;
uart->tx = 1;
uart->brr_val = SHELL_UART_DEFAULT_BRR_REG_VALUE;
uart->rcc_reg = &SHELL_UART_RCC_REG;
uart->rcc_bit_no = BITMASK_TO_BITNO(SHELL_UART_RCC_MASK);
uart->uart_dev = SHELL_UART_PERIPH;
uart->dma_rx_buff = shell_uart_rx_buff;
uart->dma_tx_buff = shell_uart_tx_buff;
uart->rx_buff_count = sizeof(shell_uart_rx_buff);
uart->tx_buff_count = sizeof(shell_uart_tx_buff);
uart->base_dma_num = 2;
uart->dma_rx_stream = SHELL_UART_RECEIVE_DMA_STREAM;
uart->dma_tx_stream = SHELL_UART_SEND_DMA_STREAM;
uart->dma_rx_trigger_channel = SHELL_UART_RX_DMA_TRIGGER;
uart->dma_tx_trigger_channel = SHELL_UART_TX_DMA_TRIGGER;
uart_init(uart);
NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}
shellmatta_retCode_t shell_uart_write_callback(const char *data, uint32_t len)
{
uart_send_array_with_dma(&shell_uart, data, len);
return SHELLMATTA_OK;
}
int shell_uart_receive_data_with_dma(const char **data, size_t *len)
{
return uart_receive_data_with_dma(&shell_uart, data, len);
}
int32_t shell_uart_reconfig_baud(uint32_t new_baud)
{
uint32_t brr_val_floor;
uint32_t brr_val_remainder;
uint32_t error_permille;
int64_t actual_baud;
/* Calculate the new BRR register value */
brr_val_floor = SHELL_UART_PERIPHERAL_CLOCK / new_baud;
brr_val_remainder = SHELL_UART_PERIPHERAL_CLOCK % new_baud;
/* Round to the nearest value */
if (brr_val_remainder > (new_baud / 2u)) {
brr_val_floor++;
brr_val_remainder = new_baud - brr_val_remainder;
}
actual_baud = (1000U *(int64_t)SHELL_UART_PERIPHERAL_CLOCK) / brr_val_floor;
error_permille = (ABS(actual_baud - 1000U * (int64_t)new_baud)) / (int64_t)new_baud;
if (error_permille < 20u) {
uart_change_brr(&shell_uart, brr_val_floor);
} else {
return -1;
}
return (int32_t)error_permille;
}
uint32_t shell_uart_get_current_baudrate(void)
{
uint32_t brr;
brr = uart_get_brr(&shell_uart);
if (brr == 0)
return 0;
return (SHELL_UART_PERIPHERAL_CLOCK) / brr;
}
/**
* @brief Handles the TX of UART1 (Shellmatta)
*/
void DMA2_Stream7_IRQHandler(void)
{
uint32_t hisr = DMA2->HISR & (0x3F << 22);
DMA2->HIFCR = hisr;
if (hisr & DMA_HISR_TCIF7)
uart_tx_dma_complete_int_callback(&shell_uart);
}

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ void flash_writer_perform_mass_erase(void)
flash_writer_enable_access();
while (flash_op_busy());
FLASH->CR = FLASH_CR_PSIZE_1;
FLASH->CR = DMA_SxCR_PSIZE_1;
FLASH->CR |= FLASH_CR_MER;
FLASH->CR |= FLASH_CR_STRT;

View File

@@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14b /
/ FatFs - Generic FAT Filesystem module R0.14 /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2021, ChaN, all right reserved.
/ Copyright (C) 2019, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@@ -20,7 +20,7 @@
#ifndef FF_DEFINED
#define FF_DEFINED 86631 /* Revision ID */
#define FF_DEFINED 86606 /* Revision ID */
#ifdef __cplusplus
extern "C" {
@@ -35,14 +35,10 @@ extern "C" {
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Windows VC++ (for development only) */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#include <float.h>
#define isnan(v) _isnan(v)
#define isinf(v) (!_finite(v))
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
@@ -52,7 +48,6 @@ typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
typedef WORD WCHAR; /* UTF-16 character type */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
@@ -63,29 +58,28 @@ typedef WORD WCHAR; /* UTF-16 character type */
#endif
/* Type of file size and LBA variables */
/* Definitions of volume management */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
#endif
typedef QWORD FSIZE_t;
#if FF_LBA64
typedef QWORD LBA_t;
#else
typedef DWORD LBA_t;
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#else
#if FF_LBA64
#error exFAT needs to be enabled when enable 64-bit LBA
#endif
typedef DWORD FSIZE_t;
typedef DWORD LBA_t;
#endif
/* Type of path name strings on FatFs API (TCHAR) */
/* Type of path name strings on FatFs API */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
@@ -107,22 +101,28 @@ typedef char TCHAR;
#define _TEXT(x) x
#endif
/* Definitions of volume management */
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
/* Type of file size and LBA variables */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#endif
typedef QWORD FSIZE_t;
#if FF_LBA64
typedef QWORD LBA_t;
#else
typedef DWORD LBA_t;
#endif
#else
#if FF_LBA64
#error exFAT needs to be enabled when enable 64-bit LBA
#endif
typedef DWORD FSIZE_t;
typedef DWORD LBA_t;
#endif
@@ -345,6 +345,10 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
#define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF
#define EOF (-1)
#endif

View File

@@ -2,7 +2,7 @@
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 86631 /* Revision ID */
#define FFCONF_DEF 86606 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@@ -25,7 +25,15 @@
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_FIND 1
#define FF_USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
@@ -56,30 +64,6 @@
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
#define FF_USE_STRFUNC 1
#define FF_PRINT_LLI 0
#define FF_PRINT_FLOAT 0
#define FF_STRF_ENCODE 0
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
/ 1: Enable without 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
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
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
@@ -153,6 +137,19 @@
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 0
/* This option configures support for relative path.
/
@@ -197,7 +194,7 @@
#define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk, but a larger value may be required for on-board flash memory and some
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
@@ -208,8 +205,8 @@
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
#define FF_MIN_GPT 0x10000000
/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and
#define FF_MIN_GPT 0x100000000
/* Minimum number of sectors to switch GPT format to create partition in f_mkfs and
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
@@ -231,7 +228,7 @@
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 1
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
@@ -240,7 +237,7 @@
#define FF_FS_NORTC 0
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2020
#define FF_NORTC_YEAR 2019
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp

View File

@@ -6,7 +6,7 @@
void uart_init(void)
{
SHELL_UART_RCC_REG |= SHELL_UART_RCC_MASK;
SHELL_UART_PERIPH->BRR = SHELL_UART_DEFAULT_BRR_REG_VALUE;
SHELL_UART_PERIPH->BRR = SHELL_UART_BRR_REG_VALUE;
SHELL_UART_PERIPH->CR2 = 0;
SHELL_UART_PERIPH->CR3 = 0;
SHELL_UART_PERIPH->CR1 = USART_CR1_TE | USART_CR1_UE;