STM32F429移植SQLITE记录

7 篇文章 0 订阅

不知道自己是哪根筋搭错了还是怎么回事,一时心血来潮,突发奇想,决定把SQLite移植到STM32F429上。在此记录一下过程,也确认一下此事可行。
先说一下结果:移植后的SQLite可运行,可操作,但是比较耗资源(相对单片机来说),内存小的,就别想了,根本玩不起来的。
这是未加载时的内存使用情况:
在这里插入图片描述
这是打开数据库时内存的情况:
在这里插入图片描述
这是使用查询后的内存使用情况:
在这里插入图片描述
从内存使用的情况上来看,小单片机就算了,即使是STM32F429,高达192K的内存,也经不起这样折腾,还是得老实点加外存。

OK,结果也看了,现在来说说移植要点。
背景:STM32F429,32M外存SDRAM。RTT。FATFS。SD卡。
一切在SQLite的说明文档时已经交待清楚了,这里只是重复一下原作者的声明而已。
1、用替代实现替换内置的互斥锁子系统。
2、完全禁用在单线程应用程序中使用的所有静音。
3、重新配置内存分配子系统,以使用标准库中的malloc()实现以外的其他内存分配器。
4、重新对齐内存分配子系统,以便它根本不会调用malloc(),而是使用在启动时分配给SQLite的固定大小的内存缓冲区来满足所有内存请求。
5、用替代设计替换文件系统的接口。换句话说,覆盖SQLite进行的所有系统调用,以便使用一组完全不同的系统调用与磁盘进行对话。
6、覆盖其他操作系统接口,例如获取Zulu或本地时间的调用。
其实以上六条只是三个子系统的接口需要处理。分别是:
1、配置或替换Mutex子系统
2、配置或更换内存分配子系统
3、添加新的虚拟文件系统
最后补全这两个函数
sqlite3_os_init()
sqlite3_os_end()
做好上述工作,写个简单的测试程序。OK,接下来就可以放心测试调整了。
值得说的是:
仔细观察内存使用,这耗费了我太多的时间。栈空间从2K起,一直调整到16K,才算勉强成功。
另外:
得了解POSIX,若是你没有这个基础,需要花点时间了解下什么标准操作接口。
得了解VFS,若是你不知道这是什么东西,需要了解下虚拟文件系统的组成及原理。
得了解下单片机是怎么操作外存的,尤其是STM32Fx系列,我用的是Keil MDK,外挂32MSDRAM。
至于在调试过程中会遇到莫名其妙的出错时,请不要怀疑Sqlite,把Shell的栈空间放大点,至少到16K。2K是肯定不要想了,4K只够打开数据库,8K免强可以查询一下,16K测试下还目前还算稳定。

SQLite作者的原话:
为了将SQLite移植到新的操作系统(默认情况下不支持该操作系统),应用程序必须提供…
1、有效的互斥子系统(但仅在多线程的情况下),
2、一个工作的内存分配子系统(假设它在其标准库中缺少malloc()),
3、并且有效的VFS实施。

OK,从一开始,我拼命折腾SQLite源码,各种宏开关修改了个遍,最后才发现其实只要额外定义几个作者描述的宏之外,根本不需要动任何东西。事实上我最终也没有动任何源码,另外加了一个头文件用于声明宏开关。
若是想移植到freeRTOS,注意上面的三点,仿照RTT重写部分接口,一定会成功的。小伙伴们不要在SQLite源码里折腾了。
这是测试文件,移植代码不附了。请参考RTT就行。


#include "stdio.h"
#include "sqlite3.h"

#include "rtthread.h"
#include "string.h"

sqlite3 *db;

void DB_Open()
{
	int rc = 0;
	
	sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
	
	sqlite3_initialize();
	
	rc = sqlite3_open("test.db",&db);
	
	if(rc)
	{
		rt_kprintf("Can't open database!\r\n");
		return;
	}
	
	rt_kprintf("Open database success!\r\n");
	
}
MSH_CMD_EXPORT(DB_Open,SQLite3 runing);

void DB_Close()
{
	sqlite3_close(db);

}
MSH_CMD_EXPORT(DB_Close,SQLite3 closed);

