1 /* 2 * Ben NanoNote and EM027AS012 E-Paper Display Adapter Board communication. 3 * 4 * Copyright (C) 2013 Paul Boddie 5 * 6 * SPI functions derived from those in lib/atben.c by Werner Almesberger: 7 * 8 * Copyright (C) 2010-2011 Werner Almesberger 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * Driver-related code originally provided under the following terms: 16 * 17 * Copyright 2013 Pervasive Displays, Inc. 18 * 19 * Licensed under the Apache License, Version 2.0 (the "License"); 20 * you may not use this file except in compliance with the License. 21 * You may obtain a copy of the License at: 22 * 23 * http://www.apache.org/licenses/LICENSE-2.0 24 * 25 * Unless required by applicable law or agreed to in writing, 26 * software distributed under the License is distributed on an 27 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 28 * express or implied. See the License for the specific language 29 * governing permissions and limitations under the License. 30 */ 31 32 #include <ubb/ubb.h> 33 #include <unistd.h> 34 #include <sys/time.h> 35 #include <time.h> 36 #include <stdio.h> 37 #include "bsp.h" 38 #include "Display_Hardware_Driver.h" 39 40 void bsp_init() 41 { 42 OUT(UBB_DAT2); 43 OUT(UBB_DAT3); 44 OUT(UBB_CMD); 45 OUT(UBB_CLK); 46 OUT(UBB_DAT0); 47 OUT(UBB_DAT1); 48 } 49 50 /* NanoNote-specific functions. */ 51 52 void shift_select() 53 { 54 CLR(MUX_S0); 55 } 56 57 void shift_update() 58 { 59 SET(SHIFT_RCK); 60 CLR(SHIFT_RCK); 61 } 62 63 void shift_init() 64 { 65 /* Initiate a clear operation. */ 66 67 CLR(SHIFT_SCLR); 68 69 /* Set clocks to known state. */ 70 71 CLR(SHIFT_SCK); 72 CLR(SHIFT_RCK); 73 74 /* Propagate the clear operation. */ 75 76 shift_update(); 77 78 /* Finalise the initialisation. */ 79 80 SET(SHIFT_SCLR); 81 } 82 83 void shift_reinit() 84 { 85 /* Set clocks to known state. */ 86 87 CLR(SHIFT_SCK); 88 CLR(SHIFT_RCK); 89 90 /* Avoid clear operation. */ 91 92 SET(SHIFT_SCLR); 93 } 94 95 void shift_in(uint8_t v) 96 { 97 if (v) 98 SET(SHIFT_SI); 99 else 100 CLR(SHIFT_SI); 101 102 SET(SHIFT_SCK); 103 CLR(SHIFT_SCK); 104 } 105 106 void epd_select() 107 { 108 SET(MUX_S0); 109 } 110 111 /* Callback functions. */ 112 113 void bsp_InitDisplayHardware() 114 { 115 /* This should do the following: 116 117 PANEL = 0 118 CS/SSEL = 0 119 PWM = 0 120 RESET = 0 121 DIS = 0 122 123 (Could shift 0, 0 -> PANEL, DIS 124 or 0, 0, 0 -> PANEL, BORDER, DIS.) 125 */ 126 127 shift_select(); 128 shift_init(); /* PANEL = DIS = 0 */ 129 130 epd_select(); 131 CLR(EPD_SSEL); 132 CLR(EPD_PWM); 133 CLR(EPD_RESET); 134 CLR(EPD_MOSI); 135 136 printf("Hardware initialised.\n"); 137 } 138 139 void bsp_PowerOn() 140 { 141 /* This should do the following: 142 143 RESET = 0 144 DIS = 0 145 CS/SSEL = 0 146 */ 147 148 epd_select(); 149 epd_rst_low(); 150 151 shift_select(); 152 shift_init(); /* PANEL = DIS = 0 */ 153 154 printf("RESET = PANEL = DIS = 0\n"); 155 156 /* Then, the following: 157 158 PWM = 1/0 (5ms) 159 PANEL = 1 160 PWM = 1/0 (10ms) 161 BORDER = 1? 162 RESET = 1 163 PWM = 1/0 (5ms) 164 RESET = 0 165 PWM = 1/0 (5ms) 166 RESET = 1 167 PWM = 1/0 (5ms) 168 169 (Could shift 1 -> PANEL => PANEL=1, DIS=0 170 or 1, 1 -> PANEL, BORDER => PANEL=1, BORDER=1, DIS=0) 171 */ 172 173 epd_select(); 174 epd_spi_init(); 175 printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); 176 epd_pwm_active(5); 177 printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); 178 179 shift_select(); 180 shift_init(); /* PANEL = DIS = 0 (still) */ 181 shift_in(1); /* PANEL = 1 */ 182 shift_update(); 183 printf("PANEL = 1\n"); 184 185 epd_select(); 186 printf("PWM at 10ms starting: %u\n", bsp_getMsTicks()); 187 epd_pwm_active(10); 188 printf("PWM at 10ms done: %u\n", bsp_getMsTicks()); 189 epd_cs_high(); 190 epd_rst_high(); 191 printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); 192 epd_pwm_active(5); 193 printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); 194 epd_rst_low(); 195 printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); 196 epd_pwm_active(5); 197 printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); 198 epd_rst_high(); 199 printf("PWM at 5ms starting: %u\n", bsp_getMsTicks()); 200 epd_pwm_active(5); 201 printf("PWM at 5ms done: %u\n", bsp_getMsTicks()); 202 203 printf("Hardware powered.\n"); 204 } 205 206 void bsp_pwm_active(uint16_t delayInMs) 207 { 208 uint16_t numOfIterations; 209 210 numOfIterations = delayInMs * 100; 211 for (; numOfIterations > 0; numOfIterations--) 212 { 213 // PWM_SET_HIGH; 214 SET(EPD_PWM); 215 bsp_delayUs(5); //100kHz (96kHz ideal) 216 // PWM_SET_LOW; 217 CLR(EPD_PWM); 218 bsp_delayUs(5); 219 } 220 } 221 222 void bsp_Shutdown() 223 { 224 /* This should complete the power off operation as follows: 225 226 RESET = 0 227 CS/SSEL = 0 228 PANEL = 0 229 BORDER = 0? 230 DIS = 1 231 DIS = 0 (after 150ms) 232 233 (Could shift 0 -> PANEL => PANEL=0, DIS=1 234 or 0, 0 -> PANEL, BORDER => PANEL=0, BORDER=0, DIS=1) 235 */ 236 237 epd_select(); 238 epd_rst_low(); 239 epd_cs_low(); 240 epd_spi_detach(); 241 242 shift_reinit(); 243 shift_select(); 244 shift_in(0); /* PANEL = 0; DIS = 1 */ 245 shift_update(); 246 printf("Wait for 150ms, starting: %u\n", bsp_getMsTicks()); 247 epd_delay_ms(150); 248 printf("Wait for 150ms, done: %u\n", bsp_getMsTicks()); 249 shift_in(0); /* PANEL = 0; DIS = 0 */ 250 shift_update(); 251 252 printf("Hardware shut down.\n"); 253 } 254 255 void bsp_spiInit() 256 { 257 CLR(EPD_SCK); 258 } 259 260 /** 261 * Send the given value via MOSI. 262 */ 263 void bsp_writeToDisplay(uint8_t *data, uint16_t len) 264 { 265 uint8_t mask, *ptr, *limit = data + len; 266 267 for (ptr = data; ptr < limit; ptr++) 268 { 269 for (mask = 0x80; mask; mask >>= 1) 270 { 271 if (*ptr & mask) 272 { 273 SET(EPD_MOSI); 274 } 275 else 276 { 277 CLR(EPD_MOSI); 278 } 279 280 SET(EPD_SCK); 281 CLR(EPD_SCK); 282 } 283 } 284 } 285 286 void bsp_delayMs(uint32_t ms) 287 { 288 bsp_delayUs(ms * 1000); 289 } 290 291 void bsp_delayUs(uint32_t us) 292 { 293 #ifndef NANONOTE 294 struct timespec tv; 295 tv.tv_sec = 0; 296 tv.tv_nsec = us * 100; 297 nanosleep(&tv, NULL); 298 #else 299 uint64_t i = us * 16; 300 while (i-- > 0); 301 #endif 302 } 303 304 uint32_t bsp_getMsTicks() 305 { 306 struct timeval tv; 307 gettimeofday(&tv, NULL); 308 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 309 } 310 311 /* Unsupported. */ 312 313 int16_t bsp_getTemp() 314 { 315 return 20; 316 }