This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28374S:升级问题

Guru**** 2513185 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1560747/tms320f28374s-upgrade-issue

器件型号:TMS320F28374S


工具/软件:

我需要制定 A 侧和 B 侧升级的要求。 A 侧是程序运行区域、B 侧是程序备份区域。 当主机升级芯片固件时、它会将新的二进制文件写入 B 端。 然后、引导加载程序将 B 侧的内容复制到 A 侧并跳转到 A 侧执行。

但是、我在从 B 端到 A 端的复制过程中遇到了无法解决的问题:每次只复制大约 60%的内容。 二进制文件的总大小约为 157 KB、这意味着每次进程停止前仅复制约 100 KB、导致升级失败。 尽管如此、如果我关闭芯片电源、然后再次为其通电、整个内容将成功复制、芯片可以跳转到 A 侧来执行代码。

为解决此问题、我尝试了以下操作:

  1. 禁用全局中断 (DINT) 以防止其他中断任务中断复制过程。
  2. 在复制过程中馈送看门狗、避免由于看门狗未能及时馈送而导致芯片复位。
  3. 在任务初始化之前执行复制、以防止其他优先级较高的任务中断。
  4. 添加通信延迟以确保芯片有足够的时间执行复制过程。
  5. 怀疑内存不足、因此将用作缓冲区的数组变量声明为静态。

不幸的是、上述措施都没有奏效。 因此、我想征询您的意见:为什么下电上电复位(断电和重新上电)允许芯片完成复制、而看门狗复位则不能?

相关代码

bool flash_copy_region(void)
{
// 定义源地址和目标地址范围
const uint32_t SRC_ADDR_START = 0xA0000;
const uint32_t SRC_ADDR_END = 0xB7FFF;
const uint32_t DST_ADDR_START = 0x88000;
const uint32_t DST_ADDR_END = 0x9FFFF;

// 先擦除目标区域
if (!erase_dest_region(DST_ADDR_START, 0x18000UL))
{
return false;
}

// 检查地址范围大小是否一致
if ((SRC_ADDR_END - SRC_ADDR_START) != (DST_ADDR_END - DST_ADDR_START))
{
// 错误类型:地址范围大小不匹配
return false;
}

// 计算总字节数
const uint32_t TOTAL_BYTES = SRC_ADDR_END - SRC_ADDR_START + 1;

// 使用与原代码相同的缓冲区大小
static uint64_t data_block[256 / sizeof(uint64_t)];
const uint32_t BLOCK_SIZE = sizeof(data_block); // 256字节

// struct
// {
// uint16_t ErrType;
// uint16_t ErrData;
// } err_code = {0, 0};

// 源地址指针(指向Flash区域)
const uint8_t *src_ptr = (const uint8_t *)SRC_ADDR_START;

// 按块复制数据
uint32_t offset;
for (offset = 0; offset < TOTAL_BYTES; offset += BLOCK_SIZE)
{
uint32_t current_block_size = BLOCK_SIZE;

// 处理最后一个可能不完整的块
if (offset + BLOCK_SIZE > TOTAL_BYTES)
{
current_block_size = TOTAL_BYTES - offset;
}

// 计算当前目标地址
uint32_t dst_addr = DST_ADDR_START + offset;

// 通过指针直接从Flash读取数据(不依赖flash_read函数)
memcpy(data_block, &src_ptr[offset], current_block_size);

// 将数据写入目标地址
uint32_t i;
for (i = 0; i < current_block_size / sizeof(uint64_t); i++)
{
uint32_t write_addr = dst_addr + i * sizeof(uint64_t);
uint64_t write_data = data_block[i];

if (!flash_program(write_addr, &write_data))
{
return false;
}
}
}

return true;
}

#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(flash_program, ".TI.ramfunc");
#endif
bool flash_program(uint32_t addr_align_4, const uint64_t * data)
{
bool ok = false;

EALLOW;
do
{
Fapi_StatusType oReturnCheck;

if(addr_align_4 % 4)
{
break;
}

oReturnCheck = Fapi_issueProgrammingCommand((uint32 *)addr_align_4,
(uint16_t*)data,
4,
0,
0,
Fapi_DataOnly);//Fapi_AutoEccGeneration);

while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);

if(oReturnCheck != Fapi_Status_Success)
{
break;
}

ok = true;
}while(0);
EDIS;

return ok;
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Cheng、

    复位后、PLL 和闪存等待状态将处于其默认值;PLL 关闭、闪存 WS 最大为  您是否确认了当您在正常代码执行期间运行此函数时、您已经配置了 PLL 并将适当的 CPU 时钟传递给闪存 API 初始化函数?  同样、您是否确认闪存等待状态寄存器中使用的值与 CPU 时钟频率相匹配?

    禁用 ISR 是一个好主意(对于也调试 WD)、可能会出现的问题是某些代码仍位于可编程的同一闪存组中?  回想一下、在对闪存进行编程时、不能像编程下那样从同一存储体运行代码。

    此致、
    Matthew