你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【NUCLEO-H533RE评测】CmBacktrace 信息存储至FLASH

[复制链接]
andey 发布时间:2024-7-10 14:10

简介

上一篇(【NUCLEO-H533RE评测】CmBacktrace 移植适配)已经适配了CmBacktrace,MCU 发生了hardfault 时会将hardfault信息输出至串口,但是在实际的量产项目中,在客户手中的设备基本不会接着串口查看异常信息,而且有的死机问题复现率不高的,如果我们能将异常信息信息存储到flash中,这样就能将现场的信息保存下来,方便我们点差之前死机的原因。

FLASH 控制

STM32H533 芯片内部集成了512KB的flash 空间,内部有两个bank,每个bank 包含32个section,每个sector 的大小为8KB,内部使用的128bit 的总线对FLASH进行访问,以下是flash 的内部框图,可以方便了解内部结构。

flash.png

flash2.png

本次试验使用flash 的bank2 的 31 sector 的末端的8K FLASH 存储异常信息,每个异常信息块分配2K的空间,最多可以保存四次coredump 的异常信息。

对应代码如下,在cmbtrace 处理的入口调用cmt_recorder_start 函数查找合适的存储空间,在cmbtrace 处理函数退出时,调用cmt_recorder_end 接口lock flash 访问,将cmt_recorder_putc 对接到CmBacktrace 信息输出接口将信息写入flash,对应代码如下:

/** ************************************************************************************************
 * @file     cmback_trace_recoder.c                                                                           *
 * @brief    recoder cortex-m hardfault infomation                                                                       *
 *                                                                                                 *
 **************************************************************************************************/
/***************************************************************************************************
 *                                      Include header files                                       *
 **************************************************************************************************/
#include <stdint.h>
#include <string.h>
#include <stm32h5xx_hal.h>

/***************************************************************************************************
 *                                 Global Macro definition                                         *
 **************************************************************************************************/
#define CMT_HEADER_SIZE            16U
#define CMT_PG_SIZE                16U
#define CMT_FLASH_BASE_START       ((uint32_t)0x0807e000u) /* Base @ of SECTOR 31, 8 Kbytes */
#define CMT_FLASH_BASE_END         (CMT_FLASH_BASE_START + FLASH_SECTOR_SIZE - 1)
#define CMT_INFO_BLOCK_SIZE        2048U
#define CMT_INFO_BLOCK_NUM         FLASH_SECTOR_SIZE/CMT_INFO_BLOCK_SIZE
#define CMT_INFO_MAGIC             0xa1b2c3d4u

/***************************************************************************************************
 *                                  Global Types definition                                        *
 **************************************************************************************************/

/** @brief  Structure defining the recoder block header */
typedef struct cmt_recorder_header{
    union{
        struct{
            uint32_t magic;
            uint32_t pflash_start;
            uint16_t pflash_offset;
            uint16_t size;
            uint32_t crc;
        };
        uint8_t parray[CMT_HEADER_SIZE];
    };
} cmt_recorder_header_t;


static cmt_recorder_header_t  header = {0x00u};

static uint8_t cmt_check_block_is_dirty(uint32_t* p)
{
    int i = 0;

    for(; i < CMT_INFO_BLOCK_SIZE/sizeof(uint32_t);i++)
    {
        if(p[i] != 0xffffffffu)
            break;
    }

    return i == CMT_INFO_BLOCK_SIZE/sizeof(uint32_t) ? 0 : 1;
}

static uint32_t  cmt_get_free_block_addr(void)
{
    uint32_t * p_flash = (uint32_t *)CMT_FLASH_BASE_START;
    uint8_t i = 0;

    for(; i < CMT_INFO_BLOCK_NUM;i++)
    {
        if(p_flash[0] == CMT_INFO_MAGIC)
        {
            /* the block is used to find next */
            p_flash += CMT_INFO_BLOCK_SIZE/4;
        }
        else
        {
            if( 0 == cmt_check_block_is_dirty(p_flash))
                break;
        }
    }

    return  i == CMT_INFO_BLOCK_NUM ? 0 : (CMT_FLASH_BASE_START + i*CMT_INFO_BLOCK_SIZE);
}

static uint8_t pg_array[CMT_PG_SIZE] = {0x00};
static uint8_t index = 0;
static uint8_t cmstart = 0;

uint8_t cmt_recorder_putc(uint8_t ch)
{
    if(cmstart == 0)
        return ch;

    pg_array[index++] = ch;

    if(index == CMT_PG_SIZE)
    {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, header.pflash_start + header.pflash_offset, ((uint32_t)pg_array));
        header.pflash_offset += CMT_PG_SIZE;
        header.size += CMT_PG_SIZE;

        /* reset index & cache buffer */
        index = 0;
        memset((void *)pg_array,0,CMT_PG_SIZE);
    }

    return ch;
}

/**
  * @brief  Gets the sector of a given address
  * @param  Addr: Address of the FLASH Memory
  * @retval The sector of a given address
  */