static int callback_create(void *NotUsed, int argc, char **argv, char **azColName){
   int i;
   for(i=0; i<argc; i++){
      rt_kprintf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   rt_kprintf("\n");
   return 0;
}

void CreateTable(void)
{
	int rc;
	char *zErrMsg = 0;
	char *sql;
	
   /* Create SQL statement */
   sql = "CREATE TABLE COMPANY("  \
         "ID INT PRIMARY KEY     NOT NULL," \
         "NAME           TEXT    NOT NULL," \
         "AGE            INT     NOT NULL," \
         "ADDRESS        CHAR(50)," \
         "SALARY         REAL );";

   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback_create, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
	rt_kprintf("SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      rt_kprintf("Table created successfully\n");
   }
   sqlite3_close(db);
}
MSH_CMD_EXPORT(CreateTable,Create Table);


//控制台调用形式:
//	Insert 5 murphy 32 California 2000.00
void Insert(int argc,char **argv)
{
   char *zErrMsg = 0;
   int rc;
   char *sql;
	
	if(argc < 2)
		return;
	
	char sqlCmd[128] = {0};

	/* Create SQL statement */   
//	sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) "  \
//         "VALUES (6, 'Murphy2', 32, 'California', 20000.00 ); ";
	sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (";
	//6, 'Murphy2', 32, 'California', 20000.00 ); ";
	
	
	strcpy(sqlCmd,sql);
	
	strcat(sqlCmd,argv[1]);		//ID
	strcat(sqlCmd,", '");
	
	strcat(sqlCmd,argv[2]);		//name
	strcat(sqlCmd,"', ");
	
	strcat(sqlCmd,argv[3]);		//age
	strcat(sqlCmd,", '");
	
	strcat(sqlCmd,argv[4]);		//address
	strcat(sqlCmd,"', ");
   
	strcat(sqlCmd,argv[5]);		//salary
	strcat(sqlCmd,"); ");

   /* Execute SQL statement */
   rc = sqlite3_exec(db, sqlCmd, callback_create, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
      rt_kprintf( "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      rt_kprintf( "Records created successfully\n");
   }

}
MSH_CMD_EXPORT(Insert,Insert record to table);



static int callback_query(void *data, int argc, char **argv, char **azColName){
   int i;
   rt_kprintf( "%s: ", (const char*)data);
   for(i=0; i<argc; i++){
      rt_kprintf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   rt_kprintf("\n");
   return 0;
}

void Query()
{
   char *zErrMsg = 0;
   int rc;
   char *sql;
   const char* data = "Callback function called";

   /* Create SQL statement */
   sql = "SELECT * from COMPANY";

   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback_query, (void*)data, &zErrMsg);
   if( rc != SQLITE_OK ){
      rt_kprintf( "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      rt_kprintf( "Operation done successfully\n");
   }
}
MSH_CMD_EXPORT(Query,Query infomation from table);	
	
static int callback_Delete(void *data, int argc, char **argv, char **azColName){
   int i;
   rt_kprintf( "%s: ", (const char*)data);
   for(i=0; i<argc; i++){
      rt_kprintf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   rt_kprintf("\n");
   return 0;
}

//调用形式:DeleteByID 10 删除ID = 10 的一条记录
void DeleteByID(int argc,char **argv)
{
	int rc;
	char *sql;
	char *zErrMsg = 0;
	const char * data = "Callback function called";
		
	if(argc < 2)
		return;
	
	sql = "DELETE FROM COMPANY WHERE ID = ";
	char sqlCmd[50] = {0};
	
	strcpy(sqlCmd,sql);
	strcat(sqlCmd,argv[1]);	
	
	rc = sqlite3_exec(db,sqlCmd,callback_query,(void *)data,&zErrMsg);
	
}
MSH_CMD_EXPORT(DeleteByID,Delete infomation from table);	


  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
移植SQLite数据库代码需要以下几个步骤: 1. 下载SQLite源代码。 2. 将SQLite源代码中的sqlite3.c和sqlite3.h文件添加到你的工程中。 3. 根据你的实际情况修改sqlite3.h文件中的宏定义,比如修改sqlite3_malloc和sqlite3_free函数为你的系统内存分配和释放函数。 4. 实现sqlite3.h文件中定义的回调函数,比如sqlite3_vfs结构体中定义的xOpen、xRead、xWrite、xClose等函数。 5. 在你的应用程序中调用sqlite3_open函数打开数据库,调用sqlite3_exec函数执行SQL语句。 6. 最后,在你的工程中添加必要的头文件和库文件即可。 下面是一个基于STM32F4和HAL库的SQLite数据库移植示例代码,仅供参考: ```c #include "sqlite3.h" #include "stdlib.h" #include "string.h" #include "stm32f4xx_hal.h" /* 自定义内存分配函数 */ static void *MyMalloc(int nBytes) { return malloc(nBytes); } /* 自定义内存释放函数 */ static void MyFree(void *p) { free(p); } /* 自定义文件操作结构体 */ static const sqlite3_io_methods MyIoMethods = { 1, /* iVersion */ NULL, /* xClose */ NULL, /* xRead */ NULL, /* xWrite */ NULL, /* xTruncate */ NULL, /* xSync */ NULL, /* xFileSize */ NULL, /* xLock */ NULL, /* xUnlock */ NULL, /* xCheckReservedLock */ NULL, /* xFileControl */ NULL, /* xSectorSize */ NULL, /* xDeviceCharacteristics */ NULL, /* xShmMap */ NULL, /* xShmLock */ NULL, /* xShmBarrier */ NULL /* xShmUnmap */ }; /* 自定义文件操作函数 */ static int MyOpen(sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags) { HAL_SD_CardInfoTypeDef SDCardInfo; /* 打开SD卡 */ if (HAL_SD_InitCard(&hsd) == HAL_OK) { /* 获取SD卡信息 */ if (HAL_SD_GetCardInfo(&hsd, &SDCardInfo) == HAL_OK) { /* 以读写方式打开文件 */ if (HAL_SD_ReadBlocks(&hsd, pFile->pMethods, 0, 1, 1000) == HAL_OK) { pFile->pMethods = &MyIoMethods; return SQLITE_OK; } } } return SQLITE_ERROR; } /* SQLite数据库初始化函数 */ void SQLiteInit(void) { sqlite3_vfs *pVfs; /* 获取默认的VFS */ pVfs = sqlite3_vfs_find(NULL); /* 修改默认的VFS */ pVfs->szOsFile = sizeof(sqlite3_file); pVfs->mxPathname = 512; pVfs->zName = "MySDCardVFS"; pVfs->pAppData = NULL; pVfs->xOpen = MyOpen; pVfs->xDelete = NULL; pVfs->xAccess = NULL; pVfs->xFullPathname = NULL; pVfs->xDlOpen = NULL; pVfs->xDlError = NULL; pVfs->xDlSym = NULL; pVfs->xDlClose = NULL; pVfs->xRandomness = NULL; pVfs->xSleep = NULL; pVfs->xCurrentTime = NULL; /* 设置自定义的内存分配和释放函数 */ sqlite3_config(SQLITE_CONFIG_MALLOC, MyMalloc, MyFree); } ``` 在使用SQLite数据库时,只需要在程序启动时调用SQLiteInit函数进行初始化,然后就可以使用SQLite提供的API进行数据库操作了。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值