Salida de texto a pantalla OLED con controlador SH1106 a través del bus SPI a través de la biblioteca HAL

Hola queridos lectores. En mis desarrollos en microcontroladores STM32, para mostrar información significativa, utilizo pantallas OLED en el chip SSD1306. La última vez que me llegó una pantalla de 1.3 "a un precio democrático, unos 200 rublos. Lo primero que me llamó la atención fue la inscripción SH1106 en lugar de SSD1306, una búsqueda en Internet dejó en claro que esto es casi lo mismo, solo queda el único modo de dirección de página, y está limitado a una línea. Intentaré explicar cómo trabajar con él en esta publicación.

Hace aproximadamente un año, comencé a extrañar las capacidades de la píldora azul (STM32F103) y se ordenó la placa de desarrollo china STM32F407VE. Para depurar, a menudo, dos LED no son suficientes, por lo que en cada proyecto conecto OLED SSD1306 a través del bus I2C para mostrar información, de la que me enamoré desde los días de Arduino. Como no muestro gráficos, principalmente números y texto, y el tamaño de las bibliotecas terminadas y su contenido asombró mi imaginación, se escribió una pequeña biblioteca, que adapté un poco para SH1106 y quiero compartir con ustedes el proceso de escritura. La pantalla llegó de 7 pines SPI:

sh1106

Tengo una placa de desarrollo de este tipo, pero nada le impedirá conectarse a otra, incluso en STM32F103, para la que se inventó HAL (¿no es así?):

F407board

CubeMX STM32F407VE , , UART1. Clock Configuration 8MHz 168MHz HSE. PA6 PA7, D2 D3 ( «0») :

RccDebug

SPI1 NRF24L01 ESP-PSRAM64H, SPI3. DMA , :

SpiAll

DC (/), RESET ( ) CS ( ) :

Gpio

:

SH1106 — STM32F407
  1. GND — GND
  2. VDD — 3V3
  3. SCK — PC10
  4. SDA — PC12
  5. RES — PD0
  6. DC — PC11
  7. CS — PA15

Heap Stack 2 Atollic, . , . Src File->Source File, spi1106.c File->Header File spi1106.h. Src Inc , #define ic1306_H_ #endif /* ic1306_H_ */ CD, RESET CS :

#define SPI1106_H_
#include "main.h"
void sh1106Init (uint8_t contrast, uint8_t bright, uint8_t mirror);
#define SH_Command HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET)
#define SH_Data HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET)
#define SH_ResHi HAL_GPIO_WritePin(RES_GPIO_Port, RES_Pin, GPIO_PIN_SET)
#define SH_ResLo HAL_GPIO_WritePin(RES_GPIO_Port, RES_Pin, GPIO_PIN_RESET)
#define SH_CsHi HAL_GPIO_WritePin(GPIOA, CS_Pin, GPIO_PIN_SET)
#define SH_CsLo HAL_GPIO_WritePin(GPIOA, CS_Pin, GPIO_PIN_RESET)
#endif /* SPI1106_H_ */

spi1106.c , main.h, SPI :

#include "main.h"
#include <spi1106.h>
extern SPI_HandleTypeDef hspi3;

SPI HAL:

void SH1106_WC (uint8_t comm)
{
uint8_t temp[1];
SH_Command;
SH_CsLo;
temp[0]=comm;
HAL_SPI_Transmit(&hspi3,&temp,1,1);
SH_CsHi;
}

:

void sh1106Init (uint8_t contrast, uint8_t bright,uint8_t mirror)
{
SH_ResLo;
HAL_Delay(1);
SH_ResHi;
HAL_Delay(1);
SH1106_WC(0xAE); //display off
SH1106_WC(0xA8); //--set multiplex ratio(1 to 64)
SH1106_WC(0x3F); //
SH1106_WC(0x81); //--set contrast control register
SH1106_WC(contrast);
if (mirror) {SH1106_WC(0xA0);
SH1106_WC(0xC0);}
else {SH1106_WC(0xA1);
SH1106_WC(0xC8); }
SH1106_WC(0xDA);
SH1106_WC(0x12);
SH1106_WC(0xD3);
SH1106_WC(0x00);
SH1106_WC(0x40);
SH1106_WC(0xD9); //--set pre-charge period
SH1106_WC(bright);
SH1106_WC(0xAF); //--turn on SSD1306 panel
}

, , — (0-255), — ( , 0xX0 0x0X ), — (0/1). « . 1. OLED 0.96» (12864) SSD1306" SSD1306.

main.c :

/* USER CODE BEGIN 2 */
sh1106Init (40,0x22,0);
/* USER CODE END 2 */

:

ruido

spi1106.h — , :

void sh1106Clear(uint8_t start, uint8_t stop);
void sh1106SmallPrint(uint8_t posx, uint8_t posy, uint8_t *str);
void sh1106MediumPrint(uint8_t posx, uint8_t posy,uint8_t *str);

spi1106.c 0- 7- 0xB0...0xB7 :

void sh1106Clear(uint8_t start, uint8_t stop)
{ uint32_t *adrclear;
uint32_t timep,timec;
uint8_t dt[128];
adrclear=(uint32_t *)dt;
for(uint8_t i=0;i<32;i++) {*adrclear++=0x00;}
for (uint8_t m = start; m <= stop; m++)
{
SH1106_WC(0xB0+m);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt,128);
timec=HAL_GetTick();
timep=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timep))
{timec=HAL_GetTick();}
SH_CsHi;
}
}