static uint32_t cmt_get_sector(uint32_t address)
{
    uint32_t sector = 0;

    if((address >= FLASH_BASE) && (address < FLASH_BASE + FLASH_BANK_SIZE))
    {
        sector = (address & ~FLASH_BASE) / FLASH_SECTOR_SIZE;
    }
    else if ((address >= FLASH_BASE + FLASH_BANK_SIZE) && (address < FLASH_BASE + FLASH_SIZE))
    {
        sector = ((address & ~FLASH_BASE) - FLASH_BANK_SIZE) / FLASH_SECTOR_SIZE;
    }
    else
    {
        sector = 0xFFFFFFFF; /* Address out of range */
    }

    return sector;
}

/**
  * @brief  Gets the bank of a given address
  * @param  Addr: Address of the FLASH Memory
  * @retval The bank of a given address
  */
static uint32_t cmt_get_bank(uint32_t addr)
{
    uint32_t bank = 0;

    if (READ_BIT(FLASH->OPTSR_CUR, FLASH_OPTSR_SWAP_BANK) == 0)
    {
        /* No Bank swap */
        if (addr < (FLASH_BASE + FLASH_BANK_SIZE))
        {
            bank = FLASH_BANK_1;
        }
        else
        {
            bank = FLASH_BANK_2;
        }
    }
    else
    {
        /* Bank swap */
        if (addr < (FLASH_BASE + FLASH_BANK_SIZE))
        {
            bank = FLASH_BANK_2;
        }
        else
        {
        bank = FLASH_BANK_1;
        }
    }

    return bank;
}

uint32_t cmt_recorder_start(void)
{
     FLASH_EraseInitTypeDef EraseInitStruct;
     cmstart = 1;
     uint32_t sectorerr;

     HAL_ICACHE_Disable();

     /* Unlock the Flash to enable the flash control register access *************/
    HAL_FLASH_Unlock();

    header.pflash_start = cmt_get_free_block_addr();

    if(0u == header.pflash_start)
    {
        EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
        EraseInitStruct.Banks         = cmt_get_bank(CMT_FLASH_BASE_START);
        EraseInitStruct.Sector        = cmt_get_sector(CMT_FLASH_BASE_START);
        EraseInitStruct.NbSectors     = 1;
        HAL_FLASHEx_Erase(&EraseInitStruct, §orerr);
        header.pflash_start = CMT_FLASH_BASE_START;
    }

    header.pflash_offset = CMT_HEADER_SIZE;

    return 0;
}

uint32_t cmt_recorder_end(void)
{
    if(index != 0)
    {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, header.pflash_start + header.pflash_offset, ((uint32_t)pg_array));
        header.pflash_offset += CMT_PG_SIZE;
        header.size += CMT_PG_SIZE;
    }

    header.magic = CMT_INFO_MAGIC;
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, header.pflash_start, ((uint32_t)header.parray));

    /* Lock the Flash to disable the flash control register access (recommended
     to protect the FLASH memory against possible unwanted operation) *********/
    HAL_FLASH_Lock();

    HAL_ICACHE_Enable();

    return 0;
}


#include "littleshell.h"
#include <stdio.h>

int cmbdump(char argc,char ** argv)
{
    uint32_t * p_flash = (uint32_t *)CMT_FLASH_BASE_START;
    uint8_t i = 0;

    for(; i < CMT_INFO_BLOCK_NUM ; i++, p_flash += CMT_INFO_BLOCK_SIZE/4)
    {
        if(p_flash[0] == CMT_INFO_MAGIC)
        {
            /* the block is used to find next */
            printf("%s",(char *)(p_flash+CMT_HEADER_SIZE));
        }
    }
    return 0;
}

LTSH_FUNCTION_EXPORT(cmbdump,"dump hard fault infomation")



int erase(char argc,char ** argv)
{
     FLASH_EraseInitTypeDef EraseInitStruct;
     uint32_t sectorerr;

     HAL_ICACHE_Disable();

     /* Unlock the Flash to enable the flash control register access *************/
    HAL_FLASH_Unlock();

    EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.Banks         = cmt_get_bank(CMT_FLASH_BASE_START);
    EraseInitStruct.Sector        = cmt_get_sector(CMT_FLASH_BASE_START);
    EraseInitStruct.NbSectors     = 1;
    HAL_FLASHEx_Erase(&EraseInitStruct, §orerr);

    /* Lock the Flash to disable the flash control register access (recommended
    to protect the FLASH memory against possible unwanted operation) *********/
    HAL_FLASH_Lock();

    HAL_ICACHE_Enable();
    return 0;
}

LTSH_FUNCTION_EXPORT(erase,"erase test flash")

功能验证

我们使用之前集成的测试命令触发hard fault,发现异常信息已经按照预期的写入了flash了。

flash3.png

异常信息存储到flash ,我们可以添加命令dump 异常信息至串口方便 我们查看之前发生的死机现场,用于定位异常问题。

flash_4.png

收藏 评论1 发布时间:2024-7-10 14:10

举报

1个回答
y369369 回答时间:2024-8-6 09:03:00

支持一下

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版