├── src ├── st │ ├── stm32l4xx.h │ ├── stm32_assert.h │ ├── ll │ │ ├── stm32l4xx_ll_pwr.c │ │ ├── stm32l4xx_ll_gpio.c │ │ ├── stm32l4xx_ll_spi.c │ │ └── stm32l4xx_ll_utils.h │ ├── system_stm32l4xx.h │ └── system_stm32l4xx.c ├── modules │ ├── shell_cmd.h │ ├── nand_ftl_diskio.h │ ├── mem.c │ ├── led.c │ ├── led.h │ ├── mem.h │ ├── uart.h │ ├── sys_time.h │ ├── shell.h │ ├── spi.h │ ├── sys_time.c │ ├── fifo.h │ ├── spi_nand.h │ ├── nand_ftl_diskio.c │ ├── uart.c │ ├── shell.c │ └── spi.c ├── stm32l432kc_it.c ├── dhara │ ├── error.h │ ├── bytes.h │ ├── error.c │ ├── nand.h │ ├── nand.c │ ├── map.h │ ├── journal.h │ └── map.c ├── cmsis │ ├── cmsis_version.h │ ├── cmsis_compiler.h │ └── mpu_armv7.h ├── syscalls.c ├── fatfs │ ├── diskio.h │ ├── diskio.c │ ├── ffsystem.c │ └── ffconf.h ├── stm32l432kc.ld ├── main.c └── startup_stm32l432kc.c ├── .clang-format ├── .gitignore ├── LICENSE ├── Makefile └── README.md /src/st/stm32l4xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aloebs29/flash_management/HEAD/src/st/stm32l4xx.h -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | UseTab: Never 2 | IndentWidth: 4 3 | BreakBeforeBraces: Stroustrup 4 | AllowShortIfStatementsOnASingleLine: true 5 | AllowShortFunctionsOnASingleLine: false 6 | AlignConsecutiveMacros: true 7 | IndentCaseLabels: true 8 | ColumnLimit: 100 -------------------------------------------------------------------------------- /src/modules/shell_cmd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shell_cmd.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the shell command module 5 | * 6 | * Provides command processing for the shell. 7 | * 8 | */ 9 | 10 | #ifndef __SHELL_CMD_H 11 | #define __SHELL_CMD_H 12 | 13 | #include 14 | 15 | /// @brief Parses the command buffer into argv/argc and calls the relevant handler function 16 | void shell_cmd_process(char *buff, size_t len); 17 | 18 | #endif // __SHELL_CMD_H 19 | -------------------------------------------------------------------------------- /src/modules/nand_ftl_diskio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nand_ftl_diskio.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the nand ftl diskio module 5 | * 6 | * Glue layer between fatfs diskio and dhara ftl. 7 | * 8 | */ 9 | 10 | #ifndef __NAND_FTL_DISKIO_H 11 | #define __NAND_FTL_DISKIO_H 12 | 13 | #include "../fatfs/diskio.h" // types from the diskio driver 14 | #include "../fatfs/ff.h" // BYTE type 15 | 16 | DSTATUS nand_ftl_diskio_initialize(void); 17 | DSTATUS nand_ftl_diskio_status(void); 18 | DRESULT nand_ftl_diskio_read(BYTE *buff, LBA_t sector, UINT count); 19 | DRESULT nand_ftl_diskio_write(const BYTE *buff, LBA_t sector, UINT count); 20 | DRESULT nand_ftl_diskio_ioctl(BYTE cmd, void *buff); 21 | 22 | #endif // __NAND_FTL_DISKIO_H 23 | -------------------------------------------------------------------------------- /src/modules/mem.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mem.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the memory management module 5 | * 6 | */ 7 | 8 | #include "mem.h" 9 | 10 | #include 11 | 12 | #include "spi_nand.h" 13 | 14 | // private variables 15 | static uint8_t mem_buffer[SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE]; 16 | static bool allocated = false; 17 | 18 | // public function definitions 19 | uint8_t *mem_alloc(size_t size) 20 | { 21 | if (!allocated && size <= sizeof(mem_buffer)) { 22 | allocated = true; 23 | return mem_buffer; 24 | } 25 | else { 26 | return NULL; 27 | } 28 | } 29 | 30 | void mem_free(uint8_t *ptr) 31 | { 32 | if (ptr == mem_buffer) { 33 | allocated = false; 34 | } 35 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | .vscode/ 55 | build/ 56 | datasheets/ 57 | examples/ 58 | .clangd/ 59 | compile_commands.json 60 | -------------------------------------------------------------------------------- /src/modules/led.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file led.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the LED module 5 | * 6 | */ 7 | 8 | #include "led.h" 9 | 10 | #include "../st/ll/stm32l4xx_ll_bus.h" 11 | 12 | // public function definitions 13 | void led_init(void) 14 | { 15 | // enable peripheral clock 16 | if (!LL_AHB2_GRP1_IsEnabledClock(LL_AHB2_GRP1_PERIPH_GPIOB)) 17 | LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); 18 | 19 | // setup pin as output -- default to low (LED off) 20 | led_set_output(false); 21 | LL_GPIO_SetPinMode(LD3_PORT, LD3_PIN, LL_GPIO_MODE_OUTPUT); 22 | LL_GPIO_SetPinOutputType(LD3_PORT, LD3_PIN, LL_GPIO_OUTPUT_PUSHPULL); 23 | LL_GPIO_SetPinSpeed(LD3_PORT, LD3_PIN, LL_GPIO_SPEED_FREQ_LOW); 24 | LL_GPIO_SetPinPull(LD3_PORT, LD3_PIN, LL_GPIO_PULL_NO); 25 | } 26 | -------------------------------------------------------------------------------- /src/modules/led.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file led.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the LED module 5 | * 6 | * Handles interaction with the "LD3" LED on the NUCLEO-L432KC board. 7 | * 8 | */ 9 | 10 | #ifndef __LED_H 11 | #define __LED_H 12 | 13 | #include 14 | 15 | #include "../st/ll/stm32l4xx_ll_gpio.h" 16 | 17 | #define LD3_PORT GPIOB 18 | #define LD3_PIN LL_GPIO_PIN_3 19 | 20 | /// @brief Enables GPIOB clock and sets up LED pin 21 | void led_init(void); 22 | 23 | /// @brief Sets the LED output 24 | /// @note This function is inlined as it will be called from exception handlers 25 | static inline void led_set_output(bool pin_state) 26 | { 27 | if (pin_state) { 28 | LL_GPIO_SetOutputPin(LD3_PORT, LD3_PIN); 29 | } 30 | else { 31 | LL_GPIO_ResetOutputPin(LD3_PORT, LD3_PIN); 32 | } 33 | } 34 | 35 | #endif // __LED_H 36 | -------------------------------------------------------------------------------- /src/stm32l432kc_it.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stm32l432_it.c 3 | * @author Andrew Loebs 4 | * @brief Interrupt handler definitions 5 | * 6 | * Based on ST's LL template project. All handlers defined here will override 7 | * their weak aliases in the startup file. 8 | * 9 | */ 10 | 11 | #include "modules/led.h" 12 | #include "modules/sys_time.h" 13 | #include "modules/uart.h" 14 | 15 | void NMI_Handler(void) 16 | { 17 | // TODO: write production-worthy exception handlers 18 | led_set_output(true); 19 | while (1) 20 | ; 21 | } 22 | 23 | void HardFault_Handler(void) 24 | { 25 | led_set_output(true); 26 | while (1) 27 | ; 28 | } 29 | 30 | void MemManage_Handler(void) 31 | { 32 | led_set_output(true); 33 | while (1) 34 | ; 35 | } 36 | 37 | void BusFault_Handler(void) 38 | { 39 | led_set_output(true); 40 | while (1) 41 | ; 42 | } 43 | 44 | void UsageFault_Handler(void) 45 | { 46 | led_set_output(true); 47 | while (1) 48 | ; 49 | } 50 | 51 | void SysTick_Handler(void) { _sys_time_increment(); } 52 | 53 | void USART2_IRQHandler(void) { _uart_isr(); } 54 | -------------------------------------------------------------------------------- /src/modules/mem.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mem.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the memory management module 5 | * 6 | * A simple module to manage allocation of a single nand page buffer. 7 | * 8 | * This was made in response to many modules (shell_command, spi_nand), 9 | * needing temporary access to a page-sized array, and not wanting to 10 | * create that array on the stack or allocate it statically for the lifetime 11 | * of the application. This is not the page buffer used by the flash translation 12 | * layer. 13 | * 14 | * 15 | */ 16 | 17 | #ifndef __MEM_H 18 | #define __MEM_H 19 | 20 | #include 21 | #include 22 | 23 | /// @brief Attempts to allocate a nand page buffer. 24 | /// @return Pointer to the buffer if available, NULL if not available 25 | /// @note Return value should always be checked against null. 26 | /// @note Max size: SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE 27 | uint8_t *mem_alloc(size_t size); 28 | 29 | /// @brief Frees the allocated nand page buffer 30 | /// @param ptr pointer to the nand page buffer 31 | void mem_free(uint8_t *ptr); 32 | 33 | #endif // __MEM_H 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Andrew Loebs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/modules/uart.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file uart.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the UART module 5 | * 6 | * Handles interaction with the UART module. Functions should not be called directly -- 7 | * this module provides functionality for c std lib functions (putc, getc, printf, etc.). 8 | * 9 | * This is not intended to be a high-speed UART driver, it does have blocking functions. 10 | * 11 | */ 12 | 13 | #ifndef __UART_H 14 | #define __UART_H 15 | 16 | #include 17 | 18 | /// @brief Enables GPIOA and USART clocks, sets up pins and USART2 module. 19 | /// @note Called in main() -- cannot be called by __libc_init_array() since 20 | /// system clock is not configured 21 | void uart_init(void); 22 | 23 | /// @brief Writes a character to the UART 24 | /// @note Called by _write sys call 25 | void _uart_putc(char c); 26 | 27 | /// @brief Returns true and writes character to c if present, false if not 28 | /// @note Called by _read sys call 29 | bool _uart_try_getc(char *c); 30 | 31 | /// @brief Handles uart interrupt 32 | /// @note Called by USART2_IRQHandler 33 | void _uart_isr(void); 34 | 35 | #endif // __UART_H 36 | -------------------------------------------------------------------------------- /src/modules/sys_time.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sys_time.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the sys time module 5 | * 6 | * Exposes a millisecond time to the system (driven by systick) and provides 7 | * functions for comparing times (with wrap-around) and blocking delays. 8 | * 9 | */ 10 | 11 | #ifndef __SYS_TIME_H 12 | #define __SYS_TIME_H 13 | 14 | #include 15 | #include 16 | 17 | /// @brief Resets the system time and enables sys tick interrupt 18 | void sys_time_init(void); 19 | 20 | /// @brief Increments the system time counter -- should only be called by interrupt! 21 | void _sys_time_increment(void); 22 | 23 | /// @brief Returns system time counter (which tracks milliseconds) 24 | uint32_t sys_time_get_ms(void); 25 | 26 | /// @brief Returns the number of milliseconds elapsed since the start value 27 | uint32_t sys_time_get_elapsed(uint32_t start); 28 | 29 | /// @brief Checks whether a given time duration has elapsed since a given start time 30 | bool sys_time_is_elapsed(uint32_t start, uint32_t duration_ms); 31 | 32 | /// @brief Blocking delay for a given duration 33 | void sys_time_delay(uint32_t duration_ms); 34 | 35 | #endif // __SYS_TIME_H 36 | -------------------------------------------------------------------------------- /src/modules/shell.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shell.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the shell module 5 | * 6 | * Provides functionality for a virtual shell & CLI. 7 | * 8 | */ 9 | 10 | #ifndef __SHELL_H 11 | #define __SHELL_H 12 | 13 | #include // size_t 14 | 15 | /// @brief Initializes the shell 16 | void shell_init(void); 17 | 18 | /// @brief Gives processing time to the shell 19 | void shell_tick(void); 20 | 21 | /// @brief Writes characters to the shell 22 | void shell_print(const char *buff, size_t len); 23 | 24 | /// @brief Writes a string to the shell 25 | void shell_prints(const char *string); 26 | 27 | /// @brief Writes a string + newline to the shell 28 | void shell_prints_line(const char *string); 29 | 30 | /// @brief Writes formatted output to the shell 31 | void shell_printf(const char *format, ...); 32 | 33 | /// @brief Writes formatted output + newline to the shell 34 | void shell_printf_line(const char *format, ...); 35 | 36 | /// @brief Writes a newline character to the shell 37 | /// @note This keeps our newline in a single function in case we decide to use a different line 38 | /// ending in the future 39 | void shell_put_newline(void); 40 | 41 | #endif // __SHELL_H 42 | -------------------------------------------------------------------------------- /src/modules/spi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file spi.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the spi module 5 | * 6 | * SPI1 master driver (interfaces SPI NAND flash chip) 7 | * 8 | */ 9 | 10 | #ifndef __SPI_H 11 | #define __SPI_H 12 | 13 | #include 14 | #include 15 | 16 | /// @brief SPI return statuses 17 | #define SPI_RET_OK 0 18 | #define SPI_RET_TIMEOUT -1 19 | #define SPI_RET_NULL_PTR -2 20 | 21 | /// @brief Initializes the spi driver 22 | void spi_init(void); 23 | 24 | /// @brief Writes data to the bus 25 | /// @note Caller is expected to drive the chip select line for the relevant device 26 | int spi_write(const uint8_t *write_buff, size_t write_len, uint32_t timeout_ms); 27 | 28 | /// @brief Reads data from the bus 29 | /// @note Caller is expected to drive the chip select line for the relevant device 30 | /// @note Transmits 0x00 on the MOSI line during the transaction 31 | int spi_read(uint8_t *read_buff, size_t read_len, uint32_t timeout_ms); 32 | 33 | /// @brief Writes/reads data to/from to the bus 34 | /// @note Caller is expected to drive the chip select line for the relevant device 35 | int spi_write_read(const uint8_t *write_buff, uint8_t *read_buff, size_t transfer_len, 36 | uint32_t timeout_ms); 37 | 38 | #endif // __SPI_H 39 | -------------------------------------------------------------------------------- /src/dhara/error.h: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DHARA_ERROR_H_ 18 | #define DHARA_ERROR_H_ 19 | 20 | typedef enum { 21 | DHARA_E_NONE = 0, 22 | DHARA_E_BAD_BLOCK, 23 | DHARA_E_ECC, 24 | DHARA_E_TOO_BAD, 25 | DHARA_E_RECOVER, 26 | DHARA_E_JOURNAL_FULL, 27 | DHARA_E_NOT_FOUND, 28 | DHARA_E_MAP_FULL, 29 | DHARA_E_CORRUPT_MAP, 30 | DHARA_E_MAX 31 | } dhara_error_t; 32 | 33 | /* Produce a human-readable error message. This function is kept in a 34 | * separate compilation unit and can be omitted to reduce binary size. 35 | */ 36 | const char *dhara_strerror(dhara_error_t err); 37 | 38 | /* Save an error */ 39 | static inline void dhara_set_error(dhara_error_t *err, dhara_error_t v) 40 | { 41 | if (err) 42 | *err = v; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/dhara/bytes.h: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DHARA_BYTES_H_ 18 | #define DHARA_BYTES_H_ 19 | 20 | #include 21 | 22 | static inline uint16_t dhara_r16(const uint8_t *data) 23 | { 24 | return ((uint16_t)data[0]) | 25 | (((uint16_t)data[1]) << 8); 26 | } 27 | 28 | static inline void dhara_w16(uint8_t *data, uint16_t v) 29 | { 30 | data[0] = v; 31 | data[1] = v >> 8; 32 | } 33 | 34 | static inline uint32_t dhara_r32(const uint8_t *data) 35 | { 36 | return ((uint32_t)data[0]) | 37 | (((uint32_t)data[1]) << 8) | 38 | (((uint32_t)data[2]) << 16) | 39 | (((uint32_t)data[3]) << 24); 40 | } 41 | 42 | static inline void dhara_w32(uint8_t *data, uint32_t v) 43 | { 44 | data[0] = v; 45 | data[1] = v >> 8; 46 | data[2] = v >> 16; 47 | data[3] = v >> 24; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/dhara/error.c: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include "error.h" 19 | 20 | const char *dhara_strerror(dhara_error_t err) 21 | { 22 | static const char *const messages[DHARA_E_MAX] = { 23 | [DHARA_E_NONE] = "No error", 24 | [DHARA_E_BAD_BLOCK] = "Bad page/eraseblock", 25 | [DHARA_E_ECC] = "ECC failure", 26 | [DHARA_E_TOO_BAD] = "Too many bad blocks", 27 | [DHARA_E_RECOVER] = "Journal recovery is required", 28 | [DHARA_E_JOURNAL_FULL] = "Journal is full", 29 | [DHARA_E_NOT_FOUND] = "No such sector", 30 | [DHARA_E_MAP_FULL] = "Sector map is full", 31 | [DHARA_E_CORRUPT_MAP] = "Sector map is corrupted" 32 | }; 33 | const char *msg = NULL; 34 | 35 | if ((err >= 0) && (err < DHARA_E_MAX)) 36 | msg = messages[err]; 37 | 38 | if (msg) 39 | return msg; 40 | 41 | return "Unknown error"; 42 | } 43 | -------------------------------------------------------------------------------- /src/modules/sys_time.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sys_time.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the sys time module 5 | * 6 | */ 7 | 8 | #include "sys_time.h" 9 | 10 | #include "../st/ll/stm32l4xx_ll_utils.h" 11 | #include "../st/stm32l4xx.h" 12 | #include "../st/system_stm32l4xx.h" 13 | 14 | // defines 15 | #define SYSTICK_PREEMPT_PRIORITY 0 16 | #define SYSTICK_SUB_PRIORITY 0 17 | 18 | // private variables 19 | uint32_t sys_time_ms = 0; 20 | 21 | // public function definitions 22 | void sys_time_init(void) 23 | { 24 | sys_time_ms = 0; 25 | 26 | // setup 1 ms sys tick 27 | SysTick_Config((SystemCoreClock / 1000) - 1); 28 | NVIC_SetPriority(SysTick_IRQn, 29 | NVIC_EncodePriority(NVIC_GetPriorityGrouping(), SYSTICK_PREEMPT_PRIORITY, 30 | SYSTICK_SUB_PRIORITY)); 31 | } 32 | 33 | void _sys_time_increment(void) 34 | { 35 | sys_time_ms++; 36 | } 37 | 38 | uint32_t sys_time_get_ms(void) 39 | { 40 | return sys_time_ms; 41 | } 42 | 43 | uint32_t sys_time_get_elapsed(uint32_t start) 44 | { 45 | return sys_time_ms - start; 46 | } 47 | 48 | // TODO: add unit test for this function 49 | // normal case 50 | // current time overlapped, end time not overlapped 51 | // current time overlapped, end time overlapped 52 | // current time not overlapped, end time overlapped 53 | // all above cases when duration is 0 54 | bool sys_time_is_elapsed(uint32_t start, uint32_t duration_ms) 55 | { 56 | return (sys_time_get_elapsed(start) >= duration_ms); 57 | } 58 | 59 | void sys_time_delay(uint32_t duration_ms) 60 | { 61 | uint32_t start = sys_time_ms; 62 | while (!sys_time_is_elapsed(start, duration_ms)) 63 | ; 64 | } -------------------------------------------------------------------------------- /src/cmsis/cmsis_version.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file cmsis_version.h 3 | * @brief CMSIS Core(M) Version definitions 4 | * @version V5.0.2 5 | * @date 19. April 2017 6 | ******************************************************************************/ 7 | /* 8 | * Copyright (c) 2009-2017 ARM Limited. All rights reserved. 9 | * 10 | * SPDX-License-Identifier: Apache-2.0 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the License); you may 13 | * not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 20 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #if defined ( __ICCARM__ ) 26 | #pragma system_include /* treat file as system include file for MISRA check */ 27 | #elif defined (__clang__) 28 | #pragma clang system_header /* treat file as system include file */ 29 | #endif 30 | 31 | #ifndef __CMSIS_VERSION_H 32 | #define __CMSIS_VERSION_H 33 | 34 | /* CMSIS Version definitions */ 35 | #define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ 36 | #define __CM_CMSIS_VERSION_SUB ( 1U) /*!< [15:0] CMSIS Core(M) sub version */ 37 | #define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ 38 | __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ 39 | #endif 40 | -------------------------------------------------------------------------------- /src/syscalls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "modules/uart.h" 10 | 11 | void *_sbrk(int incr) 12 | { 13 | extern int end; 14 | static char *heap_end; 15 | char *prev_heap_end; 16 | 17 | if (!heap_end) heap_end = (char *)&end; 18 | 19 | prev_heap_end = heap_end; 20 | heap_end += incr; 21 | 22 | return prev_heap_end; 23 | } 24 | 25 | int _open(char *path, int flags, ...) { return -1; } 26 | 27 | int _close(int file) { return -1; } 28 | 29 | int _fstat(int file, struct stat *st) 30 | { 31 | st->st_mode = S_IFCHR; 32 | return 0; 33 | } 34 | 35 | int _isatty(int file) { return 1; } 36 | 37 | int _lseek(int file, int ptr, int dir) { return 0; } 38 | 39 | void _kill(int pid, int sig) { return; } 40 | 41 | void _exit(int status) 42 | { 43 | _kill(status, -1); 44 | while (1) { 45 | } 46 | } 47 | 48 | int _getpid(void) { return -1; } 49 | 50 | int _read(int file, char *ptr, int len) 51 | { 52 | if (STDIN_FILENO == file) { 53 | int i; // this needs to persist after the for loop 54 | for (i = 0; i < len; i++) { 55 | if (!_uart_try_getc(&ptr[i])) { 56 | break; 57 | } 58 | } 59 | return i; 60 | } 61 | else { 62 | // anything other than STDIN is invalid 63 | errno = EBADF; 64 | return -1; 65 | } 66 | } 67 | 68 | int _write(int file, char *ptr, int len) 69 | { 70 | if ((STDOUT_FILENO == file) || (STDERR_FILENO == file)) { 71 | for (int i = 0; i < len; i++) { 72 | _uart_putc(ptr[i]); 73 | } 74 | return len; 75 | } 76 | else { 77 | // anything other than STDOUT or STDERR is invalid 78 | errno = EBADF; 79 | return -1; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/modules/fifo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fifo.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the FIFO module 5 | * 6 | * Simple inline functions for FIFO buffer interaction 7 | * 8 | */ 9 | 10 | #ifndef __FIFO_H 11 | #define __FIFO_H 12 | 13 | #include 14 | #include 15 | 16 | typedef struct { 17 | uint8_t *_front; 18 | uint8_t *_back; 19 | uint8_t *_read; 20 | uint8_t *_write; 21 | } fifo_t; 22 | 23 | /// @brief Macro for fifo static initializer 24 | /// @param buffer Underlying memory block to be used by the fifo 25 | /// @param len Length of the memory block 26 | #define FIFO_STATIC_INIT(buffer, len) \ 27 | { \ 28 | ._front = (buffer), ._back = &(buffer)[(len)-1], ._read = (buffer), ._write = (buffer), \ 29 | } 30 | 31 | /// @brief Inline function for checking if the fifo is empty 32 | static inline bool fifo_is_empty(fifo_t *fifo) { return fifo->_read == fifo->_write; } 33 | 34 | /// @brief Inline function for checking if the fifo is full 35 | static inline bool fifo_is_full(fifo_t *fifo) 36 | { 37 | bool normal_case = (fifo->_write + 1) == fifo->_read; 38 | bool edge_case = (fifo->_write == fifo->_back) && (fifo->_read == fifo->_front); 39 | 40 | return normal_case || edge_case; 41 | } 42 | 43 | /// @brief Inline function for enqueueing a byte into the fifo 44 | /// @return true if enqueued successfully, false if full 45 | static inline bool fifo_enqueue(fifo_t *fifo, uint8_t value) 46 | { 47 | if (fifo_is_full(fifo)) return false; 48 | 49 | *fifo->_write = value; 50 | // circular increment 51 | if (fifo->_write == fifo->_back) 52 | fifo->_write = fifo->_front; 53 | else 54 | fifo->_write++; 55 | 56 | return true; 57 | } 58 | 59 | /// @brief Inline function for dequeueing a byte from the fifo 60 | /// @return true if dequeued successfully, false if empty 61 | static inline bool fifo_try_dequeue(fifo_t *fifo, uint8_t *out) 62 | { 63 | if (fifo_is_empty(fifo)) return false; 64 | 65 | *out = *fifo->_read; 66 | // circular increment 67 | if (fifo->_read == fifo->_back) 68 | fifo->_read = fifo->_front; 69 | else 70 | fifo->_read++; 71 | 72 | return true; 73 | } 74 | 75 | #endif // __FIFO_H 76 | -------------------------------------------------------------------------------- /src/st/stm32_assert.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32_assert.h 4 | * @author MCD Application Team 5 | * @brief STM32 assert template file. 6 | * This file should be copied to the application folder and renamed 7 | * to stm32_assert.h. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© Copyright (c) 2017 STMicroelectronics. 12 | * All rights reserved.

