Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

1. Module Source>>>

Module Physical Display:

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Data Download Link: https://pan.baidu.com/s/1U9r32qeS2jOANB0SNwtwnw

Data Extraction Code: 8888

2. Specifications>>>

Refer to manufacturer documentation for the following information:

Operating Voltage: 3.3V

Operating Current: 15MA

Module Size: 27.3 x 27.8 MM

Pixel Size: 128(H) x 64(V) RGB

Driver Chip: SSD1306

Communication Protocol: SPI

Pin Count: 7 Pins (2.54mm pitch header)

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Size Parameters

3. Porting Process>>>3.1 View Documentation

Our goal is to port the example routine to the Lichuang CW32F030C8T6 development board. Follow the steps below to complete the porting.

  1. Import the source code into the project;

  2. Make rough modifications based on compilation errors;

  3. Modify pin configurations;

  4. Modify timing configurations;

  5. Porting verification.

Open the manufacturer’s example documentation (example download link can be found in the cloud link). The specific path is shown in the image below.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

3.2 Porting to Project

Copy the [OLED] folder from the manufacturer’s documentation path into your own project. Your project must have at least a millisecond delay function. (Refer to the introductory manual for the project)

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Open your project and import the copied .c and .h files.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Then, in oled.h, add the following macro definition, changing sys.h to board.hUsing the CW32 Module with a 0.96-inch SPI Monochrome Screen

Next, comment out the #include “delay.h” in the oled.c file.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

3.3 Pin Selection

This screen requires the configuration of 7 interfaces; specific interface descriptions are shown in the table below.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

The module operates as a slave in the SPI communication protocol, where D0 is the SPI signal line (SCK), D1 is the SPI output line (MOSI), and CS is the SPI chip select line (NSS). The following sections will explain both software SPI and hardware SPI porting.

3.3.1 Software SPI Porting

The current manufacturer’s source code uses a software SPI interface, and the SPI timing has already been completed by the manufacturer. We only need to configure the pins and delays accordingly. Therefore, please connect the screen pins as per your requirements. The selected pins are shown in the table below.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

After selecting the pins, enter the project and start writing the screen pin initialization code. Modify the void OLED_Init(void) function in the oled.c source code as follows:

// OLED Initialization
void OLED_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct;   // GPIO initialization structure
    __RCC_GPIOA_CLK_ENABLE();           // Enable GPIOA clock
    GPIO_InitStruct.Pins =  OLED_SCL_PIN| // GPIO pins
                            OLED_MOSI_PIN|
                            OLED_RES_PIN|
                            OLED_DC_PIN|
                            OLED_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;    // Push-pull output
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;       // High output speed
    GPIO_Init(OLED_GPIO_PORT, &GPIO_InitStruct);   // Initialize
    OLED_RES_Clr();
    delay_ms(200);
    OLED_RES_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 (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 inverted, 0xa1 normal)
    OLED_WR_Byte(0xC8, OLED_CMD); // Set COM/Row Scan Direction (0xc0 inverted, 0xc8 normal)
    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
    OLED_WR_Byte(0x00, OLED_CMD); // No 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_Clear();
    OLED_WR_Byte(0xAF, OLED_CMD);
}

Modify the OLED port definitions in lcd_init.h to match the style shown in the right image below.

//-----------------OLED Port Definitions----------------
#define OLED_GPIO_PORT      CW_GPIOA
#define OLED_SCL_PIN        GPIO_PIN_5
#define OLED_MOSI_PIN       GPIO_PIN_7
#define OLED_RES_PIN        GPIO_PIN_3
#define OLED_DC_PIN         GPIO_PIN_2
#define OLED_CS_PIN         GPIO_PIN_4

#define OLED_SCL_Clr() GPIO_WritePin(OLED_GPIO_PORT, OLED_SCL_PIN, GPIO_Pin_RESET) // SCL
#define OLED_SCL_Set() GPIO_WritePin(OLED_GPIO_PORT, OLED_SCL_PIN, GPIO_Pin_SET)
#define OLED_SDA_Clr() GPIO_WritePin(OLED_GPIO_PORT, OLED_MOSI_PIN, GPIO_Pin_RESET) // SDA
#define OLED_SDA_Set() GPIO_WritePin(OLED_GPIO_PORT, OLED_MOSI_PIN, GPIO_Pin_SET)
#define OLED_RES_Clr() GPIO_WritePin(OLED_GPIO_PORT, OLED_RES_PIN, GPIO_Pin_RESET) // RES
#define OLED_RES_Set() GPIO_WritePin(OLED_GPIO_PORT, OLED_RES_PIN, GPIO_Pin_SET)
#define OLED_DC_Clr()  GPIO_WritePin(OLED_GPIO_PORT, OLED_DC_PIN, GPIO_Pin_RESET) // DC
#define OLED_DC_Set()  GPIO_WritePin(OLED_GPIO_PORT, OLED_DC_PIN, GPIO_Pin_SET)
#define OLED_CS_Clr()  GPIO_WritePin(OLED_GPIO_PORT, OLED_CS_PIN, GPIO_Pin_RESET) // CS
#define OLED_CS_Set()  GPIO_WritePin(OLED_GPIO_PORT, OLED_CS_PIN, GPIO_Pin_SET)

