运行例程TMS320C6748的SPI Flash,发现程序一直卡在忙判断中,循环执行读状态寄存器的指令,读取到的数据全为0xff。例程仅将SPI1改为了SPI0,然后用的flash芯片为W25Q128JW,请问这种情况应如何调试
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.
运行例程TMS320C6748的SPI Flash,发现程序一直卡在忙判断中,循环执行读状态寄存器的指令,读取到的数据全为0xff。例程仅将SPI1改为了SPI0,然后用的flash芯片为W25Q128JW,请问这种情况应如何调试
下面的我的主函数,基本上对原始例程没有修改
/****************************************************************************/
/* */
/* SPI FLASH 读写测试 */
/* */
/* 2024年12月05日 */
/* */
/****************************************************************************/
/****************************************************************************/
/* */
/* 头文件声明(硬件抽象层HAL) */
/* */
/****************************************************************************/
#include "TL6748.h" // TL6748芯片 ,函数声明
#include "soc_C6748.h" // 系统级芯片SoC ———— C6748 SOC的外设信息
#include "hw_psc_C6748.h" // 电源系统控制器PSC ———— 硬件寄存器和字段
#include "uart.h" // 异步收发传输器UART————宏定义
#include "spi.h" // 串行外设接口SPI————宏定义
#include "psc.h" // 电源系统控制器PSC————宏定义
#include "uartStdio.h" // 函数原型
#include "interrupt.h" // DSP中断相关的API声明和系统中断
#include <string.h> // C标准库中的字符串处理函数
/****************************************************************************/
/* */
/* 宏定义 */
/* */
/****************************************************************************/
// SPI 管脚配置
#define SIMO_SOMI_CLK_CS 0x00000E01 // SPI接口的引脚配置值
#define CHAR_LENGTH 0x8 // 数据长度 或 缓冲区大小
// FLASH 地址
#define SPI_FLASH_ADDR_MSB1 0x0A // 这三行定义了访问SPI Flash时的地址 0A0000
#define SPI_FLASH_ADDR_MSB0 0x00
#define SPI_FLASH_ADDR_LSB 0x00
// SPI Flash 操作指令码
#define SPI_FLASH_SECTOR_ERASE 0xD8 // 扇区擦除命令 0xD8
#define SPI_FLASH_PAGE_WRITE 0x02 // 页写入命令 0x02
#define SPI_FLASH_STATUS_RX 0x05 // 读状态寄存器命令 0x05
#define SPI_FLASH_WRITE_EN 0x06 // 写使能命令 0x06
#define SPI_FLASH_READ 0x03 // 读命令 0x03
// 写操作执行中
#define WRITE_IN_PROGRESS 0x01 // 表示写操作正在进行的标志位
/****************************************************************************/
/* */
/* 全局变量 */
/* */
/****************************************************************************/
// 同步操作的标志
volatile unsigned int flag = 1; // volatile确保编译器不会缓存该变量的值
// 发送和接收数据的长度
unsigned int tx_len;
unsigned int rx_len;
// 用于存放发送、接收、验证数据的数组
unsigned char vrf_data[260];
unsigned char tx_data[260];
unsigned char rx_data[260];
// 指针————指向发送和接收的数据缓冲区
unsigned char *p_tx;
unsigned char *p_rx;
/****************************************************************************/
/* */
/* 函数声明 */
/* */
/****************************************************************************/
void PSCInit(void); // 初始化电源系统控制器PSC
void GPIOBankPinMuxSet(void); // 配置GPIO引脚复用
void SPIDataFormatConfig(unsigned int dataFormat); //配置SPI数据格式
void ReadFromFlash(void); // 从Flash读取数据
void IsFlashBusy(void); // 检查Flash是否忙
void WritetoFlash(void); // 向Flash写入数据
void WriteEnable(void); // 启用写操作
void SpiTransfer(void); // 进行SPI数据传输
void SectorErase(void); // 擦除Flash
int VerifyData(void); // 校验数据
void StatusGet(void); // 获取Flash的状态
void InterruptInit(void); // 初始化中断系统
void SPIInterruptInit(void); // 初始化SPI中断
void SPIInit(void); // 初始化SPI接口
void SPIIsr(void); // SPI中断服务例程
/****************************************************************************/
/* */
/* 主函数 */
/* */
/****************************************************************************/
int main(void)
{
PSCInit(); // 初始化PSC
GPIOBankPinMuxSet(); // GPIO管脚复用
UARTStdioInit(); // 初始化UART,使用串口2
UARTPuts("SPI Flash实验\r\n", -1);
GPIOBankPinMuxSet(); // 初始化GPIO管脚复用,再次调用,保证GPIO配置正确
InterruptInit(); // 初始化DSP中断
SPIInterruptInit(); // 初始化SPI中断
SPIInit(); // 初始化SPI接口
WriteEnable(); // 写使能启用对Flash的写操作(擦除前需要写使能)
SectorErase(); // 擦除 Flash ——————————————————目前程序问题出现在这里
// 向Flash写入数据并验证是否正确
WriteEnable(); // 写使能
WritetoFlash(); // 写入Flash数据
ReadFromFlash(); // 读取Flash数据
VerifyData(); // 验证数据一致性
UARTPuts("已验证Flash数据\r\n", -1);
// 进入无限循环,等待下一步处理或退出程序
for(;;)
{
}
}
// ———————————————————————————————————————— 其他子函数 ————————————————————————————————————————
/****************************************************************************/
/* */
/* 初始化 */
/* */
/****************************************************************************/
// PSC初始化
void PSCInit(void)
{
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_SPI0, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
// 指定PSC0基地址、指定硬件模块SPI0、电源开启、模块使能
// 确保SPI0模块有电且随时可用(SPI0模块由PCS0管理)
}
// GPIO 管脚复用配置
void GPIOBankPinMuxSet(void)
{
SPIPinMuxSetup(0); // 启用SPI0通道————参数为0表示设置PINMUX3的15_0位(对应SPI0),参数为1表示设置PINMUX5的23_8位(对应SPI1)
SPI1CSPinMuxSetup(0); // 设置SPI0_SCS0引脚————为SPI0通道设置片选引脚SPI0_SCS0
}
// 初始化DSP中断
void InterruptInit(void)
{
IntDSPINTCInit(); // 初始化DSP中断控制器
IntGlobalEnable(); // 使能DSP全局中断
}
// 初始化SPI中断
void SPIInterruptInit(void)
{
IntRegister(C674X_MASK_INT4, SPIIsr); // 注册中断服务函数————注册INT4中断函数为SPIIsr,将c674xISRtbI[4]指向SPIIsr
IntEventMap(C674X_MASK_INT4, SYS_INT_SPI0_INT); // 映射中断事件————将SPI0中断源映射到INT4
IntEnable(C674X_MASK_INT4); // 使能可屏蔽中断————使能INT4
}
// 初始化SPI接口
void SPIInit(void)
{
unsigned char cs = 0x01; // 配置SPI片选信号
unsigned char dcs = 0x01;
unsigned int val = SIMO_SOMI_CLK_CS; // 用于存储SPI引脚配置
SPIReset(SOC_SPI_0_REGS); // SPI0复位,确保处于已知状态,其中SOC_SPI_0_REGS 表示SPI0寄存器的基地址
SPIOutOfReset(SOC_SPI_0_REGS); // 取消SPI0复位,SPI0开始工作
SPIModeConfigure(SOC_SPI_0_REGS, SPI_MASTER_MODE); // 配置SPI0为主模式
SPIClkConfigure(SOC_SPI_0_REGS, 228000000, 20000000, SPI_DATA_FORMAT0); // 配置时钟,SPI工作时钟频率为20MHz,模块时钟为228MHz (228000000, 20000000)
SPIPinControl(SOC_SPI_0_REGS, 0, 0, &val); // 配置SPI引脚控制器————这里是写SPIPC0,配置SPI模块的引脚功能(而不是GPIO功能)
SPIDefaultCSSet(SOC_SPI_0_REGS, dcs); // 配置CS脚的缺省值,无数据传输时CS电平为缺省值(此处设为高电平)
SPIDataFormatConfig(SPI_DATA_FORMAT0); // 配置SPI数据格式————配置为DATA_FORMAT0寄存器中的格式值
SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), cs); // 配置SPI数据格式及片选信号
SPIIntLevelSet(SOC_SPI_0_REGS, SPI_RECV_INTLVL | SPI_TRANSMIT_INTLVL); // 配置SPI中断级别(分别配置接收中断级别、发送中断级别)
SPIEnable(SOC_SPI_0_REGS); // 使能 SPI0
}
/****************************************************************************/
/* */
/* SPI Flash读写验证 */
/* */
/****************************************************************************/
// SPI Flash写使能
void WriteEnable(void)
{
tx_data[0] = SPI_FLASH_WRITE_EN; // SPI写使能
tx_len = rx_len = 1; // 数据长度为1
SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
SpiTransfer();
}
// 擦除SPI Flash
void SectorErase(void)
{
tx_data[0] = SPI_FLASH_SECTOR_ERASE;
tx_data[1] = SPI_FLASH_ADDR_MSB1;
tx_data[2] = SPI_FLASH_ADDR_MSB0;
tx_data[3] = SPI_FLASH_ADDR_LSB;
tx_len = rx_len = 4;
SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
SpiTransfer();
UARTPuts("程序停止在忙判断(完成数据传输,未完成忙判断)\r\n", -1);
IsFlashBusy(); // 忙判断——————————————————————————————————目前程序停止在这
}
// 写SPI Flash
void WritetoFlash(void)
{
unsigned int index;
tx_data[0] = SPI_FLASH_PAGE_WRITE;
tx_data[1] = SPI_FLASH_ADDR_MSB1;
tx_data[2] = SPI_FLASH_ADDR_MSB0;
tx_data[3] = SPI_FLASH_ADDR_LSB;
for (index = 4; index < 260; index++)
{
tx_data[index] = index;
}
for(index = 4; index < 260; index++)
{
vrf_data[index] = index;
}
tx_len = rx_len = index;
SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
SpiTransfer();
IsFlashBusy();
}
// 读SPI Flash
void ReadFromFlash(void)
{
unsigned int index;
tx_data[0] = SPI_FLASH_READ;
tx_data[1] = SPI_FLASH_ADDR_MSB1;
tx_data[2] = SPI_FLASH_ADDR_MSB0;
tx_data[3] = SPI_FLASH_ADDR_LSB;
for (index = 4; index < 260; index++)
{
tx_data[index] = 0;
}
tx_len = rx_len = index;
SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
SpiTransfer();
}
// 数据校验
int VerifyData(void)
{
unsigned int index;
UARTPuts(" 数据校验: ", -1);
UARTPuts("\r\n", -1);
for(index = 4; index < 260; index++)
{
if(vrf_data[index] != rx_data[index])
{
UARTPuts("\r\n", -1);
UARTPuts(" 数据不匹配的位置: ", -1);
UARTPutNum((int)index - 3);
UARTPuts("\r\n", -1);
UARTPuts("验证失败\r\n", -1);
return 0;
}
}
if (index == 260)
{
UARTPuts("\r\n", -1);
UARTPuts("读写数据相同\r\n", -1);
UARTPuts("验证成功\r\n", -1);
return 1;
}
return 0;
}
/****************************************************************************/
/* */
/* 其他函数 */
/* */
/****************************************************************************/
// SPI Flash忙判断
void IsFlashBusy(void)
{
do{
StatusGet();
}while(rx_data[1] & WRITE_IN_PROGRESS); // 退出循环的条件为rx_data[1] = 0
}
// 读状态寄存器
void StatusGet(void)
{
tx_data[0] = SPI_FLASH_STATUS_RX;
tx_len = rx_len = 2;
SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
SpiTransfer();
}
// 配置 SPI 数据格式
void SPIDataFormatConfig(unsigned int dataFormat)
{
// 配置 SPI 时钟(极性和相位,SPI时钟空闲时为高电平,数据在第一个边沿被采样(下降沿采样))
SPIConfigClkFormat(SOC_SPI_0_REGS,
(SPI_CLK_POL_HIGH | SPI_CLK_INPHASE),
dataFormat);
// 配置 SPI 发送时 MSB 优先,MSB表示最高有效位
SPIShiftMsbFirst(SOC_SPI_0_REGS, dataFormat);
// 设置字符长度,设定每个字符的位数(数据字长度为8位,即一个字符8位)
SPICharLengthSet(SOC_SPI_0_REGS, CHAR_LENGTH, dataFormat);
}
// SPI数据传输
void SpiTransfer(void)
{
p_tx = &tx_data[0]; // 将指针p_tx指向tx_data的第一个元素
p_rx = &rx_data[0]; // 将指针p_rx指向rx_data的第一个元素
SPIIntEnable(SOC_SPI_0_REGS, (SPI_RECV_INT | SPI_TRANSMIT_INT));
// 使能发送中断和接收中断,产生SPI0中断,转入SPIIsr中断服务函数
while(flag);
flag = 1;
SPIDat1Config(SOC_SPI_0_REGS, SPI_DATA_FORMAT0, 0x1); // 配置SPI数据格式及片选信号
}
// SPI 中断服务函数
void SPIIsr(void)
{
unsigned int intCode = 0; // 清除CPU中断标志,intCode用于存储中断向量码
IntEventClear(SYS_INT_SPI0_INT); // 清除SPI0中断标志,确保中断已经被处理
intCode = SPIInterruptVectorGet(SOC_SPI_0_REGS); // 读取SPI0中断向量码,确定引起中断的事件类型
while (intCode) // 判断是发送中断还是接收中断
{
if(intCode == SPI_TX_BUF_EMPTY) // 发送缓冲区空引起的中断
{
tx_len--; // tx_len减1,用于后面if条件判断
SPITransmitData1(SOC_SPI_0_REGS, *p_tx); // 发送当前指向的数据
p_tx++; // 移动指针到下一个待发送数据
if (!tx_len) // 如果所有数据都发送完毕(tx_len=0),禁用发送中断
{
SPIIntDisable(SOC_SPI_0_REGS, SPI_TRANSMIT_INT);
}
}
if(intCode == SPI_RECV_FULL) // 接收缓冲区满引起的中断
{
rx_len--; // rx_len减1,用于后面if条件判断
*p_rx = (char)SPIDataReceive(SOC_SPI_0_REGS); // 读取接收到的数据,类型转为char,存储到*p_rx指向的位置
p_rx++; // 移动指针到下一个待接收的数据
if (!rx_len) // 如果所有数据都接收完毕(rx_len=0),禁用接收中断,设置标志位flag=0
{
flag = 0;
SPIIntDisable(SOC_SPI_0_REGS, SPI_RECV_INT);
}
}
intCode = SPIInterruptVectorGet(SOC_SPI_0_REGS); // 重新读取中断向量码,确保没有新的中断发生(intCode=0),退出ISR
}
}
您好
由于长时间未收到回复,本贴关闭。
如果仍有问题,请随时重新发帖咨询。