器件型号: MSP430FR6007
工具/软件:
您好、
在我的 linke 命令文件中、我执行以下操作:
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.
器件型号: MSP430FR6007
工具/软件:
您好、
在我的 linke 命令文件中、我执行以下操作:
通常、不能假设.text 只有一个 crc_table 条目:
1) 链接器能够生成对齐“空洞“、因此某些字节在加载后无法预测。 对于这种情况、链接器会生成多个条目。
2).text 可以在 FLASH 和 FLASH2 之间拆分。 (如果优先使用 FLASH2,这是不可能的,因为它太大了,但这是可能的。)
只需逐步检查 num_recs 条目次数。
-----
DMASA/DMADA 为 32 位、因此可容纳 FLASH2 中的地址。 若要确保编译器的指针大小正确、应使用内在函数“__data20_write_long",“,如、如示例 msp430fr60x7_DMA_01.c 中所示、此处为:
https://dev.ti.com/tirex/explore/node?node=A__AJThw7eQLuzxGR4hTWjRfQ__msp430ware__IOGqZri__LATEST
我目前在 DMA 源策略中使用 TI 驱动程序库中的 DMA_setSrcAddress。 据我所知、这种实现方式是错误的、可能会成为问题?
void DMA_setSrcAddress(uint8_t channelSelect, uint32_t srcAddress, uint16_t directionSelect)
{
// Set the Source Address
__data16_write_addr((unsigned short)(DMA_BASE + channelSelect + OFS_DMA0SA), srcAddress);
// Reset bits before setting them
HWREG16(DMA_BASE + channelSelect + OFS_DMA0CTL) &= ~(DMASRCINCR_3);
HWREG16(DMA_BASE + channelSelect + OFS_DMA0CTL) |= directionSelect;
}
void DMA_setDstAddress(uint8_t channelSelect, uint32_t dstAddress, uint16_t directionSelect)
{
// Set the Destination Address
__data16_write_addr((unsigned short)(DMA_BASE + channelSelect + OFS_DMA0DA), dstAddress);
// Reset bits before setting them
HWREG16(DMA_BASE + channelSelect + OFS_DMA0CTL) &= ~(DMADSTINCR_3);
HWREG16(DMA_BASE + channelSelect + OFS_DMA0CTL) |= (directionSelect << 2);
}根据 C 编译器用户指南 (SLAU132Y) 表 6-5、“16"与“与“20"表示“表示目标(寄存器)地址的宽度、而不是基准大小(两种情况下均为 32 位)。 在 FR6007 [Ref 数据表 (SLASEV3A) 表 9-64]上、这些寄存器从大约 0x0500 开始、即 16 位可寻址。
因此、虽然 data20 变体可能是一个“好习惯“、但我预计 data16 变体可以正常工作。
从 TI 链接器脚本保存的校验和与我的计算校验和不同。 Im 按字节写入。 您可以忽略 CRC 的类型、它是一个普通的添加功能。 可能有所不同
CRC_TABLE const *p_crc_table_text = &crc_table_text;
CRC_TABLE const *p_crc_table_isr_text = &crc_table_isr_text;
const uint32_t calculatedCrcText = crc_calc((uint8_t *)p_crc_table_text->recs[0].addr,
p_crc_table_text->recs[0].size, 0x00000000, false);
if (calculatedCrcText != p_crc_table_text->recs[0].crc_value)
{
// Error
}
我在隔离式 CRC 元件中进行了一些测试
一些输入
一般而言、如前所述、计算是有效的。 不幸的是、当我创建一个巨大的阵列来模拟一个已填充的 FRAM 时、链接器似乎没有放置它
我创建了一个数组:
__attribute__((section(".const"), used)) const std::array<uint8_t, 0x33000> fill_array{0x01}
在链接器命令文件中、我放置了以下内容:
.const : {} crc_table (crc_table_const, algorithm=CRC32_PRIME)>> FRAM | FRAM2 /* Constant data */
在映射文件中:

它在那里和列表中 
您可以看到它位于较高的 FRAM 上、但在目标上、您可以看到它没有高器件和低器件两个条目。 我真的不明白、甚至不知道如何对其进行仿真以得到误差。 计算出的校验和拟合(可在下图中看到)、因此到目前为止计算是正确的。 在我看来,应该有一些与高和低内存区域有关的东西。

