IoT-MBBR (masterthesis)
Masterthesis upgrading a Moving Bed BioReactor with extra sensors and cloud connectivity.
serlcd.c
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file serlcd.c
3  * @brief Sparkfun serLCD functionality.
4  * @version 1.0
5  * @author Brecht Van Eeckhoudt
6  *
7  * ******************************************************************************
8  *
9  * @section Versions
10  *
11  * @li v1.0: Initial version.
12  *
13  * ******************************************************************************
14  *
15  * @section License
16  *
17  * **Copyright (C) 2020 - Brecht Van Eeckhoudt**
18  *
19  * This program is free software: you can redistribute it and/or modify
20  * it under the terms of the **GNU General Public License** as published by
21  * the Free Software Foundation, either **version 3** of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * *A copy of the GNU General Public License can be found in the `LICENSE`
30  * file along with this source code.*
31  *
32  * @n
33  *
34  * Some methods use code obtained from examples from [Silicon Labs' GitHub](https://github.com/SiliconLabs/peripheral_examples).
35  * These sections are licensed under the Silabs License Agreement. See the file
36  * "Silabs_License_Agreement.txt" for details. Before using this software for
37  * any purpose, you must agree to the terms of that agreement.
38  *
39  * @n
40  *
41  * Code based on: https://github.com/sparkfun/SparkFun_SerLCD_Arduino_Library/blob/master/src/SerLCD.cpp
42  *
43  * ******************************************************************************
44  *
45  * @section cheatsheet Command cheat sheet:
46  *
47  * ASCII / DEC / HEX
48  * '|' / 124 / 0x7C - Put into setting mode
49  * Ctrl+c / 3 / 0x03 - Change width to 20
50  * Ctrl+d / 4 / 0x04 - Change width to 16
51  * Ctrl+e / 5 / 0x05 - Change lines to 4
52  * Ctrl+f / 6 / 0x06 - Change lines to 2
53  * Ctrl+g / 7 / 0x07 - Change lines to 1
54  * Ctrl+h / 8 / 0x08 - Software reset of the system
55  * Ctrl+i / 9 / 0x09 - Enable/disable splash screen
56  * Ctrl+j / 10 / 0x0A - Save currently displayed text as splash
57  * Ctrl+k / 11 / 0x0B - Change baud to 2400bps
58  * Ctrl+l / 12 / 0x0C - Change baud to 4800bps
59  * Ctrl+m / 13 / 0x0D - Change baud to 9600bps
60  * Ctrl+n / 14 / 0x0E - Change baud to 14400bps
61  * Ctrl+o / 15 / 0x0F - Change baud to 19200bps
62  * Ctrl+p / 16 / 0x10 - Change baud to 38400bps
63  * Ctrl+q / 17 / 0x11 - Change baud to 57600bps
64  * Ctrl+r / 18 / 0x12 - Change baud to 115200bps
65  * Ctrl+s / 19 / 0x13 - Change baud to 230400bps
66  * Ctrl+t / 20 / 0x14 - Change baud to 460800bps
67  * Ctrl+u / 21 / 0x15 - Change baud to 921600bps
68  * Ctrl+v / 22 / 0x16 - Change baud to 1000000bps
69  * Ctrl+w / 23 / 0x17 - Change baud to 1200bps
70  * Ctrl+x / 24 / 0x18 - Change the contrast. Follow Ctrl+x with number 0 to 255. 120 is default.
71  * Ctrl+y / 25 / 0x19 - Change the TWI address. Follow Ctrl+x with number 0 to 255. 114 (0x72) is default.
72  * Ctrl+z / 26 / 0x1A - Enable/disable ignore RX pin on startup (ignore emergency reset)
73  * '+' / 43 / 0x2B - Set RGB backlight with three following bytes, 0-255
74  * ',' / 44 / 0x2C - Display current firmware version
75  * '-' / 45 / 0x2D - Clear display. Move cursor to home position.
76  * '.' / 46 / 0x2E - Enable system messages (ie, display 'Contrast: 5' when changed)
77  * '/' / 47 / 0x2F - Disable system messages (ie, don't display 'Contrast: 5' when changed)
78  * '0' / 48 / 0x30 - Enable splash screen
79  * '1' / 49 / 0x31 - Disable splash screen
80  * / 128-157 / 0x80-0x9D - Set the primary backlight brightness. 128 = Off, 157 = 100%.
81  * / 158-187 / 0x9E-0xBB - Set the green backlight brightness. 158 = Off, 187 = 100%.
82  * / 188-217 / 0xBC-0xD9 - Set the blue backlight brightness. 188 = Off, 217 = 100%.
83  * For example, to change the baud rate to 115200 send 124 followed by 18.
84  *
85  ******************************************************************************/
86 
87 
88 #include <stdint.h> /* (u)intXX_t */
89 #include <stdbool.h> /* "bool", "true", "false" */
90 #include "em_device.h" /* Include necessary MCU-specific header file */
91 #include "em_cmu.h" /* Clock management unit */
92 #include "em_gpio.h" /* General Purpose IO */
93 #include "em_i2c.h"
94 
95 #include "serlcd.h" /* Corresponding header file */
96 #include "debug_dbprint.h" /* Enable or disable printing to UART */
97 #include "pin_mapping.h" /* PORT and PIN definitions */
98 #include "i2c.h" /* I2C initialization */
99 
100 
101 /* Local definitions */
102 #define DISPLAY_ADDRESS 0x72 /* This is the default address of the OpenLCD (7 bit notation) */
103 
104 /* OpenLCD command characters */
105 #define SPECIAL_COMMAND 254 /* Magic number for sending a special command */
106 #define SETTING_COMMAND 0x7C /* 124, |, the pipe character: The command to change settings: baud, lines, width, backlight, splash, etc */
107 
108 /* OpenLCD commands */
109 #define CLEAR_COMMAND 0x2D //45, -, the dash character: command to clear and home the display
110 #define CONTRAST_COMMAND 0x18 //Command to change the contrast setting
111 #define ADDRESS_COMMAND 0x19 //Command to change the i2c address
112 #define SET_RGB_COMMAND 0x2B //43, +, the plus character: command to set backlight RGB value
113 #define ENABLE_SYSTEM_MESSAGE_DISPLAY 0x2E //46, ., command to enable system messages being displayed
114 #define DISABLE_SYSTEM_MESSAGE_DISPLAY 0x2F //47, /, command to disable system messages being displayed
115 #define ENABLE_SPLASH_DISPLAY 0x30 //48, 0, command to enable splash screen at power on
116 #define DISABLE_SPLASH_DISPLAY 0x31 //49, 1, command to disable splash screen at power on
117 #define SAVE_CURRENT_DISPLAY_AS_SPLASH 0x0A //10, Ctrl+j, command to save current text on display as splash
118 
119 // special commands
120 #define LCD_RETURNHOME 0x02
121 #define LCD_ENTRYMODESET 0x04
122 #define LCD_DISPLAYCONTROL 0x08
123 #define LCD_CURSORSHIFT 0x10
124 #define LCD_SETDDRAMADDR 0x80
125 
126 // flags for display entry mode
127 #define LCD_ENTRYRIGHT 0x00
128 #define LCD_ENTRYLEFT 0x02
129 #define LCD_ENTRYSHIFTINCREMENT 0x01
130 #define LCD_ENTRYSHIFTDECREMENT 0x00
131 
132 // flags for display on/off control
133 #define LCD_DISPLAYON 0x04
134 #define LCD_DISPLAYOFF 0x00
135 #define LCD_CURSORON 0x02
136 #define LCD_CURSOROFF 0x00
137 #define LCD_BLINKON 0x01
138 #define LCD_BLINKOFF 0x00
139 
140 // flags for display/cursor shift
141 #define LCD_DISPLAYMOVE 0x08
142 #define LCD_CURSORMOVE 0x00
143 #define LCD_MOVERIGHT 0x04
144 #define LCD_MOVELEFT 0x00
145 
146 
147 /* Local variables */
148 bool heartBeat = false; /* Heartbeat status (doesn't mean it's enabled or disabled) */
149 
150 
151 /**************************************************************************//**
152  * @brief
153  * Clear the LCD.
154  *
155  * @details
156  * This method also initializes i2C if necessary.
157  *
158  * @return
159  * @return
160  * @li `0` - Byte written correctly.
161  * @li `-1` - `i2cTransferNack`, NACK received during transfer.
162  * @li `-2` - `i2cTransferBusErr`, Bus error during transfer (misplaced START/STOP).
163  * @li `-3` - `i2cTransferArbLost`, Arbitration lost during transfer.
164  * @li `-4` - `i2cTransferUsageFault`, Usage fault.
165  * @li `-5` - `i2cTransferSwFault`, SW fault.
166  * @li `-6` - Coudldn't configure I2C.
167  *****************************************************************************/
169 {
170  /* Initialize I2C if not already the case */
171  if (initI2C() != 0) return (-6);
172 
173  /* Put commands in array */
174  uint8_t data_buf[2] = {SETTING_COMMAND, CLEAR_COMMAND};
175 
176  /* Transfer structure */
177  I2C_TransferSeq_TypeDef i2cTransfer;
178  I2C_TransferReturn_TypeDef result;
179 
180  /* Initializing I2C transfer */
181  i2cTransfer.addr = DISPLAY_ADDRESS << 1; /* Left shift so we go to 8 bit notation instead of 7 */
182  i2cTransfer.flags = I2C_FLAG_WRITE; /* Data written from buf[0].data */
183  i2cTransfer.buf[0].data = data_buf;
184  i2cTransfer.buf[0].len = 2; /* Data is two bytes */
185  result = I2C_TransferInit(BUS_I2C, &i2cTransfer);
186 
187  /* Transmitting I2C data (busy-wait until transfer is complete) */
188  while (result == i2cTransferInProgress) result = I2C_Transfer(BUS_I2C);
189 
190  return (result);
191 }
192 
193 
194 /**************************************************************************//**
195  * @brief
196  * Write a character (one byte) to the LCD.
197  *
198  * @details
199  * This method also initializes i2C if necessary.
200  *
201  * @param[in] data
202  * The data (`uint8_t`) to put on the I2C bus.
203  *
204  * @return
205  * @return
206  * @li `0` - Byte written correctly.
207  * @li `-1` - `i2cTransferNack`, NACK received during transfer.
208  * @li `-2` - `i2cTransferBusErr`, Bus error during transfer (misplaced START/STOP).
209  * @li `-3` - `i2cTransferArbLost`, Arbitration lost during transfer.
210  * @li `-4` - `i2cTransferUsageFault`, Usage fault.
211  * @li `-5` - `i2cTransferSwFault`, SW fault.
212  * @li `-6` - Coudldn't configure I2C.
213  *****************************************************************************/
215 {
216  /* Initialize I2C if not already the case */
217  if (initI2C() != 0) return (-6);
218 
219  /* Separate data in bytes */
220  uint8_t data_buf[1] = {data};
221 
222  /* Transfer structure */
223  I2C_TransferSeq_TypeDef i2cTransfer;
224  I2C_TransferReturn_TypeDef result;
225 
226  /* Initializing I2C transfer */
227  i2cTransfer.addr = DISPLAY_ADDRESS << 1; /* Left shift so we go to 8 bit notation instead of 7 */
228  i2cTransfer.flags = I2C_FLAG_WRITE; /* Data written from buf[0].data */
229  i2cTransfer.buf[0].data = data_buf;
230  i2cTransfer.buf[0].len = 1; /* Data is one byte */
231  result = I2C_TransferInit(BUS_I2C, &i2cTransfer);
232 
233  /* Transmitting I2C data (busy-wait until transfer is complete) */
234  while (result == i2cTransferInProgress) result = I2C_Transfer(BUS_I2C);
235 
236  return (result);
237 }
238 
239 
240 /**************************************************************************//**
241  * @brief
242  * Print a string (char array) to the LCD.
243  *
244  * @note
245  * If the input is not a string (ex.: `"Hello world!"`) but a char array,
246  * the input message (array) needs to end with NULL (`"\0"`)!
247  *
248  * @details
249  * This method also initializes i2C if necessary.
250  *
251  * @param[in] message
252  * The string to print to the LCD.
253  *
254  * @return
255  * @return
256  * @li `0` - Byte written correctly.
257  * @li `-1` - `i2cTransferNack`, NACK received during transfer.
258  * @li `-2` - `i2cTransferBusErr`, Bus error during transfer (misplaced START/STOP).
259  * @li `-3` - `i2cTransferArbLost`, Arbitration lost during transfer.
260  * @li `-4` - `i2cTransferUsageFault`, Usage fault.
261  * @li `-5` - `i2cTransferSwFault`, SW fault.
262  * @li `-6` - Coudldn't configure I2C.
263  *****************************************************************************/
264 int8_t writeStringLCD (char *message)
265 {
266  /* Initialize I2C if not already the case */
267  if (initI2C() != 0) return (-6);
268 
269  /* Check string length */
270  uint8_t length = 0;
271 
272  /* Count up until we reach a NULL */
273  while (message[length] != '\0') length++;
274 
275  /* Transfer structure */
276  I2C_TransferSeq_TypeDef i2cTransfer;
277  I2C_TransferReturn_TypeDef result;
278 
279  /* Initializing I2C transfer */
280  i2cTransfer.addr = DISPLAY_ADDRESS << 1; /* Left shift so we go to 8 bit notation instead of 7 */
281  i2cTransfer.flags = I2C_FLAG_WRITE; /* Data written from buf[0].data */
282  i2cTransfer.buf[0].data = (unsigned char *)message;
283  i2cTransfer.buf[0].len = length; /* Data is one byte */
284  result = I2C_TransferInit(BUS_I2C, &i2cTransfer);
285 
286  /* Transmitting I2C data (busy-wait until transfer is complete) */
287  while (result == i2cTransferInProgress) result = I2C_Transfer(BUS_I2C);
288 
289  return (result);
290 }
291 
292 
293 /**************************************************************************//**
294  * @brief
295  * Set the cursor to a specific location on the LCD.
296  *
297  * @details
298  * This method also initializes i2C if necessary.
299  *
300  * @param[in] col
301  * Column (`uint8_t`, MAX = 20).
302  *
303  * @param[in] row
304  * Row (`uint8_t`, MAX = 4).
305  *
306  * @return
307  * @return
308  * @li `0` - Byte written correctly.
309  * @li `-1` - `i2cTransferNack`, NACK received during transfer.
310  * @li `-2` - `i2cTransferBusErr`, Bus error during transfer (misplaced START/STOP).
311  * @li `-3` - `i2cTransferArbLost`, Arbitration lost during transfer.
312  * @li `-4` - `i2cTransferUsageFault`, Usage fault.
313  * @li `-5` - `i2cTransferSwFault`, SW fault.
314  * @li `-6` - Coudldn't configure I2C.
315  *****************************************************************************/
317 {
318  uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
319 
320  /* Initialize I2C if not already the case */
321  if (initI2C() != 0) return (-6);
322 
323  /* Separate data in bytes */
324  uint8_t data_buf[2] = {254, LCD_SETDDRAMADDR | (col-1 + row_offsets[row-1])};
325 
326  /* Transfer structure */
327  I2C_TransferSeq_TypeDef i2cTransfer;
328  I2C_TransferReturn_TypeDef result;
329 
330  /* Initializing I2C transfer */
331  i2cTransfer.addr = DISPLAY_ADDRESS << 1; /* Left shift so we go to 8 bit notation instead of 7 */
332  i2cTransfer.flags = I2C_FLAG_WRITE; /* Data written from buf[0].data */
333  i2cTransfer.buf[0].data = data_buf;
334  i2cTransfer.buf[0].len = 2; /* Data is two bytes */
335  result = I2C_TransferInit(BUS_I2C, &i2cTransfer);
336 
337  /* Transmitting I2C data (busy-wait until transfer is complete) */
338  while (result == i2cTransferInProgress) result = I2C_Transfer(BUS_I2C);
339 
340  return (result);
341 }
342 
343 
344 /**************************************************************************//**
345  * @brief
346  * Update the heartbeat icon.
347  *
348  * @details
349  * This method also initializes i2C if necessary.
350  *
351  * @return
352  * @return
353  * @li `0` - Byte written correctly.
354  * @li `-1` - `i2cTransferNack`, NACK received during transfer.
355  * @li `-2` - `i2cTransferBusErr`, Bus error during transfer (misplaced START/STOP).
356  * @li `-3` - `i2cTransferArbLost`, Arbitration lost during transfer.
357  * @li `-4` - `i2cTransferUsageFault`, Usage fault.
358  * @li `-5` - `i2cTransferSwFault`, SW fault.
359  * @li `-6` - Coudldn't configure I2C.
360  *****************************************************************************/
362 {
363  /* Initialize I2C if not already the case */
364  if (initI2C() != 0) return (-6);
365 
366  /* Separate data in bytes */
367  uint8_t data_buf[3] = {254, LCD_SETDDRAMADDR | 19 }; /* 19th position on first row */
368 
369  /* Fill last location of data_buf according to heartBeat status */
370  if (heartBeat) data_buf[2] = '+';
371  else data_buf[2] = '*';
372  heartBeat = !heartBeat;
373 
374  /* Transfer structure */
375  I2C_TransferSeq_TypeDef i2cTransfer;
376  I2C_TransferReturn_TypeDef result;
377 
378  /* Initializing I2C transfer */
379  i2cTransfer.addr = DISPLAY_ADDRESS << 1; /* Left shift so we go to 8 bit notation instead of 7 */
380  i2cTransfer.flags = I2C_FLAG_WRITE; /* Data written from buf[0].data */
381  i2cTransfer.buf[0].data = data_buf;
382  i2cTransfer.buf[0].len = 3; /* Data is two bytes */
383  result = I2C_TransferInit(BUS_I2C, &i2cTransfer);
384 
385  /* Transmitting I2C data (busy-wait until transfer is complete) */
386  while (result == i2cTransferInProgress) result = I2C_Transfer(BUS_I2C);
387 
388  return (result);
389 }
390 
391 
392 
int8_t writeStringLCD(char *message)
Print a string (char array) to the LCD.
Definition: serlcd.c:264
#define SETTING_COMMAND
Definition: serlcd.c:106
signed char int8_t
Typedef defining 8 bit char type. The developer should modify this to suit the platform being deploye...
Definition: vl53l1_types.h:103
int8_t clearLCD(void)
Clear the LCD.
Definition: serlcd.c:168
#define LCD_SETDDRAMADDR
Definition: serlcd.c:124
MeasurementData_t data
Definition: main.c:86
#define BUS_I2C
Definition: pin_mapping.h:53
serLCD functionality.
int8_t writeCharLCD(uint8_t data)
Write a character (one byte) to the LCD.
Definition: serlcd.c:214
#define DISPLAY_ADDRESS
Definition: serlcd.c:102
The pin definitions for the custom board.
bool heartBeat
Definition: serlcd.c:148
Enable or disable printing to UART with dbprint.
int8_t heartBeatLCD(void)
Update the heartbeat icon.
Definition: serlcd.c:361
int8_t initI2C(void)
I2C initialization (if not already initialized).
Definition: i2c.c:66
int8_t setCursorLCD(uint8_t col, uint8_t row)
Set the cursor to a specific location on the LCD.
Definition: serlcd.c:316
#define CLEAR_COMMAND
Definition: serlcd.c:109
unsigned char uint8_t
Typedef defining 8 bit unsigned char type. The developer should modify this to suit the platform bein...
Definition: vl53l1_types.h:98
I2C functionality.