1 /**
2  *
3  * \file
4  *
5  * \brief SAM Segment Liquid Crystal Display(SLCD) Controller.
6  *
7  * This file defines a useful set of functions for the SLCD on SAM devices.
8  *
9  * Copyright (c) 2015-2016 Atmel Corporation. All rights reserved.
10  *
11  * \asf_license_start
12  *
13  * \page License
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions are met:
17  *
18  * 1. Redistributions of source code must retain the above copyright notice,
19  *    this list of conditions and the following disclaimer.
20  *
21  * 2. Redistributions in binary form must reproduce the above copyright notice,
22  *    this list of conditions and the following disclaimer in the documentation
23  *    and/or other materials provided with the distribution.
24  *
25  * 3. The name of Atmel may not be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * 4. This software may only be redistributed and used in connection with an
29  *    Atmel microcontroller product.
30  *
31  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
34  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
35  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
40  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGE.
42  *
43  * \asf_license_stop
44  *
45  */
46 /*
47  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
48  */
49 
50 #include <slcd.h>
51 #include <conf_slcd.h>
52 
53 #include <system.h>
54 
55 #if !defined(CONF_SLCD_CLOCK_SOURCE)
56 #  warning  SLCD_CLOCK_SOURCE is not defined, assuming 0.
57 #  define CONF_SLCD_CLOCK_SOURCE 0
58 #endif
59 
60 #if !defined(CONF_SLCD_DUTY)
61 #  warning  CONF_SLCD_DUTY is not defined, assuming 0.
62 #  define CONF_SLCD_DUTY 0
63 #endif
64 
65 #if !defined(CONF_SLCD_BIAS)
66 #  warning  CONF_SLCD_BIAS is not defined, assuming 0.
67 #  define CONF_SLCD_BIAS 0
68 #endif
69 
70 #if !defined(CONF_SLCD_PVAL)
71 #  warning  CONF_SLCD_PVAL is not defined, assuming 0.
72 #  define CONF_SLCD_PVAL 0
73 #endif
74 
75 #if !defined(CONF_SLCD_CKDIV)
76 #  warning  CONF_SLCD_CKDIV is not defined, assuming 0.
77 #  define CONF_SLCD_CKDIV 0
78 #endif
79 
80 #if !defined(CONF_SLCD_VLCD_SEL)
81 #  warning  CONF_SLCD_VLCD_SEL is not defined, assuming 0.
82 #  define CONF_SLCD_VLCD_SEL 0
83 #endif
84 
85 #if !defined(CONF_SLCD_REF_REFRESH_FREQ)
86 #  warning  CONF_SLCD_REF_REFRESH_FREQ is not defined, assuming 0.
87 #  define CONF_SLCD_REF_REFRESH_FREQ 0
88 #endif
89 
90 #if !defined(CONF_SLCD_POWER_REFRESH_FREQ)
91 #  warning  CONF_SLCD_POWER_REFRESH_FREQ is not defined, assuming 0.
92 #  define CONF_SLCD_POWER_REFRESH_FREQ 0
93 #endif
94 
95 #if !defined(CONF_SLCD_POWER_MODE)
96 #  warning  CONF_SLCD_POWER_MODE is not defined, assuming 0.
97 #  define CONF_SLCD_POWER_MODE 0
98 #endif
99 
100 #if !defined(CONF_SLCD_PIN_L_MASK)
101 #  warning  CONF_SLCD_PIN_L_MASK is not defined, assuming 0.
102 #  define CONF_SLCD_PIN_L_MASK 0
103 #endif
104 
105 #if !defined(CONF_SLCD_PIN_H_MASK)
106 #  warning  CONF_SLCD_PIN_H_MASK is not defined, assuming 0.
107 #  define CONF_SLCD_PIN_H_MASK 0
108 #endif
109 
110 /**
111  * \brief Initializes SLCD configurations struct to defaults
112  *
113  * Initailizes SLCD configuration struct to predefined safe default settings.
114  *
115  * \param[in] config Pointer to an instance of \ref struct slcd_config
116  *
117  */
slcd_get_config_defaults(struct slcd_config * config)118 void slcd_get_config_defaults(struct slcd_config *config)
119 {
120 	Assert(config);
121 
122 	config->run_in_standby = false;
123 	config->waveform_mode = SLCD_LOW_POWER_WAVEFORM_MODE;
124 	config->low_resistance_duration = 0;
125 	config->enable_low_resistance = false;
126 	config->bias_buffer_duration = 0;
127 	config->enable_bias_buffer = false;
128 }
129 
130 /**
131  * \brief Initialize SLCD module
132  *
133  * \param[in] config  Pointer to an SLCD configuration structure
134  *
135  *  \note SLCD cannot be Initialized while it is enabled.
136  *
137  * \return Status of the configuration procedure.
138  * \retval STATUS_OK SLCD configuration went successful
139  * \retval STATUS_ERR_INVALID_ARG  If an invalid configuration was supplied
140  */
slcd_init(struct slcd_config * const config)141 enum status_code slcd_init(struct slcd_config *const config)
142 {
143 	if (!config) {
144 		return STATUS_ERR_INVALID_ARG;
145 	}
146 	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_SLCD);
147 
148 	/* Select SLCD clock */
149 	OSC32KCTRL->SLCDCTRL.reg = CONF_SLCD_CLOCK_SOURCE & OSC32KCTRL_SLCDCTRL_MASK;
150 
151 	slcd_disable();
152 	slcd_reset();
153 
154 	SLCD->CTRLA.reg = SLCD_CTRLA_DUTY(CONF_SLCD_DUTY) | SLCD_CTRLA_BIAS(CONF_SLCD_BIAS)
155 					 | SLCD_CTRLA_PRESC(CONF_SLCD_PVAL) | SLCD_CTRLA_CKDIV(CONF_SLCD_CKDIV)
156 					 | (CONF_SLCD_VLCD_SEL << SLCD_CTRLA_XVLCD_Pos)
157 					 | (config->run_in_standby << SLCD_CTRLA_RUNSTDBY_Pos)
158 					 | SLCD_CTRLA_RRF(CONF_SLCD_REF_REFRESH_FREQ)
159 					 | SLCD_CTRLA_PRF(CONF_SLCD_POWER_REFRESH_FREQ)
160 					 | (config->waveform_mode << SLCD_CTRLA_WMOD_Pos);
161 	SLCD->CTRLB.reg = SLCD_CTRLB_BBD(config->bias_buffer_duration)
162   					| (config->enable_bias_buffer << SLCD_CTRLB_BBEN_Pos)
163   					| SLCD_CTRLB_LRD(config->low_resistance_duration)
164   					| (config->enable_low_resistance << SLCD_CTRLB_LREN_Pos);
165 
166 
167     SLCD->CTRLC.reg |= SLCD_CTRLC_LPPM(CONF_SLCD_POWER_MODE) | SLCD_CTRLC_CTST(0x0F);
168 
169 	SLCD->LPENL.reg = CONF_SLCD_PIN_L_MASK & SLCD_LPENL_MASK;
170 	SLCD->LPENH.reg = CONF_SLCD_PIN_H_MASK & SLCD_LPENH_MASK;
171 
172    return STATUS_OK;
173 }
174 
175 /**
176  * \brief Enables the SLCD module
177  *
178  * Enables the SLCD module once it has been configured, ready for use. Most
179  * module configuration parameters cannot be altered while the module is enabled.
180  */
181 
slcd_enable(void)182 void slcd_enable(void)
183 {
184 	SLCD->CTRLA.reg |= SLCD_CTRLA_ENABLE;
185 
186 	while (slcd_is_syncing()) {
187 		/* Wait for synchronization */
188 	}
189 
190 	while (!slcd_get_vlcd_ready_status()) {
191    	}
192 }
193 
194 /**
195  * \brief Disables the SLCD module
196  *
197  * Disables the SLCD module.
198  */
slcd_disable(void)199 void slcd_disable(void)
200 {
201 	SLCD->INTENCLR.reg = SLCD_INTENCLR_MASK;
202 	SLCD->INTFLAG.reg = SLCD_INTFLAG_MASK;
203 	SLCD->CTRLA.reg &= ~(SLCD_CTRLA_ENABLE);
204 	while (slcd_is_syncing()) {
205 		/* Wait for synchronization */
206 	}
207 }
208 
209 /**
210  * \brief Check if SLCD module is enabled or not
211  *
212  * Check if SLCD module is enabled or not.
213  *
214  * \return Enable status.
215  * \retval true SLCD module is enabled
216  * \retval false SLCD module is disabled
217  */
218 
slcd_is_enabled(void)219 bool slcd_is_enabled(void)
220 {
221 	return ((SLCD->CTRLA.reg & SLCD_CTRLA_ENABLE) == SLCD_CTRLA_ENABLE);
222 }
223 
224 /**
225  * \brief Reset the SLCD module
226  *
227  * Reset the SLCD module.
228  */
slcd_reset(void)229 void slcd_reset(void)
230 {
231 	slcd_disable();
232 	SLCD->CTRLA.reg |= SLCD_CTRLA_SWRST;
233 	while (slcd_is_syncing()) {
234 		/* Wait for synchronization */
235 	}
236 }
237 
238 /**
239  * \brief Set the SLCD fine contrast
240  *
241  * The LCD contrast is defined by the value of VLCD voltage. The higher is the
242  * VLCD voltage, the higher is the contrast. The software contrast adjustment
243  * is only possible in internal supply mode.
244  * In internal supply mode, VLCD is in the range 2.5V to 3.5V. VLCD can be
245  * adjusted with 16 steps, each step is 60 mV.The contrast value can be written
246  * at any time.
247  *
248  * \param[in] contrast Contrast value
249  *
250  * \return Status of set contrast.
251  * \retval STATUS_OK               SLCD contrast set successful
252  * \retval STATUS_ERR_INVALID_ARG  SLCD is not working in internal supply mode
253  */
slcd_set_contrast(uint8_t contrast)254 enum status_code slcd_set_contrast(uint8_t contrast)
255 {
256 
257 	if (SLCD->CTRLA.bit.XVLCD) {
258 		return STATUS_ERR_INVALID_ARG;
259 	}
260 	uint16_t temp = SLCD->CTRLC.reg;
261 
262 	temp &= ~ SLCD_CTRLC_CTST(0xf);
263 	temp |= SLCD_CTRLC_CTST(contrast);
264 
265 	SLCD->CTRLC.reg = temp;
266 	return STATUS_OK;
267 }
268 
269 /**
270  * \brief Initializes SLCD blink configurations struct to defaults
271  *
272  * Initailizes SLCD blink configuration struct to predefined safe default settings.
273  *
274  * \param[in] config Pointer to an instance of \ref struct slcd_blink_config
275  *
276  */
slcd_blink_get_config_defaults(struct slcd_blink_config * blink_config)277 void slcd_blink_get_config_defaults(struct slcd_blink_config *blink_config)
278 {
279 	Assert(blink_config);
280 
281 	blink_config->fc = SLCD_FRAME_COUNTER_0;
282 	blink_config->blink_all_seg = true;
283 }
284 
285 /**
286  * \brief Set SLCD blink mode
287  *
288  * Set SLCD blink mode.
289  *
290  *  \note SLCD blink cannot be set while module or blink is enabled.
291  *
292  * \param[in] config  Pointer to an SLCD blink configuration structure
293  *
294  * \return Status of the configuration procedure.
295  * \retval STATUS_OK               SLCD blink configuration went successful
296  * \retval STATUS_ERR_INVALID_ARG  If blink configuration failed
297  */
298 
slcd_blink_set_config(struct slcd_blink_config * const blink_config)299 enum status_code  slcd_blink_set_config(struct slcd_blink_config *const blink_config)
300 {
301 	if (!blink_config) {
302 		return STATUS_ERR_INVALID_ARG;
303 	}
304 
305 	SLCD->BCFG.bit.MODE = (!(blink_config->blink_all_seg) << SLCD_BCFG_MODE_Pos);
306 	SLCD->BCFG.bit.FCS	= SLCD_BCFG_FCS(blink_config->fc);
307 	return STATUS_OK;
308 }
309 
310 /**
311  * \brief Start an SLCD pixel/segment blinking
312  *
313  * \param[in] pix_com Pixel/segment COM coordinate
314  * \param[in] pix_seg Pixel/segment SEG coordinate (range 0 to 1 inclusive)
315  */
slcd_set_blink_pixel(uint8_t pix_com,uint8_t pix_seg)316 void slcd_set_blink_pixel(
317 		uint8_t pix_com,
318 		uint8_t pix_seg)
319 {
320 	/* Validate parameters. */
321 	Assert(pix_seg<=1);
322 
323 	if (pix_seg == 0) {
324 		SLCD->BCFG.reg |= SLCD_BCFG_BSS0(1 << pix_com);
325 	}
326 
327 	if (pix_seg == 1) {
328 		SLCD->BCFG.reg |= SLCD_BCFG_BSS1(1 << pix_com);
329 	}
330 }
331 
332 /**
333  * \brief Stop a specified SLCD pixel/segment from blinking
334  *
335  * \param[in] pix_com Pixel/segment COM coordinate
336  * \param[in] pix_seg Pixel/segment SEG coordinate (range 0 to 1 inclusive)
337  */
slcd_clear_blink_pixel(uint8_t pix_com,uint8_t pix_seg)338 void slcd_clear_blink_pixel(
339 		uint8_t pix_com,
340 		uint8_t pix_seg)
341 {
342 	/* Validate parameters. */
343 	Assert(pix_seg<=1);
344 
345 	if (pix_seg == 0) {
346 		SLCD->BCFG.reg &= ~ SLCD_BCFG_BSS0(1 << pix_com);
347 	}
348 
349 	if (pix_seg == 1) {
350 		SLCD->BCFG.reg &= ~ SLCD_BCFG_BSS1(1 << pix_com);
351 	}
352 }
353 
354 /**
355  * \brief Stop all SLCD pixels/segments from blinking
356  */
slcd_clear_blink_all_pixel(void)357 void slcd_clear_blink_all_pixel(void)
358 {
359 	SLCD->BCFG.bit.BSS0 = 0;
360 	SLCD->BCFG.bit.BSS1 = 0;
361 }
362 
363 
364 /**
365  * \brief Set all bits in the SLCD display memory high
366  */
slcd_set_display_memory(void)367 void slcd_set_display_memory(void)
368 {
369 	SLCD->SDATAH0.reg = SLCD_SDATAH0_MASK;
370 	SLCD->SDATAL0.reg = SLCD_SDATAL0_MASK;
371 	SLCD->SDATAH1.reg = SLCD_SDATAH1_MASK;
372 	SLCD->SDATAL1.reg = SLCD_SDATAL1_MASK;
373 	SLCD->SDATAH2.reg = SLCD_SDATAH2_MASK;
374 	SLCD->SDATAL2.reg = SLCD_SDATAL2_MASK;
375 	SLCD->SDATAH3.reg = SLCD_SDATAH3_MASK;
376 	SLCD->SDATAL3.reg = SLCD_SDATAL3_MASK;
377 	SLCD->SDATAH4.reg = SLCD_SDATAH4_MASK;
378 	SLCD->SDATAL4.reg = SLCD_SDATAL4_MASK;
379 	SLCD->SDATAH5.reg = SLCD_SDATAH5_MASK;
380 	SLCD->SDATAL5.reg = SLCD_SDATAL5_MASK;
381 	SLCD->SDATAH6.reg = SLCD_SDATAH6_MASK;
382 	SLCD->SDATAL6.reg = SLCD_SDATAL6_MASK;
383 	SLCD->SDATAH7.reg = SLCD_SDATAH7_MASK;
384 	SLCD->SDATAL7.reg = SLCD_SDATAL7_MASK;
385 }
386 
387 
388 /**
389  * \brief Enable the specified pixel/segment in the SLCD display memory
390  *
391  * \param[in] pix_com Pixel/segment COM coordinate,within [0-7]
392  * \param[in] pix_seg Pixel/segment SEG coordinate within [0-43]
393  */
slcd_set_pixel(uint8_t pix_com,uint8_t pix_seg)394  void slcd_set_pixel(
395 		uint8_t pix_com,
396 		uint8_t pix_seg)
397 {
398 	if ((pix_com < SLCD_MAX_COM) &&
399 			(pix_seg < SLCD_MAX_SEG)) {
400 		switch(pix_com){
401 			case 0:
402 				if (pix_seg >= 32) {
403 					SLCD->SDATAH0.reg |= (1 <<(pix_seg-32));
404 				} else {
405 					SLCD->SDATAL0.reg |= 1 <<pix_seg;
406 				}
407 				break;
408 			case 1:
409 				if (pix_seg >= 32) {
410 					SLCD->SDATAH1.reg |= (1 <<(pix_seg-32));
411 				} else {
412 					SLCD->SDATAL1.reg |= 1 <<pix_seg;
413 				}
414 				break;
415 			case 2:
416 				if (pix_seg >= 32) {
417 					SLCD->SDATAH2.reg |= (1 <<(pix_seg-32));
418 				} else {
419 					SLCD->SDATAL2.reg |= 1 <<pix_seg;
420 				}
421 				break;
422 			case 3:
423 				if (pix_seg >= 32) {
424 					SLCD->SDATAH3.reg |= (1 <<(pix_seg-32));
425 				} else {
426 					SLCD->SDATAL3.reg |= 1 <<pix_seg;
427 				}
428 				break;
429 			case 4:
430 				if (pix_seg >= 32) {
431 					SLCD->SDATAH4.reg |= (1 <<(pix_seg-32));
432 				} else {
433 					SLCD->SDATAL4.reg |= 1 <<pix_seg;
434 				}
435 				break;
436 			case 5:
437 				if (pix_seg >= 32) {
438 					SLCD->SDATAH5.reg |= (1 <<(pix_seg-32));
439 				} else {
440 					SLCD->SDATAL5.reg |= 1 <<pix_seg;
441 				}
442 				break;
443 			case 6:
444 				if (pix_seg >= 32) {
445 					SLCD->SDATAH6.reg |= (1 <<(pix_seg-32));
446 				} else {
447 					SLCD->SDATAL6.reg |= 1 <<pix_seg;
448 				}
449 				break;
450 			case 7:
451 				if (pix_seg >= 32) {
452 					SLCD->SDATAH7.reg |= (1 <<(pix_seg-32));
453 				} else {
454 					SLCD->SDATAL7.reg |= 1 <<pix_seg;
455 				}
456 				break;
457 		}
458 		while (slcd_get_char_writing_status()) {
459 		}
460 	}
461 }
462 
463 /**
464  * \brief Disable the specified pixel/segment in the SLCD display memory
465  *
466  * \param[in] pix_com Pixel/segment COM coordinate
467  * \param[in] pix_seg Pixel/segment SEG coordinate
468  */
slcd_clear_pixel(uint8_t pix_com,uint8_t pix_seg)469  void slcd_clear_pixel(uint8_t pix_com, uint8_t pix_seg)
470 {
471 	if ((pix_com < SLCD_MAX_COM) &&
472 			(pix_seg < SLCD_MAX_SEG)) {
473 		switch(pix_com){
474 			case 0:
475 				if (pix_seg >= 32) {
476 					SLCD->SDATAH0.reg &= ~(1 <<(pix_seg-32));
477 				} else {
478 					SLCD->SDATAL0.reg &= ~(1 <<pix_seg);
479 				}
480 				break;
481 			case 1:
482 				if (pix_seg >= 32) {
483 					SLCD->SDATAH1.reg &= ~(1 <<(pix_seg-32));
484 				} else {
485 					SLCD->SDATAL1.reg &= ~(1 <<pix_seg);
486 				}
487 				break;
488 			case 2:
489 				if (pix_seg >= 32) {
490 					SLCD->SDATAH2.reg &= (1 <<(pix_seg-32));
491 				} else {
492 					SLCD->SDATAL2.reg &= ~(1 <<pix_seg);
493 				}
494 				break;
495 			case 3:
496 				if (pix_seg >= 32) {
497 					SLCD->SDATAH3.reg &= ~(1 <<(pix_seg-32));
498 				} else {
499 					SLCD->SDATAL3.reg &= ~(1 <<pix_seg);
500 				}
501 				break;
502 			case 4:
503 				if (pix_seg >= 32) {
504 					SLCD->SDATAH4.reg &= ~(1 <<(pix_seg-32));
505 				} else {
506 					SLCD->SDATAL4.reg &= ~(1 <<pix_seg);
507 				}
508 				break;
509 			case 5:
510 				if (pix_seg >= 32) {
511 					SLCD->SDATAH5.reg &= ~(1 <<(pix_seg-32));
512 				} else {
513 					SLCD->SDATAL5.reg &= ~(1 <<pix_seg);
514 				}
515 				break;
516 			case 6:
517 				if (pix_seg >= 32) {
518 					SLCD->SDATAH6.reg &= ~(1 <<(pix_seg-32));
519 				} else {
520 					SLCD->SDATAL6.reg &= ~(1 <<pix_seg);
521 				}
522 				break;
523 			case 7:
524 				if (pix_seg >= 32) {
525 					SLCD->SDATAH7.reg &= ~(1 <<(pix_seg-32));
526 				} else {
527 					SLCD->SDATAL7.reg &= ~(1 <<pix_seg);
528 				}
529 				break;
530 		}
531 		while (slcd_get_char_writing_status()) {
532 		}
533 	}
534 }
535 
536 /**
537  * \brief Set the specified segment in the SLCD display memory
538  *
539  * \param[in] pix_seg     Pixel/segment SEG coordinate
540  * \param[in] byte_offset Byte offset in display memory
541  * \param[in] seg_mask    Byte offset in display memory
542  */
slcd_set_seg_data(uint8_t seg_data,uint8_t byte_offset,uint8_t seg_mask)543 void slcd_set_seg_data(uint8_t seg_data,uint8_t byte_offset,uint8_t seg_mask)
544 {
545 	SLCD->ISDATA.reg = SLCD_ISDATA_SDATA(seg_data)
546 					 | SLCD_ISDATA_OFF(byte_offset)
547 					 | SLCD_ISDATA_SDMASK(seg_mask);
548 
549 	while (slcd_get_char_writing_status()) {
550 	}
551 }
552 
553 /**
554  * \brief Initializes SLCD Automated Character configurations struct to defaults
555  *
556  * Initailizes SLCD Automated Character configuration struct to predefined safe default settings.
557  *
558  * \param[in] config Pointer to an instance of \ref struct slcd_automated_char_config
559  *
560  */
slcd_automated_char_get_config_default(struct slcd_automated_char_config * config)561 void slcd_automated_char_get_config_default(
562 		struct slcd_automated_char_config *config)
563 {
564 	Assert(config);
565 
566 	config->order = SLCD_AUTOMATED_CHAR_START_FROM_BOTTOM_RIGHT;
567 	config->fc = SLCD_FRAME_COUNTER_0;
568 	config->mode = SLCD_AUTOMATED_CHAR_SEQ;
569 	config->seg_line_num = 0;
570 	config->start_seg_line = 0;
571 	config->row_digit_num = 1;
572 	config->digit_num = 0;
573 	config->scrolling_step = 1;
574 	config->com_line_num = 1;
575 	config->data_mask = 0;
576 
577 }
578 
579 /**
580  * \brief Set SLCD automated character
581  *
582  * Set automated character mode.
583  *
584  *  \note SLCD automated character mode cannot be set while module or
585  * automated character is enabled.
586  *
587  * \param[in] config  Pointer to an SLCD automated character configuration structure
588  *
589  * \return Status of the configuration procedure.
590  * \retval STATUS_OK               SLCD automated character configuration went successful
591  * \retval STATUS_ERR_INVALID_ARG  If automated character  configuration failed
592  */
slcd_automated_char_set_config(struct slcd_automated_char_config * const config)593 enum status_code slcd_automated_char_set_config(
594 		struct slcd_automated_char_config *const config)
595 {
596 	if (!config) {
597 		return STATUS_ERR_INVALID_ARG;
598 	}
599 	SLCD->CMCFG.reg = SLCD_CMCFG_NSEG(config->seg_line_num)
600 					 | (config->order  << SLCD_CMCFG_DEC_Pos);
601 	SLCD->ACMCFG.reg = SLCD_ACMCFG_FCS(config->fc)
602 					 | (config->mode << SLCD_ACMCFG_MODE_Pos)
603 					 | SLCD_ACMCFG_STSEG(config->start_seg_line)
604 					 | SLCD_ACMCFG_NDROW(config->row_digit_num)
605 					 | SLCD_ACMCFG_NDIG(config->digit_num)
606 					 | SLCD_ACMCFG_STEPS(config->scrolling_step)
607 					 | SLCD_ACMCFG_NCOM(config->com_line_num);
608 
609 	SLCD->CMDMASK.reg = SLCD_CMDMASK_SDMASK(config->data_mask);
610 
611 	return STATUS_OK;
612 }
613 
614 /**
615  * \brief Set SLCD character mapping
616  *
617  * Set Character mode amd SEG line per digit.
618  *
619  * \param[in] order         Mapping order in char mode
620  * \param[in] seg_line_num  Define the number of SEG line per digit,
621  *                          it equal to number of SEG line - 1
622  */
slcd_character_map_set(enum slcd_automated_char_order order,uint8_t seg_line_num)623 void slcd_character_map_set(
624 		enum slcd_automated_char_order order,
625 		uint8_t seg_line_num)
626 {
627 	SLCD->CMCFG.reg = SLCD_CMCFG_NSEG(seg_line_num)
628 					 | (order  << SLCD_CMCFG_DEC_Pos);
629 }
630 
631 /**
632  * \brief Write segments data to display memory in character mode
633  *
634  * \param[in] seg_data       Pixel/segment data
635  * \param[in] data_mask      Segments data mask
636  * \param[in] com_line_index COM line index
637  * \param[in] seg_line_index Segments line index
638  */
slcd_character_write_data(uint8_t com_line_index,uint8_t seg_line_index,uint32_t seg_data,uint32_t data_mask)639 void slcd_character_write_data(uint8_t com_line_index,
640 									uint8_t seg_line_index,
641 									uint32_t seg_data,uint32_t data_mask)
642 {
643 
644 	SLCD->CMINDEX.reg = SLCD_CMINDEX_SINDEX(seg_line_index)
645 						| SLCD_CMINDEX_CINDEX(com_line_index);
646 	SLCD->CMDMASK.reg = SLCD_CMDMASK_SDMASK(data_mask);
647 	SLCD->CMDATA.reg = SLCD_CMDATA_SDATA(seg_data);
648 	while (slcd_get_char_writing_status()) {
649 	}
650 }
651 
652 /**
653  * \brief Initializes circular shift configurations struct to defaults
654  *
655  * Initailizes circular shift configuration struct to predefined safe default settings.
656  *
657  * \param[in] config Pointer to an instance of \ref struct slcd_circular_shift_config
658  *
659  */
slcd_circular_shift_get_config_defaults(struct slcd_circular_shift_config * const config)660 void slcd_circular_shift_get_config_defaults(
661 		struct slcd_circular_shift_config *const config)
662 {
663 	Assert(config);
664 
665 	config->fc = SLCD_FRAME_COUNTER_0;
666 	config->dir = SLCD_CIRCULAR_SHIFT_LEFT;
667 	config->size = 0;
668 	config->data = 0;
669 }
670 
671 /**
672  * \brief Set SLCD circular shift
673  *
674  * Set circular shift mode.
675  *
676  * \note SLCD circular shift mode cannot be set while module or circular shift is enabled.
677  *
678  * \param[in] config  Pointer to an SLCD circular shift configuration structure
679  *
680  * \return Status of the configuration procedure.
681  * \retval STATUS_OK               SLCD circular shift configuration went successful
682  * \retval STATUS_ERR_INVALID_ARG  If circular shift configuration failed
683  */
684 
slcd_circular_shift_set_config(struct slcd_circular_shift_config * const config)685 enum status_code slcd_circular_shift_set_config(
686 		struct slcd_circular_shift_config *const config)
687 {
688 	if (!config) {
689 		return STATUS_ERR_INVALID_ARG;
690 	}
691 	SLCD->CSRCFG.reg = SLCD_CSRCFG_FCS(config->fc)
692 					 | (config->dir << SLCD_CSRCFG_DIR_Pos)
693 					 | SLCD_CSRCFG_SIZE(config->size)
694 					 | SLCD_CSRCFG_DATA(config->data);
695 
696 	return STATUS_OK;
697 }
698 
699