这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【CH582M】SPI0外设在操作发收处理时要注意的问题

共8条 1/1 1 跳转至

【CH582M】SPI0外设在操作发收处理时要注意的问题

专家
2026-08-28 09:13:22     打赏

在之前的学习中,使用其他开发板读写W25Q64时,遇到过时序上的问题,见《【STCAi8051U】使用Ai8051U的SPI外设读写W25Q128

》(https://forum.eepw.com.cn/thread/394802/1)。在发送完读取指令和地址后,在发送用的SCK的最后一个脉冲的下降沿开始读取来自Flash的数据。而本次使用CH582M开发板,按照这个模式去操作就遇到了问题。表现为在读取JEDEC ID时,返回的数据为0x17 00 00。

读取的程序代码为:

/**
 * @brief  SPI0 单字节收发(全双工,直接操作寄存器)
 */
static uint8_t SPI0_SendRecvByte(uint8_t byte) {
    SPI0_MasterSendByte(byte);
    return SPI0_MasterRecvByte();
}
 
/**
 * @brief  读 JEDEC ID (Manufacturer + Memory Type + Capacity)
 * @retval 例如 W25Q64 返回 0xEF4017
 */
uint32_t W25Q64_ReadJEDECID(void) {
    uint32_t id = 0;
    W25Q64_CS_LOW();
    SPI0_SendRecvByte(W25X_JEDEC_ID);
    id |= ((uint32_t)SPI0_SendRecvByte(0xFF) << 16); /* Manufacturer ID */
    id |= ((uint32_t)SPI0_SendRecvByte(0xFF) << 8);  /* Memory Type */
    id |= SPI0_SendRecvByte(0xFF);                   /* Capacity */
    W25Q64_CS_HIGH();
    return id;    
}
由逻

串口输出调试日志:

image.png

逻辑分析仪获取到的信号波形:

 image.png

由时序信号上看,

1、Flash已经正确返回了JEDEC ID,即:0xEF 40 17

2、这个读取过程返回了多余的4个0xFF数据

仔细分析W25Q64_ReadJEDECID这个函数的代码,发现问题所在。

1、在使用SPI0_SendRecvByte函数发送W25X_JEDEC_ID对应的指令时,产生的逻辑处理时是:

1)发送W25X_JEDEC_ID指令

2)接收数据

2、接下来由执行了三次SPI0_SendRecvByte(0xFF),也就是三组

1)发送0xFF

2)接收数据

 

从信号时序上看,感觉发送三个0xFF的动作是多余的,在发送完W25X_JEDEC_ID指令后应该完全转入读取的动作。至于为什么会多出来四个0xFF数据,是因为每执行一次SPI0_MasterRecvByte()处理,就会产生一次0xFF的发送动作。加上执行W25X_JEDEC_ID指令时产生的SPI0_MasterRecvByte()处理,刚好是四个0xFF信号。

按照上面的分析,修改代码为:

/**
 * @brief  读 JEDEC ID (Manufacturer + Memory Type + Capacity)
 * @retval 例如 W25Q64 返回 0xEF4017
 */
uint32_t W25Q64_ReadJEDECID(void) {
    uint32_t id = 0;
    uint8_t id1 = 0, id2 = 0, id3 = 0;
    W25Q64_CS_LOW();
    SPI0_MasterSendByte(W25X_JEDEC_ID);
    id1 = SPI0_MasterRecvByte();
    id2 = SPI0_MasterRecvByte();
    id3 = SPI0_MasterRecvByte();
    W25Q64_CS_HIGH();
    id = ((uint32_t)id1 << 16) + ((uint32_t)id2 << 8) + id3;
   return id;
}

编译、烧录、运行,由逻辑分析仪获取到逻辑信号:

 image.png

这次终于正确了,多余的0xFF数据也消失了。

这里对比Ai8051U的读写处理,还有一点不同。在Ai8051U的读写处理中,发出W25X_JEDEC_ID指令后的最后一个SCK脉冲的下降沿开始读取数据,而在CH582M中,使用的是SPI的模式0,是在发出W25X_JEDEC_ID指令后,新发出的SCK脉冲的上升沿开始读取数据。为什么会是这样,我也是百思而不得其解啊。

 

 

 





关键词: CH582M     SPI    

专家
2026-08-28 15:15:12     打赏
2楼

感谢楼主分享。

按照经验是不是模式配置的问题。


专家
2026-08-28 15:22:28     打赏
3楼

应该不是模式的问题。

CH582M的SPI0的模式只有模式0和模式3。经测试,模式3也不行,反而是模式0可用。


高工
2026-08-28 15:23:04     打赏
4楼

是不是库函数的不同导致的这个问题还是SPI的模式设置导致的这个问题呢? 你有逻辑分析仪可以很方便的帮你定位问题


专家
2026-08-28 15:31:27     打赏
5楼

是的,就是因为有逻辑分析仪,才解决了这个问题。经过组合模式测试,看信号时序,感觉这个真有可能是CH582M特有的处理方式。以前用其它厂家的开发板,它们之间逻辑上基本一样。


专家
2026-08-28 15:35:08     打赏
6楼

在库函数里SPI0_MasterSendByte和SPI0_MasterRecvByte已经是底层函数,直接操纵寄存器了。只能说,和其它厂家的对比,应该是在硬件设计上有不同的地方,导致软件处理的不同。


院士
2026-08-28 15:42:41     打赏
7楼

谢谢分享。


专家
2026-08-28 15:50:29     打赏
8楼


/*********************************************************************
 * @fn      SPI0_MasterSendByte
 *
 * @brief   发送单字节 (buffer)
 *
 * @param   d       - 发送字节
 *
 * @return  none
 */
void SPI0_MasterSendByte(uint8_t d)
{
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
    R8_SPI0_BUFFER = d;
    while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));
}
/*********************************************************************
 * @fn      SPI0_MasterRecvByte
 *
 * @brief   接收单字节 (buffer)
 *
 * @param   none
 *
 * @return  接收到的字节
 */
uint8_t SPI0_MasterRecvByte(void)
{
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
    R8_SPI0_BUFFER = 0xFF; // 启动传输
    while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));
    return (R8_SPI0_BUFFER);
}

在SPI0_MasterRecvByte函数中,R8_SPI0_BUFFER兼具发送和接收的缓冲。从代码上看,向R8_SPI0_BUFFER赋值就相当于启动发送了,根据代码,就是发送0xFF了。因此在之前测试W25Q64的时候,是真的不能主动由SPI0_MasterSendByte发送0xFF。发了就相当于重复发送了一次。 

这样看的话,逻辑处理上,和其他开发板的处理就匹配了。也就是说,逻辑上已经由库函数完成了发送数据 -》 接收数据这个过程。

另外从逻辑分析仪捕捉的结果上看,来自W25Q64的数据,的确是可以从SCK的上升沿获取的。



共8条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]