diff --git a/CMakeLists.txt b/CMakeLists.txt index 842ab07..166baf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,9 @@ set(UART_DRIVER set(I2C_DRIVER ${CMAKE_SOURCE_DIR}/drivers/i2c/stm_i2c.c ) +set(FLASH_DRIVER + ${CMAKE_SOURCE_DIR}/drivers/flash/stm_flash.c +) project(blinky C) set(CPU_FLAGS "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard") @@ -75,7 +78,9 @@ set(SOURCES ${CMAKE_SOURCE_DIR}/cli/app/cli_app.c ${CMAKE_SOURCE_DIR}/cli/app/cli_helper.c ${CMAKE_SOURCE_DIR}/samples/i2c_sample.c + ${CMAKE_SOURCE_DIR}/samples/flash_sample.c ${UART_DRIVER} + ${FLASH_DRIVER} ${I2C_DRIVER} ${FREERTOS_SRC} ${FREERTOS_TESTS} @@ -87,6 +92,7 @@ target_include_directories(RTOS.elf PRIVATE ${CMAKE_SOURCE_DIR}/includes ${CMAKE_SOURCE_DIR}/drivers/uart ${CMAKE_SOURCE_DIR}/drivers/i2c + ${CMAKE_SOURCE_DIR}/drivers/flash ${CMAKE_SOURCE_DIR}/tests/freertos ${CMAKE_SOURCE_DIR}/cli/base/ ${CMAKE_SOURCE_DIR}/cli/app/ diff --git a/drivers/flash/stm_flash.c b/drivers/flash/stm_flash.c new file mode 100644 index 0000000..9da68dc --- /dev/null +++ b/drivers/flash/stm_flash.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include "stm_reg_access.h" + +#define FLASH_BASE 0x40022000 + +#define FLASH_SR_OFFSET 0x10 +#define FLASH_CR_OFFSET 0x14 +#define FLASH_KEYR_OFFSET 0x8 + +#define FLASH_SR FLASH_BASE + FLASH_SR_OFFSET +#define FLASH_CR FLASH_BASE + FLASH_CR_OFFSET +#define FLASH_KEYR FLASH_BASE + FLASH_KEYR_OFFSET + +#define FLASH_KEY1 0x45670123U +#define FLASH_KEY2 0xCDEF89ABU + +#define FLASH_SR_EOP (1U << 0) +#define FLASH_SR_PGSERR (1U << 7) +#define FLASH_SR_SIZERR (1U << 6) +#define FLASH_SR_PGAERR (1U << 5) +#define FLASH_SR_BSY (1U << 16) + +#define FLASH_CR_PG (1U << 0) +#define FLASH_CR_PER (1U << 1) +#define FLASH_CR_PNB_Pos 3U +#define FLASH_CR_PNB_Msk (0xFFU << FLASH_CR_PNB_Pos) +#define FLASH_CR_STRT (1U << 16) +#define FLASH_CR_LOCK (1U << 31) + + +static void flash_wait_not_busy(void) +{ + while(1) + { + uint32_t reg_val = REG_RD(FLASH_BASE + FLASH_SR_OFFSET); + if((reg_val & FLASH_SR_BSY) == 0) + break; + } +} + +static void flash_clear_flags(void) +{ + uint32_t reg_val = 0; + reg_val = REG_RD(FLASH_BASE + FLASH_SR_OFFSET); + reg_val |= FLASH_SR_EOP | FLASH_SR_PGSERR | FLASH_SR_SIZERR | FLASH_SR_PGAERR; + REG_WR(FLASH_BASE + FLASH_SR_OFFSET, reg_val); +} + +static void flash_unlock(void) +{ + uint32_t reg_val; + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + if (reg_val & FLASH_CR_LOCK) + { + REG_WR(FLASH_BASE + FLASH_KEYR_OFFSET, FLASH_KEY1); + REG_WR(FLASH_BASE + FLASH_KEYR_OFFSET, FLASH_KEY2); + } +} + +static void flash_lock(void) +{ + uint32_t reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val |= FLASH_CR_LOCK; + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, FLASH_CR_LOCK); +} + +void flash_erase_page(uint32_t page_number) +{ + uint32_t reg_val = 0; + flash_wait_not_busy(); + flash_clear_flags(); + flash_unlock(); + + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val &= ~FLASH_CR_PNB_Msk; + reg_val |= FLASH_CR_PER | ((page_number << FLASH_CR_PNB_Pos) & FLASH_CR_PNB_Msk); + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, reg_val); + + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val |= FLASH_CR_STRT; + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, reg_val); + + flash_wait_not_busy(); + flash_clear_flags(); + + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val &= ~FLASH_CR_PER; + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, reg_val); +} + +int flash_write_doubleword(uint32_t addr, uint64_t data) +{ + uint32_t reg_val = 0; + if (addr % 8 != 0) + return -1; + + flash_wait_not_busy(); + flash_clear_flags(); + flash_unlock(); + + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val |= FLASH_CR_PG; + reg_val &= ~(1 << 1); + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, reg_val); + + *(volatile uint32_t*)addr = (uint32_t)(data & 0xFFFFFFFFU); + *(volatile uint32_t*)(addr + 4) = (uint32_t)(data >> 32); + + flash_wait_not_busy(); + + reg_val = REG_RD(FLASH_BASE + FLASH_SR_OFFSET); + + if (reg_val & (FLASH_SR_PGSERR | FLASH_SR_SIZERR | FLASH_SR_PGAERR)) + { + flash_clear_flags(); + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val &= ~FLASH_CR_PG; + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, reg_val); + flash_lock(); + return -2; + } + + flash_clear_flags(); + reg_val = REG_RD(FLASH_BASE + FLASH_CR_OFFSET); + reg_val &= ~FLASH_CR_PG; + REG_WR(FLASH_BASE + FLASH_CR_OFFSET, reg_val); + + flash_lock(); + + uint64_t read_back = *((volatile uint64_t*)addr); + if (read_back != data) + return -3; + + return 0; +} + + diff --git a/drivers/flash/stm_flash.h b/drivers/flash/stm_flash.h new file mode 100644 index 0000000..0c21bb0 --- /dev/null +++ b/drivers/flash/stm_flash.h @@ -0,0 +1,10 @@ +#ifndef FLASH_DRIVER_H +#define FLASH_DRIVER_H + +#include + +void flash_erase_page(uint32_t page_number); +int flash_write_doubleword(uint32_t addr, uint64_t data); + +#endif /* FLASH_DRIVER_H */ + diff --git a/samples/flash_sample.c b/samples/flash_sample.c new file mode 100644 index 0000000..0c324af --- /dev/null +++ b/samples/flash_sample.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include "FreeRTOS.h" +#include "task.h" +#include "stm_flash.h" + +void flash_task(void *pvParameters); + +void flash_sample(void) +{ + xTaskCreate(flash_task, + "I2C_RTC", + 256, + NULL, + 2, + NULL); + + vTaskStartScheduler(); + + while(1) + ; +} + +#define DEBUG 0 + +void flash_task(void *pvParameters) +{ + (void)pvParameters; + uint32_t page_number = 127; + uint32_t flash_addr = 0x0803F800; + uint64_t value = 0x123456; + +#if DEBUG + uint64_t temp = *(volatile uint32_t*)flash_addr; +#endif + flash_erase_page(page_number); + + int ret = flash_write_doubleword(flash_addr, value); + if (ret == 0) + { + while (1) + ; + } + else + { + while (1) + ; + } + +} diff --git a/samples/stm_samples.c b/samples/stm_samples.c index 6fa6ca6..dffa0bf 100644 --- a/samples/stm_samples.c +++ b/samples/stm_samples.c @@ -1,8 +1,10 @@ -#define I2C_SAMPLE 1 -#define BLINKY_SAMPLE 1 +#define I2C_SAMPLE 0 +#define BLINKY_SAMPLE 0 +#define FLASH_SAMPLE 1 void i2c_sample(); -void stm_stm_sample(); +void stm_blinky_app(); +void flash_sample(); void stm_samples() { @@ -10,5 +12,7 @@ void stm_samples() i2c_sample(); #elif BLINKY_SAMPLE stm_blinky_app(); +#elif FLASH_SAMPLE + flash_sample(); #endif }