13 | * 14 | * This software component is licensed by ST under BSD 3-Clause license, 15 | * the "License"; You may not use this file except in compliance with the 16 | * License. You may obtain a copy of the License at: 17 | * opensource.org/licenses/BSD-3-Clause 18 | * 19 | ****************************************************************************** 20 | */ 21 | 22 | /* Define to prevent recursive inclusion -------------------------------------*/ 23 | #ifndef STM32_ASSERT_H 24 | #define STM32_ASSERT_H 25 | 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /* Exported types ------------------------------------------------------------*/ 33 | /* Exported constants --------------------------------------------------------*/ 34 | /* Includes ------------------------------------------------------------------*/ 35 | /* Exported macro ------------------------------------------------------------*/ 36 | #ifdef USE_FULL_ASSERT 37 | /** 38 | * @brief The assert_param macro is used for function's parameters check. 39 | * @param expr: If expr is false, it calls assert_failed function 40 | * which reports the name of the source file and the source 41 | * line number of the call that failed. 42 | * If expr is true, it returns no value. 43 | * @retval None 44 | */ 45 | #define assert_param(expr) ((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__)) 46 | /* Exported functions ------------------------------------------------------- */ 47 | void assert_failed(char *file, uint32_t line); 48 | #else 49 | #define assert_param(expr) ((void)0U) 50 | #endif /* USE_FULL_ASSERT */ 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif /* STM32_ASSERT_H */ 57 | 58 | 59 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 60 | -------------------------------------------------------------------------------- /src/st/ll/stm32l4xx_ll_pwr.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32l4xx_ll_pwr.c 4 | * @author MCD Application Team 5 | * @brief PWR LL module driver. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2017 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under BSD 3-Clause license, 13 | * the "License"; You may not use this file except in compliance with the 14 | * License. You may obtain a copy of the License at: 15 | * opensource.org/licenses/BSD-3-Clause 16 | * 17 | ****************************************************************************** 18 | */ 19 | #if defined(USE_FULL_LL_DRIVER) 20 | 21 | /* Includes ------------------------------------------------------------------*/ 22 | #include "stm32l4xx_ll_pwr.h" 23 | #include "stm32l4xx_ll_bus.h" 24 | 25 | /** @addtogroup STM32L4xx_LL_Driver 26 | * @{ 27 | */ 28 | 29 | #if defined(PWR) 30 | 31 | /** @defgroup PWR_LL PWR 32 | * @{ 33 | */ 34 | 35 | /* Private types -------------------------------------------------------------*/ 36 | /* Private variables ---------------------------------------------------------*/ 37 | /* Private constants ---------------------------------------------------------*/ 38 | /* Private macros ------------------------------------------------------------*/ 39 | /* Private function prototypes -----------------------------------------------*/ 40 | 41 | /* Exported functions --------------------------------------------------------*/ 42 | /** @addtogroup PWR_LL_Exported_Functions 43 | * @{ 44 | */ 45 | 46 | /** @addtogroup PWR_LL_EF_Init 47 | * @{ 48 | */ 49 | 50 | /** 51 | * @brief De-initialize the PWR registers to their default reset values. 52 | * @retval An ErrorStatus enumeration value: 53 | * - SUCCESS: PWR registers are de-initialized 54 | * - ERROR: not applicable 55 | */ 56 | ErrorStatus LL_PWR_DeInit(void) 57 | { 58 | /* Force reset of PWR clock */ 59 | LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_PWR); 60 | 61 | /* Release reset of PWR clock */ 62 | LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_PWR); 63 | 64 | return SUCCESS; 65 | } 66 | 67 | /** 68 | * @} 69 | */ 70 | 71 | /** 72 | * @} 73 | */ 74 | 75 | /** 76 | * @} 77 | */ 78 | #endif /* defined(PWR) */ 79 | /** 80 | * @} 81 | */ 82 | 83 | #endif /* USE_FULL_LL_DRIVER */ 84 | 85 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 86 | -------------------------------------------------------------------------------- /src/st/system_stm32l4xx.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file system_stm32l4xx.h 4 | * @author MCD Application Team 5 | * @brief CMSIS Cortex-M4 Device System Source File for STM32L4xx devices. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2017 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under BSD 3-Clause license, 13 | * the "License"; You may not use this file except in compliance with the 14 | * License. You may obtain a copy of the License at: 15 | * opensource.org/licenses/BSD-3-Clause 16 | * 17 | ****************************************************************************** 18 | */ 19 | 20 | /** @addtogroup CMSIS 21 | * @{ 22 | */ 23 | 24 | /** @addtogroup stm32l4xx_system 25 | * @{ 26 | */ 27 | 28 | /** 29 | * @brief Define to prevent recursive inclusion 30 | */ 31 | #ifndef __SYSTEM_STM32L4XX_H 32 | #define __SYSTEM_STM32L4XX_H 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | /** @addtogroup STM32L4xx_System_Includes 39 | * @{ 40 | */ 41 | 42 | /** 43 | * @} 44 | */ 45 | 46 | 47 | /** @addtogroup STM32L4xx_System_Exported_Variables 48 | * @{ 49 | */ 50 | /* The SystemCoreClock variable is updated in three ways: 51 | 1) by calling CMSIS function SystemCoreClockUpdate() 52 | 2) by calling HAL API function HAL_RCC_GetSysClockFreq() 53 | 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency 54 | Note: If you use this function to configure the system clock; then there 55 | is no need to call the 2 first functions listed above, since SystemCoreClock 56 | variable is updated automatically. 57 | */ 58 | extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ 59 | 60 | extern const uint8_t AHBPrescTable[16]; /*!< AHB prescalers table values */ 61 | extern const uint8_t APBPrescTable[8]; /*!< APB prescalers table values */ 62 | extern const uint32_t MSIRangeTable[12]; /*!< MSI ranges table values */ 63 | 64 | /** 65 | * @} 66 | */ 67 | 68 | /** @addtogroup STM32L4xx_System_Exported_Constants 69 | * @{ 70 | */ 71 | 72 | /** 73 | * @} 74 | */ 75 | 76 | /** @addtogroup STM32L4xx_System_Exported_Macros 77 | * @{ 78 | */ 79 | 80 | /** 81 | * @} 82 | */ 83 | 84 | /** @addtogroup STM32L4xx_System_Exported_Functions 85 | * @{ 86 | */ 87 | 88 | extern void SystemInit(void); 89 | extern void SystemCoreClockUpdate(void); 90 | /** 91 | * @} 92 | */ 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | 98 | #endif /*__SYSTEM_STM32L4XX_H */ 99 | 100 | /** 101 | * @} 102 | */ 103 | 104 | /** 105 | * @} 106 | */ 107 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 108 | -------------------------------------------------------------------------------- /src/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2019 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "ff.h" /* Obtains integer types */ 13 | 14 | /* Status of Disk Functions */ 15 | typedef BYTE DSTATUS; 16 | 17 | /* Results of Disk Functions */ 18 | typedef enum { 19 | RES_OK = 0, /* 0: Successful */ 20 | RES_ERROR, /* 1: R/W Error */ 21 | RES_WRPRT, /* 2: Write Protected */ 22 | RES_NOTRDY, /* 3: Not Ready */ 23 | RES_PARERR /* 4: Invalid Parameter */ 24 | } DRESULT; 25 | 26 | /*---------------------------------------*/ 27 | /* Prototypes for disk control functions */ 28 | 29 | DSTATUS disk_initialize(BYTE pdrv); 30 | DSTATUS disk_status(BYTE pdrv); 31 | DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count); 32 | DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count); 33 | DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff); 34 | 35 | /* Disk Status Bits (DSTATUS) */ 36 | 37 | #define STA_NOINIT 0x01 /* Drive not initialized */ 38 | #define STA_NODISK 0x02 /* No medium in the drive */ 39 | #define STA_PROTECT 0x04 /* Write protected */ 40 | 41 | /* Command code for disk_ioctrl fucntion */ 42 | 43 | /* Generic command (Used by FatFs) */ 44 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 45 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 46 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 47 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 48 | #define CTRL_TRIM \ 49 | 4 /* Inform device that the data on the block of sectors is no longer used (needed at \ 50 | FF_USE_TRIM == 1) */ 51 | 52 | /* Generic command (Not used by FatFs) */ 53 | #define CTRL_POWER 5 /* Get/Set power status */ 54 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 55 | #define CTRL_EJECT 7 /* Eject media */ 56 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 57 | 58 | /* MMC/SDC specific ioctl command */ 59 | #define MMC_GET_TYPE 10 /* Get card type */ 60 | #define MMC_GET_CSD 11 /* Get CSD */ 61 | #define MMC_GET_CID 12 /* Get CID */ 62 | #define MMC_GET_OCR 13 /* Get OCR */ 63 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 64 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 65 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 66 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 67 | 68 | /* ATA/CF specific ioctl command */ 69 | #define ATA_GET_REV 20 /* Get F/W revision */ 70 | #define ATA_GET_MODEL 21 /* Get model name */ 71 | #define ATA_GET_SN 22 /* Get serial number */ 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/modules/spi_nand.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file spi_nand.h 3 | * @author Andrew Loebs 4 | * @brief Header file of the spi nand module 5 | * 6 | * SPI NAND flash chip driver for the Micron MT29F1G01ABAFDWB. 7 | * 8 | */ 9 | 10 | #ifndef __SPI_NAND_H 11 | #define __SPI_NAND_H 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | /// @brief SPI return statuses 18 | enum { 19 | SPI_NAND_RET_OK = 0, 20 | SPI_NAND_RET_BAD_SPI = -1, 21 | SPI_NAND_RET_TIMEOUT = -2, 22 | SPI_NAND_RET_DEVICE_ID = -3, 23 | SPI_NAND_RET_BAD_ADDRESS = -4, 24 | SPI_NAND_RET_INVALID_LEN = -5, 25 | SPI_NAND_RET_ECC_REFRESH = -6, 26 | SPI_NAND_RET_ECC_ERR = -7, 27 | SPI_NAND_RET_P_FAIL = -8, 28 | SPI_NAND_RET_E_FAIL = -9, 29 | }; 30 | 31 | #define SPI_NAND_PAGE_SIZE 2048 32 | #define SPI_NAND_OOB_SIZE 64 33 | #define SPI_NAND_PAGES_PER_BLOCK 64 34 | #define SPI_NAND_BLOCKS_PER_LUN 1024 35 | 36 | #define SPI_NAND_LOG2_PAGE_SIZE 11 37 | #define SPI_NAND_LOG2_PAGES_PER_BLOCK 6 38 | 39 | #define SPI_NAND_MAX_PAGE_ADDRESS (SPI_NAND_PAGES_PER_BLOCK - 1) // zero-indexed 40 | #define SPI_NAND_MAX_BLOCK_ADDRESS (SPI_NAND_BLOCKS_PER_LUN - 1) // zero-indexed 41 | 42 | /// @brief Nand row address 43 | typedef union { 44 | uint32_t whole; 45 | struct { 46 | /// valid range 0-63 47 | uint32_t page : 6; 48 | /// valid range 0-1023 49 | uint32_t block : 26; 50 | }; 51 | } row_address_t; 52 | /// @brief Nand column address (valid range 0-2175) 53 | typedef uint16_t column_address_t; 54 | 55 | /// @brief Initializes the spi nand driver 56 | int spi_nand_init(void); 57 | 58 | /// @brief Performs a read page operation 59 | int spi_nand_page_read(row_address_t row, column_address_t column, uint8_t *data_out, 60 | size_t read_len); 61 | 62 | /// @brief Performs a page program operation 63 | int spi_nand_page_program(row_address_t row, column_address_t column, const uint8_t *data_in, 64 | size_t write_len); 65 | 66 | /// @brief Copies the source page to the destination page using nand's internal cache 67 | int spi_nand_page_copy(row_address_t src, row_address_t dest); 68 | 69 | /// @brief Performs a block erase operation 70 | /// @note Block operation -- page component of row address is ignored 71 | int spi_nand_block_erase(row_address_t row); 72 | 73 | /// @brief Checks if a given block is bad 74 | /// @note Block operation -- page component of row address is ignored 75 | /// @return SPI_NAND_RET_OK if good block, SPI_NAND_RET_BAD_BLOCK if bad, other returns if error is 76 | /// encountered 77 | int spi_nand_block_is_bad(row_address_t row, bool *is_bad); 78 | 79 | /// @brief Marks a given block as bad 80 | /// @note Block operation -- page component of row address is ignored 81 | int spi_nand_block_mark_bad(row_address_t row); 82 | 83 | /// @brief Checks if a given page is free 84 | int spi_nand_page_is_free(row_address_t row, bool *is_free); 85 | 86 | /// @brief Erases all blocks from the device, ignoring those marked as bad 87 | int spi_nand_clear(void); 88 | 89 | #endif // __SPI_NAND_H 90 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Heavily influenced by the makefile used in the interrupt blog's zero to main series 2 | # see: https://github.com/memfault/zero-to-main 3 | 4 | ifdef DEBUG 5 | NO_ECHO := 6 | else 7 | NO_ECHO := @ 8 | endif 9 | 10 | PROJECT := flash_management 11 | BUILD_DIR ?= build 12 | 13 | SRCS += \ 14 | src/st/ll/stm32l4xx_ll_gpio.c \ 15 | src/st/ll/stm32l4xx_ll_pwr.c \ 16 | src/st/ll/stm32l4xx_ll_rcc.c \ 17 | src/st/ll/stm32l4xx_ll_spi.c \ 18 | src/st/ll/stm32l4xx_ll_utils.c \ 19 | src/st/system_stm32l4xx.c \ 20 | src/dhara/error.c \ 21 | src/dhara/journal.c \ 22 | src/dhara/map.c \ 23 | src/dhara/nand.c \ 24 | src/fatfs/diskio.c \ 25 | src/fatfs/ff.c \ 26 | src/fatfs/ffsystem.c \ 27 | src/fatfs/ffunicode.c \ 28 | src/modules/led.c \ 29 | src/modules/nand_ftl_diskio.c \ 30 | src/modules/mem.c \ 31 | src/modules/shell.c \ 32 | src/modules/shell_cmd.c \ 33 | src/modules/spi.c \ 34 | src/modules/spi_nand.c \ 35 | src/modules/sys_time.c \ 36 | src/modules/uart.c \ 37 | src/syscalls.c \ 38 | src/startup_stm32l432kc.c \ 39 | src/stm32l432kc_it.c \ 40 | src/main.c 41 | 42 | INCLUDES += \ 43 | src/st \ 44 | src/st/ll \ 45 | src/cmsis \ 46 | 47 | 48 | CC=arm-none-eabi-gcc 49 | LD=arm-none-eabi-ld 50 | OCPY=arm-none-eabi-objcopy 51 | ODUMP=arm-none-eabi-objdump 52 | SZ=arm-none-eabi-size 53 | MKDIR=mkdir 54 | STFLASH=st-flash 55 | 56 | ASMFLAGS += \ 57 | -mcpu=cortex-m4 \ 58 | -g3 \ 59 | -x assembler \ 60 | --specs=nano.specs \ 61 | -mfpu=fpv4-sp-d16 \ 62 | -mfloat-abi=hard \ 63 | -mthumb 64 | 65 | CFLAGS += \ 66 | -mcpu=cortex-m4 \ 67 | -std=gnu11 \ 68 | -g3 \ 69 | -Og \ 70 | -ffunction-sections \ 71 | -fdata-sections \ 72 | -Wall \ 73 | -fno-signed-char \ 74 | -Wno-pointer-sign \ 75 | -fstack-usage \ 76 | --specs=nano.specs \ 77 | -mfpu=fpv4-sp-d16 \ 78 | -mfloat-abi=hard \ 79 | -mthumb 80 | 81 | LDFLAGS += \ 82 | -T src/stm32l432kc.ld \ 83 | -static \ 84 | -lc \ 85 | -lm \ 86 | -Wl,-Map=$(BUILD_DIR)/$(PROJECT).map \ 87 | -Wl,--gc-sections \ 88 | -Wl,--print-memory-usage 89 | 90 | DEFINES += \ 91 | DEBUG \ 92 | USE_FULL_ASSERT \ 93 | STM32L432xx 94 | 95 | CFLAGS += $(foreach i,$(INCLUDES),-I$(i)) 96 | CFLAGS += $(foreach d,$(DEFINES),-D$(d)) 97 | 98 | OBJ_DIR = $(BUILD_DIR)/objs 99 | OBJS = $(patsubst %.c,$(OBJ_DIR)/%.o,$(SRCS)) 100 | 101 | .PHONY: all 102 | all: $(BUILD_DIR)/$(PROJECT).bin 103 | 104 | $(BUILD_DIR): 105 | $(NO_ECHO)$(MKDIR) -p $(BUILD_DIR) 106 | 107 | $(OBJ_DIR): 108 | $(NO_ECHO)$(MKDIR) -p $(OBJ_DIR) 109 | 110 | $(OBJ_DIR)/%.o: %.s $(OBJ_DIR) 111 | @echo "Assembling $<" 112 | $(NO_ECHO)$(MKDIR) -p $(dir $@) 113 | $(NO_ECHO)$(CC) -c -o $@ $< $(ASMFLAGS) 114 | 115 | $(OBJ_DIR)/%.o: %.c $(OBJ_DIR) 116 | @echo "Compiling $<" 117 | $(NO_ECHO)$(MKDIR) -p $(dir $@) 118 | $(NO_ECHO)$(CC) -c -o $@ $< $(CFLAGS) 119 | 120 | $(BUILD_DIR)/$(PROJECT).bin: $(BUILD_DIR)/$(PROJECT).elf $(BUILD_DIR)/$(PROJECT).lst 121 | $(OCPY) $< $@ -O binary 122 | $(SZ) $< 123 | 124 | $(BUILD_DIR)/$(PROJECT).lst: $(BUILD_DIR)/$(PROJECT).elf $(BUILD_DIR) 125 | $(ODUMP) -D $< > $@ 126 | 127 | $(BUILD_DIR)/$(PROJECT).elf: $(OBJS) 128 | @echo "Linking $@" 129 | $(NO_ECHO)$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ 130 | 131 | .PHONY: clean 132 | clean: 133 | rm -rf $(BUILD_DIR) 134 | 135 | .PHONY: flash 136 | flash: $(BUILD_DIR)/$(PROJECT).bin 137 | $(STFLASH) write $(BUILD_DIR)/$(PROJECT).bin 0x08000000 138 | -------------------------------------------------------------------------------- /src/stm32l432kc.ld: -------------------------------------------------------------------------------- 1 | /* Entry point */ 2 | ENTRY(Reset_Handler) 3 | 4 | /* Memory map */ 5 | MEMORY { 6 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K 7 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K 8 | } 9 | 10 | /* Stack and heap sizes */ 11 | STACK_SIZE = 4096; 12 | HEAP_SIZE = 512; 13 | 14 | /* Sections */ 15 | SECTIONS { 16 | .isr_vector : { 17 | . = ALIGN(4); 18 | KEEP(*(.isr_vector)) /* Startup code */ 19 | . = ALIGN(4); 20 | } >FLASH 21 | 22 | .text : { 23 | . = ALIGN(4); 24 | *(.text) /* .text sections (code) */ 25 | *(.text*) /* .text* sections (code) */ 26 | *(.glue_7) /* glue arm to thumb code */ 27 | *(.glue_7t) /* glue thumb to arm code */ 28 | *(.eh_frame) 29 | 30 | KEEP (*(.init)) 31 | KEEP (*(.fini)) 32 | 33 | . = ALIGN(4); 34 | _etext = .; /* define a global symbols at end of code */ 35 | } >FLASH 36 | 37 | .rodata : { 38 | . = ALIGN(4); 39 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 40 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 41 | . = ALIGN(4); 42 | } >FLASH 43 | 44 | .ARM.extab : { 45 | . = ALIGN(4); 46 | *(.ARM.extab* .gnu.linkonce.armextab.*) 47 | . = ALIGN(4); 48 | } >FLASH 49 | 50 | .ARM : { 51 | . = ALIGN(4); 52 | __exidx_start = .; 53 | *(.ARM.exidx*) 54 | __exidx_end = .; 55 | . = ALIGN(4); 56 | } >FLASH 57 | 58 | .preinit_array : { 59 | . = ALIGN(4); 60 | PROVIDE_HIDDEN (__preinit_array_start = .); 61 | KEEP (*(.preinit_array*)) 62 | PROVIDE_HIDDEN (__preinit_array_end = .); 63 | . = ALIGN(4); 64 | } >FLASH 65 | 66 | .init_array : { 67 | . = ALIGN(4); 68 | PROVIDE_HIDDEN (__init_array_start = .); 69 | KEEP (*(SORT(.init_array.*))) 70 | KEEP (*(.init_array*)) 71 | PROVIDE_HIDDEN (__init_array_end = .); 72 | . = ALIGN(4); 73 | } >FLASH 74 | 75 | .fini_array : { 76 | . = ALIGN(4); 77 | PROVIDE_HIDDEN (__fini_array_start = .); 78 | KEEP (*(SORT(.fini_array.*))) 79 | KEEP (*(.fini_array*)) 80 | PROVIDE_HIDDEN (__fini_array_end = .); 81 | . = ALIGN(4); 82 | } >FLASH 83 | 84 | /* End of FLASH */ 85 | _etext = .; 86 | 87 | .stack : { 88 | __stack_start__ = .; 89 | . = . + STACK_SIZE; 90 | . = ALIGN(4); 91 | __stack_end__ = .; 92 | } >RAM 93 | 94 | .data : AT (_etext) { 95 | __data_load = LOADADDR (.data); 96 | __data_start = .; 97 | *(.data) /* .data sections */ 98 | *(.data*) /* .data* sections */ 99 | . = ALIGN(4); 100 | __data_end__ = .; 101 | _edata = __data_end__; 102 | } >RAM 103 | 104 | .bss : { 105 | __bss_start__ = .; 106 | *(.bss) 107 | *(.bss*) 108 | *(COMMON) 109 | . = ALIGN(4); 110 | _ebss = .; /* define a global symbol at bss end */ 111 | __bss_end__ = .; 112 | } >RAM 113 | 114 | PROVIDE ( end = _ebss ); 115 | PROVIDE ( _end = _ebss ); 116 | PROVIDE ( __end__ = _ebss ); 117 | 118 | .heap : { 119 | __heap_start__ = .; 120 | . = . + HEAP_SIZE; 121 | . = ALIGN(4); 122 | __heap_end__ = .; 123 | } >RAM 124 | 125 | /* Remove information from the standard libraries */ 126 | /DISCARD/ : { 127 | libc.a ( * ) 128 | libm.a ( * ) 129 | libgcc.a ( * ) 130 | } 131 | 132 | .ARM.attributes 0 : { *(.ARM.attributes) } 133 | } -------------------------------------------------------------------------------- /src/fatfs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* If a working storage control module is available, it should be */ 5 | /* attached to the FatFs via a glue function rather than modifying it. */ 6 | /* This is an example of glue functions to attach various exsisting */ 7 | /* storage control modules to the FatFs module with a defined API. */ 8 | /*-----------------------------------------------------------------------*/ 9 | 10 | #include "diskio.h" /* Declarations of disk functions */ 11 | 12 | #include "../modules/nand_ftl_diskio.h" 13 | 14 | // Drive number for spi_nand device 15 | #define PDRV_NAND_FTL 0 16 | 17 | /*-----------------------------------------------------------------------*/ 18 | /* Get Drive Status */ 19 | /*-----------------------------------------------------------------------*/ 20 | DSTATUS disk_status(BYTE pdrv /* Physical drive nmuber to identify the drive */ 21 | ) 22 | { 23 | if (PDRV_NAND_FTL == pdrv) { 24 | return nand_ftl_diskio_status(); 25 | } 26 | else { 27 | return STA_NODISK; 28 | } 29 | } 30 | 31 | /*-----------------------------------------------------------------------*/ 32 | /* Inidialize a Drive */ 33 | /*-----------------------------------------------------------------------*/ 34 | 35 | DSTATUS disk_initialize(BYTE pdrv /* Physical drive nmuber to identify the drive */ 36 | ) 37 | { 38 | if (PDRV_NAND_FTL == pdrv) { 39 | return nand_ftl_diskio_initialize(); 40 | } 41 | else { 42 | return STA_NODISK; 43 | } 44 | } 45 | 46 | /*-----------------------------------------------------------------------*/ 47 | /* Read Sector(s) */ 48 | /*-----------------------------------------------------------------------*/ 49 | 50 | DRESULT disk_read(BYTE pdrv, /* Physical drive nmuber to identify the drive */ 51 | BYTE *buff, /* Data buffer to store read data */ 52 | LBA_t sector, /* Start sector in LBA */ 53 | UINT count /* Number of sectors to read */ 54 | ) 55 | { 56 | if (PDRV_NAND_FTL == pdrv) { 57 | return nand_ftl_diskio_read(buff, sector, count); 58 | } 59 | else { 60 | return STA_NODISK; 61 | } 62 | } 63 | 64 | /*-----------------------------------------------------------------------*/ 65 | /* Write Sector(s) */ 66 | /*-----------------------------------------------------------------------*/ 67 | 68 | #if FF_FS_READONLY == 0 69 | 70 | DRESULT disk_write(BYTE pdrv, /* Physical drive nmuber to identify the drive */ 71 | const BYTE *buff, /* Data to be written */ 72 | LBA_t sector, /* Start sector in LBA */ 73 | UINT count /* Number of sectors to write */ 74 | ) 75 | { 76 | if (PDRV_NAND_FTL == pdrv) { 77 | return nand_ftl_diskio_write(buff, sector, count); 78 | } 79 | else { 80 | return STA_NODISK; 81 | } 82 | } 83 | 84 | #endif 85 | 86 | /*-----------------------------------------------------------------------*/ 87 | /* Miscellaneous Functions */ 88 | /*-----------------------------------------------------------------------*/ 89 | 90 | DRESULT disk_ioctl(BYTE pdrv, /* Physical drive nmuber (0..) */ 91 | BYTE cmd, /* Control code */ 92 | void *buff /* Buffer to send/receive control data */ 93 | ) 94 | { 95 | if (PDRV_NAND_FTL == pdrv) { 96 | return nand_ftl_diskio_ioctl(cmd, buff); 97 | } 98 | else { 99 | return STA_NODISK; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main.c 3 | * @author Andrew Loebs 4 | * @brief Main application 5 | * 6 | */ 7 | 8 | #include 9 | 10 | #include "st/ll/stm32l4xx_ll_bus.h" 11 | #include "st/ll/stm32l4xx_ll_rcc.h" 12 | #include "st/ll/stm32l4xx_ll_system.h" 13 | #include "st/ll/stm32l4xx_ll_utils.h" 14 | #include "st/stm32_assert.h" 15 | 16 | #include "modules/led.h" 17 | #include "modules/mem.h" 18 | #include "modules/shell.h" 19 | #include "modules/spi.h" 20 | #include "modules/sys_time.h" 21 | #include "modules/uart.h" 22 | 23 | #include "fatfs/ff.h" 24 | #include "fatfs/ffconf.h" 25 | 26 | // defines 27 | #define STARTUP_LED_DURATION_MS 200 28 | 29 | // private function prototypes 30 | static void clock_config(void); 31 | 32 | // private variables 33 | FATFS fs; // file system object 34 | 35 | // application main function 36 | int main(void) 37 | { 38 | // setup clock 39 | clock_config(); 40 | 41 | // init base modules 42 | led_init(); 43 | sys_time_init(); 44 | uart_init(); 45 | shell_init(); 46 | spi_init(); 47 | 48 | // blink LED to let user know we're on 49 | led_set_output(true); 50 | sys_time_delay(STARTUP_LED_DURATION_MS); 51 | led_set_output(false); 52 | 53 | // mount file system 54 | FRESULT res = f_mount(&fs, "", 1); 55 | if (FR_OK == res) { 56 | shell_prints_line("f_mount succeeded!"); 57 | } 58 | else { 59 | shell_printf_line("f_mount failed, result: %d.", res); 60 | } 61 | 62 | // if filesystem mount failed due to no filesystem, attempt to make it 63 | if (FR_NO_FILESYSTEM == res) { 64 | shell_prints_line("No filesystem present. Attempting to make file system.."); 65 | uint8_t *work_buffer = mem_alloc(FF_MAX_SS); 66 | if (!work_buffer) { 67 | shell_prints_line("Unable to allocate f_mkfs work buffer. File system not created."); 68 | } 69 | else { 70 | // make the file system 71 | res = f_mkfs("", 0, work_buffer, FF_MAX_SS); 72 | if (FR_OK != res) { 73 | shell_printf_line("f_mkfs failed, result: %d.", res); // fs make failure 74 | } 75 | else { 76 | shell_prints_line("f_mkfs succeeded!"); // fs make success 77 | // retry mount 78 | res = f_mount(&fs, "", 1); 79 | if (FR_OK == res) { 80 | shell_prints_line("f_mount succeeded!"); 81 | } 82 | else { 83 | shell_printf_line("f_mount failed, result: %d.", res); 84 | } 85 | } 86 | 87 | mem_free(work_buffer); 88 | } 89 | } 90 | 91 | for (;;) { 92 | shell_tick(); 93 | } 94 | } 95 | 96 | // private function definitions 97 | static void clock_config(void) 98 | { 99 | // enable prefetch & set latency -- icache and dcache are enabled by default 100 | LL_FLASH_EnablePrefetch(); // according to the ref manual, this negates perf impact due to flash 101 | // latency 102 | LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); 103 | // enable MSI 104 | LL_RCC_MSI_Enable(); 105 | while (LL_RCC_MSI_IsReady() != 1) 106 | ; // TODO: add timeouts to these while loops 107 | 108 | // pll config & enable 109 | LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 40, LL_RCC_PLLR_DIV_2); 110 | LL_RCC_PLL_Enable(); 111 | LL_RCC_PLL_EnableDomain_SYS(); 112 | while (LL_RCC_PLL_IsReady() != 1) 113 | ; 114 | 115 | // sys clk activation 116 | LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); 117 | LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); 118 | while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) 119 | ; 120 | 121 | // setup APB1 & APB2 122 | LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); 123 | LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); 124 | 125 | // configure peripheral clock sources 126 | LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_PCLK1); 127 | 128 | // update CMSIS variable 129 | LL_SetSystemCoreClock(80000000UL); 130 | } 131 | -------------------------------------------------------------------------------- /src/dhara/nand.h: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DHARA_NAND_H_ 18 | #define DHARA_NAND_H_ 19 | 20 | #include 21 | #include 22 | #include "error.h" 23 | 24 | /* Each page in a NAND device is indexed, starting at 0. It's required 25 | * that there be a power-of-two number of pages in a eraseblock, so you can 26 | * view a page number is being a concatenation (in binary) of a block 27 | * number and the number of a page within a block. 28 | */ 29 | typedef uint32_t dhara_page_t; 30 | 31 | /* Blocks are also indexed, starting at 0. */ 32 | typedef uint32_t dhara_block_t; 33 | 34 | /* Each NAND chip must be represented by one of these structures. It's 35 | * intended that this structure be embedded in a larger structure for 36 | * context. 37 | * 38 | * The functions declared below are not implemented -- they must be 39 | * provided and satisfy the documented conditions. 40 | */ 41 | struct dhara_nand { 42 | /* Base-2 logarithm of the page size. If your device supports 43 | * partial programming, you may want to subdivide the actual 44 | * pages into separate ECC-correctable regions and present those 45 | * as pages. 46 | */ 47 | uint8_t log2_page_size; 48 | 49 | /* Base-2 logarithm of the number of pages within an eraseblock */ 50 | uint8_t log2_ppb; 51 | 52 | /* Total number of eraseblocks */ 53 | unsigned int num_blocks; 54 | }; 55 | 56 | /* Is the given block bad? */ 57 | int dhara_nand_is_bad(const struct dhara_nand *n, dhara_block_t b); 58 | 59 | /* Mark bad the given block (or attempt to). No return value is 60 | * required, because there's nothing that can be done in response. 61 | */ 62 | void dhara_nand_mark_bad(const struct dhara_nand *n, dhara_block_t b); 63 | 64 | /* Erase the given block. This function should return 0 on success or -1 65 | * on failure. 66 | * 67 | * The status reported by the chip should be checked. If an erase 68 | * operation fails, return -1 and set err to E_BAD_BLOCK. 69 | */ 70 | int dhara_nand_erase(const struct dhara_nand *n, dhara_block_t b, 71 | dhara_error_t *err); 72 | 73 | /* Program the given page. The data pointer is a pointer to an entire 74 | * page ((1 << log2_page_size) bytes). The operation status should be 75 | * checked. If the operation fails, return -1 and set err to 76 | * E_BAD_BLOCK. 77 | * 78 | * Pages will be programmed sequentially within a block, and will not be 79 | * reprogrammed. 80 | */ 81 | int dhara_nand_prog(const struct dhara_nand *n, dhara_page_t p, 82 | const uint8_t *data, 83 | dhara_error_t *err); 84 | 85 | /* Check that the given page is erased */ 86 | int dhara_nand_is_free(const struct dhara_nand *n, dhara_page_t p); 87 | 88 | /* Read a portion of a page. ECC must be handled by the NAND 89 | * implementation. Returns 0 on sucess or -1 if an error occurs. If an 90 | * uncorrectable ECC error occurs, return -1 and set err to E_ECC. 91 | */ 92 | int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, 93 | size_t offset, size_t length, 94 | uint8_t *data, 95 | dhara_error_t *err); 96 | 97 | /* Read a page from one location and reprogram it in another location. 98 | * This might be done using the chip's internal buffers, but it must use 99 | * ECC. 100 | */ 101 | int dhara_nand_copy(const struct dhara_nand *n, 102 | dhara_page_t src, dhara_page_t dst, 103 | dhara_error_t *err); 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /src/modules/nand_ftl_diskio.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nand_ftl_diskio.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the nand ftl diskio module 5 | * 6 | */ 7 | 8 | #include "nand_ftl_diskio.h" 9 | 10 | #include "../dhara/map.h" 11 | #include "../dhara/nand.h" 12 | #include "shell.h" 13 | #include "spi_nand.h" 14 | 15 | // private variables 16 | static bool initialized = false; 17 | static struct dhara_map map; 18 | static uint8_t page_buffer[SPI_NAND_PAGE_SIZE]; 19 | static struct dhara_nand nand = { 20 | .log2_page_size = SPI_NAND_LOG2_PAGE_SIZE, 21 | .log2_ppb = SPI_NAND_LOG2_PAGES_PER_BLOCK, 22 | .num_blocks = SPI_NAND_BLOCKS_PER_LUN, 23 | }; 24 | 25 | // public function definitions 26 | DSTATUS nand_ftl_diskio_initialize(void) 27 | { 28 | // init flash management stack 29 | int ret = spi_nand_init(); 30 | if (SPI_NAND_RET_OK != ret) { 31 | shell_printf_line("spi_nand_init failed, status: %d.", ret); 32 | return STA_NOINIT; 33 | } 34 | // init flash translation layer 35 | dhara_map_init(&map, &nand, page_buffer, 4); 36 | dhara_error_t err = DHARA_E_NONE; 37 | ret = dhara_map_resume(&map, &err); 38 | shell_printf_line("dhara resume return: %d, error: %d", ret, err); 39 | // map_resume will return a bad status in the case of an empty map, however this just 40 | // means that the file system is empty 41 | 42 | // TODO: Flag statuses from dhara that do not indicate an empty map 43 | initialized = true; 44 | return 0; 45 | } 46 | 47 | DSTATUS nand_ftl_diskio_status(void) 48 | { 49 | if (!initialized) { 50 | return STA_NOINIT; 51 | } 52 | else { 53 | return 0; 54 | } 55 | } 56 | 57 | DRESULT nand_ftl_diskio_read(BYTE *buff, LBA_t sector, UINT count) 58 | { 59 | dhara_error_t err; 60 | // read *count* consecutive sectors 61 | for (int i = 0; i < count; i++) { 62 | int ret = dhara_map_read(&map, sector, buff, &err); 63 | if (ret) { 64 | shell_printf_line("dhara read failed: %d, error: %d", ret, err); 65 | return RES_ERROR; 66 | } 67 | buff += SPI_NAND_PAGE_SIZE; // sector size == page size 68 | sector++; 69 | } 70 | 71 | return RES_OK; 72 | } 73 | 74 | DRESULT nand_ftl_diskio_write(const BYTE *buff, LBA_t sector, UINT count) 75 | { 76 | dhara_error_t err; 77 | // write *count* consecutive sectors 78 | for (int i = 0; i < count; i++) { 79 | int ret = dhara_map_write(&map, sector, buff, &err); 80 | if (ret) { 81 | shell_printf_line("dhara write failed: %d, error: %d", ret, err); 82 | return RES_ERROR; 83 | } 84 | buff += SPI_NAND_PAGE_SIZE; // sector size == page size 85 | sector++; 86 | } 87 | 88 | return RES_OK; 89 | } 90 | 91 | DRESULT nand_ftl_diskio_ioctl(BYTE cmd, void *buff) 92 | { 93 | dhara_error_t err; 94 | 95 | switch (cmd) { 96 | case CTRL_SYNC: { 97 | int ret = dhara_map_sync(&map, &err); 98 | if (ret) { 99 | shell_printf_line("dhara sync failed: %d, error: %d", ret, err); 100 | return RES_ERROR; 101 | } 102 | break; 103 | } 104 | case GET_SECTOR_COUNT: { 105 | dhara_sector_t sector_count = dhara_map_capacity(&map); 106 | shell_printf_line("dhara capacity: %d", sector_count); 107 | LBA_t *sector_count_out = (LBA_t *)buff; 108 | *sector_count_out = sector_count; 109 | break; 110 | } 111 | case GET_SECTOR_SIZE: { 112 | WORD *sector_size_out = (WORD *)buff; 113 | *sector_size_out = SPI_NAND_PAGE_SIZE; 114 | break; 115 | } 116 | case GET_BLOCK_SIZE: { 117 | DWORD *block_size_out = (DWORD *)buff; 118 | *block_size_out = SPI_NAND_PAGES_PER_BLOCK; 119 | break; 120 | } 121 | case CTRL_TRIM: { 122 | LBA_t *args = (LBA_t *)buff; 123 | LBA_t start = args[0]; 124 | LBA_t end = args[1]; 125 | while (start <= end) { 126 | int ret = dhara_map_trim(&map, start, &err); 127 | if (ret) { 128 | shell_printf_line("dhara trim failed: %d, error: %d", ret, err); 129 | return RES_ERROR; 130 | } 131 | start++; 132 | } 133 | break; 134 | } 135 | default: 136 | return RES_PARERR; 137 | } 138 | 139 | return RES_OK; 140 | } 141 | -------------------------------------------------------------------------------- /src/dhara/nand.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nand.c 3 | * @author Andrew Loebs 4 | * @brief "Glue" layer between dhara and spi_nand module 5 | * 6 | */ 7 | 8 | #include "nand.h" 9 | 10 | #include 11 | 12 | #include "../modules/spi_nand.h" 13 | 14 | // public function definitions 15 | int dhara_nand_is_bad(const struct dhara_nand *n, dhara_block_t b) 16 | { 17 | // construct row address 18 | row_address_t row = {.block = b, .page = 0}; 19 | // call spi_nand layer for block status 20 | bool is_bad; 21 | int ret = spi_nand_block_is_bad(row, &is_bad); 22 | if (SPI_NAND_RET_OK != ret) { 23 | // if we get a bad return, we'll just call this block bad 24 | is_bad = true; 25 | } 26 | 27 | return (int)is_bad; 28 | } 29 | 30 | void dhara_nand_mark_bad(const struct dhara_nand *n, dhara_block_t b) 31 | { 32 | // construct row address 33 | row_address_t row = {.block = b, .page = 0}; 34 | // call spi_nand layer 35 | spi_nand_block_mark_bad(row); // ignore ret 36 | } 37 | 38 | int dhara_nand_erase(const struct dhara_nand *n, dhara_block_t b, dhara_error_t *err) 39 | { 40 | // construct row address 41 | row_address_t row = {.block = b, .page = 0}; 42 | // call spi_nand layer 43 | int ret = spi_nand_block_erase(row); 44 | if (SPI_NAND_RET_OK == ret) { // success 45 | return 0; 46 | } 47 | else if (SPI_NAND_RET_E_FAIL == ret) { // failed internally on nand 48 | *err = DHARA_E_BAD_BLOCK; 49 | return -1; 50 | } 51 | else { // failed for some other reason 52 | return -1; 53 | } 54 | } 55 | 56 | int dhara_nand_prog(const struct dhara_nand *n, dhara_page_t p, const uint8_t *data, 57 | dhara_error_t *err) 58 | { 59 | // construct row address -- dhara's page address is identical to an MT29F row address 60 | row_address_t row = {.whole = p}; 61 | // call spi_nand layer 62 | int ret = spi_nand_page_program(row, 0, data, SPI_NAND_PAGE_SIZE); 63 | if (SPI_NAND_RET_OK == ret) { // success 64 | return 0; 65 | } 66 | else if (SPI_NAND_RET_P_FAIL == ret) { // failed internally on nand 67 | *err = DHARA_E_BAD_BLOCK; 68 | return -1; 69 | } 70 | else { // failed for some other reason 71 | return -1; 72 | } 73 | } 74 | 75 | int dhara_nand_is_free(const struct dhara_nand *n, dhara_page_t p) 76 | { 77 | // construct row address -- dhara's page address is identical to an MT29F row address 78 | row_address_t row = {.whole = p}; 79 | // call spi_nand layer 80 | bool is_free; 81 | int ret = spi_nand_page_is_free(row, &is_free); 82 | if (SPI_NAND_RET_OK != ret) { 83 | // if we get a bad return, we'll report the page as "not free" 84 | is_free = false; 85 | } 86 | 87 | return (int)is_free; 88 | } 89 | 90 | int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, size_t length, 91 | uint8_t *data, dhara_error_t *err) 92 | { 93 | // construct row address -- dhara's page address is identical to an MT29F row address 94 | row_address_t row = {.whole = p}; 95 | // call spi_nand layer 96 | int ret = spi_nand_page_read(row, offset, data, length); 97 | if (SPI_NAND_RET_OK == ret) { // success 98 | return 0; 99 | } 100 | else if (SPI_NAND_RET_ECC_ERR == ret) { // ECC failure 101 | *err = DHARA_E_ECC; 102 | return -1; 103 | } 104 | else { // failed for some other reason 105 | return -1; 106 | } 107 | } 108 | 109 | /* Read a page from one location and reprogram it in another location. 110 | * This might be done using the chip's internal buffers, but it must use 111 | * ECC. 112 | */ 113 | int dhara_nand_copy(const struct dhara_nand *n, dhara_page_t src, dhara_page_t dst, 114 | dhara_error_t *err) 115 | { 116 | // construct row addresses -- dhara's page address is identical to an MT29F row address 117 | row_address_t source = {.whole = src}; 118 | row_address_t dest = {.whole = dst}; 119 | // call spi_nand layer 120 | int ret = spi_nand_page_copy(source, dest); 121 | if (SPI_NAND_RET_OK == ret) { // success 122 | return 0; 123 | } 124 | else if (SPI_NAND_RET_ECC_ERR == ret) { // ECC failure on read 125 | *err = DHARA_E_ECC; 126 | return -1; 127 | } 128 | else if (SPI_NAND_RET_P_FAIL == ret) { // program failure 129 | *err = DHARA_E_BAD_BLOCK; 130 | return -1; 131 | } 132 | else { // failed for some other reason 133 | return -1; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/dhara/map.h: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DHARA_MAP_H_ 18 | #define DHARA_MAP_H_ 19 | 20 | #include "journal.h" 21 | 22 | /* The map is a journal indexing format. It maps virtual sectors to 23 | * pages of data in flash memory. 24 | */ 25 | typedef uint32_t dhara_sector_t; 26 | 27 | /* This sector value is reserved */ 28 | #define DHARA_SECTOR_NONE 0xffffffff 29 | 30 | struct dhara_map { 31 | struct dhara_journal journal; 32 | 33 | uint8_t gc_ratio; 34 | dhara_sector_t count; 35 | }; 36 | 37 | /* Initialize a map. You need to supply a buffer for page metadata, and 38 | * a garbage collection ratio. This is the ratio of garbage collection 39 | * operations to real writes when automatic collection is active. 40 | * 41 | * Smaller values lead to faster and more predictable IO, at the 42 | * expense of capacity. You should always initialize the same chip with 43 | * the same garbage collection ratio. 44 | */ 45 | void dhara_map_init(struct dhara_map *m, const struct dhara_nand *n, 46 | uint8_t *page_buf, uint8_t gc_ratio); 47 | 48 | /* Recover stored state, if possible. If there is no valid stored state 49 | * on the chip, -1 is returned, and an empty map is initialized. 50 | */ 51 | int dhara_map_resume(struct dhara_map *m, dhara_error_t *err); 52 | 53 | /* Clear the map (delete all sectors). */ 54 | void dhara_map_clear(struct dhara_map *m); 55 | 56 | /* Obtain the maximum capacity of the map. */ 57 | dhara_sector_t dhara_map_capacity(const struct dhara_map *m); 58 | 59 | /* Obtain the current number of allocated sectors. */ 60 | static inline dhara_sector_t dhara_map_size(const struct dhara_map *m) 61 | { 62 | return m->count; 63 | } 64 | 65 | /* Find the physical page which holds the current data for this sector. 66 | * Returns 0 on success or -1 if an error occurs. If the sector doesn't 67 | * exist, the error is E_NOT_FOUND. 68 | */ 69 | int dhara_map_find(struct dhara_map *m, dhara_sector_t s, 70 | dhara_page_t *loc, dhara_error_t *err); 71 | 72 | /* Read from the given logical sector. If the sector is unmapped, a 73 | * blank page (0xff) will be returned. 74 | */ 75 | int dhara_map_read(struct dhara_map *m, dhara_sector_t s, 76 | uint8_t *data, dhara_error_t *err); 77 | 78 | /* Write data to a logical sector. */ 79 | int dhara_map_write(struct dhara_map *m, dhara_sector_t s, 80 | const uint8_t *data, dhara_error_t *err); 81 | 82 | /* Copy any flash page to a logical sector. */ 83 | int dhara_map_copy_page(struct dhara_map *m, dhara_page_t src, 84 | dhara_sector_t dst, dhara_error_t *err); 85 | 86 | /* Copy one sector to another. If the source sector is unmapped, the 87 | * destination sector will be trimmed. 88 | */ 89 | int dhara_map_copy_sector(struct dhara_map *m, dhara_sector_t src, 90 | dhara_sector_t dst, dhara_error_t *err); 91 | 92 | /* Delete a logical sector. You don't necessarily need to do this, but 93 | * it's a useful hint if you no longer require the sector's data to be 94 | * kept. 95 | * 96 | * If order is non-zero, it specifies that all sectors in the 97 | * (2**order)-aligned group of s are to be deleted. 98 | */ 99 | int dhara_map_trim(struct dhara_map *m, dhara_sector_t s, 100 | dhara_error_t *err); 101 | 102 | /* Synchronize the map. Once this returns successfully, all changes to 103 | * date are persistent and durable. Conversely, there is no guarantee 104 | * that unsynchronized changes will be persistent. 105 | */ 106 | int dhara_map_sync(struct dhara_map *m, dhara_error_t *err); 107 | 108 | /* Perform one garbage collection step. You can do this whenever you 109 | * like, but it's not necessary -- garbage collection happens 110 | * automatically and is interleaved with other operations. 111 | */ 112 | int dhara_map_gc(struct dhara_map *m, dhara_error_t *err); 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/modules/uart.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file uart.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the UART module 5 | * 6 | */ 7 | 8 | #include "uart.h" 9 | 10 | #include 11 | #include 12 | 13 | #include "../st/ll/stm32l4xx_ll_bus.h" 14 | #include "../st/ll/stm32l4xx_ll_gpio.h" 15 | #include "../st/ll/stm32l4xx_ll_rcc.h" 16 | #include "../st/ll/stm32l4xx_ll_usart.h" 17 | #include "../st/stm32l4xx.h" 18 | 19 | #include "fifo.h" 20 | #include "sys_time.h" 21 | 22 | // defines 23 | #define VCP_TX_PORT GPIOA 24 | #define VCP_TX_PIN LL_GPIO_PIN_2 25 | #define VCP_RX_PORT GPIOA 26 | #define VCP_RX_PIN LL_GPIO_PIN_15 27 | 28 | #define VCP_UART USART2 29 | 30 | #define BAUD_RATE 115200 31 | #define PUTC_TIMEOUT 10 // ms 32 | 33 | #define UART_PREEMPT_PRIORITY 7 // low 34 | #define UART_SUB_PRIORITY 0 35 | 36 | #define RX_BUFF_LEN 256 37 | 38 | // private function prototypes 39 | static uint32_t get_pclk1_hz(void); 40 | 41 | // private variables 42 | static uint8_t rx_fifo_memblock[RX_BUFF_LEN]; 43 | static fifo_t rx_fifo = FIFO_STATIC_INIT(rx_fifo_memblock, sizeof(rx_fifo_memblock)); 44 | 45 | // public function definitions 46 | void uart_init(void) 47 | { 48 | // enable peripheral clocks 49 | LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2); 50 | if (!LL_AHB2_GRP1_IsEnabledClock(LL_AHB2_GRP1_PERIPH_GPIOA)) 51 | LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); 52 | 53 | // setup pins 54 | LL_GPIO_SetPinMode(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_MODE_ALTERNATE); 55 | LL_GPIO_SetPinOutputType(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL); 56 | LL_GPIO_SetPinSpeed(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); 57 | LL_GPIO_SetPinPull(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_PULL_NO); 58 | LL_GPIO_SetAFPin_0_7(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_AF_7); 59 | 60 | LL_GPIO_SetPinMode(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_MODE_ALTERNATE); 61 | LL_GPIO_SetPinOutputType(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL); 62 | LL_GPIO_SetPinSpeed(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); 63 | LL_GPIO_SetPinPull(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_PULL_NO); 64 | LL_GPIO_SetAFPin_8_15(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_AF_3); 65 | 66 | // configure UART CR1 67 | LL_USART_SetDataWidth(VCP_UART, LL_USART_DATAWIDTH_8B); 68 | LL_USART_SetParity(VCP_UART, LL_USART_PARITY_NONE); 69 | LL_USART_EnableDirectionTx(VCP_UART); 70 | LL_USART_EnableDirectionRx(VCP_UART); 71 | LL_USART_SetOverSampling(VCP_UART, LL_USART_OVERSAMPLING_16); 72 | 73 | // configure UART CR2 74 | LL_USART_SetStopBitsLength(VCP_UART, LL_USART_STOPBITS_1); 75 | 76 | // configure UART CR3 77 | LL_USART_DisableOneBitSamp(VCP_UART); 78 | LL_USART_SetHWFlowCtrl(VCP_UART, LL_USART_HWCONTROL_NONE); 79 | 80 | // config UART BRR 81 | LL_USART_SetBaudRate(VCP_UART, get_pclk1_hz(), LL_USART_OVERSAMPLING_16, BAUD_RATE); 82 | 83 | // enable UART interrupt for rx 84 | LL_USART_EnableIT_RXNE(VCP_UART); 85 | NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 86 | UART_PREEMPT_PRIORITY, UART_SUB_PRIORITY)); 87 | NVIC_EnableIRQ(USART2_IRQn); 88 | 89 | // enable UART 90 | LL_USART_Enable(VCP_UART); 91 | } 92 | 93 | void _uart_putc(char c) 94 | { 95 | // Blocking single-byte transmit with timeout 96 | uint32_t start = sys_time_get_ms(); 97 | LL_USART_TransmitData8(VCP_UART, c); 98 | // wait for completion 99 | while (!LL_USART_IsActiveFlag_TC(VCP_UART) && !sys_time_is_elapsed(start, PUTC_TIMEOUT)) 100 | ; 101 | } 102 | 103 | bool _uart_try_getc(char *c) { return fifo_try_dequeue(&rx_fifo, c); } 104 | 105 | void _uart_isr(void) 106 | { 107 | // if there is an overrun flag, clear it 108 | if (LL_USART_IsActiveFlag_ORE(VCP_UART)) { 109 | LL_USART_ClearFlag_ORE(VCP_UART); 110 | } 111 | // if there is an rxn flag, read byte 112 | if (LL_USART_IsActiveFlag_RXNE(VCP_UART)) { 113 | // TODO: grab the return value from this and log a "uart fifo full" 114 | // status somewhere if false 115 | fifo_enqueue(&rx_fifo, LL_USART_ReceiveData8(VCP_UART)); 116 | } 117 | } 118 | 119 | // private function definitions 120 | static uint32_t get_pclk1_hz(void) 121 | { 122 | uint32_t pclk1 = SystemCoreClock; 123 | switch (LL_RCC_GetAPB1Prescaler()) { 124 | case LL_RCC_APB1_DIV_1: 125 | // do nothing 126 | break; 127 | case LL_RCC_APB1_DIV_2: 128 | pclk1 /= 2; 129 | break; 130 | case LL_RCC_APB1_DIV_4: 131 | pclk1 /= 4; 132 | break; 133 | case LL_RCC_APB1_DIV_8: 134 | pclk1 /= 8; 135 | break; 136 | case LL_RCC_APB1_DIV_16: 137 | pclk1 /= 16; 138 | break; 139 | default: 140 | break; 141 | } 142 | 143 | return pclk1; 144 | } 145 | -------------------------------------------------------------------------------- /src/modules/shell.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shell.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the shell module 5 | * 6 | */ 7 | 8 | #include "shell.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "shell_cmd.h" 15 | 16 | // defines 17 | #define RECEIVE_BUFFER_LEN 128 // max command + args length supported 18 | 19 | // private function prototypes 20 | static void receive_buffer_reset(void); 21 | static bool receive_buffer_is_full(void); 22 | static size_t receive_buffer_len(void); 23 | static void receive_buffer_push(char c); 24 | 25 | static bool try_get_char(char *out); 26 | static void echo(char c); 27 | static void put_prompt(void); 28 | 29 | // private variables 30 | static char receive_buffer[RECEIVE_BUFFER_LEN]; 31 | static size_t receive_index; 32 | 33 | // public function definitions 34 | void shell_init(void) 35 | { 36 | receive_buffer_reset(); 37 | // start with welcome message and prompt 38 | shell_put_newline(); 39 | shell_put_newline(); 40 | shell_prints_line("==== shell started! ===="); 41 | shell_put_newline(); 42 | put_prompt(); 43 | } 44 | 45 | void shell_tick(void) 46 | { 47 | char c; 48 | if (try_get_char(&c)) { 49 | // ignore newline -- we only expect carriage return from the client 50 | if (c != '\n') { 51 | echo(c); 52 | receive_buffer_push(c); 53 | // if carriage return, process command 54 | if ('\r' == c) { 55 | shell_cmd_process(receive_buffer, receive_buffer_len()); 56 | shell_put_newline(); // more readable with the extra newline 57 | put_prompt(); 58 | receive_buffer_reset(); 59 | } 60 | // else, check for rx full 61 | else if (receive_buffer_is_full()) { 62 | shell_printf_line("Receive buffer full (limit %d). Resetting receive buffer.", 63 | RECEIVE_BUFFER_LEN); 64 | receive_buffer_reset(); 65 | } 66 | } 67 | } 68 | } 69 | 70 | void shell_print(const char *buff, size_t len) 71 | { 72 | for (int i = 0; i < len; i++) { 73 | putchar(buff[i]); 74 | } 75 | } 76 | 77 | void shell_prints(const char *string) 78 | { 79 | while (*string) { 80 | putchar(*string); 81 | string++; 82 | } 83 | } 84 | 85 | void shell_prints_line(const char *string) 86 | { 87 | // this gives us control over the newline behavior (over puts()) 88 | while (*string) { 89 | putchar(*string); 90 | string++; 91 | } 92 | shell_put_newline(); 93 | } 94 | 95 | void shell_printf(const char *format, ...) 96 | { 97 | va_list args; 98 | va_start(args, format); 99 | vprintf(format, args); 100 | va_end(args); 101 | } 102 | 103 | void shell_printf_line(const char *format, ...) 104 | { 105 | // handle the printf 106 | va_list args; 107 | va_start(args, format); 108 | vprintf(format, args); 109 | va_end(args); 110 | // newline 111 | shell_put_newline(); 112 | } 113 | 114 | void shell_put_newline(void) 115 | { 116 | putchar('\r'); 117 | putchar('\n'); 118 | } 119 | 120 | // private function definitions 121 | static void receive_buffer_reset(void) 122 | { 123 | receive_buffer[0] = 0; 124 | receive_index = 0; 125 | } 126 | 127 | static bool receive_buffer_is_full(void) 128 | { 129 | return receive_index >= (RECEIVE_BUFFER_LEN - 1); 130 | } 131 | 132 | static size_t receive_buffer_len(void) 133 | { 134 | return receive_index; 135 | } 136 | 137 | static void receive_buffer_push(char c) 138 | { 139 | if ('\b' == c) { 140 | if (receive_index != 0) { 141 | receive_index--; 142 | receive_buffer[receive_index] = 0; 143 | } 144 | } 145 | else { 146 | receive_buffer[receive_index] = c; 147 | receive_index++; 148 | } 149 | } 150 | 151 | static bool try_get_char(char *out) 152 | { 153 | // To get around getchar() blocking, the _read() syscall returns 154 | // EOF for stdin whenever the UART rx is empty. Because of this, 155 | // we must check getchar() for EOF so that we know if we have a new 156 | // character, and rewind stdin when we do not. 157 | char c = getchar(); 158 | if ((char)EOF == c) { 159 | rewind(stdin); 160 | return false; 161 | } 162 | else { 163 | *out = c; 164 | return true; 165 | } 166 | } 167 | 168 | static void echo(char c) 169 | { 170 | // handle newline 171 | if ('\r' == c) { 172 | shell_put_newline(); 173 | } 174 | // handle backspace 175 | else if ('\b' == c) { 176 | if (receive_index != 0) { // dont backspace prompt 177 | putchar('\b'); 178 | putchar(' '); 179 | putchar('\b'); 180 | } 181 | } 182 | // else, just echo 183 | else { 184 | putchar(c); 185 | } 186 | } 187 | 188 | static void put_prompt(void) 189 | { 190 | putchar('>'); 191 | putchar(' '); 192 | } 193 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flash_management 2 | Flash management stack consisting of a flash translation layer ([dhara](https://github.com/dlbeer/dhara)) and an SPI NAND driver. Uses an STM32L432KCUX MCU connected to a Micron MT29F1G01ABAFDWB SPI NAND SLC flash chip. 3 | 4 | This project is intended to be the "minimum implementation" needed to tie a FAT filesystem, flash translation layer, and low-level flash driver together. Most areas of the source code are heavily commented (probably over commented) in an effort to make it easy as possible for people unfamiliar with ONFI & flash translation concepts to follow. 5 | 6 | > [!TIP] 7 | > This implementation was written for a single-plane flash part. If you're trying to adapt this repo to work on with a multi-plane flash part, you will need to change the implementation of the `spi_nand_copy` function (as the implementation here only works for copying within a plane). See [this issue](https://github.com/aloebs29/flash_management/issues/2#issuecomment-1890906616) for a discussion + fork of this repo that was made to work with a multi-planar storage device. 8 | 9 | ## project structure 10 | ``` 11 | src 12 | ├── cmsis 13 | │ └── (...) 14 | ├── dhara 15 | │ └── (...) 16 | ├── fatfs 17 | │ └── (...) 18 | ├── modules 19 | │ ├── fifo.h 20 | │ ├── led.h/c 21 | │ ├── mem.h/c 22 | │ ├── nand_ftl_diskio.h/c 23 | │ ├── shell.h/c 24 | │ ├── shell_cmd.h/c 25 | │ ├── spi.h/c 26 | │ ├── spi_nand.h/c 27 | │ ├── sys_time.h/c 28 | │ └── uart.h/c 29 | ├── st 30 | │ └── (...) 31 | ├── main.c 32 | ├── startup_stm32l432kc.c 33 | ├── stm32l432kc.ld 34 | ├── stm32l432kc_it.c 35 | └── syscalls.c 36 | ``` 37 | - **cmsis/** - Cortex Microcontroller Software Interface Standard files. 38 | - **dhara/** - Dhara NAND flash translation layer ([see here](https://github.com/dlbeer/dhara)). 39 | - **fatfs/** - ChaN FAT file system library ([see here](http://elm-chan.org/fsw/ff/00index_e.html)). 40 | - **modules/** 41 | - **fifo.h** - Barebones header-only FIFO implementation (for raw bytes). 42 | - **led.h/c** - Barebones LED driver; used on startup to notify the user that code is running. 43 | - **mem.h/c** - Dumb memory allocator for gaining access to a single buffer thats the length of an SPI NAND page (to avoid putting this buffer on the stack or duplicating in static definitions - where possible). This is written as a generic "mem" module so that it could be expanded into a real heap allocator without updates to the calling code. 44 | - **nand_ftl_diskio.h/c** - Implements the disk IO functions used by the FAT file system. Disk IO is a nice abstraction as USB MSC read/write & get size functions can call directly into this layer (be careful with mutual exclusion between FATFS and USB MSC if both are implemented in your project). 45 | - **shell.h/c** - Barebones shell functionality for interacting with the device over a serial connection such as USB CDC or UART (only UART is implemented in this project). 46 | - **shell_cmd.h/c** - Defines the shell commands used in the project. 47 | - **spi.h/c** - Barebones synchronous SPI driver. 48 | - **spi_nand.h/c** - Low-level SPI NAND driver. This is written specifically to support the MT29F for simplicity (rather than having a generic core driver + chip specific drivers). 49 | - **sys_time.h/c** - Uses the sys tick to generate a 1ms time base; exposes convenience functions such as get time, delay, is elapsed, etc. 50 | - **uart.h/c** - Barebones synchronous UART driver. 51 | - **st/** - ST low-level driver files (only files used by the project are present). 52 | - **main.c** - Main application. 53 | - **startup_stm32l432kc.c** - Defines weak exception handlers, calls CMSIS & libc init functions, initializes bss and data sections, calls main application. 54 | - **stm32l432kc.ld** - Linker script -- differs from ST's default linker script in that the stack is placed at bottom of RAM so that stack overflows cause an exception rather than silently overwriting data (thanks uncle Miro). 55 | - **stm32l432kc_it.c** - All overrides for exception handlers. All faults just turn on the LED (if able). 56 | - **syscalls.c** - Lib c sys calls. 57 | 58 | ## usage 59 | All interaction is handled through the shell (currently) which uses a UART backend. If you're using a nucleo board you can simply plug in to USB and use the virtual com port. 60 | ### shell commands 61 | #### utility 62 | - help 63 | #### raw flash interaction 64 | - read_page 65 | - write_page 66 | - erase_block 67 | - get_bbt 68 | - mark_bb 69 | - page_is_free 70 | - copy_page 71 | - erase_all 72 | #### file system interaction 73 | - write_file 74 | - read_file 75 | - list_dir 76 | - file_size 77 | 78 | ## future improvements 79 | - More shell commands for interacting with the FAT filesystem, especially format. This is needed to recover from FS errors that may occur when using raw flash commands from the shell. 80 | - Add USB MSC. I'd really like to avoid using ST's HAL, so the easiest pathway here is probably porting [TinyUSB](https://github.com/hathach/tinyusb) to the STM32L4 (F4 is already supported). 81 | - Example datalogging application. 82 | 83 | ## acknowledgements 84 | - https://github.com/dlbeer/dhara - Dhara NAND flash translation layer. 85 | - http://elm-chan.org/fsw/ff/00index_e.html - ChaN FAT file system library. 86 | - https://www.state-machine.com/quickstart/ - Miro Samek's "Modern Embedded Systems Programming Course". Great course for beginners, but also a great reference for writing your own linker and startup files. 87 | - https://interrupt.memfault.com/blog/tag/zero-to-main - A series of blog posts detailing how to bootstrap C applications on cortex-m MCU's. 88 | -------------------------------------------------------------------------------- /src/modules/spi.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file spi.c 3 | * @author Andrew Loebs 4 | * @brief Implementation file of the spi module 5 | * 6 | */ 7 | 8 | #include "spi.h" 9 | 10 | #include "../st/ll/stm32l4xx_ll_bus.h" 11 | #include "../st/ll/stm32l4xx_ll_gpio.h" 12 | #include "../st/ll/stm32l4xx_ll_spi.h" 13 | 14 | #include "sys_time.h" 15 | 16 | // defines 17 | #define SPI_INSTANCE SPI1 18 | 19 | #define MOSI_PORT GPIOA 20 | #define MOSI_PIN LL_GPIO_PIN_7 21 | #define MOSI_AF LL_GPIO_AF_5 22 | 23 | #define MISO_PORT GPIOA 24 | #define MISO_PIN LL_GPIO_PIN_6 25 | #define MISO_AF LL_GPIO_AF_5 26 | 27 | #define SCK_PORT GPIOA 28 | #define SCK_PIN LL_GPIO_PIN_1 29 | #define SCK_AF LL_GPIO_AF_5 30 | 31 | // public function definitions 32 | void spi_init(void) 33 | { 34 | // enable peripheral clocks 35 | LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); 36 | if (!LL_AHB2_GRP1_IsEnabledClock(LL_AHB2_GRP1_PERIPH_GPIOA)) 37 | LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); 38 | 39 | // configure pins 40 | LL_GPIO_SetPinMode(MOSI_PORT, MOSI_PIN, LL_GPIO_MODE_ALTERNATE); 41 | LL_GPIO_SetAFPin_0_7(MOSI_PORT, MOSI_PIN, MOSI_AF); 42 | LL_GPIO_SetPinSpeed(MOSI_PORT, MOSI_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); 43 | LL_GPIO_SetPinPull(MOSI_PORT, MOSI_PIN, LL_GPIO_PULL_DOWN); 44 | 45 | LL_GPIO_SetPinMode(MISO_PORT, MISO_PIN, LL_GPIO_MODE_ALTERNATE); 46 | LL_GPIO_SetAFPin_0_7(MISO_PORT, MISO_PIN, MISO_AF); 47 | LL_GPIO_SetPinSpeed(MISO_PORT, MISO_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); 48 | LL_GPIO_SetPinPull(MISO_PORT, MISO_PIN, LL_GPIO_PULL_DOWN); 49 | 50 | LL_GPIO_SetPinMode(SCK_PORT, SCK_PIN, LL_GPIO_MODE_ALTERNATE); 51 | LL_GPIO_SetAFPin_0_7(SCK_PORT, SCK_PIN, SCK_AF); 52 | LL_GPIO_SetPinSpeed(SCK_PORT, SCK_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); 53 | LL_GPIO_SetPinPull(SCK_PORT, SCK_PIN, LL_GPIO_PULL_DOWN); 54 | 55 | // configure SPI module 56 | LL_SPI_SetBaudRatePrescaler(SPI_INSTANCE, LL_SPI_BAUDRATEPRESCALER_DIV2); 57 | LL_SPI_SetTransferDirection(SPI_INSTANCE, LL_SPI_FULL_DUPLEX); 58 | LL_SPI_SetClockPolarity(SPI_INSTANCE, LL_SPI_POLARITY_LOW); 59 | LL_SPI_SetClockPhase(SPI_INSTANCE, LL_SPI_PHASE_1EDGE); 60 | 61 | LL_SPI_SetDataWidth(SPI_INSTANCE, LL_SPI_DATAWIDTH_8BIT); 62 | LL_SPI_SetNSSMode(SPI_INSTANCE, LL_SPI_NSS_SOFT); 63 | LL_SPI_SetRxFIFOThreshold(SPI_INSTANCE, LL_SPI_RX_FIFO_TH_QUARTER); 64 | 65 | LL_SPI_SetMode(SPI_INSTANCE, LL_SPI_MODE_MASTER); 66 | LL_SPI_Enable(SPI_INSTANCE); 67 | } 68 | 69 | int spi_write(const uint8_t *write_buff, size_t write_len, uint32_t timeout_ms) 70 | { 71 | // validate input 72 | if (!write_buff) return SPI_RET_NULL_PTR; 73 | 74 | // perform transfer 75 | uint32_t start_time = sys_time_get_ms(); 76 | for (int i = 0; i < write_len; i++) { 77 | // block until tx empty or timeout 78 | while (!LL_SPI_IsActiveFlag_TXE(SPI_INSTANCE)) { 79 | if (sys_time_is_elapsed(start_time, timeout_ms)) { 80 | return SPI_RET_TIMEOUT; 81 | } 82 | } 83 | // transmit data 84 | LL_SPI_TransmitData8(SPI_INSTANCE, write_buff[i]); 85 | // block until rx not empty 86 | while (!LL_SPI_IsActiveFlag_RXNE(SPI_INSTANCE)) { 87 | if (sys_time_is_elapsed(start_time, timeout_ms)) { 88 | return SPI_RET_TIMEOUT; 89 | } 90 | } 91 | // read data to clear buffer 92 | LL_SPI_ReceiveData8(SPI_INSTANCE); 93 | } 94 | 95 | return SPI_RET_OK; 96 | } 97 | 98 | int spi_read(uint8_t *read_buff, size_t read_len, uint32_t timeout_ms) 99 | { 100 | // validate input 101 | if (!read_buff) return SPI_RET_NULL_PTR; 102 | 103 | // perform transfer 104 | uint32_t start_time = sys_time_get_ms(); 105 | for (int i = 0; i < read_len; i++) { 106 | // block until tx empty or timeout 107 | while (!LL_SPI_IsActiveFlag_TXE(SPI_INSTANCE)) { 108 | if (sys_time_is_elapsed(start_time, timeout_ms)) { 109 | return SPI_RET_TIMEOUT; 110 | } 111 | } 112 | // transmit data 113 | LL_SPI_TransmitData8(SPI_INSTANCE, 0); 114 | // block until rx not empty 115 | while (!LL_SPI_IsActiveFlag_RXNE(SPI_INSTANCE)) { 116 | if (sys_time_is_elapsed(start_time, timeout_ms)) { 117 | return SPI_RET_TIMEOUT; 118 | } 119 | } 120 | // read data from buffer 121 | read_buff[i] = LL_SPI_ReceiveData8(SPI_INSTANCE); 122 | } 123 | 124 | return SPI_RET_OK; 125 | } 126 | 127 | int spi_write_read(const uint8_t *write_buff, uint8_t *read_buff, size_t transfer_len, 128 | uint32_t timeout_ms) 129 | { 130 | // validate input 131 | if (!read_buff) return SPI_RET_NULL_PTR; 132 | 133 | // perform transfer 134 | uint32_t start_time = sys_time_get_ms(); 135 | for (int i = 0; i < transfer_len; i++) { 136 | // block until tx empty or timeout 137 | while (!LL_SPI_IsActiveFlag_TXE(SPI_INSTANCE)) { 138 | if (sys_time_is_elapsed(start_time, timeout_ms)) { 139 | return SPI_RET_TIMEOUT; 140 | } 141 | } 142 | // transmit data 143 | LL_SPI_TransmitData8(SPI_INSTANCE, write_buff[i]); 144 | // block until rx not empty 145 | while (!LL_SPI_IsActiveFlag_RXNE(SPI_INSTANCE)) { 146 | if (sys_time_is_elapsed(start_time, timeout_ms)) { 147 | return SPI_RET_TIMEOUT; 148 | } 149 | } 150 | // read data from buffer 151 | read_buff[i] = LL_SPI_ReceiveData8(SPI_INSTANCE); 152 | } 153 | 154 | return SPI_RET_OK; 155 | } 156 | -------------------------------------------------------------------------------- /src/fatfs/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2018 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | 9 | 10 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 11 | 12 | /*------------------------------------------------------------------------*/ 13 | /* Allocate a memory block */ 14 | /*------------------------------------------------------------------------*/ 15 | 16 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ 17 | UINT msize /* Number of bytes to allocate */ 18 | ) 19 | { 20 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 21 | } 22 | 23 | 24 | /*------------------------------------------------------------------------*/ 25 | /* Free a memory block */ 26 | /*------------------------------------------------------------------------*/ 27 | 28 | void ff_memfree ( 29 | void* mblock /* Pointer to the memory block to free (nothing to do if null) */ 30 | ) 31 | { 32 | free(mblock); /* Free the memory block with POSIX API */ 33 | } 34 | 35 | #endif 36 | 37 | 38 | 39 | #if FF_FS_REENTRANT /* Mutal exclusion */ 40 | 41 | /*------------------------------------------------------------------------*/ 42 | /* Create a Synchronization Object */ 43 | /*------------------------------------------------------------------------*/ 44 | /* This function is called in f_mount() function to create a new 45 | / synchronization object for the volume, such as semaphore and mutex. 46 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 47 | */ 48 | 49 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ 50 | 51 | 52 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 53 | BYTE vol, /* Corresponding volume (logical drive number) */ 54 | FF_SYNC_t* sobj /* Pointer to return the created sync object */ 55 | ) 56 | { 57 | /* Win32 */ 58 | *sobj = CreateMutex(NULL, FALSE, NULL); 59 | return (int)(*sobj != INVALID_HANDLE_VALUE); 60 | 61 | /* uITRON */ 62 | // T_CSEM csem = {TA_TPRI,1,1}; 63 | // *sobj = acre_sem(&csem); 64 | // return (int)(*sobj > 0); 65 | 66 | /* uC/OS-II */ 67 | // OS_ERR err; 68 | // *sobj = OSMutexCreate(0, &err); 69 | // return (int)(err == OS_NO_ERR); 70 | 71 | /* FreeRTOS */ 72 | // *sobj = xSemaphoreCreateMutex(); 73 | // return (int)(*sobj != NULL); 74 | 75 | /* CMSIS-RTOS */ 76 | // *sobj = osMutexCreate(&Mutex[vol]); 77 | // return (int)(*sobj != NULL); 78 | } 79 | 80 | 81 | /*------------------------------------------------------------------------*/ 82 | /* Delete a Synchronization Object */ 83 | /*------------------------------------------------------------------------*/ 84 | /* This function is called in f_mount() function to delete a synchronization 85 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 86 | / the f_mount() function fails with FR_INT_ERR. 87 | */ 88 | 89 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 90 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 91 | ) 92 | { 93 | /* Win32 */ 94 | return (int)CloseHandle(sobj); 95 | 96 | /* uITRON */ 97 | // return (int)(del_sem(sobj) == E_OK); 98 | 99 | /* uC/OS-II */ 100 | // OS_ERR err; 101 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 102 | // return (int)(err == OS_NO_ERR); 103 | 104 | /* FreeRTOS */ 105 | // vSemaphoreDelete(sobj); 106 | // return 1; 107 | 108 | /* CMSIS-RTOS */ 109 | // return (int)(osMutexDelete(sobj) == osOK); 110 | } 111 | 112 | 113 | /*------------------------------------------------------------------------*/ 114 | /* Request Grant to Access the Volume */ 115 | /*------------------------------------------------------------------------*/ 116 | /* This function is called on entering file functions to lock the volume. 117 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 118 | */ 119 | 120 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 121 | FF_SYNC_t sobj /* Sync object to wait */ 122 | ) 123 | { 124 | /* Win32 */ 125 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 126 | 127 | /* uITRON */ 128 | // return (int)(wai_sem(sobj) == E_OK); 129 | 130 | /* uC/OS-II */ 131 | // OS_ERR err; 132 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 133 | // return (int)(err == OS_NO_ERR); 134 | 135 | /* FreeRTOS */ 136 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 137 | 138 | /* CMSIS-RTOS */ 139 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 140 | } 141 | 142 | 143 | /*------------------------------------------------------------------------*/ 144 | /* Release Grant to Access the Volume */ 145 | /*------------------------------------------------------------------------*/ 146 | /* This function is called on leaving file functions to unlock the volume. 147 | */ 148 | 149 | void ff_rel_grant ( 150 | FF_SYNC_t sobj /* Sync object to be signaled */ 151 | ) 152 | { 153 | /* Win32 */ 154 | ReleaseMutex(sobj); 155 | 156 | /* uITRON */ 157 | // sig_sem(sobj); 158 | 159 | /* uC/OS-II */ 160 | // OSMutexPost(sobj); 161 | 162 | /* FreeRTOS */ 163 | // xSemaphoreGive(sobj); 164 | 165 | /* CMSIS-RTOS */ 166 | // osMutexRelease(sobj); 167 | } 168 | 169 | #endif 170 | 171 | -------------------------------------------------------------------------------- /src/cmsis/cmsis_compiler.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file cmsis_compiler.h 3 | * @brief CMSIS compiler generic header file 4 | * @version V5.0.4 5 | * @date 10. January 2018 6 | ******************************************************************************/ 7 | /* 8 | * Copyright (c) 2009-2018 Arm Limited. All rights reserved. 9 | * 10 | * SPDX-License-Identifier: Apache-2.0 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the License); you may 13 | * not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 20 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #ifndef __CMSIS_COMPILER_H 26 | #define __CMSIS_COMPILER_H 27 | 28 | #include 29 | 30 | /* 31 | * Arm Compiler 4/5 32 | */ 33 | #if defined ( __CC_ARM ) 34 | #include "cmsis_armcc.h" 35 | 36 | 37 | /* 38 | * Arm Compiler 6 (armclang) 39 | */ 40 | #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 41 | #include "cmsis_armclang.h" 42 | 43 | 44 | /* 45 | * GNU Compiler 46 | */ 47 | #elif defined ( __GNUC__ ) 48 | #include "cmsis_gcc.h" 49 | 50 | 51 | /* 52 | * IAR Compiler 53 | */ 54 | #elif defined ( __ICCARM__ ) 55 | #include 56 | 57 | 58 | /* 59 | * TI Arm Compiler 60 | */ 61 | #elif defined ( __TI_ARM__ ) 62 | #include 63 | 64 | #ifndef __ASM 65 | #define __ASM __asm 66 | #endif 67 | #ifndef __INLINE 68 | #define __INLINE inline 69 | #endif 70 | #ifndef __STATIC_INLINE 71 | #define __STATIC_INLINE static inline 72 | #endif 73 | #ifndef __STATIC_FORCEINLINE 74 | #define __STATIC_FORCEINLINE __STATIC_INLINE 75 | #endif 76 | #ifndef __NO_RETURN 77 | #define __NO_RETURN __attribute__((noreturn)) 78 | #endif 79 | #ifndef __USED 80 | #define __USED __attribute__((used)) 81 | #endif 82 | #ifndef __WEAK 83 | #define __WEAK __attribute__((weak)) 84 | #endif 85 | #ifndef __PACKED 86 | #define __PACKED __attribute__((packed)) 87 | #endif 88 | #ifndef __PACKED_STRUCT 89 | #define __PACKED_STRUCT struct __attribute__((packed)) 90 | #endif 91 | #ifndef __PACKED_UNION 92 | #define __PACKED_UNION union __attribute__((packed)) 93 | #endif 94 | #ifndef __UNALIGNED_UINT32 /* deprecated */ 95 | struct __attribute__((packed)) T_UINT32 { uint32_t v; }; 96 | #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) 97 | #endif 98 | #ifndef __UNALIGNED_UINT16_WRITE 99 | __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; 100 | #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) 101 | #endif 102 | #ifndef __UNALIGNED_UINT16_READ 103 | __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; 104 | #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) 105 | #endif 106 | #ifndef __UNALIGNED_UINT32_WRITE 107 | __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; 108 | #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) 109 | #endif 110 | #ifndef __UNALIGNED_UINT32_READ 111 | __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; 112 | #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) 113 | #endif 114 | #ifndef __ALIGNED 115 | #define __ALIGNED(x) __attribute__((aligned(x))) 116 | #endif 117 | #ifndef __RESTRICT 118 | #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. 119 | #define __RESTRICT 120 | #endif 121 | 122 | 123 | /* 124 | * TASKING Compiler 125 | */ 126 | #elif defined ( __TASKING__ ) 127 | /* 128 | * The CMSIS functions have been implemented as intrinsics in the compiler. 129 | * Please use "carm -?i" to get an up to date list of all intrinsics, 130 | * Including the CMSIS ones. 131 | */ 132 | 133 | #ifndef __ASM 134 | #define __ASM __asm 135 | #endif 136 | #ifndef __INLINE 137 | #define __INLINE inline 138 | #endif 139 | #ifndef __STATIC_INLINE 140 | #define __STATIC_INLINE static inline 141 | #endif 142 | #ifndef __STATIC_FORCEINLINE 143 | #define __STATIC_FORCEINLINE __STATIC_INLINE 144 | #endif 145 | #ifndef __NO_RETURN 146 | #define __NO_RETURN __attribute__((noreturn)) 147 | #endif 148 | #ifndef __USED 149 | #define __USED __attribute__((used)) 150 | #endif 151 | #ifndef __WEAK 152 | #define __WEAK __attribute__((weak)) 153 | #endif 154 | #ifndef __PACKED 155 | #define __PACKED __packed__ 156 | #endif 157 | #ifndef __PACKED_STRUCT 158 | #define __PACKED_STRUCT struct __packed__ 159 | #endif 160 | #ifndef __PACKED_UNION 161 | #define __PACKED_UNION union __packed__ 162 | #endif 163 | #ifndef __UNALIGNED_UINT32 /* deprecated */ 164 | struct __packed__ T_UINT32 { uint32_t v; }; 165 | #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) 166 | #endif 167 | #ifndef __UNALIGNED_UINT16_WRITE 168 | __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; 169 | #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) 170 | #endif 171 | #ifndef __UNALIGNED_UINT16_READ 172 | __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; 173 | #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) 174 | #endif 175 | #ifndef __UNALIGNED_UINT32_WRITE 176 | __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; 177 | #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) 178 | #endif 179 | #ifndef __UNALIGNED_UINT32_READ 180 | __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; 181 | #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) 182 | #endif 183 | #ifndef __ALIGNED 184 | #define __ALIGNED(x) __align(x) 185 | #endif 186 | #ifndef __RESTRICT 187 | #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. 188 | #define __RESTRICT 189 | #endif 190 | 191 | 192 | /* 193 | * COSMIC Compiler 194 | */ 195 | #elif defined ( __CSMC__ ) 196 | #include 197 | 198 | #ifndef __ASM 199 | #define __ASM _asm 200 | #endif 201 | #ifndef __INLINE 202 | #define __INLINE inline 203 | #endif 204 | #ifndef __STATIC_INLINE 205 | #define __STATIC_INLINE static inline 206 | #endif 207 | #ifndef __STATIC_FORCEINLINE 208 | #define __STATIC_FORCEINLINE __STATIC_INLINE 209 | #endif 210 | #ifndef __NO_RETURN 211 | // NO RETURN is automatically detected hence no warning here 212 | #define __NO_RETURN 213 | #endif 214 | #ifndef __USED 215 | #warning No compiler specific solution for __USED. __USED is ignored. 216 | #define __USED 217 | #endif 218 | #ifndef __WEAK 219 | #define __WEAK __weak 220 | #endif 221 | #ifndef __PACKED 222 | #define __PACKED @packed 223 | #endif 224 | #ifndef __PACKED_STRUCT 225 | #define __PACKED_STRUCT @packed struct 226 | #endif 227 | #ifndef __PACKED_UNION 228 | #define __PACKED_UNION @packed union 229 | #endif 230 | #ifndef __UNALIGNED_UINT32 /* deprecated */ 231 | @packed struct T_UINT32 { uint32_t v; }; 232 | #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) 233 | #endif 234 | #ifndef __UNALIGNED_UINT16_WRITE 235 | __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; 236 | #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) 237 | #endif 238 | #ifndef __UNALIGNED_UINT16_READ 239 | __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; 240 | #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) 241 | #endif 242 | #ifndef __UNALIGNED_UINT32_WRITE 243 | __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; 244 | #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) 245 | #endif 246 | #ifndef __UNALIGNED_UINT32_READ 247 | __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; 248 | #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) 249 | #endif 250 | #ifndef __ALIGNED 251 | #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. 252 | #define __ALIGNED(x) 253 | #endif 254 | #ifndef __RESTRICT 255 | #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. 256 | #define __RESTRICT 257 | #endif 258 | 259 | 260 | #else 261 | #error Unknown compiler. 262 | #endif 263 | 264 | 265 | #endif /* __CMSIS_COMPILER_H */ 266 | 267 | -------------------------------------------------------------------------------- /src/dhara/journal.h: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DHARA_JOURNAL_H_ 18 | #define DHARA_JOURNAL_H_ 19 | 20 | #include 21 | #include "nand.h" 22 | 23 | /* Number of bytes used by the journal checkpoint header. */ 24 | #define DHARA_HEADER_SIZE 16 25 | 26 | /* Global metadata available for a higher layer. This metadata is 27 | * persistent once the journal reaches a checkpoint, and is restored on 28 | * startup. 29 | */ 30 | #define DHARA_COOKIE_SIZE 4 31 | 32 | /* This is the size of the metadata slice which accompanies each written 33 | * page. This is independent of the underlying page/OOB size. 34 | */ 35 | #define DHARA_META_SIZE 132 36 | 37 | /* When a block fails, or garbage is encountered, we try again on the 38 | * next block/checkpoint. We can do this up to the given number of 39 | * times. 40 | */ 41 | #define DHARA_MAX_RETRIES 8 42 | 43 | /* This is a page number which can be used to represent "no such page". 44 | * It's guaranteed to never be a valid user page. 45 | */ 46 | #define DHARA_PAGE_NONE ((dhara_page_t)0xffffffff) 47 | 48 | /* State flags */ 49 | #define DHARA_JOURNAL_F_DIRTY 0x01 50 | #define DHARA_JOURNAL_F_BAD_META 0x02 51 | #define DHARA_JOURNAL_F_RECOVERY 0x04 52 | #define DHARA_JOURNAL_F_ENUM_DONE 0x08 53 | 54 | /* The journal layer presents the NAND pages as a double-ended queue. 55 | * Pages, with associated metadata may be pushed onto the end of the 56 | * queue, and pages may be popped from the end. 57 | * 58 | * Block erase, metadata storage are handled automatically. Bad blocks 59 | * are handled by relocating data to the next available non-bad page in 60 | * the sequence. 61 | * 62 | * It's up to the user to ensure that the queue doesn't grow beyond the 63 | * capacity of the NAND chip, but helper functions are provided to 64 | * assist with this. If the head meets the tail, the journal will refuse 65 | * to enqueue more pages. 66 | */ 67 | struct dhara_journal { 68 | const struct dhara_nand *nand; 69 | uint8_t *page_buf; 70 | 71 | /* In the journal, user data is grouped into checkpoints of 72 | * 2**log2_ppc contiguous aligned pages. 73 | * 74 | * The last page of each checkpoint contains the journal header 75 | * and the metadata for the other pages in the period (the user 76 | * pages). 77 | */ 78 | uint8_t log2_ppc; 79 | 80 | /* Epoch counter. This is incremented whenever the journal head 81 | * passes the end of the chip and wraps around. 82 | */ 83 | uint8_t epoch; 84 | 85 | /* General purpose flags field */ 86 | uint8_t flags; 87 | 88 | /* Bad-block counters. bb_last is our best estimate of the 89 | * number of bad blocks in the chip as a whole. bb_current is 90 | * the number of bad blocks in all blocks before the current 91 | * head. 92 | */ 93 | dhara_block_t bb_current; 94 | dhara_block_t bb_last; 95 | 96 | /* Log head and tail. The tail pointer points to the last user 97 | * page in the log, and the head pointer points to the next free 98 | * raw page. The root points to the last written user page. 99 | */ 100 | dhara_page_t tail_sync; 101 | dhara_page_t tail; 102 | dhara_page_t head; 103 | 104 | /* This points to the last written user page in the journal */ 105 | dhara_page_t root; 106 | 107 | /* Recovery mode: recover_root points to the last valid user 108 | * page in the block requiring recovery. recover_next points to 109 | * the next user page needing recovery. 110 | * 111 | * If we had buffered metadata before recovery started, it will 112 | * have been dumped to a free page, indicated by recover_meta. 113 | * If this block later goes bad, we will have to defer bad-block 114 | * marking until recovery is complete (F_BAD_META). 115 | */ 116 | dhara_page_t recover_next; 117 | dhara_page_t recover_root; 118 | dhara_page_t recover_meta; 119 | }; 120 | 121 | /* Initialize a journal. You must supply a pointer to a NAND chip 122 | * driver, and a single page buffer. This page buffer will be used 123 | * exclusively by the journal, but you are responsible for allocating 124 | * it, and freeing it (if necessary) at the end. 125 | * 126 | * No NAND operations are performed at this point. 127 | */ 128 | void dhara_journal_init(struct dhara_journal *j, 129 | const struct dhara_nand *n, 130 | uint8_t *page_buf); 131 | 132 | /* Start up the journal -- search the NAND for the journal head, or 133 | * initialize a blank journal if one isn't found. Returns 0 on success 134 | * or -1 if a (fatal) error occurs. 135 | * 136 | * This operation is O(log N), where N is the number of pages in the 137 | * NAND chip. All other operations are O(1). 138 | * 139 | * If this operation fails, the journal will be reset to an empty state. 140 | */ 141 | int dhara_journal_resume(struct dhara_journal *j, dhara_error_t *err); 142 | 143 | /* Obtain an upper bound on the number of user pages storable in the 144 | * journal. 145 | */ 146 | dhara_page_t dhara_journal_capacity(const struct dhara_journal *j); 147 | 148 | /* Obtain an upper bound on the number of user pages consumed by the 149 | * journal. 150 | */ 151 | dhara_page_t dhara_journal_size(const struct dhara_journal *j); 152 | 153 | /* Obtain a pointer to the cookie data */ 154 | static inline uint8_t *dhara_journal_cookie(const struct dhara_journal *j) 155 | { 156 | return j->page_buf + DHARA_HEADER_SIZE; 157 | } 158 | 159 | /* Obtain the locations of the first and last pages in the journal. 160 | */ 161 | static inline dhara_page_t dhara_journal_root(const struct dhara_journal *j) 162 | { 163 | return j->root; 164 | } 165 | 166 | /* Read metadata associated with a page. This assumes that the page 167 | * provided is a valid data page. The actual page data is read via the 168 | * normal NAND interface. 169 | */ 170 | int dhara_journal_read_meta(struct dhara_journal *j, dhara_page_t p, 171 | uint8_t *buf, dhara_error_t *err); 172 | 173 | /* Advance the tail to the next non-bad block and return the page that's 174 | * ready to read. If no page is ready, return DHARA_PAGE_NONE. 175 | */ 176 | dhara_page_t dhara_journal_peek(struct dhara_journal *j); 177 | 178 | /* Remove the last page from the journal. This doesn't take permanent 179 | * effect until the next checkpoint. 180 | */ 181 | void dhara_journal_dequeue(struct dhara_journal *j); 182 | 183 | /* Remove all pages form the journal. This doesn't take permanent effect 184 | * until the next checkpoint. 185 | */ 186 | void dhara_journal_clear(struct dhara_journal *j); 187 | 188 | /* Append a page to the journal. Both raw page data and metadata must be 189 | * specified. The push operation is not persistent until a checkpoint is 190 | * reached. 191 | * 192 | * This operation may fail with the error code E_RECOVER. If this 193 | * occurs, the upper layer must complete the assisted recovery procedure 194 | * and then try again. 195 | * 196 | * This operation may be used as part of a recovery. If further errors 197 | * occur during recovery, E_RECOVER is returned, and the procedure must 198 | * be restarted. 199 | */ 200 | int dhara_journal_enqueue(struct dhara_journal *j, 201 | const uint8_t *data, const uint8_t *meta, 202 | dhara_error_t *err); 203 | 204 | /* Copy an existing page to the front of the journal. New metadata must 205 | * be specified. This operation is not persistent until a checkpoint is 206 | * reached. 207 | * 208 | * This operation may fail with the error code E_RECOVER. If this 209 | * occurs, the upper layer must complete the assisted recovery procedure 210 | * and then try again. 211 | * 212 | * This operation may be used as part of a recovery. If further errors 213 | * occur during recovery, E_RECOVER is returned, and the procedure must 214 | * be restarted. 215 | */ 216 | int dhara_journal_copy(struct dhara_journal *j, 217 | dhara_page_t p, const uint8_t *meta, 218 | dhara_error_t *err); 219 | 220 | /* Mark the journal dirty. */ 221 | static inline void dhara_journal_mark_dirty(struct dhara_journal *j) 222 | { 223 | j->flags |= DHARA_JOURNAL_F_DIRTY; 224 | } 225 | 226 | /* Is the journal checkpointed? If true, then all pages enqueued are now 227 | * persistent. 228 | */ 229 | static inline int dhara_journal_is_clean(const struct dhara_journal *j) 230 | { 231 | return !(j->flags & DHARA_JOURNAL_F_DIRTY); 232 | } 233 | 234 | /* If an operation returns E_RECOVER, you must begin the recovery 235 | * procedure. You must then: 236 | * 237 | * - call dhara_journal_next_recoverable() to obtain the next block 238 | * to be recovered (if any). If there are no blocks remaining to be 239 | * recovered, DHARA_JOURNAL_PAGE_NONE is returned. 240 | * 241 | * - proceed to the next checkpoint. Once the journal is clean, 242 | * recovery will finish automatically. 243 | * 244 | * If any operation during recovery fails due to a bad block, E_RECOVER 245 | * is returned again, and recovery restarts. Do not add new data to the 246 | * journal (rewrites of recovered data are fine) until recovery is 247 | * complete. 248 | */ 249 | static inline int dhara_journal_in_recovery(const struct dhara_journal *j) 250 | { 251 | return j->flags & DHARA_JOURNAL_F_RECOVERY; 252 | } 253 | 254 | dhara_page_t dhara_journal_next_recoverable(struct dhara_journal *j); 255 | 256 | #endif 257 | -------------------------------------------------------------------------------- /src/st/ll/stm32l4xx_ll_gpio.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32l4xx_ll_gpio.c 4 | * @author MCD Application Team 5 | * @brief GPIO LL module driver. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2017 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under BSD 3-Clause license, 13 | * the "License"; You may not use this file except in compliance with the 14 | * License. You may obtain a copy of the License at: 15 | * opensource.org/licenses/BSD-3-Clause 16 | * 17 | ****************************************************************************** 18 | */ 19 | #if defined(USE_FULL_LL_DRIVER) 20 | 21 | /* Includes ------------------------------------------------------------------*/ 22 | #include "stm32l4xx_ll_gpio.h" 23 | #include "stm32l4xx_ll_bus.h" 24 | #ifdef USE_FULL_ASSERT 25 | #include "stm32_assert.h" 26 | #else 27 | #define assert_param(expr) ((void)0U) 28 | #endif 29 | 30 | /** @addtogroup STM32L4xx_LL_Driver 31 | * @{ 32 | */ 33 | 34 | #if defined (GPIOA) || defined (GPIOB) || defined (GPIOC) || defined (GPIOD) || defined (GPIOE) || defined (GPIOF) || defined (GPIOG) || defined (GPIOH) || defined (GPIOI) 35 | 36 | /** @addtogroup GPIO_LL 37 | * @{ 38 | */ 39 | /** MISRA C:2012 deviation rule has been granted for following rules: 40 | * Rule-12.2 - Medium: RHS argument is in interval [0,INF] which is out of 41 | * range of the shift operator in following API : 42 | * LL_GPIO_Init 43 | */ 44 | 45 | /* Private types -------------------------------------------------------------*/ 46 | /* Private variables ---------------------------------------------------------*/ 47 | /* Private constants ---------------------------------------------------------*/ 48 | /* Private macros ------------------------------------------------------------*/ 49 | /** @addtogroup GPIO_LL_Private_Macros 50 | * @{ 51 | */ 52 | #define IS_LL_GPIO_PIN(__VALUE__) (((0x00u) < (__VALUE__)) && ((__VALUE__) <= (LL_GPIO_PIN_ALL))) 53 | 54 | #define IS_LL_GPIO_MODE(__VALUE__) (((__VALUE__) == LL_GPIO_MODE_INPUT) ||\ 55 | ((__VALUE__) == LL_GPIO_MODE_OUTPUT) ||\ 56 | ((__VALUE__) == LL_GPIO_MODE_ALTERNATE) ||\ 57 | ((__VALUE__) == LL_GPIO_MODE_ANALOG)) 58 | 59 | #define IS_LL_GPIO_OUTPUT_TYPE(__VALUE__) (((__VALUE__) == LL_GPIO_OUTPUT_PUSHPULL) ||\ 60 | ((__VALUE__) == LL_GPIO_OUTPUT_OPENDRAIN)) 61 | 62 | #define IS_LL_GPIO_SPEED(__VALUE__) (((__VALUE__) == LL_GPIO_SPEED_FREQ_LOW) ||\ 63 | ((__VALUE__) == LL_GPIO_SPEED_FREQ_MEDIUM) ||\ 64 | ((__VALUE__) == LL_GPIO_SPEED_FREQ_HIGH) ||\ 65 | ((__VALUE__) == LL_GPIO_SPEED_FREQ_VERY_HIGH)) 66 | 67 | #define IS_LL_GPIO_PULL(__VALUE__) (((__VALUE__) == LL_GPIO_PULL_NO) ||\ 68 | ((__VALUE__) == LL_GPIO_PULL_UP) ||\ 69 | ((__VALUE__) == LL_GPIO_PULL_DOWN)) 70 | 71 | #define IS_LL_GPIO_ALTERNATE(__VALUE__) (((__VALUE__) == LL_GPIO_AF_0 ) ||\ 72 | ((__VALUE__) == LL_GPIO_AF_1 ) ||\ 73 | ((__VALUE__) == LL_GPIO_AF_2 ) ||\ 74 | ((__VALUE__) == LL_GPIO_AF_3 ) ||\ 75 | ((__VALUE__) == LL_GPIO_AF_4 ) ||\ 76 | ((__VALUE__) == LL_GPIO_AF_5 ) ||\ 77 | ((__VALUE__) == LL_GPIO_AF_6 ) ||\ 78 | ((__VALUE__) == LL_GPIO_AF_7 ) ||\ 79 | ((__VALUE__) == LL_GPIO_AF_8 ) ||\ 80 | ((__VALUE__) == LL_GPIO_AF_9 ) ||\ 81 | ((__VALUE__) == LL_GPIO_AF_10 ) ||\ 82 | ((__VALUE__) == LL_GPIO_AF_11 ) ||\ 83 | ((__VALUE__) == LL_GPIO_AF_12 ) ||\ 84 | ((__VALUE__) == LL_GPIO_AF_13 ) ||\ 85 | ((__VALUE__) == LL_GPIO_AF_14 ) ||\ 86 | ((__VALUE__) == LL_GPIO_AF_15 )) 87 | /** 88 | * @} 89 | */ 90 | 91 | /* Private function prototypes -----------------------------------------------*/ 92 | 93 | /* Exported functions --------------------------------------------------------*/ 94 | /** @addtogroup GPIO_LL_Exported_Functions 95 | * @{ 96 | */ 97 | 98 | /** @addtogroup GPIO_LL_EF_Init 99 | * @{ 100 | */ 101 | 102 | /** 103 | * @brief De-initialize GPIO registers (Registers restored to their default values). 104 | * @param GPIOx GPIO Port 105 | * @retval An ErrorStatus enumeration value: 106 | * - SUCCESS: GPIO registers are de-initialized 107 | * - ERROR: Wrong GPIO Port 108 | */ 109 | ErrorStatus LL_GPIO_DeInit(GPIO_TypeDef *GPIOx) 110 | { 111 | ErrorStatus status = SUCCESS; 112 | 113 | /* Check the parameters */ 114 | assert_param(IS_GPIO_ALL_INSTANCE(GPIOx)); 115 | 116 | /* Force and Release reset on clock of GPIOx Port */ 117 | if (GPIOx == GPIOA) 118 | { 119 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOA); 120 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOA); 121 | } 122 | else if (GPIOx == GPIOB) 123 | { 124 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOB); 125 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOB); 126 | } 127 | else if (GPIOx == GPIOC) 128 | { 129 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOC); 130 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOC); 131 | } 132 | #if defined(GPIOD) 133 | else if (GPIOx == GPIOD) 134 | { 135 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOD); 136 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOD); 137 | } 138 | #endif /* GPIOD */ 139 | #if defined(GPIOE) 140 | else if (GPIOx == GPIOE) 141 | { 142 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOE); 143 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOE); 144 | } 145 | #endif /* GPIOE */ 146 | #if defined(GPIOF) 147 | else if (GPIOx == GPIOF) 148 | { 149 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOF); 150 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOF); 151 | } 152 | #endif /* GPIOF */ 153 | #if defined(GPIOG) 154 | else if (GPIOx == GPIOG) 155 | { 156 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOG); 157 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOG); 158 | } 159 | #endif /* GPIOG */ 160 | #if defined(GPIOH) 161 | else if (GPIOx == GPIOH) 162 | { 163 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOH); 164 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOH); 165 | } 166 | #endif /* GPIOH */ 167 | #if defined(GPIOI) 168 | else if (GPIOx == GPIOI) 169 | { 170 | LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_GPIOI); 171 | LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_GPIOI); 172 | } 173 | #endif /* GPIOI */ 174 | else 175 | { 176 | status = ERROR; 177 | } 178 | 179 | return (status); 180 | } 181 | 182 | /** 183 | * @brief Initialize GPIO registers according to the specified parameters in GPIO_InitStruct. 184 | * @param GPIOx GPIO Port 185 | * @param GPIO_InitStruct pointer to a @ref LL_GPIO_InitTypeDef structure 186 | * that contains the configuration information for the specified GPIO peripheral. 187 | * @retval An ErrorStatus enumeration value: 188 | * - SUCCESS: GPIO registers are initialized according to GPIO_InitStruct content 189 | * - ERROR: Not applicable 190 | */ 191 | ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct) 192 | { 193 | uint32_t pinpos; 194 | uint32_t currentpin; 195 | 196 | /* Check the parameters */ 197 | assert_param(IS_GPIO_ALL_INSTANCE(GPIOx)); 198 | assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin)); 199 | assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode)); 200 | assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull)); 201 | 202 | /* ------------------------- Configure the port pins ---------------- */ 203 | /* Initialize pinpos on first pin set */ 204 | pinpos = POSITION_VAL(GPIO_InitStruct->Pin); 205 | 206 | /* Configure the port pins */ 207 | while (((GPIO_InitStruct->Pin) >> pinpos) != 0x00u) 208 | { 209 | /* Get current io position */ 210 | currentpin = (GPIO_InitStruct->Pin) & (0x00000001uL << pinpos); 211 | 212 | if (currentpin != 0x00u) 213 | { 214 | /* Pin Mode configuration */ 215 | LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode); 216 | 217 | if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE)) 218 | { 219 | /* Check Speed mode parameters */ 220 | assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed)); 221 | 222 | /* Speed mode configuration */ 223 | LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed); 224 | } 225 | 226 | /* Pull-up Pull down resistor configuration*/ 227 | LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull); 228 | 229 | if (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE) 230 | { 231 | /* Check Alternate parameter */ 232 | assert_param(IS_LL_GPIO_ALTERNATE(GPIO_InitStruct->Alternate)); 233 | 234 | /* Speed mode configuration */ 235 | if (currentpin < LL_GPIO_PIN_8) 236 | { 237 | LL_GPIO_SetAFPin_0_7(GPIOx, currentpin, GPIO_InitStruct->Alternate); 238 | } 239 | else 240 | { 241 | LL_GPIO_SetAFPin_8_15(GPIOx, currentpin, GPIO_InitStruct->Alternate); 242 | } 243 | } 244 | } 245 | pinpos++; 246 | } 247 | 248 | if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE)) 249 | { 250 | /* Check Output mode parameters */ 251 | assert_param(IS_LL_GPIO_OUTPUT_TYPE(GPIO_InitStruct->OutputType)); 252 | 253 | /* Output mode configuration*/ 254 | LL_GPIO_SetPinOutputType(GPIOx, GPIO_InitStruct->Pin, GPIO_InitStruct->OutputType); 255 | 256 | } 257 | return (SUCCESS); 258 | } 259 | 260 | /** 261 | * @brief Set each @ref LL_GPIO_InitTypeDef field to default value. 262 | * @param GPIO_InitStruct pointer to a @ref LL_GPIO_InitTypeDef structure 263 | * whose fields will be set to default values. 264 | * @retval None 265 | */ 266 | 267 | void LL_GPIO_StructInit(LL_GPIO_InitTypeDef *GPIO_InitStruct) 268 | { 269 | /* Reset GPIO init structure parameters values */ 270 | GPIO_InitStruct->Pin = LL_GPIO_PIN_ALL; 271 | GPIO_InitStruct->Mode = LL_GPIO_MODE_ANALOG; 272 | GPIO_InitStruct->Speed = LL_GPIO_SPEED_FREQ_LOW; 273 | GPIO_InitStruct->OutputType = LL_GPIO_OUTPUT_PUSHPULL; 274 | GPIO_InitStruct->Pull = LL_GPIO_PULL_NO; 275 | GPIO_InitStruct->Alternate = LL_GPIO_AF_0; 276 | } 277 | 278 | /** 279 | * @} 280 | */ 281 | 282 | /** 283 | * @} 284 | */ 285 | 286 | /** 287 | * @} 288 | */ 289 | 290 | #endif /* defined (GPIOA) || defined (GPIOB) || defined (GPIOC) || defined (GPIOD) || defined (GPIOE) || defined (GPIOF) || defined (GPIOG) || defined (GPIOH) || defined (GPIOI) */ 291 | 292 | /** 293 | * @} 294 | */ 295 | 296 | #endif /* USE_FULL_LL_DRIVER */ 297 | 298 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 299 | -------------------------------------------------------------------------------- /src/st/ll/stm32l4xx_ll_spi.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32l4xx_ll_spi.c 4 | * @author MCD Application Team 5 | * @brief SPI LL module driver. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2017 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under BSD 3-Clause license, 13 | * the "License"; You may not use this file except in compliance with the 14 | * License. You may obtain a copy of the License at: 15 | * opensource.org/licenses/BSD-3-Clause 16 | * 17 | ****************************************************************************** 18 | */ 19 | #if defined(USE_FULL_LL_DRIVER) 20 | 21 | /* Includes ------------------------------------------------------------------*/ 22 | #include "stm32l4xx_ll_spi.h" 23 | #include "stm32l4xx_ll_bus.h" 24 | 25 | #ifdef USE_FULL_ASSERT 26 | #include "stm32_assert.h" 27 | #else 28 | #define assert_param(expr) ((void)0U) 29 | #endif 30 | 31 | /** @addtogroup STM32L4xx_LL_Driver 32 | * @{ 33 | */ 34 | 35 | #if defined (SPI1) || defined (SPI2) || defined (SPI3) 36 | 37 | /** @addtogroup SPI_LL 38 | * @{ 39 | */ 40 | 41 | /* Private types -------------------------------------------------------------*/ 42 | /* Private variables ---------------------------------------------------------*/ 43 | 44 | /* Private constants ---------------------------------------------------------*/ 45 | /** @defgroup SPI_LL_Private_Constants SPI Private Constants 46 | * @{ 47 | */ 48 | /* SPI registers Masks */ 49 | #define SPI_CR1_CLEAR_MASK (SPI_CR1_CPHA | SPI_CR1_CPOL | SPI_CR1_MSTR | \ 50 | SPI_CR1_BR | SPI_CR1_LSBFIRST | SPI_CR1_SSI | \ 51 | SPI_CR1_SSM | SPI_CR1_RXONLY | SPI_CR1_CRCL | \ 52 | SPI_CR1_CRCNEXT | SPI_CR1_CRCEN | SPI_CR1_BIDIOE | \ 53 | SPI_CR1_BIDIMODE) 54 | /** 55 | * @} 56 | */ 57 | 58 | /* Private macros ------------------------------------------------------------*/ 59 | /** @defgroup SPI_LL_Private_Macros SPI Private Macros 60 | * @{ 61 | */ 62 | #define IS_LL_SPI_TRANSFER_DIRECTION(__VALUE__) (((__VALUE__) == LL_SPI_FULL_DUPLEX) \ 63 | || ((__VALUE__) == LL_SPI_SIMPLEX_RX) \ 64 | || ((__VALUE__) == LL_SPI_HALF_DUPLEX_RX) \ 65 | || ((__VALUE__) == LL_SPI_HALF_DUPLEX_TX)) 66 | 67 | #define IS_LL_SPI_MODE(__VALUE__) (((__VALUE__) == LL_SPI_MODE_MASTER) \ 68 | || ((__VALUE__) == LL_SPI_MODE_SLAVE)) 69 | 70 | #define IS_LL_SPI_DATAWIDTH(__VALUE__) (((__VALUE__) == LL_SPI_DATAWIDTH_4BIT) \ 71 | || ((__VALUE__) == LL_SPI_DATAWIDTH_5BIT) \ 72 | || ((__VALUE__) == LL_SPI_DATAWIDTH_6BIT) \ 73 | || ((__VALUE__) == LL_SPI_DATAWIDTH_7BIT) \ 74 | || ((__VALUE__) == LL_SPI_DATAWIDTH_8BIT) \ 75 | || ((__VALUE__) == LL_SPI_DATAWIDTH_9BIT) \ 76 | || ((__VALUE__) == LL_SPI_DATAWIDTH_10BIT) \ 77 | || ((__VALUE__) == LL_SPI_DATAWIDTH_11BIT) \ 78 | || ((__VALUE__) == LL_SPI_DATAWIDTH_12BIT) \ 79 | || ((__VALUE__) == LL_SPI_DATAWIDTH_13BIT) \ 80 | || ((__VALUE__) == LL_SPI_DATAWIDTH_14BIT) \ 81 | || ((__VALUE__) == LL_SPI_DATAWIDTH_15BIT) \ 82 | || ((__VALUE__) == LL_SPI_DATAWIDTH_16BIT)) 83 | 84 | #define IS_LL_SPI_POLARITY(__VALUE__) (((__VALUE__) == LL_SPI_POLARITY_LOW) \ 85 | || ((__VALUE__) == LL_SPI_POLARITY_HIGH)) 86 | 87 | #define IS_LL_SPI_PHASE(__VALUE__) (((__VALUE__) == LL_SPI_PHASE_1EDGE) \ 88 | || ((__VALUE__) == LL_SPI_PHASE_2EDGE)) 89 | 90 | #define IS_LL_SPI_NSS(__VALUE__) (((__VALUE__) == LL_SPI_NSS_SOFT) \ 91 | || ((__VALUE__) == LL_SPI_NSS_HARD_INPUT) \ 92 | || ((__VALUE__) == LL_SPI_NSS_HARD_OUTPUT)) 93 | 94 | #define IS_LL_SPI_BAUDRATE(__VALUE__) (((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV2) \ 95 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV4) \ 96 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV8) \ 97 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV16) \ 98 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV32) \ 99 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV64) \ 100 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV128) \ 101 | || ((__VALUE__) == LL_SPI_BAUDRATEPRESCALER_DIV256)) 102 | 103 | #define IS_LL_SPI_BITORDER(__VALUE__) (((__VALUE__) == LL_SPI_LSB_FIRST) \ 104 | || ((__VALUE__) == LL_SPI_MSB_FIRST)) 105 | 106 | #define IS_LL_SPI_CRCCALCULATION(__VALUE__) (((__VALUE__) == LL_SPI_CRCCALCULATION_ENABLE) \ 107 | || ((__VALUE__) == LL_SPI_CRCCALCULATION_DISABLE)) 108 | 109 | #define IS_LL_SPI_CRC_POLYNOMIAL(__VALUE__) ((__VALUE__) >= 0x1U) 110 | 111 | /** 112 | * @} 113 | */ 114 | 115 | /* Private function prototypes -----------------------------------------------*/ 116 | 117 | /* Exported functions --------------------------------------------------------*/ 118 | /** @addtogroup SPI_LL_Exported_Functions 119 | * @{ 120 | */ 121 | 122 | /** @addtogroup SPI_LL_EF_Init 123 | * @{ 124 | */ 125 | 126 | /** 127 | * @brief De-initialize the SPI registers to their default reset values. 128 | * @param SPIx SPI Instance 129 | * @retval An ErrorStatus enumeration value: 130 | * - SUCCESS: SPI registers are de-initialized 131 | * - ERROR: SPI registers are not de-initialized 132 | */ 133 | ErrorStatus LL_SPI_DeInit(SPI_TypeDef *SPIx) 134 | { 135 | ErrorStatus status = ERROR; 136 | 137 | /* Check the parameters */ 138 | assert_param(IS_SPI_ALL_INSTANCE(SPIx)); 139 | 140 | #if defined(SPI1) 141 | if (SPIx == SPI1) 142 | { 143 | /* Force reset of SPI clock */ 144 | LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); 145 | 146 | /* Release reset of SPI clock */ 147 | LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); 148 | 149 | status = SUCCESS; 150 | } 151 | #endif /* SPI1 */ 152 | #if defined(SPI2) 153 | if (SPIx == SPI2) 154 | { 155 | /* Force reset of SPI clock */ 156 | LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); 157 | 158 | /* Release reset of SPI clock */ 159 | LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); 160 | 161 | status = SUCCESS; 162 | } 163 | #endif /* SPI2 */ 164 | #if defined(SPI3) 165 | if (SPIx == SPI3) 166 | { 167 | /* Force reset of SPI clock */ 168 | LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI3); 169 | 170 | /* Release reset of SPI clock */ 171 | LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI3); 172 | 173 | status = SUCCESS; 174 | } 175 | #endif /* SPI3 */ 176 | 177 | return status; 178 | } 179 | 180 | /** 181 | * @brief Initialize the SPI registers according to the specified parameters in SPI_InitStruct. 182 | * @note As some bits in SPI configuration registers can only be written when the SPI is disabled (SPI_CR1_SPE bit =0), 183 | * SPI peripheral should be in disabled state prior calling this function. Otherwise, ERROR result will be returned. 184 | * @param SPIx SPI Instance 185 | * @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure 186 | * @retval An ErrorStatus enumeration value. (Return always SUCCESS) 187 | */ 188 | ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct) 189 | { 190 | ErrorStatus status = ERROR; 191 | 192 | /* Check the SPI Instance SPIx*/ 193 | assert_param(IS_SPI_ALL_INSTANCE(SPIx)); 194 | 195 | /* Check the SPI parameters from SPI_InitStruct*/ 196 | assert_param(IS_LL_SPI_TRANSFER_DIRECTION(SPI_InitStruct->TransferDirection)); 197 | assert_param(IS_LL_SPI_MODE(SPI_InitStruct->Mode)); 198 | assert_param(IS_LL_SPI_DATAWIDTH(SPI_InitStruct->DataWidth)); 199 | assert_param(IS_LL_SPI_POLARITY(SPI_InitStruct->ClockPolarity)); 200 | assert_param(IS_LL_SPI_PHASE(SPI_InitStruct->ClockPhase)); 201 | assert_param(IS_LL_SPI_NSS(SPI_InitStruct->NSS)); 202 | assert_param(IS_LL_SPI_BAUDRATE(SPI_InitStruct->BaudRate)); 203 | assert_param(IS_LL_SPI_BITORDER(SPI_InitStruct->BitOrder)); 204 | assert_param(IS_LL_SPI_CRCCALCULATION(SPI_InitStruct->CRCCalculation)); 205 | 206 | if (LL_SPI_IsEnabled(SPIx) == 0x00000000U) 207 | { 208 | /*---------------------------- SPIx CR1 Configuration ------------------------ 209 | * Configure SPIx CR1 with parameters: 210 | * - TransferDirection: SPI_CR1_BIDIMODE, SPI_CR1_BIDIOE and SPI_CR1_RXONLY bits 211 | * - Master/Slave Mode: SPI_CR1_MSTR bit 212 | * - ClockPolarity: SPI_CR1_CPOL bit 213 | * - ClockPhase: SPI_CR1_CPHA bit 214 | * - NSS management: SPI_CR1_SSM bit 215 | * - BaudRate prescaler: SPI_CR1_BR[2:0] bits 216 | * - BitOrder: SPI_CR1_LSBFIRST bit 217 | * - CRCCalculation: SPI_CR1_CRCEN bit 218 | */ 219 | MODIFY_REG(SPIx->CR1, 220 | SPI_CR1_CLEAR_MASK, 221 | SPI_InitStruct->TransferDirection | SPI_InitStruct->Mode | 222 | SPI_InitStruct->ClockPolarity | SPI_InitStruct->ClockPhase | 223 | SPI_InitStruct->NSS | SPI_InitStruct->BaudRate | 224 | SPI_InitStruct->BitOrder | SPI_InitStruct->CRCCalculation); 225 | 226 | /*---------------------------- SPIx CR2 Configuration ------------------------ 227 | * Configure SPIx CR2 with parameters: 228 | * - DataWidth: DS[3:0] bits 229 | * - NSS management: SSOE bit 230 | */ 231 | MODIFY_REG(SPIx->CR2, 232 | SPI_CR2_DS | SPI_CR2_SSOE, 233 | SPI_InitStruct->DataWidth | (SPI_InitStruct->NSS >> 16U)); 234 | 235 | /*---------------------------- SPIx CRCPR Configuration ---------------------- 236 | * Configure SPIx CRCPR with parameters: 237 | * - CRCPoly: CRCPOLY[15:0] bits 238 | */ 239 | if (SPI_InitStruct->CRCCalculation == LL_SPI_CRCCALCULATION_ENABLE) 240 | { 241 | assert_param(IS_LL_SPI_CRC_POLYNOMIAL(SPI_InitStruct->CRCPoly)); 242 | LL_SPI_SetCRCPolynomial(SPIx, SPI_InitStruct->CRCPoly); 243 | } 244 | status = SUCCESS; 245 | } 246 | 247 | return status; 248 | } 249 | 250 | /** 251 | * @brief Set each @ref LL_SPI_InitTypeDef field to default value. 252 | * @param SPI_InitStruct pointer to a @ref LL_SPI_InitTypeDef structure 253 | * whose fields will be set to default values. 254 | * @retval None 255 | */ 256 | void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct) 257 | { 258 | /* Set SPI_InitStruct fields to default values */ 259 | SPI_InitStruct->TransferDirection = LL_SPI_FULL_DUPLEX; 260 | SPI_InitStruct->Mode = LL_SPI_MODE_SLAVE; 261 | SPI_InitStruct->DataWidth = LL_SPI_DATAWIDTH_8BIT; 262 | SPI_InitStruct->ClockPolarity = LL_SPI_POLARITY_LOW; 263 | SPI_InitStruct->ClockPhase = LL_SPI_PHASE_1EDGE; 264 | SPI_InitStruct->NSS = LL_SPI_NSS_HARD_INPUT; 265 | SPI_InitStruct->BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2; 266 | SPI_InitStruct->BitOrder = LL_SPI_MSB_FIRST; 267 | SPI_InitStruct->CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; 268 | SPI_InitStruct->CRCPoly = 7U; 269 | } 270 | 271 | /** 272 | * @} 273 | */ 274 | 275 | /** 276 | * @} 277 | */ 278 | 279 | /** 280 | * @} 281 | */ 282 | 283 | #endif /* defined (SPI1) || defined (SPI2) || defined (SPI3) */ 284 | 285 | /** 286 | * @} 287 | */ 288 | 289 | #endif /* USE_FULL_LL_DRIVER */ 290 | 291 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 292 | -------------------------------------------------------------------------------- /src/cmsis/mpu_armv7.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file mpu_armv7.h 3 | * @brief CMSIS MPU API for Armv7-M MPU 4 | * @version V5.0.4 5 | * @date 10. January 2018 6 | ******************************************************************************/ 7 | /* 8 | * Copyright (c) 2017-2018 Arm Limited. All rights reserved. 9 | * 10 | * SPDX-License-Identifier: Apache-2.0 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the License); you may 13 | * not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 20 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #if defined ( __ICCARM__ ) 26 | #pragma system_include /* treat file as system include file for MISRA check */ 27 | #elif defined (__clang__) 28 | #pragma clang system_header /* treat file as system include file */ 29 | #endif 30 | 31 | #ifndef ARM_MPU_ARMV7_H 32 | #define ARM_MPU_ARMV7_H 33 | 34 | #define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes 35 | #define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes 36 | #define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes 37 | #define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes 38 | #define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes 39 | #define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte 40 | #define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes 41 | #define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes 42 | #define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes 43 | #define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes 44 | #define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes 45 | #define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes 46 | #define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes 47 | #define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes 48 | #define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes 49 | #define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte 50 | #define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes 51 | #define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes 52 | #define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes 53 | #define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes 54 | #define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes 55 | #define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes 56 | #define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes 57 | #define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes 58 | #define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes 59 | #define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte 60 | #define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes 61 | #define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes 62 | 63 | #define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access 64 | #define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only 65 | #define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only 66 | #define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access 67 | #define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only 68 | #define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access 69 | 70 | /** MPU Region Base Address Register Value 71 | * 72 | * \param Region The region to be configured, number 0 to 15. 73 | * \param BaseAddress The base address for the region. 74 | */ 75 | #define ARM_MPU_RBAR(Region, BaseAddress) \ 76 | (((BaseAddress) & MPU_RBAR_ADDR_Msk) | \ 77 | ((Region) & MPU_RBAR_REGION_Msk) | \ 78 | (MPU_RBAR_VALID_Msk)) 79 | 80 | /** 81 | * MPU Memory Access Attributes 82 | * 83 | * \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. 84 | * \param IsShareable Region is shareable between multiple bus masters. 85 | * \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. 86 | * \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. 87 | */ 88 | #define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \ 89 | ((((TypeExtField ) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \ 90 | (((IsShareable ) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \ 91 | (((IsCacheable ) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \ 92 | (((IsBufferable ) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)) 93 | 94 | /** 95 | * MPU Region Attribute and Size Register Value 96 | * 97 | * \param DisableExec Instruction access disable bit, 1= disable instruction fetches. 98 | * \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. 99 | * \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_. 100 | * \param SubRegionDisable Sub-region disable field. 101 | * \param Size Region size of the region to be configured, for example 4K, 8K. 102 | */ 103 | #define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \ 104 | ((((DisableExec ) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \ 105 | (((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \ 106 | (((AccessAttributes) ) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) 107 | 108 | /** 109 | * MPU Region Attribute and Size Register Value 110 | * 111 | * \param DisableExec Instruction access disable bit, 1= disable instruction fetches. 112 | * \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. 113 | * \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. 114 | * \param IsShareable Region is shareable between multiple bus masters. 115 | * \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. 116 | * \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. 117 | * \param SubRegionDisable Sub-region disable field. 118 | * \param Size Region size of the region to be configured, for example 4K, 8K. 119 | */ 120 | #define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \ 121 | ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size) 122 | 123 | /** 124 | * MPU Memory Access Attribute for strongly ordered memory. 125 | * - TEX: 000b 126 | * - Shareable 127 | * - Non-cacheable 128 | * - Non-bufferable 129 | */ 130 | #define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U) 131 | 132 | /** 133 | * MPU Memory Access Attribute for device memory. 134 | * - TEX: 000b (if non-shareable) or 010b (if shareable) 135 | * - Shareable or non-shareable 136 | * - Non-cacheable 137 | * - Bufferable (if shareable) or non-bufferable (if non-shareable) 138 | * 139 | * \param IsShareable Configures the device memory as shareable or non-shareable. 140 | */ 141 | #define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U)) 142 | 143 | /** 144 | * MPU Memory Access Attribute for normal memory. 145 | * - TEX: 1BBb (reflecting outer cacheability rules) 146 | * - Shareable or non-shareable 147 | * - Cacheable or non-cacheable (reflecting inner cacheability rules) 148 | * - Bufferable or non-bufferable (reflecting inner cacheability rules) 149 | * 150 | * \param OuterCp Configures the outer cache policy. 151 | * \param InnerCp Configures the inner cache policy. 152 | * \param IsShareable Configures the memory as shareable or non-shareable. 153 | */ 154 | #define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U)) 155 | 156 | /** 157 | * MPU Memory Access Attribute non-cacheable policy. 158 | */ 159 | #define ARM_MPU_CACHEP_NOCACHE 0U 160 | 161 | /** 162 | * MPU Memory Access Attribute write-back, write and read allocate policy. 163 | */ 164 | #define ARM_MPU_CACHEP_WB_WRA 1U 165 | 166 | /** 167 | * MPU Memory Access Attribute write-through, no write allocate policy. 168 | */ 169 | #define ARM_MPU_CACHEP_WT_NWA 2U 170 | 171 | /** 172 | * MPU Memory Access Attribute write-back, no write allocate policy. 173 | */ 174 | #define ARM_MPU_CACHEP_WB_NWA 3U 175 | 176 | 177 | /** 178 | * Struct for a single MPU Region 179 | */ 180 | typedef struct { 181 | uint32_t RBAR; //!< The region base address register value (RBAR) 182 | uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR 183 | } ARM_MPU_Region_t; 184 | 185 | /** Enable the MPU. 186 | * \param MPU_Control Default access permissions for unconfigured regions. 187 | */ 188 | __STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) 189 | { 190 | __DSB(); 191 | __ISB(); 192 | MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; 193 | #ifdef SCB_SHCSR_MEMFAULTENA_Msk 194 | SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; 195 | #endif 196 | } 197 | 198 | /** Disable the MPU. 199 | */ 200 | __STATIC_INLINE void ARM_MPU_Disable(void) 201 | { 202 | __DSB(); 203 | __ISB(); 204 | #ifdef SCB_SHCSR_MEMFAULTENA_Msk 205 | SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; 206 | #endif 207 | MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; 208 | } 209 | 210 | /** Clear and disable the given MPU region. 211 | * \param rnr Region number to be cleared. 212 | */ 213 | __STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) 214 | { 215 | MPU->RNR = rnr; 216 | MPU->RASR = 0U; 217 | } 218 | 219 | /** Configure an MPU region. 220 | * \param rbar Value for RBAR register. 221 | * \param rsar Value for RSAR register. 222 | */ 223 | __STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr) 224 | { 225 | MPU->RBAR = rbar; 226 | MPU->RASR = rasr; 227 | } 228 | 229 | /** Configure the given MPU region. 230 | * \param rnr Region number to be configured. 231 | * \param rbar Value for RBAR register. 232 | * \param rsar Value for RSAR register. 233 | */ 234 | __STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr) 235 | { 236 | MPU->RNR = rnr; 237 | MPU->RBAR = rbar; 238 | MPU->RASR = rasr; 239 | } 240 | 241 | /** Memcopy with strictly ordered memory access, e.g. for register targets. 242 | * \param dst Destination data is copied to. 243 | * \param src Source data is copied from. 244 | * \param len Amount of data words to be copied. 245 | */ 246 | __STATIC_INLINE void orderedCpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) 247 | { 248 | uint32_t i; 249 | for (i = 0U; i < len; ++i) 250 | { 251 | dst[i] = src[i]; 252 | } 253 | } 254 | 255 | /** Load the given number of MPU regions from a table. 256 | * \param table Pointer to the MPU configuration table. 257 | * \param cnt Amount of regions to be configured. 258 | */ 259 | __STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) 260 | { 261 | const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; 262 | while (cnt > MPU_TYPE_RALIASES) { 263 | orderedCpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize); 264 | table += MPU_TYPE_RALIASES; 265 | cnt -= MPU_TYPE_RALIASES; 266 | } 267 | orderedCpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize); 268 | } 269 | 270 | #endif 271 | -------------------------------------------------------------------------------- /src/startup_stm32l432kc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file startup_stm23l432kc.c 3 | * @author Andrew Loebs 4 | * @brief Startup file for the application 5 | * 6 | * Defines the vector table, initializes static variables, zeros bss, 7 | * calls stdlib init, and the main() function. 8 | * 9 | * Heavily influenced by Miro Samek's startup file used in lesson 19 10 | * of his "Modern Embedded Systems Programming Course". 11 | * @see https://www.state-machine.com/quickstart/ 12 | * 13 | */ 14 | 15 | #include 16 | 17 | // stack boundary 18 | extern int __stack_start__; 19 | extern int __stack_end__; 20 | 21 | // function prototypes 22 | void Default_Handler(void); 23 | void Reset_Handler(void); 24 | void assert_failed(char *file, uint32_t line); 25 | 26 | // weak aliases for each exception handler to the Default_Handler. 27 | void NMI_Handler(void) __attribute__((weak)); 28 | void HardFault_Handler(void) __attribute__((weak)); 29 | void MemManage_Handler(void) __attribute__((weak)); 30 | void BusFault_Handler(void) __attribute__((weak)); 31 | void UsageFault_Handler(void) __attribute__((weak)); 32 | 33 | void SVC_Handler(void) __attribute__((weak, alias("Default_Handler"))); 34 | void DebugMon_Handler(void) __attribute__((weak, alias("Default_Handler"))); 35 | void PendSV_Handler(void) __attribute__((weak, alias("Default_Handler"))); 36 | void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler"))); 37 | 38 | void GPIOPortA_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 39 | void WWDG_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 40 | void PVD_PVM_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 41 | void TAMP_STAMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 42 | void RTC_WKUP_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 43 | void FLASH_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 44 | void RCC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 45 | void EXTI0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 46 | void EXTI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 47 | void EXTI2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 48 | void EXTI3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 49 | void EXTI4_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 50 | void DMA1_Channel1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 51 | void DMA1_Channel2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 52 | void DMA1_Channel3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 53 | void DMA1_Channel4_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 54 | void DMA1_Channel5_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 55 | void DMA1_Channel6_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 56 | void DMA1_Channel7_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 57 | void ADC1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 58 | void CAN1_TX_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 59 | void CAN1_RX0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 60 | void CAN1_RX1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 61 | void CAN1_SCE_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 62 | void EXTI9_5_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 63 | void TIM1_BRK_TIM15_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 64 | void TIM1_UP_TIM16_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 65 | void TIM1_TRG_COM_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 66 | void TIM1_CC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 67 | void TIM2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 68 | void I2C1_EV_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 69 | void I2C1_ER_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 70 | void SPI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 71 | void USART1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 72 | void USART2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 73 | void EXTI15_10_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 74 | void RTC_Alarm_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 75 | void SPI3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 76 | void TIM6_DAC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 77 | void TIM7_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 78 | void DMA2_Channel1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 79 | void DMA2_Channel2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 80 | void DMA2_Channel3_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 81 | void DMA2_Channel4_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 82 | void DMA2_Channel5_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 83 | void COMP_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 84 | void LPTIM1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 85 | void LPTIM2_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 86 | void USB_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 87 | void DMA2_Channel6_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 88 | void DMA2_Channel7_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 89 | void LPUART1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 90 | void QUADSPI_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 91 | void I2C3_EV_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 92 | void I2C3_ER_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 93 | void SAI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 94 | void SWPMI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 95 | void TSC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 96 | void RNG_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 97 | void FPU_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 98 | void CRS_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); 99 | 100 | // vector table 101 | __attribute__((section(".isr_vector"))) int const g_pfnVectors[] = { 102 | (int)&__stack_end__, 103 | (int)&Reset_Handler, 104 | (int)&NMI_Handler, 105 | (int)&HardFault_Handler, 106 | (int)&MemManage_Handler, 107 | (int)&BusFault_Handler, 108 | (int)&UsageFault_Handler, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | (int)&SVC_Handler, 114 | (int)&DebugMon_Handler, 115 | 0, 116 | (int)&PendSV_Handler, 117 | (int)&SysTick_Handler, 118 | (int)&WWDG_IRQHandler, 119 | (int)&PVD_PVM_IRQHandler, 120 | (int)&TAMP_STAMP_IRQHandler, 121 | (int)&RTC_WKUP_IRQHandler, 122 | (int)&FLASH_IRQHandler, 123 | (int)&RCC_IRQHandler, 124 | (int)&EXTI0_IRQHandler, 125 | (int)&EXTI1_IRQHandler, 126 | (int)&EXTI2_IRQHandler, 127 | (int)&EXTI3_IRQHandler, 128 | (int)&EXTI4_IRQHandler, 129 | (int)&DMA1_Channel1_IRQHandler, 130 | (int)&DMA1_Channel2_IRQHandler, 131 | (int)&DMA1_Channel3_IRQHandler, 132 | (int)&DMA1_Channel4_IRQHandler, 133 | (int)&DMA1_Channel5_IRQHandler, 134 | (int)&DMA1_Channel6_IRQHandler, 135 | (int)&DMA1_Channel7_IRQHandler, 136 | (int)&ADC1_IRQHandler, 137 | (int)&CAN1_TX_IRQHandler, 138 | (int)&CAN1_RX0_IRQHandler, 139 | (int)&CAN1_RX1_IRQHandler, 140 | (int)&CAN1_SCE_IRQHandler, 141 | (int)&EXTI9_5_IRQHandler, 142 | (int)&TIM1_BRK_TIM15_IRQHandler, 143 | (int)&TIM1_UP_TIM16_IRQHandler, 144 | (int)&TIM1_TRG_COM_IRQHandler, 145 | (int)&TIM1_CC_IRQHandler, 146 | (int)&TIM2_IRQHandler, 147 | 0, 148 | 0, 149 | (int)&I2C1_EV_IRQHandler, 150 | (int)&I2C1_ER_IRQHandler, 151 | 0, 152 | 0, 153 | (int)&SPI1_IRQHandler, 154 | 0, 155 | (int)&USART1_IRQHandler, 156 | (int)&USART2_IRQHandler, 157 | 0, 158 | (int)&EXTI15_10_IRQHandler, 159 | (int)&RTC_Alarm_IRQHandler, 160 | 0, 161 | 0, 162 | 0, 163 | 0, 164 | 0, 165 | 0, 166 | 0, 167 | 0, 168 | 0, 169 | (int)&SPI3_IRQHandler, 170 | 0, 171 | 0, 172 | (int)&TIM6_DAC_IRQHandler, 173 | (int)&TIM7_IRQHandler, 174 | (int)&DMA2_Channel1_IRQHandler, 175 | (int)&DMA2_Channel2_IRQHandler, 176 | (int)&DMA2_Channel3_IRQHandler, 177 | (int)&DMA2_Channel4_IRQHandler, 178 | (int)&DMA2_Channel5_IRQHandler, 179 | 0, 180 | 0, 181 | 0, 182 | (int)&COMP_IRQHandler, 183 | (int)&LPTIM1_IRQHandler, 184 | (int)&LPTIM2_IRQHandler, 185 | (int)&USB_IRQHandler, 186 | (int)&DMA2_Channel6_IRQHandler, 187 | (int)&DMA2_Channel7_IRQHandler, 188 | (int)&LPUART1_IRQHandler, 189 | (int)&QUADSPI_IRQHandler, 190 | (int)&I2C3_EV_IRQHandler, 191 | (int)&I2C3_ER_IRQHandler, 192 | (int)&SAI1_IRQHandler, 193 | 0, 194 | (int)&SWPMI1_IRQHandler, 195 | (int)&TSC_IRQHandler, 196 | 0, 197 | 0, 198 | (int)&RNG_IRQHandler, 199 | (int)&FPU_IRQHandler, 200 | (int)&CRS_IRQHandler, 201 | }; 202 | 203 | // reset handler 204 | void Reset_Handler(void) 205 | { 206 | extern void SystemInit(void); 207 | extern int __libc_init_array(void); 208 | extern int main(void); 209 | 210 | extern unsigned __data_start; 211 | extern unsigned __data_end__; 212 | extern unsigned const __data_load; 213 | extern unsigned __bss_start__; 214 | extern unsigned __bss_end__; 215 | 216 | SystemInit(); 217 | 218 | unsigned const *src; 219 | unsigned *dst; 220 | // copy the data segment initializers from flash to RAM 221 | src = &__data_load; 222 | for (dst = &__data_start; dst < &__data_end__; ++dst, ++src) { 223 | *dst = *src; 224 | } 225 | 226 | // zero fill the .bss segment in RAM 227 | for (dst = &__bss_start__; dst < &__bss_end__; ++dst) { 228 | *dst = 0; 229 | } 230 | 231 | __libc_init_array(); 232 | (void)main(); 233 | 234 | // we should never get here 235 | assert_failed("Reset_Handler", __LINE__); 236 | } 237 | 238 | void assert_failed(char *file, uint32_t line) 239 | { 240 | // TODO: print file & line 241 | while (1) { 242 | } 243 | } 244 | 245 | // exception handlers 246 | __attribute__((naked)) void NMI_Handler(void); 247 | void NMI_Handler(void) 248 | { 249 | __asm volatile(" ldr r0,=str_nmi\n\t" 250 | " mov r1,#1\n\t" 251 | " b assert_failed\n\t" 252 | "str_nmi: .asciz \"NMI\"\n\t" 253 | " .align 2\n\t"); 254 | } 255 | __attribute__((naked)) void MemManage_Handler(void); 256 | void MemManage_Handler(void) 257 | { 258 | __asm volatile(" ldr r0,=str_mem\n\t" 259 | " mov r1,#1\n\t" 260 | " b assert_failed\n\t" 261 | "str_mem: .asciz \"MemManage\"\n\t" 262 | " .align 2\n\t"); 263 | } 264 | __attribute__((naked)) void HardFault_Handler(void); 265 | void HardFault_Handler(void) 266 | { 267 | __asm volatile(" ldr r0,=str_hrd\n\t" 268 | " mov r1,#1\n\t" 269 | " b assert_failed\n\t" 270 | "str_hrd: .asciz \"HardFault\"\n\t" 271 | " .align 2\n\t"); 272 | } 273 | __attribute__((naked)) void BusFault_Handler(void); 274 | void BusFault_Handler(void) 275 | { 276 | __asm volatile(" ldr r0,=str_bus\n\t" 277 | " mov r1,#1\n\t" 278 | " b assert_failed\n\t" 279 | "str_bus: .asciz \"BusFault\"\n\t" 280 | " .align 2\n\t"); 281 | } 282 | __attribute__((naked)) void UsageFault_Handler(void); 283 | void UsageFault_Handler(void) 284 | { 285 | __asm volatile(" ldr r0,=str_usage\n\t" 286 | " mov r1,#1\n\t" 287 | " b assert_failed\n\t" 288 | "str_usage: .asciz \"UsageFault\"\n\t" 289 | " .align 2\n\t"); 290 | } 291 | __attribute__((naked)) void Default_Handler(void); 292 | void Default_Handler(void) 293 | { 294 | __asm volatile(" ldr r0,=str_dflt\n\t" 295 | " mov r1,#1\n\t" 296 | " b assert_failed\n\t" 297 | "str_dflt: .asciz \"Default\"\n\t" 298 | " .align 2\n\t"); 299 | } 300 | -------------------------------------------------------------------------------- /src/fatfs/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs Functional Configurations 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define FFCONF_DEF 86606 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Function Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define FF_FS_READONLY 0 12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 13 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 15 | / and optional writing functions as well. */ 16 | 17 | #define FF_FS_MINIMIZE 0 18 | /* This option defines minimization level to remove some basic API functions. 19 | / 20 | / 0: Basic functions are fully enabled. 21 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 22 | / are removed. 23 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 24 | / 3: f_lseek() function is removed in addition to 2. */ 25 | 26 | #define FF_USE_STRFUNC 0 27 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). 28 | / 29 | / 0: Disable string functions. 30 | / 1: Enable without LF-CRLF conversion. 31 | / 2: Enable with LF-CRLF conversion. */ 32 | 33 | #define FF_USE_FIND 0 34 | /* This option switches filtered directory read functions, f_findfirst() and 35 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 36 | 37 | #define FF_USE_MKFS 1 38 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 39 | 40 | #define FF_USE_FASTSEEK 0 41 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 42 | 43 | #define FF_USE_EXPAND 0 44 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 45 | 46 | #define FF_USE_CHMOD 0 47 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 48 | / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ 49 | 50 | #define FF_USE_LABEL 0 51 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 52 | / (0:Disable or 1:Enable) */ 53 | 54 | #define FF_USE_FORWARD 0 55 | /* This option switches f_forward() function. (0:Disable or 1:Enable) */ 56 | 57 | /*---------------------------------------------------------------------------/ 58 | / Locale and Namespace Configurations 59 | /---------------------------------------------------------------------------*/ 60 | 61 | #define FF_CODE_PAGE 437 62 | /* This option specifies the OEM code page to be used on the target system. 63 | / Incorrect code page setting can cause a file open failure. 64 | / 65 | / 437 - U.S. 66 | / 720 - Arabic 67 | / 737 - Greek 68 | / 771 - KBL 69 | / 775 - Baltic 70 | / 850 - Latin 1 71 | / 852 - Latin 2 72 | / 855 - Cyrillic 73 | / 857 - Turkish 74 | / 860 - Portuguese 75 | / 861 - Icelandic 76 | / 862 - Hebrew 77 | / 863 - Canadian French 78 | / 864 - Arabic 79 | / 865 - Nordic 80 | / 866 - Russian 81 | / 869 - Greek 2 82 | / 932 - Japanese (DBCS) 83 | / 936 - Simplified Chinese (DBCS) 84 | / 949 - Korean (DBCS) 85 | / 950 - Traditional Chinese (DBCS) 86 | / 0 - Include all code pages above and configured by f_setcp() 87 | */ 88 | 89 | #define FF_USE_LFN 0 90 | #define FF_MAX_LFN 255 91 | /* The FF_USE_LFN switches the support for LFN (long file name). 92 | / 93 | / 0: Disable LFN. FF_MAX_LFN has no effect. 94 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 95 | / 2: Enable LFN with dynamic working buffer on the STACK. 96 | / 3: Enable LFN with dynamic working buffer on the HEAP. 97 | / 98 | / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function 99 | / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and 100 | / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. 101 | / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can 102 | / be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN 103 | / specification. 104 | / When use stack for the working buffer, take care on stack overflow. When use heap 105 | / memory for the working buffer, memory management functions, ff_memalloc() and 106 | / ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ 107 | 108 | #define FF_LFN_UNICODE 0 109 | /* This option switches the character encoding on the API when LFN is enabled. 110 | / 111 | / 0: ANSI/OEM in current CP (TCHAR = char) 112 | / 1: Unicode in UTF-16 (TCHAR = WCHAR) 113 | / 2: Unicode in UTF-8 (TCHAR = char) 114 | / 3: Unicode in UTF-32 (TCHAR = DWORD) 115 | / 116 | / Also behavior of string I/O functions will be affected by this option. 117 | / When LFN is not enabled, this option has no effect. */ 118 | 119 | #define FF_LFN_BUF 255 120 | #define FF_SFN_BUF 12 121 | /* This set of options defines size of file name members in the FILINFO structure 122 | / which is used to read out directory items. These values should be suffcient for 123 | / the file names to read. The maximum possible length of the read file name depends 124 | / on character encoding. When LFN is not enabled, these options have no effect. */ 125 | 126 | #define FF_STRF_ENCODE 3 127 | /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), 128 | / f_putc(), f_puts and f_printf() convert the character encoding in it. 129 | / This option selects assumption of character encoding ON THE FILE to be 130 | / read/written via those functions. 131 | / 132 | / 0: ANSI/OEM in current CP 133 | / 1: Unicode in UTF-16LE 134 | / 2: Unicode in UTF-16BE 135 | / 3: Unicode in UTF-8 136 | */ 137 | 138 | #define FF_FS_RPATH 0 139 | /* This option configures support for relative path. 140 | / 141 | / 0: Disable relative path and remove related functions. 142 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 143 | / 2: f_getcwd() function is available in addition to 1. 144 | */ 145 | 146 | /*---------------------------------------------------------------------------/ 147 | / Drive/Volume Configurations 148 | /---------------------------------------------------------------------------*/ 149 | 150 | #define FF_VOLUMES 1 151 | /* Number of volumes (logical drives) to be used. (1-10) */ 152 | 153 | #define FF_STR_VOLUME_ID 0 154 | #define FF_VOLUME_STRS "RAM", "NAND", "CF", "SD", "SD2", "USB", "USB2", "USB3" 155 | /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. 156 | / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive 157 | / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each 158 | / logical drives. Number of items must not be less than FF_VOLUMES. Valid 159 | / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are 160 | / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is 161 | / not defined, a user defined volume string table needs to be defined as: 162 | / 163 | / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... 164 | */ 165 | 166 | #define FF_MULTI_PARTITION 0 167 | /* This option switches support for multiple volumes on the physical drive. 168 | / By default (0), each logical drive number is bound to the same physical drive 169 | / number and only an FAT volume found on the physical drive will be mounted. 170 | / When this function is enabled (1), each logical drive number can be bound to 171 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 172 | / funciton will be available. */ 173 | 174 | #define FF_MIN_SS 2048 175 | #define FF_MAX_SS 2048 176 | /* This set of options configures the range of sector size to be supported. (512, 177 | / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and 178 | / harddisk. But a larger value may be required for on-board flash memory and some 179 | / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured 180 | / for variable sector size mode and disk_ioctl() function needs to implement 181 | / GET_SECTOR_SIZE command. */ 182 | 183 | #define FF_LBA64 0 184 | /* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) 185 | / To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ 186 | 187 | #define FF_MIN_GPT 0x100000000 188 | /* Minimum number of sectors to switch GPT format to create partition in f_mkfs and 189 | / f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ 190 | 191 | #define FF_USE_TRIM 0 192 | /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) 193 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 194 | / disk_ioctl() function. */ 195 | 196 | /*---------------------------------------------------------------------------/ 197 | / System Configurations 198 | /---------------------------------------------------------------------------*/ 199 | 200 | #define FF_FS_TINY 0 201 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 202 | / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. 203 | / Instead of private sector buffer eliminated from the file object, common sector 204 | / buffer in the filesystem object (FATFS) is used for the file data transfer. */ 205 | 206 | #define FF_FS_EXFAT 0 207 | /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) 208 | / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) 209 | / Note that enabling exFAT discards ANSI C (C89) compatibility. */ 210 | 211 | #define FF_FS_NORTC 1 212 | #define FF_NORTC_MON 1 213 | #define FF_NORTC_MDAY 1 214 | #define FF_NORTC_YEAR 2020 215 | /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have 216 | / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable 217 | / the timestamp function. Every object modified by FatFs will have a fixed timestamp 218 | / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. 219 | / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be 220 | / added to the project to read current time form real-time clock. FF_NORTC_MON, 221 | / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. 222 | / These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ 223 | 224 | #define FF_FS_NOFSINFO 0 225 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 226 | / option, and f_getfree() function at first time after volume mount will force 227 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 228 | / 229 | / bit0=0: Use free cluster count in the FSINFO if available. 230 | / bit0=1: Do not trust free cluster count in the FSINFO. 231 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 232 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 233 | */ 234 | 235 | #define FF_FS_LOCK 0 236 | /* The option FF_FS_LOCK switches file lock function to control duplicated file open 237 | / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY 238 | / is 1. 239 | / 240 | / 0: Disable file lock function. To avoid volume corruption, application program 241 | / should avoid illegal open, remove and rename to the open objects. 242 | / >0: Enable file lock function. The value defines how many files/sub-directories 243 | / can be opened simultaneously under file lock control. Note that the file 244 | / lock control is independent of re-entrancy. */ 245 | 246 | /* #include // O/S definitions */ 247 | #define FF_FS_REENTRANT 0 248 | #define FF_FS_TIMEOUT 1000 249 | #define FF_SYNC_t HANDLE 250 | /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 251 | / module itself. Note that regardless of this option, file access to different 252 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 253 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 254 | / to the same volume is under control of this function. 255 | / 256 | / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. 257 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 258 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 259 | / function, must be added to the project. Samples are available in 260 | / option/syscall.c. 261 | / 262 | / The FF_FS_TIMEOUT defines timeout period in unit of time tick. 263 | / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 264 | / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be 265 | / included somewhere in the scope of ff.h. */ 266 | 267 | /*--- End of configuration options ---*/ 268 | -------------------------------------------------------------------------------- /src/st/ll/stm32l4xx_ll_utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32l4xx_ll_utils.h 4 | * @author MCD Application Team 5 | * @brief Header file of UTILS LL module. 6 | @verbatim 7 | ============================================================================== 8 | ##### How to use this driver ##### 9 | ============================================================================== 10 | [..] 11 | The LL UTILS driver contains a set of generic APIs that can be 12 | used by user: 13 | (+) Device electronic signature 14 | (+) Timing functions 15 | (+) PLL configuration functions 16 | 17 | @endverbatim 18 | ****************************************************************************** 19 | * @attention 20 | * 21 | *

