查看: 1104|回复: 0

[分享] 【MCX-N947分享】调试SPI外设中遇到的沟沟坎坎

[复制链接]
  • TA的每日心情
    开心
    昨天 14:34
  • 签到天数: 1100 天

    连续签到: 18 天

    [LV.10]以坛为家III

    28

    主题

    4267

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    5778
    最后登录
    2025-7-26
    发表于 2024-7-20 10:35:52 | 显示全部楼层 |阅读模式
    本帖最后由 suncat0504 于 2024-7-20 10:36 编辑

    之前在调试使用SD模块的过程中,在使用模拟SPI方式和SD卡的通讯过程,总是无法正常实现,就考虑使用FRDM-MCX-N947开发板的SPI外设,来实现这一个过程。为了呢个直观观测测试过程,确认通讯过程是否正常,准备使用SPI接口的TFT显示屏来完成这一个测试过程。

    官方提供了frdmmcxn947_lpspi_polling_b2b_transfer_master例程,是以轮询方式实现SPI主设备的处理。我就在这个程序的基础上进行修改。这个例程中使用P0_24(SDO,MOSI)、P0_25(SCK)、P0_26(SDO,MISO)、P0_27(SS)作为接口,全都在J2上。同时为了匹配TFT显示屏的RST(复位),DC(命令寄存器/数据寄存器选择),使用J2的第2(P0_28)、4(P0_10)引脚作为。而且P0_10还是开发板上红色LED的驱动口,这样测试更方便。

    原理图中,我用到的接口被圈了红色。因为TFT显示屏不需要向外输出数据,所以MISO没有被使用。

    图片1.png
    把显示屏的驱动程序做了修改,主要是去掉MOSI,SCK,CS的模拟处理部分,修改RST和DC的处理。
    1. <font face="Tahoma" size="4">#define LCD_RS_PORT GPIO0

    2. #define LCD_RS 10U // P0_10 ,使用红色LED的端口

    3. #define LCD_RST_PORT GPIO0

    4. #define LCD_RST 28U // P0_28



    5. //液晶控制口置1操作语句宏定义

    6. //#define LCD_SCL_SET GPIO_PinWrite(GPIO3, LCD_SCL, 1)

    7. //#define LCD_SDA_SET GPIO_PinWrite(GPIO3, LCD_SDA, 1)

    8. //#define LCD_CS_SET GPIO_PinWrite(GPIO3, LCD_CS, 1)



    9. #define LCD_RS_SET GPIO_PinWrite(LCD_RS_PORT, LCD_RS, 1)

    10. #define LCD_RST_SET GPIO_PinWrite(LCD_RST_PORT, LCD_RST, 1)



    11. //液晶控制口置0操作语句宏定义

    12. //#define LCD_SCL_CLR GPIO_PinWrite(GPIO3, LCD_SCL, 0)

    13. //#define LCD_SDA_CLR GPIO_PinWrite(GPIO3, LCD_SDA, 0)

    14. //#define LCD_CS_CLR GPIO_PinWrite(GPIO3, LCD_CS, 0)

    15. #define LCD_RS_CLR GPIO_PinWrite(LCD_RS_PORT, LCD_RS, 0)

    16. #define LCD_RST_CLR GPIO_PinWrite(LCD_RST_PORT, LCD_RST, 0)</font>
    复制代码

    接下来,要修改数据发送部分,改成使用SPI外设,每次发送一个字节。同时修改发送指令和发送数据时,DC(RS)的输出控制。
    1. <font face="Tahoma" size="4">//向SPI总线传输一个8位数据

    2. void SPI_WriteData(uint8_t Data) {

    3. masterXfer.txData = &Data;

    4. masterXfer.rxData = NULL;

    5. masterXfer.dataSize = 1;

    6. masterXfer.configFlags =

    7. EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;



    8. LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);



    9. }



    10. //向液晶屏写一个8位指令

    11. void Lcd_WriteIndex(uint8_t Index) {

    12. //SPI 写命令时序开始

    13. //LCD_CS_CLR;

    14. LCD_RS_CLR;

    15. SPI_WriteData(Index);

    16. //LCD_CS_SET;

    17. }



    18. //向液晶屏写一个8位数据

    19. void Lcd_WriteData(uint8_t Data) {

    20. //LCD_CS_CLR;

    21. LCD_RS_SET;

    22. SPI_WriteData(Data);

    23. //LCD_CS_SET;

    24. }</font>
    复制代码

    接下来在PIN的初始化处理中,在原来代码的基础上加入RST和DC引脚的初始化处理
    1. <font face="Tahoma" size="4">// 控制DC和RST的口

    2. const port_pin_config_t port0_10_pinB12_config = {/* Internal pull-up/down resistor is disabled */

    3. kPORT_PullDisable,

    4. /* Low internal pull resistor value is selected. */

    5. kPORT_LowPullResistor,

    6. /* Fast slew rate is configured */

    7. kPORT_FastSlewRate,

    8. /* Passive input filter is disabled */

    9. kPORT_PassiveFilterDisable,

    10. /* Open drain output is disabled */

    11. kPORT_OpenDrainDisable,

    12. /* Low drive strength is configured */

    13. kPORT_LowDriveStrength,

    14. /* Pin is configured as PIO0_10 */

    15. kPORT_MuxAlt0,

    16. /* Digital input enabled */

    17. kPORT_InputBufferEnable,

    18. /* Digital input is not inverted */

    19. kPORT_InputNormal,

    20. /* Pin Control Register fields [15:0] are not locked */

    21. kPORT_UnlockRegister};

    22. /* PORT0_10 (pin B12) is configured as PIO0_10 */

    23. // 这个口作为TFT屏幕的DC(RS)控制口

    24. PORT_SetPinConfig(PORT0, 10U, &port0_10_pinB12_config);

    25. PORT_SetPinConfig(PORT0, 28U, &port0_10_pinB12_config);</font>
    复制代码

    这段代码参考了led_blinky。
    在接下来在主程序中加入RST、DC对应管脚的输出方向的控制和TFT显示屏的初始化动作和显示语句。
    1. <font face="Tahoma" size="4">// 初始化管脚的输出电平

    2. GPIO_PinWrite(GPIO0, 10U, LOGIC_LED_OFF);

    3. GPIO_PinWrite(GPIO0, 28U, LOGIC_LED_ON);

    4. // PIO0_10、PIO0_28、PIO1_2:Output

    5. // 设置数据方向(输出)

    6. // LCD - DC(RS)

    7. GPIO0->PDDR |= (1U << 10U); // PIO0_10;

    8. GPIO0->PDDR |= (1U << 28U); // PIO0_28;</font>
    复制代码

    调整系统滴答器的频率
    1. <font face="Tahoma" size="4">SysTick_Config(12000UL);</font>
    复制代码


    这里改成12000UL是参考之前led_blinky工程。led_blinky工程中设置为12000000UL时,滴答器函数SysTick_Handler的调用周期为1秒,那么调整到1ms,就是改成12000UL,实际测试也确实是这样。但在lpspi例程中使用的是BOARD_BootClockPLL150M,那么SysTick_Config(12000UL)对应的滴答器是否是毫秒周期,我没有用示波器确认,暂且认为是正常的(实际上要是这个数据不正常,是非常有可能影响TFT显示屏的初始化的)。



    然后信心满满地启动编译、测试,结果没有任何反应。哪怕是控制RST和DC的那两个引脚,也没有产生高低电平的而变化。TFT显示屏也没看到初始化的迹象。实测监测到SPI外设的数据输出有正常变化,但RST和DC没有正常输出该有的电平变化。接下来为这个过程,又折腾了一天,也没有啥成果。哪怕用单步调试、示波器监测引脚电平变化。简单想了想,应该是由于RST和DC没有正常工作,导致显示屏不能被正常初始化。对比led_blinky工程,发现初始化PIN的代码没有任何问题。

    但在调试中发现一个有趣的现象,在主函数中,第一个语句“CLOCK_EnableClock(kCLOCK_Gpio0);”,是使能端口时钟的语句,而这条语句在执行BOARD_InitBootPins,经由BOARD_InitPins时,被又执行了一遍。如果主函数main中不要这一句,那么端口的输出控制就不能成功。同样,主函数中执行端口时钟使能,而在BOARD_InitPins中去掉端口时钟使能处理,结果是也不行。原因我是不懂,就是感觉挺神奇的。

    在led_blinky工程的基础上,把SPI外设的处理和TFT显示屏的处理移植过来后,经过简单调整、编译、下载运行,发现TFT显示屏有变化了。再经过修改,已经可以正常显示了。然后对比frdmmcxn947_lpspi_polling_b2b_transfer_master例程,好像没啥变化,用这个例程测试,竟然也OK了。哈!真的是无语了。

    图片2.png   

    哎...今天够累的,签到来了~
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-27 17:43 , Processed in 0.077230 second(s), 19 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表