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.

[参考译文] TCAN4550EVM:无法通过 STM32F407VET6与 TCAN4550EVM 建立通信

Guru**** 667810 points
Other Parts Discussed in Thread: TCAN4550EVM, MSP430FR6989, TCAN4550
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/interface-group/interface/f/interface-forum/1250484/tcan4550evm-trouble-in-establishing-communication-to-tcan4550evm-with-stm32f407vet6

器件型号:TCAN4550EVM
主题中讨论的其他器件: MSP430FR6989TCAN4550

您好!

我正在尝试 将 TCAN4550EVM 连接到我的 STM32F407VET6板、但我在第一步中遇到困难。 我甚至无法正确读取器件 ID。 我从地址'h000 &'h0004得到的是随机值。

我能够使用 USART 和 COM 功能 并 读取 MCU 板上闪存的器件 ID、因此 MCU 本身不会损坏。  

我正在使用的编译器是 Keil V5 Lite。 网站上的代码示例似乎用于 其他编译器和 MCU、因此我无法直接使用。  我将代码简化为与 SPI 相关的代码、希望有人可以检查出任何问题。 我在 MCU 应用方面的经验非常有限。 可能是简单的错误。

我将 SPI 频率设置为10MHz (APB 时钟为80MHz)、CPHA=0、CPOL=0。 仅连接6根导线:VBAT 和 GND 至12V 电源、SCLK 至 PA5、SDI 至 PA7、SDO 至 PA6、NCS 至 PA4。

void SPISendByte(unsigned char tmpData)
{
	while((SPI1->SR&2)==0);		//wait for TXE
	SPI1->DR = tmpData;
}
unsigned char SPIGetByte()
{
	while((SPI1->SR&2)==0);		//wait for TXE
	while(SPI1->SR&(1<<7));		//wait for !BSY
	SPI1->DR = 0;		//send dummy data
	while(!(SPI1->SR&1));		//wait for RXNE
	return SPI1->DR;
}

void TCANReadBytes(unsigned short address, unsigned char *tmpC, unsigned short len1)
{
	GPIOA->BSRRH |= GPIO_Pin_4;		//set to 0, enable
	SPISendByte(0x41);		//read
	SPISendByte(address>>8);		//MSB
	SPISendByte(address&0xFF);		//LSB
	SPISendByte(len1);		//len1*32bit
	while((SPI1->SR&2)==0);		//wait for TXE
	while(SPI1->SR&(1<<7));		//wait for !BSY
	SPI1->DR;		//read the last dummy byte
	for (unsigned short idx1=0; idx1<len1*4; ++idx1)
		tmpC[idx1] = SPIGetByte();
	GPIOA->BSRRL |= GPIO_Pin_4;		//set to 1, disable
}

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	USART1_Init(115200);

	//SPI settings
	RCC->AHB1ENR |= RCC_AHB1Periph_GPIOA;
	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4;		//nCS
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIOA->BSRRL |= GPIO_Pin_4;		//set to 1, disable NCS
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
	
	RCC->APB2ENR |= (1<<12);		//enable SPI1 clock
	SPI1->CR1 |= 0 << 0;		//CPHA = 0
	SPI1->CR1 |= 0 << 1;		//CPOL = 0
	SPI1->CR1 |= 1 << 2;		//master mode
	SPI1->CR1 |= 2 << 3;		//baudrate = fPCLK /8
	SPI1->CR1 |= 0 << 7;		//MSB first
	SPI1->CR1 |= 1 << 9;		//software slave management
	SPI1->CR1 |= 1 << 8;		//software slave internal
	SPI1->CR1 |= 0 << 10;		//RXonly =0, full-duplex
	SPI1->CR1 |= 0 << 11;		//frame format: 8 bit data
	SPI1->CR1 |= 1 << 6;		//enable external
	
	unsigned char tmpC[5];
	tmpC[4] = 10;
	for(int idx1=0;idx1<8;idx1=idx1+4)
	{
		tmpC[0] = 0;
		tmpC[1] = 0;
		tmpC[2] = 0;
		tmpC[3] = 0;
		TCANReadBytes(idx1, tmpC, 1);
		USART1SendChar((char*)tmpC, 5);		//send the response to PC via COM port
	}

	while (1)
	{
	}
}


响应将
[ 2023年07月20日10:43:10.502]#接收十六进制>
00 00 00 00 0A C0 7F F2 40 0A
[ 2023年07月20日10:43:12.824]#接收十六进制>
FF EA 00 0A 02 00 00 0A
[ 2023年07月20日10:43:15.247]#接收十六进制>
FF FF 92 00 0A 02 00 00 0A
[ 2023年07月20日10:43:17.708]#接收十六进制>
FF F5 40 0A 02 00 00 0A
[ 2023年07月20日10:43:20.001]#接收十六进制>
FF FF 92 00 0A 00 00 00 0A
[ 2023年07月20日10:43:23.255]#接收十六进制>
00 00 00 00 0A 00 00 52 0A
[ 2023年07月20日10:43:25.510]#接收十六进制>
FF FF 89 00 0A 00 01 39 05 0A
[ 2023年07月20日10:43:27.581]#接收十六进制>
00 00 00 00 0A 00 00 00 0A
[ 2023年07月20日10:43:29.656]#接收十六进制>
00 00 00 00 0A 00 00 00 0A
[ 2023年07月20日10:43:31.665]#接收十六进制>
00 00 00 00 0A 00 00 00 0A
[ 2023年07月20日10:43:33.786]#接收十六进制>
00 00 00 00 0A 00 00 00 0A
[ 2023年07月20日10:43:35.888]#接收十六进制>
00 00 00 00 0A 00 00 00 0A
[ 2023年07月20日10:43:38.188]#接收十六进制>
7F FF FF 0A C4 80 00 00 0A
[ 2023年07月20日10:43:40.176]# RECV HEXE>
FF FF 92 00 0A 00 01 39 05 0A