crc_tables 的屏幕截图指示 num_recs=2、但(调试器看到它时)每个都只有一个元素。 这大概来自 crc_tbl.h 中的“crc_record recs[1];“声明 您可能必须使用 Memory Browser 来查看另一个条目。
------------------------
我之前在 FR5994 上使用了高 FRAM 上的 DMA(我需要大型输入缓冲器)、并按预期工作。 也就是说、有零星的报告称 DMAxSA/DA 未获取所有位(存储器模型和勘误表的混合)、通常的建议(如 Lehman 先生在这里所说) 是始终使用 data20_write_long。 (我不知道为什么 DriverLib 人没有。) 在 DMA 操作之前和之后检查 DMA0 寄存器 (CTL/SA/DA/SZ) 可能会很有用。
你会看到,在 FRAM2 填充的情况下,这在这种情况下不太可能(因为你填充了大部分 FRAM2 的阵列)。
您的屏幕截图显示 num_recs=2(对于.text 和.const)、显然这就是所发生的情况。
如果有任何函数声明为 ISR (#pragma vector=)、则将其放入名为“.text:_isr“的函数中、该函数放置在低 FRAM 中。 (我认为)该区域不包括在.text CRC 中。
所以我的 CRC DMA 源方法看起来像这样,但这会杀死系统
我对本模块有很多问题、我非常沮丧。
static void feed(const uint8_t *src, size_t length, const uint8_t *dst)
{
// Add size validation (your original 0x5FF is fine)
if (length > 0xFFFF || length == 0)
{
return; // Invalid size
}
DMA_initParam cfg = {
DMA_CHANNEL_0, // channelSelect
DMA_TRANSFER_BLOCK, // transferModeSelect
length, // transferSize
DMA_TRIGGERSOURCE_0, // triggerSourceSelect
DMA_SIZE_SRCBYTE_DSTBYTE, // transferUnitSelect
DMA_TRIGGER_RISINGEDGE // triggerTypeSelect
};
DMA_init(&cfg);
// Set direction bits
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) &= ~(DMASRCINCR | DMADSTINCR);
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) |= DMASRCINCR_3;
// Try without masking first
__data20_write_long((uintptr_t)&DMA0SA, (uintptr_t)src);
__data20_write_long((uintptr_t)&DMA0DA, (uintptr_t)dst);
// Clear flag and enable
DMA0CTL &= ~DMAIFG;
DMA_enableTransfers(DMA_CHANNEL_0);
DMA0CTL |= DMAREQ;
// Add timeout to debug
uint32_t timeout = 10000;
while (!(DMA0CTL & DMAIFG) && --timeout)
{
__no_operation();
}
if (timeout == 0)
{
// Timeout occurred - add breakpoint here for debugging
__no_operation();
}
DMA_disableTransfers(DMA_CHANNEL_0);
}
我想计算代码的 CRC。 软件太慢、因此应使用 DMA。
从 CRC 驱动程序中、我为馈送函数提供一个存储器块(因为 DMA 长度限制为 16 位)。 根据我的设置、我将该存储器块逐字节传输到一个块中的 CRC 目标地址。 想象一下 dst 是 CRC 目标寄存器。 从设置点开始、DMA 只应递增 src 地址、而不是目标地址。 当我添加 DMA0CTL |= DMAREQ 行时、系统崩溃。 我不希望出现中断。 这条线是否是必需的? 但是当我删除这条线时,我得到了内存移动的超时。 您是否有一个结合使用 DMA 和 CRC 模块来计算 20 位存储器区域中的 CRC 的工作示例?
添加 DMA0CTL |= DMAREQ 行时、系统崩溃。 我不希望出现中断。 是否需要此行?
当然、这是必需的。 必须触发 DMA、否则不会发生任何情况。
嗯。 我只是在查看 GCC 版本的__data20_write_long()、它有什么问题。
#define _data20_write_long(addr,src) \
({ \
unsigned int __tmp; \
unsigned long __addr = addr; \
__asm__ __volatile__ ( \
"movx.a %1, %0 \n\t" \
"mov.w %L2, 0(%0) \n\t" \
"mov.w %H2, 2(%0)" \
: "=&r"((unsigned int) __tmp) \
: "m"((unsigned long) __addr), "ri"((long) src) \
); \
})
在预期的 movx.a 指令之后、有两个字写入。 当与 DMA 地址寄存器一起使用时、这会完全破坏意图并将高位字清零。 过去有一个__data20_write_addr() 没有这种冗余和错误的写入。
e2e.ti.com/.../test_5F00_dma.zip
我使用 driverlib 进行了一个微小的测试。 我可以看到-- data-model large 控制器在频率设置中挂起。 当包含 DMA 设置时、当我排除 DMA 设置时、它不会卡在晶体设置中。 它似乎适用于-data-mode 受限的情况。 但这只是一个直觉,我没有尝试所有的组合。
我没有使用 CRC32 的器件、但我确实在 FR5969 上运行了此代码、没有遇到任何问题:
int main(void)
{
DMA0CTL = DMASBDB | DMASRCINCR_3 | DMADT_1;
DMA0DA = &CRCDIRB_H;
__data16_write_addr(&DMA0SA, 0x10000L);
DMA0SZ = 0xffff;
DMA0CTL |= DMAEN;
CRCINIRES = 0xffff;
DMA0CTL |= DMAREQ;
while (1);
}
它不应该是。 至少通过 GCC 我得到了合理的代码和预期的行为。
$/usr/ti/gcc/bin/msp430-elf-objdump -S a.out
__data16_write_addr(&DMA0SA, 0x10000L);
4468: 81 43 00 00 mov #0, 0(r1) ;r3 As==00
446c: 91 43 02 00 mov #1, 2(r1) ;r3 As==01
00004470 <.Loc.17.1>:
4470: 8c 00 12 05 mova #1298, r12 ;0x00512
4474: 00 18 ec 41 movx.a @r1, 0(r12) ;
4478: 00 00
很遗憾、这对我没有帮助。 第一个 I 使用 CGT、第二个 I 使用__data20_wirte。 我也得到了使用__data20_write 的正确汇编、但当我添加:DMA0CTL |= DMAREQ;(在时钟初始化后完成)时、代码仍然卡滞。 当此行未注释时。 无论出于何种原因、晶体设置在 while 循环中挂起。
uint16_t volatile resetReason = 0;
int main()
{
resetReason = SYSRSTIV;
resetReason = 0;
WDTCTL = WDTPW | WDTHOLD; // Stop the watchdog timer
// To enable LFXT, the PSEL bits associated with the crystal pins must be set. - RM 3.2
// Setting the PSEL bit causes the LFXIN and LFXOUT ports to be configured for LFXT operation.
// LFXIN = PJ.4
PJSEL0 |= BIT4 | BIT5; // Set bits 4 and 5 in PJSEL0 to enable primary function
PJSEL1 &= ~(BIT4 | BIT5); // Clear bits 4 and 5 in PJSEL1 to select primary function
PM5CTL0 &= ~LOCKLPM5; // Clear the LOCKLPM5 bit to enable GPIO functionality
// Unlock CS registers
CSCTL0 = 0xA500; // Password to unlock clock system registers
// Set DCO to 8 MHz
CSCTL1 = 0x000C;
// Configure clock sources
CSCTL2 = SELM__DCOCLK | SELS__DCOCLK | SELA__LFXTCLK;
// MCLK = DCOCLK, SMCLK = DCOCLK, ACLK = LFXTCLK
// Set dividers for MCLK, SMCLK, and ACLK
CSCTL3 = DIVM__1 | DIVS__1 | DIVA__1;
// MCLK = DCO / 1, SMCLK = DCO / 1, ACLK = LFXT / 1
// Enable LFXT with drive strength 3
CSCTL4 &= ~LFXTOFF; // Enable LFXT
CSCTL4 |= LFXTDRIVE_3; // Set LFXT drive strength to 3
// Clear fault flags and wait for LFXT to stabilize
do
{
CSCTL5 &= ~LFXTOFFG; // Clear LFXT fault flag
SFRIFG1 &= ~OFIFG; // Clear oscillator fault flag
} while (SFRIFG1 & OFIFG);
// Lock CS registers
CSCTL0_H = 0x01; // Lock clock system registers
uint16_t length = 0xFFFF;
DMA_initParam cfg = {
DMA_CHANNEL_0, // channelSelect
DMA_TRANSFER_BLOCK, // transferModeSelect
length, // transferSize
DMA_TRIGGERSOURCE_0, // triggerSourceSelect
DMA_SIZE_SRCBYTE_DSTBYTE, // transferUnitSelect
DMA_TRIGGER_RISINGEDGE // triggerTypeSelect
};
uintptr_t src = (uintptr_t)(0x10000);
uintptr_t dst = (uintptr_t)(&CRC32DIRBB0);
DMA_init(&cfg);
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) &= ~(DMASRCINCR | DMADSTINCR);
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) |= DMASRCINCR_3;
__data20_write_long((uintptr_t)&DMA0SA, src);
__data20_write_long((uintptr_t)&DMA0DA, dst);
DMA0CTL &= ~DMAIFG;
DMA_enableTransfers(DMA_CHANNEL_0);
//DMA0CTL |= DMAREQ;
uint32_t timeout = 10000;
while (!(DMA0CTL & DMAIFG) && --timeout)
{
__no_operation();
}
/**/
while (1)
{
};
}您好 Luke、
让我再次解锁该主题并发布客户的最新反馈:
我刚刚注意到其他一些问题:在较低地址(16 位)中使用 DMA 功能时工作正常、但在使用较高的 FRAM 区域时、器件停止工作。
我还在数据表中找到了以下注释:

