|
【HC32F448测评】SPI_DMA/软件SPI/硬件SPI驱动OLED与SPI驱动OLED无显示原因可能
[复制链接]
- 上一篇的SPI软硬件驱动OLED的测评篇硬件SPI的解决办法
- 上一篇说到硬件SPI无法驱动OLED显示的现象,而且SPI似乎比较慢,经过几天的研究终于解决的了问题,先说结论,代码没问题,解决办法是在SPI的CS SCK MOIS(或者叫SDIN)这三根线上串一个100R电阻,用来维持SPI的波形(原来有可能是因为SPI速度太快导致信号串扰),而在开发板上工程师也已经把100R给串好了(因为一开始懒得找这个口,丝印不好找)
- 关于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);
-
HC32F系列指SPI_DMA+SPI_软件+SPI_硬件驱动OLED显示代码
-
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
-
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
|
|