# HG changeset patch # User Paul Boddie # Date 1368998296 0 # Node ID d3bbe70e6383ea0bcba0cbb418c8faea3937e76d # Parent f6507ae3df9322c00db388b1b050cfccca608154 Attempted to write NanoNote-compatible interface code. Added a tool to convert bitmaps to the appropriate format. diff -r f6507ae3df93 -r d3bbe70e6383 Display_COG_Process.c --- a/Display_COG_Process.c Sun Apr 07 18:35:52 2013 +0000 +++ b/Display_COG_Process.c Sun May 19 21:18:16 2013 +0000 @@ -22,6 +22,7 @@ #include "Display_COG_Process.h" #include "Display_Hardware_Driver.h" #include "Display_Controller.h" +#include /****************************************************************************** @@ -519,32 +520,7 @@ void epd_PowerOn(void) { - epd_discharge_low(); - epd_rst_low(); - epd_cs_low(); - epd_spi_init(); - - epd_pwm_active(5); - - epd_panelon_on(); - - epd_pwm_active(10); - - epd_cs_high(); - - //epd_border_high(); - - epd_rst_high(); - - epd_pwm_active(5); - - epd_rst_low(); - - epd_pwm_active(5); - - epd_rst_high(); - - epd_pwm_active(5); + bsp_PowerOn(); } void epd_InitializeDriver(uint8_t EPDIndex) @@ -599,6 +575,7 @@ epd_SPI_Send_Byte(0x05, 0x0f); epd_delay_ms(30); epd_SPI_Send_Byte(0x02, 0x24); + printf("Done initialisation.\n"); } void epd_Display (uint8_t *pNewImg, uint8_t *pPrevImg) @@ -633,18 +610,7 @@ epd_SPI_Send_Byte(0x04, 0xA0); epd_delay_ms(40); epd_SPI_Send_Byte(0x04, 0x00); - - epd_rst_low(); - epd_cs_low(); - epd_spi_detach(); - epd_panelon_off(); - - //epd_border_low(); - - epd_discharge_high(); - epd_delay_ms(150); - epd_discharge_low(); + + printf("Shutdown...\n"); + bsp_Shutdown(); } - - - diff -r f6507ae3df93 -r d3bbe70e6383 Display_Hardware_Driver.c --- a/Display_Hardware_Driver.c Sun Apr 07 18:35:52 2013 +0000 +++ b/Display_Hardware_Driver.c Sun May 19 21:18:16 2013 +0000 @@ -16,6 +16,7 @@ * Includes *****************************************************************************/ #include "Display_Hardware_Driver.h" +#include /****************************************************************************** @@ -24,59 +25,25 @@ void epd_cs_high(void) { // CS_SET_HIGH; - bsp_pinOut(BSP_PIN_6, 1); + SET(EPD_SSEL); } void epd_cs_low(void) { // CS_SET_LOW; - bsp_pinOut(BSP_PIN_6, 0); + CLR(EPD_SSEL); } void epd_rst_high(void) { // RST_SET_HIGH; - bsp_pinOut(BSP_PIN_12, 1); + SET(EPD_RESET); } void epd_rst_low(void) { // RST_SET_LOW; - bsp_pinOut(BSP_PIN_12, 0); -} - -void epd_discharge_high(void) -{ - // DISCHARGE_SET_HIGH; - bsp_pinOut(BSP_PIN_14, 1); -} - -void epd_discharge_low(void) -{ - // DISCHARGE_SET_LOW; - bsp_pinOut(BSP_PIN_14, 0); -} - -void epd_panelon_off(void) -{ - // PANELON_SET_LOW; - bsp_pinOut(BSP_PIN_13, 0); -} - -void epd_panelon_on(void) -{ - // PANELON_SET_HIGH; - bsp_pinOut(BSP_PIN_13, 1); -} - -void epd_border_high(void) -{ - // BORDER_SET_HIGH; -} - -void epd_border_low(void) -{ - // BORDER_SET_LOW; + CLR(EPD_RESET); } void epd_delay_ms(uint32_t Time) @@ -119,20 +86,7 @@ #endif void epd_pwm_active(uint16_t delayInMs) { - uint16_t numOfIterations; - - numOfIterations = delayInMs * 100; - // PWM_DIR_OUT; - bsp_pinMode(BSP_PIN_11, BSP_PINMODE_OUTPUT); - for(; numOfIterations > 0; numOfIterations--) - { - // PWM_SET_HIGH; - bsp_pinOut(BSP_PIN_11, 1); - bsp_delayUs(5); //100kHz (96kHz ideal) - // PWM_SET_LOW; - bsp_pinOut(BSP_PIN_11, 0); - bsp_delayUs(5); - } + bsp_pwm_active(delayInMs); } @@ -204,29 +158,7 @@ void epd_InitDisplayHardware(void) { - // RST_DIR_OUT; - bsp_pinMode(BSP_PIN_12, BSP_PINMODE_OUTPUT); - // DISCHARGE_DIR_OUT; - bsp_pinMode(BSP_PIN_14, BSP_PINMODE_OUTPUT); - // CS_DIR_OUT; - bsp_pinMode(BSP_PIN_6, BSP_PINMODE_OUTPUT); - // PANELON_DIR_OUT; - bsp_pinMode(BSP_PIN_13, BSP_PINMODE_OUTPUT); - // DRIVERBUSY_DIR_IN; - bsp_pinMode(BSP_PIN_7, BSP_PINMODE_INPUT); - // BORDER_DIR_OUT; - - - epd_panelon_off(); - epd_spi_init(); - epd_cs_low(); - // epd_pwm_low(); - epd_pwm_active(0); //set output low - epd_rst_low(); - epd_discharge_low(); - -// TESTPin_DIR_OUT(); -// TESTPin2_DIR_OUT(); + bsp_InitDisplayHardware(); } //************************************************************************ diff -r f6507ae3df93 -r d3bbe70e6383 Display_Hardware_Driver.h --- a/Display_Hardware_Driver.h Sun Apr 07 18:35:52 2013 +0000 +++ b/Display_Hardware_Driver.h Sun May 19 21:18:16 2013 +0000 @@ -68,16 +68,9 @@ void epd_cs_low(void); void epd_rst_high(void); void epd_rst_low(void); -void epd_discharge_high(void); -void epd_discharge_low(void); -void epd_panelon_off(void); -void epd_panelon_on(void); void epd_pwm_active(uint16_t delayInMs); -void epd_border_high(void); -void epd_border_low(void); - void epd_TestPinLow(void); void epd_TestPinHigh(void); void epd_TestPinTrigger(void); diff -r f6507ae3df93 -r d3bbe70e6383 Makefile --- a/Makefile Sun Apr 07 18:35:52 2013 +0000 +++ b/Makefile Sun May 19 21:18:16 2013 +0000 @@ -9,15 +9,16 @@ LIBUBB = ../ben-blinkenlights/libubb SYSLIBS = ../openwrt-xburst/staging_dir/target-mipsel_eglibc-2.15/usr/lib +TOOLBIN = ../openwrt-xburst/staging_dir/toolchain-mipsel_gcc-4.6-linaro_eglibc-2.15/bin ARCH = mipsel-openwrt-linux -CC = $(ARCH)-gcc +CC = $(TOOLBIN)/$(ARCH)-gcc -CFLAGS = -g -Wall -fPIC -march=mips32 -I$(LIBUBB)/include # -DDEBUG=1 +CFLAGS = -g -Wall -fPIC -march=mips32 -I$(LIBUBB)/include -DNANONOTE # -DDISPLAY_IN_USE=EPD_TYPE_270 # -DDEBUG=1 LDFLAGS = -lubb -L$(LIBUBB) #-static #-L$(SYSLIBS) TARGET = test -SRC = test.c Display_COG_Process.c Display_Controller.c Display_Hardware_Driver.c +SRC = test.c bsp.c Display_COG_Process.c Display_Controller.c Display_Hardware_Driver.c logo.c OBJ = $(SRC:.c=.o) .PHONY: all clean distclean @@ -31,7 +32,7 @@ echo "Nothing else to clean." $(TARGET): $(OBJ) - $(CC) $(LDFLAGS) $< -o $@ + $(CC) $(LDFLAGS) $(OBJ) -o $@ .c.o: $(CC) -c $(CFLAGS) $< -o $@ diff -r f6507ae3df93 -r d3bbe70e6383 bsp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bsp.c Sun May 19 21:18:16 2013 +0000 @@ -0,0 +1,316 @@ +/* + * Ben NanoNote and EM027AS012 E-Paper Display Adapter Board communication. + * + * Copyright (C) 2013 Paul Boddie + * + * SPI functions derived from those in lib/atben.c by Werner Almesberger: + * + * Copyright (C) 2010-2011 Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Driver-related code originally provided under the following terms: + * + * Copyright 2013 Pervasive Displays, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "bsp.h" +#include "Display_Hardware_Driver.h" + +void bsp_init() +{ + OUT(UBB_DAT2); + OUT(UBB_DAT3); + OUT(UBB_CMD); + OUT(UBB_CLK); + OUT(UBB_DAT0); + OUT(UBB_DAT1); +} + +/* NanoNote-specific functions. */ + +void shift_select() +{ + CLR(MUX_S0); +} + +void shift_update() +{ + SET(SHIFT_RCK); + CLR(SHIFT_RCK); +} + +void shift_init() +{ + /* Initiate a clear operation. */ + + CLR(SHIFT_SCLR); + + /* Set clocks to known state. */ + + CLR(SHIFT_SCK); + CLR(SHIFT_RCK); + + /* Propagate the clear operation. */ + + shift_update(); + + /* Finalise the initialisation. */ + + SET(SHIFT_SCLR); +} + +void shift_reinit() +{ + /* Set clocks to known state. */ + + CLR(SHIFT_SCK); + CLR(SHIFT_RCK); + + /* Avoid clear operation. */ + + SET(SHIFT_SCLR); +} + +void shift_in(uint8_t v) +{ + if (v) + SET(SHIFT_SI); + else + CLR(SHIFT_SI); + + SET(SHIFT_SCK); + CLR(SHIFT_SCK); +} + +void epd_select() +{ + SET(MUX_S0); +} + +/* Callback functions. */ + +void bsp_InitDisplayHardware() +{ + /* This should do the following: + + PANEL = 0 + CS/SSEL = 0 + PWM = 0 + RESET = 0 + DIS = 0 + + (Could shift 0, 0 -> PANEL, DIS + or 0, 0, 0 -> PANEL, BORDER, DIS.) + */ + + shift_select(); + shift_init(); /* PANEL = DIS = 0 */ + + epd_select(); + CLR(EPD_SSEL); + CLR(EPD_PWM); + CLR(EPD_RESET); + CLR(EPD_MOSI); + + printf("Hardware initialised.\n"); +} + +void bsp_PowerOn() +{ + /* This should do the following: + + RESET = 0 + DIS = 0 + CS/SSEL = 0 + */ + + epd_select(); + epd_rst_low(); + + shift_select(); + shift_init(); /* PANEL = DIS = 0 */ + + printf("RESET = PANEL = DIS = 0\n"); + + /* Then, the following: + + PWM = 1/0 (5ms) + PANEL = 1 + PWM = 1/0 (10ms) + BORDER = 1? + RESET = 1 + PWM = 1/0 (5ms) + RESET = 0 + PWM = 1/0 (5ms) + RESET = 1 + PWM = 1/0 (5ms) + + (Could shift 1 -> PANEL => PANEL=1, DIS=0 + or 1, 1 -> PANEL, BORDER => PANEL=1, BORDER=1, DIS=0) + */ + + epd_select(); + epd_spi_init(); + printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); + epd_pwm_active(5); + printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); + + shift_select(); + shift_init(); /* PANEL = DIS = 0 (still) */ + shift_in(1); /* PANEL = 1 */ + shift_update(); + printf("PANEL = 1\n"); + + epd_select(); + printf("PWM at 10ms starting: %u\n", bsp_getMsTicks()); + epd_pwm_active(10); + printf("PWM at 10ms done: %u\n", bsp_getMsTicks()); + epd_cs_high(); + epd_rst_high(); + printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); + epd_pwm_active(5); + printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); + epd_rst_low(); + printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); + epd_pwm_active(5); + printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); + epd_rst_high(); + printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); + epd_pwm_active(5); + printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); + + printf("Hardware powered.\n"); +} + +void bsp_pwm_active(uint16_t delayInMs) +{ + uint16_t numOfIterations; + + numOfIterations = delayInMs * 100; + for (; numOfIterations > 0; numOfIterations--) + { + // PWM_SET_HIGH; + SET(EPD_PWM); + bsp_delayUs(5); //100kHz (96kHz ideal) + // PWM_SET_LOW; + CLR(EPD_PWM); + bsp_delayUs(5); + } +} + +void bsp_Shutdown() +{ + /* This should complete the power off operation as follows: + + RESET = 0 + CS/SSEL = 0 + PANEL = 0 + BORDER = 0? + DIS = 1 + DIS = 0 (after 150ms) + + (Could shift 0 -> PANEL => PANEL=0, DIS=1 + or 0, 0 -> PANEL, BORDER => PANEL=0, BORDER=0, DIS=1) + */ + + epd_select(); + epd_rst_low(); + epd_cs_low(); + epd_spi_detach(); + + shift_reinit(); + shift_select(); + shift_in(0); /* PANEL = 0; DIS = 1 */ + shift_update(); + printf("Wait for 150ms, starting: %u\n", bsp_getMsTicks()); + epd_delay_ms(150); + printf("Wait for 150ms, done: %u\n", bsp_getMsTicks()); + shift_in(0); /* PANEL = 0; DIS = 0 */ + shift_update(); + + printf("Hardware shut down.\n"); +} + +void bsp_spiInit() +{ + CLR(EPD_SCK); +} + +/** + * Send the given value via MOSI. + */ +void bsp_writeToDisplay(uint8_t *data, uint16_t len) +{ + uint8_t mask, *ptr, *limit = data + len; + + for (ptr = data; ptr < limit; ptr++) + { + for (mask = 0x80; mask; mask >>= 1) + { + if (*ptr & mask) + { + SET(EPD_MOSI); + } + else + { + CLR(EPD_MOSI); + } + + SET(EPD_SCK); + CLR(EPD_SCK); + } + } +} + +void bsp_delayMs(uint32_t ms) +{ + bsp_delayUs(ms * 1000); +} + +void bsp_delayUs(uint32_t us) +{ + #ifndef NANONOTE + struct timespec tv; + tv.tv_sec = 0; + tv.tv_nsec = us * 100; + nanosleep(&tv, NULL); + #else + uint64_t i = us * 16; + while (i-- > 0); + #endif +} + +uint32_t bsp_getMsTicks() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +/* Unsupported. */ + +int16_t bsp_getTemp() +{ + return 20; +} diff -r f6507ae3df93 -r d3bbe70e6383 bsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bsp.h Sun May 19 21:18:16 2013 +0000 @@ -0,0 +1,112 @@ +#ifndef __BSP_H__ +#define __BSP_H__ + +#include + +/* Pin assignments (74HC4052): + * + * Sniffer UBB 74HC4052 #1 74HC4052 #2 10K Resistor M74HC595B1R EM027AS012 + * ------- ---- ----------- ----------- ------------ ----------- ---------- + * DAT2 DAT2 13 (1Z) + * CD DAT3 3 (2Z) + * CMD CMD 10 (S0) 10 (S0) IN OUT 10 (SCLR#) + * VCC VDD 16 (VCC) 16 (VCC) 16 (VCC) 2 (3V3) + * CLK CLK 3 (SCK) + * GND GND 8 (GND) 8 (GND) 8 (GND) 1 (GND) + * DAT0 DAT0 13 (1Z) + * DAT1 DAT1 3 (2Z) + * + * Multiplexer pin selection: + * + * {Z}Y{S1/S0} + * + * 1Z with S1=0, S0=0 => 1Y0 (output 1, channel 0) + * 2Z with S1=0, S0=0 => 2Y0 (output 2, channel 0) + * + * 1Z with S1=0, S0=1 => 1Y1 (output 1, channel 1) + * 2Z with S1=0, S0=1 => 2Y1 (output 2, channel 1) + * + * Connections to the shift register (channel 0): + * + * Sniffer UBB 74HC4052 #1 M74HC595B1R + * ------- --- ----------- ----------- + * DAT2 DAT2 12 (1Y0) 12 (RCK) + * CD DAT3 1 (2Y0) 14 (SI) + * + * 74HC4052 #2 + * ----------- + * DAT0 DAT0 12 (1Y0) 10 (SCLR#) + * DAT1 DAT1 1 (2Y0) 11 (SCK) + * + * Connections to the display board (channel 1): + * + * Sniffer UBB 74HC4052 #1 EM027AS012 + * ------- --- ----------- ---------- + * DAT2 DAT2 14 (1Y1) 4 (MOSI) + * CD DAT3 5 (2Y1) 6 (SSEL) + * + * 74HC4052 #2 + * ----------- + * DAT0 DAT0 14 (1Y1) 11 (PWM) + * DAT1 DAT1 5 (2Y1) 12 (RESET) + * + * Connections from the shift register (providing persistent outputs for + * channel 0): + * + * M74HC595B1R EM027AS012 + * ----------- ---------- + * 15 (QA) 13 (PANEL) + * 1 (QB) 14 (DIS) + * + * General connections: + * + * Sniffer UBB 74HC4052 M74HC595B1R + * ------- ---- -------- ----------- + * GND GND 6 (E#) 13 (G#) + * 7 (VEE) + * 9 (S1) + */ + +/* CMD/S0 = 0 */ + +#define SHIFT_SCLR UBB_DAT0 +#define SHIFT_SCK UBB_DAT1 +#define SHIFT_RCK UBB_DAT2 +#define SHIFT_SI UBB_DAT3 + +/* CMD/S1 = 1 */ + +#define EPD_PWM UBB_DAT0 +#define EPD_RESET UBB_DAT1 +#define EPD_MOSI UBB_DAT2 +#define EPD_SSEL UBB_DAT3 + +/* Channel-insensitive. */ + +#define MUX_S0 UBB_CMD +#define EPD_SCK UBB_CLK + +/* NanoNote-specific functions. */ + +void shift_select(); +void shift_update(); +void shift_init(); +void shift_reinit(); +void shift_in(uint8_t v); +void epd_select(); + +/* Board-specific interface functions. */ + +void bsp_init(); +void bsp_InitDisplayHardware(); +void bsp_PowerOn(); +void bsp_pwm_active(uint16_t delayInMs); +void bsp_Shutdown(); +void bsp_spiInit(); +void bsp_writeToDisplay(uint8_t *data, uint16_t len); +void bsp_delayMs(uint32_t ms); +void bsp_delayUs(uint32_t us); +uint32_t bsp_getMsTicks(); +int16_t bsp_getTemp(); + +#endif /* __BSP_H__ */ diff -r f6507ae3df93 -r d3bbe70e6383 test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test.c Sun May 19 21:18:16 2013 +0000 @@ -0,0 +1,71 @@ +/* + * Ben NanoNote and EM027AS012 E-Paper Display Adapter Board communication. + * + * Copyright (C) 2013 Paul Boddie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include "logo.h" +#include "Display_Controller.h" +#include "bsp.h" + +/** + * Handle termination of the process. + */ +void shutdown(int signum) +{ + printf("Closing...\n"); + ubb_close(0); + exit(1); +} + +/* Main program and basic initialisation. */ + +int main(int argc, char *argv[]) +{ + uint8_t *current_image, blank_image[176][33]; + + signal(SIGINT, &shutdown); + + if (ubb_open(0) < 0) { + perror("ubb_open"); + return 1; + } + + ubb_power(1); + printf("Power on.\n"); + + /* Need to initialise the board. */ + + bsp_init(); + printf("Initialised.\n"); + + /* Initialise an array containing the current image. */ + + memset((uint8_t*) &blank_image[0][0], 0xff, 176*33); + current_image = (uint8_t*) &blank_image[0][0]; + printf("Set blank image.\n"); + + /* Call epd_DisplayImg with the new image and current image. */ + + epd_DisplayImg(DISPLAY_IN_USE, (uint8_t *) &image_data[0][0][0], current_image); + printf("Updated image.\n"); + + /* Set the current image to the new image. */ + + current_image = &image_data[0][0][0]; + + printf("Closing...\n"); + ubb_close(0); + + return 0; +} diff -r f6507ae3df93 -r d3bbe70e6383 tools/bitmap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/bitmap.py Sun May 19 21:18:16 2013 +0000 @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +import PIL.Image +import sys + +def get_image(input_filename, width, height): + + i = PIL.Image.open(input_filename) + if i.size != (width, height): + i.thumbnail((width, height), PIL.Image.ANTIALIAS) + + # Convert to monochrome. + + i = i.convert("1") + + all_values = [] + values = [] + last = None + x = 0 + byte = 0 + + for value in i.getdata(): + + byte = (byte << 1) + (value == 255 and 1 or 0) + x += 1 + + if x % 8 == 0: + values.append(byte) + byte = 0 + + if x == width: + x = 0 + byte = 0 + all_values.append(values) + values = [] + + return all_values + +if __name__ == "__main__": + import sys, os + + if len(sys.argv) < 3: + print sys.argv[0], " ..." + sys.exit(1) + + output_basename = sys.argv[1] + input_filenames = sys.argv[2:] + width = 264 + height = 176 + number_of_images = len(input_filenames) + + f = open("%s.c" % output_basename, "wb") + + try: + # Write the image data. + + f.write("#include \n") + f.write("const uint8_t image_data[%d][%d][%d] = {\n" % (number_of_images, height, width / 8)) + for input_filename in input_filenames: + f.write("{\n") + data = get_image(input_filename, width, height) + for y in range(0, height): + values = data[y] + f.write("{\n") + f.write(", ".join([("0x%02x" % v) for v in values])) + f.write("},\n") + f.write("},\n") + f.write("};\n") + + finally: + f.close() + + f = open("%s.h" % output_basename, "wb") + + try: + f.write("#include \n") + f.write("extern const uint8_t image_data[%d][%d][%d];\n" % (number_of_images, height, width / 8)) + f.write("#define MAX_IMAGE %d\n" % (number_of_images - 1)) + f.write("#define NUMBER_OF_IMAGES %d\n" % number_of_images) + + finally: + f.close() + +# vim: tabstop=4 expandtab shiftwidth=4