HC32F460填坑 - SPI POLLING

  • 总结

目前,小一点的系统很流行SPI接口的显示屏,有黑白TN,有彩色TFT,有高对比OLED,显示分辨率从3296到320240不等,这些显示屏成本低,接口少,易于驱动,所以非常受欢迎

硬件连线通常有以下:
复位RESET,片选CS,地址A0,时钟SCK,数据SDI,背光正负,电源正负,可以做到10PIN以内

因为显示屏的SPI在某些TIMING上会有一些要求,所以片选CS通常使用GPIO模拟,另外RESET,A0也是GPIO,SCK,SDI会使用硬件SPI,达到比较高的传输速率(50MHZ)


这是MCU驱动SPI显示屏的时序图,CS选中器件,DC(A0)决定写指令还是写参数,如果当前BYTE传输期间A0是LOW,表示写指令,如果A0是HIGH,表示写参数,传输完成后,CS再拉高

#include "board.h"#define LCDCODE_REGFLAG_DELAY       0xFFFE
#define LCDCODE_REGFLAG_END         0xFFFF
#define LCDCODE_DATA_LEN            32typedef struct
{uint16_t reg;uint16_t len;uint8_t  dat[LCDCODE_DATA_LEN];
}lcd_code_t;static struct rt_semaphore spi3_tx_wait = {0x00};static void spi3_tx_dma_tc0_irq_cb(void)
{DMA_ClearIrqFlag(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, TrnCpltIrq);rt_sem_release(&spi3_tx_wait);
}static void spi3_dma_config(void)
{stc_dma_config_t stcDmaCfg;stc_irq_regi_conf_t stcIrqRegiConf;/* configuration structure initialization */MEM_ZERO_STRUCT(stcDmaCfg);/* Configuration peripheral clock */PWC_Fcg0PeriphClockCmd(SPI3_DMA_CLOCK_UNIT, Enable);PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);/* Configure TX DMA */stcDmaCfg.u16BlockSize           = 1u;stcDmaCfg.u16TransferCnt         = 128;stcDmaCfg.u32SrcAddr             = (uint32_t)(0);stcDmaCfg.u32DesAddr             = (uint32_t)(&SPI3_UNIT->DR);stcDmaCfg.stcDmaChCfg.enSrcInc   = AddressIncrease;stcDmaCfg.stcDmaChCfg.enDesInc   = AddressFix;stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit;stcDmaCfg.stcDmaChCfg.enIntEn    = Enable;DMA_InitChannel(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, &stcDmaCfg);DMA_SetTriggerSrc(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, SPI3_DMA_TX_TRIG_SOURCE);/* Enable DMA. */DMA_Cmd(SPI3_DMA_UNIT, Enable);/* Set DMA block transfer complete IRQ */stcIrqRegiConf.enIRQn      = IRQ_SPI3_DMA_TX;stcIrqRegiConf.pfnCallback = &spi3_tx_dma_tc0_irq_cb;stcIrqRegiConf.enIntSrc    = INT_DMA1_TC0;enIrqRegistration(&stcIrqRegiConf);NVIC_SetPriority(stcIrqRegiConf.enIRQn, IRQ_PRIORITY_SPI3_DMA_TX);NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}static void bsp_spi3_init(void)
{stc_spi_init_t stcSpiInit;/* configuration structure initialization */MEM_ZERO_STRUCT(stcSpiInit);/* Configuration peripheral clock */PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);/* Configuration SPI structure */stcSpiInit.enClkDiv                 = SpiClkDiv32;stcSpiInit.enFrameNumber            = SpiFrameNumber1;stcSpiInit.enDataLength             = SpiDataLengthBit8;stcSpiInit.enFirstBitPosition       = SpiFirstBitPositionMSB;stcSpiInit.enSckPolarity            = SpiSckIdleLevelLow;stcSpiInit.enSckPhase               = SpiSckOddSampleEvenChange;stcSpiInit.enReadBufferObject       = SpiReadReceiverBuffer;stcSpiInit.enWorkMode               = SpiWorkMode3Line;stcSpiInit.enTransMode              = SpiTransOnlySend;stcSpiInit.enCommAutoSuspendEn      = Disable;stcSpiInit.enModeFaultErrorDetectEn = Disable;stcSpiInit.enParitySelfDetectEn     = Disable;stcSpiInit.enParityEn               = Disable;stcSpiInit.enParity                 = SpiParityEven;stcSpiInit.enMasterSlaveMode = SpiModeMaster;stcSpiInit.stcDelayConfig.enSsSetupDelayOption   = SpiSsSetupDelayCustomValue;stcSpiInit.stcDelayConfig.enSsSetupDelayTime     = SpiSsSetupDelaySck1;stcSpiInit.stcDelayConfig.enSsHoldDelayOption    = SpiSsHoldDelayCustomValue;stcSpiInit.stcDelayConfig.enSsHoldDelayTime      = SpiSsHoldDelaySck1;stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;stcSpiInit.stcDelayConfig.enSsIntervalTime       = SpiSsIntervalSck1PlusPck2;SPI_Init(SPI3_UNIT, &stcSpiInit);spi3_dma_config();SPI_Cmd(SPI3_UNIT, Enable);   rt_sem_init(&spi3_tx_wait, "spi3tx", 0, RT_IPC_FLAG_FIFO);
}static void lcd_spi_send(uint8_t dat)
{ while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}SPI_SendData8(SPI3_UNIT, dat);while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle)){;}
}
/*
static void lcd_spi_trans(uint8_t *dat, uint16_t len)
{DMA_SetSrcAddress (SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, (uint32_t)dat);DMA_SetTransferCnt(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, len);LCD_CS_L;DMA_ChannelCmd(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, Enable);SPI_Cmd(SPI3_UNIT, Enable);   rt_sem_take(&spi3_tx_wait, RT_WAITING_FOREVER);LCD_CS_H;SPI_Cmd(SPI3_UNIT, Disable);DMA_ChannelCmd(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, Disable);
}
*/
static void delayms(uint16_t ms)
{rt_thread_delay(ms);
}static void write_codetable(lcd_code_t *code, uint32_t count)
{lcd_code_t *pcode = code;//传输指令和参数for (uint32_t i = 0; i < count; i++){   if (pcode->reg == LCDCODE_REGFLAG_END){                                   //结束跳出break;}else if (pcode->reg == LCDCODE_REGFLAG_DELAY){                                   //延时MSdelayms(pcode->len);}else{                                   //常规发送指令LCD_A0_L;LCD_CS_L;lcd_spi_send(pcode->reg);for (uint32_t j = 0; j < pcode->len; j++){LCD_A0_H;lcd_spi_send(pcode->dat[j]);}LCD_CS_H;}pcode++;                            //下一个寄存器}
}//初始化指令表
static lcd_code_t st7789v_initcode[] = {
//{0x11,  0, {0x00} },
//{LCDCODE_REGFLAG_DELAY, 120, {0x00}},
//{0xb2,  5, {0x0c, 0x0c, 0x00, 0x33, 0x33} },
//{0xb7,  1, {0x35} },
//{0xbb,  1, {0x35} },
//{0xc0,  1, {0x2c} },
//{0xc2,  1, {0x01} },
//{0xc3,  1, {0x0b} },
//{0xc4,  1, {0x20} },
//{0xc6,  1, {0x0f} },
//{0xd0,  2, {0xa4, 0xa1} },
//{0xe0, 14, {0xd0, 0x00, 0x02, 0x07, 0x0b, 0x1a, 0x32, 0x54, 0x40, 0x29, 0x12, 0x12, 0x12, 0x17} },
//{0xe1, 14, {0xd0, 0x00, 0x02, 0x07, 0x05, 0x25, 0x2d, 0x44, 0x45, 0x1c, 0x18, 0x16, 0x1c, 0x1d} },
//{0x36,  1, {0x00} },
{0x3a,  1, {0x05} },
//{0x29,  0, {0x00} },
{LCDCODE_REGFLAG_END, 0x00, {0x00} }
};/*显示区域设置*/
static lcd_code_t st7789v_blockcode[] = {
{0x2a,  4, {0x00, 0x00, 0x00, 0x00} },
{0x2b,  4, {0x00, 0x00, 0x00, 0x00} },
{0x2c,  0, {0x00} },
{LCDCODE_REGFLAG_END, 0x00, {0x00} }
};static void write_block(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{st7789v_blockcode[0].dat[0] = 0x00;st7789v_blockcode[0].dat[1] = x0;st7789v_blockcode[0].dat[2] = 0x00;st7789v_blockcode[0].dat[3] = x1;st7789v_blockcode[1].dat[0] = y0 >> 8;st7789v_blockcode[1].dat[1] = y0 & 0xff;st7789v_blockcode[1].dat[2] = y1 >> 8;st7789v_blockcode[1].dat[3] = y1 & 0xff;write_codetable(st7789v_blockcode, 5);
}void st7789v_init(void)
{stc_port_init_t stcPortInit;MEM_ZERO_STRUCT(stcPortInit);PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);/* Configuration SPI pin */PORT_SetFunc(SPI3_NSS_PORT, SPI3_NSS_PIN, Func_Gpio,     Disable);    PORT_SetFunc(SPI3_SCK_PORT, SPI3_SCK_PIN, SPI3_SCK_FUNC, Disable);PORT_SetFunc(SPI3_SDI_PORT, SPI3_SDI_PIN, SPI3_SDI_FUNC, Disable);PORT_SetFunc(LCD_RST_PORT,  LCD_RST_PIN,  Func_Gpio,     Disable);PORT_SetFunc(LCD_A0_PORT,   LCD_A0_PIN,   Func_Gpio,     Disable);stcPortInit.enPinMode = Pin_Mode_Out;stcPortInit.enPinDrv  = Pin_Drv_H;PORT_Init(LCD_RST_PORT, LCD_RST_PIN, &stcPortInit);PORT_Init(LCD_A0_PORT,  LCD_A0_PIN,  &stcPortInit);PORT_Init(LCD_CS_PORT,  LCD_CS_PIN,  &stcPortInit);bsp_spi3_init();LCD_RST_H;LCD_A0_H;LCD_CS_H;delayms(10);LCD_RST_L;delayms(10);LCD_RST_H;delayms(120);write_codetable(st7789v_initcode, sizeof(st7789v_initcode)/sizeof(lcd_code_t));
}void st7789v_test(void)
{LCD_RST_H;LCD_A0_H;LCD_CS_H;delayms(10);LCD_RST_L;delayms(10);LCD_RST_H;delayms(120);write_codetable(st7789v_initcode, sizeof(st7789v_initcode)/sizeof(lcd_code_t));delayms(10);//write_block(1, 1, 128, 300);
}

