libero PolarFire soc SPI-DirectC .dat 烧录文件解析

 

libero PolarFire soc SPI-DirectC 实战 生成 固件 包含 softconsole 生成 的 HEX 文件 - 所长 - 博客园

 

1、参考文档 SPI-DirectC User Guide,下图是 系统框图, 可以使用 一个芯片 通过SPI接口 烧录文件到  目标设备 ,目标设备支持 smartfusion2 polarfire 、以及 polarfire soc 系列

image

 2、升级文件 格式描述

image

3、实际文件 截图

 

image

 4、字段1 , Designer Version Number 24字节

G5M-Designer

5、字段2 , Header Size  , 0x 48 = 72 字节

6、字段3 , Image Size,  4个 字节  0x90C232 = 9486898 字节 ,正好 整个文件大小!

7、字段4 ,DAT File Version 1个字节  0x05

8、字段5, Tools Version Number 2个字节  = 0x0034 

9、字段6 , Map Version Number 2个字节 = 0x0000

10、字段7 , Feature Flag = 0x0000

11、Device Family = 0x08  , 正好和 SPI-DirectC /  dpalg.h/ 137行/  代码中   #define G5SOC_DEVICE_FAMILY   0x8u  

 12、Device ID = 0x0F81A1CF 

13、 Device ID Mask = 0x0F FF FF FF

14、Silicon Signature 0x00 1c 1c 1e 签名

15、Checksum = 0x3FC0

16 、Number of BSR Bits = 0x064F

17、Number of Components = 0x0008

18、Data Size = 0x0005

19、Erase Data Size =  0x0003

20、Verify Data Size = 0x0000

21、ENVM Data Size = 0x00 00

22、ENVM Verify Data Size = 0x00 00 

23、UEK1_EXISTS  0x00 

后面都是0 , 最后 多出 两个字节, 0x0006 无法解析,   

 

header  大小这里是 72 字节 , 和 文档 对不上   ,文档里只有 70字节 相关解析!

 

数据块 编号 0x02  0x03 0x04 0x05 0x08 0x09

image

 

 

 

数据块 编号 对应 含义 :DirectC | Microchip Technology  SPI-DirectC / dpalg.h / 87行

#define GXM_Header_ID                        0u
#define GXM_USER_INFO_ID                     1u
#define GXM_ACT_UROW_DESIGN_NAME_ID          2u
#define GXM_BsrPattern_ID                    3u
#define GXM_BsrPatternMask_ID                4u
#define GXM_NUMBER_OF_BLOCKS_ID              5u
#define GXM_UPK1_ID                          6u
#define GXM_UPK2_ID                          7u
#define GXM_datastream_ID                    8u
#define GXM_erasedatastream_ID               9u
#define GXM_VerifyDataStream_ID              10u
#define GXM_EnvmDataStream_ID                11u
#define GXM_EnvmVerifyDataStream_ID          12u
#define GXM_DPK_ID                           13u
 
02 80 00 00 00 09 00 00 00, 数据块 0x02  , 数据地址 0x00 00 00 80 , 数据长度 9个字节 ,  说是9个字节,但是 不足16个字节 补的0 , 看到这里 前面 header 说是 70字节, 后面补充 2个0x00 , 满足 4字节对齐的 !
 
99 70 32 9C EC 97 63 85 2C 00 00 00 00 00 00 00

image

 

03 90 00 00 00 CA 00 00 00 , 数据块 0x03,  数据地址 0x00 00 00 90,  数据长度 0xCA

image

 04 60 01 00 00 CA 00 00 00 数据块 0x04  ,  地址  0x0160  长度 0xCA 

image

 

05 30 02 00 00 16 00 00 00  数据块 0x05   数据地址 0x230 ,  数据长度  0x16 , 这个字段 22字节 分成 了 8个 22bit ,用于 记录 每次 16字节传输的 循环次数!

数据内容是 

1F 00 C0 26 00 90 7A 90 8C 0A 00 1F 00 C0 07 00 B0 09 00 7C 00 00

 

