⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdramtest.c

📁 对嵌入式系统进行内存遍历测试的源代码, 分为地址线测试, 数据线测试, 内存单元遍历测试, 是一个很完整的内存测试程序
💻 C
字号:
#include "vxWorks.h"
#include "config.h"
#include "semLib.h"
#include "cacheLib.h"
#include "ioLib.h"
#include "taskLib.h"
#include "BoardApi.h" /*added by jack*/
/***************************************************************************** 
 *  函数名称   : TestSdramData(*)
 *  功能描述   : 测试内存数据线是否正常工作
 *  读全局变量 : 无
 *  写全局变量 : 无
 *  输入参数   : 无
 *  输出参数   : 无
 *  返 回 值   : 成功与否
 *  其它说明   : 
 *---------------------------------------------------------------------------
 * 历史记录(变更单, 责任人@修改日期, 操作说明)
 *  $0000000(N/A), 田瑞忠@2007-12-14 9:36:42
 *----------------------------------------------------------------------------
 */
ULONG TestSdramData(void)
{
    register ULONG  i, j, testVal;
    int     testAdrVal;
    
    printf("\nTest Data Bus of SDRAM at %p...\n\n", &testAdrVal);
    testAdrVal = testVal = 0;

    if (testAdrVal != testVal)
    {
        printf("\nCan't write to zero at %p!\n", &testAdrVal);
    }

    for (i = j = 0, testVal = 1; i < 32; i++, testVal <<= 1)
    {
        testAdrVal = testVal;
        printf("Test SDRAM data bus line #%d, ", i);
        if (testAdrVal != testVal)
        {
            printf("read %p while %p expected\n!", testAdrVal, testVal);
            j++;
        }
        else
        {
            printf("OK!\n");
        }
        taskDelay(sysClkRateGet() / 4);
    }
    printf("\nSDRAM test, data line OK!\n");

    return j;
}

/***************************************************************************** 
 *  函数名称   : TestSdramAddr(*)
 *  功能描述   : 测试内存地址线
 *  读全局变量 : 无
 *  写全局变量 : 无
 *  输入参数   : 无
 *  输出参数   : 无
 *  返 回 值   : 成功与否
 *  其它说明   : 部分借鉴了中兴3G平台的思想(最大内存获取, 高端地址开始)
 *---------------------------------------------------------------------------
 * 历史记录(变更单, 责任人@修改日期, 操作说明)
 *  $0000000(N/A), 田瑞忠@2007-12-14 9:34:07
 *----------------------------------------------------------------------------
 */
