wangpengcheng 发表于 2014-8-31 17:00:52

【分享】配合前几天发的SPI Flash的驱动,分析MQX驱动架构!

本帖最后由 FSL_TICS_ZJJ 于 2014-9-11 16:05 编辑

首先声明:以下都是我个人在MQX学习、使用过程中的一些见解,当然,里面可能会有一些说的不是很明白,我希望我扔出来的这块砖头,能引来他山之玉{:titter:}

在参考了MQX自带的内部Flash驱动中,我看到Flash其实可以分区进行不同区域来做驱动,比如我自己的这个驱动,就是将一个8M的SPI Flash分为两块,前2M是一块,后面6M是一块,而每个块我们都需要不同的参数来进行标记,我做了一个Flash Block的结构体如下:
typedef struct spi_flash_block
{
    char *block_name;                                //分块名称
    uint32_t block_start_address;                //块起始地址
    uint32_t block_end_address;                //块结束地址
    uint32_t sector_address;               //当前操作扇区地址
    uint32_t sector_size;                        //驱动大小
    uint8_t *sector_buff;                        //CACHE指针
    bool sector_change_flag;                        //写标志
}SPI_FLASH_BLOCK, *SPI_FLASH_BLOCK_PTR;

然后定义两个区,我将一个命名为系统区,另一个命名为用户区:
static SPI_FLASH_BLOCK spi_flash_block_descr[] = {
    {"system", 0x00000000, 0x001FFFFF, 0x00000000, SPI_MEMORY_SECTOR_SIZE, NULL, FALSE},
    {"user",   0x00200000, 0x007FFFFF, 0x00200000, SPI_MEMORY_SECTOR_SIZE, NULL, FALSE},
    {0,      0,          0,          0,          0,                      0         }
};

当然还有一个比较重要的参数,就是SPI口了,这个参数可以用来改变SPI口,因为我的Flash挂接在SPI0上,所以如下定义:
#if BSP_SPI_MEMORY_CHANNEL == 0
      #define SPI_CHANNEL SPI0_BASE_PTR
#elif BSP_SPI_MEMORY_CHANNEL == 1
      #define SPI_CHANNEL SPI1_BASE_PTR
#elif BSP_SPI_MEMORY_CHANNEL == 2
      #define SPI_CHANNELSPI2_BASE_PTR
#else
   #error Unsupported SPI channel number. Please check settings of BSP_SPI_MEMORY_CHANNEL in BSP.
#endif

而为了更方便将来对驱动的修改,我添加了一个公共的数据结构,虽然目前没有其它参数,但如果以后要使用,可以在此结构体里面添加:

typedef struct spi_flash_struct
{
    SPI_MemMapPtr SPIx;
}SPI_FLASH_STRUCT, *SPI_FLASH_STRUCT_PTR;

好了,前期的准备工作我们做好了,接下来我们要做驱动了,其实OS的驱动不外乎就是几个函数,我要完成以下几个函数的编写:
_mqx_uint _spi_flash_install(char *identifier, SPI_FLASH_STRUCT const *init_ptr);
_mqx_int _spi_flash_init(const void *init_data_ptr, void **io_info_ptr_ptr);
_mqx_int _spi_flash_open(MQX_FILE_PTR fd_ptr, char *open_name_ptr, char *flags);
_mqx_int _spi_flash_close(MQX_FILE_PTR fd_ptr);
_mqx_int _spi_flash_read(MQX_FILE_PTR fd_ptr, char *data_ptr, _mqx_int num);
_mqx_int _spi_flash_write(MQX_FILE_PTR fd_ptr, char *data_ptr, _mqx_int num);
_mqx_int _spi_flash_ioctl(MQX_FILE_PTR fd_ptr, _mqx_uint cmd, void *param_ptr);
_mqx_int _spi_flash_uninstall(IO_DEVICE_STRUCT_PTR   io_dev_ptr);