image

 

08 50 02 00 00 E0 BF 90 00  数据块 0x08 ,  数据地址 0x250 , 数据长度  0x90BFE0  

image

 

09 A0 B4 90 00 00 00 00 00  数据块 0x09  ,  数据地址 0x90B4A0 ,  数据块 长度 0x00

 

 

void dp_G5M_do_program(void)  函数 解析
 
第一步 :  设置编程模式,发送指令  g5_pgmmode = 0x01 ;
 
第二步 : 读取 header  字段中 的   Data Size 字段 , 值 = 0x05,  函数如下:  这一步 把全局变量 
global_uint1 = 5,   global_uint2 = 1;  干啥用的 不知!
 
// 根据 根据偏移 55 读取 header 中的   Data Size 字段 
dp_get_bytes(GXM_Header_ID,GXM_DATASIZE_OFFSET,GXM_DATASIZE_BYTE_LENGTH);
 
第三步:调取  dp_G5M_process_data(GXM_datastream_ID);  处理 数据块  编号 =  0x08 =  GXM_datastream_ID
 
这里有 FOR 外循环 ,index 初始值 = global_uint2  =1  , 循环 次数 = global_uint1 = 5次;  循环多少次 ,是 生成 的文件 里 Data Size 字段 决定的。
 
第一次循环
 
下面这段操作 就是 从 22字节 里,取出 对应 22bit 的值, 22字节 共计分成 8个 22bit!
先是读取 数据块编号 =  GXM_NUMBER_OF_BLOCKS_ID = 5,  数据偏移 = 0*22/8=0,  数据长度 4个字节 赋值 给  global_ulong1 ,
根据  数据块 05 内容 1F 00 C0 26 00 90 7A 90 8C 0A 00 1F 00 C0 07 00 B0 09 00 7C 00 00, 推断出 global_ulong1 = 0x26C0001F;
global_ulong1 >> 1-1)*22/%8 = 0; 这一步操作没有变化!
global_ulong1  =  global_ulong1  & 0x3FFFFF =  0x1F
 
内循环 , 循环 次数 = global_ulong1  的值 = 31 次。
‘’‘重点’‘‘这里仔细看了下, 数据块 05 字段里 有 22字节, 22字节 分成8个 22bit , 每个 22bit 对应的值就是 内循环次数。2026年1月23日 16点19分’’‘’‘’
 
spi_command_buffer = G5M_SPI_FRAME_DATA;
dp_G5M_get_and_shift_in(BlockID, SPI_BUFFER_BIT_SIZE, DataIndex);
 
发送 指令 spi_command_buffer  G5M_SPI_FRAME_DATA = 0xEE ,  读取 数据块 0x08 ,  BUFF 大小 128 bit  = 16 字节, 数据 index = 0;
 
调用函数  dp_get_data 根据 数据块编号=8 , 和 数据起始位置   start_bit_index = DataIndex。
 
dp_G5M_check_hwstatus // 调用 接口 检测 BUSY 状态
 
// 将1个字节命令 0XEE 和 读取到 的 16字节数据 =  17个字节 传输给 spi 从机!
do_SPI_SCAN_in(spi_command_buffer, SPI_BUFFER_BIT_SIZE, page_buffer_ptr); (0xEE,  128,  16字节数据 );
 
 数据 index = index + (128bit = 16 字节);  继续内循环!
 
 
#include <stdio.h>
#include <stdint.h>

// data_block_5 有 22 字节
uint8_t data_block_5[22] = {0x1F,0x00,0xC0,0x26,0x00,0x90,0x7A,0x90,0x8C,0x0A,0x00,
    0x1F,0x00,0xC0,0x07,0x00,0xB0,0x09,0x00,0x7C,0x00,0x00};

uint32_t cycle_cnt = 0;

