【AT-START-F423测评】 硬件SPI与模拟spi中时钟信号与分频之疑惑
@21小跑堂今天在调试spi驱动TFT屏,发现spi的硬件spi时钟时序与软件的时序的波形是有大的差别。
【测试环境】
IDE:MDK5.38
spi的驱动,使用摸拟与硬件通过条件编译来选择切换,代码如下:
//作 者 : 刘建华
//生成日期 : 2023-11-7
//最近修改 :
//功能描述 :AT32F435 GC9306
// 说明:
// ----------------------------------------------------------------
// GND 电源地
// VCC 3.3v电源
// SCL PA13(SCLK)
// SDA PA14(MOSI)
// RES PA0
// DC PA1
// CS PA12
// BLK PA3
// ----------------------------------------------------------------
// 修改历史 :
// 日 期 :
//All rights reserved
//******************************************************************************/
#define SOFTWARE_SPI_ENABLE 0
void LCD_GPIO_Init(void)
{
gpio_init_type gpio_init_struct;
spi_init_type spi_init_struct;
/* 使能GPIOA GPIOB时钟 */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
#if SOFTWARE_SPI_ENABLE
/* configure the led gpio */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type= GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOA, &gpio_init_struct);
gpio_bits_set(GPIOA,GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_7);
#else
/*SPI1 :
PA4/CS
PA5/SCK
PA6/MISO
PA7/MOSI
*/
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_pins = GPIO_PINS_4;
gpio_init(GPIOA, &gpio_init_struct);
gpio_bits_set(GPIOA,GPIO_PINS_4);
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE5, GPIO_MUX_5);
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE6, GPIO_MUX_5);
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_5);
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_pins = GPIO_PINS_5;
gpio_init(GPIOA, &gpio_init_struct);
// gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
// gpio_init_struct.gpio_pull = GPIO_PULL_UP;
// gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
//
// gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
// gpio_init_struct.gpio_pins = GPIO_PINS_6;
// gpio_init(GPIOA, &gpio_init_struct);
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_pins = GPIO_PINS_7 | GPIO_PINS_6;
gpio_init(GPIOA, &gpio_init_struct);
crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);
spi_default_para_init(&spi_init_struct);
spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_2;
spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;//SPI_CLOCK_POLARITY_HIGH
spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE; //SPI_CLOCK_PHASE_2EDGE
spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
spi_init(SPI1, &spi_init_struct);
spi_enable(SPI1, TRUE);
#endif
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type= GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_0|GPIO_PINS_1|GPIO_PINS_2;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
gpio_bits_set(GPIOB,GPIO_PINS_0|GPIO_PINS_1|GPIO_PINS_2);
}
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat要写入的串行数据
返回值:无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
LCD_CS_Clr;
//gpio_bits_reset( GPIOA, GPIO_PINS_4 );
#if SOFTWARE_SPI_ENABLE
u8 i;
for(i=0;i<8;i++)
{
LCD_SCLK_LOW();
if(dat&0x80)
{
LCD_MOSI_HIGH();
}
else
{
LCD_MOSI_LOW();
}
LCD_SCLK_HIGH();
dat<<=1;
}
#else
spi_i2s_data_transmit(SPI1, dat );
while(spi_i2s_flag_get(SPI1, SPI_I2S_TDBE_FLAG) == RESET) {};
#endif
}
测试结果:
使用软件摸的SPI,时钟可以达到5MHz显示图像正常,用逻辑分仪器捕获时序如下:
使用硬件spi配置 分频配置为时时钟正常,也可以正常驱动屏幕,捕获时序如下:
配置为spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_4;时,SCK的时钟信号就不是很规律了,但是可以驱动屏,时序如下:
配置为spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8;时序乱了,cs信号也跟着乱了,屏点不亮,捕获的时序如下:
如果我们使用图形配置工具,它是不能配置低于8倍分频的:
【讨论】
在使用spi中,图形化配置好的代码,不能用于spi屏的驱动,时序会乱。而如果配置为2倍频,spi只能跑到2MHz,而摸拟的却可以跑到5MHz。我看数据手册spi是可以跑到120MHz的。如果大佬们能给我指点一下,不胜感谢!
SPI时钟源可以到150M,但SPI最高速度不能超过36M。如下图,423数据手册有SPI的最高速度为36M。你workbench的配置的主频是150M,APB也是150M。所以SPI要8除频才可以。
如果想SPI跑快一点,可以将主频配置为144M,APB为144M,SPI使用4除频,即36M。
muyichuan2012 发表于 2023-11-7 13:05
SPI时钟源可以到150M,但SPI最高速度不能超过36M。如下图,423数据手册有SPI的最高速度为36M。你workbench ...
但是事实上,我配置为8时他时序乱了,需要配置2-4才能正常工作。 可以跑一下BSP里SPI example muyichuan2012 发表于 2023-11-7 14:55
可以跑一下BSP里SPI example
我有两块开发板,有空跑一下互相通信,看看情况怎么样。 你的逻辑分析仪采样率调的太低了,20M采样来读取3M时钟有点低,看样子波形不太好,估计上升沿,下降沿有些时间长,用示波器看一下。 fxyc87 发表于 2023-11-8 09:06
你的逻辑分析仪采样率调的太低了,20M采样来读取3M时钟有点低,看样子波形不太好,估计上升沿,下降沿有些 ...
好的,我回去试试用200M来采一下样看看。模拟的时钟5M的时序是非常好的。
学习,围观 那是因为你的逻辑分析仪分辨率不够,抓不到高频的波形,所以出现那种不规律的显示 Jon495323976 发表于 2023-11-9 17:40
那是因为你的逻辑分析仪分辨率不够,抓不到高频的波形,所以出现那种不规律的显示 ...
有道理,我回去再试试高频抓包,我的逻辑分析好象可以抓400M的,这个我没有注意到,多谢大佬的指点! 在硬件SPI中,时钟信号是由SPI控制器产生的。 硬件SPI可以实现更高的速度和稳定性,因为它依赖于精确的硬件组件来控制时钟信号 。 需要降低时钟信号的频率,以适应软件的处理速度。 MCU需要将内部系统时钟分频后,再通过外部时钟引脚发送给SPI设备。 模拟SPI是一种通过软件模拟SPI协议的通信方式,通常用于在没有硬件SPI接口的情况下实现SPI通信。 硬件SPI通常具有较高的通信速度。 时钟信号的产生和传输都是硬件级别的操作,通常由专门的硬件电路来完成。 不需要极高的传输速率,模拟SPI也可以满足需求。 在SPI 通信中,时钟信号和分频都是非常重要的组成部分 硬件和软件模拟肯定有区别啊