以上代码是测试MCU发送指令0x3a, 参数0x05,SPI发送代码参考HC32F460 DDL库hc32f460_ddl_Rev2.2.0.zip

static void lcd_spi_send(uint8_t dat)
{ while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}SPI_SendData8(SPI3_UNIT, dat);
}LCD_A0_L;LCD_CS_L;lcd_spi_send(pcode->reg);for (uint32_t j = 0; j < pcode->len; j++){LCD_A0_H;lcd_spi_send(pcode->dat[j]);}LCD_CS_H;

每次发送BYTE之前判断SPI BUFFER是否为空,如果空,写入数据,实施证明,BUFFER空,仅仅是BUFFER空,数据还在SPI硬件里发送着,根本就没结束,而且参考手册里面,SPI和发送相关的状态位也就这个BUFFER EMPTY,而不像之前STM,还有一个发送结束COMPLETE状态位。

看下面波形,第一个字节8个CLK还没结束,CS,A0就已经变高了,造成实际传输无效

修改如下:

static void lcd_spi_send(uint8_t dat)
{ while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}SPI_SendData8(SPI3_UNIT, dat);while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle)){;}
}LCD_A0_L;LCD_CS_L;lcd_spi_send(pcode->reg);for (uint32_t j = 0; j < pcode->len; j++){LCD_A0_H;lcd_spi_send(pcode->dat[j]);}LCD_CS_H;