第一个当然是install函数,我写的函数如下:
_mqx_uint _spi_flash_install ( char *identifier, SPI_FLASH_STRUCT const   *init_ptr)
{
    SPI_FLASH_STRUCT_PTR spi_flash_data = _mem_alloc_system(sizeof(SPI_FLASH_STRUCT));        //定义了公共的变量
    spi_flash_init(spi_flash_data, NULL);                //初始化端口以及数据
    return (_io_dev_install_ext(                               //进行驱动注册
      identifier,
      _spi_flash_open,
      _spi_flash_close,
      _spi_flash_read,
      _spi_flash_write,
      _spi_flash_ioctl,
      _spi_flash_uninstall,
      spi_flash_data));
}
这里我要注明一下,其实很多驱动都可以在驱动OPEN的时候再进行初始化,但是考虑到我初始里面有个公共的变量SPI口的选择,所以我将初始化功能放在了此处。此函数要在使用SPI Flash之前调用,用来注册驱动。使用方法:
_spi_flash_install("spi_flash:", NULL);

第二个函数是相对install来说的,就是uninstall函数:
_mqx_int _spi_flash_uninstall( IO_DEVICE_STRUCT_PTR   io_dev_ptr)
{
    SPI_FLASH_STRUCT_PTR user_data = (SPI_FLASH_STRUCT_PTR)io_dev_ptr->DRIVER_INIT_PTR;
    _mem_free(user_data);        //因为在install函数中申请了内存,所以在此要将内存释放掉,不然会造成内存泄漏
    io_dev_ptr->DRIVER_INIT_PTR = NULL; //将驱动数据清空,防止野指针的出现
   return MQX_OK;
}

第三个函数当然就是初始化了:
_mqx_int _spi_flash_init( const void*init_data_ptr, void **io_info_ptr_ptr )
{
    SPI_FLASH_STRUCT_PTR user_data = (SPI_FLASH_STRUCT_PTR)init_data_ptr;
    user_data->SPIx = SPI_CHANNEL;
    hal_spi0_init(user_data->SPIx);
   
    return SPI_FLASH_OK;
}
初始化函数就比较简单,我只是选择了SPI接口,然后配置硬件SPI口。