我尝试在 MCU 启动期间读取 TCAN ID、并使用 MCU 板的复位按钮对其进行了测试。

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

    您好 Reko:

    TCAN4550演示代码是使用 Code Composer Studio 和 MSP430FR6989 MCU 开发的。  但是、大多数代码是 ANSI-C、可按原样移植到任何应用中。  必须修改固件 GPIO 引脚控制和 SPI 驱动程序以匹配应用的 MCU、例如 本例中的 STM32F407VET6。

    您是否能够使用示波器或逻辑分析仪监控 SPI 信号?  如果是、它们应该与数据表中显示需要遵循的字节序列的 SPI 读取和写入数字相匹配。  请注意、单个寄存器读取/写入事务有两个数据字、NCS 引脚在整个64位期间必须保持低电平。  它无法在32位字之间转换为高电平、这是调试 SPI 驱动器代码时的常见观察结果。

    请注意、数据表图显示了双倍寄存器写入或读取、该值在第一个(标头)字中设置"长度"字节、这将指示需要写入或读取2个(数据)字。  对于单次寄存器读取、您要将长度字节设置为0x01、然后仅在单个32位数据字期间保持 nCS 引脚处于低电平状态。

    您能否共享所有 SPI 信号的示波器或逻辑分析仪图、以及或同时传输的 MOSI 和 MISO 数据以供查看?  仅仅看到收到的响应不能让我知道实际 SPI 信号是多少、其中包括发送到 TCAN4550的 MOSI 数据。  如果 MOSI 数据格式不正确、TCAN4550将不会返回有效数据。

    此致、

    乔纳森

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

    感谢您的建议。 逻辑分析仪是一款非常有用的工具。 我从同事那里借用了一个、发现我的 nCS 引脚异常。 我将 nCS 更改为另一个引脚、并建立了基本通信。

    但我也发现了其他2个问题。

    1. 上电大约5分钟后、TCAN 返回全零、而不是正确的 ID。  nINT 和 nWKRQ 的 LED 熄灭、INH 亮起。 其他功能也可能已停止。

    除了 SPI 线之外、我还将 TCAN 的5V 连接到 MCU 板5V、并将 VIO 连接到 MCU 3.3V。 MCU 板可通过 PC 上的5V 引脚或 USB 电缆供电。 按下复位按钮可使其恢复正常、其中  nINT 和 nWKRQ 打开、 INH 关闭。 我发现此问题与 TCAN4550EVM 类似:连接 MCU 时遇到问题-接口论坛-接口- TI E2E 支持论坛、但我尚未配置 TCAN、并且未连接 CAN 电缆。

    如果 TCAN 在未连接 MCU 的情况下上电、则 INH、GPO2、nINT、GPIO1的 LED 会亮起、并且 nWKRQ 会在上电5分钟后熄灭。 在该状态下、复位按钮不起作用。 电路板必须由电源复位。

    这种 行为是否正常? 我在手册中没有找到状态更改逻辑、所有功能模式都不符合上述 LED 状态。

    2.您的代码样本在读取 SPI 数据时使用"wait_for_idle"。 我复制了这个逻辑、并将其转换为"while (SPI1->SR&(1<<7));"(我在这里学到了:controllerstech.com/spi-using-registers-in-stm32/)。 但逻辑分析仪显示、该线路在一段时间内暂停 SPI 时钟。

    据我所知、ST 和 TI 的 MCU 都是基于 ARM 的、因此它们的行为方式应该类似。 因此我想 "wait_for_idle" 不等于"while (SPI1->SR&(1<<7));"。 我找到了"#define WAIT_FOR_IDLE while ((HWREG16 (SPI_HW_ADDR + OFS_UCBxSTATW)& UCBUSY))"、但我找不到 UCBUSY 的值。 您认为我应该如何解释"wait_for_idle"? 虽然我不使用 code composer、但我想您能理解这两种编译器。

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

    您好 Reko:

    您的第一个问题的答案是器件由于睡眠唤醒错误(SWE)计时器超时而进入睡眠模式、这是器件的失效防护功能之一。  如需更多信息、请参阅数据表的8.4.5失效防护特性部分。  上电后、您将有4分钟的时间来清除 PWRON 标志(0x0820[20])或配置器件、并通过写入工作模式和引脚配置寄存器(0x0800[7:6])中的 MODE_SEL 字段来进入正常模式。  如果在4分钟 SWE 计时器到期之前未发生上述任一情况、则器件将进入睡眠模式并需要唤醒事件。

    在第二个问题中、这实际上只是用来检查 MSP430 MCU 是否仍在积极处理 SPI 传输的一行代码。  UCBUSY 是一个信号、表示器件正在发送或接收。

    因为 SPI 协议是基于边沿的、所以在 SPI 时钟突发之间可以暂停、例如在每8或16位之间暂停。  只要出现时钟信号、就会捕获数据。 大多数 MCU 将在总体数据的较小的8位或16位部分上运行、在 SPI 时钟波形中通常会看到这些短暂的停顿。

    此致、

    乔纳森