查看: 2385|回复: 0

sam4s16c的片内flash读写

[复制链接]
  • TA的每日心情
    奋斗
    2021-7-30 11:40
  • 签到天数: 1792 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2016-11-8 10:11:53 | 显示全部楼层 |阅读模式
    分享到:
    最近一直在玩sam4s16c,网上的所有论坛基本找不到atmel的资料,真心的不喜欢,但是工作需要,没办法。只能静下心来仔细研究Datasheet,别无他径。
    内部flash的组织架构见下图

    由图可知,flash是由很多的page组成,这个mcu的page size是512bits,而且,每个lock bit锁存8192bits,就是8k。
    erase可以是全部,块,页等。
    sam4s16c的片内flash大小的1m,0x100000.在片内的起始地址是0x400000,所有的读写都要从这个地址开始。不然会跑飞,我在调试时,试验了。很苦涩。
    找了1天的原因,后来发现是我少写了个“0”,写成0x47000了,可能是自己不仔细,也可能是笔者经验不足,当然都是借口。
    flash的写步骤是,
    第一,先解锁
    需要调用解锁函数flash_unlock()在xdk-asf-3.32.0\sam\services\flash_efc目录下的flash_efc.c文件里
    里面很复杂,起初看的很晕。我是一遍又一遍的单步调试才搞明白的。
    大家有兴趣可以研究一下,附上代码
    uint32_t flash_unlock(uint32_t ul_start, uint32_t ul_end,
                    uint32_t *pul_actual_start, uint32_t *pul_actual_end)
    {
            Efc *p_efc;
            uint32_t ul_actual_start, ul_actual_end;
            uint16_t us_start_page, us_end_page;
            uint32_t ul_error;
            uint16_t us_num_pages_in_region =
                            IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;

            /* Compute actual unlock range and store it */
            compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end);
            if (pul_actual_start != NULL) {
                    *pul_actual_start = ul_actual_start;
            }
            if (pul_actual_end != NULL) {
                    *pul_actual_end = ul_actual_end;
            }

            /* Compute page numbers */
            translate_address(&p_efc, ul_actual_start, &us_start_page, 0);
            translate_address(0, ul_actual_end, &us_end_page, 0);

            /* Unlock all pages */
            while (us_start_page < us_end_page) {
                    ul_error = efc_perform_command(p_efc, EFC_FCMD_CLB,
                                    us_start_page);
                    if (ul_error) {
                            return ul_error;
                    }
                    us_start_page += us_num_pages_in_region;
            }

            return FLASH_RC_OK;
    }

    第二步  解锁完成后要先擦除,可以选,全部,块或页。
    调用库函数flash_erase_sector(),路径同上
    这个函数看起来比较简单些,代码如下,有兴趣可以自己研究。
    uint32_t flash_erase_sector(uint32_t ul_address)
    {
            Efc *p_efc;
            uint16_t us_page;

            translate_address(&p_efc, ul_address, &us_page, NULL);

            if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_ES, us_page)) {
                    return FLASH_RC_ERROR;
            }

            return FLASH_RC_OK;
    }

    第三步,可以开始写数据。
    调用flash_write()函数,路径同上
    代码如下
    uint32_t flash_write(uint32_t ul_address, const void *p_buffer,
                    uint32_t ul_size, uint32_t ul_erase_flag)
    {
            Efc *p_efc;
            uint32_t ul_fws_temp;
            uint16_t us_page;
            uint16_t us_offset;
            uint32_t writeSize;
            uint32_t ul_page_addr;
            uint16_t us_padding;
            uint32_t ul_error;
            uint32_t ul_idx;
            uint32_t *p_aligned_dest;
            uint8_t *puc_page_buffer = (uint8_t *) gs_ul_page_buffer;

            translate_address(&p_efc, ul_address, &us_page, &us_offset);

    #if SAM3S || SAM3N || SAM3XA || SAM3U
            /* According to the errata, set the wait state value to 6. */
            ul_fws_temp = efc_get_wait_state(p_efc);
            efc_set_wait_state(p_efc, 6);
    #else
            UNUSED(ul_fws_temp);
    #endif

            /* Write all pages */
            while (ul_size > 0) {
                    /* Copy data in temporary buffer to avoid alignment problems. */
                    writeSize = Min((uint32_t) IFLASH_PAGE_SIZE - us_offset,
                                    ul_size);
                    compute_address(p_efc, us_page, 0, &ul_page_addr);
                    us_padding = IFLASH_PAGE_SIZE - us_offset - writeSize;

                    /* Pre-buffer data */
                    memcpy(puc_page_buffer, (void *)ul_page_addr, us_offset);

                    /* Buffer data */
                    memcpy(puc_page_buffer + us_offset, p_buffer, writeSize);

                    /* Post-buffer data */
                    memcpy(puc_page_buffer + us_offset + writeSize,
                                    (void *)(ul_page_addr + us_offset + writeSize),
                                    us_padding);

                    /* Write page.
                     * Writing 8-bit and 16-bit data is not allowed and may lead to
                     * unpredictable data corruption.
                     */
                    p_aligned_dest = (uint32_t *) ul_page_addr;
                    for (ul_idx = 0; ul_idx < (IFLASH_PAGE_SIZE / sizeof(uint32_t));
                                    ++ul_idx) {
                            *p_aligned_dest++ = gs_ul_page_buffer[ul_idx];
                    }

                    if (ul_erase_flag) {
                            ul_error = efc_perform_command(p_efc, EFC_FCMD_EWP,
                                            us_page);
                    } else {
                            ul_error = efc_perform_command(p_efc, EFC_FCMD_WP,
                                            us_page);
                    }

                    if (ul_error) {
                            return ul_error;
                    }

                    /* Progression */
                    p_buffer = (void *)((uint32_t) p_buffer + writeSize);
                    ul_size -= writeSize;
                    us_page++;
                    us_offset = 0;
            }

    #if SAM3S || SAM3N || SAM3XA || SAM3U
            /* According to the errata, restore the wait state value. */
            efc_set_wait_state(p_efc, ul_fws_temp);
    #endif

            return FLASH_RC_OK;
    }

    这个函数嵌套很深,比较复杂,笔者也是单步调试,好多遍才搞懂。水平有限。
    第四步,就是上锁
    调用flash_lock()函数,路径同上
    代码附上
    uint32_t flash_lock(uint32_t ul_start, uint32_t ul_end,
                    uint32_t *pul_actual_start, uint32_t *pul_actual_end)
    {
            Efc *p_efc;
            uint32_t ul_actual_start, ul_actual_end;
            uint16_t us_start_page, us_end_page;
            uint32_t ul_error;
            uint16_t us_num_pages_in_region =
                            IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;

            /* Compute actual lock range and store it */
            compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end);

            if (pul_actual_start != NULL) {
                    *pul_actual_start = ul_actual_start;
            }

            if (pul_actual_end != NULL) {
                    *pul_actual_end = ul_actual_end;
            }

            /* Compute page numbers */
            translate_address(&p_efc, ul_actual_start, &us_start_page, 0);
            translate_address(0, ul_actual_end, &us_end_page, 0);

            /* Lock all pages */
            while (us_start_page < us_end_page) {
                    ul_error = efc_perform_command(p_efc, EFC_FCMD_SLB, us_start_page);

                    if (ul_error) {
                            return ul_error;
                    }
                    us_start_page += us_num_pages_in_region;
            }

            return FLASH_RC_OK;
    }

    官方的库函数,都是很复杂,目前没有简单的寄存器版本,看的很累。有兴趣的自己研究。


    片内flash的读,步骤是
    解锁,读取,上锁,这个很简单,不在此处多说。
    水平和经验有限,请大家多指点,谢谢!
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-27 11:39 , Processed in 0.115166 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.