At this point, the software SPI porting is complete. Please proceed to section 4 for porting verification.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Source Port Definitions

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Modified Port Definitions

The software SPI porting is now complete. Please proceed to section 4 for porting verification.3.3.2 Hardware SPI Porting

Compared to software SPI, hardware SPI relies on the hardware SPI controller, where all clock edge sampling, clock generation, and timing control are handled by hardware. This reduces CPU usage and increases operating speed. Software SPI, on the other hand, uses code to control IO output high and low levels, simulating SPI timing, which is slower and less reliable.

To use hardware SPI to drive the screen, you need to ensure that the selected pins have SPI peripheral functionality. This can be checked in the datasheet.

Note

The datasheet and user manual are available in the Baidu cloud resources; see the introductory manual for the link.

Currently, we are using a hardware SPI interface, and we only need to control the screen without reading data from it. Therefore, we are using a 3-wire SPI, which only requires the clock line SCK, the master output slave input line MOSI, and the software-controlled chip select line NSS. The NSS is controlled by software, so aside from the SCL(SCK)/SDA(MOSI) pins that need to use hardware SPI functionality, other pins can use other GPIOs on the development board. Here, we choose to use the PA5/PA7 SPI multiplexing function. Please connect the other corresponding screen pins as per your requirements. The selected pins are shown in the hardware SPI wiring table.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Wiring Diagram

After selecting the pins, enter the project and start writing the screen pin initialization code.

The pin initialization configuration is shown in the following code.

// OLED Initialization
void OLED_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct;   // GPIO initialization structure
    __RCC_GPIOA_CLK_ENABLE();           // Enable GPIOA clock
    __RCC_SPI1_CLK_ENABLE();            // Enable SPI1 clock
    // GPIO multiplexing for SPI1
    SPI1_AF_SCK();
    SPI1_AF_MOSI();
    GPIO_InitStruct.Pins =  OLED_SCL_PIN| // GPIO pins
                            OLED_MOSI_PIN|
                            OLED_RES_PIN|
                            OLED_DC_PIN|
                            OLED_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;    // Push-pull output
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;       // High output speed
    GPIO_Init(OLED_GPIO_PORT, &GPIO_InitStruct);   // Initialize
    SPI_InitTypeDef  SPI_InitStructure; // SPI initialization structure
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    // Full duplex
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                         // Master mode
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                     // Frame data length is 8 bits
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                           // Clock idle level is high
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                          // Sample on the second edge
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                             // Chip select signal controlled by SSI register
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;    // Baud rate is PCLK divided by 8
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                    // Most significant bit MSB transmitted first
    SPI_InitStructure.SPI_Speed = SPI_Speed_Low;                          // Low-speed SPI
    SPI_Init(BSP_SPI1, &SPI_InitStructure);   // Initialize
    SPI_Cmd(BSP_SPI1, ENABLE); // Enable SPI1

    OLED_RES_Clr();
    delay_ms(200);
    OLED_RES_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 (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 inverted, 0xa1 normal)
    OLED_WR_Byte(0xC8, OLED_CMD); // Set COM/Row Scan Direction (0xc0 inverted, 0xc8 normal)
    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
    OLED_WR_Byte(0x00, OLED_CMD); // No 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_Clear();
    OLED_WR_Byte(0xAF, OLED_CMD);
}

Modify the LCD port definitions in oled.h to match the style shown in the right images below.

//-----------------OLED Port Definitions----------------
#define BSP_SPI1               CW_SPI1
// GPIO AF
#define SPI1_AF_SCK()          PA05_AFx_SPI1SCK()
#define SPI1_AF_MOSI()         PA07_AFx_SPI1MOSI()
#define OLED_GPIO_PORT         CW_GPIOA
#define OLED_SCL_PIN           GPIO_PIN_5
#define OLED_MOSI_PIN          GPIO_PIN_7
#define OLED_RES_PIN           GPIO_PIN_3
#define OLED_DC_PIN            GPIO_PIN_2
#define OLED_CS_PIN            GPIO_PIN_4

#define OLED_RES_Clr() GPIO_WritePin(OLED_GPIO_PORT, OLED_RES_PIN, GPIO_Pin_RESET) // RES
#define OLED_RES_Set() GPIO_WritePin(OLED_GPIO_PORT, OLED_RES_PIN, GPIO_Pin_SET)
#define OLED_DC_Clr()  GPIO_WritePin(OLED_GPIO_PORT, OLED_DC_PIN, GPIO_Pin_RESET) // DC
#define OLED_DC_Set()  GPIO_WritePin(OLED_GPIO_PORT, OLED_DC_PIN, GPIO_Pin_SET)
#define OLED_CS_Clr()  GPIO_WritePin(OLED_GPIO_PORT, OLED_CS_PIN, GPIO_Pin_RESET) // CS
#define OLED_CS_Set()  GPIO_WritePin(OLED_GPIO_PORT, OLED_CS_PIN, GPIO_Pin_SET)

Using the CW32 Module with a 0.96-inch SPI Monochrome ScreenSource Port Definitions

Using the CW32 Module with a 0.96-inch SPI Monochrome ScreenModified Port Definitions

With the initialization part complete, we also need to modify the data sending part. The source code uses software SPI, and the timing is completed by the manufacturer. We need to modify it for hardware SPI.

In the oled.c file, modify the source code function void OLED_WR_Byte(u8 dat,u8 cmd) to match the style shown in the right images below.

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Source Code Format

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Modified Code

void OLED_WR_Byte(u8 dat,u8 cmd) {
    if(cmd)      OLED_DC_Set();
    else      OLED_DC_Clr();
    OLED_CS_Clr();
    while (SPI_GetFlagStatus(BSP_SPI1, SPI_FLAG_TXE) == RESET);
    SPI_SendData(BSP_SPI1, dat); // Send data
    while (SPI_GetFlagStatus(BSP_SPI1, SPI_FLAG_RXNE) == RESET);
    uint16_t temp = SPI_ReceiveData(BSP_SPI1); // Return data
    OLED_CS_Set();
    OLED_DC_Set();
}

The hardware SPI porting is now complete. Please proceed to section 4 for porting verification.

4. Porting Verification>>>

Enter the following code in main.c:

/* * Change Logs: * Date           Author       Notes * 2024-06-18     LCKFB-LP    first version */
#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "oled.h"

int32_t main(void) {
    board_init();        // Development board initialization
    uart1_init(115200);  // UART1 baud rate 115200
    OLED_Init();         // Initialize OLED
    OLED_Clear();        // Clear OLED
    while(1) {
        OLED_ShowString(0,0,(uint8_t *)"ABC",8,1); // 6*8 "ABC"
        OLED_ShowString(0,8,(uint8_t *)"ABC",12,1); // 6*12 "ABC"
        OLED_ShowString(0,20,(uint8_t *)"ABC",16,1); // 8*16 "ABC"
        OLED_ShowString(0,36,(uint8_t *)"ABC",24,1); // 12*24 "ABC"
        OLED_Refresh();
        delay_ms(500);
    }
}

Power-on effect:

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Successful Porting Case (Software and Hardware SPI):

Link:https://pan.baidu.com/s/1qLFWvxXXPbBx4afX4p4KBw?pwd=LCKF

Extraction Code: LCKF

ENDPrevious ReviewsREVIEW

[Product Application] CW32 Electric Tool Product Open Source

[Product Solution] Low-Cost Electric Tool Solution Based on CW32L010

[Product Application] Smart Power Bank Based on CW32 (Open Source Solution)

[Product Application] CW-W88 Water Pump Universal Control Board Design Scheme (Open Source)

[Product Application] Angle Grinder Controller Product Solution Based on CW32

[Product Solution] Low-Voltage Brushless Fan Sensorless Controller Based on CW32F030C8

[Product Solution] Brushless DC Hollow Cup Motor Sensor Control Drive Solution Based on CW32

[Product Solution] Brushless DC Hollow Cup Motor Sensorless Square Wave Control Drive Solution Based on CW32

[Product Solution] Digital Voltage and Current Meter Product Solution Based on CW32F003E4P7

[Product Solution] Low-Cost Industrial Instrument Based on CW32L010

CW32 Ecological Community (WX) Group

Using the CW32 Module with a 0.96-inch SPI Monochrome ScreenScan to Join QQ Group4 Group | 478586307

Get materials and “Developer Support Program” first-hand information

Using the CW32 Module with a 0.96-inch SPI Monochrome Screen

Leave a Comment