但让我来展示一下我在做什么:
template <size_t VMaxChunkSize = 0xFFFF>
struct CRC32DataFeedMockWithDma
{
static constexpr auto maxChunkSize()
{
return VMaxChunkSize;
}
static struct Internals m_internals;
static void feed(const uint8_t *src, size_t length, const uint8_t *dst)
{
// Safety check: DMA transfer size is uint16_t, max 65535
if (length > 0xFFFF || length == 0)
{
return; // or assert/abort
}
DMA_initParam cfg = {
DMA_CHANNEL_0, // channelSelect
DMA_TRANSFER_BLOCK, // transferModeSelect
static_cast<uint16_t>(length), // transferSize
DMA_TRIGGERSOURCE_0, // triggerSourceSelect
DMA_SIZE_SRCBYTE_DSTBYTE, // transferUnitSelect
DMA_TRIGGER_RISINGEDGE // triggerTypeSelect
};
DMA_init(&cfg);
// Use proper 20-bit address handling
// Convert pointers to 32-bit first to avoid truncation
uint32_t volatile src_addr = reinterpret_cast<uint32_t>(src);
uint32_t volatile dst_addr = reinterpret_cast<uint32_t>(dst);
// Set the Source Address (20-bit)
__data20_write_long((uint32_t)&DMA0SA, src_addr & 0xFFFFF);
// Reset bits before setting them
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) &= ~(DMASRCINCR_3);
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) |= DMA_DIRECTION_INCREMENT;
// Set the Destination Address (20-bit)
__data20_write_long((uint32_t)&DMA0DA, dst_addr & 0xFFFFF);
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) &= ~(DMADSTINCR_3);
HWREG16(DMA_BASE + DMA_CHANNEL_0 + OFS_DMA0CTL) |= (DMA_DIRECTION_UNCHANGED << 2);
// Clear DMA interrupt flag and start transfer
DMA0CTL &= ~DMAIFG;
DMA_enableTransfers(DMA_CHANNEL_0);
DMA_startTransfer(DMA_CHANNEL_0);
// Poll for completion
while (!(DMA0CTL & DMAIFG))
{
__no_operation();
}
DMA_disableTransfers(DMA_CHANNEL_0);
}
};
你知道这里可能有什么问题吗?
谢谢!
我们解决了这一主题中的问题。
MSP430FR6007:在 20 位地址空间中使用 DMA 失败 — MSP 低功耗微控制器论坛 — MSP 低功耗微控制器 — TI E2E 支持论坛