© Copyright (c) 2017 STMicroelectronics. 22 | * All rights reserved.

23 | * 24 | * This software component is licensed by ST under BSD 3-Clause license, 25 | * the "License"; You may not use this file except in compliance with the 26 | * License. You may obtain a copy of the License at: 27 | * opensource.org/licenses/BSD-3-Clause 28 | * 29 | ****************************************************************************** 30 | */ 31 | 32 | /* Define to prevent recursive inclusion -------------------------------------*/ 33 | #ifndef STM32L4xx_LL_UTILS_H 34 | #define STM32L4xx_LL_UTILS_H 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /* Includes ------------------------------------------------------------------*/ 41 | #include "stm32l4xx.h" 42 | 43 | /** @addtogroup STM32L4xx_LL_Driver 44 | * @{ 45 | */ 46 | 47 | /** @defgroup UTILS_LL UTILS 48 | * @{ 49 | */ 50 | 51 | /* Private types -------------------------------------------------------------*/ 52 | /* Private variables ---------------------------------------------------------*/ 53 | 54 | /* Private constants ---------------------------------------------------------*/ 55 | /** @defgroup UTILS_LL_Private_Constants UTILS Private Constants 56 | * @{ 57 | */ 58 | 59 | /* Max delay can be used in LL_mDelay */ 60 | #define LL_MAX_DELAY 0xFFFFFFFFU 61 | 62 | /** 63 | * @brief Unique device ID register base address 64 | */ 65 | #define UID_BASE_ADDRESS UID_BASE 66 | 67 | /** 68 | * @brief Flash size data register base address 69 | */ 70 | #define FLASHSIZE_BASE_ADDRESS FLASHSIZE_BASE 71 | 72 | /** 73 | * @brief Package data register base address 74 | */ 75 | #define PACKAGE_BASE_ADDRESS PACKAGE_BASE 76 | 77 | /** 78 | * @} 79 | */ 80 | 81 | /* Private macros ------------------------------------------------------------*/ 82 | /** @defgroup UTILS_LL_Private_Macros UTILS Private Macros 83 | * @{ 84 | */ 85 | /** 86 | * @} 87 | */ 88 | /* Exported types ------------------------------------------------------------*/ 89 | /** @defgroup UTILS_LL_ES_INIT UTILS Exported structures 90 | * @{ 91 | */ 92 | /** 93 | * @brief UTILS PLL structure definition 94 | */ 95 | typedef struct 96 | { 97 | uint32_t PLLM; /*!< Division factor for PLL VCO input clock. 98 | This parameter can be a value of @ref RCC_LL_EC_PLLM_DIV 99 | 100 | This feature can be modified afterwards using unitary function 101 | @ref LL_RCC_PLL_ConfigDomain_SYS(). */ 102 | 103 | uint32_t PLLN; /*!< Multiplication factor for PLL VCO output clock. 104 | This parameter must be a number between Min_Data = 8 and Max_Data = 86 105 | 106 | This feature can be modified afterwards using unitary function 107 | @ref LL_RCC_PLL_ConfigDomain_SYS(). */ 108 | 109 | uint32_t PLLR; /*!< Division for the main system clock. 110 | This parameter can be a value of @ref RCC_LL_EC_PLLR_DIV 111 | 112 | This feature can be modified afterwards using unitary function 113 | @ref LL_RCC_PLL_ConfigDomain_SYS(). */ 114 | } LL_UTILS_PLLInitTypeDef; 115 | 116 | /** 117 | * @brief UTILS System, AHB and APB buses clock configuration structure definition 118 | */ 119 | typedef struct 120 | { 121 | uint32_t AHBCLKDivider; /*!< The AHB clock (HCLK) divider. This clock is derived from the system clock (SYSCLK). 122 | This parameter can be a value of @ref RCC_LL_EC_SYSCLK_DIV 123 | 124 | This feature can be modified afterwards using unitary function 125 | @ref LL_RCC_SetAHBPrescaler(). */ 126 | 127 | uint32_t APB1CLKDivider; /*!< The APB1 clock (PCLK1) divider. This clock is derived from the AHB clock (HCLK). 128 | This parameter can be a value of @ref RCC_LL_EC_APB1_DIV 129 | 130 | This feature can be modified afterwards using unitary function 131 | @ref LL_RCC_SetAPB1Prescaler(). */ 132 | 133 | uint32_t APB2CLKDivider; /*!< The APB2 clock (PCLK2) divider. This clock is derived from the AHB clock (HCLK). 134 | This parameter can be a value of @ref RCC_LL_EC_APB2_DIV 135 | 136 | This feature can be modified afterwards using unitary function 137 | @ref LL_RCC_SetAPB2Prescaler(). */ 138 | 139 | } LL_UTILS_ClkInitTypeDef; 140 | 141 | /** 142 | * @} 143 | */ 144 | 145 | /* Exported constants --------------------------------------------------------*/ 146 | /** @defgroup UTILS_LL_Exported_Constants UTILS Exported Constants 147 | * @{ 148 | */ 149 | 150 | /** @defgroup UTILS_EC_HSE_BYPASS HSE Bypass activation 151 | * @{ 152 | */ 153 | #define LL_UTILS_HSEBYPASS_OFF 0x00000000U /*!< HSE Bypass is not enabled */ 154 | #define LL_UTILS_HSEBYPASS_ON 0x00000001U /*!< HSE Bypass is enabled */ 155 | /** 156 | * @} 157 | */ 158 | 159 | /** @defgroup UTILS_EC_PACKAGETYPE PACKAGE TYPE 160 | * @{ 161 | */ 162 | #define LL_UTILS_PACKAGETYPE_LQFP64 0x00000000U /*!< LQFP64 package type */ 163 | #define LL_UTILS_PACKAGETYPE_WLCSP64 0x00000001U /*!< WLCSP64 package type */ 164 | #define LL_UTILS_PACKAGETYPE_LQFP100 0x00000002U /*!< LQFP100 package type */ 165 | #define LL_UTILS_PACKAGETYPE_BGA132 0x00000003U /*!< BGA132 package type */ 166 | #define LL_UTILS_PACKAGETYPE_LQFP144_CSP72 0x00000004U /*!< LQFP144, WLCSP81 or WLCSP72 package type */ 167 | #define LL_UTILS_PACKAGETYPE_UFQFPN32 0x00000008U /*!< UFQFPN32 package type */ 168 | #define LL_UTILS_PACKAGETYPE_UFQFPN48 0x0000000AU /*!< UFQFPN48 package type */ 169 | #define LL_UTILS_PACKAGETYPE_LQFP48 0x0000000BU /*!< LQFP48 package type */ 170 | #define LL_UTILS_PACKAGETYPE_WLCSP49 0x0000000CU /*!< WLCSP49 package type */ 171 | #define LL_UTILS_PACKAGETYPE_UFBGA64 0x0000000DU /*!< UFBGA64 package type */ 172 | #define LL_UTILS_PACKAGETYPE_UFBGA100 0x0000000EU /*!< UFBGA100 package type */ 173 | #define LL_UTILS_PACKAGETYPE_UFBGA169 0x00000010U /*!< UFBGA169 package type */ 174 | #define LL_UTILS_PACKAGETYPE_LQFP100_DSI 0x00000012U /*!< LQFP100 with DSI package type */ 175 | #define LL_UTILS_PACKAGETYPE_WLCSP144_DSI 0x00000013U /*!< WLCSP144 with DSI package type */ 176 | #define LL_UTILS_PACKAGETYPE_UFBGA144_DSI 0x00000013U /*!< UFBGA144 with DSI package type */ 177 | #define LL_UTILS_PACKAGETYPE_UFBGA169_DSI 0x00000014U /*!< UFBGA169 with DSI package type */ 178 | #define LL_UTILS_PACKAGETYPE_LQFP144_DSI 0x00000015U /*!< LQFP144 with DSI package type */ 179 | /** 180 | * @} 181 | */ 182 | 183 | /** 184 | * @} 185 | */ 186 | 187 | /* Exported macro ------------------------------------------------------------*/ 188 | 189 | /* Exported functions --------------------------------------------------------*/ 190 | /** @defgroup UTILS_LL_Exported_Functions UTILS Exported Functions 191 | * @{ 192 | */ 193 | 194 | /** @defgroup UTILS_EF_DEVICE_ELECTRONIC_SIGNATURE DEVICE ELECTRONIC SIGNATURE 195 | * @{ 196 | */ 197 | 198 | /** 199 | * @brief Get Word0 of the unique device identifier (UID based on 96 bits) 200 | * @retval UID[31:0]: X and Y coordinates on the wafer expressed in BCD format 201 | */ 202 | __STATIC_INLINE uint32_t LL_GetUID_Word0(void) 203 | { 204 | return (uint32_t)(READ_REG(*((uint32_t *)UID_BASE_ADDRESS))); 205 | } 206 | 207 | /** 208 | * @brief Get Word1 of the unique device identifier (UID based on 96 bits) 209 | * @retval UID[63:32]: Wafer number (UID[39:32]) & LOT_NUM[23:0] (UID[63:40]) 210 | */ 211 | __STATIC_INLINE uint32_t LL_GetUID_Word1(void) 212 | { 213 | return (uint32_t)(READ_REG(*((uint32_t *)(UID_BASE_ADDRESS + 4U)))); 214 | } 215 | 216 | /** 217 | * @brief Get Word2 of the unique device identifier (UID based on 96 bits) 218 | * @retval UID[95:64]: Lot number (ASCII encoded) - LOT_NUM[55:24] 219 | */ 220 | __STATIC_INLINE uint32_t LL_GetUID_Word2(void) 221 | { 222 | return (uint32_t)(READ_REG(*((uint32_t *)(UID_BASE_ADDRESS + 8U)))); 223 | } 224 | 225 | /** 226 | * @brief Get Flash memory size 227 | * @note This bitfield indicates the size of the device Flash memory expressed in 228 | * Kbytes. As an example, 0x040 corresponds to 64 Kbytes. 229 | * @retval FLASH_SIZE[15:0]: Flash memory size 230 | */ 231 | __STATIC_INLINE uint32_t LL_GetFlashSize(void) 232 | { 233 | return (uint32_t)(READ_REG(*((uint32_t *)FLASHSIZE_BASE_ADDRESS)) & 0xFFFFU); 234 | } 235 | 236 | /** 237 | * @brief Get Package type 238 | * @retval Returned value can be one of the following values: 239 | * @arg @ref LL_UTILS_PACKAGETYPE_LQFP64 (*) 240 | * @arg @ref LL_UTILS_PACKAGETYPE_LQFP100 (*) 241 | * @arg @ref LL_UTILS_PACKAGETYPE_BGA132 (*) 242 | * @arg @ref LL_UTILS_PACKAGETYPE_LQFP144_CSP72 (*) 243 | * @arg @ref LL_UTILS_PACKAGETYPE_UFQFPN32 (*) 244 | * @arg @ref LL_UTILS_PACKAGETYPE_UFQFPN48 (*) 245 | * @arg @ref LL_UTILS_PACKAGETYPE_LQFP48 (*) 246 | * @arg @ref LL_UTILS_PACKAGETYPE_WLCSP49 (*) 247 | * @arg @ref LL_UTILS_PACKAGETYPE_UFBGA64 (*) 248 | * @arg @ref LL_UTILS_PACKAGETYPE_UFBGA100 (*) 249 | * @arg @ref LL_UTILS_PACKAGETYPE_UFBGA169 (*) 250 | * @arg @ref LL_UTILS_PACKAGETYPE_LQFP100_DSI (*) 251 | * @arg @ref LL_UTILS_PACKAGETYPE_WLCSP144_DSI (*) 252 | * @arg @ref LL_UTILS_PACKAGETYPE_UFBGA144_DSI (*) 253 | * @arg @ref LL_UTILS_PACKAGETYPE_UFBGA169_DSI (*) 254 | * @arg @ref LL_UTILS_PACKAGETYPE_LQFP144_DSI (*) 255 | * 256 | * (*) value not defined in all devices. 257 | */ 258 | __STATIC_INLINE uint32_t LL_GetPackageType(void) 259 | { 260 | return (uint32_t)(READ_REG(*((uint32_t *)PACKAGE_BASE_ADDRESS)) & 0x1FU); 261 | } 262 | 263 | /** 264 | * @} 265 | */ 266 | 267 | /** @defgroup UTILS_LL_EF_DELAY DELAY 268 | * @{ 269 | */ 270 | 271 | /** 272 | * @brief This function configures the Cortex-M SysTick source of the time base. 273 | * @param HCLKFrequency HCLK frequency in Hz (can be calculated thanks to RCC helper macro) 274 | * @note When a RTOS is used, it is recommended to avoid changing the SysTick 275 | * configuration by calling this function, for a delay use rather osDelay RTOS service. 276 | * @param Ticks Number of ticks 277 | * @retval None 278 | */ 279 | __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks) 280 | { 281 | /* Configure the SysTick to have interrupt in 1ms time base */ 282 | SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */ 283 | SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ 284 | SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 285 | SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */ 286 | } 287 | 288 | void LL_Init1msTick(uint32_t HCLKFrequency); 289 | void LL_mDelay(uint32_t Delay); 290 | 291 | /** 292 | * @} 293 | */ 294 | 295 | /** @defgroup UTILS_EF_SYSTEM SYSTEM 296 | * @{ 297 | */ 298 | 299 | void LL_SetSystemCoreClock(uint32_t HCLKFrequency); 300 | ErrorStatus LL_PLL_ConfigSystemClock_MSI(LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, 301 | LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct); 302 | ErrorStatus LL_PLL_ConfigSystemClock_HSI(LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, 303 | LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct); 304 | ErrorStatus LL_PLL_ConfigSystemClock_HSE(uint32_t HSEFrequency, uint32_t HSEBypass, 305 | LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct); 306 | 307 | /** 308 | * @} 309 | */ 310 | 311 | /** 312 | * @} 313 | */ 314 | 315 | /** 316 | * @} 317 | */ 318 | 319 | /** 320 | * @} 321 | */ 322 | 323 | #ifdef __cplusplus 324 | } 325 | #endif 326 | 327 | #endif /* STM32L4xx_LL_UTILS_H */ 328 | 329 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 330 | -------------------------------------------------------------------------------- /src/st/system_stm32l4xx.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file system_stm32l4xx.c 4 | * @author MCD Application Team 5 | * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File 6 | * 7 | * This file provides two functions and one global variable to be called from 8 | * user application: 9 | * - SystemInit(): This function is called at startup just after reset and 10 | * before branch to main program. This call is made inside 11 | * the "startup_stm32l4xx.s" file. 12 | * 13 | * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used 14 | * by the user application to setup the SysTick 15 | * timer or configure other parameters. 16 | * 17 | * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must 18 | * be called whenever the core clock is changed 19 | * during program execution. 20 | * 21 | * After each device reset the MSI (4 MHz) is used as system clock source. 22 | * Then SystemInit() function is called, in "startup_stm32l4xx.s" file, to 23 | * configure the system clock before to branch to main program. 24 | * 25 | * This file configures the system clock as follows: 26 | *============================================================================= 27 | *----------------------------------------------------------------------------- 28 | * System Clock source | MSI 29 | *----------------------------------------------------------------------------- 30 | * SYSCLK(Hz) | 4000000 31 | *----------------------------------------------------------------------------- 32 | * HCLK(Hz) | 4000000 33 | *----------------------------------------------------------------------------- 34 | * AHB Prescaler | 1 35 | *----------------------------------------------------------------------------- 36 | * APB1 Prescaler | 1 37 | *----------------------------------------------------------------------------- 38 | * APB2 Prescaler | 1 39 | *----------------------------------------------------------------------------- 40 | * PLL_M | 1 41 | *----------------------------------------------------------------------------- 42 | * PLL_N | 8 43 | *----------------------------------------------------------------------------- 44 | * PLL_P | 7 45 | *----------------------------------------------------------------------------- 46 | * PLL_Q | 2 47 | *----------------------------------------------------------------------------- 48 | * PLL_R | 2 49 | *----------------------------------------------------------------------------- 50 | * PLLSAI1_P | NA 51 | *----------------------------------------------------------------------------- 52 | * PLLSAI1_Q | NA 53 | *----------------------------------------------------------------------------- 54 | * PLLSAI1_R | NA 55 | *----------------------------------------------------------------------------- 56 | * PLLSAI2_P | NA 57 | *----------------------------------------------------------------------------- 58 | * PLLSAI2_Q | NA 59 | *----------------------------------------------------------------------------- 60 | * PLLSAI2_R | NA 61 | *----------------------------------------------------------------------------- 62 | * Require 48MHz for USB OTG FS, | Disabled 63 | * SDIO and RNG clock | 64 | *----------------------------------------------------------------------------- 65 | *============================================================================= 66 | ****************************************************************************** 67 | * @attention 68 | * 69 | *

