wangpengcheng 发表于 2014-5-15 10:14:50

资料分享:MQX中的函数从Flash中拷贝到RAM中的一种方法

这几天研究MQX的Flashx的驱动,在里面发现了一种函数拷贝的方法,以前没这么用过,觉得很有意思,发出来与大家分享,闲话少说,正题开始!

在Flash操作的时候,有需要在RAM中运行等待指令,在MQX中函数定义如下:

/*FUNCTION*-------------------------------------------------------------------
*
* Function Name    : ftfl_ram_function
* Returned Value   : void
* Comments         :
*   Code required to run in SRAM to perform flash commands.
*   All else can be run in flash.
*   Parameter is an address of flash status register.
*
*END*-----------------------------------------------------------------------*/
static void ftfl_ram_function
(
    /* Flash info structure */
    volatile uint8_t *ftfl_fstat_ptr
)
{
    /* start flash write */
    *ftfl_fstat_ptr |= FTFL_FSTAT_CCIF_MASK;

    /* wait until execution complete */
    while (0 == ((*ftfl_fstat_ptr) & FTFL_FSTAT_CCIF_MASK))
    { /* void */ }
}

static void ftfl_ram_function_end(void)
{}

这么定义的函数,他保存肯定是在Flash中,怎么样能把它搬到RAM中呢?我们看看他的运输函数:
/*FUNCTION*-------------------------------------------------------------------
*
* Function Name    : ftfl_init_ram_function
* Returned Value   : pointer to allocated RAM function
* Comments         :
*   Allocate and copy flash RAM function.
*
*END*-----------------------------------------------------------------------*/
char *ftfl_init_ram_function
(
    char *function_start,
    char *function_end
)
{
    char *ram_code_ptr;
    _mem_size ftfl_ram_function_start;

    /* remove thumb2 flag from the address and align to word size */
    ftfl_ram_function_start = (_mem_size)function_start & ~3;

    /* allocate space to run flash command out of RAM */
    ram_code_ptr = _mem_alloc_align((char *)function_end - (char *)ftfl_ram_function_start, 4);

#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (ram_code_ptr == NULL)
    {
      return NULL;
    }
#endif

    /* aopy code to RAM buffer */
    _mem_copy ((char *)ftfl_ram_function_start, ram_code_ptr, (char *)function_end - (char *)ftfl_ram_function_start);

    /* adjust address with respect to the original alignment */
    ram_code_ptr = (char *)((_mem_size)ram_code_ptr | ((_mem_size)function_start & 3));

    return ram_code_ptr;
}

下面是开始搬运:
flash_execute_code_ptr = ftfl_init_ram_function((char *)ftfl_ram_function, (char *)ftfl_ram_function_end);

我分析了一下上面的代码,发现这是利用了编译器顺序排放函数的特点,首先先定义了一个ftfl_ram_function函数,然后在紧跟着它的后面再放一个名为ftfl_ram_function_end的空函数,这样在编译器编译完后,产生的BIN中ftfl_ram_function函数的代码范围就是从ftfl_ram_function地址开始,到ftfl_ram_function_end地址结束,这就给搬运时把起始位置与长度定义了,再要做的事情无非就是将这段代码拷贝到RAM中运行就可以了。

说起拷贝,我们看到ftfl_init_ram_function函数中一开始并没有直接拷贝,而是有下面这样的语句:
ftfl_ram_function_start = (_mem_size)function_start & ~3;
那么这个语句又是干什么的呢?呵呵,其实很简单,它是做对齐的,因为ARM的指令级是32位的,它产生的代码当然要按32位来存放才可以执行,而这条语句就是将低三位清零,得到一个对齐的地址,然后再操作!

其实说起来蛮简单的,但用起来很方便的,希望能给大家提提神!

FSL_TICS_ZJJ 发表于 2014-5-15 10:43:57

楼主的经验分享都是经过实际验证的,非常好。

zndz410 发表于 2014-5-15 11:38:47

谢谢分亨哈,学习学习。

wangpengcheng 发表于 2014-5-15 11:40:43

zndz410 发表于 2014-5-15 11:38
谢谢分亨哈,学习学习。

不用客气,呵呵,技术是公有的,产品是私有的,技术共享是应该的!

fengyunyu 发表于 2014-9-1 21:38:56

好文章,推荐!

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

本帖最后由 wangpengcheng 于 2014-9-1 21:45 编辑

fengyunyu 发表于 2014-9-1 21:38
好文章,推荐!

我也觉得这个办法比较好玩,不用做数组,呵呵!

sunnyqd 发表于 2014-9-1 21:47:45

这个方法我也考虑过,没想到在这里找到了呢,很好!

浪里白条 发表于 2014-9-1 21:48:05

学习啦,感谢楼主分享。

wangpengcheng 发表于 2014-9-1 21:48:30

sunnyqd 发表于 2014-9-1 21:47
这个方法我也考虑过,没想到在这里找到了呢,很好!

MQX中的,呵呵,我也是现学现卖!

rockyyangyang 发表于 2014-9-4 14:55:00

mark                     
页: [1]
查看完整版本: 资料分享:MQX中的函数从Flash中拷贝到RAM中的一种方法