1730|1

61

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【HC32F448测评】SPI_DMA/软件SPI/硬件SPI驱动OLED与SPI驱动OLED无显示原因可能 [复制链接]

 
  1. 上一篇的SPI软硬件驱动OLED的测评篇硬件SPI的解决办法
    1. 上一篇说到硬件SPI无法驱动OLED显示的现象,而且SPI似乎比较慢,经过几天的研究终于解决的了问题,说结论,代码没问题,解决办法是在SPI的CS SCK MOIS(或者叫SDIN)这三根线上串一个100R电阻,用来维持SPI的波形(原来有可能是因为SPI速度太快导致信号串扰),而在开发板上工程师也已经把100R给串好了(因为一开始懒得找这个口,丝印不好找)  
    2. 关于SPI的另外一些补充:如果按上一篇的SPI的配置方法配置SPI,WireMode必须是4线制,SpiMode不能是MD_1,如果要用MD_1就要更改其他配置了,此外MD_2,MD_3都可以直接用。
      		stc_gpio_init_t stcGpioInit;
      	  stc_spi_init_t stcspiinit;
          /* Configuration SPI */
      		(void)GPIO_StructInit(&stcGpioInit);
      	  stcGpioInit.u16PinDrv       = PIN_HIGH_DRV;
          stcGpioInit.u16PinInputType = PIN_IN_TYPE_CMOS;
      		(void)GPIO_Init(CS2_PORT , CS2_PIN, &stcGpioInit);
      		(void)GPIO_Init(MISO_PORT,MISO_PIN, &stcGpioInit);
          (void)GPIO_Init(SCK2_PORT,  SCK2_PIN,  &stcGpioInit);
          (void)GPIO_Init(SDIN_PORT , SDIN_PIN, &stcGpioInit);
      	
      			/* Configure Port */
          GPIO_SetFunc(CS2_PORT,   CS2_PIN,   CS_FUNC);
          GPIO_SetFunc(SCK2_PORT,  SCK2_PIN,  SCK_FUNC);
          GPIO_SetFunc(SDIN_PORT, SDIN_PIN, MOSI_FUNC);
          GPIO_SetFunc(MISO_PORT, MISO_PIN, MISO_FUNC);
      		/* Peripheral clock enable */
      		FCG_Fcg1PeriphClockCmd(SPI_CLK, ENABLE);
      		
      			(void)SPI_StructInit(&stcspiinit);
          stcspiinit.u32WireMode          = SPI_4_WIRE;
          stcspiinit.u32TransMode         = SPI_SEND_ONLY;//有两种模式,都可以
          stcspiinit.u32MasterSlave       = SPI_MASTER;
          stcspiinit.u32Parity            = SPI_PARITY_INVD;
          stcspiinit.u32SpiMode           = SPI_MD_0;//不能够时MD_0
          stcspiinit.u32BaudRatePrescaler = SPI_BR_CLK_DIV64;
          stcspiinit.u32DataBits          = SPI_DATA_SIZE_8BIT;
          stcspiinit.u32FirstBit          = SPI_FIRST_MSB;
          stcspiinit.u32FrameLevel        = SPI_1_FRAME;
      		(void)SPI_Init(SPI_UNIT, &stcspiinit);

             
       

  2. HC32F系列指SPI_DMA+SPI_软件+SPI_硬件驱动OLED显示代码

    1. oled.h头文件和宏定义
       

      #ifndef __OLED_H
      #define __OLED_H 
       
      #include "hc32_ll.h"
      #include "hc32_ll_gpio.h"
      #include "stdlib.h"	
      #include "time.h"
      
      #define OLED_MODE 0
      #define SIZE 8
      #define XLevelL		0x00
      #define XLevelH		0x10
      #define Max_Column	128
      #define Max_Row		64
      #define	Brightness	0xFF
      #define X_WIDTH 	128
      #define Y_WIDTH 	64
      
      typedef uint8_t u8;
      typedef uint16_t u16;
      typedef uint32_t u32;
      	
      //-----------------OLED端口定义---------------- 
      /*串口初始地址*/
      #define SPI_UNIT                        (CM_SPI1)
      #define DMA_UNIT                     (CM_DMA2)
      
      /*时钟初始化*/
      #define DMA_CLK                      (FCG0_PERIPH_DMA2 | FCG0_PERIPH_AOS)
      #define SPI_CLK                      (FCG1_PERIPH_SPI1)
      
      /* MISO = PA11 */
      #define MISO_PORT                   (GPIO_PORT_A)
      #define MISO_PIN                    (GPIO_PIN_11)
      #define MISO_FUNC                   (GPIO_FUNC_41)
      
      /* CS = PA9 */
      #define CS2_PORT        (GPIO_PORT_A)
      #define CS2_PIN         (GPIO_PIN_09)
      #define CS_FUNC          (GPIO_FUNC_42)
      
      #define DC2_PORT				 GPIO_PORT_D
      #define DC2_PIN					 GPIO_PIN_01
      
      #define RST2_PORT				 GPIO_PORT_D
      #define RST2_PIN				 GPIO_PIN_02
      
      /* MOSI = PA3 */
      #define SDIN_PORT        (GPIO_PORT_A)
      #define SDIN_PIN        	(GPIO_PIN_03)
      #define MOSI_FUNC        (GPIO_FUNC_40)
      
      /* SCK = PA8 */
      #define SCK2_PORT         (GPIO_PORT_A)
      #define SCK2_PIN          (GPIO_PIN_08)
       #define SCK_FUNC          (GPIO_FUNC_43)
      #define OLED_CMD  0	//写命令
      #define OLED_DATA 1	//写数据
      
      /* DMA definition */
      #define DMA_CH                       (DMA_CH0)//DMA传输通道
      #define DMA_TRIG_CH                  (AOS_DMA2_0)//DMA传输触发
      #define DMA_INT_SRC                  (INT_SRC_DMA2_TC0)//DMA中断序列号
      #define DMA_INT_CH                   (DMA_INT_TC_CH0)//中断传输完成
      
      #define SPI_TX_EVT_SRC               (EVT_SRC_SPI1_SPTI)
      #define DMA_IRQ_NUM                  (INT006_IRQn)//DMA中断号
      
      #define Use_SPI_DMA 1//使用DMA
      #define Use_SPI_Software 0//使用软件SPI
      
      /*软件SPI高低电平命令*/
      #define OLED_RST_Clr() 	GPIO_ResetPins(RST2_PORT, RST2_PIN)//RES
      #define OLED_RST_Set() 	GPIO_SetPins(RST2_PORT, RST2_PIN)
       
      #define OLED_DC_Clr() 	GPIO_ResetPins(DC2_PORT, DC2_PIN)//DC
      #define OLED_DC_Set() 	GPIO_SetPins(DC2_PORT, DC2_PIN)
       		     
      #define OLED_CS_Clr()   GPIO_ResetPins(CS2_PORT, CS2_PIN)//CS
      #define OLED_CS_Set()   GPIO_SetPins(CS2_PORT, CS2_PIN)
      
      #define OLED_SCLK_Clr()  GPIO_ResetPins(SCK2_PORT, SCK2_PIN)//CS
      #define OLED_SCLK_Set()  GPIO_SetPins(SCK2_PORT, SCK2_PIN)
       
      #define OLED_SDIN_Clr()  GPIO_ResetPins(SDIN_PORT, SDIN_PIN)//CS
      #define OLED_SDIN_Set()  GPIO_SetPins(SDIN_PORT, SDIN_PIN)
      
      static __IO en_flag_status_t enCompleteFlag = RESET;//软件触发标志
      
      
      void SPI_Config(void);
      void DMA_TransCompleteCallback(void);
      //OLED控制用函数
      void OLED_WR_Byte(u8 dat,u8 cmd);	    
      void OLED_Display_On(void);
      void OLED_Display_Off(void);	   							   		    
      void OLED_Init(void);
      void OLED_Clear(void);
      void OLED_DrawPoint(u8 x,u8 y,u8 t);
      void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
      void OLED_ShowChar(u8 x,u8 y,u8 chr);
      void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
      void OLED_ShowString(u8 x,u8 y, u8 *p);	 
      void OLED_Set_Pos(unsigned char x, unsigned char y);
      void OLED_ShowCHinese(u8 x,u8 y,u8 no);
      void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
      
      #endif

       

    2. SPI_config

      static uint8_t data[1]={0};//全局数组,用来存放要放出去的数据
      void SPI_Config(void)
      {
      
      		stc_gpio_init_t stcGpioInit;
      	  stc_spi_init_t stcspiinit;
      	
      		stc_irq_signin_config_t stcIrqSignConfig;
      		stc_dma_init_t stcDmaInit;
      #if(Use_SPI_Software==0)
          /* Configuration SPI */
      		(void)GPIO_StructInit(&stcGpioInit);
      	  stcGpioInit.u16PinDrv       = PIN_HIGH_DRV;
          stcGpioInit.u16PinInputType = PIN_IN_TYPE_CMOS;
      		(void)GPIO_Init(CS2_PORT , CS2_PIN, &stcGpioInit);
      		(void)GPIO_Init(MISO_PORT,MISO_PIN, &stcGpioInit);
          (void)GPIO_Init(SCK2_PORT,  SCK2_PIN,  &stcGpioInit);
          (void)GPIO_Init(SDIN_PORT , SDIN_PIN, &stcGpioInit);
      	
      			/* Configure Port */
          GPIO_SetFunc(CS2_PORT,   CS2_PIN,   CS_FUNC);
          GPIO_SetFunc(SCK2_PORT,  SCK2_PIN,  SCK_FUNC);
          GPIO_SetFunc(SDIN_PORT, SDIN_PIN, MOSI_FUNC);
          GPIO_SetFunc(MISO_PORT, MISO_PIN, MISO_FUNC);
      		/* Peripheral clock enable */
      		FCG_Fcg1PeriphClockCmd(SPI_CLK, ENABLE);
      		
      			(void)SPI_StructInit(&stcspiinit);
          stcspiinit.u32WireMode          = SPI_4_WIRE;
          stcspiinit.u32TransMode         = SPI_SEND_ONLY;
          stcspiinit.u32MasterSlave       = SPI_MASTER;
          stcspiinit.u32Parity            = SPI_PARITY_INVD;
          stcspiinit.u32SpiMode           = SPI_MD_0;
          stcspiinit.u32BaudRatePrescaler = SPI_BR_CLK_DIV64;
          stcspiinit.u32DataBits          = SPI_DATA_SIZE_8BIT;
          stcspiinit.u32FirstBit          = SPI_FIRST_MSB;
          stcspiinit.u32FrameLevel        = SPI_1_FRAME;
      		(void)SPI_Init(SPI_UNIT, &stcspiinit);
      #endif
      
      
      #if(Use_SPI_DMA==1)	
      	
      			/* DMA configuration */
          FCG_Fcg0PeriphClockCmd(DMA_CLK, ENABLE);
      		FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
          (void)DMA_StructInit(&stcDmaInit);		
          stcDmaInit.u32BlockSize  = 1UL;
          stcDmaInit.u32TransCount = 1UL;
          stcDmaInit.u32DataWidth  = DMA_DATAWIDTH_8BIT;
      		
      		stcDmaInit.u32SrcAddrInc     = DMA_SRC_ADDR_INC;//源地址可变/递增
      		stcDmaInit.u32DestAddrInc    = DMA_DEST_ADDR_FIX;//目的地址固定
      		
      		stcDmaInit.u32SrcAddr    = ( uint32_t)(&data[0]);
          stcDmaInit.u32DestAddr   =(uint32_t)(&SPI_UNIT->DR);
      		stcDmaInit.u32IntEn      = DMA_INT_ENABLE;
      
          (void)DMA_Init(DMA_UNIT, DMA_CH, &stcDmaInit);
      		
      		
          AOS_SetTriggerEventSrc(DMA_TRIG_CH, SPI_TX_EVT_SRC);//设置其为传输启动触发源。
      
          /* DMA receive NVIC configure */
          stcIrqSignConfig.enIntSrc    = DMA_INT_SRC;
          stcIrqSignConfig.enIRQn      = DMA_IRQ_NUM;
          stcIrqSignConfig.pfnCallback = &DMA_TransCompleteCallback;//中断函数
          (void)INTC_IrqSignIn(&stcIrqSignConfig);
      		DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_FLAG_TC_CH0 );//清除完成标志
      
          /* NVIC setting */
          NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
          NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
          NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);
      
          /* Enable DMA and channel */
          DMA_Cmd(DMA_UNIT, ENABLE);
          (void)DMA_ChCmd(DMA_UNIT, DMA_CH, ENABLE);
      //			     /* Enable SPI */
      //     SPI_Cmd(SPI_UNIT, ENABLE);
      #endif
      	
      }

      3.SPI传输函数-包括中断回调,写一字节函数,DMA传输函数,要主要清除标志,允许和禁止SPI和DMA的顺序要注意,还要加个延时(太快了又不能显示)。
       

      static uint8_t data[1]={0};//全局数组,与上面那个是用一个数组
      /**
       * [url=home.php?mod=space&uid=159083]@brief[/url] DMA transmit complete callback.
       * @param  None
       * @retval None
       */
       void DMA_TransCompleteCallback(void)
      {
      	enCompleteFlag=SET;
          DMA_ClearTransCompleteStatus(DMA_UNIT,DMA_INT_TC_CH0);//必须要有,清除DMA中断标志
      		    /* Enable DMA channel */
         (void)DMA_ChCmd(DMA_UNIT, DMA_CH, DISABLE);//禁止DMA
      		
      }
      
      void DMA_transmaster(void)
      {
      				/* Enable SPI */
           SPI_Cmd(SPI_UNIT, ENABLE);//要开启SPI
        	 DMA_SetTransCount(DMA_UNIT, DMA_CH,1);//传输次数
      	  DMA_SetSrcAddr(DMA_UNIT, DMA_CH, (uint32_t)&data[0]);//传出到SPI_DR的数据
      
      	    /* Enable DMA channel */
         (void)DMA_ChCmd(DMA_UNIT, DMA_CH, ENABLE);//使能DMA
      	DDL_DelayUS(6);//延时是必须的,因为DMA太快了,导致不延时又无法显示了。
      	        /* Waiting for completion of reception */
              while (RESET == enCompleteFlag) {
      							enCompleteFlag=	DMA_GetTransCompleteStatus(DMA_UNIT,DMA_INT_TC_CH0);
              }
      				enCompleteFlag=RESET;
      
      
      		/* diable SPI */
           SPI_Cmd(SPI_UNIT, DISABLE);
      	
      }
       //向SSD1306写入一个字节。
      //dat:要写入的数据/命令
      //cmd:数据/命令标志 0,表示命令;1,表示数据;
      void OLED_WR_Byte(u8 dat,u8 cmd)
      {	
      	if(cmd)
      	  OLED_DC_Set();
      	else 
      	  OLED_DC_Clr();	
      #if(Use_SPI_Software==1)	
      	OLED_CS_Clr();
      	for(i=0;i<8;i++)
      	{			  
      		OLED_SCLK_Clr();
      		if(dat&0x80)
      		   OLED_SDIN_Set();
      		else 
      		   OLED_SDIN_Clr();
      		OLED_SCLK_Set();
      		dat<<=1;   
      	}			
      #elif(Use_SPI_Software==0)
      	
      	#if(Use_SPI_DMA==1)	
      	
      			data[0]=dat;//data[]是一个全局数组
      			DMA_transmaster();
      	#elif(Use_SPI_DMA==0)
      	
      		/* Enable SPI */
           SPI_Cmd(SPI_UNIT, ENABLE);
      			(void)SPI_Trans(SPI_UNIT , &dat, 1, 200);
      	#endif
      #endif
      //	OLED_CS_Set();
      	
      	OLED_DC_Set();   	  
      } 
      
      //初始化SSD1306					    
      void OLED_Init(void)
      { 	
      	stc_gpio_init_t stcGpioInit;
      	
      		(void)GPIO_StructInit(&stcGpioInit);
      		stcGpioInit.u16PinDir = PIN_DIR_OUT;
      	
      		(void)GPIO_Init(RST2_PORT, RST2_PIN	, &stcGpioInit);
      		(void)GPIO_Init(DC2_PORT, DC2_PIN	,  &stcGpioInit);
      
      #if(Use_SPI_Software==1)
      	 (void)GPIO_Init(CS2_PORT,   CS2_PIN,   &stcGpioInit);
         (void)GPIO_Init(SCK2_PORT,  SCK2_PIN,  &stcGpioInit);
         (void)GPIO_Init(SDIN_PORT , SDIN_PIN, &stcGpioInit);
      #endif
       
        OLED_RST_Set();
      	DDL_DelayMS(100);
      	OLED_RST_Clr();
      	DDL_DelayMS(200);
      	OLED_RST_Set(); 
      	OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
      	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
      	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
      	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
      
      	OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
      	OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
      	OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
      	OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
      	OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
      	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
      	OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
      
      	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
      	OLED_WR_Byte(0x00,OLED_CMD);//-not offset
      	OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
      	OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
      	OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
      	OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
      	OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
      	OLED_WR_Byte(0x12,OLED_CMD);
      
      	OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
      	OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
      	OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
      	OLED_WR_Byte(0x02,OLED_CMD);//
      
      	OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
      	OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
      
      	OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
      	OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) 
      	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
      
      	OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ 
      
      	OLED_Clear();
      
      //	OLED_Set_Pos(0,0); 	
      
      }  
      
      /**main.c的主函数
       * @brief  Main function
       * @param  None
       */
      int32_t main(void)
      {
      uint32_t i=12345;
          /* Unlock peripherals or registers */
          LL_PERIPH_WE(LL_PERIPH_ALL);
      	
          /* Initialize BSP expand IO. */
          BSP_IO_Init();//也把SDA和SCL初始化成功了
      
      //    /* Initialize BSP LED. */
          BSP_LED_Init();
      
          BSP_KEY_Init();
      		/* Initialize DDL_Printf */
      		DDL_PrintfInit(BSP_PRINTF_DEVICE, BSP_PRINTF_BAUDRATE, BSP_PRINTF_Preinit);
      
      		SPI_Config();
      
      OLED_Init();
          /* Peripheral registers write protected */
      //    LL_PERIPH_WP(LL_PERIPH_ALL);
      	
      	
      
      	DDL_Printf("yes");
      
      //        memset(u8RxBuf, 0, 1);
             
      			DDL_DelayMS(200);
      
      //			OLED_ShowString(1,0,"HC32F448");
      	        DDL_DelayMS(10U);
      			OLED_Clear();
      
      
          for (;;) {
      //											OLED_Clear();	
      
      						OLED_ShowString(1,5,"huang");
      			OLED_ShowString(1,2,"OLED Test");
      
      //			DDL_DelayMS(1000);
      			OLED_ShowNum(1,1,i,5,16);
      			i++;
          }
      }
      


      3显示效果(手机摄像头摔坏了,没办法聚焦还反光。。。)

       

      其他的OLED的内容请看前两期我发的测评里,都是同一个oled.c

最新回复

确实不是代码没问题     详情 回复 发表于 2023-9-16 21:06
点赞 关注
 
 

回复
举报

6809

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

确实不是代码没问题

 

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表