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