每次写数据之前判断BUFFER是否空,每次写数据之后,等待SPI传输结束

波形上已经达到我们时序的要求,所以,直接参考当前库代码,至少对于驱动LCD,是有问题的。

总结

有异常,外设无法工作时候,我们要习惯于分析波形,从时序中排查问题,然后再尝试解决问题。

HC32F460填坑 - SPI POLLING SEND相关推荐

  1. 【日常填坑】之ajax请求laravel的api接口

    关于作者 程序开发人员,不拘泥于语言与技术,目前主要从事PHP和前端开发,使用Laravel和VueJs,App端使用Apicloud混合式开发.合适和够用是最完美的追求. 个人网站:http://w ...

  2. 填坑之PHP的yield和协程在一起的日子里

    首先是,这是我第一次把公众号文章复制粘贴到github来. 其次是,很久很久之前,我挖了一个yield的一个坑,自己挖的坑自己填,不然迟早会把自己埋掉. 最后是,如果想看之前那个坑,请发送" ...

  3. kylin4.0.1安装与填坑

    kylin4.0.1安装 解压安装包 将hdfs-site.xml,core-site.xml,hive-site.xml,spark-defaults.conf文件添加到/$KYLIN_HOME/c ...

  4. 开源android项目到jcenter,手把手教你将Android项目开源到JCenter两种方式以及挖坑和填坑(一)...

    - 前言 开发中,或多或少都会用到无私的程序猿分享的开源项目,Androidstudio中使用开源也很方便 例如家喻户晓的Rxjava,只需要一句话compile 'io.reactivex:rxja ...

  5. [单片机][at32][填坑日记] [USB卡包] usb上电过程中快速发包导致卡包(终章)

    文章目录 一.原因造成如下: 1. 串口外设优先级大于USB中断(USBOTG_IRQn),导致串口数据打断USB,致使PC或MCU丢包. 2. 当PC请求usb设备描述符字符串时,USB的其他通道不 ...

  6. java.lang.OutOfMemoryError:GC overhead limit exceeded填坑心得

    该文章出自:http://www.cnblogs.com/hucn/p/3572384.html 分析工具:http://www.blogjava.net/jjshcc/archive/2014/03 ...

  7. 20150726 填坑日记

    三中内填坑: 1. 组合数递推什么的 C(m,n)=C(m,n-1)+C(m-1,n-1).填了个大坑,以前没认真听课QAQ 2. 裸题过河卒 3. 缺角正方形摆放车统计,分上下部分,枚举上部分放几个 ...

  8. 传统行业转型微服务的挖坑与填坑

    原文:传统行业转型微服务的挖坑与填坑 一.微服务落地是一个复杂问题,牵扯到IT架构,应用架构,组织架构多个方面 在多家传统行业的企业走访和落地了微服务之后,发现落地微服务是一个非常复杂的问题,甚至都不 ...

  9. 开发工具总结(4)之Android Studio3.0填坑指南

    序言 Android Studio 3.0 上篇讲了: 全面总结Android Studio2.X的填坑指南 这篇讲一下AS3.0的坑.. 作为这个世界上走在最前沿的生物"猿",怎 ...