uint32_t dp_get_bytes( uint32_t byte_index )
{
    // 最高位字节(左移24位),最低位字节(左移0位)
    return (uint32_t)data_block_5[byte_index+3] << 24 | 
           (uint32_t)data_block_5[byte_index+2] << 16 | 
           (uint32_t)data_block_5[byte_index+1] << 8  | 
           (uint32_t)data_block_5[byte_index+0];
}

int main( void )
{
    for( int i=1; i<=5; i++ )
    {

        // 内循环 次数变量 长度 是  22bit 
        // 因此 22字节里, 存放了  8个 22bit 的 内循环次数
        // 先取出 4个字节数据, 然后 再进行移位, 在进行22bit与运算,最后得出 22bit
        cycle_cnt = dp_get_bytes(((i - 1u) * 22u) / 8u);
        cycle_cnt = cycle_cnt >>(((i - 1u) * 22u) % 8u);
        cycle_cnt = cycle_cnt & 0x3FFFFF;

        printf( "外循环=%d, 内循环=%d.\n", i, cycle_cnt );

    }

    printf( "end.\n" );
}

 

运行结果:

 

外循环=1, 内循环=31.
外循环=2, 内循环=155.
外循环=3, 内循环=591785.
外循环=4, 内循环=675.
外循环=5, 内循环=31.
end.

 
dp_G5M_erase_action  擦除 执行函数 解析 ;
 
擦除 也分 内循环和外循环 ,   外循环 = header 里的 Number of Components 字段 = 8  -(  Erase Data Size = 3 -1) , 即 结果 = 8-2=6;
 
外循环 从 6 开始  到 8 结束, 也就是 说 上面 那个 22字节, 也记录了  擦除 的 内循环次数 !,这也就是为什么 是 22 字节了, 前五个 是  编程 内循环次数, 后三个是 擦除内循环次数!!!!
 

外循环=1, 内循环=31.
外循环=2, 内循环=155.
外循环=3, 内循环=591785.
外循环=4, 内循环=675.
外循环=5, 内循环=31.
外循环=6, 内循环=31.
外循环=7, 内循环=155.
外循环=8, 内循环=31.

 
 总结:
 
  擦除内循环 总次数 =  31+155+31 = 217 , 每次 16字节, 217 *16 = 3472字节 = 0xD90;  数据块 9 中的 长度 是 0,  对不上 ,尴尬!
  编程内循环 总次数 = 31+155+591785+675+31 = 592677,592677*16字节 = 9482832= 0x90B250  , 数据块8 中的 长度 =  0x90BFE0   对不上, 尴尬 ! 差值 = 3472 /16 = 217,  难道是  编程数据块的长度 包含了 擦除数据块的 长度,?
 
又去分析了一下 数据 ,上面分析是对的, 编程数据块长度 包含了 擦除数据块 长度:

// 编程 数据块 8 起始地址 0x250, 数据长度 0x90BFE0 两者之和 = 0x90C230 再加2个字节等于整个文件大小
// 擦除 数据块 9 起始地址 0x90B4A0, 数据长度0
// 分析结果: 编程数据块 中 包含了 擦除数据块

// 编程字节数 = 0x90B4A0 - 0x250    = 擦除总字节数 0X90B250= 9482832 / 16 = 内循环总次数= 592677
// 擦除字节数 = 0x90C230 - 0x90B4A0 = 擦除总字节数 0XD90= 3472 / 16 = 内循环总次数= 217
 
 校验 流程 ,   首先 发送指令g5_pgmmode  = 0x02  ,  再把 编程数据发过去, 如果,出错误 说明 编程失败!
 
文件 CRC 校验

void dp_compute_crc(void)
{
    for (global_uchar2 = 0u; global_uchar2 < 8u; global_uchar2++)
    {
        global_uint2 = (global_uchar1 ^ global_uint1) & 0x01u;
        global_uint1 >>= 1u;
        if (global_uint2)
        {
            global_uint1 ^= 0x8408u;
        }
        global_uchar1 >>= 1u;
    }
   
    return;
}

 



 

posted on 2026-01-22 10:50  所长  阅读(86)  评论(0)    收藏  举报

导航