AMLogic的8613 MBOX是一个非常不错的视频播放系统,稳定、成熟度高,成本也较低。其开发的AVOS应该是基于uC/OS内核做的,运行效率很高。其开发的模式也很有意思,没有文档,网上也找不着资料,只能手把手地教,甚至连它的开发环境也只能到其公司去安装。开发过程中遇到问题是常有的事,有时只能自己摸索。前几天我自己就遇到个SPI问题,在这里记录一下供参考。
起因是换了一个开发板。这块新板的SPI-Flash的型号跟原板不同,原板的是25x32VSIG,新板是N25S32-75HE,测试的结果是可以调试,但烧录时瞬间假烧完成,重新上电没反应。问AML那边的支持,答曰可能不支持该型号,底层驱动的代码只有原厂才有无法获取修改,建议换SPI。
于是买了跟原板一样的25x32 SPI换上去,但不知是不是硬件不兼容,这次索性连调试都无法进行了,直接下载完就校验出错。把原板的SPI拖下来,焊到新板上,问题依旧。
换回新板N25S32的SPI,调试跟踪,发现是打开SPI设备时出错了,尝试调用SPIGetDevice()获取设备信息,结果是返回空。意思是没有找到支持的SPI设备。因为系统支持的SPI已经在bsp.c里列明了,只支持以下几种:
SPISupport(&spi_w25x16);
SPISupport(&spi_w25q16);
SPISupport(&spi_mx25l3205d);
SPISupport(&spi_w25x32);
SPISupport(&spi_w25x16V);
SPISupport(&spi_MX25L800);
SPISupport(&spi_en25b32b);
SPISupport(&spi_MX25L160);
SPISupport(&spi_en25f32b);
另外spi_flash.h里还有几种SPI的声明,但经测试加入系统后仍然无法识别N25S32。
为了探明SPI的识别原理,找出各型号SPI的区别,我写了一个函数,将系统能支持的SPI的所有信息全打印出来。spi_flash.h里有SPI结构的定义:
typedef struct{
unsigned deviceId;
char* chipname;
unsigned chip_size; // chip size in byte
unsigned block_size;
unsigned sector_size;
SpiFlashOpResult (*erase_chip) (SpiFlashDevice *device);
SpiFlashOpResult (*erase_block)(SpiFlashDevice *device, unsigned block_num);
SpiFlashOpResult (*erase_sector)(SpiFlashDevice *device, unsigned sector_num);
SpiFlashOpResult (*write_address)(SpiFlashDevice *device, unsigned spiaddr, unsigned *src_addr, int len);
SpiFlashOpResult (*read_address)(SpiFlashDevice *device, unsigned spiaddr, unsigned *dest_addr, int len);
int (* get_sector_num)(SpiFlashDevice *device,unsigned spiaddr);
void *fs_offset;
unsigned fs_kb;
}SpiFlashChip;
其中很明显,erase_chip、erase_block、write_address等函数是一样的,在spi_flash.h里有相应的实现。我们只需要打印其它信息:
//added by huz
int spi_info_i=0;
void print_spi_info(const SpiFlashChip * spi)
{
if(spi==NULL)
{
printf("spi is null/n");
return;
}
spi_info_i++;
printf("spi_%d info :/n",spi_info_i);
printf("deviceId: %d (HEX:%X)/n",spi->deviceId,spi->deviceId);
printf("chipname: %s/n",spi->chipname);
printf("chip_size: %d/n",spi->chip_size);
printf("block_size: %d/n",spi->block_size);
printf("sector_size: %d/n",spi->sector_size);
printf("fs_offset: %X/n",((int)spi->fs_offset));
printf("fs_kb: %d/n/n",spi->fs_kb);
}
void print_spi_infos()
{
printf("by huz - spi infos:/n/n");
print_spi_info(&spi_w25x16);
print_spi_info(&spi_w25q16);
print_spi_info(&spi_mx25l3205d);
print_spi_info(&spi_w25x32);
print_spi_info(&spi_w25x16V);
...
print_spi_info(&spi_s25fl032p);
}
运行结果,在JTAG调试时输出如下:
by huz - spi infos:
spi_1 info :
deviceId: 1388783 (HEX:1530EF)
chipname: WINBOND W25X16
chip_size: 2097152
block_size: 65536
sector_size: 4096
fs_offset: 1FF000
fs_kb: 4096
spi_2 info :
deviceId: 1392879 (HEX:1540EF)
chipname: WINBOND W25Q16
chip_size: 2097152
block_size: 65536
sector_size: 4096
fs_offset: 1FF000
fs_kb: 4096
spi_3 info :
deviceId: 1450178 (HEX:1620C2)
chipname: MX25L3205D
chip_size: 4194304
block_size: 65536
sector_size: 4096
fs_offset: 3FF000
fs_kb: 4096
spi_4 info :
deviceId: 1454319 (HEX:1630EF)
chipname: WINBOND W25X32
chip_size: 4194304
block_size: 65536
sector_size: 4096
fs_offset: 3FF000
fs_kb: 4096
spi_5 info :
deviceId: 1388783 (HEX:1530EF)
chipname: WINBOND W25X16V
chip_size: 2097152
block_size: 65536
sector_size: 4096
fs_offset: 1FF000
fs_kb: 4096
...
spi_17 info :
deviceId: 1376769 (HEX:150201)
chipname: SPANSION S25FL032P
chip_size: 4194304
block_size: 65536
sector_size: 4096
fs_offset: 3F0000
fs_kb: 65536
很显然,deviceId和chipname是决定SPI型号用的,而deviceId应该是关键,每个SPI的deviceId都不一样,系统初始化时应该是会把支持的SPI的deviceId轮询一次,如果有响应的话则说明对应型号的SPI接到系统上了。
于是在网上查了下N25S32-75HE的资料,其中有设备ID的说明:
跟上述打印的信息一比较,显然我们需要的设备ID是0x1630D5。于是手工增加了一个SPI的定义:
const SpiFlashChip spi_N25S32XX={
0x1630d5,
"QTHUZ N25S32",
(32/8)*1024*1024,
65536,
4*1024,
SPIEraseChip,
SPIEraseBlock,
SPIEraseSector,
SPIWrite,
SPIRead,
SPIGetSectorNum,
(void *) 0x3ff000,
4*1024, };
SPISupport(&spi_N25S32);
接着运行,发现用SPIGetDevice()确实能找到SPI了。于是修改了代码,满怀希望地开始烧录,但最终仍然是写入失败,断点停在一个写参数的位置。
分析了一下原因,这时除了chipname,其它参数都是相当正确的。由于没有SPI的驱动代码,也无法判断原因,只能猜测是AML做了什么手脚。
由于N25S32的芯片号称是跟W25X32兼容的,于是我又想到,如果直接用W25X32的定义,强制在内存中修改其设备ID,也许可以骗过AML。说干就干,我在SPI初始化前加入以下代码:
int devid=0x1630d5;
memcpy((void*)&(spi_w25x32.deviceId),(void*)&devid,4);
再次运行,用SPIGetDevice()获取并打印SPI信息如下:
spi_1 info :
deviceId: 1454293 (HEX:1630D5)
chipname: WINBOND W25X32
chip_size: 4194304
block_size: 65536
sector_size: 4096
fs_offset: 3FF000
fs_kb: 4096
呵呵,W25X32的设备ID被修改成0x1630d5。接着修改代码执行烧录,这次终于烧录成功:
>make prom
Using Sun Microsystems Inc. Java version 1.6.0_06 on Windows.
Welcome to the GUI version of the MetaWare Debugger, v8.2.5 (1362).
License SeeCode expires
USB JTAG Firmware (Ver1.04) / DLL (Ver1.05)
Parallel port driver (gportio.sys) version 4 (fast) detected.
ELF segment #0 addr 0x3800000 size 0x000130 .
ELF segment #1 addr 0x3800500 size 0x370b14 ................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
.........
ELF segment #1 addr 0x3b71014 zero 0x024f30 (program zeroes BSS)
[1] Progress display created was 10920e28
License SC_AC expires
Added by huz - Burn start...
spi_1 info :
deviceId: 1454293 (HEX:1630D5)
chipname: WINBOND W25X32
chip_size: 4194304
block_size: 65536
sector_size: 4096
fs_offset: 3FF000
fs_kb: 4096
by huz - open source: /dev/ramdisk0
by huz - loop segs
by huz - open target: /dev/spi
by huz - upgrade start...
upgrading in progress 99%
by huz - clean memory
by huz - exiting...
by huz - Burn OK, can power down now.
Shutting down all processes...Done
重新上电,终于在视频输出上看到亲切的开机界面了。