最新文章

  1. ATS中的动态回源插件stale-while-revalidate调研
  2. vivado烧录flash过程
  3. 以比特币现金(BCH)为核心的慈善经济体系革新业态
  4. html 超出部分被遮挡,div被iframe遮住的几种情况及解决方法
  5. 全球通吃5G!高通发布最新骁龙865、7系芯片,小米、OPPO将实现首发
  6. 2017-06-09 问题
  7. [crypto]-53-openssl命令行的使用(aes/rsa签名校验/rsa加密解密/hmac)
  8. POJ 1287 Prim算法模板
  9. ubuntu ifconfig命令找不到_那些年踩过的坑--无法使用MobaXterm远程登录Ubuntu
  10. 第六章:nginx实现动静分离
  11. vmware虚拟机的tomcat启动以后,主机无法访问
  12. mysql导出kml_谷歌地图如何导出kml文件 导出kml文件教程
  13. Android学习之——ListView下拉刷新
  14. 自动优化工具Black帮你写出规范漂亮的python代码
  15. ArduinoUNO实战-第九章-光敏电阻或亮度传感器
  16. 2017中兴捧月算法精英挑战赛-迪杰斯特拉
  17. 华为网络设备介绍及基础配置命令
  18. excel学习-日期计算函数DATEDIF函数(计算相隔年数、月数、天数)
  19. 获取星期--蔡勒公式
  20. 为什么青少年一定要学Python?

热门文章

  1. 海外军团能否拯救山寨机
  2. 爆笑:IT人士群聚喝酒的讲究 [笑话]
  3. Oracle 拼音排序
  4. sharepoint infopath
  5. 人脸识别 + 语音识别实现智能电话会议 | python demo
  6. 引擎呼啸再度出发,QQ飞车手游车神赏金赛正式打响!
  7. Java List 的 remove 方法
  8. Win+Ubuntu 双系统完全删除Ubuntu系统方法
  9. 智能音箱 之 功放与扬声器(喇叭)的匹配关系
  10. 网页制作---眉头(导航栏)及页尾(版权信息)处理