官方概述
整体代码框架
代码
核心逻辑部分(tx os对接)
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-4 shchl first version
*
*
* tx_kernel_enter() 执行逻辑(关键)
* TX_PORT_SPECIFIC_PRE_INITIALIZATION----可扩展
* _tx_initialize_low_level() --- 设备层(寄存器)初始化
* _tx_initialize_high_level() --- tx os 内部相关初始化
* TX_INITIALIZE_KERNEL_ENTER_EXTENSION----可扩展
* tx_application_define(_tx_initialize_unused_memory);
* TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION ---可扩展
*
*/
#include "includes.h"
#define APP_MAIN_STACK_SIZE 2048
#define APP_MEM_ALLOC_STATIC_ENABLE (0) /*静态内存分配使能*/
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
extern void app_component_init(void);
extern void app_define_component_init(void);
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static TX_THREAD app_start_thread; /*应用启动线程*/
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
static void app_start_entry(ULONG input);
/*
*********************************************************************************************************
* 内部函数
*********************************************************************************************************
*/
static void app_start_entry(ULONG input) {
/*应用组件初始化*/
app_component_init();
while (1) {
/* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
bsp_ProPer1ms();
tx_thread_sleep(1);
}
}
/**
* @brief 应用组件定义初始化
* @param first_unused_memory : 指向第一个未使用的内存的指针
* @retval None
*/
VOID tx_application_define(VOID *first_unused_memory) {
UINT stat;
#if APP_MEM_ALLOC_STATIC_ENABLE
#define TX_STATIC_MEM_SIZE (60*1024) /*静态内存字节数*/
/*内存池初始化*/
static uint8_t mem_pool_area[TX_STATIC_MEM_SIZE];
tx_mem_pool_static_init(mem_pool_area, TX_STATIC_MEM_SIZE);
#else
if (first_unused_memory) {
tx_mem_pool_init(first_unused_memory);
} else {
// todo 未使用动态内存,后面禁止使用 app_malloc 函数
/*错误处理: 线程创建失败*/
Error_Handler();
}
#endif
stat = tx_thread_create(&app_start_thread, "app start thread",
app_start_entry, 0,
app_malloc(APP_MAIN_STACK_SIZE), APP_MAIN_STACK_SIZE,
2, 2,
TX_NO_TIME_SLICE, TX_AUTO_START);
if (stat != TX_SUCCESS) {
/*错误处理: 线程创建失败*/
Error_Handler();
}
/*组件初始化---不需要主线程中进行初始化的部分,使用TX_APP_DEFINE_EXPORT此进行初始化*/
app_define_component_init();
}
自动初始化组件
使用到的宏定义
#define TX_APP_DEFINE_EXPORT(fn) INIT_EXPORT(fn, "6.5")
#define TX_THREAD_EXPORT_LV1(fn) INIT_EXPORT(fn, "7.0")
#define TX_THREAD_EXPORT(fn) INIT_EXPORT(fn, "7.5")
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-13 shchl first version
*/
#include "includes.h"
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
TX_MUTEX AppPrintfSemp; /* 用于printf互斥 */
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
/**
* @brief 组件初始化开始
* @return
*/
static int tx_app_define_init_start() {
return TX_SUCCESS;
}
INIT_EXPORT(tx_app_define_init_start, "6");
/**
* @brief 组件初始化开始
* @return
*/
static int tx_component_init_start() {
/* 创建互斥信号量 */
tx_mutex_create(&AppPrintfSemp, "AppPrintfSemp", TX_NO_INHERIT);
return TX_SUCCESS;
}
INIT_EXPORT(tx_component_init_start, "7");
static int tx_component_init_end() {
return TX_SUCCESS;
}
INIT_EXPORT(tx_component_init_end, "8");
void app_component_init(void) {
tx_log("--------------app component init[start]---------------\r\n");
bsp_components_app_init(&__os_init_tx_component_init_start,
&__os_init_tx_component_init_end);
tx_log("--------------app component init[end]---------------\r\n");
}
void app_define_component_init(void) {
bsp_components_app_init(&__os_init_tx_app_define_init_start,
&__os_init_tx_component_init_start);
}
levelx组件的初始化(这里使用的是自动初始化方式)
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-15 shchl first version
*/
#include "includes.h"
#if 1
#include "lx_api.h"
#include "levelx/lx_stm32_nor_w25q128_driver.h"
LX_NOR_FLASH nor_w25q128;
int lx_application_define(void) {
lx_nor_flash_initialize();
return LX_SUCCESS;
}
TX_APP_DEFINE_EXPORT(lx_application_define); /*首先创建模块应用*/
/**
* @brief nor flash 设备初始化
* @return
*/
int app_nor_flash_init() {
UINT status = lx_nor_flash_open(&nor_w25q128,
"nor w25q128",
lx_stm32_nor_w25q128bv_driver_initialize);
/*打开失败(将失败的空间进行格式化)*/
if (status) { /*这个一般只会执行一次,后面基本上不会再执行*/
tx_log("need format space\r\n");
lx_stm32_nor_w25q128bv_flash_format(&nor_w25q128); /*格式化*/
/*再尝试一次*/
status = lx_nor_flash_open(&nor_w25q128,
"nor w25q128",
lx_stm32_nor_w25q128bv_driver_initialize);
if (status) {
tx_log("nor flash init error\r\n");
// todo
return (int) status;
}
}
tx_log("nor flash device init ok\r\n");
// 是否需要关?
//lx_nor_flash_close(&nor_w25q128);/*这里直接关闭,后面如果需要,再打开*/
return (int) LX_SUCCESS; /*返回状态*/
}
TX_THREAD_EXPORT(app_nor_flash_init);
#endif
levelx驱动实现(w25q128)
头文件
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
#ifndef LX_STM32_NOR_DRIVER_H
#define LX_STM32_NOR_DRIVER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "lx_api.h"
#define W25Q128_PHY_TOTAL_SIZE (16*1024*1024) /*16M*/
#define W25Q128_PHY_PER_BLOCK_SIZE (64*1024) /*64KB*/
#define W25Q128_PHY_PER_SECTOR_SIZE (4*1024) /*4KB*/
#define LX_NOR_W25Q128_BASE_ADDR (0x0U) /*相对于硬件的基地址*/
#define LX_NOR_W25Q128_ALLOC_TOTAL_SIZE (2*1024*1024) /*分配给LX管理 2M*/
#define LX_NOR_W25Q128_PER_BLOCK_SIZE W25Q128_PHY_PER_SECTOR_SIZE /*LX每个块的大小(字节)*/
#define LX_NOR_W25Q128_BLOCKS_NUM ((LX_NOR_W25Q128_ALLOC_TOTAL_SIZE)/(LX_NOR_W25Q128_PER_BLOCK_SIZE)) /*LX 总块数*/
UINT lx_stm32_nor_w25q128bv_driver_initialize(LX_NOR_FLASH *nor_flash);
UINT lx_stm32_nor_w25q128bv_flash_format(LX_NOR_FLASH *nor_flash);
#ifdef __cplusplus
}
#endif
#endif /* LX_STM32_NOR_DRIVER_H */
源文件
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
#include "includes.h"
#include "levelx/lx_stm32_nor_w25q128_driver.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* Private typedef -----------------------------------------------------------*/
static UINT lx_nor_driver_read(ULONG *flash_address, ULONG *destination, ULONG words);
static UINT lx_nor_driver_write(ULONG *flash_address, ULONG *source, ULONG words);
static UINT lx_nor_driver_block_erase(ULONG block, ULONG erase_count);
static UINT lx_nor_driver_block_erased_verify(ULONG block);
/* USER CODE BEGIN USER_CODE_SECTION_1 */
/* USER CODE END USER_CODE_SECTION_1 */
#ifndef LX_DIRECT_READ
#ifndef LX_NOR_W25Q128_PER_BLOCK_SIZE
#define LX_NOR_W25Q128_PER_BLOCK_SIZE 512
#endif
static ULONG nor_sector_memory[LX_NOR_W25Q128_PER_BLOCK_SIZE / sizeof(ULONG)];
#endif
UINT lx_stm32_nor_w25q128bv_driver_initialize(LX_NOR_FLASH *nor_flash) {
UINT ret = LX_SUCCESS;
nor_flash->lx_nor_flash_total_blocks = LX_NOR_W25Q128_BLOCKS_NUM;
nor_flash->lx_nor_flash_words_per_block = LX_NOR_W25Q128_PER_BLOCK_SIZE / sizeof(ULONG);
nor_flash->lx_nor_flash_driver_read = lx_nor_driver_read;
nor_flash->lx_nor_flash_driver_write = lx_nor_driver_write;
nor_flash->lx_nor_flash_driver_block_erase = lx_nor_driver_block_erase;
nor_flash->lx_nor_flash_driver_block_erased_verify = lx_nor_driver_block_erased_verify;
#ifndef LX_DIRECT_READ
nor_flash->lx_nor_flash_sector_buffer = nor_sector_memory; /*直接赋值底层数据缓冲区,避免多次开辟数据*/
#endif
return ret;
}
/**
* @brief
* @param flash_address 读取地址
* @param destination 保存数据的位置
* @param words 读取的数据量
* @return
*/
static UINT lx_nor_driver_read(ULONG *flash_address, ULONG *destination, ULONG words) {
uint32_t real_addr = (uint32_t) flash_address + LX_NOR_W25Q128_BASE_ADDR;
sf_ReadBuffer((uint8_t *) destination,
real_addr,
words * sizeof(ULONG));
return LX_SUCCESS;
}
/**
* @brief
* @param flash_address 写入地址
* @param source 要写入的数据
* @param words 写入的数据大小(字)
* @return
*/
static UINT lx_nor_driver_write(ULONG *flash_address, ULONG *source, ULONG words) {
uint32_t real_addr = (uint32_t) flash_address + LX_NOR_W25Q128_BASE_ADDR;
sf_WriteBuffer((uint8_t *) source,
real_addr,
words * sizeof(ULONG));
return LX_SUCCESS;
}
/**
* @brief
* @param block 擦除块的下标
* @param erase_count 擦除的大小(字)
* @note 这里已在驱动写入的时候就会覆盖,这里就不做任何处理了
* @return
*/
static UINT lx_nor_driver_block_erase(ULONG block, ULONG erase_count) {
// sf_EraseSector(block * FLASH_SIZE_BYTE_PER_SECTOR);
return LX_SUCCESS;
}
/**
* @brief 块擦除验证
* @param block 块的索引下标
* @return
*/
static UINT lx_nor_driver_block_erased_verify(ULONG block) {
return LX_SUCCESS;
}
/**
* @brief 格式化分配的内存空间
* @param nor_flash
* @return
*/
UINT lx_stm32_nor_w25q128bv_flash_format(LX_NOR_FLASH *nor_flash) {
uint32_t erase_addr = 0;
for (int i = 0; i < nor_flash->lx_nor_flash_total_blocks; ++i) {
erase_addr = i * LX_NOR_W25Q128_PER_BLOCK_SIZE + LX_NOR_W25Q128_BASE_ADDR;
sf_EraseSector(erase_addr);
}
return LX_SUCCESS;
}
w25q128驱动(这里使用的是:论坛里面驱动代码)
测试线程(使用串口线程)
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-4 shchl first version
*/
#include "includes.h"
#if 1
#define APP_TASK_SERIAL_MONI_STK_SIZE 2048
#define APP_TASK_SERIAL_MONI_PRIO 10
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static TX_THREAD serial_moni_thread;
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
static void serial_moni_entry(ULONG input);
/*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
/**
* @brief cpu 状态任务
*/
int tx_task_serial_monitor_create() {
tx_thread_create(&serial_moni_thread, /* 任务控制块地址 */
"serial_moni", /* 任务名 */
serial_moni_entry, /* 启动任务函数地址 */
0, /* 传递给任务的参数 */
app_malloc(APP_TASK_SERIAL_MONI_STK_SIZE), /* 堆栈基地址 */
APP_TASK_SERIAL_MONI_STK_SIZE, /* 堆栈空间大小 */
APP_TASK_SERIAL_MONI_PRIO, /* 任务优先级*/
APP_TASK_SERIAL_MONI_PRIO, /* 任务抢占阀值 */
TX_NO_TIME_SLICE, /* 不开启时间片 */
TX_AUTO_START); /* 创建后立即启动 */
return TX_SUCCESS;
}
TX_THREAD_EXPORT(tx_task_serial_monitor_create);
/*
*********************************************************************************************************
* 内部函数
*********************************************************************************************************
*/
extern void lx_write_data_test();
static void serial_moni_entry(ULONG input) {
uint8_t cmd;
while (1) {
comGetChar(COM1, &cmd);
switch (cmd) {
case '1': {
lx_write_data_test();
}
break;
case '2':
break;
case '5':
app_task_info_out();
break;
default:
break;
}
cmd = 0;
tx_thread_sleep(10);
}
}
#endif
测试代码
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-15 shchl first version
*/
#include "includes.h"
#if 1
#include "lx_api.h"
extern LX_NOR_FLASH nor_w25q128;
static ULONG wr_data_buf[LX_NOR_SECTOR_SIZE];
static ULONG rd_data_buf[LX_NOR_SECTOR_SIZE];
void lx_write_data_test() {
static ULONG dat = 0;
for (int i = 0; i < LX_NOR_SECTOR_SIZE; ++i) {
wr_data_buf[i] = dat;
dat++;
}
lx_nor_flash_sector_write(&nor_w25q128, 1, wr_data_buf);
lx_nor_flash_sector_read(&nor_w25q128, 1, rd_data_buf);
for (int i = 0; i < LX_NOR_SECTOR_SIZE; ++i) {
if (wr_data_buf[i] != rd_data_buf[i]) {
tx_log("lx_write_data_test error\r\n");
return;
}
}
tx_log("lx_write_data_test ok\r\n");
}
#endif
测试结果
总结
- 这里使用lx_nor_flash_open打开设备的时候会出现状态不正确的情况,原因可能是flash中的数据格式问题,需要格式化一次。