ULONG TestSdramAddr(void)
{
    UCHAR ucTotalLine, ucErrorLine, ucCountLine, ucIndex, ucBitCount;
    ULONG dwSafeStart, dwSafeEnd, dwTestAddr, dwBitMask;
    ULONG dwTestCount, *pBaseAddr, *pStoreVal, *pStoreAdrs;
    register ULONG dwTestedBit;

    /* 计算有效地址比特数, 减4去除边界单元计数 */
    dwTestAddr = (ULONG)sysPhysMemTop() - sizeof(ULONG);
    for (ucIndex = 0; dwTestAddr; dwTestAddr >>= 1) ucIndex++;
    ucTotalLine = ucIndex;

    printf("\nTest Address Bus of SDRAM...\n");
    
    /* 取得最大的可用测试内存, 实际上是找到最小的低端可用内存地址 */
    dwTestCount = (ULONG)memFindMax() / sizeof(ULONG) * sizeof(ULONG);
    for (pStoreAdrs = NULL; dwTestCount >= 0x2000; dwTestCount -= 0x2000)
    {
        if (NULL != (pStoreAdrs = (ULONG *)malloc(dwTestCount))) break;
    }
    
    if (pStoreAdrs == NULL)
    {
        printf("\nCan't allocate memory for SDRAM address test!\n");
        return BSP_ERROR;
    }

    pBaseAddr = 0;
    pStoreVal = pStoreAdrs + 32;
    dwSafeStart = (ULONG)(pStoreVal + 32) / sizeof(ULONG);
    dwSafeEnd   = ((ULONG)pStoreAdrs + dwTestCount) / sizeof(ULONG);
    
    /* 通常情况下, 系统驻留在低端内存, 测试从终止地址(高端)开始, 
     * 通过切换地址比特位, 可以尽可能地测试到最多的地址线, 
     * 只要系统占用的内存不超过物理存储区的一半, 理论上说就可以遍历所有地址线 */
    printf("\nSafe start address %p, end address %p.\n", 
        dwSafeStart * sizeof(ULONG), dwSafeEnd * sizeof(ULONG));

    ucCountLine = ucErrorLine = 0;

    /* 对于测试地址线用到的存储区, 将原来的数据保留, 
     * 以便在测试结束后可以恢复 */
    pStoreAdrs[ucCountLine] = dwSafeEnd;
    pStoreVal[ucCountLine] = pBaseAddr[dwSafeEnd];
    
    /* 第一个测试地址中的数据清0 */
    pBaseAddr[dwSafeEnd] = 0, dwBitMask = 1, dwTestedBit = 0;

    /* 找到可用的测试地址, 并往相应的存储单元中填入测试数据 */
    for(ucIndex = 2; ucIndex < ucTotalLine; ucIndex++, dwBitMask <<= 1)
    {
        dwTestAddr = dwSafeEnd ^ dwBitMask;

        /* 对于高端内存的数据, 一般不是核心数据, 由于这些数据都可以恢复, 
         * 所以对于超过安全测试区的地址, 也可以进行测试 */
        if (dwTestAddr >= dwSafeStart && 
            dwTestAddr <= (ULONG)sysPhysMemTop() / sizeof(ULONG))
        {
            ucCountLine++, dwTestedBit |= 0x1 << ucIndex;
            pStoreAdrs[ucCountLine] = dwTestAddr;
            pStoreVal[ucCountLine] = pBaseAddr[dwTestAddr];
            pBaseAddr[dwTestAddr] = 0x01010101 * ucIndex;
        }
    }

    /* 当测试的地址线并不充分时, 给出警示信息 */
    if (ucCountLine + 2 < ucTotalLine)
    {
        printf("nOnly test %d address line for all %d line\n",
            ucCountLine, ucTotalLine);
    }

    /* 对比测试数据, 与期望值是否匹配, 从读出来的数据分析, 
     * 不仅可以判断地址线存在问题, 还可以判断存在串扰及部分判断数据线的问题 */
    dwTestAddr = pStoreAdrs[0];
    if (pBaseAddr[dwTestAddr] != 0)
    {
        printf("Begin address read %p at %p while 0 is expected!", 
            pBaseAddr[dwTestAddr], dwTestAddr * 4);
    }
    for (ucBitCount = 2, ucIndex = 1; ucIndex <= ucCountLine;)
    {
        dwTestAddr = pStoreAdrs[ucIndex];
        while ((dwTestedBit & (1 << ucBitCount)) == 0)  ucBitCount++;
        printf("test SDRAM address bus line #%d at %p, ", 
            31 - ucBitCount, dwTestAddr * 4);
        if (pBaseAddr[dwTestAddr] != 0x01010101 * ucBitCount)
        {
            printf("read %p, %p expected!\n", 
                pBaseAddr[dwTestAddr], 0x01010101 * ucBitCount);
            ucErrorLine++;
        }
        else
        {
            printf("OK!\n");
        }
        taskDelay(sysClkRateGet() / 4);
        ucIndex++, ucBitCount++;
    }

    /* 恢复测试用到的内存单元中的数据 */
    for(ucIndex = 0; ucIndex <= ucCountLine; ucIndex++)
    {
        dwTestAddr = pStoreAdrs[ucIndex];
        pBaseAddr[dwTestAddr] = pStoreVal[ucIndex];
    }

    free(pStoreAdrs);

    if (ucErrorLine)
    {
        printf("\nTest Address Bus %d lines Failed, %d error\n.", 
            ucCountLine, ucErrorLine);
        return BSP_ERROR;
    }

    printf("\nTest Address Bus %d lines OK!\n", ucCountLine);
    return BSP_OK;

} /* TestSdramAddr() */

/***************************************************************************** 
 *  函数名称   : TestSdramWR(*)
 *  功能描述   : 内存存储单元遍历测试
 *  读全局变量 : 无
 *  写全局变量 : 无
 *  输入参数   : 无
 *  输出参数   : 无
 *  返 回 值   : 成功与否
 *  其它说明   : 
 *---------------------------------------------------------------------------
 * 历史记录(变更单, 责任人@修改日期, 操作说明)
 *  $0000000(N/A), 田瑞忠@2007-12-14 9:34:07
 *----------------------------------------------------------------------------
 */