第四个函数是OPEN:
_mqx_int _spi_flash_open ( MQX_FILE_PTR fd_ptr, char   *open_name_ptr, char   *flags)
{
    SPI_FLASH_BLOCK_PTR user_block = NULL;
    int i = 0;
    for(i = 0; spi_flash_block_descr.block_name != 0; i++)
    {
      if(0 != strstr(open_name_ptr, spi_flash_block_descr.block_name))        //用块名称对块进行查找
      {
            user_block = (SPI_FLASH_BLOCK_PTR)_mem_alloc_system(sizeof(SPI_FLASH_BLOCK));       //找到块之后申请内存作为当前打开块的初始化数据
            memcpy(user_block, &(spi_flash_block_descr), sizeof(SPI_FLASH_BLOCK));      //对块数据进行初始化
            fd_ptr->DEV_DATA_PTR = user_block;   //将块指针赋值给当前打开的驱动数据指针
            break;
      }
    }
    if(user_block == NULL)
    {
      return IO_ERROR;
    }
    user_block->sector_buff = _mem_alloc_system(user_block->sector_size);    //给CACHE申请内存
    fd_ptr->SIZE = user_block->block_end_address - user_block->block_start_address + 1;//初始化当前驱动块的尺寸
    fd_ptr->LOCATION = user_block->block_start_address;   //初始化LOCATION
    read_sector(fd_ptr);//初始化当前CACHE
    return MQX_OK;
}
这个函数我也是参考原MQX中Flash驱动中的OPEN函数,这块有点说道,因为Flash分块了,所以在OPEN的时候需要做一件事情,驱动我目前要OPEN的是哪一个块,使用如下:
fopen("spi_flash:system", NULL);
或者
fopen("spi_flash:user, NULL);

第五个函数close,这个函数相对比较简单,就是释放Open时申请的所有资源,然后将指针清空:
_mqx_int _spi_flash_close ( MQX_FILE_PTR fd_ptr )
{
    SPI_FLASH_BLOCK_PTR user_block = (SPI_FLASH_BLOCK_PTR)fd_ptr->DEV_DATA_PTR;
    fflush(fd_ptr);
    _mem_free(user_block->sector_buff);
    _mem_free(user_block);
    fd_ptr->DEV_DATA_PTR = NULL;
    return MQX_OK;   
}

第六个函数read,这个函数其实也没什么,直接从Flash中读数据,但是这里需要注意的是要改变CACHE的切换:
_mqx_int _spi_flash_read ( MQX_FILE_PTR fd_ptr,char   *data_ptr, _mqx_int   num )
{   
    SPI_FLASH_BLOCK_PTR user_block = (SPI_FLASH_BLOCK_PTR)fd_ptr->DEV_DATA_PTR;
    uint32_t sector_start = user_block->sector_address;
    uint32_t sector_next_start = user_block->sector_address + user_block->sector_size;
    uint8_t *buff_ptr;
    _mqx_int location = fd_ptr->LOCATION;
    _mqx_int over_num = num;
    _mqx_int read_num_one_time;
    do
    {
      if((location < sector_start) || (location >= sector_next_start))
      {
            uint32_t error = switching_sector(fd_ptr, location);                //如果地址范围超出当前CACHE,要进行切换
            if(error != SPI_FLASH_OK)
            {
                return error;
            }
            sector_start = user_block->sector_address;
            sector_next_start = user_block->sector_address + user_block->sector_size;
      }
      buff_ptr = user_block->sector_buff + (location & (user_block->sector_size - 1));
      read_num_one_time = ((location + over_num) >= sector_next_start) ? sector_next_start - location : over_num;
      memcpy(data_ptr, buff_ptr,read_num_one_time);
      data_ptr += read_num_one_time;
      location += read_num_one_time;
      over_num -= read_num_one_time;
    }while(over_num > 0);
    fd_ptr->LOCATION += num;
    return num;
}

第七个函数write,写函数跟读函数一样,要注意CACHE切换,另外,写函数还要注意一定要将写标志置起来,此标志是为了CACHE切换时知道Flash是否需要改变:
_mqx_int _spi_flash_write (MQX_FILE_PTR fd_ptr,char   *data_ptr, _mqx_int   num )
{
    SPI_FLASH_BLOCK_PTR user_block = (SPI_FLASH_BLOCK_PTR)fd_ptr->DEV_DATA_PTR;
    uint32_t sector_start = user_block->sector_address;
    uint32_t sector_next_start = user_block->sector_address + user_block->sector_size;
    uint8_t *buff_ptr;
    _mqx_int location = fd_ptr->LOCATION;
    _mqx_int write_num_one_time;
    _mqx_int over_num = num;
    do
    {
      if((location < sector_start) || (location >= sector_next_start))
      {
            uint32_t error = switching_sector(fd_ptr, location);
            if(error != SPI_FLASH_OK)
            {
                return error;
            }
            sector_start = user_block->sector_address;
            sector_next_start = user_block->sector_address + user_block->sector_size;
      }
      buff_ptr = user_block->sector_buff + (location & (user_block->sector_size - 1));
      write_num_one_time = ((location + over_num) >= sector_next_start) ? sector_next_start - location : over_num;
      memcpy(buff_ptr, data_ptr, write_num_one_time);
       user_block->sector_change_flag = TRUE;
      data_ptr += write_num_one_time;
      location += write_num_one_time;
      over_num -= write_num_one_time;
      if(location >= sector_next_start)
      {
            write_sector(fd_ptr);
      }
    }while(over_num > 0);
    fd_ptr->LOCATION += num;
    return num;
}

最后一个IOCTRL函数,在驱动中,此函数的重要性我想我就不用说了,下面是我的函数,因为只用到了一部分命令,所以函数不算太大,MQX中Flash的IOCTRL函数那才叫个大呢:
_mqx_int _spi_flash_ioctl (MQX_FILE_PTR fd_ptr, _mqx_uint    cmd,void      *param_ptr )
{
    SPI_FLASH_STRUCT_PTR user_data = (SPI_FLASH_STRUCT_PTR)fd_ptr->DEV_PTR->DRIVER_INIT_PTR;
    SPI_FLASH_BLOCK_PTR user_block = (SPI_FLASH_BLOCK_PTR)fd_ptr->DEV_DATA_PTR;
    _mqx_int                           result = MQX_OK;
    _mqx_uint_ptr                      uparam_ptr;
    switch(cmd)
    {
      case IO_IOCTL_FLUSH_OUTPUT:                      //Flush功能,这个功能很有用,我一开始没有加此命令,结果文件写完后下次开机就不见了,大家知道原因吧,哈哈
            write_sector(fd_ptr);
            break;
      case FLASH_IOCTL_ERASE_CHIP:            
            hal_spi_dev_flash_erase_dev(user_data->SPIx);
            hal_spi_dev_flash_read(user_data->SPIx, user_block->sector_address, user_block->sector_buff, user_block->sector_size);
            break;

      case IO_IOCTL_DEVICE_IDENTIFY:
            /*
            ** This is to let the upper layer know what kind of device this is.
            ** It's a physical flash device, capable of being erased, read, seeked,
            ** and written. Flash devices are not interrupt driven, so
            ** IO_DEV_ATTR_POLL is included.
            */   
            uparam_ptr = (_mqx_uint_ptr)param_ptr;
            uparam_ptr = IO_DEV_TYPE_PHYS_FLASHX;
            uparam_ptr = IO_DEV_TYPE_LOGICAL_MFS;
            uparam_ptr = IO_DEV_ATTR_ERASE | IO_DEV_ATTR_POLL
                           | IO_DEV_ATTR_READ | IO_DEV_ATTR_SEEK |
                           IO_DEV_ATTR_WRITE;
            break;
      
      case IO_IOCTL_GET_NUM_SECTORS:
            *(uint32_t *)param_ptr = fd_ptr->SIZE / SPI_MEMORY_SECTOR_SIZE;
            break;
      case IO_IOCTL_GET_BLOCK_SIZE:      
      case FLASH_IOCTL_GET_SECTOR_SIZE:
            /* returns the fixed size for MFS sector size */
            *(uint32_t *)param_ptr = user_block->sector_size;
            break;
      case IO_IOCTL_SEEK:                     //这个命令一定要添加,因为我们Flash分块了,所以起始地址不一样,如果不加此功能,那么它起始地址都是默认从0开始,那第二个                                                                   //块肯定会读写错误
            fd_ptr->LOCATION += user_block->block_start_address;
            break;
      default:
            result = IO_ERROR_INVALID_IOCTL_CMD;
    }
    return result;
}

最后的最后,还有一个函数我必须得说明一下,切换扇区,需要注意的是一开始定义的写标志在这里起了作用,看代码:
uint32_t switching_sector(MQX_FILE_PTR fd_ptr, _mqx_int address)
{
    SPI_FLASH_BLOCK_PTR user_block = (SPI_FLASH_BLOCK_PTR)fd_ptr->DEV_DATA_PTR;
    uint32_t error_code;
    //取旧扇区的起始地址
    _mqx_int sector_start_address = address & (~(user_block->sector_size - 1));
    //写Flash
    if(user_block->sector_change_flag)
         error_code = write_sector(fd_ptr);
    if(error_code != SPI_FLASH_OK)
    {
      return error_code;
    }
    //更新扇区的起始地址参数
    user_block->sector_address = sector_start_address;
    //重新填充CACHE
    error_code = read_sector(fd_ptr);
    if(error_code != SPI_FLASH_OK)
    {
      return error_code;
    }
    return SPI_FLASH_OK;
}

OK了,其它的一些再底层的函数我就没有必要一一说明了!尾部再将源文件传上来:


砖来了,玉在哪?{:titter:}

cn_x 发表于 2014-8-31 17:05:46

感谢分享,这个确实实用,收藏先
楼主辛苦

浪里白条 发表于 2014-8-31 17:10:39

哈,楼主讲得好详细,这个可以加精

wangpengcheng 发表于 2014-8-31 17:12:25

浪里白条 发表于 2014-8-31 17:10
哈,楼主讲得好详细,这个可以加精

谢谢捧场啊,你的飞币飞升啊!{:lol:} 为了追赶你,得搞有质量的帖子才成啊!

wangpengcheng 发表于 2014-8-31 17:13:43

本帖最后由 wangpengcheng 于 2014-8-31 17:15 编辑

晕,代码里面想加红,没加上{:titter:},希望大家看的时候要多注意带字样的那些代码行!

浪里白条 发表于 2014-8-31 17:15:55

wangpengcheng 发表于 2014-8-31 17:12
谢谢捧场啊,你的飞币飞升啊! 为了追赶你,得搞有质量的帖子才成啊! ...

哈哈,那一起加油,早点拿到TOWER

wangpengcheng 发表于 2014-8-31 17:17:20

浪里白条 发表于 2014-8-31 17:15
哈哈,那一起加油,早点拿到TOWER

一起努力,哈哈!

abszy 发表于 2014-8-31 17:32:05

楼主最近帖子质量很高啊都是原创的   给力!

wangpengcheng 发表于 2014-8-31 17:33:19

abszy 发表于 2014-8-31 17:32
楼主最近帖子质量很高啊都是原创的   给力!

一切为了TOWER{:titter:}

abszy 发表于 2014-8-31 17:36:12

wangpengcheng 发表于 2014-8-31 17:33
一切为了TOWER

楼主最近再多发发原创的心得让大家一起跟着学学   

希望莫大能多给原创帖子加精

wangpengcheng 发表于 2014-8-31 17:37:50

abszy 发表于 2014-8-31 17:36
楼主最近再多发发原创的心得让大家一起跟着学学   

希望莫大能多给原创帖子加精 ...

回头我再整理看看,看有没有能放出来的{:titter:}

sunnyqd 发表于 2014-8-31 18:05:07

玉在哪?同求,嘿嘿

oner 发表于 2014-8-31 18:53:11

不明觉厉

fengyunyu 发表于 2014-8-31 20:07:47

LZ帖子质量很高!

wangpengcheng 发表于 2014-8-31 20:10:28

oner 发表于 2014-8-31 18:53
不明觉厉

其实不难的,呵呵!

wbxjtu 发表于 2014-8-31 20:42:23

谢谢楼主提供的资料

rootxie 发表于 2014-8-31 21:17:29

不明觉厉,貌似结构体编译器都会字节对齐,很浪费内存呢

lzl000 发表于 2014-8-31 21:24:44

楼主的原创帖好厉害啊

qinshiysb 发表于 2014-8-31 21:25:36

支持原创作品,感谢分享

qinshiysb 发表于 2014-8-31 21:26:27

wangpengcheng 发表于 2014-8-31 17:33
一切为了TOWER

这个趋势,应该快了啊

wangpengcheng 发表于 2014-8-31 22:25:46

qinshiysb 发表于 2014-8-31 21:26
这个趋势,应该快了啊

谢谢捧场哦!

dgtg 发表于 2014-8-31 23:54:56

mark!学习了!!

wangpengcheng 发表于 2014-9-1 00:03:59

dgtg 发表于 2014-8-31 23:54
mark!学习了!!

有问题可以交流啊!

WEIZ666 发表于 2014-9-1 00:07:08

收下谢谢{:handshake:}楼主               

zwei99999999 发表于 2014-9-1 00:12:28

谢谢楼主分享{:handshake:}               

wangpengcheng 发表于 2014-9-1 10:08:12

zwei99999999 发表于 2014-9-1 00:12
谢谢楼主分享

谢谢参观

sdlibin007 发表于 2014-9-1 10:23:16

好贴就得顶!!

songjie 发表于 2014-9-1 11:27:30

分析MQX驱动架构

架构是个什么意思呢?

javabean 发表于 2014-9-1 12:51:55

好长,不明觉厉~

wangpengcheng 发表于 2014-9-1 20:25:56

songjie 发表于 2014-9-1 11:27
分析MQX驱动架构

架构是个什么意思呢?

找不到合适的词,呵呵,语文学的不好!

wxfje 发表于 2014-9-1 20:33:17

谢谢分享,楼主真厉害呀

wangpengcheng 发表于 2014-9-1 20:49:52

wxfje 发表于 2014-9-1 20:33
谢谢分享,楼主真厉害呀

从MQX源码中一点一点学,有可能断章取义了,但能用,呵呵

wxfje 发表于 2014-9-1 21:19:06

wangpengcheng 发表于 2014-9-1 20:49
从MQX源码中一点一点学,有可能断章取义了,但能用,呵呵

这已经很厉害了
想问下楼主,这种flash怎么防止坏块呢

wangpengcheng 发表于 2014-9-1 21:23:20

wxfje 发表于 2014-9-1 21:19
这已经很厉害了
想问下楼主,这种flash怎么防止坏块呢

我用的时候用文件系统,会自己检测坏块,原理没研究过!

cn_x 发表于 2014-9-1 21:29:11

支持原创,,支持精华··········
话说马上也要进入MQX学习了,先收藏先

songjie 发表于 2014-9-1 22:20:19

wangpengcheng 发表于 2014-9-1 20:25
找不到合适的词,呵呵,语文学的不好!

没有, 我看很多的 招聘上面都是要 熟悉什么什么 架构,

不是很 明白 架构的 意思~~~

wangpengcheng 发表于 2014-9-1 22:21:42

songjie 发表于 2014-9-1 22:20
没有, 我看很多的 招聘上面都是要 熟悉什么什么 架构,

不是很 明白 架构的 意思~~~


框架中构造,呵呵!

songjie 发表于 2014-9-1 22:22:19

wangpengcheng 发表于 2014-9-1 22:21
框架中构造,呵呵!

还是不明白~

wangpengcheng 发表于 2014-9-1 22:23:30

songjie 发表于 2014-9-1 22:22
还是不明白~

你写程序之前是不是得先考虑大概的框架啊!

songjie 发表于 2014-9-1 22:24:14

wangpengcheng 发表于 2014-9-1 22:23
你写程序之前是不是得先考虑大概的框架啊!

不是都差不多啊~~~·.c .h~

wangpengcheng 发表于 2014-9-1 22:27:26

songjie 发表于 2014-9-1 22:24
不是都差不多啊~~~·.c .h~

呵呵,建议你多看看小的OS,像UCOS、RTT、MQX、RTOS、FREEOS之类的代码,那里面有一些软件思想可以学习!

cn_x 发表于 2014-9-1 22:29:01

songjie 发表于 2014-9-1 22:24
不是都差不多啊~~~·.c .h~

哈哈,典型的想到哪写到哪
如果有一定的框架的话,以后写程序就按这个框架模式走,就不用做很多重复的工作
要做的就是在框架下不断的添加功能应用,开发效率会高很多
想到哪写到哪就会导致很多重复劳动,而且程序看起来也不是很有条理

songjie 发表于 2014-9-1 22:29:05

wangpengcheng 发表于 2014-9-1 22:27
呵呵,建议你多看看小的OS,像UCOS、RTT、MQX、RTOS、FREEOS之类的代码,那里面有一些软件思想可以学习! ...

正在看 ucos ~

RTOS 了解过~

songjie 发表于 2014-9-1 22:30:13

cn_x 发表于 2014-9-1 22:29
哈哈,典型的想到哪写到哪
如果有一定的框架的话,以后写程序就按这个框架模式走,就不用做很多重复的工 ...

您的意思是 模块化 吧~~~在相关的模块中,增加 相关的函数 ?

类似于 C++ 的类 ,增加 删除 功能?

wangpengcheng 发表于 2014-9-1 22:31:43

songjie 发表于 2014-9-1 22:30
您的意思是 模块化 吧~~~在相关的模块中,增加 相关的函数 ?

类似于 C++ 的类 ,增加 删除 功能? ...

差不多!

songjie 发表于 2014-9-1 22:35:10

wangpengcheng 发表于 2014-9-1 22:31
差不多!

IC的 一个 .c . H
SPI 的 一个.c.h
Uart 的一个 .c 。h

LCD 的

LED 的

按键的

7816的

14443的

Rf的

USB 的

等等吧   用哪个挂那个的 include<.h>吧 ,不能的 屏蔽掉吧 ~~~~

   框架大概是 这个 意思吧??????????????

songjie 发表于 2014-9-1 22:36:06

当然还有很多 中断的

timer 的

GPIO的 ,

各种宏的

各种结构体的

数据结构的·~~~

等等

wangpengcheng 发表于 2014-9-1 22:39:08

songjie 发表于 2014-9-1 22:35
IC的 一个 .c . H
SPI 的 一个.c.h
Uart 的一个 .c 。h


不尽然是!呵呵,你看UCOS,你觉得他那里的驱动程序怎么样?是不是都差不多?一个OPEN、一个WRITE、一个READ、一个CLOSE、一个IOCTRL,但是就这几个函数就可以做出不同的底层驱动!也就是说,你在编程的时候往往需要先考虑好怎么做最方便,而你考虑好之后执行的时候那个思路,就叫作大概的程序架构!

wangpengcheng 发表于 2014-9-1 22:39:52

songjie 发表于 2014-9-1 22:36
当然还有很多 中断的

timer 的


我觉得是一种思路,不是具体的哪个东西!

浪里白条 发表于 2014-9-1 22:46:16

wangpengcheng 发表于 2014-9-1 22:39
我觉得是一种思路,不是具体的哪个东西!

高手 请教一下呢
比如我有了
uart.c uart.h
gsm.c gsm.h
main.c

我gsm.c中需要调用uart.c中的函数,这种做法合理不
如果不合理,改进的办法是什么呢

songjie 发表于 2014-9-1 22:49:17

wangpengcheng 发表于 2014-9-1 22:39
不尽然是!呵呵,你看UCOS,你觉得他那里的驱动程序怎么样?是不是都差不多?一个OPEN、一个WRITE、一个R ...

让我先 理解理解~~

wangpengcheng 发表于 2014-9-1 22:51:16

浪里白条 发表于 2014-9-1 22:46
高手 请教一下呢
比如我有了
uart.c uart.h


你要分两个对像来处理的话,为了移植方便,比如下次你用gsm模块调用的是SPI模块的同样的一个函数,我一般的做法是在GSM模块中添加一个函数指针,然后在初始化的时候从UART模块或SPI模块中把函数地址拿出来初始化此指针,而此指针就是GSM模块中的变量,需要注意的是在用此函数的之前要判断他是否已经被赋值,不然很容易出现野指针,呵呵!

rootxie 发表于 2014-9-2 08:01:30

这一套驱动都是从linux来得,看来linux才是鼻祖

loyal248 发表于 2014-9-2 08:13:09

还不错!!!!!!!!!

浪里白条 发表于 2014-9-2 08:25:23

wangpengcheng 发表于 2014-9-1 22:51
你要分两个对像来处理的话,为了移植方便,比如下次你用gsm模块调用的是SPI模块的同样的一个函数,我一般 ...

感谢回复,又学到知识了。

wangpengcheng 发表于 2014-9-2 12:25:40

rootxie 发表于 2014-9-2 08:01
这一套驱动都是从linux来得,看来linux才是鼻祖

那当然,无数人的智慧积累啊!

wangpengcheng 发表于 2014-9-2 12:32:43

浪里白条 发表于 2014-9-2 08:25
感谢回复,又学到知识了。

呵呵,多交流啊!

wxfje 发表于 2014-9-2 21:10:45

wangpengcheng 发表于 2014-9-1 21:23
我用的时候用文件系统,会自己检测坏块,原理没研究过!

这样呀,谢谢您

wxfje 发表于 2014-9-2 21:12:48

rootxie 发表于 2014-8-31 21:17
不明觉厉,貌似结构体编译器都会字节对齐,很浪费内存呢

这个可以设置的,但一般都采用默认的

wangpengcheng 发表于 2014-9-2 21:14:13

rootxie 发表于 2014-8-31 21:17
不明觉厉,貌似结构体编译器都会字节对齐,很浪费内存呢

不一定哦,前几天发现不能全靠编译器!

holts2 发表于 2014-9-2 21:17:10

wangpengcheng 发表于 2014-9-2 21:14
不一定哦,前几天发现不能全靠编译器!

编译器在大部份情况下还是靠得住的

wangpengcheng 发表于 2014-9-2 21:21:44

holts2 发表于 2014-9-2 21:17
编译器在大部份情况下还是靠得住的

呵呵,有些情况还真不好查,我那个问题后来是靠猜的!{:titter:}

holts2 发表于 2014-9-2 21:27:07

wangpengcheng 发表于 2014-9-2 21:21
呵呵,有些情况还真不好查,我那个问题后来是靠猜的!

能否开个贴细说分享下哈

wangpengcheng 发表于 2014-9-2 21:28:15

holts2 发表于 2014-9-2 21:27
能否开个贴细说分享下哈

不好说,呵呵,能开早就开了,还能赚飞币,具体情况比较复杂!{:titter:}

taojie 发表于 2014-9-2 21:46:29

了解一下这方面的知识,虽然用不上

wangpengcheng 发表于 2014-9-2 21:47:33

taojie 发表于 2014-9-2 21:46
了解一下这方面的知识,虽然用不上

要做单片机,迟早能用上,呵呵!

mypear 发表于 2014-9-2 23:26:39

来看详解的         

ludikn 发表于 2014-9-2 23:31:29

这个不错

rockyyangyang 发表于 2014-9-4 10:57:49

mark            

一夕nandy 发表于 2014-9-27 20:45:24

mark下 备用

swap2013 发表于 2014-9-27 22:17:11

flash 要处理写平衡、坏块管理吧

wangpengcheng 发表于 2014-9-27 23:35:52

swap2013 发表于 2014-9-27 22:17
flash 要处理写平衡、坏块管理吧

好像文件系统中有!

32MCU 发表于 2014-9-28 17:38:44

linux和MQX的驱动结构原理是一样的吗?

xaper 发表于 2014-9-30 14:55:16

收藏{:biggrin:}{:biggrin:}

千年明月 发表于 2014-10-1 10:23:12

谢谢了,支持一下

starting 发表于 2014-11-30 20:23:22

帮顶,标记一下。 飞思卡尔SPI驱动

sblpp 发表于 2014-12-1 12:11:03

谢谢分享!!

sj1125055001 发表于 2014-12-1 12:21:54

顶                                             

sj1125055001 发表于 2014-12-1 12:22:16

顶                                                                                                            

dswkl11 发表于 2014-12-1 13:42:53

可以像 epprom那样随即写不,擦除算法均衡不?

机器人天空 发表于 2014-12-1 13:53:39

楼主费心了{:lol:}

子鱼 发表于 2014-12-1 13:58:07

MQX自带的内部Flash驱动 支持哪些厂家的芯片 好像不同的厂家需要进行移植才能用

eliterxzgxu 发表于 2014-12-2 13:44:39

感谢分享,这个确实实用,收藏先
楼主辛苦

jiwx2011 发表于 2014-12-2 14:55:22

谢谢分享,lz辛苦

craigtao 发表于 2014-12-31 09:40:25

楼主,请教一下,MQX的驱动不知道和Linux的相比怎么样?是不是都有现成的? 在开发包里

wangpengcheng 发表于 2015-1-1 11:36:52

craigtao 发表于 2014-12-31 09:40
楼主,请教一下,MQX的驱动不知道和Linux的相比怎么样?是不是都有现成的? 在开发包里 ...

有BSP与PSP,一般不用改动!

craigtao 发表于 2015-1-1 19:58:50

wangpengcheng 发表于 2015-1-1 11:36
有BSP与PSP,一般不用改动!

哦哦,这么说开发起来还是挺容易的?

craigtao 发表于 2015-1-1 20:00:00

wangpengcheng 发表于 2015-1-1 11:36
有BSP与PSP,一般不用改动!

这么说开发还是挺容易的?

holts2 发表于 2015-1-1 20:11:04

craigtao 发表于 2015-1-1 20:00
这么说开发还是挺容易的?

肯定不容易,是会者不 难

craigtao 发表于 2015-1-1 20:13:01

holts2 发表于 2015-1-1 20:11
肯定不容易,是会者不 难

哈哈,,下一个目标是K46?

holts2 发表于 2015-1-1 20:20:15

craigtao 发表于 2015-1-1 20:13
哈哈,,下一个目标是K46?

不,还是K02

craigtao 发表于 2015-1-3 10:07:29

holts2 发表于 2015-1-1 20:20
不,还是K02

嗯嗯,,加油啊,看来你是要搭建一个大的系统啊,,以后向你学习啊,

holts2 发表于 2015-1-3 11:35:05

craigtao 发表于 2015-1-3 10:07
嗯嗯,,加油啊,看来你是要搭建一个大的系统啊,,以后向你学习啊,

没有啦,我只是玩点简单的

craigtao 发表于 2015-1-3 14:54:06

holts2 发表于 2015-1-3 11:35
没有啦,我只是玩点简单的

不要谦虚了啦,

Juggernaut 发表于 2015-1-3 19:48:28

好长的代码

wangpengcheng 发表于 2015-1-5 10:45:39

Juggernaut 发表于 2015-1-3 19:48
好长的代码

还好吧!函数大小都在要求之内

Juggernaut 发表于 2015-1-5 10:56:28

wangpengcheng 发表于 2015-1-5 10:45
还好吧!函数大小都在要求之内

哈哈,看的眼花
页: [1]
查看完整版本: 【分享】配合前几天发的SPI Flash的驱动,分析MQX驱动架构!