Contiki-NG
rgb-bl-lcd.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Zolertia <http://www.zolertia.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 /*---------------------------------------------------------------------------*/
33 /**
34  * \addtogroup zoul-lcd-backlight-lcd
35  * @{
36  *
37  * \file
38  * Grove LCD with RGB backlight driver
39  * \author
40  * Antonio Lignan <alinan@zolertia.com>
41  */
42 /*---------------------------------------------------------------------------*/
43 #include <stdio.h>
44 #include "contiki.h"
45 #include "dev/i2c.h"
46 #include "dev/rgb-bl-lcd.h"
47 #include "lib/sensors.h"
48 /*---------------------------------------------------------------------------*/
49 #define DEBUG 0
50 #if DEBUG
51 #define PRINTF(...) printf(__VA_ARGS__)
52 #else
53 #define PRINTF(...)
54 #endif
55 /*---------------------------------------------------------------------------*/
56 static uint8_t enabled;
57 /*---------------------------------------------------------------------------*/
58 typedef struct {
59  uint8_t display_func;
60  uint8_t display_ctrl;
61  uint8_t display_mode;
62  uint8_t num_lines;
63  uint8_t cur_line;
64 } rgb_lcd_config_t;
65 
66 static rgb_lcd_config_t lcd;
67 /*---------------------------------------------------------------------------*/
68 static const unsigned char rgb_color[7][3] =
69 {
70  { 0xFF, 0xFF, 0xFF }, /**< White */
71  { 0xFF, 0x00, 0x00 }, /**< Red */
72  { 0x00, 0xFF, 0x00 }, /**< Green */
73  { 0x00, 0x00, 0xFF }, /**< Blue */
74  { 0xFF, 0xFF, 0x00 }, /**< Yellow */
75  { 0x00, 0xFF, 0xFF }, /**< Purple */
76  { 0x00, 0x00, 0x00 }, /**< Black (off) */
77 };
78 /*---------------------------------------------------------------------------*/
79 static int
80 lcd_backlight_write_reg(uint8_t addr, uint8_t val)
81 {
82  uint8_t buf[2];
83  buf[0] = addr;
84  buf[1] = val;
85 
87  if(i2c_burst_send(LCD_RGB_ADDR, buf, 2) == I2C_MASTER_ERR_NONE) {
88  return LCD_RGB_SUCCESS;
89  }
90  return LCD_RGB_ERROR;
91 }
92 /*---------------------------------------------------------------------------*/
93 int
94 lcd_backlight_color(uint8_t color)
95 {
96  lcd_backlight_write_reg(LCD_RGB_LED_RED, rgb_color[color][0]);
97  lcd_backlight_write_reg(LCD_RGB_LED_GREEN, rgb_color[color][1]);
98  lcd_backlight_write_reg(LCD_RGB_LED_BLUE, rgb_color[color][2]);
99 
100  return LCD_RGB_SUCCESS;
101 }
102 /*---------------------------------------------------------------------------*/
103 static int
104 lcd_write_reg(uint8_t *buf, uint8_t num)
105 {
106  if((buf == NULL) || (num <= 0)) {
107  PRINTF("LCD: invalid write values\n");
108  return LCD_RGB_ERROR;
109  }
110 
112  if(i2c_burst_send(LCD_ADDR, buf, num) == I2C_MASTER_ERR_NONE) {
113  return LCD_RGB_SUCCESS;
114  }
115  return LCD_RGB_ERROR;
116 }
117 /*---------------------------------------------------------------------------*/
118 static int
119 lcd_cmd(uint8_t value)
120 {
121  uint8_t buf[2];
122  buf[0] = LCD_RGB_COMMAND_BYTE;
123  buf[1] = value;
124 
125  if(lcd_write_reg(buf, 2) == LCD_RGB_SUCCESS) {
126  return LCD_RGB_SUCCESS;
127  }
128 
129  PRINTF("LCD: failed to send command 0x%02X\n", value);
130  return LCD_RGB_ERROR;
131 }
132 /*---------------------------------------------------------------------------*/
133 int
134 lcd_clear_display(void)
135 {
136  if(lcd_cmd(LCD_RGB_CLEAR_DISPLAY) == LCD_RGB_SUCCESS) {
137  clock_delay_usec(LCD_RGB_DELAY_2MS);
138  return LCD_RGB_SUCCESS;
139  }
140  PRINTF("LCD: failed to clear LCD\n");
141  return LCD_RGB_ERROR;
142 }
143 /*---------------------------------------------------------------------------*/
144 int
145 lcd_return_home(void)
146 {
147  if(lcd_cmd(LCD_RGB_RETURN_HOME) == LCD_RGB_SUCCESS) {
148  clock_delay_usec(LCD_RGB_DELAY_2MS);
149  return LCD_RGB_SUCCESS;
150  }
151  PRINTF("LCD: failed to return home\n");
152  return LCD_RGB_ERROR;
153 }
154 /*---------------------------------------------------------------------------*/
155 int
156 lcd_set_cursor(uint8_t col, uint8_t row)
157 {
158  uint8_t buf[2];
159  buf[0] = LCD_RGB_SETDDRAM_ADDR;
160  buf[1] = col;
161  buf[1] += (!row) ? LCD_RGB_START_1ST_ROW : LCD_RGB_START_2ND_ROW;
162 
163  if(lcd_write_reg(buf, 2) == LCD_RGB_SUCCESS) {
164  return LCD_RGB_SUCCESS;
165  }
166 
167  PRINTF("LCD: failed to set cursor\n");
168  return LCD_RGB_ERROR;
169 }
170 /*---------------------------------------------------------------------------*/
171 int
172 lcd_display(uint8_t state)
173 {
174  lcd.display_ctrl &= ~LCD_RGB_DISPLAY_ON;
175  if(state) {
176  lcd.display_ctrl |= LCD_RGB_DISPLAY_ON;
177  }
178 
179  if(lcd_cmd(LCD_RGB_DISPLAY_CONTROL + lcd.display_ctrl) == LCD_RGB_SUCCESS) {
180  return LCD_RGB_SUCCESS;
181  }
182  PRINTF("LCD: failed to set display\n");
183  return LCD_RGB_ERROR;
184 }
185 /*---------------------------------------------------------------------------*/
186 int
187 lcd_cursor(uint8_t state)
188 {
189  lcd.display_ctrl &= ~LCD_RGB_DISPLAY_CURSOR_ON;
190  if(state) {
191  lcd.display_ctrl |= LCD_RGB_DISPLAY_CURSOR_ON;
192  }
193 
194  if(lcd_cmd(LCD_RGB_DISPLAY_CONTROL + lcd.display_ctrl) == LCD_RGB_SUCCESS) {
195  return LCD_RGB_SUCCESS;
196  }
197  PRINTF("LCD: failed to set cursor\n");
198  return LCD_RGB_ERROR;
199 }
200 /*---------------------------------------------------------------------------*/
201 int
202 lcd_blink(uint8_t state)
203 {
204  lcd.display_ctrl &= ~LCD_RGB_DISPLAY_BLINK_ON;
205  if(state) {
206  lcd.display_ctrl |= LCD_RGB_DISPLAY_BLINK_ON;
207  }
208 
209  if(lcd_cmd(LCD_RGB_DISPLAY_CONTROL + lcd.display_ctrl) == LCD_RGB_SUCCESS) {
210  return LCD_RGB_SUCCESS;
211  }
212  PRINTF("LCD: failed to set blink\n");
213  return LCD_RGB_ERROR;
214 }
215 /*---------------------------------------------------------------------------*/
216 int
217 lcd_scroll_display(uint8_t direction, uint8_t num)
218 {
219  uint8_t i;
220 
221  /* FIXME: add check for num */
222 
223  for(i = 0; i < num; i++) {
224  if(lcd_cmd(LCD_RGB_CURSOR_SHIFT + LCD_RGB_CURSOR_DISPLAY_MOVE +
225  direction) != LCD_RGB_SUCCESS) {
226  PRINTF("LCD: failed to set scroll\n");
227  return LCD_RGB_ERROR;
228  }
229  }
230  return LCD_RGB_SUCCESS;
231 }
232 /*---------------------------------------------------------------------------*/
233 int
234 lcd_text_direction(uint8_t direction)
235 {
236  lcd.display_mode &= ~LCD_RGB_ENTRY_MODE_LEFT;
237  if(direction) {
238  lcd.display_mode |= LCD_RGB_ENTRY_MODE_LEFT;
239  }
240 
241  if(lcd_cmd(LCD_RGB_ENTRY_MODE_SET + lcd.display_mode) == LCD_RGB_SUCCESS) {
242  return LCD_RGB_SUCCESS;
243  }
244  PRINTF("LCD: failed to set text direction\n");
245  return LCD_RGB_ERROR;
246 }
247 /*---------------------------------------------------------------------------*/
248 int
249 lcd_autoscroll(uint8_t state)
250 {
251  lcd.display_mode &= ~LCD_RGB_ENTRY_SHIFT_INCREMENT;
252  if(state) {
253  lcd.display_mode |= LCD_RGB_ENTRY_SHIFT_INCREMENT;
254  }
255 
256  if(lcd_cmd(LCD_RGB_ENTRY_MODE_SET + lcd.display_mode) == LCD_RGB_SUCCESS) {
257  return LCD_RGB_SUCCESS;
258  }
259  PRINTF("LCD: failed to set autoscroll\n");
260  return LCD_RGB_ERROR;
261 }
262 /*---------------------------------------------------------------------------*/
263 static int
264 lcd_write_byte(int c)
265 {
266  uint8_t buf[2];
267  buf[0] = LCD_RGB_SETCGRAM_ADDR;
268  buf[1] = c;
269 
270  if(lcd_write_reg(buf, 2) == LCD_RGB_SUCCESS) {
271  return LCD_RGB_SUCCESS;
272  }
273  return LCD_RGB_ERROR;
274 }
275 /*---------------------------------------------------------------------------*/
276 uint8_t
277 lcd_write(const char *s)
278 {
279  uint8_t i = 0;
280  while(s && *s != 0) {
281  lcd_write_byte(*s++);
282  i++;
283  }
284 
285  PRINTF("LCD: wrote %u bytes\n", i);
286  return i;
287 }
288 /*---------------------------------------------------------------------------*/
289 static int
290 configure(int type, int value)
291 {
292 
293  if(type != LCD_RGB_ACTIVE) {
294  PRINTF("LCD: option not supported\n");
295  return LCD_RGB_ERROR;
296  }
297 
298  switch(type) {
299 
300  /* Default initialization value is 16 columns and 2 rows */
301  case LCD_RGB_ACTIVE:
302  if(value) {
303  i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
304  I2C_SCL_NORMAL_BUS_SPEED);
305 
306  lcd.display_func = LCD_RGB_FUNCTION_SET_2_LINE +
307  LCD_RGB_FUNCTION_SET_5x8_DOTS;
308 
309  /* wait at least 50ms for the LCD to initialize */
310  clock_delay_usec(LCD_RGB_DELAY_50MS);
311 
312  /* Send function set command sequence */
313  if(lcd_cmd(LCD_RGB_FUNCTION_SET + lcd.display_func) == LCD_RGB_ERROR) {
314  return LCD_RGB_ERROR;
315  }
316  clock_delay_usec(LCD_RGB_DELAY_4_5MS);
317 
318  /* Datasheet instructs to repeat a second time... */
319  if(lcd_cmd(LCD_RGB_FUNCTION_SET + lcd.display_func) == LCD_RGB_ERROR) {
320  return LCD_RGB_ERROR;
321  }
322  clock_delay_usec(LCD_RGB_DELAY_150US);
323 
324  /* and a third... */
325  if(lcd_cmd(LCD_RGB_FUNCTION_SET + lcd.display_func) == LCD_RGB_ERROR) {
326  return LCD_RGB_ERROR;
327  }
328 
329  /* Now we can configure everything */
330  if(lcd_cmd(LCD_RGB_FUNCTION_SET + lcd.display_func) == LCD_RGB_ERROR) {
331  return LCD_RGB_ERROR;
332  }
333 
334  /* Turn on the display */
335  lcd.display_ctrl = LCD_RGB_DISPLAY_ON + LCD_RGB_DISPLAY_CURSOR_OFF +
336  LCD_RGB_DISPLAY_BLINK_OFF;
337  if(lcd_cmd(LCD_RGB_DISPLAY_CONTROL + lcd.display_ctrl) == LCD_RGB_ERROR) {
338  return LCD_RGB_ERROR;
339  }
340 
341  /* Clear the display */
342  if(lcd_clear_display() == LCD_RGB_ERROR) {
343  return LCD_RGB_ERROR;
344  }
345 
346  /* Initialize text direction (the LCD supports japanese, cool! */
347  lcd.display_mode = LCD_RGB_ENTRY_MODE_LEFT + LCD_RGB_ENTRY_SHIFT_DECREMENT;
348 
349  /* configure the entry mode */
350  if(lcd_cmd(LCD_RGB_ENTRY_MODE_SET + lcd.display_mode) == LCD_RGB_ERROR) {
351  return LCD_RGB_ERROR;
352  }
353 
354  /* Backlight initialization */
355  lcd_backlight_write_reg(LCD_RGB_LED_MODE_1, LCD_RGB_LED_MODE_DEFAULT);
356  lcd_backlight_write_reg(LCD_RGB_LED_MODE_2, LCD_RGB_LED_MODE_DEFAULT);
357  lcd_backlight_write_reg(LCD_RGB_LED_OUT, LCD_RGB_LED_OUT_PWM_CTRL);
358 
359  /* Set the backlight color */
360  lcd_backlight_color(LCD_RGB_RED);
361 
362  PRINTF("LCD: initialized\n");
363  enabled = 1;
364  return LCD_RGB_SUCCESS;
365  } else {
366  lcd_display(LCD_RGB_DISPLAY_OFF);
367  lcd_backlight_color(LCD_RGB_BLACK);
368  enabled = 0;
369  }
370  }
371 
372  return LCD_RGB_ERROR;
373 }
374 /*---------------------------------------------------------------------------*/
375 SENSORS_SENSOR(rgb_bl_lcd, RGB_BACKLIGHT_LCD, NULL, configure, NULL);
376 /*---------------------------------------------------------------------------*/
377 /** @} */
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:116
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:150
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition: i2c.c:49
Grove LCD with RGB backlight header.
void i2c_master_enable(void)
Enable master I2C module.
Definition: i2c.c:91