diff --git a/stm-firmware/.gitignore b/stm-firmware/.gitignore index bcb7a46..3258d04 100644 --- a/stm-firmware/.gitignore +++ b/stm-firmware/.gitignore @@ -16,3 +16,10 @@ reflow-controller.includes *.files *.user.* *.user + +# VSCODE and CLANGD sepcific excludes + +.vscode/ +build/ +.cache/ +compile_commands.json diff --git a/stm-firmware/CMakeLists.txt b/stm-firmware/CMakeLists.txt index 6325d1d..164ee2f 100644 --- a/stm-firmware/CMakeLists.txt +++ b/stm-firmware/CMakeLists.txt @@ -1,7 +1,7 @@ set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_CROSSCOMPILING 1) -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.18) set(CMAKE_TOOLCHAIN_FILE "arm-none-eabi-gcc.cmake") @@ -43,26 +43,12 @@ else (GIT_FOUND) message("Version is set to: ${GIT_DESCRIBE}${ColorReset}") endif (GIT_FOUND) -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) +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) set(ELFFILE ${PROJECT_NAME}.elf) @@ -71,7 +57,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 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare) +add_compile_options(-mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare) set(GIT_DESCRIBE "${GIT_DESCRIBE}") @@ -124,15 +110,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 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage) +target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage) target_link_libraries(${ELFFILE} base64-lib linklist-lib) target_include_directories(${ELFFILE} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/updater/ram-code/include/") add_custom_command( TARGET ${ELFFILE} POST_BUILD - COMMAND ./python "${CMAKE_CURRENT_SOURCE_DIR}/crc-patcher/crc-patch-elf.py" "${CMAKE_CURRENT_BINARY_DIR}/${ELFFILE}" - WORKING_DIRECTORY ${VENV_BIN} + 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} COMMENT "Running Flash CRC Patcher" ) diff --git a/stm-firmware/config-parser/config-parser.c b/stm-firmware/config-parser/config-parser.c index 3522ddd..2ec48e4 100644 --- a/stm-firmware/config-parser/config-parser.c +++ b/stm-firmware/config-parser/config-parser.c @@ -28,7 +28,14 @@ #include #include +/** + * @brief Config parser magic value used to check sanity of passed structs + */ #define CONFIG_PARSER_MAGIC 0x464a6e2bUL + +/** + * @brief Config parser type casting macro + */ #define CONFIG_PARSER(p) ((struct config_parser *)(p)) /** diff --git a/stm-firmware/crc-patcher/crc-patch-elf.py b/stm-firmware/crc-patcher/crc-patch-elf.py deleted file mode 100755 index 64e3439..0000000 --- a/stm-firmware/crc-patcher/crc-patch-elf.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/bin/python - -""" -This script patches the CRC checksums into an existing ELF file. - -For this, it searches the follwoing sections: - 1) .text - 2) .data - 3) .ccmdata - 4) .vectors - -All sections MUST be a multiple of 4 bytes long because the CRC calculation relies on whole 32 bit words. -The sections are excrated and the CRC is calculated for each section. - -In the section .flashcrc, the script expects a single struct with the prototype: -struct flash_crcs { - uint32_t start_magic; - uint32_t crc_section_text; - uint32_t crc_section_data; - uint32_t crc_section_ccm_data; - uint32_t crc_section_vectors; - uint32_t end_magic; -}; - -It checks, if the start magic and end magic are set to the appropriate values and then patches in the CRC values of the sections. -The magic values checked for are: 0xA8BE53F9 and 0xFFA582FF -""" -from elftools.elf.elffile import ELFFile -from elftools.elf.segments import Segment -import elftools.elf.constants as elf_const -import sys -import crcmod -import crcmod.predefined -import struct - -crc_calc = crcmod.predefined.mkCrcFun('crc-32-mpeg') - -if len(sys.argv) < 2: - print("Usage:", sys.argv[0], ' ') - sys.exit(-1) - -filename=sys.argv[1] - -def section_calculate_crc(section): - data = bytearray(section.data()) - be_data = bytearray([0 for k in range(0, len(data))]) - # Rearrange data, because the STM controller sees it as 32 bit little endian words - for i in range(0, int(len(data)/4)): - be_data[i*4+0] = data[i*4+3] - be_data[i*4+1] = data[i*4+2] - be_data[i*4+2] = data[i*4+1] - be_data[i*4+3] = data[i*4+0] - - return crc_calc(be_data) - -with open(filename, 'r+b') as f: - elf = ELFFile(f) - sections = {} - sections['.text'] = elf.get_section_by_name('.text') - sections['.data'] = elf.get_section_by_name('.data') - sections['.ccmdata'] = elf.get_section_by_name('.ccmdata') - sections['.vectors'] = elf.get_section_by_name('.vectors') - - for key, sec in sections.items(): - if sec is None: - print("Error! Section", key, "not found in ELF file!") - sys.exit(-1) - print('Found section', key, 'Size:', - sec.data_size, 'Type:', sec['sh_type']) - if sec['sh_type'] != 'SHT_PROGBITS': - print('Error! Section must be of type SHT_PROGBITS') - sys.exit(-1) - if (sec.data_size % 4 != 0): - print("Section", key, "has wrong size. Must be a multiple of 4 bytes!") - sys.exit(-1) - - text_crc = section_calculate_crc(sections['.text']) - print('CRC of .text section:', hex(text_crc)) - data_crc = section_calculate_crc(sections['.data']) - print('CRC of .data section:', hex(data_crc)) - ccmdata_crc = section_calculate_crc(sections['.ccmdata']) - print('CRC of .ccmdata section:', hex(ccmdata_crc)) - vextors_crc = section_calculate_crc(sections['.vectors']) - print('CRC of .vectors section:', hex(vextors_crc)) - - # Check the flashcrc section - flashcrc_sec = elf.get_section_by_name('.flashcrc') - if flashcrc_sec is None: - print('Section for flash CRC missing!') - sys.exit(-1) - if flashcrc_sec.data_size != 6*4: - print("Error: .flashcrc section has wrong size:",flashcrc_sec.data_size) - sys.exit(-1); - - crc_sec_data = bytearray(flashcrc_sec.data()) - magic1 = struct.unpack(' +* Copyright (C) 2022 Mario Hüttel * * 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!") diff --git a/stm-firmware/hw-version-detect.c b/stm-firmware/hw-version-detect.c index 64df7f4..7dee01e 100644 --- a/stm-firmware/hw-version-detect.c +++ b/stm-firmware/hw-version-detect.c @@ -27,10 +27,15 @@ #include #include +#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; + uint16_t port_bitmask = 0U; /* Use uint16_t because a port can have 16 IOs max. */ + const uint16_t highest_bit_mask = (1 << (HW_REV_DETECT_PIN_HIGH - HW_REV_DETECT_PIN_LOW)); static enum hw_revision revision = HW_REV_NOT_DETECTED; /* If the revision has been previously detected, @@ -53,7 +58,7 @@ enum hw_revision get_pcb_hardware_version(void) */ for (current_pin = HW_REV_DETECT_PIN_LOW; current_pin <= HW_REV_DETECT_PIN_HIGH; current_pin++) { port_bitmask >>= 1; - port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : 0x80; + port_bitmask |= (HW_REV_DETECT_GPIO->IDR & (1 << current_pin)) ? 0x0 : highest_bit_mask; } /* Resolve the read in bitmask to a hardware version */ diff --git a/stm-firmware/include/reflow-controller/hw-version-detect.h b/stm-firmware/include/reflow-controller/hw-version-detect.h index ef9721a..ff41ea4 100644 --- a/stm-firmware/include/reflow-controller/hw-version-detect.h +++ b/stm-firmware/include/reflow-controller/hw-version-detect.h @@ -48,7 +48,6 @@ */ #define HW_REV_DETECT_PIN_HIGH (15U) - /** * @brief PCB/Hardware Revision Type */ diff --git a/stm-firmware/include/reflow-controller/safety/flash-crc-struct.h b/stm-firmware/include/reflow-controller/safety/flash-crc-struct.h new file mode 100644 index 0000000..7166eaf --- /dev/null +++ b/stm-firmware/include/reflow-controller/safety/flash-crc-struct.h @@ -0,0 +1,37 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 Mario Hüttel +* +* 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 . +*/ + +#ifndef _SAFETY_FLASH_CRC_STRUCT_H_ +#define _SAFETY_FLASH_CRC_STRUCT_H_ + +#include + +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_ */ diff --git a/stm-firmware/include/reflow-controller/safety/flash-crc.h b/stm-firmware/include/reflow-controller/safety/flash-crc.h new file mode 100644 index 0000000..174dc81 --- /dev/null +++ b/stm-firmware/include/reflow-controller/safety/flash-crc.h @@ -0,0 +1,56 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 Mario Hüttel +* +* 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 . +*/ + +#ifndef _SAFETY_FLASH_CRC_H_ +#define _SAFETY_FLASH_CRC_H_ + +#include + +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_ */ diff --git a/stm-firmware/include/reflow-controller/safety/safety-config.h b/stm-firmware/include/reflow-controller/safety/safety-config.h index 009ef27..4f451d7 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-config.h +++ b/stm-firmware/include/reflow-controller/safety/safety-config.h @@ -27,6 +27,15 @@ #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. * @@ -159,7 +168,7 @@ enum analog_value_monitor { #define SAFETY_CRC_MON_SAFETY_ADC_PW 0xA8DF2368 /** - * @brief Default persistence of safety flags. These values are loaded into the safety tables on startup + * @brief Default persistence of safety flags. These values are loaded into the safety tables on startup. */ #define SAFETY_CONFIG_DEFAULT_PERSIST ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, false), \ @@ -183,9 +192,9 @@ enum analog_value_monitor { ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_CODE, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, true), \ - ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true), \ + ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true) /** - * @brief Default config weights of safety flags. These values are loaded into the safety tables on startup + * @brief Default config weights of safety flags. These values are loaded into the safety tables on startup. */ #define SAFETY_CONFIG_DEFAULT_WEIGHTS ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ @@ -206,9 +215,9 @@ enum analog_value_monitor { ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ - ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_PANIC) #endif /* __SAFETY_CONFIG_H__ */ diff --git a/stm-firmware/include/reflow-controller/safety/safety-controller.h b/stm-firmware/include/reflow-controller/safety/safety-controller.h index 4390d73..98ed431 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-controller.h +++ b/stm-firmware/include/reflow-controller/safety/safety-controller.h @@ -75,9 +75,9 @@ void safety_controller_init(void); /** * @brief Handle the safety controller. * @note This function must be executed periodically in order to prevent the watchdog from resetting the firmware - * @return 0 if successful + * @returns Worst flag weigth that is currently set. */ -int safety_controller_handle(void); +enum config_weight safety_controller_handle(void); /** * @brief Report one or multiple errors to the safety controller @@ -267,13 +267,6 @@ 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 diff --git a/stm-firmware/include/reflow-controller/safety/safety-memory.h b/stm-firmware/include/reflow-controller/safety/safety-memory.h index 0d03b0f..18e6094 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-memory.h +++ b/stm-firmware/include/reflow-controller/safety/safety-memory.h @@ -24,6 +24,7 @@ #include #include #include +#include /** @addtogroup safety-memory * @{ @@ -131,15 +132,6 @@ 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 */ diff --git a/stm-firmware/include/reflow-controller/sd.h b/stm-firmware/include/reflow-controller/sd.h new file mode 100644 index 0000000..5233a71 --- /dev/null +++ b/stm-firmware/include/reflow-controller/sd.h @@ -0,0 +1,42 @@ +/* Reflow Oven Controller + * + * Copyright (C) 2022 Mario Hüttel + * + * 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 . + */ + + #ifndef _SD_H_ + #define _SD_H_ + +#include +#include + +/** + * @brief Mount the SD card if available and not already mounted + * @param fs Filesystem to mount to. + * @return true if mounted, false if an error occured or the SD is not inserted and cannot be mounted + */ +bool mount_sd_card_if_avail(FATFS *fs); + +/** + * @brief Return whether an SD card is inserted and mounted + * + * @return true SD inserted and mounted + * @return false No SD inserted or not mounted + */ +bool sd_card_is_mounted(void); + +#endif /* _SD_H_ */ \ No newline at end of file diff --git a/stm-firmware/main.c b/stm-firmware/main.c index dcf8145..5573003 100644 --- a/stm-firmware/main.c +++ b/stm-firmware/main.c @@ -32,13 +32,13 @@ #include #include #include -#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h" #include #include #include #include #include #include +#include #include #include #include @@ -88,40 +88,6 @@ 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 bool mount_sd_card_if_avail(bool mounted) -{ - FRESULT res; - static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0; - - if (sdio_check_inserted() && mounted) { - memset(fs_ptr, 0, sizeof(FATFS)); - sdio_stop_clk(); - inserted_counter = 0; - return false; - } - - if (!sdio_check_inserted() && inserted_counter < 255) - inserted_counter++; - - if (!sdio_check_inserted() && !mounted && inserted_counter > 4) { - inserted_counter = 0; - res = f_mount(fs_ptr, "0:/", 1); - if (res == FR_OK) { - led_set(1, 1); - return true; - } else { - return false; - } - } - - return mounted; -} - /** * @brief Process the boot status structure in the safety (backup) RAM * Depending on the flags set there, this function will: @@ -286,6 +252,7 @@ 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_system(); @@ -312,9 +279,9 @@ int main(void) * it is tried to load it from SD card. */ if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) { - led_set(1, 0); + led_set(1u, 0); sd_old = sd_card_mounted; - sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted); + sd_card_mounted = mount_sd_card_if_avail(fs_ptr); if (sd_card_mounted && !sd_old) { adc_pt1000_get_resistance_calibration(NULL, NULL, &cal_active); @@ -325,6 +292,14 @@ int main(void) } } + /* Check if any flags are present, that disable the PID controller. Blink + * LED 0 in this case + */ + if (worst_safety_flag >= SAFETY_FLAG_CONFIG_WEIGHT_PID) + led_set(0u, led_get(0u) ? 0 : 1); + else + led_set(0u, 0); + quarter_sec_timestamp = systick_get_global_tick(); } @@ -338,7 +313,7 @@ int main(void) temp_profile_executer_handle(); /** - Handle the safety controller. This must be called! Otherwise a watchdog reset will occur */ - safety_controller_handle(); + worst_safety_flag = safety_controller_handle(); /** - If the Oven PID controller is running, we handle its sample function */ if (oven_pid_get_status() == OVEN_PID_RUNNING) diff --git a/stm-firmware/safety/flash-crc-struct.c b/stm-firmware/safety/flash-crc-struct.c new file mode 100644 index 0000000..ebe7989 --- /dev/null +++ b/stm-firmware/safety/flash-crc-struct.c @@ -0,0 +1,31 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 Mario Hüttel +* +* 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 . +*/ + +#include +#include + +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, +}; diff --git a/stm-firmware/safety/flash-crc.c b/stm-firmware/safety/flash-crc.c new file mode 100644 index 0000000..0840802 --- /dev/null +++ b/stm-firmware/safety/flash-crc.c @@ -0,0 +1,152 @@ +/* Reflow Oven Controller +* +* Copyright (C) 2022 Mario Hüttel +* +* 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 . +*/ + +#include +#include +#include +#include + +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; +} diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index e7dab1b..72f8df5 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -43,6 +43,7 @@ #include #include #include +#include #include /** @@ -154,15 +155,6 @@ 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; @@ -364,6 +356,10 @@ static void set_overtemp_config(float over_temperature) 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) @@ -910,7 +906,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(); - safety_controller_trigger_flash_crc_check(); + flash_crc_trigger_check(); stack_check_init_corruption_detect_area(); hw_rev = get_pcb_hardware_version(); @@ -1113,12 +1109,15 @@ 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 void safety_controller_handle_weighted_flags(void) +static enum config_weight safety_controller_handle_weighted_flags(void) { 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]; @@ -1128,6 +1127,11 @@ static void safety_controller_handle_weighted_flags(void) 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; @@ -1143,6 +1147,8 @@ static void safety_controller_handle_weighted_flags(void) } } + + return worst; } #ifndef DEBUGBUILD @@ -1152,9 +1158,9 @@ static void external_watchdog_toggle(void) } #endif -int safety_controller_handle(void) +enum config_weight safety_controller_handle(void) { - int ret = 0; + enum config_weight worst_weight_set; #ifndef DEBUGBUILD static uint32_t watchdog_counter = 0UL; #endif @@ -1164,9 +1170,10 @@ int safety_controller_handle(void) safety_controller_handle_memory_checks(); safety_controller_do_systick_checking(); safety_controller_process_monitor_checks(); - safety_controller_handle_weighted_flags(); + worst_weight_set = safety_controller_handle_weighted_flags(); - ret |= watchdog_ack(WATCHDOG_MAGIC_KEY); + /* Ignore error here. Will trigger restart anyway */ + (void)watchdog_ack(WATCHDOG_MAGIC_KEY); #ifndef DEBUGBUILD if (get_pcb_hardware_version() != HW_REV_V1_2) { @@ -1177,7 +1184,8 @@ int safety_controller_handle(void) } } #endif - return (ret ? -1 : 0); + + return worst_weight_set; } int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable) @@ -1438,94 +1446,6 @@ 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(void) -{ - /* 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; diff --git a/stm-firmware/sd.c b/stm-firmware/sd.c new file mode 100644 index 0000000..eee16e2 --- /dev/null +++ b/stm-firmware/sd.c @@ -0,0 +1,65 @@ +/* Reflow Oven Controller + * + * Copyright (C) 2022 Mario Hüttel + * + * 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 . + */ + +#include +#include "fatfs/ff.h" +#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h" +#include +#include +#include +#include + +static bool sd_card_mounted_state = false; + +bool mount_sd_card_if_avail(FATFS *fs) +{ + FRESULT res; + static uint8_t IN_SECTION(.ccm.bss) inserted_counter = 0; + + if (sdio_check_inserted() && sd_card_mounted_state) { + memset(fs, 0, sizeof(FATFS)); + sdio_stop_clk(); + inserted_counter = 0; + sd_card_mounted_state = false; + goto ret; + } + + if (!sdio_check_inserted() && inserted_counter < 255) + inserted_counter++; + + if (!sdio_check_inserted() && !sd_card_mounted_state && inserted_counter > 4) { + inserted_counter = 0; + res = f_mount(fs, "0:/", 1); + if (res == FR_OK) { + led_set(1, 1); + sd_card_mounted_state = true; + } else { + sd_card_mounted_state = false; + } + } + +ret: + return sd_card_mounted_state; +} + +bool sd_card_is_mounted(void) +{ + return sd_card_mounted_state; +} \ No newline at end of file diff --git a/stm-firmware/ui/gui.c b/stm-firmware/ui/gui.c index 608e46a..9594941 100644 --- a/stm-firmware/ui/gui.c +++ b/stm-firmware/ui/gui.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -789,7 +790,6 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr if (entry_type != MENU_ENTRY_CONTINUE) { menu_changed = true; menu_display_clear(menu); - update_display_buffer(0, "Main Menu"); menu_ack_rotary_delta(menu); if (entry_type == MENU_ENTRY_FIRST_ENTER) { list.entry_names = root_entry_names; @@ -800,6 +800,8 @@ static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entr } } + update_display_buffer(0, sd_card_is_mounted() ? "Main Menu [SD]" : "Main Menu [--]"); + push_button = menu_get_button_state(menu); rot_delta = menu_get_rotary_delta(menu); diff --git a/stm-firmware/ui/shell.c b/stm-firmware/ui/shell.c index 6634e8b..06f9722 100644 --- a/stm-firmware/ui/shell.c +++ b/stm-firmware/ui/shell.c @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -1020,6 +1021,53 @@ shellmatta_retCode_t shell_cmd_set_baud(const shellmatta_handle_t handle, const 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 */ @@ -1029,7 +1077,7 @@ shellmatta_retCode_t shell_cmd_set_baud(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[25] = { +static shellmatta_cmd_t cmd[26] = { { .cmd = "version", .cmdAlias = "ver", @@ -1229,6 +1277,14 @@ static shellmatta_cmd_t cmd[25] = { .helpText = "Set a new temporary baudrate for the UART", .usageText = "baudrate ", .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, },