ULONG TestSdramWR(void)
{
    ULONG dwBadCells, dwBadCount, dwCount, dwTestCount, dwBadAll;
    ULONG *pBaseAddr;

    /* 取得最大的可用测试内存, 实际上是找到最小的低端可用内存地址 */
    dwTestCount = (ULONG)memFindMax() & 0xffff0000;
    for (pBaseAddr = NULL; dwTestCount >= 0x10000; dwTestCount -= 0x10000)
    {
        if (NULL != (pBaseAddr = (ULONG *)malloc(dwTestCount))) break;
    }
    
    if (pBaseAddr == NULL)
    {
        printf("\nCan't allocate memory for SDRAM address test!\n");
        return BSP_ERROR;
    }

    printf("\nTest memory cell of SDRAM...\n");
    printf("Start address %p, end address %p, length %lu Bytes\n",
        pBaseAddr, pBaseAddr + dwTestCount / sizeof(ULONG), dwTestCount);

    printf("Writing first time(0x55555555):\n");
    dwBadCells = 0, dwBadCount = 0;
    for (dwCount = 0; dwCount < dwTestCount / sizeof(ULONG);)
    {
        pBaseAddr[dwCount++] = 0x55555555;
        if ((dwCount & 0x7fff) == 0)   printf(".");
    }
    
    printf("\nReading first time('.' for OK, '0'~'9' for error):\n");
    for (dwCount = 0; dwCount < dwTestCount / sizeof(ULONG);)
    {
        if (pBaseAddr[dwCount++] != 0x55555555)
        {
            dwBadCells++, dwBadCount++;
        }
        if ((dwCount & 0x7fff) == 0)
        {
            if (dwBadCount)
            {
                printf("%c", '0' + (dwBadCount - 1) * 10 / 0x4000);
            }
            else
            {
                printf(".");
            }
            dwBadCount = 0;
        }    
    }

    printf("\nfirst cycle ended, bad cells %lu\n", dwBadCells);
    taskDelay(sysClkRateGet() / 2);

    printf("Writing seconed time(0xaaaaaaaa):\n");
    dwBadAll = dwBadCells, dwBadCells = 0, dwBadCount = 0;
    for (dwCount = 0; dwCount < dwTestCount / sizeof(ULONG); )
    {
        pBaseAddr[dwCount++] = 0xaaaaaaaa;
        if ((dwCount & 0x7fff) == 0)   printf(".");
    }
    
    printf("\nReading second time('.' for OK, '0'~'9' for error):\n");
    for (dwCount = 0; dwCount < dwTestCount / sizeof(ULONG); )
    {
        if (pBaseAddr[dwCount++] != 0xaaaaaaaa)
        {
            dwBadCells++, dwBadCount++;
        }
        if ((dwCount & 0x7fff) == 0)
        {
            if (dwBadCount)
            {
                printf("%c", '0' + (dwBadCount - 1) * 10 / 0x4000);
            }
            else
            {
                printf(".");
            }
            dwBadCount = 0;
        }    
    }
    printf("\nsecond cycle ended, bad cells %lu\n", dwBadCells);
    dwBadAll += dwBadCells;
    
    free(pBaseAddr);

    return dwBadAll;
}

/***************************************************************************** 
 *  函数名称   : SdramTest(*)
 *  功能描述   : 测试内存地址线
 *  读全局变量 : 无
 *  写全局变量 : 无
 *  输入参数   : 无
 *  输出参数   : 无
 *  返 回 值   : 成功与否
 *  其它说明   : 部分借鉴了中兴3G平台的思想(最大内存获取, 高端地址开始)
 *---------------------------------------------------------------------------
 * 历史记录(变更单, 责任人@修改日期, 操作说明)
 *  $0000000(N/A), 田瑞忠@2007-12-14 9:34:07
 *----------------------------------------------------------------------------
 */
ULONG SdramTest(void)
{
    UCHAR   ucGet;
    ULONG   ulRet;

    /* 禁用CACHE, 以便立即访问数据及地址总线 */
    cacheDisable(DATA_CACHE);
    cacheDisable(INSTRUCTION_CACHE);

    /* 首先测试数据总线 */
    ulRet = TestSdramData();
    printf("Press 'q' to abort, other key to continue...");
    ucGet = getQuitChar("", WAIT_FOREVER);
    if (ucGet == 'q' || ucGet == 'Q')
    {
        return ulRet;
    }

    /* 其次测试地址总线 */
    (ulRet == BSP_OK) ? (ulRet = TestSdramAddr()) : TestSdramAddr();
    printf("Press 'q' to abort, other key to continue...");
    ucGet = getQuitChar("", WAIT_FOREVER);
    if (ucGet == 'q' || ucGet == 'Q')
    {
        return ulRet;
    }
    
    /* 最后测试读写 */
    (ulRet == BSP_OK) ? (ulRet = TestSdramWR()) : TestSdramWR();
    
    cacheEnable(DATA_CACHE);
    cacheEnable(INSTRUCTION_CACHE);
    
    return ulRet;
} /* SdramTest() */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -