Ashok R
Published © CC BY-NC-ND

EInk Shield for Nucode - NU54DK

Design of custom 0.96" Eink display shield board for NU54 Development Kit

BeginnerShowcase (no instructions)8 hours43
EInk Shield for Nucode - NU54DK

Things used in this project

Hardware components

Nordic Semiconductor NUCODE - NU54 DK
×1
ePaper / eInk Eink Shield
×1

Software apps and online services

VS Code
Microsoft VS Code

Story

Read more

Custom parts and enclosures

NU54- EInk Shield 3D design

Schematics

NU54 Eink Shield Schematic

Code

Eink.c

C/C++
#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "eink.h"
#include "images.h"
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/gpio.h>

#define MY_SPI_MASTER DT_NODELABEL(my_spi_master)

static const struct gpio_dt_spec epd_bsy = GPIO_DT_SPEC_GET(DT_ALIAS(gpiobsy), gpios);

static const struct gpio_dt_spec epd_dc = GPIO_DT_SPEC_GET(DT_ALIAS(gpiodc), gpios);

static const struct gpio_dt_spec epd_rst = GPIO_DT_SPEC_GET(DT_ALIAS(gpiorst) , gpios);

static const struct gpio_dt_spec epd_cs = GPIO_DT_SPEC_GET(DT_ALIAS(gpiocs), gpios);

//static const struct gpio_dt_spec epd_en = GPIO_DT_SPEC_GET(DT_ALIAS(gpioeen), gpios);


#define EPD_cs_low() 		gpio_pin_set_dt(&epd_cs, 0);
#define EPD_cs_high() 		gpio_pin_set_dt(&epd_cs, 1);

#define EPD_dc_low() 		gpio_pin_set_dt(&epd_dc, 0);
#define EPD_dc_high() 		gpio_pin_set_dt(&epd_dc, 1);

#define EPD_rst_low() 		gpio_pin_set_dt(&epd_rst, 0);
#define EPD_rst_high() 		gpio_pin_set_dt(&epd_rst, 1);

#define EPD_delay_ms(X)		k_sleep(K_MSEC(X));

extern volatile int lock_status;
extern struct k_sem epd_init_ok;

// SPI master functionality
const struct device *spi_dev;
static struct spi_config spi_cfg = {
	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB, // | SPI_MODE_CPOL | SPI_MODE_CPHA,
	.frequency = 8000000,
	.slave = 0,
	.cs = {.gpio = NULL, .delay = 0},
};



static void spi_sendbyte(uint8_t data)
{

	const struct spi_buf tx_buf = {
		.buf = &data,
		.len = 1
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};

	int error = spi_write(spi_dev, &spi_cfg, &tx);
	if(error != 0){
		printk("SPI write error: %i\n", error);
	}

}

static void spi_sendbytes(uint8_t *data, uint32_t len)
{

	struct spi_buf tx_buf = {
		.buf = data,
		.len = len
	};
	struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};

	int error = spi_write(spi_dev, &spi_cfg, &tx);
	if(error != 0){
		printk("SPI write error: %i\n", error);
	}
}

static void sendCmd( uint8_t cmd) {

  EPD_cs_low();
  EPD_dc_low();
  spi_sendbyte(cmd);
  EPD_cs_high();

}

static void sendData( uint8_t data) {

  EPD_cs_low();
  EPD_dc_high();
  spi_sendbyte(data);
  EPD_cs_high();

}

static void sendDatabytes(uint8_t *data, uint32_t len) {

  EPD_cs_low();
  EPD_dc_high();
  spi_sendbytes(data,len);
  EPD_cs_high();

}

void eink_spi_init(void)
{
	spi_dev = DEVICE_DT_GET(MY_SPI_MASTER);
	if(!device_is_ready(spi_dev)) {
		printk("SPI master device not ready!\n");
	}
	printk("spi init done!\r\n");
}

void epd_wait(void)
{
	printk("epd wait start.. status=%d \r\n", gpio_pin_get_dt(&epd_bsy));
    while(gpio_pin_get_dt(&epd_bsy) != 0)
    {
		/* Spin for ever */
		EPD_delay_ms(1);
    }
	printk("epd wait over. status=%d \r\n", gpio_pin_get_dt(&epd_bsy));
}

void epd_gd_soft_reset(void)
{
	sendCmd(0x12);   //Soft-reset
}

void epd_gd_sleep(void)
{
	sendCmd(0x10);
	sendData(0x01);    //Sleep
}

void epd_gd_set_temp()
{
	sendCmd(0x18);
	sendData(0x80);    //temp

	sendCmd(0x22);
	sendData(0xb1);    //temp
	sendCmd(0x20);

	epd_wait();

	sendCmd(0x1a);
	sendData(0x64); 
	sendData(0x00); 

	sendCmd(0x22);
	sendData(0x91); 
	sendCmd(0x20);

	epd_wait();
    printk("epd set temp done\r\n");
}


void epd_gd_set_doc()
{

	sendCmd(0x01); //Driver output control     
	sendData((EPD_GD_HEIGHT+EPD_GD_OFFSET-1)%256); 
	sendData((EPD_GD_HEIGHT+EPD_GD_OFFSET-1)/256); 
	sendData(EPD_GD_MIRROR); // 0x01 - mirror

	sendCmd(0x11);
	sendData(0x01);  //data entry mode 

    printk("epd set doc done\r\n");
}

void epd_gd_set_duc()
{
	uint8_t temp[2] = {0x00, 0x80};

	sendCmd(0x21);
	sendData(0x00); 
	sendData(0x80); //Display update control 

    printk("epd set duc done\r\n");
}

void epd_gd_set_pos()
{
	sendCmd(0x44);
	sendData(0x00); 
	sendData((EPD_GD_WIDTH/8)-1); //Set ram x start/end pos    

	sendCmd(0x45);
	sendData((EPD_GD_HEIGHT+EPD_GD_OFFSET-1)%256); 
	sendData((EPD_GD_HEIGHT+EPD_GD_OFFSET-1)/256); //Set ram y start/end pos    
	sendData(0x00); 
	sendData(0x00); 

	sendCmd(0x3c);
	sendData(0x05); //BorderWaveform
	//sendData(0x80); //Set borderwave

    printk("epd set pos done\r\n");
}

void epd_gd_set_pos2()
{
	sendCmd(0x4E);
	sendData(0x00); //Set ram x count to 0   

	sendCmd(0x4F);
	sendData((EPD_GD_HEIGHT+EPD_GD_OFFSET -1)%256); //Set ram x count to 128   
	sendData((EPD_GD_HEIGHT+EPD_GD_OFFSET -1)/256); 

    printk("epd set pos2 done\r\n");
}


//Full screen refresh display function
void eink_gd_init_bw_0_97(void)
{

	sendCmd(0x24);

	sendDatabytes(gImage_gd_elock_bw_flash_0_97,EPD_GD_BYTES_SIZE);
	sendCmd(0x18);
	sendData(0xff);

	sendCmd(0x22);
	sendData(0xf7);	//Display Update Control
	sendCmd(0x20);//Activate Display Update Sequence

	epd_wait();
}

//Full screen refresh display function
void eink_gd_update_bw_0_97(void)
{

	sendCmd(0x24);

	if(button_status)
	{
		sendDatabytes(gImage_gd_bw_0_97_emclub_logo,EPD_GD_BYTES_SIZE);
	}
	else
	{
		sendDatabytes(gImage_gd_bw_0_97_nucode_logo,EPD_GD_BYTES_SIZE);
		
	}

	sendCmd(0x18);
	sendData(0xff);
	sendCmd(0x22);
	sendData(0xf7);	//Display Update Control
	sendCmd(0x20);	//Activate Display Update Sequence

	epd_wait();
}


void eink_gd_set_white(void)
{

	sendCmd(0x24);
	sendDatabytes(gImage_gd_white_2_13,EPD_GD_BYTES_SIZE);

	sendCmd(0x22);
	sendData(0xf7);	//Display Update Control
	sendCmd(0x20);	//Activate Display Update Sequence

	epd_wait();
}


void eink_gd_hwinit_screen(void)
{
	EPD_rst_low();
	EPD_delay_ms(10);
	EPD_rst_high();
	EPD_delay_ms(10);

	epd_wait();

	epd_gd_soft_reset();  //soft reset

	epd_wait();

	epd_gd_set_doc();

	epd_gd_set_pos();

	epd_gd_set_duc();

	epd_gd_read_temp();

	epd_gd_set_pos2();

	epd_wait();

	printk("EPD init done\r\n");

}



uint8_t eink_configure_gpio(void)
{

	if (!gpio_is_ready_dt(&epd_cs)) {
		return 0;
	}

	if (gpio_pin_configure_dt(&epd_cs, GPIO_OUTPUT) != 0) {
		printk("Failed to configure LED device %s pin %d\n",
				epd_cs.port->name, epd_cs.pin);
	return 0;
	}	

	if (!gpio_is_ready_dt(&epd_dc)) {
		return 0;
	}

	if (gpio_pin_configure_dt(&epd_dc, GPIO_OUTPUT) != 0) {
		printk("Failed to configure LED device %s pin %d\n",
				epd_dc.port->name, epd_dc.pin);
	return 0;
	}

	if (!gpio_is_ready_dt(&epd_rst)) {
		return 0;
	}

	if (gpio_pin_configure_dt(&epd_rst, GPIO_OUTPUT) != 0) {
		printk("Failed to configure LED device %s pin %d\n",
				epd_rst.port->name, epd_rst.pin);
	return 0;
	}

	if (!gpio_is_ready_dt(&epd_bsy)) {
		return 0;
	}

	if (gpio_pin_configure_dt(&epd_bsy, GPIO_INPUT) != 0) {
		printk("Failed to configure %s pin %d\n",
		       epd_bsy.port->name, epd_bsy.pin);
		return 0;
	}


}


void eink_power_off(void)
{
	//gpio_pin_set_dt(&epd_en, 0);
#if 0
	if (gpio_pin_configure_dt(&epd_en, GPIO_DISCONNECTED ) != 0) {
		printk("Failed to configure %s pin %d\n",
		       epd_en.port->name, epd_en.pin);
		return 0;
	}
#endif
	if (gpio_pin_configure_dt(&epd_bsy, GPIO_DISCONNECTED ) != 0) {
		printk("Failed to configure %s pin %d\n",
		       epd_bsy.port->name, epd_bsy.pin);
		return 0;
	}

	if (gpio_pin_configure_dt(&epd_rst, GPIO_DISCONNECTED ) != 0) {
		printk("Failed to configure %s pin %d\n",
		       epd_rst.port->name, epd_rst.pin);
		return 0;
	}

	if (gpio_pin_configure_dt(&epd_cs, GPIO_DISCONNECTED ) != 0) {
		printk("Failed to configure %s pin %d\n",
		       epd_cs.port->name, epd_cs.pin);
		return 0;
	}
	
	if (gpio_pin_configure_dt(&epd_dc, GPIO_DISCONNECTED ) != 0) {
		printk("Failed to configure %s pin %d\n",
		       epd_dc.port->name, epd_dc.pin);
		return 0;
	}


}

Credits

Ashok R
38 projects • 104 followers
Hobbyist/Engineer/Director/Animatior

Comments