© Copyright (c) 2017 STMicroelectronics. 70 | * All rights reserved.

71 | * 72 | * This software component is licensed by ST under BSD 3-Clause license, 73 | * the "License"; You may not use this file except in compliance with the 74 | * License. You may obtain a copy of the License at: 75 | * opensource.org/licenses/BSD-3-Clause 76 | * 77 | ****************************************************************************** 78 | */ 79 | 80 | /** @addtogroup CMSIS 81 | * @{ 82 | */ 83 | 84 | /** @addtogroup stm32l4xx_system 85 | * @{ 86 | */ 87 | 88 | /** @addtogroup STM32L4xx_System_Private_Includes 89 | * @{ 90 | */ 91 | 92 | #include "stm32l4xx.h" 93 | 94 | #if !defined (HSE_VALUE) 95 | #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ 96 | #endif /* HSE_VALUE */ 97 | 98 | #if !defined (MSI_VALUE) 99 | #define MSI_VALUE 4000000U /*!< Value of the Internal oscillator in Hz*/ 100 | #endif /* MSI_VALUE */ 101 | 102 | #if !defined (HSI_VALUE) 103 | #define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/ 104 | #endif /* HSI_VALUE */ 105 | 106 | /** 107 | * @} 108 | */ 109 | 110 | /** @addtogroup STM32L4xx_System_Private_TypesDefinitions 111 | * @{ 112 | */ 113 | 114 | /** 115 | * @} 116 | */ 117 | 118 | /** @addtogroup STM32L4xx_System_Private_Defines 119 | * @{ 120 | */ 121 | 122 | /************************* Miscellaneous Configuration ************************/ 123 | /*!< Uncomment the following line if you need to relocate your vector Table in 124 | Internal SRAM. */ 125 | /* #define VECT_TAB_SRAM */ 126 | #define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. 127 | This value must be a multiple of 0x200. */ 128 | /******************************************************************************/ 129 | /** 130 | * @} 131 | */ 132 | 133 | /** @addtogroup STM32L4xx_System_Private_Macros 134 | * @{ 135 | */ 136 | 137 | /** 138 | * @} 139 | */ 140 | 141 | /** @addtogroup STM32L4xx_System_Private_Variables 142 | * @{ 143 | */ 144 | /* The SystemCoreClock variable is updated in three ways: 145 | 1) by calling CMSIS function SystemCoreClockUpdate() 146 | 2) by calling HAL API function HAL_RCC_GetHCLKFreq() 147 | 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency 148 | Note: If you use this function to configure the system clock; then there 149 | is no need to call the 2 first functions listed above, since SystemCoreClock 150 | variable is updated automatically. 151 | */ 152 | uint32_t SystemCoreClock = 4000000U; 153 | 154 | const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U}; 155 | const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U}; 156 | const uint32_t MSIRangeTable[12] = {100000U, 200000U, 400000U, 800000U, 1000000U, 2000000U, \ 157 | 4000000U, 8000000U, 16000000U, 24000000U, 32000000U, 48000000U}; 158 | /** 159 | * @} 160 | */ 161 | 162 | /** @addtogroup STM32L4xx_System_Private_FunctionPrototypes 163 | * @{ 164 | */ 165 | 166 | /** 167 | * @} 168 | */ 169 | 170 | /** @addtogroup STM32L4xx_System_Private_Functions 171 | * @{ 172 | */ 173 | 174 | /** 175 | * @brief Setup the microcontroller system. 176 | * @param None 177 | * @retval None 178 | */ 179 | 180 | void SystemInit(void) 181 | { 182 | /* FPU settings ------------------------------------------------------------*/ 183 | #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) 184 | SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ 185 | #endif 186 | 187 | /* Reset the RCC clock configuration to the default reset state ------------*/ 188 | /* Set MSION bit */ 189 | RCC->CR |= RCC_CR_MSION; 190 | 191 | /* Reset CFGR register */ 192 | RCC->CFGR = 0x00000000U; 193 | 194 | /* Reset HSEON, CSSON , HSION, and PLLON bits */ 195 | RCC->CR &= 0xEAF6FFFFU; 196 | 197 | /* Reset PLLCFGR register */ 198 | RCC->PLLCFGR = 0x00001000U; 199 | 200 | /* Reset HSEBYP bit */ 201 | RCC->CR &= 0xFFFBFFFFU; 202 | 203 | /* Disable all interrupts */ 204 | RCC->CIER = 0x00000000U; 205 | 206 | /* Configure the Vector Table location add offset address ------------------*/ 207 | #ifdef VECT_TAB_SRAM 208 | SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ 209 | #else 210 | SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ 211 | #endif 212 | } 213 | 214 | /** 215 | * @brief Update SystemCoreClock variable according to Clock Register Values. 216 | * The SystemCoreClock variable contains the core clock (HCLK), it can 217 | * be used by the user application to setup the SysTick timer or configure 218 | * other parameters. 219 | * 220 | * @note Each time the core clock (HCLK) changes, this function must be called 221 | * to update SystemCoreClock variable value. Otherwise, any configuration 222 | * based on this variable will be incorrect. 223 | * 224 | * @note - The system frequency computed by this function is not the real 225 | * frequency in the chip. It is calculated based on the predefined 226 | * constant and the selected clock source: 227 | * 228 | * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*) 229 | * 230 | * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) 231 | * 232 | * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) 233 | * 234 | * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) 235 | * or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors. 236 | * 237 | * (*) MSI_VALUE is a constant defined in stm32l4xx_hal.h file (default value 238 | * 4 MHz) but the real value may vary depending on the variations 239 | * in voltage and temperature. 240 | * 241 | * (**) HSI_VALUE is a constant defined in stm32l4xx_hal.h file (default value 242 | * 16 MHz) but the real value may vary depending on the variations 243 | * in voltage and temperature. 244 | * 245 | * (***) HSE_VALUE is a constant defined in stm32l4xx_hal.h file (default value 246 | * 8 MHz), user has to ensure that HSE_VALUE is same as the real 247 | * frequency of the crystal used. Otherwise, this function may 248 | * have wrong result. 249 | * 250 | * - The result of this function could be not correct when using fractional 251 | * value for HSE crystal. 252 | * 253 | * @param None 254 | * @retval None 255 | */ 256 | void SystemCoreClockUpdate(void) 257 | { 258 | uint32_t tmp = 0U, msirange = 0U, pllvco = 0U, pllr = 2U, pllsource = 0U, pllm = 2U; 259 | 260 | /* Get MSI Range frequency--------------------------------------------------*/ 261 | if((RCC->CR & RCC_CR_MSIRGSEL) == RESET) 262 | { /* MSISRANGE from RCC_CSR applies */ 263 | msirange = (RCC->CSR & RCC_CSR_MSISRANGE) >> 8U; 264 | } 265 | else 266 | { /* MSIRANGE from RCC_CR applies */ 267 | msirange = (RCC->CR & RCC_CR_MSIRANGE) >> 4U; 268 | } 269 | /*MSI frequency range in HZ*/ 270 | msirange = MSIRangeTable[msirange]; 271 | 272 | /* Get SYSCLK source -------------------------------------------------------*/ 273 | switch (RCC->CFGR & RCC_CFGR_SWS) 274 | { 275 | case 0x00: /* MSI used as system clock source */ 276 | SystemCoreClock = msirange; 277 | break; 278 | 279 | case 0x04: /* HSI used as system clock source */ 280 | SystemCoreClock = HSI_VALUE; 281 | break; 282 | 283 | case 0x08: /* HSE used as system clock source */ 284 | SystemCoreClock = HSE_VALUE; 285 | break; 286 | 287 | case 0x0C: /* PLL used as system clock source */ 288 | /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN 289 | SYSCLK = PLL_VCO / PLLR 290 | */ 291 | pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC); 292 | pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> 4U) + 1U ; 293 | 294 | switch (pllsource) 295 | { 296 | case 0x02: /* HSI used as PLL clock source */ 297 | pllvco = (HSI_VALUE / pllm); 298 | break; 299 | 300 | case 0x03: /* HSE used as PLL clock source */ 301 | pllvco = (HSE_VALUE / pllm); 302 | break; 303 | 304 | default: /* MSI used as PLL clock source */ 305 | pllvco = (msirange / pllm); 306 | break; 307 | } 308 | pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 8U); 309 | pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 25U) + 1U) * 2U; 310 | SystemCoreClock = pllvco/pllr; 311 | break; 312 | 313 | default: 314 | SystemCoreClock = msirange; 315 | break; 316 | } 317 | /* Compute HCLK clock frequency --------------------------------------------*/ 318 | /* Get HCLK prescaler */ 319 | tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4U)]; 320 | /* HCLK clock frequency */ 321 | SystemCoreClock >>= tmp; 322 | } 323 | 324 | 325 | /** 326 | * @} 327 | */ 328 | 329 | /** 330 | * @} 331 | */ 332 | 333 | /** 334 | * @} 335 | */ 336 | 337 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 338 | -------------------------------------------------------------------------------- /src/dhara/map.c: -------------------------------------------------------------------------------- 1 | /* Dhara - NAND flash management layer 2 | * Copyright (C) 2013 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include "bytes.h" 19 | #include "map.h" 20 | 21 | #define DHARA_RADIX_DEPTH (sizeof(dhara_sector_t) << 3) 22 | 23 | static inline dhara_sector_t d_bit(int depth) 24 | { 25 | return ((dhara_sector_t)1) << (DHARA_RADIX_DEPTH - depth - 1); 26 | } 27 | 28 | /************************************************************************ 29 | * Metadata/cookie layout 30 | */ 31 | 32 | static inline void ck_set_count(uint8_t *cookie, dhara_sector_t count) 33 | { 34 | dhara_w32(cookie, count); 35 | } 36 | 37 | static inline dhara_sector_t ck_get_count(const uint8_t *cookie) 38 | { 39 | return dhara_r32(cookie); 40 | } 41 | 42 | static inline void meta_clear(uint8_t *meta) 43 | { 44 | memset(meta, 0xff, DHARA_META_SIZE); 45 | } 46 | 47 | static inline dhara_sector_t meta_get_id(const uint8_t *meta) 48 | { 49 | return dhara_r32(meta); 50 | } 51 | 52 | static inline void meta_set_id(uint8_t *meta, dhara_sector_t id) 53 | { 54 | dhara_w32(meta, id); 55 | } 56 | 57 | static inline dhara_page_t meta_get_alt(const uint8_t *meta, int level) 58 | { 59 | return dhara_r32(meta + 4 + (level << 2)); 60 | } 61 | 62 | static inline void meta_set_alt(uint8_t *meta, int level, dhara_page_t alt) 63 | { 64 | dhara_w32(meta + 4 + (level << 2), alt); 65 | } 66 | 67 | /************************************************************************ 68 | * Public interface 69 | */ 70 | 71 | void dhara_map_init(struct dhara_map *m, const struct dhara_nand *n, 72 | uint8_t *page_buf, uint8_t gc_ratio) 73 | { 74 | if (!gc_ratio) 75 | gc_ratio = 1; 76 | 77 | dhara_journal_init(&m->journal, n, page_buf); 78 | m->gc_ratio = gc_ratio; 79 | } 80 | 81 | int dhara_map_resume(struct dhara_map *m, dhara_error_t *err) 82 | { 83 | if (dhara_journal_resume(&m->journal, err) < 0) { 84 | m->count = 0; 85 | return -1; 86 | } 87 | 88 | m->count = ck_get_count(dhara_journal_cookie(&m->journal)); 89 | return 0; 90 | } 91 | 92 | void dhara_map_clear(struct dhara_map *m) 93 | { 94 | if (m->count) { 95 | m->count = 0; 96 | dhara_journal_clear(&m->journal); 97 | } 98 | } 99 | 100 | dhara_sector_t dhara_map_capacity(const struct dhara_map *m) 101 | { 102 | const dhara_sector_t cap = dhara_journal_capacity(&m->journal); 103 | const dhara_sector_t reserve = cap / (m->gc_ratio + 1); 104 | const dhara_sector_t safety_margin = 105 | DHARA_MAX_RETRIES << m->journal.nand->log2_ppb; 106 | 107 | if (reserve + safety_margin >= cap) 108 | return 0; 109 | 110 | return cap - reserve - safety_margin; 111 | } 112 | 113 | /* Trace the path from the root to the given sector, emitting 114 | * alt-pointers and alt-full bits in the given metadata buffer. This 115 | * also returns the physical page containing the given sector, if it 116 | * exists. 117 | * 118 | * If the page can't be found, a suitable path will be constructed 119 | * (containing PAGE_NONE alt-pointers), and DHARA_E_NOT_FOUND will be 120 | * returned. 121 | */ 122 | static int trace_path(struct dhara_map *m, dhara_sector_t target, 123 | dhara_page_t *loc, uint8_t *new_meta, 124 | dhara_error_t *err) 125 | { 126 | uint8_t meta[DHARA_META_SIZE]; 127 | int depth = 0; 128 | dhara_page_t p = dhara_journal_root(&m->journal); 129 | 130 | if (new_meta) 131 | meta_set_id(new_meta, target); 132 | 133 | if (p == DHARA_PAGE_NONE) 134 | goto not_found; 135 | 136 | if (dhara_journal_read_meta(&m->journal, p, meta, err) < 0) 137 | return -1; 138 | 139 | while (depth < DHARA_RADIX_DEPTH) { 140 | const dhara_sector_t id = meta_get_id(meta); 141 | 142 | if (id == DHARA_SECTOR_NONE) 143 | goto not_found; 144 | 145 | if ((target ^ id) & d_bit(depth)) { 146 | if (new_meta) 147 | meta_set_alt(new_meta, depth, p); 148 | 149 | p = meta_get_alt(meta, depth); 150 | if (p == DHARA_PAGE_NONE) { 151 | depth++; 152 | goto not_found; 153 | } 154 | 155 | if (dhara_journal_read_meta(&m->journal, p, 156 | meta, err) < 0) 157 | return -1; 158 | } else { 159 | if (new_meta) 160 | meta_set_alt(new_meta, depth, 161 | meta_get_alt(meta, depth)); 162 | } 163 | 164 | depth++; 165 | } 166 | 167 | if (loc) 168 | *loc = p; 169 | 170 | return 0; 171 | 172 | not_found: 173 | if (new_meta) { 174 | while (depth < DHARA_RADIX_DEPTH) 175 | meta_set_alt(new_meta, depth++, DHARA_SECTOR_NONE); 176 | } 177 | 178 | dhara_set_error(err, DHARA_E_NOT_FOUND); 179 | return -1; 180 | } 181 | 182 | int dhara_map_find(struct dhara_map *m, dhara_sector_t target, 183 | dhara_page_t *loc, dhara_error_t *err) 184 | { 185 | return trace_path(m, target, loc, NULL, err); 186 | } 187 | 188 | int dhara_map_read(struct dhara_map *m, dhara_sector_t s, 189 | uint8_t *data, dhara_error_t *err) 190 | { 191 | const struct dhara_nand *n = m->journal.nand; 192 | dhara_error_t my_err; 193 | dhara_page_t p; 194 | 195 | if (dhara_map_find(m, s, &p, &my_err) < 0) { 196 | if (my_err == DHARA_E_NOT_FOUND) { 197 | memset(data, 0xff, 1 << n->log2_page_size); 198 | return 0; 199 | } 200 | 201 | dhara_set_error(err, my_err); 202 | return -1; 203 | } 204 | 205 | return dhara_nand_read(n, p, 0, 1 << n->log2_page_size, data, err); 206 | } 207 | 208 | /* Check the given page. If it's garbage, do nothing. Otherwise, rewrite 209 | * it at the front of the map. Return raw errors from the journal (do 210 | * not perform recovery). 211 | */ 212 | static int raw_gc(struct dhara_map *m, dhara_page_t src, 213 | dhara_error_t *err) 214 | { 215 | dhara_sector_t target; 216 | dhara_page_t current; 217 | dhara_error_t my_err; 218 | uint8_t meta[DHARA_META_SIZE]; 219 | 220 | if (dhara_journal_read_meta(&m->journal, src, meta, err) < 0) 221 | return -1; 222 | 223 | /* Is the page just filler/garbage? */ 224 | target = meta_get_id(meta); 225 | if (target == DHARA_SECTOR_NONE) 226 | return 0; 227 | 228 | /* Find out where the sector once represented by this page 229 | * currently resides (if anywhere). 230 | */ 231 | if (trace_path(m, target, ¤t, meta, &my_err) < 0) { 232 | if (my_err == DHARA_E_NOT_FOUND) 233 | return 0; 234 | 235 | dhara_set_error(err, my_err); 236 | return -1; 237 | } 238 | 239 | /* Is this page still the most current representative? If not, 240 | * do nothing. 241 | */ 242 | if (current != src) 243 | return 0; 244 | 245 | /* Rewrite it at the front of the journal with updated metadata */ 246 | ck_set_count(dhara_journal_cookie(&m->journal), m->count); 247 | if (dhara_journal_copy(&m->journal, src, meta, err) < 0) 248 | return -1; 249 | 250 | return 0; 251 | } 252 | 253 | static int pad_queue(struct dhara_map *m, dhara_error_t *err) 254 | { 255 | dhara_page_t p = dhara_journal_root(&m->journal); 256 | uint8_t root_meta[DHARA_META_SIZE]; 257 | 258 | ck_set_count(dhara_journal_cookie(&m->journal), m->count); 259 | 260 | if (p == DHARA_PAGE_NONE) 261 | return dhara_journal_enqueue(&m->journal, NULL, NULL, err); 262 | 263 | if (dhara_journal_read_meta(&m->journal, p, root_meta, err) < 0) 264 | return -1; 265 | 266 | return dhara_journal_copy(&m->journal, p, root_meta, err); 267 | } 268 | 269 | /* Attempt to recover the journal */ 270 | static int try_recover(struct dhara_map *m, dhara_error_t cause, 271 | dhara_error_t *err) 272 | { 273 | int restart_count = 0; 274 | 275 | if (cause != DHARA_E_RECOVER) { 276 | dhara_set_error(err, cause); 277 | return -1; 278 | } 279 | 280 | while (dhara_journal_in_recovery(&m->journal)) { 281 | dhara_page_t p = dhara_journal_next_recoverable(&m->journal); 282 | dhara_error_t my_err; 283 | int ret; 284 | 285 | if (p == DHARA_PAGE_NONE) 286 | ret = pad_queue(m, &my_err); 287 | else 288 | ret = raw_gc(m, p, &my_err); 289 | 290 | if (ret < 0) { 291 | if (my_err != DHARA_E_RECOVER) { 292 | dhara_set_error(err, my_err); 293 | return -1; 294 | } 295 | 296 | if (restart_count >= DHARA_MAX_RETRIES) { 297 | dhara_set_error(err, DHARA_E_TOO_BAD); 298 | return -1; 299 | } 300 | 301 | restart_count++; 302 | } 303 | } 304 | 305 | return 0; 306 | } 307 | 308 | static int auto_gc(struct dhara_map *m, dhara_error_t *err) 309 | { 310 | int i; 311 | 312 | if (dhara_journal_size(&m->journal) < dhara_map_capacity(m)) 313 | return 0; 314 | 315 | for (i = 0; i < m->gc_ratio; i++) 316 | if (dhara_map_gc(m, err) < 0) 317 | return -1; 318 | 319 | return 0; 320 | } 321 | 322 | static int prepare_write(struct dhara_map *m, dhara_sector_t dst, 323 | uint8_t *meta, dhara_error_t *err) 324 | { 325 | dhara_error_t my_err; 326 | 327 | if (auto_gc(m, err) < 0) 328 | return -1; 329 | 330 | if (trace_path(m, dst, NULL, meta, &my_err) < 0) { 331 | if (my_err != DHARA_E_NOT_FOUND) { 332 | dhara_set_error(err, my_err); 333 | return -1; 334 | } 335 | 336 | if (m->count >= dhara_map_capacity(m)) { 337 | dhara_set_error(err, DHARA_E_MAP_FULL); 338 | return -1; 339 | } 340 | 341 | m->count++; 342 | } 343 | 344 | ck_set_count(dhara_journal_cookie(&m->journal), m->count); 345 | return 0; 346 | } 347 | 348 | int dhara_map_write(struct dhara_map *m, dhara_sector_t dst, 349 | const uint8_t *data, dhara_error_t *err) 350 | { 351 | for (;;) { 352 | uint8_t meta[DHARA_META_SIZE]; 353 | dhara_error_t my_err; 354 | const dhara_sector_t old_count = m->count; 355 | 356 | if (prepare_write(m, dst, meta, err) < 0) 357 | return -1; 358 | 359 | if (!dhara_journal_enqueue(&m->journal, data, meta, &my_err)) 360 | break; 361 | 362 | m->count = old_count; 363 | 364 | if (try_recover(m, my_err, err) < 0) 365 | return -1; 366 | } 367 | 368 | return 0; 369 | } 370 | 371 | int dhara_map_copy_page(struct dhara_map *m, dhara_page_t src, 372 | dhara_sector_t dst, dhara_error_t *err) 373 | { 374 | for (;;) { 375 | uint8_t meta[DHARA_META_SIZE]; 376 | dhara_error_t my_err; 377 | const dhara_sector_t old_count = m->count; 378 | 379 | if (prepare_write(m, dst, meta, err) < 0) 380 | return -1; 381 | 382 | if (!dhara_journal_copy(&m->journal, src, meta, &my_err)) 383 | break; 384 | 385 | m->count = old_count; 386 | 387 | if (try_recover(m, my_err, err) < 0) 388 | return -1; 389 | } 390 | 391 | return 0; 392 | } 393 | 394 | int dhara_map_copy_sector(struct dhara_map *m, dhara_sector_t src, 395 | dhara_sector_t dst, dhara_error_t *err) 396 | { 397 | dhara_error_t my_err; 398 | dhara_page_t p; 399 | 400 | if (dhara_map_find(m, src, &p, &my_err) < 0) { 401 | if (my_err == DHARA_E_NOT_FOUND) 402 | return dhara_map_trim(m, dst, err); 403 | 404 | dhara_set_error(err, my_err); 405 | return -1; 406 | } 407 | 408 | return dhara_map_copy_page(m, p, dst, err); 409 | } 410 | 411 | static int try_delete(struct dhara_map *m, dhara_sector_t s, 412 | dhara_error_t *err) 413 | { 414 | dhara_error_t my_err; 415 | uint8_t meta[DHARA_META_SIZE]; 416 | dhara_page_t alt_page; 417 | uint8_t alt_meta[DHARA_META_SIZE]; 418 | int level = DHARA_RADIX_DEPTH - 1; 419 | int i; 420 | 421 | if (trace_path(m, s, NULL, meta, &my_err) < 0) { 422 | if (my_err == DHARA_E_NOT_FOUND) 423 | return 0; 424 | 425 | dhara_set_error(err, my_err); 426 | return -1; 427 | } 428 | 429 | /* Select any of the closest cousins of this node which are 430 | * subtrees of at least the requested order. 431 | */ 432 | while (level >= 0) { 433 | alt_page = meta_get_alt(meta, level); 434 | if (alt_page != DHARA_PAGE_NONE) 435 | break; 436 | level--; 437 | } 438 | 439 | /* Special case: deletion of last sector */ 440 | if (level < 0) { 441 | m->count = 0; 442 | dhara_journal_clear(&m->journal); 443 | return 0; 444 | } 445 | 446 | /* Rewrite the cousin with an up-to-date path which doesn't 447 | * point to the original node. 448 | */ 449 | if (dhara_journal_read_meta(&m->journal, alt_page, alt_meta, err) < 0) 450 | return -1; 451 | 452 | meta_set_id(meta, meta_get_id(alt_meta)); 453 | 454 | meta_set_alt(meta, level, DHARA_PAGE_NONE); 455 | for (i = level + 1; i < DHARA_RADIX_DEPTH; i++) 456 | meta_set_alt(meta, i, meta_get_alt(alt_meta, i)); 457 | 458 | meta_set_alt(meta, level, DHARA_PAGE_NONE); 459 | 460 | ck_set_count(dhara_journal_cookie(&m->journal), m->count - 1); 461 | if (dhara_journal_copy(&m->journal, alt_page, meta, err) < 0) 462 | return -1; 463 | 464 | m->count--; 465 | return 0; 466 | } 467 | 468 | int dhara_map_trim(struct dhara_map *m, dhara_sector_t s, dhara_error_t *err) 469 | { 470 | for (;;) { 471 | dhara_error_t my_err; 472 | 473 | if (auto_gc(m, err) < 0) 474 | return -1; 475 | 476 | if (!try_delete(m, s, &my_err)) 477 | break; 478 | 479 | if (try_recover(m, my_err, err) < 0) 480 | return -1; 481 | } 482 | 483 | return 0; 484 | } 485 | 486 | int dhara_map_sync(struct dhara_map *m, dhara_error_t *err) 487 | { 488 | while (!dhara_journal_is_clean(&m->journal)) { 489 | dhara_page_t p = dhara_journal_peek(&m->journal); 490 | dhara_error_t my_err; 491 | int ret; 492 | 493 | if (p == DHARA_PAGE_NONE) { 494 | ret = pad_queue(m, &my_err); 495 | } else { 496 | ret = raw_gc(m, p, &my_err); 497 | dhara_journal_dequeue(&m->journal); 498 | } 499 | 500 | if ((ret < 0) && (try_recover(m, my_err, err) < 0)) 501 | return -1; 502 | } 503 | 504 | return 0; 505 | } 506 | 507 | int dhara_map_gc(struct dhara_map *m, dhara_error_t *err) 508 | { 509 | if (!m->count) 510 | return 0; 511 | 512 | for (;;) { 513 | dhara_page_t tail = dhara_journal_peek(&m->journal); 514 | dhara_error_t my_err; 515 | 516 | if (tail == DHARA_PAGE_NONE) 517 | break; 518 | 519 | if (!raw_gc(m, tail, &my_err)) { 520 | dhara_journal_dequeue(&m->journal); 521 | break; 522 | } 523 | 524 | if (try_recover(m, my_err, err) < 0) 525 | return -1; 526 | } 527 | 528 | return 0; 529 | } 530 | --------------------------------------------------------------------------------