main.c, , :

sh1106Clear(0,7);

, , , spi1106.c DefaultFonts.c ( - ). , ( SSD1306/SH1106). 4- . , , :

SmallFont
const uint8_t SmallFont[] =  //    SmallFont
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //	001)	0x20=032	
0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, //	002)	0x21=033	!
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, //	003)	0x22=034	"
0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, //	004)	0x23=035	#
0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, //	005)	0x24=036	$
0x00, 0x23, 0x13, 0x08, 0x64, 0x62, //	006)	0x25=037	%
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, //	007)	0x26=038	&
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, //	008)	0x27=039	'
0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, //	009)	0x28=040	(
0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, //	010)	0x29=041	)
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, //	011)	0x2A=042	*
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, //	012)	0x2B=043	+
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, //	013)	0x2C=044	,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, //	014)	0x2D=045-
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, //	015)	0x2E=046	.
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, //	016)	0x2F=047	/
//
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, //	017)	0x30=048	0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, //	018)	0x31=049	1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, //	019)	0x32=050	2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, //	020)	0x33=051	3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, //	021)	0x34=052	4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, //	022)	0x35=053	5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, //	023)	0x36=054	6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, //	024)	0x37=055	7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, //	025)	0x38=056	8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, //	026)	0x39=057	9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, //	027)	0x3A=058	:
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, //	028)	0x3B=059	;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, //	029)	0x3C=060	<
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, //	030)	0x3D=061 =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, //	031)	0x3E=062	>
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, //	032)	0x3F=063	?
//
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, //	033)	0x40=064	@
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, //	034)	0x41=065	A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, //	035)	0x42=066	B
// ...
}

( 6, 8 ), posx , 6 , posy (0 — , 7 — ):

void sh1106SmallPrint(uint8_t posx, uint8_t posy, uint8_t *str)
{
uint8_t dt[128];
uint16_t posfont, posscr;
uint32_t *adrclr;
uint16_t *adrdst,*adrsrc;
uint32_t timer,timec;
adrclr=(uint32_t *)&dt;
uint8_t code;
code=*str++;
for(uint8_t i=0;i<32;i++) { *adrclr++=0; }
posscr=posx*6;
while (code>31)
{
if(code==32) {posscr+=2;}
else
{posfont=6*(code-32);
adrdst=(uint16_t *)&dt[posscr];
adrsrc=(uint16_t *)&SmallFont[posfont];
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
posscr+=6;
}
code=*str++;
if (posscr>122) break;
}
SH1106_WC(0xB0+posy);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt,128);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
SH_CsHi;
}

, spi1106.c ( 16, 12 ) DefaultFonts.c ( 4 ) , posx , 12 , posy :

void sh1106MediumPrint(uint8_t posx, uint8_t posy, uint8_t *str)
{
uint8_t dt[256];
uint16_t posfont, posscr;
uint32_t *adrdst, *adrsrc;
uint32_t timer,timec;
adrdst=(uint32_t *)&dt;
uint8_t code;
code=*str++;
for(uint8_t i=0;i<64;i++) { *adrdst++=0; }
posscr=posx*12;
while (code>31)
{posfont=24*(code-32);
adrsrc=(uint32_t *)&MediumFont[posfont];
adrdst=(uint32_t *)&dt[posscr];
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
adrsrc=(uint32_t *)&MediumFont[posfont+12];
adrdst=(uint32_t *)&dt[posscr+128];
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
*(adrdst++)=*(adrsrc++);
code=*str++;
posscr+=12;
if (posscr>116) break;
}
SH1106_WC(0xB0+posy);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt,128);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
SH1106_WC(0xB0+posy+1);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,dt+128,128);
timec=HAL_GetTick();
timer=timec+50;
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY)&&(timec<timer))
{timec=HAL_GetTick();}
SH_CsHi;
}

main.c :

sh1106SmallPrint(0,0,(uint8_t *) "Hello SH1106_1234567890");
sh1106MediumPrint(0,1,(uint8_t *) "Hi SH1106");
sh1106MediumPrint(0,3,(uint8_t *) "Hello SH1106");
Hola

, , HardFault . , , , .

, , 7 :

/* Infinite loop */
/* USER CODE BEGIN WHILE */
uint8_t buf[128*8];
char str[32];
uint16_t count;
uint8_t x,y,b;
uint32_t timep,timec;
while (1)
{
count++;
b=count&0x07;
x=(count>>3)&0x7f;
y=(count>>10)&0x07;
buf[y*128+x]=buf[y*128+x]|(1<<b);
timec=HAL_GetTick();
for (uint8_t m = 0; m < 7; m++)
{SH1106_WC(0xB0+m);
SH1106_WC(2);
SH1106_WC(0x10);
SH_Data;
SH_CsLo;
HAL_SPI_Transmit_DMA(&hspi3,buf+m*128,128);
while ((HAL_SPI_GetState(&hspi3) != HAL_SPI_STATE_READY))
{__NOP();}
SH_CsHi;
}
timep=HAL_GetTick();
sprintf(str, "%d", timep-timec);
sh1106SmallPrint(0,7,str);
/* USER CODE END WHILE */
velocidad

— "0" "1" , 1ms, .. 1000fps. , , . SPI SPI DMA.

.




All Articles